Added flags "Show seconds" and "Use theme color" for clock widgets (#673)
* Added flags for use seconds and use theme color for clock widget, and "Display" clock style. Signed-off-by: Guillermo Villafuerte <gvillafu@comunidad.unam.mx> * Separator in "Display" clock changed to vector for consistency. Signed-off-by: Guillermo Villafuerte <gvillafu@comunidad.unam.mx> * "Use theme color" is now false by default. Signed-off-by: Guillermo Villafuerte <gvillafu@comunidad.unam.mx> * Added padding for all clocks. Signed-off-by: Guillermo Villafuerte <gvillafu@comunidad.unam.mx> * FIX: "Show seconds" was default true on VM, glitching the clock widget when first loaded. Signed-off-by: Guillermo Villafuerte <gvillafu@comunidad.unam.mx> * Clock time is now provided for a variable component as needed, splitting the current time provider by two. Signed-off-by: Guillermo Villafuerte <gvillafu@comunidad.unam.mx> * Compact mode is also considered for second/minute provider. Signed-off-by: Guillermo Villafuerte <gvillafu@comunidad.unam.mx> * Yet another tweak to Orbit clock colors. Signed-off-by: Guillermo Villafuerte <gvillafu@comunidad.unam.mx> * Separator flicker is now synced with second change for Display clock. Signed-off-by: Guillermo Villafuerte <gvillafu@comunidad.unam.mx> * Update libraries * Update IDEA Kotlin file * Disable seconds by default * Swap order of clock widget preferences * Invert themed orbit clock colors * Rename display clock style to 7 segment * Make watch face names localizable --------- Signed-off-by: Guillermo Villafuerte <gvillafu@comunidad.unam.mx> Co-authored-by: MM20 <15646950+MM2-0@users.noreply.github.com>
This commit is contained in:
parent
dae97d47fb
commit
1a20458904
2
.idea/kotlinc.xml
generated
2
.idea/kotlinc.xml
generated
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="KotlinJpsPluginSettings">
|
<component name="KotlinJpsPluginSettings">
|
||||||
<option name="version" value="1.9.22" />
|
<option name="version" value="1.9.23" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@ -0,0 +1,85 @@
|
|||||||
|
package de.mm20.launcher2.ui.base
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.compositionLocalOf
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
|
import de.mm20.launcher2.preferences.ui.ClockWidgetSettings
|
||||||
|
import kotlinx.coroutines.awaitCancellation
|
||||||
|
import org.koin.androidx.compose.inject
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ProvideClockTime(content: @Composable () -> Unit) {
|
||||||
|
|
||||||
|
val context = LocalContext.current
|
||||||
|
val clockSettings: ClockWidgetSettings by inject()
|
||||||
|
val showSeconds by clockSettings.showSeconds.collectAsState(initial = false)
|
||||||
|
val isCompact by clockSettings.compact.collectAsState(initial = false)
|
||||||
|
|
||||||
|
var time by remember { mutableStateOf(System.currentTimeMillis()) }
|
||||||
|
|
||||||
|
val lifecycleOwner = LocalLifecycleOwner.current
|
||||||
|
LaunchedEffect(showSeconds, isCompact) {
|
||||||
|
time = System.currentTimeMillis()
|
||||||
|
|
||||||
|
lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
|
time = System.currentTimeMillis()
|
||||||
|
val handler = Handler(Looper.myLooper()!!)
|
||||||
|
val receiver = object : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
|
time = System.currentTimeMillis()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val callback = object : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
time = System.currentTimeMillis()
|
||||||
|
handler.postDelayed(this, 1000 - (time % 1000))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isCompact && showSeconds) {
|
||||||
|
context.registerReceiver(receiver, IntentFilter().apply {
|
||||||
|
addAction(Intent.ACTION_TIME_CHANGED)
|
||||||
|
})
|
||||||
|
|
||||||
|
handler.postDelayed(callback, 1000 - (time % 1000))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
context.registerReceiver(receiver, IntentFilter().apply {
|
||||||
|
addAction(Intent.ACTION_TIME_CHANGED)
|
||||||
|
addAction(Intent.ACTION_TIME_TICK)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
awaitCancellation()
|
||||||
|
} finally {
|
||||||
|
context.unregisterReceiver(receiver)
|
||||||
|
handler.removeCallbacks(callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompositionLocalProvider(
|
||||||
|
LocalClockTime provides time,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val LocalClockTime = compositionLocalOf { System.currentTimeMillis() }
|
||||||
@ -4,8 +4,14 @@ import android.content.BroadcastReceiver
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.util.Log
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.compositionLocalOf
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
@ -23,15 +29,18 @@ fun ProvideCurrentTime(content: @Composable () -> Unit) {
|
|||||||
LaunchedEffect(null) {
|
LaunchedEffect(null) {
|
||||||
lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
time = System.currentTimeMillis()
|
time = System.currentTimeMillis()
|
||||||
|
|
||||||
val receiver = object : BroadcastReceiver() {
|
val receiver = object : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
time = System.currentTimeMillis()
|
time = System.currentTimeMillis()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context.registerReceiver(receiver, IntentFilter().apply {
|
context.registerReceiver(receiver, IntentFilter().apply {
|
||||||
addAction(Intent.ACTION_TIME_TICK)
|
|
||||||
addAction(Intent.ACTION_TIME_CHANGED)
|
addAction(Intent.ACTION_TIME_CHANGED)
|
||||||
|
addAction(Intent.ACTION_TIME_TICK)
|
||||||
})
|
})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
awaitCancellation()
|
awaitCancellation()
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@ -250,7 +250,7 @@ fun ShapedLauncherIcon(
|
|||||||
_badge.progress?.let {
|
_badge.progress?.let {
|
||||||
val progress by animateFloatAsState(it)
|
val progress by animateFloatAsState(it)
|
||||||
CircularProgressIndicator(
|
CircularProgressIndicator(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(0.8f),
|
||||||
progress = progress,
|
progress = progress,
|
||||||
strokeWidth = size / 48,
|
strokeWidth = size / 48,
|
||||||
color = MaterialTheme.colorScheme.secondaryContainer
|
color = MaterialTheme.colorScheme.secondaryContainer
|
||||||
|
|||||||
@ -101,7 +101,6 @@ abstract class SharedLauncherActivity(
|
|||||||
LocalGestureDetector provides gestureDetector,
|
LocalGestureDetector provides gestureDetector,
|
||||||
) {
|
) {
|
||||||
LauncherTheme {
|
LauncherTheme {
|
||||||
ProvideCurrentTime {
|
|
||||||
ProvideSettings {
|
ProvideSettings {
|
||||||
val statusBarColor by viewModel.statusBarColor.collectAsState()
|
val statusBarColor by viewModel.statusBarColor.collectAsState()
|
||||||
val navBarColor by viewModel.navBarColor.collectAsState()
|
val navBarColor by viewModel.navBarColor.collectAsState()
|
||||||
@ -161,6 +160,7 @@ abstract class SharedLauncherActivity(
|
|||||||
systemUiController.isNavigationBarVisible = !hideNav
|
systemUiController.isNavigationBarVisible = !hideNav
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProvideCurrentTime {
|
||||||
OverlayHost(
|
OverlayHost(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
|
|||||||
@ -17,18 +17,19 @@ import androidx.compose.foundation.layout.width
|
|||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.rounded.AccessTime
|
||||||
import androidx.compose.material.icons.rounded.Alarm
|
import androidx.compose.material.icons.rounded.Alarm
|
||||||
import androidx.compose.material.icons.rounded.AlignVerticalBottom
|
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.BatteryFull
|
import androidx.compose.material.icons.rounded.BatteryFull
|
||||||
|
import androidx.compose.material.icons.rounded.ColorLens
|
||||||
import androidx.compose.material.icons.rounded.DarkMode
|
import androidx.compose.material.icons.rounded.DarkMode
|
||||||
import androidx.compose.material.icons.rounded.Height
|
import androidx.compose.material.icons.rounded.Height
|
||||||
import androidx.compose.material.icons.rounded.HorizontalSplit
|
import androidx.compose.material.icons.rounded.HorizontalSplit
|
||||||
import androidx.compose.material.icons.rounded.LightMode
|
import androidx.compose.material.icons.rounded.LightMode
|
||||||
import androidx.compose.material.icons.rounded.MusicNote
|
import androidx.compose.material.icons.rounded.MusicNote
|
||||||
import androidx.compose.material.icons.rounded.Star
|
|
||||||
import androidx.compose.material.icons.rounded.Today
|
import androidx.compose.material.icons.rounded.Today
|
||||||
import androidx.compose.material.icons.rounded.Tune
|
import androidx.compose.material.icons.rounded.Tune
|
||||||
import androidx.compose.material.icons.rounded.VerticalSplit
|
import androidx.compose.material.icons.rounded.VerticalSplit
|
||||||
@ -65,8 +66,10 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
|||||||
import de.mm20.launcher2.preferences.ClockWidgetAlignment
|
import de.mm20.launcher2.preferences.ClockWidgetAlignment
|
||||||
import de.mm20.launcher2.preferences.ClockWidgetColors
|
import de.mm20.launcher2.preferences.ClockWidgetColors
|
||||||
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||||
|
import de.mm20.launcher2.preferences.ui.ClockWidgetSettings
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.base.LocalTime
|
import de.mm20.launcher2.ui.base.LocalClockTime
|
||||||
|
import de.mm20.launcher2.ui.base.ProvideClockTime
|
||||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||||
import de.mm20.launcher2.ui.component.preferences.Preference
|
import de.mm20.launcher2.ui.component.preferences.Preference
|
||||||
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
||||||
@ -75,9 +78,11 @@ import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.BinaryClock
|
|||||||
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.DigitalClock1
|
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.DigitalClock1
|
||||||
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.DigitalClock2
|
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.DigitalClock2
|
||||||
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.OrbitClock
|
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.OrbitClock
|
||||||
|
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.launcher.widgets.clock.parts.PartProvider
|
||||||
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
|
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
|
||||||
import de.mm20.launcher2.ui.settings.clockwidget.ClockWidgetSettingsScreenVM
|
import de.mm20.launcher2.ui.settings.clockwidget.ClockWidgetSettingsScreenVM
|
||||||
|
import org.koin.androidx.compose.inject
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ClockWidget(
|
fun ClockWidget(
|
||||||
@ -85,13 +90,14 @@ fun ClockWidget(
|
|||||||
fillScreenHeight: Boolean,
|
fillScreenHeight: Boolean,
|
||||||
editMode: Boolean = false,
|
editMode: Boolean = false,
|
||||||
) {
|
) {
|
||||||
|
ProvideClockTime {
|
||||||
val viewModel: ClockWidgetVM = viewModel()
|
val viewModel: ClockWidgetVM = viewModel()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val compact by viewModel.compactLayout.collectAsState()
|
val compact by viewModel.compactLayout.collectAsState()
|
||||||
val clockStyle by viewModel.clockStyle.collectAsState()
|
val clockStyle by viewModel.clockStyle.collectAsState()
|
||||||
val color by viewModel.color.collectAsState()
|
val color by viewModel.color.collectAsState()
|
||||||
val alignment by viewModel.alignment.collectAsState()
|
val alignment by viewModel.alignment.collectAsState()
|
||||||
val time = LocalTime.current
|
val time = LocalClockTime.current
|
||||||
|
|
||||||
val contentColor =
|
val contentColor =
|
||||||
if (color == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current || color == ClockWidgetColors.Dark) {
|
if (color == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current || color == ClockWidgetColors.Dark) {
|
||||||
@ -243,20 +249,25 @@ fun ClockWidget(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Clock(
|
fun Clock(
|
||||||
style: ClockWidgetStyle?,
|
style: ClockWidgetStyle?,
|
||||||
compact: Boolean,
|
compact: Boolean,
|
||||||
) {
|
) {
|
||||||
val time = LocalTime.current
|
val time = LocalClockTime.current
|
||||||
when (style) {
|
val clockSettings: ClockWidgetSettings by inject()
|
||||||
is ClockWidgetStyle.Digital1 -> DigitalClock1(time, compact, style)
|
val showSeconds by clockSettings.showSeconds.collectAsState(initial = false)
|
||||||
|
val useThemeColor by clockSettings.useThemeColor.collectAsState(initial = false)
|
||||||
|
|
||||||
is ClockWidgetStyle.Digital2 -> DigitalClock2(time, compact)
|
when (style) {
|
||||||
is ClockWidgetStyle.Binary -> BinaryClock(time, compact)
|
is ClockWidgetStyle.Digital1 -> DigitalClock1(time, style, compact, showSeconds, useThemeColor)
|
||||||
is ClockWidgetStyle.Analog -> AnalogClock(time, compact)
|
is ClockWidgetStyle.Digital2 -> DigitalClock2(time, compact, showSeconds, useThemeColor)
|
||||||
is ClockWidgetStyle.Orbit -> OrbitClock(time, compact)
|
is ClockWidgetStyle.Binary -> BinaryClock(time, compact, showSeconds, useThemeColor)
|
||||||
|
is ClockWidgetStyle.Analog -> AnalogClock(time, compact, showSeconds, useThemeColor)
|
||||||
|
is ClockWidgetStyle.Orbit -> OrbitClock(time, compact, showSeconds, useThemeColor)
|
||||||
|
is ClockWidgetStyle.Segment -> SegmentClock(time, compact, showSeconds, useThemeColor)
|
||||||
is ClockWidgetStyle.Empty -> {}
|
is ClockWidgetStyle.Empty -> {}
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
@ -285,6 +296,8 @@ fun ConfigureClockWidgetSheet(
|
|||||||
val style by viewModel.clockStyle.collectAsState()
|
val style by viewModel.clockStyle.collectAsState()
|
||||||
val fillHeight by viewModel.fillHeight.collectAsState()
|
val fillHeight by viewModel.fillHeight.collectAsState()
|
||||||
val alignment by viewModel.alignment.collectAsState()
|
val alignment by viewModel.alignment.collectAsState()
|
||||||
|
val showSeconds by viewModel.showSeconds.collectAsState()
|
||||||
|
val useAccentColor by viewModel.useThemeColor.collectAsState()
|
||||||
val parts by viewModel.parts.collectAsState()
|
val parts by viewModel.parts.collectAsState()
|
||||||
|
|
||||||
BottomSheetDialog(onDismissRequest = onDismiss) {
|
BottomSheetDialog(onDismissRequest = onDismiss) {
|
||||||
@ -340,6 +353,7 @@ fun ConfigureClockWidgetSheet(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (color != null && compact != null) {
|
if (color != null && compact != null) {
|
||||||
|
ProvideClockTime {
|
||||||
WatchFaceSelector(
|
WatchFaceSelector(
|
||||||
compact = compact!!,
|
compact = compact!!,
|
||||||
colors = color!!,
|
colors = color!!,
|
||||||
@ -348,6 +362,7 @@ fun ConfigureClockWidgetSheet(
|
|||||||
viewModel.setClockStyle(it)
|
viewModel.setClockStyle(it)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SingleChoiceSegmentedButtonRow(
|
SingleChoiceSegmentedButtonRow(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
@ -392,6 +407,32 @@ fun ConfigureClockWidgetSheet(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
OutlinedCard(
|
||||||
|
modifier = Modifier.padding(top = 16.dp),
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
SwitchPreference(
|
||||||
|
title = stringResource(R.string.preference_clock_widget_use_theme_color),
|
||||||
|
icon = Icons.Rounded.ColorLens,
|
||||||
|
value = useAccentColor,
|
||||||
|
onValueChanged = {
|
||||||
|
viewModel.setUseThemeColor(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
AnimatedVisibility(compact == false) {
|
||||||
|
SwitchPreference(
|
||||||
|
title = stringResource(R.string.preference_clock_widget_show_seconds),
|
||||||
|
icon = Icons.Rounded.AccessTime,
|
||||||
|
value = showSeconds,
|
||||||
|
onValueChanged = {
|
||||||
|
viewModel.setShowSeconds(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
OutlinedCard(
|
OutlinedCard(
|
||||||
modifier = Modifier.padding(top = 16.dp),
|
modifier = Modifier.padding(top = 16.dp),
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -45,6 +45,8 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.zIndex
|
import androidx.compose.ui.zIndex
|
||||||
import de.mm20.launcher2.preferences.ClockWidgetColors
|
import de.mm20.launcher2.preferences.ClockWidgetColors
|
||||||
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||||
|
import de.mm20.launcher2.ui.R
|
||||||
|
import de.mm20.launcher2.ui.base.ProvideClockTime
|
||||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||||
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
|
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -75,13 +77,13 @@ fun WatchFaceSelector(
|
|||||||
mapOf(
|
mapOf(
|
||||||
ClockStyle.DigitalClock1 to 0,
|
ClockStyle.DigitalClock1 to 0,
|
||||||
ClockStyle.DigitalClock1_Outlined to 0,
|
ClockStyle.DigitalClock1_Outlined to 0,
|
||||||
ClockStyle.DigitalClock1_MDY to 0,
|
|
||||||
ClockStyle.DigitalClock1_OnePlus to 0,
|
ClockStyle.DigitalClock1_OnePlus to 0,
|
||||||
ClockStyle.DigitalClock2 to 1,
|
ClockStyle.DigitalClock2 to 1,
|
||||||
ClockStyle.AnalogClock to 2,
|
ClockStyle.AnalogClock to 2,
|
||||||
ClockStyle.OrbitClock to 3,
|
ClockStyle.OrbitClock to 3,
|
||||||
ClockStyle.BinaryClock to 4,
|
ClockStyle.BinaryClock to 4,
|
||||||
ClockStyle.EmptyClock to 5,
|
ClockStyle.SegmentClock to 5,
|
||||||
|
ClockStyle.EmptyClock to 6,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val pagerState = rememberPagerState(
|
val pagerState = rememberPagerState(
|
||||||
@ -256,13 +258,13 @@ fun getClockstyleName(context: Context, style: ClockWidgetStyle): String {
|
|||||||
return when (style) {
|
return when (style) {
|
||||||
ClockStyle.DigitalClock1,
|
ClockStyle.DigitalClock1,
|
||||||
ClockStyle.DigitalClock1_Outlined,
|
ClockStyle.DigitalClock1_Outlined,
|
||||||
ClockStyle.DigitalClock1_MDY,
|
ClockStyle.DigitalClock1_OnePlus -> context.getString(R.string.clock_style_digital1)
|
||||||
ClockStyle.DigitalClock1_OnePlus -> "Bold"
|
ClockStyle.DigitalClock2 -> context.getString(R.string.clock_style_digital2)
|
||||||
ClockStyle.DigitalClock2 -> "Simple"
|
ClockStyle.OrbitClock -> context.getString(R.string.clock_style_orbit)
|
||||||
ClockStyle.OrbitClock -> "Orbit"
|
ClockStyle.BinaryClock -> context.getString(R.string.clock_style_binary)
|
||||||
ClockStyle.BinaryClock -> "Binary"
|
ClockStyle.AnalogClock -> context.getString(R.string.clock_style_analog)
|
||||||
ClockStyle.AnalogClock -> "Hands"
|
ClockStyle.SegmentClock -> context.getString(R.string.clock_style_segment)
|
||||||
ClockStyle.EmptyClock -> "Empty"
|
ClockStyle.EmptyClock -> context.getString(R.string.clock_style_empty)
|
||||||
else -> ""
|
else -> ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,9 +276,9 @@ fun getVariantName(context: Context, style: ClockWidgetStyle): String {
|
|||||||
ClockStyle.OrbitClock,
|
ClockStyle.OrbitClock,
|
||||||
ClockStyle.BinaryClock,
|
ClockStyle.BinaryClock,
|
||||||
ClockStyle.AnalogClock,
|
ClockStyle.AnalogClock,
|
||||||
ClockStyle.EmptyClock -> "Standard"
|
ClockStyle.SegmentClock,
|
||||||
ClockStyle.DigitalClock1_Outlined -> "Outlined"
|
ClockStyle.EmptyClock -> context.getString(R.string.clock_variant_standard)
|
||||||
ClockStyle.DigitalClock1_MDY -> "Material You"
|
ClockStyle.DigitalClock1_Outlined -> context.getString(R.string.clock_variant_outlined)
|
||||||
ClockStyle.DigitalClock1_OnePlus -> "OnePlus"
|
ClockStyle.DigitalClock1_OnePlus -> "OnePlus"
|
||||||
else -> ""
|
else -> ""
|
||||||
|
|
||||||
@ -287,11 +289,11 @@ fun getVariantName(context: Context, style: ClockWidgetStyle): String {
|
|||||||
object ClockStyle {
|
object ClockStyle {
|
||||||
val DigitalClock1 = ClockWidgetStyle.Digital1()
|
val DigitalClock1 = ClockWidgetStyle.Digital1()
|
||||||
val DigitalClock1_Outlined = ClockWidgetStyle.Digital1(outlined = true)
|
val DigitalClock1_Outlined = ClockWidgetStyle.Digital1(outlined = true)
|
||||||
val DigitalClock1_MDY = ClockWidgetStyle.Digital1(variant = ClockWidgetStyle.Digital1.Variant.MDY)
|
|
||||||
val DigitalClock1_OnePlus = ClockWidgetStyle.Digital1(variant = ClockWidgetStyle.Digital1.Variant.OnePlus)
|
val DigitalClock1_OnePlus = ClockWidgetStyle.Digital1(variant = ClockWidgetStyle.Digital1.Variant.OnePlus)
|
||||||
val DigitalClock2 = ClockWidgetStyle.Digital2
|
val DigitalClock2 = ClockWidgetStyle.Digital2
|
||||||
val OrbitClock = ClockWidgetStyle.Orbit
|
val OrbitClock = ClockWidgetStyle.Orbit
|
||||||
val AnalogClock = ClockWidgetStyle.Analog
|
val AnalogClock = ClockWidgetStyle.Analog
|
||||||
val BinaryClock = ClockWidgetStyle.Binary
|
val BinaryClock = ClockWidgetStyle.Binary
|
||||||
|
val SegmentClock = ClockWidgetStyle.Segment
|
||||||
val EmptyClock = ClockWidgetStyle.Empty
|
val EmptyClock = ClockWidgetStyle.Empty
|
||||||
}
|
}
|
||||||
@ -4,41 +4,68 @@ import androidx.compose.foundation.Canvas
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.geometry.center
|
import androidx.compose.ui.geometry.center
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.StrokeCap
|
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.LegacySettings
|
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||||
import java.util.*
|
import java.util.Calendar
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AnalogClock(
|
fun AnalogClock(
|
||||||
time: Long,
|
time: Long,
|
||||||
compact: Boolean,
|
compact: Boolean,
|
||||||
|
showSeconds: Boolean,
|
||||||
|
useThemeColor: Boolean,
|
||||||
) {
|
) {
|
||||||
val verticalLayout = !compact
|
val verticalLayout = !compact
|
||||||
val date = Calendar.getInstance()
|
val date = Calendar.getInstance()
|
||||||
date.timeInMillis = time
|
date.timeInMillis = time
|
||||||
|
val second = date[Calendar.SECOND]
|
||||||
val minute = date[Calendar.MINUTE]
|
val minute = date[Calendar.MINUTE]
|
||||||
val hour = date[Calendar.HOUR]
|
val hour = date[Calendar.HOUR]
|
||||||
|
|
||||||
val size = if (verticalLayout) 128.dp else 56.dp
|
val size = if (verticalLayout) 128.dp else 56.dp
|
||||||
val strokeWidth = if (verticalLayout) 4.dp else 2.dp
|
val strokeWidth = if (verticalLayout) 4.dp else 2.dp
|
||||||
|
|
||||||
val color = LocalContentColor.current
|
val color = if (useThemeColor) {
|
||||||
|
if (LocalContentColor.current == Color.White) {
|
||||||
|
if (LocalDarkTheme.current) MaterialTheme.colorScheme.onPrimaryContainer
|
||||||
|
else MaterialTheme.colorScheme.primaryContainer
|
||||||
|
} else {
|
||||||
|
if (LocalDarkTheme.current) MaterialTheme.colorScheme.primaryContainer
|
||||||
|
else MaterialTheme.colorScheme.primary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LocalContentColor.current
|
||||||
|
}
|
||||||
|
|
||||||
|
val secondaryColor = if (useThemeColor) {
|
||||||
|
if (LocalContentColor.current == Color.White) {
|
||||||
|
if (LocalDarkTheme.current) MaterialTheme.colorScheme.primaryContainer
|
||||||
|
else MaterialTheme.colorScheme.onPrimaryContainer
|
||||||
|
} else {
|
||||||
|
if (LocalDarkTheme.current) MaterialTheme.colorScheme.primary
|
||||||
|
else MaterialTheme.colorScheme.primaryContainer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LocalContentColor.current.invert()
|
||||||
|
}
|
||||||
|
|
||||||
|
val contentColor = LocalContentColor.current
|
||||||
|
|
||||||
Canvas(modifier = Modifier
|
Canvas(modifier = Modifier
|
||||||
.padding(bottom = if (verticalLayout) 8.dp else 0.dp)
|
.padding(top = if (verticalLayout) 8.dp else 0.dp,
|
||||||
|
bottom = if (verticalLayout) 8.dp else 0.dp)
|
||||||
.size(size)) {
|
.size(size)) {
|
||||||
drawCircle(
|
rotate(hour.toFloat() / 12f * 360f + ((minute.toFloat() / 60f) * 30f) + (second.toFloat() / 120f), this.size.center) {
|
||||||
color,
|
|
||||||
radius = strokeWidth.toPx(),
|
|
||||||
center = this.size.center,
|
|
||||||
style = Fill
|
|
||||||
)
|
|
||||||
rotate(hour.toFloat() / 12f * 360f + (minute.toFloat() / 60f) * 30f, this.size.center) {
|
|
||||||
drawLine(
|
drawLine(
|
||||||
color,
|
color,
|
||||||
this.size.center, this.size.center.copy(y = this.size.height * 0.25f),
|
this.size.center, this.size.center.copy(y = this.size.height * 0.25f),
|
||||||
@ -46,7 +73,7 @@ fun AnalogClock(
|
|||||||
cap = StrokeCap.Round
|
cap = StrokeCap.Round
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
rotate(minute.toFloat() / 60f * 360f, this.size.center) {
|
rotate(minute.toFloat() / 60f * 360f + (second.toFloat() / 60f) * 6f, this.size.center) {
|
||||||
drawLine(
|
drawLine(
|
||||||
color,
|
color,
|
||||||
this.size.center, this.size.center.copy(y = this.size.height * 0.1f),
|
this.size.center, this.size.center.copy(y = this.size.height * 0.1f),
|
||||||
@ -54,5 +81,29 @@ fun AnalogClock(
|
|||||||
cap = StrokeCap.Round,
|
cap = StrokeCap.Round,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (verticalLayout && showSeconds) {
|
||||||
|
rotate((second.toFloat() / 60f) * 360f, this.size.center) {
|
||||||
|
drawLine(
|
||||||
|
contentColor,
|
||||||
|
this.size.center, this.size.center.copy(y = this.size.height * 0.05f),
|
||||||
|
strokeWidth = (strokeWidth / 2).toPx(),
|
||||||
|
cap = StrokeCap.Round
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
drawCircle(
|
||||||
|
secondaryColor,
|
||||||
|
radius = (strokeWidth * 1.5f).toPx(),
|
||||||
|
center = this.size.center,
|
||||||
|
style = Fill
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Color.invert(alpha: Float? = null): Color =
|
||||||
|
Color(
|
||||||
|
1f - red,
|
||||||
|
1f - green,
|
||||||
|
1f - blue,
|
||||||
|
alpha ?: this.alpha, colorSpace
|
||||||
|
)
|
||||||
@ -1,28 +1,59 @@
|
|||||||
package de.mm20.launcher2.ui.launcher.widgets.clock.clocks
|
package de.mm20.launcher2.ui.launcher.widgets.clock.clocks
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import java.util.*
|
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||||
|
import java.util.Calendar
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BinaryClock(
|
fun BinaryClock(
|
||||||
time: Long,
|
time: Long,
|
||||||
compact: Boolean,
|
compact: Boolean,
|
||||||
|
showSeconds: Boolean,
|
||||||
|
useThemeColor: Boolean,
|
||||||
) {
|
) {
|
||||||
val verticalLayout = !compact
|
val verticalLayout = !compact
|
||||||
val date = Calendar.getInstance()
|
val date = Calendar.getInstance()
|
||||||
date.timeInMillis = time
|
date.timeInMillis = time
|
||||||
|
val second = date[Calendar.SECOND]
|
||||||
val minute = date[Calendar.MINUTE]
|
val minute = date[Calendar.MINUTE]
|
||||||
var hour = date[Calendar.HOUR]
|
var hour = date[Calendar.HOUR]
|
||||||
if (hour == 0) hour = 12
|
if (hour == 0) hour = 12
|
||||||
|
|
||||||
|
val color = if (useThemeColor) {
|
||||||
|
if (LocalContentColor.current == Color.White) {
|
||||||
|
if (LocalDarkTheme.current) MaterialTheme.colorScheme.onPrimaryContainer
|
||||||
|
else MaterialTheme.colorScheme.primaryContainer
|
||||||
|
} else {
|
||||||
|
if (LocalDarkTheme.current) MaterialTheme.colorScheme.primaryContainer
|
||||||
|
else MaterialTheme.colorScheme.primary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LocalContentColor.current
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Accent color by setting
|
||||||
|
val disabledColor = LocalContentColor.current.copy(alpha = 0.45f)
|
||||||
|
|
||||||
if (verticalLayout) {
|
if (verticalLayout) {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.End
|
||||||
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.padding(vertical = 24.dp)
|
modifier = Modifier.padding(start = 0.dp, top = 24.dp, end = 0.dp, bottom = 6.dp)
|
||||||
) {
|
) {
|
||||||
for (i in 0 until 10) {
|
for (i in 0 until 10) {
|
||||||
val active = if (i < 4) {
|
val active = if (i < 4) {
|
||||||
@ -35,9 +66,7 @@ fun BinaryClock(
|
|||||||
.padding(4.dp)
|
.padding(4.dp)
|
||||||
.size(12.dp)
|
.size(12.dp)
|
||||||
.background(
|
.background(
|
||||||
LocalContentColor.current.copy(
|
if (active) color else disabledColor
|
||||||
if (active) 1f else 0.45f
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if (i == 3) {
|
if (i == 3) {
|
||||||
@ -45,6 +74,24 @@ fun BinaryClock(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (showSeconds) {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.End
|
||||||
|
) {
|
||||||
|
for (i in 0 until 6) {
|
||||||
|
val active = second and (1 shl (5 - i)) != 0
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(4.dp)
|
||||||
|
.size(12.dp)
|
||||||
|
.background(
|
||||||
|
if (active) color else disabledColor
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.End
|
horizontalAlignment = Alignment.End
|
||||||
@ -57,9 +104,7 @@ fun BinaryClock(
|
|||||||
.padding( 4.dp)
|
.padding( 4.dp)
|
||||||
.size(12.dp)
|
.size(12.dp)
|
||||||
.background(
|
.background(
|
||||||
LocalContentColor.current.copy(
|
if (active) color else disabledColor
|
||||||
if (active) 1f else 0.45f
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -72,9 +117,7 @@ fun BinaryClock(
|
|||||||
.padding(4.dp)
|
.padding(4.dp)
|
||||||
.size(12.dp)
|
.size(12.dp)
|
||||||
.background(
|
.background(
|
||||||
LocalContentColor.current.copy(
|
if (active) color else disabledColor
|
||||||
if (active) 1f else 0.45f
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
package de.mm20.launcher2.ui.launcher.widgets.clock.clocks
|
package de.mm20.launcher2.ui.launcher.widgets.clock.clocks
|
||||||
|
|
||||||
import android.text.format.DateFormat
|
import android.text.format.DateFormat
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.offset
|
import androidx.compose.foundation.layout.offset
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.drawscope.Fill
|
import androidx.compose.ui.graphics.drawscope.Fill
|
||||||
@ -23,24 +26,48 @@ import de.mm20.launcher2.preferences.ClockWidgetStyle
|
|||||||
import de.mm20.launcher2.ui.ktx.toPixels
|
import de.mm20.launcher2.ui.ktx.toPixels
|
||||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.Locale
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DigitalClock1(
|
fun DigitalClock1(
|
||||||
time: Long,
|
time: Long,
|
||||||
compact: Boolean,
|
|
||||||
style: ClockWidgetStyle.Digital1 = ClockWidgetStyle.Digital1(),
|
style: ClockWidgetStyle.Digital1 = ClockWidgetStyle.Digital1(),
|
||||||
|
compact: Boolean,
|
||||||
|
showSeconds: Boolean,
|
||||||
|
useThemeColor: Boolean,
|
||||||
) {
|
) {
|
||||||
val verticalLayout = !compact
|
val verticalLayout = !compact
|
||||||
val format = SimpleDateFormat(
|
val format = SimpleDateFormat(
|
||||||
if (verticalLayout) {
|
when {
|
||||||
if (DateFormat.is24HourFormat(LocalContext.current)) "HH\nmm" else "hh\nmm"
|
DateFormat.is24HourFormat(LocalContext.current) && verticalLayout -> {
|
||||||
} else {
|
"HH\nmm"
|
||||||
if (DateFormat.is24HourFormat(LocalContext.current)) "HH mm" else "hh mm"
|
}
|
||||||
|
DateFormat.is24HourFormat(LocalContext.current) -> {
|
||||||
|
"HH mm"
|
||||||
|
}
|
||||||
|
verticalLayout -> {
|
||||||
|
"HH\nmm"
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
"hh mm"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Locale.getDefault()
|
Locale.getDefault()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val color = if (useThemeColor) {
|
||||||
|
if (LocalContentColor.current == Color.White) {
|
||||||
|
if (LocalDarkTheme.current) MaterialTheme.colorScheme.onPrimaryContainer
|
||||||
|
else MaterialTheme.colorScheme.primaryContainer
|
||||||
|
} else {
|
||||||
|
if (LocalDarkTheme.current) MaterialTheme.colorScheme.primaryContainer
|
||||||
|
else MaterialTheme.colorScheme.primary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LocalContentColor.current
|
||||||
|
}
|
||||||
|
|
||||||
val formattedString = format.format(time)
|
val formattedString = format.format(time)
|
||||||
|
|
||||||
val textStyle = MaterialTheme.typography.displayLarge.copy(
|
val textStyle = MaterialTheme.typography.displayLarge.copy(
|
||||||
@ -49,19 +76,14 @@ fun DigitalClock1(
|
|||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
lineHeight = 0.8.em,
|
lineHeight = 0.8.em,
|
||||||
drawStyle = if (style.outlined) Stroke(width = 2.dp.toPixels()) else Fill,
|
drawStyle = if (style.outlined) Stroke(width = 2.dp.toPixels()) else Fill,
|
||||||
color = if (style.variant == ClockWidgetStyle.Digital1.Variant.MDY) {
|
color = color
|
||||||
if (LocalContentColor.current == Color.White) {
|
|
||||||
if (LocalDarkTheme.current) MaterialTheme.colorScheme.onPrimaryContainer
|
|
||||||
else MaterialTheme.colorScheme.primaryContainer
|
|
||||||
} else {
|
|
||||||
if (LocalDarkTheme.current) MaterialTheme.colorScheme.primaryContainer
|
|
||||||
else MaterialTheme.colorScheme.primary
|
|
||||||
}
|
|
||||||
} else LocalContentColor.current
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val modifier = Modifier.offset(0.dp, if (verticalLayout) 16.dp else 0.dp)
|
val modifier = Modifier.offset(0.dp, if (verticalLayout) 16.dp else 0.dp)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
if (style.variant == ClockWidgetStyle.Digital1.Variant.OnePlus) {
|
if (style.variant == ClockWidgetStyle.Digital1.Variant.OnePlus) {
|
||||||
val hour = formattedString.substring(0, 2)
|
val hour = formattedString.substring(0, 2)
|
||||||
Text(
|
Text(
|
||||||
@ -80,11 +102,25 @@ fun DigitalClock1(
|
|||||||
},
|
},
|
||||||
style = textStyle
|
style = textStyle
|
||||||
)
|
)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
Text(
|
Text(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
text = formattedString,
|
text = formattedString,
|
||||||
style = textStyle,
|
style = textStyle,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (verticalLayout && showSeconds) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.offset(0.dp, (-20).dp).align(Alignment.CenterHorizontally),
|
||||||
|
text = SimpleDateFormat("ss", Locale.getDefault()).format(time),
|
||||||
|
style = textStyle.copy(
|
||||||
|
fontSize = textStyle.fontSize * 0.6,
|
||||||
|
color = color,
|
||||||
|
drawStyle = if (style.outlined) Stroke(width = 2.dp.toPixels()) else Fill,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,22 +1,69 @@
|
|||||||
package de.mm20.launcher2.ui.launcher.widgets.clock.clocks
|
package de.mm20.launcher2.ui.launcher.widgets.clock.clocks
|
||||||
|
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateFormat
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DigitalClock2(
|
fun DigitalClock2(
|
||||||
time: Long,
|
time: Long,
|
||||||
compact: Boolean,
|
compact: Boolean,
|
||||||
|
showSeconds: Boolean,
|
||||||
|
useThemeColor: Boolean,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
val verticalLayout = !compact
|
||||||
|
val color = if (useThemeColor) {
|
||||||
|
if (LocalContentColor.current == Color.White) {
|
||||||
|
if (LocalDarkTheme.current) MaterialTheme.colorScheme.onPrimaryContainer
|
||||||
|
else MaterialTheme.colorScheme.primaryContainer
|
||||||
|
} else {
|
||||||
|
if (LocalDarkTheme.current) MaterialTheme.colorScheme.primaryContainer
|
||||||
|
else MaterialTheme.colorScheme.primary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LocalContentColor.current
|
||||||
|
}
|
||||||
|
|
||||||
|
val formatString = if (verticalLayout && showSeconds) {
|
||||||
|
if (DateFormat.is24HourFormat(LocalContext.current)) {
|
||||||
|
"HH:mm:ss"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
"hh:mm:ss"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (DateFormat.is24HourFormat(LocalContext.current)) {
|
||||||
|
"HH:mm"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
"hh:mm"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val formatter = SimpleDateFormat(formatString, Locale.getDefault())
|
||||||
Text(
|
Text(
|
||||||
text = DateUtils.formatDateTime(LocalContext.current, time, DateUtils.FORMAT_SHOW_TIME),
|
modifier = Modifier.padding(top = if (verticalLayout) 12.dp else 0.dp,
|
||||||
|
bottom = if (verticalLayout) 12.dp else 0.dp,
|
||||||
|
start = 0.dp,
|
||||||
|
end = 0.dp),
|
||||||
|
text = formatter.format(time),
|
||||||
style = MaterialTheme.typography.displaySmall.copy(
|
style = MaterialTheme.typography.displaySmall.copy(
|
||||||
fontWeight = FontWeight.Normal
|
fontWeight = FontWeight.Normal,
|
||||||
|
color = color
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -23,6 +23,7 @@ import androidx.compose.ui.graphics.BlendMode
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.PathEffect
|
import androidx.compose.ui.graphics.PathEffect
|
||||||
import androidx.compose.ui.graphics.drawscope.Stroke
|
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||||
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
import androidx.compose.ui.text.drawText
|
import androidx.compose.ui.text.drawText
|
||||||
@ -31,7 +32,8 @@ import androidx.compose.ui.unit.center
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.toOffset
|
import androidx.compose.ui.unit.toOffset
|
||||||
import de.mm20.launcher2.ktx.TWO_PI
|
import de.mm20.launcher2.ktx.TWO_PI
|
||||||
import de.mm20.launcher2.preferences.LegacySettings
|
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||||
|
import palettes.TonalPalette
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
import java.time.ZonedDateTime
|
import java.time.ZonedDateTime
|
||||||
@ -47,6 +49,8 @@ private val currentTime
|
|||||||
fun OrbitClock(
|
fun OrbitClock(
|
||||||
_time: Long,
|
_time: Long,
|
||||||
compact: Boolean,
|
compact: Boolean,
|
||||||
|
showSeconds: Boolean,
|
||||||
|
useThemeColor: Boolean
|
||||||
) {
|
) {
|
||||||
val verticalLayout = !compact
|
val verticalLayout = !compact
|
||||||
|
|
||||||
@ -108,7 +112,24 @@ fun OrbitClock(
|
|||||||
label = "hoursAnimation"
|
label = "hoursAnimation"
|
||||||
)
|
)
|
||||||
|
|
||||||
val color = LocalContentColor.current
|
val fgTone = if (LocalContentColor.current == Color.White) 10 else 90
|
||||||
|
val bgTone = if (LocalContentColor.current == Color.White) 90 else 30
|
||||||
|
|
||||||
|
val background = if (useThemeColor) {
|
||||||
|
Color(TonalPalette.fromInt(MaterialTheme.colorScheme.primaryContainer.toArgb()).tone(bgTone))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LocalContentColor.current
|
||||||
|
}
|
||||||
|
|
||||||
|
val foreground = if (useThemeColor) {
|
||||||
|
Color(TonalPalette.fromInt(MaterialTheme.colorScheme.onPrimaryContainer.toArgb()).tone(fgTone))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LocalContentColor.current.invert()
|
||||||
|
}
|
||||||
|
|
||||||
|
val contentColor = LocalContentColor.current
|
||||||
|
|
||||||
val textMeasurer = rememberTextMeasurer()
|
val textMeasurer = rememberTextMeasurer()
|
||||||
val minuteStyle = MaterialTheme.typography.labelMedium
|
val minuteStyle = MaterialTheme.typography.labelMedium
|
||||||
@ -118,7 +139,8 @@ fun OrbitClock(
|
|||||||
|
|
||||||
Canvas(
|
Canvas(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(bottom = if (verticalLayout) 8.dp else 0.dp)
|
.padding(bottom = if (verticalLayout) 8.dp else 0.dp,
|
||||||
|
top = if (verticalLayout) 8.dp else 0.dp)
|
||||||
.size(if (verticalLayout) 192.dp else 56.dp)
|
.size(if (verticalLayout) 192.dp else 56.dp)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -130,9 +152,9 @@ fun OrbitClock(
|
|||||||
val mSize = size.width * 0.08f
|
val mSize = size.width * 0.08f
|
||||||
val hSize = rh + sSize + rs - 2f * rm
|
val hSize = rh + sSize + rs - 2f * rm
|
||||||
|
|
||||||
if (verticalLayout) {
|
if (verticalLayout && showSeconds) {
|
||||||
drawCircle(
|
drawCircle(
|
||||||
color = color.copy(alpha = 0.5f),
|
color = contentColor.copy(alpha = 0.5f),
|
||||||
radius = rs,
|
radius = rs,
|
||||||
style = Stroke(
|
style = Stroke(
|
||||||
width = strokeWidth.toPx(),
|
width = strokeWidth.toPx(),
|
||||||
@ -141,7 +163,7 @@ fun OrbitClock(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
drawCircle(
|
drawCircle(
|
||||||
color = color.copy(alpha = 0.5f),
|
color = contentColor.copy(alpha = 0.5f),
|
||||||
radius = rm,
|
radius = rm,
|
||||||
style = Stroke(
|
style = Stroke(
|
||||||
width = strokeWidth.toPx(),
|
width = strokeWidth.toPx(),
|
||||||
@ -154,7 +176,7 @@ fun OrbitClock(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
drawCircle(
|
drawCircle(
|
||||||
color = color.copy(alpha = 0.5f),
|
color = contentColor.copy(alpha = 0.5f),
|
||||||
radius = rh,
|
radius = rh,
|
||||||
style = Stroke(
|
style = Stroke(
|
||||||
width = strokeWidth.toPx(),
|
width = strokeWidth.toPx(),
|
||||||
@ -171,7 +193,7 @@ fun OrbitClock(
|
|||||||
val mPos = Offset(x = sin(animatedMins) * rm, y = -cos(animatedMins) * rm)
|
val mPos = Offset(x = sin(animatedMins) * rm, y = -cos(animatedMins) * rm)
|
||||||
val hPos = Offset(x = sin(animatedHrs) * rh, y = -cos(animatedHrs) * rh)
|
val hPos = Offset(x = sin(animatedHrs) * rh, y = -cos(animatedHrs) * rh)
|
||||||
|
|
||||||
if (verticalLayout) {
|
if (verticalLayout && showSeconds) {
|
||||||
drawCircle(
|
drawCircle(
|
||||||
color = Color.Black,
|
color = Color.Black,
|
||||||
radius = sSize,
|
radius = sSize,
|
||||||
@ -208,34 +230,47 @@ fun OrbitClock(
|
|||||||
|
|
||||||
drawText(
|
drawText(
|
||||||
textMResult,
|
textMResult,
|
||||||
color = color.invert(alpha = 0.65f),
|
color = Color.Black,
|
||||||
|
topLeft = size.center - textMResult.size.center.toOffset() + mPos,
|
||||||
|
blendMode = BlendMode.DstOut
|
||||||
|
)
|
||||||
|
drawText(
|
||||||
|
textHResult,
|
||||||
|
color = Color.Black,
|
||||||
|
topLeft = size.center - textHResult.size.center.toOffset() + mPos,
|
||||||
|
blendMode = BlendMode.DstOut
|
||||||
|
)
|
||||||
|
|
||||||
|
drawText(
|
||||||
|
textMResult,
|
||||||
|
color = foreground,
|
||||||
topLeft = size.center - textMResult.size.center.toOffset() + mPos,
|
topLeft = size.center - textMResult.size.center.toOffset() + mPos,
|
||||||
blendMode = BlendMode.Overlay
|
blendMode = BlendMode.Overlay
|
||||||
)
|
)
|
||||||
drawText(
|
drawText(
|
||||||
textHResult,
|
textHResult,
|
||||||
color = color.invert(alpha = 0.65f),
|
color = foreground,
|
||||||
topLeft = size.center - textHResult.size.center.toOffset() + hPos,
|
topLeft = size.center - textHResult.size.center.toOffset() + hPos,
|
||||||
blendMode = BlendMode.Overlay
|
blendMode = BlendMode.Overlay
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verticalLayout) {
|
if (verticalLayout && showSeconds) {
|
||||||
drawCircle(
|
drawCircle(
|
||||||
color = color,
|
color = background,
|
||||||
radius = sSize,
|
radius = sSize,
|
||||||
center = size.center + sPos,
|
center = size.center + sPos,
|
||||||
blendMode = BlendMode.Overlay
|
blendMode = BlendMode.Overlay
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
drawCircle(
|
drawCircle(
|
||||||
color = color,
|
color = background,
|
||||||
radius = mSize,
|
radius = mSize,
|
||||||
center = size.center + mPos,
|
center = size.center + mPos,
|
||||||
blendMode = BlendMode.Overlay
|
blendMode = BlendMode.Overlay
|
||||||
)
|
)
|
||||||
drawCircle(
|
drawCircle(
|
||||||
color = color,
|
color = background,
|
||||||
radius = hSize,
|
radius = hSize,
|
||||||
center = size.center + hPos,
|
center = size.center + hPos,
|
||||||
blendMode = BlendMode.Overlay
|
blendMode = BlendMode.Overlay
|
||||||
|
|||||||
@ -0,0 +1,282 @@
|
|||||||
|
package de.mm20.launcher2.ui.launcher.widgets.clock.clocks
|
||||||
|
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material3.LocalContentColor
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.PathFillType
|
||||||
|
import androidx.compose.ui.graphics.SolidColor
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.graphics.vector.path
|
||||||
|
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
|
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||||
|
import kotlinx.coroutines.awaitCancellation
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.ZoneId
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SegmentClock(
|
||||||
|
time: Long,
|
||||||
|
compact: Boolean,
|
||||||
|
showSeconds: Boolean,
|
||||||
|
useThemeColor: Boolean
|
||||||
|
) {
|
||||||
|
val parsed = Instant.ofEpochMilli(time).atZone(ZoneId.systemDefault())
|
||||||
|
val hour = parsed.hour
|
||||||
|
val minute = parsed.minute
|
||||||
|
val second = parsed.second
|
||||||
|
val flick = remember { mutableStateOf(time % 1000 <= 500) }
|
||||||
|
|
||||||
|
val enabled = if (useThemeColor) {
|
||||||
|
if (LocalContentColor.current == Color.White) {
|
||||||
|
if (LocalDarkTheme.current) MaterialTheme.colorScheme.onPrimaryContainer
|
||||||
|
else MaterialTheme.colorScheme.primaryContainer
|
||||||
|
} else {
|
||||||
|
if (LocalDarkTheme.current) MaterialTheme.colorScheme.primaryContainer
|
||||||
|
else MaterialTheme.colorScheme.primary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LocalContentColor.current
|
||||||
|
}
|
||||||
|
val disabled = LocalContentColor.current
|
||||||
|
|
||||||
|
val owner = LocalLifecycleOwner.current
|
||||||
|
LaunchedEffect(null) {
|
||||||
|
owner.lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
|
val handler = Handler(Looper.myLooper()!!)
|
||||||
|
|
||||||
|
val callback = object : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
val currentTime = System.currentTimeMillis()
|
||||||
|
flick.value = currentTime % 1000 <= 500
|
||||||
|
handler.postDelayed(this, (500 - (currentTime % 500)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val currentTime = System.currentTimeMillis()
|
||||||
|
handler.postDelayed(callback, (500 - (currentTime % 500)))
|
||||||
|
|
||||||
|
try {
|
||||||
|
awaitCancellation()
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
handler.removeCallbacks(callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val allSegmentVectors = remember(compact, enabled, disabled) {
|
||||||
|
val vectors = mutableListOf<ImageVector>()
|
||||||
|
|
||||||
|
for (code in segmentBitsForDigits.indices) {
|
||||||
|
vectors.add(getVectorDigitForNumber(compact, code, enabled, disabled))
|
||||||
|
}
|
||||||
|
|
||||||
|
vectors.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
val separator = remember(compact, enabled) {
|
||||||
|
getVectorSeparator(compact, enabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(top = if (!compact) 16.dp else 0.dp,
|
||||||
|
bottom = if (!compact) 16.dp else 0.dp,
|
||||||
|
start = 0.dp, end = 0.dp),
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Image(allSegmentVectors[if (hour / 10 == 0) 10 else hour / 10], null)
|
||||||
|
Separator(compact)
|
||||||
|
Image(allSegmentVectors[hour % 10], null)
|
||||||
|
|
||||||
|
Separator(compact)
|
||||||
|
Box(Modifier.alpha(if (flick.value) 1f else 0.05f)) { Image(separator, null) }
|
||||||
|
Separator(compact)
|
||||||
|
|
||||||
|
Image(allSegmentVectors[minute / 10], null)
|
||||||
|
Separator(compact)
|
||||||
|
Image(allSegmentVectors[minute % 10], null)
|
||||||
|
|
||||||
|
if (!compact && showSeconds) {
|
||||||
|
Separator(false)
|
||||||
|
Box(Modifier.alpha(if (flick.value) 1f else 0.05f)) { Image(separator, null) }
|
||||||
|
Separator(false)
|
||||||
|
|
||||||
|
Image(allSegmentVectors[second / 10], null)
|
||||||
|
Separator(false)
|
||||||
|
Image(allSegmentVectors[second % 10], null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Separator(compact: Boolean) {
|
||||||
|
Box(Modifier.size(if (compact) 3.dp else 4.dp))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
┌─(A)─┐
|
||||||
|
(F) (B) // Segments on byte: 0bGFEDBCA
|
||||||
|
├─(G)─┤ // (11 values counting one with all bits off at the end)
|
||||||
|
(E) (C)
|
||||||
|
└─(D)─┘
|
||||||
|
*/
|
||||||
|
private val segmentBitsForDigits = arrayOf(0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x00)
|
||||||
|
|
||||||
|
private fun getVectorDigitForNumber(compact: Boolean, number: Int, enabled: Color, disabled: Color) : ImageVector {
|
||||||
|
if (number < 0 || number > segmentBitsForDigits.size) {
|
||||||
|
throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
|
||||||
|
val segment = segmentBitsForDigits[number]
|
||||||
|
val solidEnabled = SolidColor(enabled)
|
||||||
|
val solidDisabled = SolidColor(disabled)
|
||||||
|
|
||||||
|
return ImageVector.Builder(
|
||||||
|
defaultWidth = if (compact) 18.dp else 30.dp,
|
||||||
|
defaultHeight = if (compact) 30.dp else 50.dp,
|
||||||
|
viewportWidth = 15.874999f,
|
||||||
|
viewportHeight = 26.458332f
|
||||||
|
).path(
|
||||||
|
name = "A",
|
||||||
|
fill = if ((segment and 0x01) == 0x01) solidEnabled else solidDisabled,
|
||||||
|
fillAlpha = if ((segment and 0x01) == 0x01) 1.0f else 0.05f,
|
||||||
|
pathFillType = PathFillType.NonZero
|
||||||
|
) {
|
||||||
|
moveTo(4.076372f, 3.6568797f)
|
||||||
|
horizontalLineToRelative(7.802962f)
|
||||||
|
lineTo(12.903025f, 0.0872854f)
|
||||||
|
lineTo(3.470742f, 0.04026844f)
|
||||||
|
curveTo(2.1788f, 0.0804f, 1.4853f, 0.7665f, 1.4853f, 0.7665f)
|
||||||
|
close()
|
||||||
|
}.path(
|
||||||
|
name = "B",
|
||||||
|
fill = if (((segment and 0x02) shr 1) == 0x01) solidEnabled else solidDisabled,
|
||||||
|
fillAlpha = if (((segment and 0x02) shr 1) == 0x01) 1.0f else 0.05f,
|
||||||
|
pathFillType = PathFillType.NonZero
|
||||||
|
) {
|
||||||
|
moveTo(13.50401f, 0.22460027f)
|
||||||
|
lineToRelative(-1.096166f, 4.134793f)
|
||||||
|
lineToRelative(-0.01958f, 7.2860675f)
|
||||||
|
lineToRelative(2.388076f, 1.485313f)
|
||||||
|
lineToRelative(1.076593f, -0.56201f)
|
||||||
|
lineToRelative(0.05628f, -9.253104f)
|
||||||
|
curveToRelative(0.0046f, -0.7586f, -0.9567f, -2.6294f, -2.4052f, -3.0911f)
|
||||||
|
close()
|
||||||
|
}.path(
|
||||||
|
name = "C",
|
||||||
|
fill = if (((segment and 0x04) shr 2) == 0x01) solidEnabled else solidDisabled,
|
||||||
|
fillAlpha = if (((segment and 0x04) shr 2) == 0x01) 1.0f else 0.05f,
|
||||||
|
pathFillType = PathFillType.NonZero
|
||||||
|
) {
|
||||||
|
moveTo(12.407844f, 15.358745f)
|
||||||
|
lineToRelative(2.27063f, -1.505385f)
|
||||||
|
lineToRelative(1.174464f, 0.56201f)
|
||||||
|
lineToRelative(0.0049f, 8.658477f)
|
||||||
|
curveToRelative(0.0015f, 2.733f, -2.9606f, 3.3846f, -2.9606f, 3.3846f)
|
||||||
|
lineToRelative(-0.469785f, -3.637352f)
|
||||||
|
close()
|
||||||
|
}.path(
|
||||||
|
name = "D",
|
||||||
|
fill = if (((segment and 0x08) shr 3) == 0x01) solidEnabled else solidDisabled,
|
||||||
|
fillAlpha = if (((segment and 0x08) shr 3) == 0x01) 1.0f else 0.05f,
|
||||||
|
pathFillType = PathFillType.NonZero
|
||||||
|
) {
|
||||||
|
moveTo(4.088724f, 22.705027f)
|
||||||
|
lineToRelative(-2.681692f, 3.010772f)
|
||||||
|
curveToRelative(0.6655f, 0.7226f, 2.1287f, 0.7828f, 2.1287f, 0.7828f)
|
||||||
|
horizontalLineToRelative(8.861135f)
|
||||||
|
lineToRelative(-0.550436f, -3.793573f)
|
||||||
|
close()
|
||||||
|
}.path(
|
||||||
|
name = "E",
|
||||||
|
fill = if (((segment and 0x10) shr 4) == 0x01) solidEnabled else solidDisabled,
|
||||||
|
fillAlpha = if (((segment and 0x10) shr 4) == 0x01) 1.0f else 0.05f,
|
||||||
|
pathFillType = PathFillType.NonZero
|
||||||
|
) {
|
||||||
|
moveTo(3.247025f, 15.459104f)
|
||||||
|
lineToRelative(-2.290205f, -1.686032f)
|
||||||
|
lineToRelative(-0.880847f, 0.461652f)
|
||||||
|
lineToRelative(-0.0367f, 8.711166f)
|
||||||
|
reflectiveCurveToRelative(0.04649f, 1.324739f, 0.800103f, 2.248042f)
|
||||||
|
lineToRelative(2.427225f, -2.461695f)
|
||||||
|
close()
|
||||||
|
}.path(
|
||||||
|
name = "F",
|
||||||
|
fill = if (((segment and 0x20) shr 5) == 0x01) solidEnabled else solidDisabled,
|
||||||
|
fillAlpha = if (((segment and 0x20) shr 5) == 0x01) 1.0f else 0.05f,
|
||||||
|
pathFillType = PathFillType.NonZero
|
||||||
|
) {
|
||||||
|
moveTo(1.035118f, 1.2482624f)
|
||||||
|
reflectiveCurveToRelative(-0.928317f, 0.8023766f, -0.929784f, 2.1552107f)
|
||||||
|
lineToRelative(-0.0098f, 9.024787f)
|
||||||
|
lineToRelative(0.880848f, 0.521867f)
|
||||||
|
lineToRelative(2.290204f, -1.465242f)
|
||||||
|
verticalLineToRelative(-7.707575f)
|
||||||
|
close()
|
||||||
|
}.path(
|
||||||
|
name = "G",
|
||||||
|
fill = if (((segment and 0x40) shr 6) == 0x01) solidEnabled else solidDisabled,
|
||||||
|
fillAlpha = if (((segment and 0x40) shr 6) == 0x01) 1.0f else 0.05f,
|
||||||
|
pathFillType = PathFillType.NonZero
|
||||||
|
) {
|
||||||
|
moveTo(1.603085f, 13.391707f)
|
||||||
|
curveToRelative(0.8352f, -0.5352f, 1.6703f, -1.0705f, 2.5055f, -1.6057f)
|
||||||
|
horizontalLineToRelative(7.340399f)
|
||||||
|
curveToRelative(0.9265f, 0.5486f, 1.853f, 1.0973f, 2.7796f, 1.6459f)
|
||||||
|
curveToRelative(-0.8482f, 0.5553f, -1.6964f, 1.1106f, -2.5447f, 1.666f)
|
||||||
|
horizontalLineTo(4.069459f)
|
||||||
|
curveToRelative(-0.8221f, -0.5687f, -1.6442f, -1.1374f, -2.4664f, -1.7061f)
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getVectorSeparator(compact: Boolean, enabled: Color) : ImageVector {
|
||||||
|
|
||||||
|
return ImageVector.Builder(
|
||||||
|
defaultWidth = if (compact) 3.6.dp else 6.dp,
|
||||||
|
defaultHeight = if (compact) 30.dp else 50.dp,
|
||||||
|
viewportWidth = 3.175f,
|
||||||
|
viewportHeight = 26.458f
|
||||||
|
).apply {
|
||||||
|
path(
|
||||||
|
fill = SolidColor(enabled),
|
||||||
|
fillAlpha = 1.0f,
|
||||||
|
pathFillType = PathFillType.NonZero
|
||||||
|
) {
|
||||||
|
moveTo(3.175f, 18.5f)
|
||||||
|
arcToRelative(1.587f, 1.587f, 0f, isMoreThanHalf = false, isPositiveArc = true, -1.587f, 1.588f)
|
||||||
|
arcToRelative(1.587f, 1.587f, 0f, isMoreThanHalf = false, isPositiveArc = true, -1.588f, -1.588f)
|
||||||
|
arcToRelative(1.587f, 1.587f, 0f, isMoreThanHalf = false, isPositiveArc = true, 1.588f, -1.587f)
|
||||||
|
arcToRelative(1.587f, 1.587f, 0f, isMoreThanHalf = false, isPositiveArc = true, 1.587f, 1.587f)
|
||||||
|
close()
|
||||||
|
moveToRelative(0f, -9.634f)
|
||||||
|
arcToRelative(1.587f, 1.587f, 0f, isMoreThanHalf = false, isPositiveArc = true, -1.587f, 1.588f)
|
||||||
|
arcToRelative(1.587f, 1.587f, 0f, isMoreThanHalf = false, isPositiveArc = true, -1.588f, -1.588f)
|
||||||
|
arcToRelative(1.587f, 1.587f, 0f, isMoreThanHalf = false, isPositiveArc = true, 1.588f, -1.587f)
|
||||||
|
arcToRelative(1.587f, 1.587f, 0f, isMoreThanHalf = false, isPositiveArc = true, 1.587f, 1.587f)
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
}.build()
|
||||||
|
}
|
||||||
@ -24,6 +24,7 @@ import androidx.navigation.navArgument
|
|||||||
import de.mm20.launcher2.licenses.AppLicense
|
import de.mm20.launcher2.licenses.AppLicense
|
||||||
import de.mm20.launcher2.licenses.OpenSourceLicenses
|
import de.mm20.launcher2.licenses.OpenSourceLicenses
|
||||||
import de.mm20.launcher2.ui.base.BaseActivity
|
import de.mm20.launcher2.ui.base.BaseActivity
|
||||||
|
import de.mm20.launcher2.ui.base.ProvideCurrentTime
|
||||||
import de.mm20.launcher2.ui.base.ProvideSettings
|
import de.mm20.launcher2.ui.base.ProvideSettings
|
||||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||||
import de.mm20.launcher2.ui.locals.LocalNavController
|
import de.mm20.launcher2.ui.locals.LocalNavController
|
||||||
@ -84,6 +85,7 @@ class SettingsActivity : BaseActivity() {
|
|||||||
LocalWallpaperColors provides wallpaperColors,
|
LocalWallpaperColors provides wallpaperColors,
|
||||||
) {
|
) {
|
||||||
ProvideSettings {
|
ProvideSettings {
|
||||||
|
ProvideCurrentTime {
|
||||||
LauncherTheme {
|
LauncherTheme {
|
||||||
val systemBarColor = MaterialTheme.colorScheme.surfaceDim
|
val systemBarColor = MaterialTheme.colorScheme.surfaceDim
|
||||||
val systemBarColorAlt = MaterialTheme.colorScheme.onSurface
|
val systemBarColorAlt = MaterialTheme.colorScheme.onSurface
|
||||||
@ -241,6 +243,7 @@ class SettingsActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val EXTRA_ROUTE = "de.mm20.launcher2.settings.ROUTE"
|
const val EXTRA_ROUTE = "de.mm20.launcher2.settings.ROUTE"
|
||||||
|
|||||||
@ -7,9 +7,7 @@ import de.mm20.launcher2.preferences.ClockWidgetColors
|
|||||||
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||||
import de.mm20.launcher2.preferences.ui.ClockWidgetSettings
|
import de.mm20.launcher2.preferences.ui.ClockWidgetSettings
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
@ -34,6 +32,20 @@ class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
settings.setColor(color)
|
settings.setColor(color)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val showSeconds = settings.showSeconds
|
||||||
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
|
fun setShowSeconds(showSeconds: Boolean) {
|
||||||
|
settings.setShowSeconds(showSeconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
val useThemeColor = settings.useThemeColor
|
||||||
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
|
fun setUseThemeColor(boolean: Boolean) {
|
||||||
|
settings.setUseThemeColor(boolean)
|
||||||
|
}
|
||||||
|
|
||||||
val fillHeight = settings.fillHeight
|
val fillHeight = settings.fillHeight
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setFillHeight(fillHeight: Boolean) {
|
fun setFillHeight(fillHeight: Boolean) {
|
||||||
|
|||||||
@ -600,6 +600,8 @@
|
|||||||
<string name="preference_clockwidget_layout">Layout</string>
|
<string name="preference_clockwidget_layout">Layout</string>
|
||||||
<string name="preference_clockwidget_layout_vertical">Default</string>
|
<string name="preference_clockwidget_layout_vertical">Default</string>
|
||||||
<string name="preference_clockwidget_layout_horizontal">Compact</string>
|
<string name="preference_clockwidget_layout_horizontal">Compact</string>
|
||||||
|
<string name="preference_clock_widget_show_seconds">Show seconds</string>
|
||||||
|
<string name="preference_clock_widget_use_theme_color">Use theme color</string>
|
||||||
<string name="preference_clock_widget_fill_height">Fill screen height</string>
|
<string name="preference_clock_widget_fill_height">Fill screen height</string>
|
||||||
<string name="preference_clock_widget_fill_height_summary">Insert extra space above the clock to fill the entire screen height</string>
|
<string name="preference_clock_widget_fill_height_summary">Insert extra space above the clock to fill the entire screen height</string>
|
||||||
<string name="preference_clock_widget_color">Color</string>
|
<string name="preference_clock_widget_color">Color</string>
|
||||||
@ -900,4 +902,14 @@
|
|||||||
<string name="unavailable_searchable">This item does not exist anymore.</string>
|
<string name="unavailable_searchable">This item does not exist anymore.</string>
|
||||||
<string name="preference_search_bar_separate_work_profile">Separate work profile apps</string>
|
<string name="preference_search_bar_separate_work_profile">Separate work profile apps</string>
|
||||||
<string name="preference_search_bar_separate_work_profile_summary">Shows work profile apps in a separate tab</string>
|
<string name="preference_search_bar_separate_work_profile_summary">Shows work profile apps in a separate tab</string>
|
||||||
|
|
||||||
|
<string name="clock_style_digital1">Bold</string>
|
||||||
|
<string name="clock_style_digital2">Simple</string>
|
||||||
|
<string name="clock_style_orbit">Orbit</string>
|
||||||
|
<string name="clock_style_binary">Binary</string>
|
||||||
|
<string name="clock_style_analog">Hands</string>
|
||||||
|
<string name="clock_style_segment">7 segment</string>
|
||||||
|
<string name="clock_style_empty">No clock</string>
|
||||||
|
<string name="clock_variant_standard">Standard</string>
|
||||||
|
<string name="clock_variant_outlined">Outlined</string>
|
||||||
</resources>
|
</resources>
|
||||||
@ -27,6 +27,8 @@ data class LauncherSettingsData(
|
|||||||
val clockWidgetCompact: Boolean = false,
|
val clockWidgetCompact: Boolean = false,
|
||||||
val clockWidgetStyle: ClockWidgetStyle = ClockWidgetStyle.Digital1(),
|
val clockWidgetStyle: ClockWidgetStyle = ClockWidgetStyle.Digital1(),
|
||||||
val clockWidgetColors: ClockWidgetColors = ClockWidgetColors.Auto,
|
val clockWidgetColors: ClockWidgetColors = ClockWidgetColors.Auto,
|
||||||
|
val clockWidgetShowSeconds: Boolean = false,
|
||||||
|
val clockWidgetUseThemeColor: Boolean = false,
|
||||||
val clockWidgetAlarmPart: Boolean = true,
|
val clockWidgetAlarmPart: Boolean = true,
|
||||||
val clockWidgetBatteryPart: Boolean = true,
|
val clockWidgetBatteryPart: Boolean = true,
|
||||||
val clockWidgetMusicPart: Boolean = true,
|
val clockWidgetMusicPart: Boolean = true,
|
||||||
@ -189,7 +191,6 @@ sealed interface ClockWidgetStyle {
|
|||||||
@Serializable
|
@Serializable
|
||||||
enum class Variant {
|
enum class Variant {
|
||||||
Default,
|
Default,
|
||||||
MDY,
|
|
||||||
OnePlus,
|
OnePlus,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,6 +211,10 @@ sealed interface ClockWidgetStyle {
|
|||||||
@SerialName("binary")
|
@SerialName("binary")
|
||||||
data object Binary : ClockWidgetStyle
|
data object Binary : ClockWidgetStyle
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("segment")
|
||||||
|
data object Segment : ClockWidgetStyle
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("empty")
|
@SerialName("empty")
|
||||||
data object Empty : ClockWidgetStyle
|
data object Empty : ClockWidgetStyle
|
||||||
|
|||||||
@ -76,7 +76,7 @@ class Migration1(
|
|||||||
LegacySettings.ClockWidgetSettings.ClockStyle.AnalogClock -> ClockWidgetStyle.Analog
|
LegacySettings.ClockWidgetSettings.ClockStyle.AnalogClock -> ClockWidgetStyle.Analog
|
||||||
LegacySettings.ClockWidgetSettings.ClockStyle.EmptyClock -> ClockWidgetStyle.Empty
|
LegacySettings.ClockWidgetSettings.ClockStyle.EmptyClock -> ClockWidgetStyle.Empty
|
||||||
LegacySettings.ClockWidgetSettings.ClockStyle.DigitalClock1_MDY -> ClockWidgetStyle.Digital1(
|
LegacySettings.ClockWidgetSettings.ClockStyle.DigitalClock1_MDY -> ClockWidgetStyle.Digital1(
|
||||||
variant = ClockWidgetStyle.Digital1.Variant.MDY
|
variant = ClockWidgetStyle.Digital1.Variant.Default
|
||||||
)
|
)
|
||||||
|
|
||||||
LegacySettings.ClockWidgetSettings.ClockStyle.DigitalClock1_Outlined -> ClockWidgetStyle.Digital1(
|
LegacySettings.ClockWidgetSettings.ClockStyle.DigitalClock1_Outlined -> ClockWidgetStyle.Digital1(
|
||||||
|
|||||||
@ -96,12 +96,30 @@ class ClockWidgetSettings internal constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val color
|
||||||
|
get() = launcherDataStore.data.map { it.clockWidgetColors }
|
||||||
|
|
||||||
fun setColor(color: ClockWidgetColors) {
|
fun setColor(color: ClockWidgetColors) {
|
||||||
launcherDataStore.update {
|
launcherDataStore.update {
|
||||||
it.copy(clockWidgetColors = color)
|
it.copy(clockWidgetColors = color)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val color
|
val showSeconds
|
||||||
get() = launcherDataStore.data.map { it.clockWidgetColors }
|
get() = launcherDataStore.data.map { it.clockWidgetShowSeconds }
|
||||||
|
|
||||||
|
fun setShowSeconds(enabled: Boolean) {
|
||||||
|
launcherDataStore.update {
|
||||||
|
it.copy(clockWidgetShowSeconds = enabled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val useThemeColor
|
||||||
|
get() = launcherDataStore.data.map { it.clockWidgetUseThemeColor }
|
||||||
|
|
||||||
|
fun setUseThemeColor(enabled: Boolean) {
|
||||||
|
launcherDataStore.update {
|
||||||
|
it.copy(clockWidgetUseThemeColor = enabled)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -8,24 +8,24 @@ pluginSdk = "1.0.0"
|
|||||||
gradle = "8.1.2"
|
gradle = "8.1.2"
|
||||||
android-gradle-plugin = "8.2.2"
|
android-gradle-plugin = "8.2.2"
|
||||||
protobuf-gradle-plugin = "0.9.4"
|
protobuf-gradle-plugin = "0.9.4"
|
||||||
ksp-gradle-plugin = "1.9.0-1.0.13"
|
ksp-gradle-plugin = "1.9.23-1.0.19"
|
||||||
|
|
||||||
kotlin = "1.9.22"
|
kotlin = "1.9.23"
|
||||||
kotlinx-coroutines = "1.7.3"
|
kotlinx-coroutines = "1.8.0"
|
||||||
kotlinx-immutable = "0.3.5"
|
kotlinx-immutable = "0.3.5"
|
||||||
kotlinx-serialization = "1.6.2"
|
kotlinx-serialization = "1.6.3"
|
||||||
|
|
||||||
jetbrains-markdown = "0.4.1"
|
jetbrains-markdown = "0.5.2"
|
||||||
|
|
||||||
androidx-compose = "1.7.0-alpha02"
|
androidx-compose = "1.7.0-alpha05"
|
||||||
androidx-compose-material3 = "1.2.0"
|
androidx-compose-material3 = "1.3.0-alpha03"
|
||||||
androidx-compose-compiler = "1.5.8"
|
androidx-compose-compiler = "1.5.11"
|
||||||
androidx-lifecycle = "2.7.0"
|
androidx-lifecycle = "2.7.0"
|
||||||
androidx-core = "1.12.0"
|
androidx-core = "1.12.0"
|
||||||
androidx-appcompat = "1.7.0-alpha03"
|
androidx-appcompat = "1.7.0-alpha03"
|
||||||
androidx-activity = "1.8.2"
|
androidx-activity = "1.8.2"
|
||||||
androidx-work = "2.9.0"
|
androidx-work = "2.9.0"
|
||||||
androidx-browser = "1.7.0"
|
androidx-browser = "1.8.0"
|
||||||
androidx-palette = "1.0.0"
|
androidx-palette = "1.0.0"
|
||||||
androidx-media2 = "1.3.0"
|
androidx-media2 = "1.3.0"
|
||||||
androidx-room = "2.6.1"
|
androidx-room = "2.6.1"
|
||||||
@ -108,7 +108,7 @@ coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coi
|
|||||||
|
|
||||||
leakcanary = { group = "com.squareup.leakcanary", name = "leakcanary", version = "2.10" }
|
leakcanary = { group = "com.squareup.leakcanary", name = "leakcanary", version = "2.10" }
|
||||||
suncalc = { group = "org.shredzone.commons", name = "commons-suncalc", version = "3.7" }
|
suncalc = { group = "org.shredzone.commons", name = "commons-suncalc", version = "3.7" }
|
||||||
jsoup = { group = "org.jsoup", name = "jsoup", version = "1.15.4" }
|
jsoup = { group = "org.jsoup", name = "jsoup", version = "1.16.1" }
|
||||||
commons-text = { group = "org.apache.commons", name = "commons-text", version = "1.10.0" }
|
commons-text = { group = "org.apache.commons", name = "commons-text", version = "1.10.0" }
|
||||||
|
|
||||||
# 4.4.2 is the last GPL compatible version, don't update to 5.x
|
# 4.4.2 is the last GPL compatible version, don't update to 5.x
|
||||||
@ -147,4 +147,4 @@ protobuf = { id = "com.google.protobuf", version.ref = "protobuf-gradle-plugin"
|
|||||||
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp-gradle-plugin" }
|
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp-gradle-plugin" }
|
||||||
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||||
kotlin-plugin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
kotlin-plugin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||||
dokka = { id = "org.jetbrains.dokka", version = "1.9.10" }
|
dokka = { id = "org.jetbrains.dokka", version = "1.9.20" }
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user