diff --git a/lawnchair/res/values/config.xml b/lawnchair/res/values/config.xml
index 530955f4e8..3cba97b869 100644
--- a/lawnchair/res/values/config.xml
+++ b/lawnchair/res/values/config.xml
@@ -67,6 +67,9 @@
true
false
false
+ true
+ false
+ false
- 1.0
- 1.0
diff --git a/lawnchair/res/values/strings.xml b/lawnchair/res/values/strings.xml
index 7b11917c33..f9270c7885 100644
--- a/lawnchair/res/values/strings.xml
+++ b/lawnchair/res/values/strings.xml
@@ -235,7 +235,10 @@
%1$s, %2$s
- EEEMMMd
+ EEEMMMd
+ HH:mm
+ hh:mm aa
+ dd MMMM
l، j F
Charging
Charged
@@ -249,6 +252,10 @@
Preview
Calendar
+ Date & Time
+ Date
+ Time
+ 24-Hour Format
Weather
Battery Status
Now Playing
diff --git a/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt b/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt
index 883ff2c03e..ef4b03861f 100644
--- a/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt
+++ b/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt
@@ -282,6 +282,21 @@ class PreferenceManager2(private val context: Context) : PreferenceManager {
defaultValue = true
)
+ val smartspaceShowDate = preference(
+ key = booleanPreferencesKey("smartspace_show_date"),
+ defaultValue = context.resources.getBoolean(R.bool.config_default_smartspace_show_date),
+ )
+
+ val smartspaceShowTime = preference(
+ key = booleanPreferencesKey("smartspace_show_time"),
+ defaultValue = context.resources.getBoolean(R.bool.config_default_smartspace_show_time),
+ )
+
+ val smartspace24HourFormat = preference(
+ key = booleanPreferencesKey("smartspace_24_hour_format"),
+ defaultValue = context.resources.getBoolean(R.bool.config_default_smartspace_24_hour_format),
+ )
+
val smartspaceCalendar = preference(
key = stringPreferencesKey(name = "smartspace_calendar"),
defaultValue = SmartspaceCalendar.fromString(context.getString(R.string.config_default_smart_space_calendar)),
diff --git a/lawnchair/src/app/lawnchair/smartspace/IcuDateTextView.kt b/lawnchair/src/app/lawnchair/smartspace/IcuDateTextView.kt
index 1ae1c12764..cf9bffdbef 100644
--- a/lawnchair/src/app/lawnchair/smartspace/IcuDateTextView.kt
+++ b/lawnchair/src/app/lawnchair/smartspace/IcuDateTextView.kt
@@ -24,6 +24,10 @@ class IcuDateTextView @JvmOverloads constructor(
private lateinit var preferenceManager2: PreferenceManager2
private var calendar: SmartspaceCalendar? = null
+ private var showDate: Boolean = true
+ private var showTime: Boolean = false
+ private var time24HourFormat: Boolean = false
+ private var formatterUpdateRequired = true
private var formatterGregorian: DateFormat? = null
private var formatterPersian: PersianDateFormat? = null
private val ticker = this::onTimeTick
@@ -50,8 +54,8 @@ class IcuDateTextView @JvmOverloads constructor(
private fun onTimeChanged(updateFormatter: Boolean) {
if (isShown) {
val timeText = when (calendar) {
- SmartspaceCalendar.Persian -> getTimeTextPersian(updateFormatter = updateFormatter)
- else -> getTimeTextGregorian(updateFormatter = updateFormatter)
+ SmartspaceCalendar.Persian -> getTimeTextPersian(updateFormatter = updateFormatter || formatterUpdateRequired)
+ else -> getTimeTextGregorian(updateFormatter = updateFormatter || formatterUpdateRequired)
}
if (text != timeText) {
textAlignment =
@@ -67,21 +71,35 @@ class IcuDateTextView @JvmOverloads constructor(
context.getString(R.string.smartspace_icu_date_pattern_persian),
PersianDateFormat.PersianDateNumberCharacter.FARSI,
).also { formatterPersian = it }
+ formatterUpdateRequired = false
return formatter.format(PersianDate(System.currentTimeMillis()))
}
private fun getTimeTextGregorian(updateFormatter: Boolean): String {
- val formatter = formatterGregorian.takeIf { updateFormatter.not() }
- ?: DateFormat.getInstanceForSkeleton(
- context.getString(R.string.smartspace_icu_date_pattern_gregorian),
- Locale.getDefault()
- ).also {
- it.setContext(DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE)
- formatterGregorian = it
- }
+ val formatter = getGregorianFormatter(updateFormatter = updateFormatter)
return formatter.format(System.currentTimeMillis())
}
+ private fun getGregorianFormatter(updateFormatter: Boolean): DateFormat {
+ var formatter = formatterGregorian.takeIf { updateFormatter.not() } ?: DateFormat.getInstanceForSkeleton(
+ context.getString(R.string.smartspace_icu_date_pattern_gregorian_wday_month_day_no_year),
+ Locale.getDefault()
+ )
+ formatter.setContext(DisplayContext.CAPITALIZATION_FOR_STANDALONE)
+ if (showTime) {
+ var format = context.getString(
+ if (time24HourFormat) R.string.smartspace_icu_date_pattern_gregorian_time
+ else R.string.smartspace_icu_date_pattern_gregorian_time_12h
+ )
+ if (showDate) format += context.getString(R.string.smartspace_icu_date_pattern_gregorian_date)
+ DateFormat.getInstanceForSkeleton(format, Locale.getDefault()).also {
+ formatter = it
+ }.setContext(DisplayContext.CAPITALIZATION_FOR_STANDALONE)
+ }
+ formatterUpdateRequired = false
+ return formatter
+ }
+
private fun onTimeTick() {
onTimeChanged(false)
val uptimeMillis: Long = SystemClock.uptimeMillis()
@@ -91,6 +109,7 @@ class IcuDateTextView @JvmOverloads constructor(
override fun onFinishInflate() {
super.onFinishInflate()
preferenceManager2 = PreferenceManager2.getInstance(context)
+
val calendarSelectionEnabled =
preferenceManager2.enableSmartspaceCalendarSelection.firstBlocking()
if (calendarSelectionEnabled) {
@@ -100,6 +119,25 @@ class IcuDateTextView @JvmOverloads constructor(
} else {
calendar = preferenceManager2.smartspaceCalendar.defaultValue
}
+
+ preferenceManager2.smartspaceShowDate.subscribeBlocking(scope = viewAttachedScope) {
+ if (it != showDate) {
+ formatterUpdateRequired = true
+ showDate = it
+ }
+ }
+ preferenceManager2.smartspaceShowTime.subscribeBlocking(scope = viewAttachedScope) {
+ if (it != showTime) {
+ formatterUpdateRequired = true
+ showTime = it
+ }
+ }
+ preferenceManager2.smartspace24HourFormat.subscribeBlocking(scope = viewAttachedScope) {
+ if (it != time24HourFormat) {
+ formatterUpdateRequired = true
+ time24HourFormat = it
+ }
+ }
}
override fun onVisibilityAggregated(isVisible: Boolean) {
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/SmartspacePreferences.kt b/lawnchair/src/app/lawnchair/ui/preferences/SmartspacePreferences.kt
index ced93cef90..e73ea8ffab 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/SmartspacePreferences.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/SmartspacePreferences.kt
@@ -4,7 +4,12 @@ import android.app.Activity
import android.view.ContextThemeWrapper
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
+import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.Crossfade
+import androidx.compose.animation.expandVertically
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
@@ -62,11 +67,6 @@ fun SmartspacePreferences(fromWidget: Boolean) {
heading = stringResource(id = R.string.what_to_show),
modifier = Modifier.padding(top = 8.dp),
) {
- val calendarSelectionEnabled =
- preferenceManager2.enableSmartspaceCalendarSelection.getAdapter()
- if (calendarSelectionEnabled.state.value) {
- SmartspaceCalendarPreference()
- }
smartspaceProvider.dataSources
.filter { it.isAvailable }
.forEach {
@@ -78,6 +78,7 @@ fun SmartspacePreferences(fromWidget: Boolean) {
}
}
}
+ SmartspaceDateAndTimePreferences()
}
}
}
@@ -114,6 +115,62 @@ fun SmartspacePreview() {
}
}
+@Composable
+fun SmartspaceDateAndTimePreferences() {
+ PreferenceGroup(
+ heading = stringResource(id = R.string.smartspace_date_and_time),
+ modifier = Modifier.padding(top = 8.dp),
+ ) {
+ val preferenceManager2 = preferenceManager2()
+
+ val calendarAdapter = preferenceManager2.smartspaceCalendar.getAdapter()
+ val showDateAdapter = preferenceManager2.smartspaceShowDate.getAdapter()
+ val showTimeAdapter = preferenceManager2.smartspaceShowTime.getAdapter()
+ val use24HourFormatAdapter = preferenceManager2.smartspace24HourFormat.getAdapter()
+
+ val calendarHasMinimumContent = !showDateAdapter.state.value || !showTimeAdapter.state.value
+ val isGregorian = calendarAdapter.state.value != SmartspaceCalendar.Persian
+
+ AnimatedVisibility(
+ visible = isGregorian,
+ enter = expandVertically() + fadeIn(),
+ exit = shrinkVertically() + fadeOut()
+ ) {
+ SwitchPreference(
+ adapter = showDateAdapter,
+ label = stringResource(id = R.string.smartspace_date),
+ enabled = if (showDateAdapter.state.value) !calendarHasMinimumContent else true,
+ )
+ }
+ AnimatedVisibility(
+ visible = isGregorian,
+ enter = expandVertically() + fadeIn(),
+ exit = shrinkVertically() + fadeOut()
+ ) {
+ SwitchPreference(
+ adapter = showTimeAdapter,
+ label = stringResource(id = R.string.smartspace_time),
+ enabled = if (showTimeAdapter.state.value) !calendarHasMinimumContent else true,
+ )
+ }
+ AnimatedVisibility(
+ visible = isGregorian && showTimeAdapter.state.value,
+ enter = expandVertically() + fadeIn(),
+ exit = shrinkVertically() + fadeOut()
+ ) {
+ SwitchPreference(
+ adapter = use24HourFormatAdapter,
+ label = stringResource(id = R.string.smartspace_time_24_hour_format),
+ )
+ }
+ val calendarSelectionEnabled =
+ preferenceManager2.enableSmartspaceCalendarSelection.getAdapter()
+ if (calendarSelectionEnabled.state.value) {
+ SmartspaceCalendarPreference()
+ }
+ }
+}
+
@Composable
fun SmartspaceCalendarPreference() {