From 7056c5963a475d0fc06e8f693a313583407b9121 Mon Sep 17 00:00:00 2001 From: MM20 <15646950+MM2-0@users.noreply.github.com> Date: Sat, 13 Apr 2024 18:26:59 +0200 Subject: [PATCH] Add option to use theme colors in app widgets and use light background variant when appropriate --- .../launcher/sheets/ConfigureWidgetSheet.kt | 25 +- .../ui/launcher/widgets/WidgetItem.kt | 62 +---- .../ui/launcher/widgets/clock/ClockWidget.kt | 2 +- .../widgets/clock/clocks/CustomClock.kt | 10 +- .../ui/launcher/widgets/external/AppWidget.kt | 228 +++++++----------- .../widgets/external/AppWidgetHost.kt | 167 +++++++++++++ core/i18n/src/main/res/values-ca/strings.xml | 2 +- core/i18n/src/main/res/values-cs/strings.xml | 2 +- core/i18n/src/main/res/values-da/strings.xml | 2 +- core/i18n/src/main/res/values-de/strings.xml | 2 +- core/i18n/src/main/res/values-es/strings.xml | 2 +- core/i18n/src/main/res/values-hu/strings.xml | 2 +- core/i18n/src/main/res/values-it/strings.xml | 2 +- core/i18n/src/main/res/values/strings.xml | 2 +- .../de/mm20/launcher2/widgets/AppWidget.kt | 1 + 15 files changed, 288 insertions(+), 223 deletions(-) create mode 100644 app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/external/AppWidgetHost.kt diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/ConfigureWidgetSheet.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/ConfigureWidgetSheet.kt index 49702f5b..5dd31be9 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/ConfigureWidgetSheet.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/ConfigureWidgetSheet.kt @@ -2,7 +2,6 @@ package de.mm20.launcher2.ui.launcher.sheets import android.app.Activity import android.app.ActivityOptions -import android.appwidget.AppWidgetHost import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetProviderInfo import android.content.Intent @@ -41,6 +40,7 @@ import androidx.compose.material.icons.rounded.OpenInNew import androidx.compose.material.icons.rounded.UnfoldMore import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Divider +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton @@ -87,7 +87,9 @@ import de.mm20.launcher2.ui.component.MissingPermissionBanner import de.mm20.launcher2.ui.component.preferences.CheckboxPreference import de.mm20.launcher2.ui.component.preferences.Preference import de.mm20.launcher2.ui.component.preferences.SwitchPreference -import de.mm20.launcher2.ui.launcher.widgets.external.ExternalWidget +import de.mm20.launcher2.ui.launcher.widgets.external.AppWidgetHost +import de.mm20.launcher2.ui.locals.LocalDarkTheme +import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper import de.mm20.launcher2.ui.settings.SettingsActivity import de.mm20.launcher2.widgets.AppWidget import de.mm20.launcher2.widgets.CalendarWidget @@ -344,12 +346,14 @@ fun ColumnScope.ConfigureAppWidget( .clip(MaterialTheme.shapes.medium) .background(MaterialTheme.colorScheme.surfaceVariant) ) { - ExternalWidget( + AppWidgetHost( widgetInfo = widgetInfo, widgetId = widget.config.widgetId, modifier = Modifier.fillMaxWidth(), height = widget.config.height + dragDelta, borderless = widget.config.borderless, + useThemeColors = widget.config.themeColors, + onLightBackground = (!LocalDarkTheme.current && widget.config.background) || LocalPreferDarkContentOverWallpaper.current ) } val density = LocalDensity.current @@ -422,7 +426,7 @@ fun ColumnScope.ConfigureAppWidget( onValueChange = { val intValue = it.toIntOrNull() if (intValue == null) textFieldValue = "" - else if (intValue in 1..500) { + else if (intValue in 1..1000) { onWidgetUpdated( widget.copy( config = widget.config.copy( @@ -458,7 +462,7 @@ fun ColumnScope.ConfigureAppWidget( onWidgetUpdated(widget.copy(config = widget.config.copy(borderless = it))) } ) - Divider() + HorizontalDivider() SwitchPreference( title = stringResource(R.string.widget_config_appwidget_background), iconPadding = false, @@ -467,6 +471,17 @@ fun ColumnScope.ConfigureAppWidget( onWidgetUpdated(widget.copy(config = widget.config.copy(background = it))) } ) + if (isAtLeastApiLevel(31)) { + HorizontalDivider() + SwitchPreference( + title = stringResource(R.string.widget_use_theme_colors), + iconPadding = false, + value = widget.config.themeColors, + onValueChanged = { + onWidgetUpdated(widget.copy(config = widget.config.copy(themeColors = it))) + } + ) + } } } if (isAtLeastApiLevel(28) && widgetInfo.widgetFeatures and AppWidgetProviderInfo.WIDGET_FEATURE_RECONFIGURABLE != 0) { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetItem.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetItem.kt index 64563529..c3d09f63 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetItem.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetItem.kt @@ -1,6 +1,5 @@ package de.mm20.launcher2.ui.launcher.widgets -import android.appwidget.AppWidgetHost import android.appwidget.AppWidgetManager import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.animateDpAsState @@ -43,7 +42,7 @@ import de.mm20.launcher2.ui.component.LauncherCard import de.mm20.launcher2.ui.launcher.sheets.ConfigureWidgetSheet import de.mm20.launcher2.ui.launcher.sheets.WidgetPickerSheet import de.mm20.launcher2.ui.launcher.widgets.calendar.CalendarWidget -import de.mm20.launcher2.ui.launcher.widgets.external.ExternalWidget +import de.mm20.launcher2.ui.launcher.widgets.external.AppWidget import de.mm20.launcher2.ui.launcher.widgets.favorites.FavoritesWidget import de.mm20.launcher2.ui.launcher.widgets.music.MusicWidget import de.mm20.launcher2.ui.launcher.widgets.notes.NotesWidget @@ -174,60 +173,11 @@ fun WidgetItem( } is AppWidget -> { - val widgetInfo = remember(widget.config.widgetId) { - AppWidgetManager.getInstance(context) - .getAppWidgetInfo(widget.config.widgetId) - } - if (widgetInfo == null) { - var replaceWidget by rememberSaveable { - mutableStateOf(false) - } - Banner( - modifier = Modifier.padding(16.dp), - text = stringResource(R.string.app_widget_loading_failed), - icon = Icons.Rounded.Warning, - secondaryAction = { - OutlinedButton(onClick = onWidgetRemove) { - Text(stringResource(R.string.widget_action_remove)) - } - }, - primaryAction = { - Button(onClick = { replaceWidget = true }) { - Text(stringResource(R.string.widget_action_replace)) - } - } - ) - if (replaceWidget) { - WidgetPickerSheet( - onDismiss = { replaceWidget = false }, - onWidgetSelected = { - val updatedWidget = when (it) { - is AppWidget -> widget.copy( - config = widget.config.copy( - widgetId = it.config.widgetId - ) - ) - - is WeatherWidget -> it.copy(id = widget.id) - is MusicWidget -> it.copy(id = widget.id) - is CalendarWidget -> it.copy(id = widget.id) - is FavoritesWidget -> it.copy(id = widget.id) - is NotesWidget -> it.copy(id = widget.id) - } - onWidgetUpdate(updatedWidget) - replaceWidget = false - } - ) - } - } else { - ExternalWidget( - widgetId = widget.config.widgetId, - widgetInfo = widgetInfo, - modifier = Modifier.fillMaxWidth(), - height = widget.config.height, - borderless = widget.config.borderless, - ) - } + AppWidget( + widget, + onWidgetUpdate = onWidgetUpdate, + onWidgetRemove = onWidgetRemove, + ) } } } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt index a8629208..8849f5ed 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt @@ -464,7 +464,7 @@ fun ConfigureClockWidgetSheet( modifier = Modifier.fillMaxWidth() ) { SwitchPreference( - title = stringResource(R.string.preference_clock_widget_use_theme_color), + title = stringResource(R.string.widget_use_theme_colors), icon = Icons.Rounded.ColorLens, value = useAccentColor, onValueChanged = { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/clocks/CustomClock.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/clocks/CustomClock.kt index 3bd47108..5b22d662 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/clocks/CustomClock.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/clocks/CustomClock.kt @@ -2,20 +2,14 @@ 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 +import de.mm20.launcher2.ui.launcher.widgets.external.AppWidgetHost @Composable fun CustomClock( @@ -35,7 +29,7 @@ fun CustomClock( .getAppWidgetInfo(widgetId) } if (widgetInfo != null) { - ExternalWidget( + AppWidgetHost( widgetInfo = widgetInfo, widgetId = widgetId, height = if (compact) 64 else 200, diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/external/AppWidget.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/external/AppWidget.kt index c22d8af6..96c3e609 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/external/AppWidget.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/external/AppWidget.kt @@ -1,165 +1,103 @@ package de.mm20.launcher2.ui.launcher.widgets.external import android.appwidget.AppWidgetHost -import android.appwidget.AppWidgetProviderInfo -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.annotation.RequiresApi -import androidx.compose.foundation.layout.BoxWithConstraints +import android.appwidget.AppWidgetManager 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.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Warning +import androidx.compose.material3.Button +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.key +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.graphics.toArgb +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.compose.ui.viewinterop.AndroidView -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.R +import de.mm20.launcher2.ui.component.Banner import de.mm20.launcher2.ui.ktx.toPixels -import palettes.TonalPalette +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 de.mm20.launcher2.widgets.CalendarWidget +import de.mm20.launcher2.widgets.FavoritesWidget +import de.mm20.launcher2.widgets.MusicWidget +import de.mm20.launcher2.widgets.NotesWidget +import de.mm20.launcher2.widgets.WeatherWidget +import de.mm20.launcher2.widgets.Widget import kotlin.math.roundToInt @Composable -fun ExternalWidget( - widgetInfo: AppWidgetProviderInfo, - widgetId: Int, - height: Int, - modifier: Modifier = Modifier, - borderless: Boolean = false, - useThemeColors: Boolean = false, - onLightBackground: Boolean = false, +fun AppWidget( + widget: AppWidget, + onWidgetUpdate: (Widget) -> Unit, + onWidgetRemove: () -> Unit, ) { - val padding = if (borderless) 0 else 8.dp.toPixels().roundToInt() + val context = LocalContext.current - val colorScheme = MaterialTheme.colorScheme - val appWidgetHost = LocalAppWidgetHost.current + val lightBackground = (!LocalDarkTheme.current && widget.config.background) || LocalPreferDarkContentOverWallpaper.current - BoxWithConstraints { - val maxWidth = maxWidth - key(widgetId) { - AndroidView( - modifier = modifier - .height(height.dp), - factory = { - val view = appWidgetHost.createView(it.applicationContext, widgetId, widgetInfo) - enableNestedScroll(view) - return@AndroidView view - }, - update = { - if (isAtLeastApiLevel(31)) { - if (useThemeColors) { - val colorMapping = getColorMapping(colorScheme) - it.setColorResources(colorMapping) - } else { - it.resetColorResources() - } + val widgetInfo = remember(widget.config.widgetId) { + AppWidgetManager.getInstance(context) + .getAppWidgetInfo(widget.config.widgetId) + } + if (widgetInfo == null) { + var replaceWidget by rememberSaveable { + mutableStateOf(false) + } + Banner( + modifier = Modifier.padding(16.dp), + text = stringResource(R.string.app_widget_loading_failed), + icon = Icons.Rounded.Warning, + secondaryAction = { + OutlinedButton(onClick = onWidgetRemove) { + Text(stringResource(R.string.widget_action_remove)) + } + }, + primaryAction = { + Button(onClick = { replaceWidget = true }) { + Text(stringResource(R.string.widget_action_replace)) + } + } + ) + if (replaceWidget) { + WidgetPickerSheet( + onDismiss = { replaceWidget = false }, + onWidgetSelected = { + val updatedWidget = when (it) { + is AppWidget -> widget.copy( + config = widget.config.copy( + widgetId = it.config.widgetId + ) + ) + + is WeatherWidget -> it.copy(id = widget.id) + is MusicWidget -> it.copy(id = widget.id) + is CalendarWidget -> it.copy(id = widget.id) + is FavoritesWidget -> it.copy(id = widget.id) + is NotesWidget -> it.copy(id = widget.id) } - - if (isAtLeastApiLevel(29)) { - it.setOnLightBackground(onLightBackground) - } - - it.updateAppWidgetSize( - null, - maxWidth.value.roundToInt(), - height, - maxWidth.value.roundToInt(), - height, - ) - it.setPadding(padding) + onWidgetUpdate(updatedWidget) + replaceWidget = false } ) } + } else { + AppWidgetHost( + widgetId = widget.config.widgetId, + widgetInfo = widgetInfo, + modifier = Modifier.fillMaxWidth(), + height = widget.config.height, + borderless = widget.config.borderless, + useThemeColors = widget.config.themeColors, + onLightBackground = lightBackground, + ) } -} - -private fun enableNestedScroll(view: View) { - if (view is ViewGroup) { - for (child in view.iterator()) { - enableNestedScroll(child) - } - } - 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 } \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/external/AppWidgetHost.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/external/AppWidgetHost.kt new file mode 100644 index 00000000..e84a9e79 --- /dev/null +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/external/AppWidgetHost.kt @@ -0,0 +1,167 @@ +package de.mm20.launcher2.ui.launcher.widgets.external + +import android.appwidget.AppWidgetHost +import android.appwidget.AppWidgetProviderInfo +import android.os.Build +import android.os.Bundle +import android.util.Log +import android.util.SparseIntArray +import android.view.View +import android.view.ViewGroup +import android.widget.ListView +import android.widget.ScrollView +import androidx.annotation.RequiresApi +import androidx.compose.foundation.layout.BoxWithConstraints +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.ui.Modifier +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.unit.dp +import androidx.compose.ui.viewinterop.AndroidView +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 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 + .height(height.dp), + factory = { + val view = appWidgetHost.createView(it.applicationContext, widgetId, widgetInfo) + enableNestedScroll(view) + return@AndroidView view + }, + update = { + if (isAtLeastApiLevel(29)) { + it.setOnLightBackground(onLightBackground) + } + if (isAtLeastApiLevel(31)) { + if (useThemeColors) { + val colorMapping = getColorMapping(colorScheme) + it.setColorResources(colorMapping) + } else { + it.resetColorResources() + } + } + + it.updateAppWidgetSize( + null, + maxWidth.value.roundToInt(), + height, + maxWidth.value.roundToInt(), + height, + ) + it.setPadding(padding) + // Workaround to force update of the widget view + it.updateAppWidgetOptions(Bundle()) + } + ) + } + } +} + +private fun enableNestedScroll(view: View) { + if (view is ViewGroup) { + for (child in view.iterator()) { + enableNestedScroll(child) + } + } + 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 +} \ No newline at end of file diff --git a/core/i18n/src/main/res/values-ca/strings.xml b/core/i18n/src/main/res/values-ca/strings.xml index e661ecbc..79291357 100644 --- a/core/i18n/src/main/res/values-ca/strings.xml +++ b/core/i18n/src/main/res/values-ca/strings.xml @@ -710,7 +710,7 @@ Mostra les aplicacions del perfil de treball en una pestanya independent Aplicacions del perfil de treball separades Mostra els segons - Utilitzeu el color del tema + Utilitzeu el color del tema Negreta Simple Orbit diff --git a/core/i18n/src/main/res/values-cs/strings.xml b/core/i18n/src/main/res/values-cs/strings.xml index 528bccbf..b037be8c 100644 --- a/core/i18n/src/main/res/values-cs/strings.xml +++ b/core/i18n/src/main/res/values-cs/strings.xml @@ -715,7 +715,7 @@ Oddělit aplikace pracovního profilu Zobrazit aplikace pracovního profilu v oddělené kartě Zobrazit sekundy - Použít barvu motivu + Použít barvu motivu Tučné Jednoduché Kruh diff --git a/core/i18n/src/main/res/values-da/strings.xml b/core/i18n/src/main/res/values-da/strings.xml index f3fe69ea..ffcbc240 100644 --- a/core/i18n/src/main/res/values-da/strings.xml +++ b/core/i18n/src/main/res/values-da/strings.xml @@ -687,7 +687,7 @@ Åbn hjemmeside Giv tilladelse til placering for at søge i nærheden. Vis sekunder - Brug temafarve + Brug temafarve Steder Søgeradius Søg i det lokale område efter butikker og andre steder diff --git a/core/i18n/src/main/res/values-de/strings.xml b/core/i18n/src/main/res/values-de/strings.xml index a6bc7b7f..d8979d59 100644 --- a/core/i18n/src/main/res/values-de/strings.xml +++ b/core/i18n/src/main/res/values-de/strings.xml @@ -710,7 +710,7 @@ Apps im Arbeitsprofil in einem separaten Tab anzeigen Dieses Element existiert nicht mehr. Sekunden anzeigen - Design-Farbe verwenden + Design-Farbe verwenden Fett Einfach Orbit diff --git a/core/i18n/src/main/res/values-es/strings.xml b/core/i18n/src/main/res/values-es/strings.xml index dd2de2cb..fbf01ac4 100644 --- a/core/i18n/src/main/res/values-es/strings.xml +++ b/core/i18n/src/main/res/values-es/strings.xml @@ -693,7 +693,7 @@ Separar apps del perfil de trabajo Mostrar apps del perfil de trabajo en una pestaña separada Mostrar segundos - Usar color del tema + Usar color del tema Radio de búsqueda Mostrar tu ubicación en el mapa Negrita diff --git a/core/i18n/src/main/res/values-hu/strings.xml b/core/i18n/src/main/res/values-hu/strings.xml index 988e1715..32bc0ec4 100644 --- a/core/i18n/src/main/res/values-hu/strings.xml +++ b/core/i18n/src/main/res/values-hu/strings.xml @@ -709,7 +709,7 @@ Ez az elem már nem létezik. 7-szegmenses Általános - Színséma használata + Színséma használata Lap elkülönítés az alkalmazásokhoz Külön lapon mutatja az alkalmazásokat Másodperc megjelenítése diff --git a/core/i18n/src/main/res/values-it/strings.xml b/core/i18n/src/main/res/values-it/strings.xml index a2cd3ec8..45466057 100644 --- a/core/i18n/src/main/res/values-it/strings.xml +++ b/core/i18n/src/main/res/values-it/strings.xml @@ -690,7 +690,7 @@ Apertura %1$s Nascondi luoghi senza categoria Mostra secondi - Usa colore del tema + Usa colore del tema Luoghi Raggio di ricerca Cerca nella zona negozi e altri luoghi diff --git a/core/i18n/src/main/res/values/strings.xml b/core/i18n/src/main/res/values/strings.xml index 61036e9d..5ae5a124 100644 --- a/core/i18n/src/main/res/values/strings.xml +++ b/core/i18n/src/main/res/values/strings.xml @@ -601,7 +601,7 @@ Default Compact Show seconds - Use theme color + Use theme color Fill screen height Insert extra space above the clock to fill the entire screen height Color diff --git a/data/widgets/src/main/java/de/mm20/launcher2/widgets/AppWidget.kt b/data/widgets/src/main/java/de/mm20/launcher2/widgets/AppWidget.kt index 98cf5259..3dd22bc0 100644 --- a/data/widgets/src/main/java/de/mm20/launcher2/widgets/AppWidget.kt +++ b/data/widgets/src/main/java/de/mm20/launcher2/widgets/AppWidget.kt @@ -17,6 +17,7 @@ data class AppWidgetConfig( val height: Int, val borderless: Boolean = false, val background: Boolean = true, + val themeColors: Boolean = true, ) data class AppWidget(