Add style to BinaryClock for 24-hour time (#1190)

* Add style to BinaryClock for 24-hour time

* Use global time format preference for all clock widget styles

* Add support for time format preference to remaining clock styles

---------

Co-authored-by: MM20 <15646950+MM2-0@users.noreply.github.com>
This commit is contained in:
Oscar Ronberg 2025-02-25 04:56:19 +11:00 committed by GitHub
parent 4330b2a712
commit 5240431348
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 158 additions and 44 deletions

View File

@ -31,6 +31,7 @@ import androidx.compose.material.icons.rounded.Height
import androidx.compose.material.icons.rounded.HorizontalSplit
import androidx.compose.material.icons.rounded.LightMode
import androidx.compose.material.icons.rounded.MusicNote
import androidx.compose.material.icons.rounded.Timer
import androidx.compose.material.icons.rounded.Today
import androidx.compose.material.icons.rounded.Tune
import androidx.compose.material.icons.rounded.VerticalSplit
@ -67,6 +68,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.preferences.ClockWidgetAlignment
import de.mm20.launcher2.preferences.ClockWidgetColors
import de.mm20.launcher2.preferences.ClockWidgetStyle
import de.mm20.launcher2.preferences.TimeFormat
import de.mm20.launcher2.preferences.ui.ClockWidgetSettings
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.base.LocalTime
@ -83,6 +85,7 @@ import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.SegmentClock
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.PartProvider
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
import de.mm20.launcher2.ui.settings.clockwidget.ClockWidgetSettingsScreenVM
import de.mm20.launcher2.ui.utils.isTwentyFourHours
import org.koin.androidx.compose.inject
@Composable
@ -164,7 +167,8 @@ fun ClockWidget(
Box(
modifier = Modifier
.then(if (fillScreenHeight) Modifier.weight(1f) else Modifier)
.fillMaxWidth().padding(horizontal = if (compact == true) 0.dp else 24.dp),
.fillMaxWidth()
.padding(horizontal = if (compact == true) 0.dp else 24.dp),
contentAlignment = when (alignment) {
ClockWidgetAlignment.Center -> Alignment.Center
ClockWidgetAlignment.Top -> Alignment.TopCenter
@ -265,34 +269,42 @@ fun Clock(
darkColors: Boolean = false
) {
val time = LocalTime.current
val context = LocalContext.current
val clockSettings: ClockWidgetSettings by inject()
val showSeconds by clockSettings.showSeconds.collectAsState(initial = false)
val useThemeColor by clockSettings.useThemeColor.collectAsState(initial = false)
val timeFormat by clockSettings.timeFormat.collectAsState(null)
if (timeFormat == null) return
val isTwentyFourHours = timeFormat!!.isTwentyFourHours(context)
when (style) {
is ClockWidgetStyle.Digital1 -> DigitalClock1(
time,
style,
compact,
showSeconds,
useThemeColor,
darkColors
time = time,
compact = compact,
showSeconds = showSeconds,
twentyFourHours = isTwentyFourHours,
useThemeColor = useThemeColor,
darkColors = darkColors,
)
is ClockWidgetStyle.Digital2 -> DigitalClock2(
time,
compact,
showSeconds,
useThemeColor,
darkColors
time = time,
compact = compact,
showSeconds = showSeconds,
twentyFourHours = isTwentyFourHours,
useThemeColor = useThemeColor,
darkColors = darkColors,
)
is ClockWidgetStyle.Binary -> BinaryClock(
time,
compact,
showSeconds,
useThemeColor,
darkColors
time = time,
compact = compact,
showSeconds = showSeconds,
twentyFourHours = isTwentyFourHours,
useThemeColor = useThemeColor,
darkColors = darkColors,
)
is ClockWidgetStyle.Analog -> AnalogClock(
@ -304,19 +316,21 @@ fun Clock(
)
is ClockWidgetStyle.Orbit -> OrbitClock(
time,
compact,
showSeconds,
useThemeColor,
darkColors
time = time,
compact = compact,
showSeconds = showSeconds,
twentyFourHours = isTwentyFourHours,
useThemeColor = useThemeColor,
darkColors = darkColors,
)
is ClockWidgetStyle.Segment -> SegmentClock(
time,
compact,
showSeconds,
useThemeColor,
darkColors
time = time,
compact = compact,
showSeconds = showSeconds,
twentyFourHours = isTwentyFourHours,
useThemeColor = useThemeColor,
darkColors = darkColors,
)
is ClockWidgetStyle.Custom -> CustomClock(style, compact, useThemeColor, darkColors)
@ -349,6 +363,7 @@ fun ConfigureClockWidgetSheet(
val fillHeight by viewModel.fillHeight.collectAsState()
val alignment by viewModel.alignment.collectAsState()
val showSeconds by viewModel.showSeconds.collectAsState()
val timeFormat by viewModel.timeFormat.collectAsState()
val useAccentColor by viewModel.useThemeColor.collectAsState()
val parts by viewModel.parts.collectAsState()
@ -488,13 +503,63 @@ fun ConfigureClockWidgetSheet(
AnimatedVisibility(compact == false && style !is ClockWidgetStyle.Custom) {
SwitchPreference(
title = stringResource(R.string.preference_clock_widget_show_seconds),
icon = Icons.Rounded.AccessTime,
icon = Icons.Rounded.Timer,
value = showSeconds,
onValueChanged = {
viewModel.setShowSeconds(it)
}
)
}
AnimatedVisibility(
style !is ClockWidgetStyle.Analog &&
style !is ClockWidgetStyle.Custom &&
style !is ClockWidgetStyle.Empty
) {
var showDropdown by remember { mutableStateOf(false) }
Preference(
title = stringResource(R.string.preference_clock_widget_time_format),
summary = when (timeFormat) {
TimeFormat.TwelveHour -> stringResource(R.string.preference_clock_widget_time_format_12h)
TimeFormat.TwentyFourHour -> stringResource(R.string.preference_clock_widget_time_format_24h)
TimeFormat.System -> stringResource(R.string.preference_clock_widget_time_format_system)
},
icon = Icons.Rounded.AccessTime,
onClick = {
showDropdown = true
}
)
DropdownMenu(
expanded = showDropdown,
onDismissRequest = { showDropdown = false }) {
DropdownMenuItem(
text = {
Text(stringResource(R.string.preference_clock_widget_time_format_system))
},
onClick = {
viewModel.setTimeFormat(TimeFormat.System)
showDropdown = false
}
)
DropdownMenuItem(
text = {
Text(stringResource(R.string.preference_clock_widget_time_format_24h))
},
onClick = {
viewModel.setTimeFormat(TimeFormat.TwentyFourHour)
showDropdown = false
}
)
DropdownMenuItem(
text = {
Text(stringResource(R.string.preference_clock_widget_time_format_12h))
},
onClick = {
viewModel.setTimeFormat(TimeFormat.TwelveHour)
showDropdown = false
}
)
}
}
}
}
OutlinedCard(

View File

@ -13,14 +13,19 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import de.mm20.launcher2.preferences.ClockWidgetStyle
import de.mm20.launcher2.preferences.TimeFormat
import de.mm20.launcher2.ui.locals.LocalDarkTheme
import de.mm20.launcher2.ui.utils.isTwentyFourHours
import java.util.Calendar
@Composable
fun BinaryClock(
time: Long,
compact: Boolean,
twentyFourHours: Boolean,
showSeconds: Boolean,
useThemeColor: Boolean,
darkColors: Boolean,
@ -30,8 +35,8 @@ fun BinaryClock(
date.timeInMillis = time
val second = date[Calendar.SECOND]
val minute = date[Calendar.MINUTE]
var hour = date[Calendar.HOUR]
if (hour == 0) hour = 12
var hour = date[if(!twentyFourHours) Calendar.HOUR else Calendar.HOUR_OF_DAY]
if (!twentyFourHours && hour == 0) hour = 12
val color = if (useThemeColor) {
if (!darkColors) {
@ -56,11 +61,11 @@ fun BinaryClock(
Row(
modifier = Modifier.padding(start = 0.dp, top = 24.dp, end = 0.dp, bottom = 6.dp)
) {
for (i in 0 until 10) {
val active = if (i < 4) {
hour and (1 shl (3 - i)) != 0
for (i in 0 until if (twentyFourHours) 11 else 10) {
val active = if (i < if (twentyFourHours) 5 else 4) {
hour and (1 shl ((if (twentyFourHours) 4 else 3) - i)) != 0
} else {
minute and (1 shl (9 - i)) != 0
minute and (1 shl ((if (twentyFourHours) 10 else 9) - i)) != 0
}
Box(
modifier = Modifier
@ -70,7 +75,7 @@ fun BinaryClock(
if (active) color else disabledColor
)
)
if (i == 3) {
if (i == if (twentyFourHours) 4 else 3) {
Box(Modifier.size(8.dp))
}
}
@ -98,8 +103,8 @@ fun BinaryClock(
horizontalAlignment = Alignment.End
) {
Row {
for (i in 0 until 4) {
val active = hour and (1 shl (3 - i)) != 0
for (i in 0 until if (twentyFourHours) 5 else 4) {
val active = hour and (1 shl ((if (twentyFourHours) 4 else 3) - i)) != 0
Box(
modifier = Modifier
.padding( 4.dp)

View File

@ -33,6 +33,7 @@ fun DigitalClock1(
time: Long,
style: ClockWidgetStyle.Digital1 = ClockWidgetStyle.Digital1(),
compact: Boolean,
twentyFourHours: Boolean,
showSeconds: Boolean,
useThemeColor: Boolean,
darkColors: Boolean,
@ -40,10 +41,10 @@ fun DigitalClock1(
val verticalLayout = !compact
val format = SimpleDateFormat(
when {
DateFormat.is24HourFormat(LocalContext.current) && verticalLayout -> {
twentyFourHours && verticalLayout -> {
"HH\nmm"
}
DateFormat.is24HourFormat(LocalContext.current) -> {
twentyFourHours -> {
"HH mm"
}
verticalLayout -> {

View File

@ -21,6 +21,7 @@ fun DigitalClock2(
time: Long,
compact: Boolean,
showSeconds: Boolean,
twentyFourHours: Boolean,
useThemeColor: Boolean,
darkColors: Boolean,
) {
@ -40,14 +41,14 @@ fun DigitalClock2(
}
val formatString = if (verticalLayout && showSeconds) {
if (DateFormat.is24HourFormat(LocalContext.current)) {
if (twentyFourHours) {
"HH:mm:ss"
}
else {
"hh:mm:ss"
}
} else {
if (DateFormat.is24HourFormat(LocalContext.current)) {
if (twentyFourHours) {
"HH:mm"
}
else {

View File

@ -48,6 +48,7 @@ fun OrbitClock(
time: Long,
compact: Boolean,
showSeconds: Boolean,
twentyFourHours: Boolean,
useThemeColor: Boolean,
darkColors: Boolean,
) {
@ -59,7 +60,7 @@ fun OrbitClock(
val minute = parsed.minute
val hour = parsed.hour
val formattedHour = (
if (DateFormat.is24HourFormat(LocalContext.current))
if (twentyFourHours)
hour
else {
((hour + 11) % 12) + 1

View File

@ -52,11 +52,12 @@ fun SegmentClock(
time: Long,
compact: Boolean,
showSeconds: Boolean,
twentyFourHours: Boolean,
useThemeColor: Boolean,
darkColors: Boolean,
) {
val parsed = Instant.ofEpochMilli(time).atZone(ZoneId.systemDefault())
val hour = if (DateFormat.is24HourFormat(LocalContext.current)) parsed.hour else (((parsed.hour + 11) % 12) + 1)
val hour = if (twentyFourHours) parsed.hour else (((parsed.hour + 11) % 12) + 1)
val minute = parsed.minute
val second = parsed.second

View File

@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.preferences.ClockWidgetAlignment
import de.mm20.launcher2.preferences.ClockWidgetColors
import de.mm20.launcher2.preferences.ClockWidgetStyle
import de.mm20.launcher2.preferences.TimeFormat
import de.mm20.launcher2.preferences.ui.ClockWidgetSettings
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
@ -21,7 +22,7 @@ class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
settings.setCompact(compact)
}
val availableClockStyles = combine(settings.digital1, settings.custom) {digital1, custom ->
val availableClockStyles = combine(settings.digital1, settings.custom) { digital1, custom ->
listOf(
digital1,
ClockWidgetStyle.Digital2,
@ -54,6 +55,13 @@ class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
settings.setShowSeconds(showSeconds)
}
val timeFormat = settings.timeFormat
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), TimeFormat.System)
fun setTimeFormat(timeFormat: TimeFormat) {
settings.setTimeFormat(timeFormat)
}
val useThemeColor = settings.useThemeColor
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)

View File

@ -0,0 +1,10 @@
package de.mm20.launcher2.ui.utils
import android.content.Context
import android.text.format.DateFormat
import de.mm20.launcher2.preferences.TimeFormat
import de.mm20.launcher2.preferences.TimeFormat.TwentyFourHour
fun TimeFormat.isTwentyFourHours(context: Context): Boolean {
return this == TimeFormat.TwentyFourHour || this == TimeFormat.System && DateFormat.is24HourFormat(context)
}

View File

@ -567,6 +567,10 @@
<string name="preference_clockwidget_layout_vertical">Default</string>
<string name="preference_clockwidget_layout_horizontal">Compact</string>
<string name="preference_clock_widget_show_seconds">Show seconds</string>
<string name="preference_clock_widget_time_format">Time format</string>
<string name="preference_clock_widget_time_format_24h">24-hour</string>
<string name="preference_clock_widget_time_format_12h">12-hour</string>
<string name="preference_clock_widget_time_format_system">System default</string>
<string name="widget_use_theme_colors">Use theme color</string>
<string name="preference_clock_widget_fill_height">Fill screen height</string>
<string name="preference_clock_widget_alignment">Alignment</string>

View File

@ -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 clockWidgetTimeFormat: TimeFormat = TimeFormat.System,
val clockWidgetUseThemeColor: Boolean = false,
val clockWidgetAlarmPart: Boolean = true,
val clockWidgetBatteryPart: Boolean = true,
@ -408,4 +409,11 @@ enum class KeyboardFilterBarItem {
@SerialName("events") Events,
@SerialName("tools") Tools,
@SerialName("hidden") HiddenResults,
}
@Serializable
enum class TimeFormat {
@SerialName("system") System,
@SerialName("12h") TwelveHour,
@SerialName("24h") TwentyFourHour
}

View File

@ -5,6 +5,7 @@ import de.mm20.launcher2.preferences.ClockWidgetColors
import de.mm20.launcher2.preferences.ClockWidgetStyle
import de.mm20.launcher2.preferences.ClockWidgetStyleEnum
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.TimeFormat
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
@ -137,6 +138,15 @@ class ClockWidgetSettings internal constructor(
}
}
val timeFormat
get() = launcherDataStore.data.map { it.clockWidgetTimeFormat }
fun setTimeFormat(timeFormat: TimeFormat) {
launcherDataStore.update {
it.copy(clockWidgetTimeFormat = timeFormat)
}
}
val useThemeColor
get() = launcherDataStore.data.map { it.clockWidgetUseThemeColor }