From e419aeb795bfb1d437db6bcd394b5b1e71637300 Mon Sep 17 00:00:00 2001 From: Christoph Liebender Date: Wed, 2 Apr 2025 17:47:53 +0200 Subject: [PATCH 1/2] AnalogClock: add option to show tick marks --- .../ui/launcher/widgets/clock/ClockWidget.kt | 18 +++++++++++++++++- .../widgets/clock/clocks/AnalogClock.kt | 14 ++++++++++++++ .../clockwidget/ClockWidgetSettingsScreenVM.kt | 7 +++++++ core/i18n/src/main/res/values/strings.xml | 1 + .../preferences/LauncherSettingsData.kt | 1 + .../preferences/ui/ClockWidgetSettings.kt | 9 +++++++++ 6 files changed, 49 insertions(+), 1 deletion(-) diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt index 2416990c9..65e3ac82d 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt @@ -24,6 +24,7 @@ import androidx.compose.material.icons.rounded.AlignVerticalBottom import androidx.compose.material.icons.rounded.AlignVerticalCenter import androidx.compose.material.icons.rounded.AlignVerticalTop import androidx.compose.material.icons.rounded.AutoAwesome +import androidx.compose.material.icons.rounded.AvTimer import androidx.compose.material.icons.rounded.BatteryFull import androidx.compose.material.icons.rounded.ColorLens import androidx.compose.material.icons.rounded.DarkMode @@ -274,6 +275,7 @@ fun Clock( val showSeconds by clockSettings.showSeconds.collectAsState(initial = false) val useThemeColor by clockSettings.useThemeColor.collectAsState(initial = false) val timeFormat by clockSettings.timeFormat.collectAsState(null) + val analogShowTicks by clockSettings.analogShowTicks.collectAsState(false) if (timeFormat == null) return @@ -312,7 +314,8 @@ fun Clock( compact, showSeconds, useThemeColor, - darkColors + darkColors, + analogShowTicks ) is ClockWidgetStyle.Orbit -> OrbitClock( @@ -363,6 +366,7 @@ fun ConfigureClockWidgetSheet( val fillHeight by viewModel.fillHeight.collectAsState() val alignment by viewModel.alignment.collectAsState() val showSeconds by viewModel.showSeconds.collectAsState() + val analogShowTicks by viewModel.analogShowTicks.collectAsState() val timeFormat by viewModel.timeFormat.collectAsState() val useAccentColor by viewModel.useThemeColor.collectAsState() val parts by viewModel.parts.collectAsState() @@ -510,6 +514,18 @@ fun ConfigureClockWidgetSheet( } ) } + AnimatedVisibility( + style is ClockWidgetStyle.Analog + ) { + SwitchPreference( + title = stringResource(R.string.preference_clock_widget_analog_show_ticks), + icon = Icons.Rounded.AvTimer, + onValueChanged = { + viewModel.setAnalogShowTicks(it) + }, + value = analogShowTicks + ) + } AnimatedVisibility( style !is ClockWidgetStyle.Analog && style !is ClockWidgetStyle.Custom && diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/clocks/AnalogClock.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/clocks/AnalogClock.kt index 9326cb740..05bd6445f 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/clocks/AnalogClock.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/clocks/AnalogClock.kt @@ -23,6 +23,7 @@ fun AnalogClock( showSeconds: Boolean, useThemeColor: Boolean, darkColors: Boolean, + showTicks: Boolean, ) { val verticalLayout = !compact val date = Calendar.getInstance() @@ -66,6 +67,19 @@ fun AnalogClock( .padding(top = if (verticalLayout) 8.dp else 0.dp, bottom = if (verticalLayout) 8.dp else 0.dp) .size(size)) { + if (showTicks) { + for (hour in 0.. 11) { + rotate(hour.toFloat() / 12f * 360f, this.size.center) { + drawLine( + secondaryColor, + this.size.center.copy(y = this.size.height * 0.95f), + this.size.center.copy(y = this.size.height), + strokeWidth = (strokeWidth * 0.75f).toPx(), + cap = StrokeCap.Round + ) + } + } + } rotate(hour.toFloat() / 12f * 360f + ((minute.toFloat() / 60f) * 30f) + (second.toFloat() / 120f), this.size.center) { drawLine( color, diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/clockwidget/ClockWidgetSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/clockwidget/ClockWidgetSettingsScreenVM.kt index e123b7f4b..7b13a28e1 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/clockwidget/ClockWidgetSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/clockwidget/ClockWidgetSettingsScreenVM.kt @@ -55,6 +55,13 @@ class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent { settings.setShowSeconds(showSeconds) } + val analogShowTicks = settings.analogShowTicks + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false) + + fun setAnalogShowTicks(analogShowTicks: Boolean) { + settings.setAnalogShowTicks(analogShowTicks) + } + val timeFormat = settings.timeFormat .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), TimeFormat.System) diff --git a/core/i18n/src/main/res/values/strings.xml b/core/i18n/src/main/res/values/strings.xml index e57c7b4f3..6af7c7e69 100644 --- a/core/i18n/src/main/res/values/strings.xml +++ b/core/i18n/src/main/res/values/strings.xml @@ -569,6 +569,7 @@ Default Compact Show seconds + Show tick marks Time format 24-hour 12-hour diff --git a/core/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherSettingsData.kt b/core/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherSettingsData.kt index 43c01e92e..bc610b146 100644 --- a/core/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherSettingsData.kt +++ b/core/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherSettingsData.kt @@ -34,6 +34,7 @@ data class LauncherSettingsData internal constructor( val clockWidgetCustom: ClockWidgetStyle.Custom = ClockWidgetStyle.Custom(), val clockWidgetColors: ClockWidgetColors = ClockWidgetColors.Auto, val clockWidgetShowSeconds: Boolean = false, + val clockWidgetAnalogShowTicks: Boolean = false, val clockWidgetTimeFormat: TimeFormat = TimeFormat.System, val clockWidgetUseThemeColor: Boolean = false, val clockWidgetAlarmPart: Boolean = true, diff --git a/core/preferences/src/main/java/de/mm20/launcher2/preferences/ui/ClockWidgetSettings.kt b/core/preferences/src/main/java/de/mm20/launcher2/preferences/ui/ClockWidgetSettings.kt index d12094e6f..3361f3914 100644 --- a/core/preferences/src/main/java/de/mm20/launcher2/preferences/ui/ClockWidgetSettings.kt +++ b/core/preferences/src/main/java/de/mm20/launcher2/preferences/ui/ClockWidgetSettings.kt @@ -138,6 +138,15 @@ class ClockWidgetSettings internal constructor( } } + val analogShowTicks + get() = launcherDataStore.data.map { it.clockWidgetAnalogShowTicks } + + fun setAnalogShowTicks(enabled: Boolean) { + launcherDataStore.update { + it.copy(clockWidgetAnalogShowTicks = enabled) + } + } + val timeFormat get() = launcherDataStore.data.map { it.clockWidgetTimeFormat } From abf567300d6a9529f859214426a79d391dfbeadb Mon Sep 17 00:00:00 2001 From: Christoph Liebender Date: Thu, 3 Apr 2025 18:44:12 +0200 Subject: [PATCH 2/2] Refactor as data class with settings in WatchFaceSelector.kt --- .../ui/launcher/widgets/clock/ClockWidget.kt | 16 +--------------- .../widgets/clock/WatchFaceSelector.kt | 19 ++++++++++++++++++- .../widgets/clock/clocks/AnalogClock.kt | 5 +++-- .../ClockWidgetSettingsScreenVM.kt | 11 ++--------- core/i18n/src/main/res/values/strings.xml | 2 +- .../preferences/LauncherSettingsData.kt | 6 ++++-- .../preferences/ui/ClockWidgetSettings.kt | 19 +++++++------------ 7 files changed, 36 insertions(+), 42 deletions(-) diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt index 65e3ac82d..d3dbe2053 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt @@ -275,7 +275,6 @@ fun Clock( val showSeconds by clockSettings.showSeconds.collectAsState(initial = false) val useThemeColor by clockSettings.useThemeColor.collectAsState(initial = false) val timeFormat by clockSettings.timeFormat.collectAsState(null) - val analogShowTicks by clockSettings.analogShowTicks.collectAsState(false) if (timeFormat == null) return @@ -315,7 +314,7 @@ fun Clock( showSeconds, useThemeColor, darkColors, - analogShowTicks + style ) is ClockWidgetStyle.Orbit -> OrbitClock( @@ -366,7 +365,6 @@ fun ConfigureClockWidgetSheet( val fillHeight by viewModel.fillHeight.collectAsState() val alignment by viewModel.alignment.collectAsState() val showSeconds by viewModel.showSeconds.collectAsState() - val analogShowTicks by viewModel.analogShowTicks.collectAsState() val timeFormat by viewModel.timeFormat.collectAsState() val useAccentColor by viewModel.useThemeColor.collectAsState() val parts by viewModel.parts.collectAsState() @@ -514,18 +512,6 @@ fun ConfigureClockWidgetSheet( } ) } - AnimatedVisibility( - style is ClockWidgetStyle.Analog - ) { - SwitchPreference( - title = stringResource(R.string.preference_clock_widget_analog_show_ticks), - icon = Icons.Rounded.AvTimer, - onValueChanged = { - viewModel.setAnalogShowTicks(it) - }, - value = analogShowTicks - ) - } AnimatedVisibility( style !is ClockWidgetStyle.Analog && style !is ClockWidgetStyle.Custom && diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/WatchFaceSelector.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/WatchFaceSelector.kt index 6d483211e..0b392d2e5 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/WatchFaceSelector.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/WatchFaceSelector.kt @@ -147,7 +147,9 @@ fun WatchFaceSelector( Box { androidx.compose.animation.AnimatedVisibility( - selected is ClockWidgetStyle.Digital1 || (selected is ClockWidgetStyle.Custom && selected.widgetId != null), + selected is ClockWidgetStyle.Digital1 || + selected is ClockWidgetStyle.Analog || + (selected is ClockWidgetStyle.Custom && selected.widgetId != null), modifier = Modifier .align(Alignment.TopEnd) .zIndex(1f), @@ -179,6 +181,21 @@ fun WatchFaceSelector( } ) } + if (selected is ClockWidgetStyle.Analog) { + DropdownMenuItem( + text = { Text(stringResource(R.string.clock_variant_analog_ticks)) }, + leadingIcon = { + Icon( + if (selected.showTicks) Icons.Rounded.CheckCircle + else Icons.Rounded.RadioButtonUnchecked, + null + ) + }, + onClick = { + onSelect(selected.copy(showTicks = !selected.showTicks)) + } + ) + } if (selected is ClockWidgetStyle.Custom) { DropdownMenuItem( text = { Text(stringResource(R.string.widget_pick_widget)) }, diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/clocks/AnalogClock.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/clocks/AnalogClock.kt index 05bd6445f..f113b146c 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/clocks/AnalogClock.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/clocks/AnalogClock.kt @@ -13,6 +13,7 @@ import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.graphics.drawscope.Fill import androidx.compose.ui.graphics.drawscope.rotate import androidx.compose.ui.unit.dp +import de.mm20.launcher2.preferences.ClockWidgetStyle import de.mm20.launcher2.ui.locals.LocalDarkTheme import java.util.Calendar @@ -23,7 +24,7 @@ fun AnalogClock( showSeconds: Boolean, useThemeColor: Boolean, darkColors: Boolean, - showTicks: Boolean, + style: ClockWidgetStyle.Analog, ) { val verticalLayout = !compact val date = Calendar.getInstance() @@ -67,7 +68,7 @@ fun AnalogClock( .padding(top = if (verticalLayout) 8.dp else 0.dp, bottom = if (verticalLayout) 8.dp else 0.dp) .size(size)) { - if (showTicks) { + if (style.showTicks) { for (hour in 0.. 11) { rotate(hour.toFloat() / 12f * 360f, this.size.center) { drawLine( diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/clockwidget/ClockWidgetSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/clockwidget/ClockWidgetSettingsScreenVM.kt index 7b13a28e1..3c18af807 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/clockwidget/ClockWidgetSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/clockwidget/ClockWidgetSettingsScreenVM.kt @@ -22,11 +22,11 @@ class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent { settings.setCompact(compact) } - val availableClockStyles = combine(settings.digital1, settings.custom) { digital1, custom -> + val availableClockStyles = combine(settings.digital1, settings.analog, settings.custom) { digital1, analog, custom -> listOf( digital1, ClockWidgetStyle.Digital2, - ClockWidgetStyle.Analog, + analog, ClockWidgetStyle.Orbit, ClockWidgetStyle.Segment, ClockWidgetStyle.Binary, @@ -55,13 +55,6 @@ class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent { settings.setShowSeconds(showSeconds) } - val analogShowTicks = settings.analogShowTicks - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false) - - fun setAnalogShowTicks(analogShowTicks: Boolean) { - settings.setAnalogShowTicks(analogShowTicks) - } - val timeFormat = settings.timeFormat .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), TimeFormat.System) diff --git a/core/i18n/src/main/res/values/strings.xml b/core/i18n/src/main/res/values/strings.xml index 6af7c7e69..90a32dcc9 100644 --- a/core/i18n/src/main/res/values/strings.xml +++ b/core/i18n/src/main/res/values/strings.xml @@ -569,7 +569,6 @@ Default Compact Show seconds - Show tick marks Time format 24-hour 12-hour @@ -862,6 +861,7 @@ No clock Custom widget Outlined + Ticks Show filters Hide filters Tools diff --git a/core/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherSettingsData.kt b/core/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherSettingsData.kt index bc610b146..15f3eba05 100644 --- a/core/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherSettingsData.kt +++ b/core/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherSettingsData.kt @@ -31,10 +31,10 @@ data class LauncherSettingsData internal constructor( @SerialName("clockWidgetStyle2") internal val clockWidgetStyle: ClockWidgetStyleEnum = ClockWidgetStyleEnum.Digital1, val clockWidgetDigital1: ClockWidgetStyle.Digital1 = ClockWidgetStyle.Digital1(), + val clockWidgetAnalog: ClockWidgetStyle.Analog = ClockWidgetStyle.Analog(), val clockWidgetCustom: ClockWidgetStyle.Custom = ClockWidgetStyle.Custom(), val clockWidgetColors: ClockWidgetColors = ClockWidgetColors.Auto, val clockWidgetShowSeconds: Boolean = false, - val clockWidgetAnalogShowTicks: Boolean = false, val clockWidgetTimeFormat: TimeFormat = TimeFormat.System, val clockWidgetUseThemeColor: Boolean = false, val clockWidgetAlarmPart: Boolean = true, @@ -249,7 +249,9 @@ sealed interface ClockWidgetStyle { @Serializable @SerialName("analog") - data object Analog : ClockWidgetStyle + data class Analog( + val showTicks: Boolean = false + ) : ClockWidgetStyle @Serializable @SerialName("binary") diff --git a/core/preferences/src/main/java/de/mm20/launcher2/preferences/ui/ClockWidgetSettings.kt b/core/preferences/src/main/java/de/mm20/launcher2/preferences/ui/ClockWidgetSettings.kt index 3361f3914..c19b39978 100644 --- a/core/preferences/src/main/java/de/mm20/launcher2/preferences/ui/ClockWidgetSettings.kt +++ b/core/preferences/src/main/java/de/mm20/launcher2/preferences/ui/ClockWidgetSettings.kt @@ -96,7 +96,7 @@ class ClockWidgetSettings internal constructor( ClockWidgetStyleEnum.Digital1 -> it.clockWidgetDigital1 ClockWidgetStyleEnum.Digital2 -> ClockWidgetStyle.Digital2 ClockWidgetStyleEnum.Orbit -> ClockWidgetStyle.Orbit - ClockWidgetStyleEnum.Analog -> ClockWidgetStyle.Analog + ClockWidgetStyleEnum.Analog -> it.clockWidgetAnalog ClockWidgetStyleEnum.Binary -> ClockWidgetStyle.Binary ClockWidgetStyleEnum.Segment -> ClockWidgetStyle.Segment ClockWidgetStyleEnum.Empty -> ClockWidgetStyle.Empty @@ -107,6 +107,9 @@ class ClockWidgetSettings internal constructor( val digital1: Flow get() = launcherDataStore.data.map { it.clockWidgetDigital1 } + val analog: Flow + get() = launcherDataStore.data.map { it.clockWidgetAnalog } + val custom: Flow get() = launcherDataStore.data.map { it.clockWidgetCustom } @@ -114,8 +117,9 @@ class ClockWidgetSettings internal constructor( launcherDataStore.update { it.copy( clockWidgetStyle = clockStyle.enumValue, - clockWidgetDigital1 = if (clockStyle is ClockWidgetStyle.Digital1) clockStyle else it.clockWidgetDigital1, - clockWidgetCustom = if (clockStyle is ClockWidgetStyle.Custom) clockStyle else it.clockWidgetCustom, + clockWidgetDigital1 = clockStyle as? ClockWidgetStyle.Digital1 ?: it.clockWidgetDigital1, + clockWidgetAnalog = clockStyle as? ClockWidgetStyle.Analog ?: it.clockWidgetAnalog, + clockWidgetCustom = clockStyle as? ClockWidgetStyle.Custom ?: it.clockWidgetCustom, ) } } @@ -138,15 +142,6 @@ class ClockWidgetSettings internal constructor( } } - val analogShowTicks - get() = launcherDataStore.data.map { it.clockWidgetAnalogShowTicks } - - fun setAnalogShowTicks(enabled: Boolean) { - launcherDataStore.update { - it.copy(clockWidgetAnalogShowTicks = enabled) - } - } - val timeFormat get() = launcherDataStore.data.map { it.clockWidgetTimeFormat }