AnalogClock: add option to show tick marks (#1334)

* AnalogClock: add option to show tick marks

* Refactor as data class with settings in WatchFaceSelector.kt
This commit is contained in:
shtrophic 2025-07-04 12:01:08 +02:00 committed by GitHub
parent 31a1580db9
commit 8cf2d625a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 50 additions and 8 deletions

View File

@ -24,6 +24,7 @@ import androidx.compose.material.icons.rounded.AlignVerticalBottom
import androidx.compose.material.icons.rounded.AlignVerticalCenter import androidx.compose.material.icons.rounded.AlignVerticalCenter
import androidx.compose.material.icons.rounded.AlignVerticalTop import androidx.compose.material.icons.rounded.AlignVerticalTop
import androidx.compose.material.icons.rounded.AutoAwesome 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.BatteryFull
import androidx.compose.material.icons.rounded.ColorLens import androidx.compose.material.icons.rounded.ColorLens
import androidx.compose.material.icons.rounded.DarkMode import androidx.compose.material.icons.rounded.DarkMode
@ -312,7 +313,8 @@ fun Clock(
compact, compact,
showSeconds, showSeconds,
useThemeColor, useThemeColor,
darkColors darkColors,
style
) )
is ClockWidgetStyle.Orbit -> OrbitClock( is ClockWidgetStyle.Orbit -> OrbitClock(

View File

@ -147,7 +147,9 @@ fun WatchFaceSelector(
Box { Box {
androidx.compose.animation.AnimatedVisibility( 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 modifier = Modifier
.align(Alignment.TopEnd) .align(Alignment.TopEnd)
.zIndex(1f), .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) { if (selected is ClockWidgetStyle.Custom) {
DropdownMenuItem( DropdownMenuItem(
text = { Text(stringResource(R.string.widget_pick_widget)) }, text = { Text(stringResource(R.string.widget_pick_widget)) },

View File

@ -13,6 +13,7 @@ import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.drawscope.Fill import androidx.compose.ui.graphics.drawscope.Fill
import androidx.compose.ui.graphics.drawscope.rotate import androidx.compose.ui.graphics.drawscope.rotate
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import de.mm20.launcher2.preferences.ClockWidgetStyle
import de.mm20.launcher2.ui.locals.LocalDarkTheme import de.mm20.launcher2.ui.locals.LocalDarkTheme
import java.util.Calendar import java.util.Calendar
@ -23,6 +24,7 @@ fun AnalogClock(
showSeconds: Boolean, showSeconds: Boolean,
useThemeColor: Boolean, useThemeColor: Boolean,
darkColors: Boolean, darkColors: Boolean,
style: ClockWidgetStyle.Analog,
) { ) {
val verticalLayout = !compact val verticalLayout = !compact
val date = Calendar.getInstance() val date = Calendar.getInstance()
@ -66,6 +68,19 @@ fun AnalogClock(
.padding(top = if (verticalLayout) 8.dp else 0.dp, .padding(top = if (verticalLayout) 8.dp else 0.dp,
bottom = if (verticalLayout) 8.dp else 0.dp) bottom = if (verticalLayout) 8.dp else 0.dp)
.size(size)) { .size(size)) {
if (style.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) { rotate(hour.toFloat() / 12f * 360f + ((minute.toFloat() / 60f) * 30f) + (second.toFloat() / 120f), this.size.center) {
drawLine( drawLine(
color, color,

View File

@ -21,11 +21,11 @@ class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
settings.setCompact(compact) 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( listOf(
digital1, digital1,
ClockWidgetStyle.Digital2, ClockWidgetStyle.Digital2,
ClockWidgetStyle.Analog, analog,
ClockWidgetStyle.Orbit, ClockWidgetStyle.Orbit,
ClockWidgetStyle.Segment, ClockWidgetStyle.Segment,
ClockWidgetStyle.Binary, ClockWidgetStyle.Binary,

View File

@ -878,6 +878,7 @@
<string name="clock_style_empty">No clock</string> <string name="clock_style_empty">No clock</string>
<string name="clock_style_custom">Custom widget</string> <string name="clock_style_custom">Custom widget</string>
<string name="clock_variant_outlined">Outlined</string> <string name="clock_variant_outlined">Outlined</string>
<string name="clock_variant_analog_ticks">Ticks</string>
<string name="menu_show_filters">Show filters</string> <string name="menu_show_filters">Show filters</string>
<string name="menu_hide_filters">Hide filters</string> <string name="menu_hide_filters">Hide filters</string>
<string name="search_filter_tools">Tools</string> <string name="search_filter_tools">Tools</string>

View File

@ -41,6 +41,7 @@ data class LauncherSettingsData internal constructor(
@SerialName("clockWidgetStyle2") @SerialName("clockWidgetStyle2")
internal val clockWidgetStyle: ClockWidgetStyleEnum = ClockWidgetStyleEnum.Digital1, internal val clockWidgetStyle: ClockWidgetStyleEnum = ClockWidgetStyleEnum.Digital1,
val clockWidgetDigital1: ClockWidgetStyle.Digital1 = ClockWidgetStyle.Digital1(), val clockWidgetDigital1: ClockWidgetStyle.Digital1 = ClockWidgetStyle.Digital1(),
val clockWidgetAnalog: ClockWidgetStyle.Analog = ClockWidgetStyle.Analog(),
val clockWidgetCustom: ClockWidgetStyle.Custom = ClockWidgetStyle.Custom(), val clockWidgetCustom: ClockWidgetStyle.Custom = ClockWidgetStyle.Custom(),
val clockWidgetColors: ClockWidgetColors = ClockWidgetColors.Auto, val clockWidgetColors: ClockWidgetColors = ClockWidgetColors.Auto,
val clockWidgetShowSeconds: Boolean = false, val clockWidgetShowSeconds: Boolean = false,
@ -249,7 +250,9 @@ sealed interface ClockWidgetStyle {
@Serializable @Serializable
@SerialName("analog") @SerialName("analog")
data object Analog : ClockWidgetStyle data class Analog(
val showTicks: Boolean = false
) : ClockWidgetStyle
@Serializable @Serializable
@SerialName("binary") @SerialName("binary")

View File

@ -84,7 +84,7 @@ class ClockWidgetSettings internal constructor(
ClockWidgetStyleEnum.Digital1 -> it.clockWidgetDigital1 ClockWidgetStyleEnum.Digital1 -> it.clockWidgetDigital1
ClockWidgetStyleEnum.Digital2 -> ClockWidgetStyle.Digital2 ClockWidgetStyleEnum.Digital2 -> ClockWidgetStyle.Digital2
ClockWidgetStyleEnum.Orbit -> ClockWidgetStyle.Orbit ClockWidgetStyleEnum.Orbit -> ClockWidgetStyle.Orbit
ClockWidgetStyleEnum.Analog -> ClockWidgetStyle.Analog ClockWidgetStyleEnum.Analog -> it.clockWidgetAnalog
ClockWidgetStyleEnum.Binary -> ClockWidgetStyle.Binary ClockWidgetStyleEnum.Binary -> ClockWidgetStyle.Binary
ClockWidgetStyleEnum.Segment -> ClockWidgetStyle.Segment ClockWidgetStyleEnum.Segment -> ClockWidgetStyle.Segment
ClockWidgetStyleEnum.Empty -> ClockWidgetStyle.Empty ClockWidgetStyleEnum.Empty -> ClockWidgetStyle.Empty
@ -95,6 +95,9 @@ class ClockWidgetSettings internal constructor(
val digital1: Flow<ClockWidgetStyle.Digital1> val digital1: Flow<ClockWidgetStyle.Digital1>
get() = launcherDataStore.data.map { it.clockWidgetDigital1 } get() = launcherDataStore.data.map { it.clockWidgetDigital1 }
val analog: Flow<ClockWidgetStyle.Analog>
get() = launcherDataStore.data.map { it.clockWidgetAnalog }
val custom: Flow<ClockWidgetStyle.Custom> val custom: Flow<ClockWidgetStyle.Custom>
get() = launcherDataStore.data.map { it.clockWidgetCustom } get() = launcherDataStore.data.map { it.clockWidgetCustom }
@ -102,8 +105,9 @@ class ClockWidgetSettings internal constructor(
launcherDataStore.update { launcherDataStore.update {
it.copy( it.copy(
clockWidgetStyle = clockStyle.enumValue, clockWidgetStyle = clockStyle.enumValue,
clockWidgetDigital1 = if (clockStyle is ClockWidgetStyle.Digital1) clockStyle else it.clockWidgetDigital1, clockWidgetDigital1 = clockStyle as? ClockWidgetStyle.Digital1 ?: it.clockWidgetDigital1,
clockWidgetCustom = if (clockStyle is ClockWidgetStyle.Custom) clockStyle else it.clockWidgetCustom, clockWidgetAnalog = clockStyle as? ClockWidgetStyle.Analog ?: it.clockWidgetAnalog,
clockWidgetCustom = clockStyle as? ClockWidgetStyle.Custom ?: it.clockWidgetCustom,
) )
} }
} }