[WIP] Custom widgets as watch face
This commit is contained in:
parent
efc50eb0a8
commit
3288d933c5
@ -0,0 +1,41 @@
|
||||
package de.mm20.launcher2.ui.base
|
||||
|
||||
import android.appwidget.AppWidgetHost
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||
import kotlinx.coroutines.awaitCancellation
|
||||
|
||||
val LocalAppWidgetHost =
|
||||
staticCompositionLocalOf<AppWidgetHost> { throw IllegalStateException("AppWidgetHost is not provided") }
|
||||
|
||||
@Composable
|
||||
fun ProvideAppWidgetHost(
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
val context = LocalContext.current
|
||||
val widgetHost = remember { AppWidgetHost(context.applicationContext, 44203) }
|
||||
LaunchedEffect(null) {
|
||||
lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
widgetHost.startListening()
|
||||
try {
|
||||
awaitCancellation()
|
||||
} finally {
|
||||
try {
|
||||
widgetHost.stopListening()
|
||||
} catch (e: Exception) {
|
||||
CrashReporter.logException(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CompositionLocalProvider(LocalAppWidgetHost provides widgetHost, content = content)
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package de.mm20.launcher2.ui.base
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
@Composable
|
||||
fun ProvideCompositionLocals(content: @Composable () -> Unit) {
|
||||
ProvideCurrentTime {
|
||||
ProvideSettings {
|
||||
ProvideAppWidgetHost {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -38,8 +38,7 @@ import de.mm20.launcher2.preferences.BaseLayout
|
||||
import de.mm20.launcher2.preferences.SystemBarColors
|
||||
import de.mm20.launcher2.ui.assistant.AssistantScaffold
|
||||
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.ProvideCompositionLocals
|
||||
import de.mm20.launcher2.ui.component.NavBarEffects
|
||||
import de.mm20.launcher2.ui.gestures.GestureDetector
|
||||
import de.mm20.launcher2.ui.gestures.LocalGestureDetector
|
||||
@ -101,7 +100,7 @@ abstract class SharedLauncherActivity(
|
||||
LocalGestureDetector provides gestureDetector,
|
||||
) {
|
||||
LauncherTheme {
|
||||
ProvideSettings {
|
||||
ProvideCompositionLocals {
|
||||
val statusBarColor by viewModel.statusBarColor.collectAsState()
|
||||
val navBarColor by viewModel.navBarColor.collectAsState()
|
||||
|
||||
@ -160,7 +159,6 @@ abstract class SharedLauncherActivity(
|
||||
systemUiController.isNavigationBarVisible = !hideNav
|
||||
}
|
||||
|
||||
ProvideCurrentTime {
|
||||
OverlayHost(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
@ -270,7 +268,6 @@ abstract class SharedLauncherActivity(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var pauseTime = 0L
|
||||
override fun onPause() {
|
||||
|
||||
@ -80,6 +80,7 @@ import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.base.LocalAppWidgetHost
|
||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||
import de.mm20.launcher2.ui.component.LargeMessage
|
||||
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
||||
@ -103,7 +104,6 @@ import kotlin.math.roundToInt
|
||||
|
||||
@Composable
|
||||
fun ConfigureWidgetSheet(
|
||||
appWidgetHost: AppWidgetHost,
|
||||
widget: Widget,
|
||||
onWidgetUpdated: (Widget) -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
@ -128,7 +128,7 @@ fun ConfigureWidgetSheet(
|
||||
) {
|
||||
when (widget) {
|
||||
is WeatherWidget -> ConfigureWeatherWidget(widget, onWidgetUpdated)
|
||||
is AppWidget -> ConfigureAppWidget(appWidgetHost, widget, onWidgetUpdated)
|
||||
is AppWidget -> ConfigureAppWidget(widget, onWidgetUpdated)
|
||||
is CalendarWidget -> ConfigureCalendarWidget(widget, onWidgetUpdated)
|
||||
is FavoritesWidget -> ConfigureFavoritesWidget(widget, onWidgetUpdated)
|
||||
is MusicWidget -> ConfigureMusicWidget()
|
||||
@ -272,7 +272,6 @@ fun ColumnScope.ConfigureMusicWidget(
|
||||
|
||||
@Composable
|
||||
fun ColumnScope.ConfigureAppWidget(
|
||||
appWidgetHost: AppWidgetHost,
|
||||
widget: AppWidget,
|
||||
onWidgetUpdated: (Widget) -> Unit,
|
||||
) {
|
||||
@ -346,7 +345,6 @@ fun ColumnScope.ConfigureAppWidget(
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant)
|
||||
) {
|
||||
ExternalWidget(
|
||||
appWidgetHost = appWidgetHost,
|
||||
widgetInfo = widgetInfo,
|
||||
widgetId = widget.config.widgetId,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
@ -472,6 +470,7 @@ fun ColumnScope.ConfigureAppWidget(
|
||||
}
|
||||
}
|
||||
if (isAtLeastApiLevel(28) && widgetInfo.widgetFeatures and AppWidgetProviderInfo.WIDGET_FEATURE_RECONFIGURABLE != 0) {
|
||||
val appWidgetHost = LocalAppWidgetHost.current
|
||||
TextButton(
|
||||
modifier = Modifier
|
||||
.padding(top = 8.dp)
|
||||
|
||||
@ -251,6 +251,8 @@ private class BindAndConfigureAppWidgetContract(
|
||||
|
||||
@Composable
|
||||
fun WidgetPickerSheet(
|
||||
includeBuiltinWidgets: Boolean = true,
|
||||
title: String = stringResource(R.string.widget_pick_widget),
|
||||
onWidgetSelected: (Widget) -> Unit,
|
||||
onDismiss: () -> Unit
|
||||
) {
|
||||
@ -277,7 +279,7 @@ fun WidgetPickerSheet(
|
||||
BottomSheetDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = {
|
||||
Text(stringResource(R.string.widget_add_widget))
|
||||
Text(title)
|
||||
}) {
|
||||
val builtIn by viewModel.builtInWidgets.collectAsState(emptyList())
|
||||
LazyColumn(
|
||||
@ -318,6 +320,7 @@ fun WidgetPickerSheet(
|
||||
) {
|
||||
}
|
||||
}
|
||||
if (includeBuiltinWidgets) {
|
||||
items(builtIn) {
|
||||
OutlinedCard(
|
||||
modifier = Modifier
|
||||
@ -359,6 +362,7 @@ fun WidgetPickerSheet(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (group in appWidgetGroups) {
|
||||
val expanded = viewModel.expandedGroup.value == group.packageName || expandAllGroups
|
||||
item(
|
||||
|
||||
@ -36,6 +36,7 @@ import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.base.LocalAppWidgetHost
|
||||
import de.mm20.launcher2.ui.ktx.animateTo
|
||||
import de.mm20.launcher2.ui.launcher.sheets.LocalBottomSheetManager
|
||||
import de.mm20.launcher2.ui.launcher.sheets.WidgetPickerSheet
|
||||
@ -51,27 +52,11 @@ fun WidgetColumn(
|
||||
) {
|
||||
|
||||
val viewModel: WidgetsVM = viewModel()
|
||||
val context = LocalContext.current
|
||||
val bottomSheetManager = LocalBottomSheetManager.current
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
val widgetHost = remember { AppWidgetHost(context.applicationContext, 44203) }
|
||||
|
||||
var addNewWidget by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(null) {
|
||||
lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
widgetHost.startListening()
|
||||
try {
|
||||
awaitCancellation()
|
||||
} finally {
|
||||
try {
|
||||
widgetHost.stopListening()
|
||||
} catch (e: Exception) {
|
||||
CrashReporter.logException(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
@ -92,9 +77,10 @@ fun WidgetColumn(
|
||||
dragOffsetAfterSwap = null
|
||||
}
|
||||
|
||||
val widgetHost = LocalAppWidgetHost.current
|
||||
|
||||
WidgetItem(
|
||||
widget = widget,
|
||||
appWidgetHost = widgetHost,
|
||||
editMode = editMode,
|
||||
onWidgetAdd = { widget, offset ->
|
||||
viewModel.addWidget(widget, i + offset)
|
||||
|
||||
@ -60,7 +60,6 @@ import de.mm20.launcher2.widgets.Widget
|
||||
@Composable
|
||||
fun WidgetItem(
|
||||
widget: Widget,
|
||||
appWidgetHost: AppWidgetHost,
|
||||
modifier: Modifier = Modifier,
|
||||
editMode: Boolean = false,
|
||||
onWidgetAdd: (widget: Widget, offset: Int) -> Unit = { _, _ -> },
|
||||
@ -222,7 +221,6 @@ fun WidgetItem(
|
||||
}
|
||||
} else {
|
||||
ExternalWidget(
|
||||
appWidgetHost = appWidgetHost,
|
||||
widgetId = widget.config.widgetId,
|
||||
widgetInfo = widgetInfo,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
@ -237,7 +235,6 @@ fun WidgetItem(
|
||||
}
|
||||
if (configure) {
|
||||
ConfigureWidgetSheet(
|
||||
appWidgetHost = appWidgetHost,
|
||||
widget = widget,
|
||||
onWidgetUpdated = onWidgetUpdate,
|
||||
onDismiss = { configure = false },
|
||||
|
||||
@ -74,6 +74,7 @@ import de.mm20.launcher2.ui.component.preferences.Preference
|
||||
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
||||
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.AnalogClock
|
||||
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.BinaryClock
|
||||
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.CustomClock
|
||||
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.OrbitClock
|
||||
@ -97,8 +98,11 @@ fun ClockWidget(
|
||||
val alignment by viewModel.alignment.collectAsState()
|
||||
val time = LocalTime.current
|
||||
|
||||
val darkColors =
|
||||
color == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current || color == ClockWidgetColors.Dark
|
||||
|
||||
val contentColor =
|
||||
if (color == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current || color == ClockWidgetColors.Dark) {
|
||||
if (darkColors) {
|
||||
Color(0, 0, 0, 180)
|
||||
} else {
|
||||
Color.White
|
||||
@ -182,7 +186,7 @@ fun ClockWidget(
|
||||
viewModel.launchClockApp(context)
|
||||
}
|
||||
) {
|
||||
Clock(clockStyle, false)
|
||||
Clock(clockStyle, false, darkColors)
|
||||
}
|
||||
|
||||
if (partProvider != null) {
|
||||
@ -227,7 +231,7 @@ fun ClockWidget(
|
||||
viewModel.launchClockApp(context)
|
||||
}
|
||||
) {
|
||||
Clock(clockStyle, true)
|
||||
Clock(clockStyle, true, darkColors)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -248,10 +252,14 @@ fun ClockWidget(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param darkColors: use dark content color / suited for light backgrounds
|
||||
*/
|
||||
@Composable
|
||||
fun Clock(
|
||||
style: ClockWidgetStyle?,
|
||||
compact: Boolean,
|
||||
darkColors: Boolean = false
|
||||
) {
|
||||
val time = LocalTime.current
|
||||
val clockSettings: ClockWidgetSettings by inject()
|
||||
@ -264,14 +272,51 @@ fun Clock(
|
||||
style,
|
||||
compact,
|
||||
showSeconds,
|
||||
useThemeColor
|
||||
useThemeColor,
|
||||
darkColors
|
||||
)
|
||||
|
||||
is ClockWidgetStyle.Digital2 -> DigitalClock2(time, compact, showSeconds, useThemeColor)
|
||||
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.Digital2 -> DigitalClock2(
|
||||
time,
|
||||
compact,
|
||||
showSeconds,
|
||||
useThemeColor,
|
||||
darkColors
|
||||
)
|
||||
|
||||
is ClockWidgetStyle.Binary -> BinaryClock(
|
||||
time,
|
||||
compact,
|
||||
showSeconds,
|
||||
useThemeColor,
|
||||
darkColors
|
||||
)
|
||||
|
||||
is ClockWidgetStyle.Analog -> AnalogClock(
|
||||
time,
|
||||
compact,
|
||||
showSeconds,
|
||||
useThemeColor,
|
||||
darkColors
|
||||
)
|
||||
|
||||
is ClockWidgetStyle.Orbit -> OrbitClock(
|
||||
time,
|
||||
compact,
|
||||
showSeconds,
|
||||
useThemeColor,
|
||||
darkColors
|
||||
)
|
||||
|
||||
is ClockWidgetStyle.Segment -> SegmentClock(
|
||||
time,
|
||||
compact,
|
||||
showSeconds,
|
||||
useThemeColor,
|
||||
darkColors
|
||||
)
|
||||
|
||||
is ClockWidgetStyle.Custom -> CustomClock(style, compact, useThemeColor, darkColors)
|
||||
is ClockWidgetStyle.Empty -> {}
|
||||
else -> {}
|
||||
}
|
||||
@ -426,7 +471,7 @@ fun ConfigureClockWidgetSheet(
|
||||
viewModel.setUseThemeColor(it)
|
||||
}
|
||||
)
|
||||
AnimatedVisibility(compact == false) {
|
||||
AnimatedVisibility(compact == false && style !is ClockWidgetStyle.Custom) {
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_clock_widget_show_seconds),
|
||||
icon = Icons.Rounded.AccessTime,
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
package de.mm20.launcher2.ui.launcher.widgets.clock
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.ActivityOptions
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.scaleOut
|
||||
@ -19,8 +24,8 @@ import androidx.compose.material.icons.rounded.Check
|
||||
import androidx.compose.material.icons.rounded.ChevronLeft
|
||||
import androidx.compose.material.icons.rounded.ChevronRight
|
||||
import androidx.compose.material.icons.rounded.Settings
|
||||
import androidx.compose.material.icons.rounded.Style
|
||||
import androidx.compose.material.icons.rounded.Tune
|
||||
import androidx.compose.material.icons.rounded.Widgets
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
@ -38,6 +43,7 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@ -50,8 +56,11 @@ import androidx.compose.ui.zIndex
|
||||
import de.mm20.launcher2.preferences.ClockWidgetColors
|
||||
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.base.LocalAppWidgetHost
|
||||
import de.mm20.launcher2.ui.launcher.sheets.WidgetPickerSheet
|
||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
|
||||
import de.mm20.launcher2.widgets.AppWidget
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
@ -63,6 +72,9 @@ fun WatchFaceSelector(
|
||||
onSelect: (ClockWidgetStyle) -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
var showWidgetPicker by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@ -78,7 +90,8 @@ fun WatchFaceSelector(
|
||||
modifier = Modifier,
|
||||
) {
|
||||
val pagerState = rememberPagerState(
|
||||
initialPage = styles.indexOfFirst { it.javaClass == selected?.javaClass }.coerceAtLeast(0),
|
||||
initialPage = styles.indexOfFirst { it.javaClass == selected?.javaClass }
|
||||
.coerceAtLeast(0),
|
||||
) {
|
||||
styles.size
|
||||
}
|
||||
@ -93,7 +106,7 @@ fun WatchFaceSelector(
|
||||
|
||||
Box {
|
||||
androidx.compose.animation.AnimatedVisibility(
|
||||
selected is ClockWidgetStyle.Digital1,
|
||||
selected is ClockWidgetStyle.Digital1 || selected is ClockWidgetStyle.Custom,
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.zIndex(1f),
|
||||
@ -123,12 +136,60 @@ fun WatchFaceSelector(
|
||||
}
|
||||
)
|
||||
}
|
||||
if (selected is ClockWidgetStyle.Custom) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.widget_pick_widget)) },
|
||||
leadingIcon = {
|
||||
Icon(Icons.Rounded.Widgets, null)
|
||||
},
|
||||
onClick = {
|
||||
showWidgetPicker = true
|
||||
showStyleSettings = false
|
||||
}
|
||||
)
|
||||
val widget = remember(selected.widgetId) {
|
||||
val id = selected.widgetId ?: return@remember null
|
||||
AppWidgetManager.getInstance(context)
|
||||
.getAppWidgetInfo(id)
|
||||
}
|
||||
val appWidgetHost = LocalAppWidgetHost.current
|
||||
if (widget?.configure != null) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.widget_config_appwidget_configure)) },
|
||||
leadingIcon = {
|
||||
Icon(Icons.Rounded.Settings, null)
|
||||
},
|
||||
onClick = {
|
||||
appWidgetHost.startAppWidgetConfigureActivityForResult(
|
||||
context as Activity,
|
||||
selected.widgetId ?: return@DropdownMenuItem,
|
||||
0,
|
||||
0,
|
||||
if (Build.VERSION.SDK_INT < 34) {
|
||||
null
|
||||
} else {
|
||||
ActivityOptions.makeBasic()
|
||||
.setPendingIntentBackgroundActivityStartMode(
|
||||
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
|
||||
)
|
||||
.setPendingIntentCreatorBackgroundActivityStartMode(
|
||||
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
|
||||
)
|
||||
.toBundle()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val darkColors = colors == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current || colors == ClockWidgetColors.Dark
|
||||
|
||||
CompositionLocalProvider(
|
||||
LocalContentColor provides if (colors == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current || colors == ClockWidgetColors.Dark) {
|
||||
LocalContentColor provides if (darkColors) {
|
||||
Color(0, 0, 0, 180)
|
||||
} else {
|
||||
Color.White
|
||||
@ -148,9 +209,9 @@ fun WatchFaceSelector(
|
||||
) {
|
||||
val currentPageStyle = styles[pageIndex]
|
||||
if (currentPageStyle.javaClass == selected?.javaClass) {
|
||||
Clock(selected, compact)
|
||||
Clock(selected, compact, darkColors)
|
||||
} else {
|
||||
Clock(currentPageStyle, compact)
|
||||
Clock(currentPageStyle, compact, darkColors)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -240,6 +301,23 @@ fun WatchFaceSelector(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (showWidgetPicker && selected is ClockWidgetStyle.Custom) {
|
||||
val previousWidgetId = selected.widgetId
|
||||
val appWidgetHost = LocalAppWidgetHost.current
|
||||
WidgetPickerSheet(
|
||||
includeBuiltinWidgets = false,
|
||||
onWidgetSelected = {
|
||||
if (previousWidgetId != null) {
|
||||
appWidgetHost.deleteAppWidgetId(previousWidgetId)
|
||||
}
|
||||
onSelect(selected.copy(widgetId = (it as AppWidget).config.widgetId))
|
||||
},
|
||||
onDismiss = {
|
||||
showWidgetPicker = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun getClockStyleName(context: Context, style: ClockWidgetStyle): String {
|
||||
@ -251,18 +329,7 @@ fun getClockStyleName(context: Context, style: ClockWidgetStyle): String {
|
||||
is ClockWidgetStyle.Analog -> context.getString(R.string.clock_style_analog)
|
||||
is ClockWidgetStyle.Segment -> context.getString(R.string.clock_style_segment)
|
||||
is ClockWidgetStyle.Empty -> context.getString(R.string.clock_style_empty)
|
||||
is ClockWidgetStyle.Custom -> context.getString(R.string.clock_style_custom)
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
// Compat for old enum names, TODO refactor this screen
|
||||
object ClockStyle {
|
||||
val DigitalClock1 = ClockWidgetStyle.Digital1()
|
||||
val DigitalClock1_Outlined = ClockWidgetStyle.Digital1(outlined = true)
|
||||
val DigitalClock2 = ClockWidgetStyle.Digital2
|
||||
val OrbitClock = ClockWidgetStyle.Orbit
|
||||
val AnalogClock = ClockWidgetStyle.Analog
|
||||
val BinaryClock = ClockWidgetStyle.Binary
|
||||
val SegmentClock = ClockWidgetStyle.Segment
|
||||
val EmptyClock = ClockWidgetStyle.Empty
|
||||
}
|
||||
@ -22,6 +22,7 @@ fun AnalogClock(
|
||||
compact: Boolean,
|
||||
showSeconds: Boolean,
|
||||
useThemeColor: Boolean,
|
||||
darkColors: Boolean,
|
||||
) {
|
||||
val verticalLayout = !compact
|
||||
val date = Calendar.getInstance()
|
||||
@ -34,7 +35,7 @@ fun AnalogClock(
|
||||
val strokeWidth = if (verticalLayout) 4.dp else 2.dp
|
||||
|
||||
val color = if (useThemeColor) {
|
||||
if (LocalContentColor.current == Color.White) {
|
||||
if (!darkColors) {
|
||||
if (LocalDarkTheme.current) MaterialTheme.colorScheme.onPrimaryContainer
|
||||
else MaterialTheme.colorScheme.primaryContainer
|
||||
} else {
|
||||
|
||||
@ -23,6 +23,7 @@ fun BinaryClock(
|
||||
compact: Boolean,
|
||||
showSeconds: Boolean,
|
||||
useThemeColor: Boolean,
|
||||
darkColors: Boolean,
|
||||
) {
|
||||
val verticalLayout = !compact
|
||||
val date = Calendar.getInstance()
|
||||
@ -33,7 +34,7 @@ fun BinaryClock(
|
||||
if (hour == 0) hour = 12
|
||||
|
||||
val color = if (useThemeColor) {
|
||||
if (LocalContentColor.current == Color.White) {
|
||||
if (!darkColors) {
|
||||
if (LocalDarkTheme.current) MaterialTheme.colorScheme.onPrimaryContainer
|
||||
else MaterialTheme.colorScheme.primaryContainer
|
||||
} else {
|
||||
|
||||
@ -0,0 +1,49 @@
|
||||
package de.mm20.launcher2.ui.launcher.widgets.clock.clocks
|
||||
|
||||
import android.appwidget.AppWidgetManager
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.material3.ElevatedButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||
import de.mm20.launcher2.ui.launcher.sheets.WidgetPickerSheet
|
||||
import de.mm20.launcher2.ui.launcher.widgets.external.ExternalWidget
|
||||
|
||||
@Composable
|
||||
fun CustomClock(
|
||||
style: ClockWidgetStyle.Custom,
|
||||
compact: Boolean,
|
||||
useThemeColor: Boolean,
|
||||
darkColors: Boolean,
|
||||
) {
|
||||
val widgetId = style.widgetId
|
||||
|
||||
if (widgetId == null) {
|
||||
Text("Hmmm…")
|
||||
} else {
|
||||
val context = LocalContext.current
|
||||
val widgetInfo = remember(widgetId) {
|
||||
AppWidgetManager.getInstance(context)
|
||||
.getAppWidgetInfo(widgetId)
|
||||
}
|
||||
if (widgetInfo != null) {
|
||||
ExternalWidget(
|
||||
widgetInfo = widgetInfo,
|
||||
widgetId = widgetId,
|
||||
height = if (compact) 64 else 200,
|
||||
useThemeColors = useThemeColor,
|
||||
onLightBackground = darkColors,
|
||||
borderless = compact,
|
||||
modifier = Modifier.widthIn(max = 250.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -35,6 +35,7 @@ fun DigitalClock1(
|
||||
compact: Boolean,
|
||||
showSeconds: Boolean,
|
||||
useThemeColor: Boolean,
|
||||
darkColors: Boolean,
|
||||
) {
|
||||
val verticalLayout = !compact
|
||||
val format = SimpleDateFormat(
|
||||
@ -56,7 +57,7 @@ fun DigitalClock1(
|
||||
)
|
||||
|
||||
val color = if (useThemeColor) {
|
||||
if (LocalContentColor.current == Color.White) {
|
||||
if (!darkColors) {
|
||||
if (LocalDarkTheme.current) MaterialTheme.colorScheme.onPrimaryContainer
|
||||
else MaterialTheme.colorScheme.primaryContainer
|
||||
} else {
|
||||
|
||||
@ -22,11 +22,12 @@ fun DigitalClock2(
|
||||
compact: Boolean,
|
||||
showSeconds: Boolean,
|
||||
useThemeColor: Boolean,
|
||||
darkColors: Boolean,
|
||||
) {
|
||||
|
||||
val verticalLayout = !compact
|
||||
val color = if (useThemeColor) {
|
||||
if (LocalContentColor.current == Color.White) {
|
||||
if (!darkColors) {
|
||||
if (LocalDarkTheme.current) MaterialTheme.colorScheme.onPrimaryContainer
|
||||
else MaterialTheme.colorScheme.primaryContainer
|
||||
} else {
|
||||
|
||||
@ -43,15 +43,13 @@ import kotlin.math.sin
|
||||
|
||||
private const val PHI_F = 1.618033988749895.toFloat()
|
||||
|
||||
private val currentTime
|
||||
get() = Instant.ofEpochMilli(System.currentTimeMillis()).atZone(ZoneId.systemDefault())
|
||||
|
||||
@Composable
|
||||
fun OrbitClock(
|
||||
time: Long,
|
||||
compact: Boolean,
|
||||
showSeconds: Boolean,
|
||||
useThemeColor: Boolean
|
||||
useThemeColor: Boolean,
|
||||
darkColors: Boolean,
|
||||
) {
|
||||
val verticalLayout = !compact
|
||||
|
||||
@ -107,8 +105,8 @@ fun OrbitClock(
|
||||
label = "hoursAnimation"
|
||||
)
|
||||
|
||||
val fgTone = if (LocalContentColor.current == Color.White) 10 else 90
|
||||
val bgTone = if (LocalContentColor.current == Color.White) 90 else 30
|
||||
val fgTone = if (!darkColors) 10 else 90
|
||||
val bgTone = if (!darkColors) 90 else 30
|
||||
|
||||
val background = if (useThemeColor) {
|
||||
Color(TonalPalette.fromInt(MaterialTheme.colorScheme.primaryContainer.toArgb()).tone(bgTone))
|
||||
|
||||
@ -50,7 +50,8 @@ fun SegmentClock(
|
||||
time: Long,
|
||||
compact: Boolean,
|
||||
showSeconds: Boolean,
|
||||
useThemeColor: Boolean
|
||||
useThemeColor: Boolean,
|
||||
darkColors: Boolean,
|
||||
) {
|
||||
val parsed = Instant.ofEpochMilli(time).atZone(ZoneId.systemDefault())
|
||||
val hour = parsed.hour
|
||||
@ -66,7 +67,7 @@ fun SegmentClock(
|
||||
}
|
||||
|
||||
val enabled = if (useThemeColor) {
|
||||
if (LocalContentColor.current == Color.White) {
|
||||
if (!darkColors) {
|
||||
if (LocalDarkTheme.current) MaterialTheme.colorScheme.onPrimaryContainer
|
||||
else MaterialTheme.colorScheme.primaryContainer
|
||||
} else {
|
||||
|
||||
@ -1,48 +1,53 @@
|
||||
package de.mm20.launcher2.ui.launcher.widgets.external
|
||||
|
||||
import android.appwidget.AppWidgetHost
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.appwidget.AppWidgetProviderInfo
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.os.Build
|
||||
import android.util.SparseIntArray
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ListView
|
||||
import android.widget.ScrollView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.core.view.doOnNextLayout
|
||||
import androidx.core.view.iterator
|
||||
import androidx.core.view.setPadding
|
||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||
import de.mm20.launcher2.ui.base.LocalAppWidgetHost
|
||||
import de.mm20.launcher2.ui.ktx.toPixels
|
||||
import palettes.TonalPalette
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@Composable
|
||||
fun ExternalWidget(
|
||||
appWidgetHost: AppWidgetHost,
|
||||
widgetInfo: AppWidgetProviderInfo,
|
||||
widgetId: Int,
|
||||
height: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
borderless: Boolean = false,
|
||||
useThemeColors: Boolean = false,
|
||||
onLightBackground: Boolean = false,
|
||||
) {
|
||||
val padding = if (borderless) 0 else 8.dp.toPixels().roundToInt()
|
||||
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
val appWidgetHost = LocalAppWidgetHost.current
|
||||
|
||||
BoxWithConstraints {
|
||||
val maxWidth = maxWidth
|
||||
key(widgetId) {
|
||||
AndroidView(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(height.dp),
|
||||
factory = {
|
||||
val view = appWidgetHost.createView(it.applicationContext, widgetId, widgetInfo)
|
||||
@ -50,6 +55,19 @@ fun ExternalWidget(
|
||||
return@AndroidView view
|
||||
},
|
||||
update = {
|
||||
if (isAtLeastApiLevel(31)) {
|
||||
if (useThemeColors) {
|
||||
val colorMapping = getColorMapping(colorScheme)
|
||||
it.setColorResources(colorMapping)
|
||||
} else {
|
||||
it.resetColorResources()
|
||||
}
|
||||
}
|
||||
|
||||
if (isAtLeastApiLevel(29)) {
|
||||
it.setOnLightBackground(onLightBackground)
|
||||
}
|
||||
|
||||
it.updateAppWidgetSize(
|
||||
null,
|
||||
maxWidth.value.roundToInt(),
|
||||
@ -72,3 +90,76 @@ private fun enableNestedScroll(view: View) {
|
||||
}
|
||||
if (view is ListView || view is ScrollView) view.isNestedScrollingEnabled = true
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.S)
|
||||
private fun getColorMapping(colorScheme: ColorScheme): SparseIntArray {
|
||||
val p = TonalPalette.fromInt(colorScheme.primary.toArgb())
|
||||
val s = TonalPalette.fromInt(colorScheme.secondary.toArgb())
|
||||
val t = TonalPalette.fromInt(colorScheme.tertiary.toArgb())
|
||||
val n = TonalPalette.fromInt(colorScheme.outline.toArgb())
|
||||
val nv = TonalPalette.fromInt(colorScheme.outlineVariant.toArgb())
|
||||
|
||||
val colorResources = SparseIntArray()
|
||||
colorResources.append(android.R.color.system_accent1_0, p.tone(100))
|
||||
colorResources.append(android.R.color.system_accent1_10, p.tone(99))
|
||||
colorResources.append(android.R.color.system_accent1_100, p.tone(90))
|
||||
colorResources.append(android.R.color.system_accent1_200, p.tone(80))
|
||||
colorResources.append(android.R.color.system_accent1_300, p.tone(70))
|
||||
colorResources.append(android.R.color.system_accent1_400, p.tone(60))
|
||||
colorResources.append(android.R.color.system_accent1_500, p.tone(50))
|
||||
colorResources.append(android.R.color.system_accent1_600, p.tone(40))
|
||||
colorResources.append(android.R.color.system_accent1_700, p.tone(30))
|
||||
colorResources.append(android.R.color.system_accent1_800, p.tone(20))
|
||||
colorResources.append(android.R.color.system_accent1_900, p.tone(10))
|
||||
colorResources.append(android.R.color.system_accent1_1000, s.tone(0))
|
||||
colorResources.append(android.R.color.system_accent2_0, s.tone(100))
|
||||
colorResources.append(android.R.color.system_accent2_10, s.tone(99))
|
||||
colorResources.append(android.R.color.system_accent2_100, s.tone(90))
|
||||
colorResources.append(android.R.color.system_accent2_200, s.tone(80))
|
||||
colorResources.append(android.R.color.system_accent2_300, s.tone(70))
|
||||
colorResources.append(android.R.color.system_accent2_400, s.tone(60))
|
||||
colorResources.append(android.R.color.system_accent2_500, s.tone(50))
|
||||
colorResources.append(android.R.color.system_accent2_600, s.tone(40))
|
||||
colorResources.append(android.R.color.system_accent2_700, s.tone(30))
|
||||
colorResources.append(android.R.color.system_accent2_800, s.tone(20))
|
||||
colorResources.append(android.R.color.system_accent2_900, s.tone(10))
|
||||
colorResources.append(android.R.color.system_accent2_1000, t.tone(0))
|
||||
colorResources.append(android.R.color.system_accent3_0, t.tone(100))
|
||||
colorResources.append(android.R.color.system_accent3_10, t.tone(99))
|
||||
colorResources.append(android.R.color.system_accent3_100, t.tone(90))
|
||||
colorResources.append(android.R.color.system_accent3_200, t.tone(80))
|
||||
colorResources.append(android.R.color.system_accent3_300, t.tone(70))
|
||||
colorResources.append(android.R.color.system_accent3_400, t.tone(60))
|
||||
colorResources.append(android.R.color.system_accent3_500, t.tone(50))
|
||||
colorResources.append(android.R.color.system_accent3_600, t.tone(40))
|
||||
colorResources.append(android.R.color.system_accent3_700, t.tone(30))
|
||||
colorResources.append(android.R.color.system_accent3_800, t.tone(20))
|
||||
colorResources.append(android.R.color.system_accent3_900, t.tone(10))
|
||||
colorResources.append(android.R.color.system_accent3_1000, t.tone(0))
|
||||
colorResources.append(android.R.color.system_neutral1_0, n.tone(100))
|
||||
colorResources.append(android.R.color.system_neutral1_10, n.tone(99))
|
||||
colorResources.append(android.R.color.system_neutral1_100, n.tone(90))
|
||||
colorResources.append(android.R.color.system_neutral1_200, n.tone(80))
|
||||
colorResources.append(android.R.color.system_neutral1_300, n.tone(70))
|
||||
colorResources.append(android.R.color.system_neutral1_400, n.tone(60))
|
||||
colorResources.append(android.R.color.system_neutral1_500, n.tone(50))
|
||||
colorResources.append(android.R.color.system_neutral1_600, n.tone(40))
|
||||
colorResources.append(android.R.color.system_neutral1_700, n.tone(30))
|
||||
colorResources.append(android.R.color.system_neutral1_800, n.tone(20))
|
||||
colorResources.append(android.R.color.system_neutral1_900, n.tone(10))
|
||||
colorResources.append(android.R.color.system_neutral1_1000, nv.tone(0))
|
||||
colorResources.append(android.R.color.system_neutral2_0, nv.tone(100))
|
||||
colorResources.append(android.R.color.system_neutral2_10, nv.tone(99))
|
||||
colorResources.append(android.R.color.system_neutral2_100, nv.tone(90))
|
||||
colorResources.append(android.R.color.system_neutral2_200, nv.tone(80))
|
||||
colorResources.append(android.R.color.system_neutral2_300, nv.tone(70))
|
||||
colorResources.append(android.R.color.system_neutral2_400, nv.tone(60))
|
||||
colorResources.append(android.R.color.system_neutral2_500, nv.tone(50))
|
||||
colorResources.append(android.R.color.system_neutral2_600, nv.tone(40))
|
||||
colorResources.append(android.R.color.system_neutral2_700, nv.tone(30))
|
||||
colorResources.append(android.R.color.system_neutral2_800, nv.tone(20))
|
||||
colorResources.append(android.R.color.system_neutral2_900, nv.tone(10))
|
||||
colorResources.append(android.R.color.system_neutral2_1000, nv.tone(0))
|
||||
|
||||
return colorResources
|
||||
}
|
||||
@ -11,8 +11,6 @@ import de.mm20.launcher2.ui.theme.WallpaperColors
|
||||
|
||||
val LocalWindowSize = compositionLocalOf { Size(0f, 0f) }
|
||||
|
||||
val LocalAppWidgetHost = compositionLocalOf<AppWidgetHost?>(defaultFactory = { null })
|
||||
|
||||
val LocalNavController = compositionLocalOf<NavController?> { null }
|
||||
|
||||
val LocalCardStyle = compositionLocalOf { CardStyle() }
|
||||
|
||||
@ -24,8 +24,7 @@ import androidx.navigation.navArgument
|
||||
import de.mm20.launcher2.licenses.AppLicense
|
||||
import de.mm20.launcher2.licenses.OpenSourceLicenses
|
||||
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.ProvideCompositionLocals
|
||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||
import de.mm20.launcher2.ui.locals.LocalNavController
|
||||
import de.mm20.launcher2.ui.locals.LocalWallpaperColors
|
||||
@ -84,8 +83,7 @@ class SettingsActivity : BaseActivity() {
|
||||
LocalNavController provides navController,
|
||||
LocalWallpaperColors provides wallpaperColors,
|
||||
) {
|
||||
ProvideSettings {
|
||||
ProvideCurrentTime {
|
||||
ProvideCompositionLocals {
|
||||
LauncherTheme {
|
||||
val systemBarColor = MaterialTheme.colorScheme.surfaceDim
|
||||
val systemBarColorAlt = MaterialTheme.colorScheme.onSurface
|
||||
@ -93,7 +91,10 @@ class SettingsActivity : BaseActivity() {
|
||||
LaunchedEffect(isDarkTheme, systemBarColor, systemBarColorAlt) {
|
||||
enableEdgeToEdge(
|
||||
if (isDarkTheme) SystemBarStyle.dark(systemBarColor.toArgb())
|
||||
else SystemBarStyle.light(systemBarColor.toArgb(), systemBarColorAlt.toArgb())
|
||||
else SystemBarStyle.light(
|
||||
systemBarColor.toArgb(),
|
||||
systemBarColorAlt.toArgb()
|
||||
)
|
||||
)
|
||||
}
|
||||
OverlayHost {
|
||||
@ -185,7 +186,9 @@ class SettingsActivity : BaseActivity() {
|
||||
PluginsSettingsScreen()
|
||||
}
|
||||
composable("settings/plugins/{id}") {
|
||||
PluginSettingsScreen(it.arguments?.getString("id") ?: return@composable)
|
||||
PluginSettingsScreen(
|
||||
it.arguments?.getString("id") ?: return@composable
|
||||
)
|
||||
}
|
||||
composable("settings/about") {
|
||||
AboutSettingsScreen()
|
||||
@ -243,7 +246,6 @@ class SettingsActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val EXTRA_ROUTE = "de.mm20.launcher2.settings.ROUTE"
|
||||
|
||||
@ -7,6 +7,7 @@ import de.mm20.launcher2.preferences.ClockWidgetColors
|
||||
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||
import de.mm20.launcher2.preferences.ui.ClockWidgetSettings
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import org.koin.core.component.KoinComponent
|
||||
@ -20,7 +21,7 @@ class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
settings.setCompact(compact)
|
||||
}
|
||||
|
||||
val availableClockStyles = settings.digital1.map {digital1 ->
|
||||
val availableClockStyles = combine(settings.digital1, settings.custom) {digital1, custom ->
|
||||
listOf(
|
||||
digital1,
|
||||
ClockWidgetStyle.Digital2,
|
||||
@ -28,6 +29,7 @@ class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
ClockWidgetStyle.Orbit,
|
||||
ClockWidgetStyle.Segment,
|
||||
ClockWidgetStyle.Binary,
|
||||
custom,
|
||||
ClockWidgetStyle.Empty,
|
||||
)
|
||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
|
||||
|
||||
@ -845,6 +845,7 @@
|
||||
<string name="widget_config_appwidget_resize_hint">Drag to resize</string>
|
||||
<string name="widget_config_weather_integration_settings">Weather integration settings</string>
|
||||
<string name="widget_config_calendar_no_calendars">No calendars found</string>
|
||||
<string name="widget_pick_widget">Pick widget</string>
|
||||
<string name="app_widget_loading_failed">App widget failed to load.</string>
|
||||
<string name="widget_config_music_integration_settings">Media control integration settings</string>
|
||||
<string name="note_widget_link_file">Link to file</string>
|
||||
@ -909,6 +910,7 @@
|
||||
<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_style_custom">Custom widget</string>
|
||||
<string name="clock_variant_standard">Standard</string>
|
||||
<string name="clock_variant_outlined">Outlined</string>
|
||||
</resources>
|
||||
@ -30,6 +30,7 @@ data class LauncherSettingsData internal constructor(
|
||||
@SerialName("clockWidgetStyle2")
|
||||
internal val clockWidgetStyle: ClockWidgetStyleEnum = ClockWidgetStyleEnum.Digital1,
|
||||
val clockWidgetDigital1: ClockWidgetStyle.Digital1 = ClockWidgetStyle.Digital1(),
|
||||
val clockWidgetCustom: ClockWidgetStyle.Custom = ClockWidgetStyle.Custom(),
|
||||
val clockWidgetColors: ClockWidgetColors = ClockWidgetColors.Auto,
|
||||
val clockWidgetShowSeconds: Boolean = false,
|
||||
val clockWidgetUseThemeColor: Boolean = false,
|
||||
@ -192,6 +193,7 @@ internal enum class ClockWidgetStyleEnum {
|
||||
Binary,
|
||||
Segment,
|
||||
Empty,
|
||||
Custom,
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@ -234,6 +236,10 @@ sealed interface ClockWidgetStyle {
|
||||
@Serializable
|
||||
@SerialName("empty")
|
||||
data object Empty : ClockWidgetStyle
|
||||
|
||||
@Serializable
|
||||
@SerialName("custom")
|
||||
data class Custom(val widgetId: Int? = null) : ClockWidgetStyle
|
||||
}
|
||||
|
||||
@Serializable
|
||||
|
||||
@ -99,17 +99,22 @@ class ClockWidgetSettings internal constructor(
|
||||
ClockWidgetStyleEnum.Binary -> ClockWidgetStyle.Binary
|
||||
ClockWidgetStyleEnum.Segment -> ClockWidgetStyle.Segment
|
||||
ClockWidgetStyleEnum.Empty -> ClockWidgetStyle.Empty
|
||||
ClockWidgetStyleEnum.Custom -> it.clockWidgetCustom
|
||||
}
|
||||
}
|
||||
|
||||
val digital1: Flow<ClockWidgetStyle.Digital1>
|
||||
get() = launcherDataStore.data.map { it.clockWidgetDigital1 }
|
||||
|
||||
val custom: Flow<ClockWidgetStyle.Custom>
|
||||
get() = launcherDataStore.data.map { it.clockWidgetCustom }
|
||||
|
||||
fun setClockStyle(clockStyle: ClockWidgetStyle) {
|
||||
launcherDataStore.update {
|
||||
it.copy(
|
||||
clockWidgetStyle = clockStyle.enumValue,
|
||||
clockWidgetDigital1 = if (clockStyle is ClockWidgetStyle.Digital1) clockStyle else it.clockWidgetDigital1,
|
||||
clockWidgetCustom = if (clockStyle is ClockWidgetStyle.Custom) clockStyle else it.clockWidgetCustom,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -151,4 +156,5 @@ internal val ClockWidgetStyle.enumValue
|
||||
is ClockWidgetStyle.Binary -> ClockWidgetStyleEnum.Binary
|
||||
is ClockWidgetStyle.Segment -> ClockWidgetStyleEnum.Segment
|
||||
is ClockWidgetStyle.Empty -> ClockWidgetStyleEnum.Empty
|
||||
is ClockWidgetStyle.Custom -> ClockWidgetStyleEnum.Custom
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user