diff --git a/lawnchair/res/values/config.xml b/lawnchair/res/values/config.xml
index d83152f463..cb5827a882 100644
--- a/lawnchair/res/values/config.xml
+++ b/lawnchair/res/values/config.xml
@@ -44,6 +44,9 @@
circle
+
+ gregorian
+
false
true
false
diff --git a/lawnchair/res/values/strings.xml b/lawnchair/res/values/strings.xml
index 0673aebc77..f92c759b49 100644
--- a/lawnchair/res/values/strings.xml
+++ b/lawnchair/res/values/strings.xml
@@ -233,7 +233,8 @@
%1$s, %2$s
- EEEMMMd
+ EEEMMMd
+ l، j F
Charging
Charged
Battery Low
@@ -245,6 +246,7 @@
Your device is configured to have system gestures (known as Quickstep) provided by %1$s, but this version of %1$s is not compatible with your Android version. To continue using your device, please uninstall %1$s updates or disable %1$s as a system-gesture provider.
Preview
+ Calendar
Weather
Battery Status
Now Playing
@@ -252,6 +254,9 @@
To use %1$s, enable Notification Dots.
" — "
+ Gregorian
+ Persian
+
Add Fonts
OTF & TTF supported.
Delete
diff --git a/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt b/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt
index 0b545cb69a..b84e97d2b9 100644
--- a/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt
+++ b/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt
@@ -26,6 +26,7 @@ import app.lawnchair.icons.CustomAdaptiveIconDrawable
import app.lawnchair.icons.shape.IconShape
import app.lawnchair.icons.shape.IconShapeManager
import app.lawnchair.qsb.providers.QsbSearchProvider
+import app.lawnchair.smartspace.model.SmartspaceCalendar
import app.lawnchair.theme.color.ColorOption
import com.android.launcher3.InvariantDeviceProfile
import com.android.launcher3.LauncherAppState
@@ -276,6 +277,13 @@ class PreferenceManager2(private val context: Context) : PreferenceManager {
defaultValue = true
)
+ val smartspaceCalendar = preference(
+ key = stringPreferencesKey(name = "smartspace_calendar"),
+ defaultValue = SmartspaceCalendar.fromString(context.getString(R.string.config_default_smart_space_calendar)),
+ parse = { SmartspaceCalendar.fromString(it) },
+ save = { it.toString() },
+ )
+
init {
initializeIconShape(iconShape.firstBlocking())
iconShape.get()
diff --git a/lawnchair/src/app/lawnchair/smartspace/IcuDateTextView.kt b/lawnchair/src/app/lawnchair/smartspace/IcuDateTextView.kt
index 4afcbb081d..9d446e853f 100644
--- a/lawnchair/src/app/lawnchair/smartspace/IcuDateTextView.kt
+++ b/lawnchair/src/app/lawnchair/smartspace/IcuDateTextView.kt
@@ -8,14 +8,23 @@ import android.icu.text.DateFormat
import android.icu.text.DisplayContext
import android.os.SystemClock
import android.util.AttributeSet
+import app.lawnchair.preferences2.PreferenceManager2
+import app.lawnchair.preferences2.subscribeBlocking
+import app.lawnchair.smartspace.model.SmartspaceCalendar
+import app.lawnchair.util.viewAttachedScope
import com.android.launcher3.R
+import saman.zamani.persiandate.PersianDate
+import saman.zamani.persiandate.PersianDateFormat
import java.util.*
class IcuDateTextView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : DoubleShadowTextView(context, attrs) {
- private var formatter: DateFormat? = null
+ private lateinit var preferenceManager2: PreferenceManager2
+ private var calendar: SmartspaceCalendar? = null
+ private var formatterGregorian: DateFormat? = null
+ private var formatterPersian: PersianDateFormat? = null
private val ticker = this::onTimeTick
private val intentReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
@@ -39,27 +48,50 @@ class IcuDateTextView @JvmOverloads constructor(
private fun onTimeChanged(updateFormatter: Boolean) {
if (isShown) {
- if (formatter == null || updateFormatter) {
- val formatter: DateFormat = DateFormat.getInstanceForSkeleton(
- context.getString(R.string.smartspace_icu_date_pattern), Locale.getDefault()
- )
- this.formatter = formatter
- formatter.setContext(DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE)
+ val format = when (calendar) {
+ SmartspaceCalendar.Persian -> getTimeTextPersian(updateFormatter = updateFormatter)
+ else -> getTimeTextGregorian(updateFormatter = updateFormatter)
}
- val format = formatter!!.format(java.lang.Long.valueOf(System.currentTimeMillis()))
if (text != format) {
+ textAlignment =
+ if (calendar == SmartspaceCalendar.Persian) TEXT_ALIGNMENT_TEXT_END else TEXT_ALIGNMENT_TEXT_START
text = format
contentDescription = format
}
}
}
+ private fun getTimeTextPersian(updateFormatter: Boolean): String {
+ val formatter = formatterPersian.takeIf { updateFormatter.not() } ?: PersianDateFormat(
+ context.getString(R.string.smartspace_icu_date_pattern_persian),
+ PersianDateFormat.PersianDateNumberCharacter.FARSI,
+ ).also { formatterPersian = it }
+ return formatter.format(PersianDate(java.lang.Long.valueOf(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 { formatterGregorian = it }
+ return formatter.format(java.lang.Long.valueOf(System.currentTimeMillis()))
+ }
+
private fun onTimeTick() {
onTimeChanged(false)
val uptimeMillis: Long = SystemClock.uptimeMillis()
handler?.postAtTime(ticker, uptimeMillis + (1000 - uptimeMillis % 1000))
}
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ preferenceManager2 = PreferenceManager2.getInstance(context)
+ preferenceManager2.smartspaceCalendar.subscribeBlocking(scope = viewAttachedScope) {
+ calendar = it
+ }
+ }
+
override fun onVisibilityAggregated(isVisible: Boolean) {
super.onVisibilityAggregated(isVisible)
handler?.removeCallbacks(ticker)
diff --git a/lawnchair/src/app/lawnchair/smartspace/model/SmartspaceCalendar.kt b/lawnchair/src/app/lawnchair/smartspace/model/SmartspaceCalendar.kt
new file mode 100644
index 0000000000..3b67e1e0fb
--- /dev/null
+++ b/lawnchair/src/app/lawnchair/smartspace/model/SmartspaceCalendar.kt
@@ -0,0 +1,31 @@
+package app.lawnchair.smartspace.model
+
+import androidx.annotation.StringRes
+import com.android.launcher3.R
+
+/**
+ * Contains the data of a single calendar system for smartspace.
+ */
+open class SmartspaceCalendar(@StringRes val nameResourceId: Int) {
+
+ companion object {
+
+ fun fromString(value: String): SmartspaceCalendar = when (value) {
+ "persian" -> Persian
+ else -> Gregorian
+ }
+
+ /**
+ * @return The list of all calendars.
+ */
+ fun values() = listOf(Gregorian, Persian)
+ }
+
+ object Gregorian : SmartspaceCalendar(nameResourceId = R.string.smartspace_calendar_gregorian) {
+ override fun toString() = "gregorian"
+ }
+ object Persian : SmartspaceCalendar(nameResourceId = R.string.smartspace_calendar_persian) {
+ override fun toString() = "persian"
+ }
+
+}
\ No newline at end of file
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/SmartspacePreferences.kt b/lawnchair/src/app/lawnchair/ui/preferences/SmartspacePreferences.kt
index 6648d5a5a9..4a9630bfd0 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/SmartspacePreferences.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/SmartspacePreferences.kt
@@ -21,7 +21,10 @@ import androidx.navigation.NavGraphBuilder
import app.lawnchair.preferences.getAdapter
import app.lawnchair.preferences2.preferenceManager2
import app.lawnchair.smartspace.SmartspaceViewContainer
+import app.lawnchair.smartspace.model.SmartspaceCalendar
import app.lawnchair.smartspace.provider.SmartspaceProvider
+import app.lawnchair.ui.preferences.components.ListPreference
+import app.lawnchair.ui.preferences.components.ListPreferenceEntry
import app.lawnchair.ui.preferences.components.PreferenceGroup
import app.lawnchair.ui.preferences.components.PreferenceLayout
import app.lawnchair.ui.preferences.components.SwitchPreference
@@ -59,6 +62,7 @@ fun SmartspacePreferences(fromWidget: Boolean) {
heading = stringResource(id = R.string.what_to_show),
modifier = Modifier.padding(top = 8.dp),
) {
+ SmartspaceCalendarPreference()
smartspaceProvider.dataSources
.filter { it.isAvailable }
.forEach {
@@ -105,3 +109,22 @@ fun SmartspacePreview() {
}
}
}
+
+@Composable
+fun SmartspaceCalendarPreference() {
+
+ val entries = remember {
+ SmartspaceCalendar.values().map { calendar ->
+ ListPreferenceEntry(calendar) { stringResource(id = calendar.nameResourceId) }
+ }
+ }
+
+ val adapter = preferenceManager2().smartspaceCalendar.getAdapter()
+
+ ListPreference(
+ adapter = adapter,
+ entries = entries,
+ label = stringResource(id = R.string.smartspace_calendar),
+ )
+}
+