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 58cf6c70..ff2c4c5a 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 @@ -384,7 +384,7 @@ fun ColumnScope.ConfigureAppWidget( val minHeight = if (widgetInfo.minResizeHeight in 1..widgetInfo.minHeight) { widgetInfo.minResizeHeight.toDp() } else { - widgetInfo.minHeight.toDp() + widgetInfo.minHeight.toDp() } DragResizeHandle( 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 8849f5ed..c028f37e 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 @@ -163,7 +163,7 @@ fun ClockWidget( Box( modifier = Modifier .then(if (fillScreenHeight) Modifier.weight(1f) else Modifier) - .fillMaxWidth(), + .fillMaxWidth().padding(horizontal = 24.dp), contentAlignment = when (alignment) { ClockWidgetAlignment.Center -> Alignment.Center ClockWidgetAlignment.Top -> Alignment.TopCenter @@ -408,6 +408,7 @@ fun ConfigureClockWidgetSheet( styles = availableStyles, compact = compact!!, colors = color!!, + themeColors = useAccentColor, selected = style, onSelect = { viewModel.setClockStyle(it) diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/WatchFaceSelector.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/WatchFaceSelector.kt index a0b57be8..d0488355 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/WatchFaceSelector.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/WatchFaceSelector.kt @@ -5,34 +5,49 @@ import android.app.ActivityOptions import android.appwidget.AppWidgetManager import android.content.Context import android.os.Build -import android.util.Log +import androidx.compose.animation.AnimatedContent import androidx.compose.animation.animateContentSize import androidx.compose.animation.scaleIn import androidx.compose.animation.scaleOut +import androidx.compose.foundation.gestures.awaitEachGesture +import androidx.compose.foundation.gestures.awaitFirstDown import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.ArrowDropDown -import androidx.compose.material.icons.rounded.Check +import androidx.compose.material.icons.rounded.CheckCircle import androidx.compose.material.icons.rounded.ChevronLeft import androidx.compose.material.icons.rounded.ChevronRight +import androidx.compose.material.icons.rounded.CropFree +import androidx.compose.material.icons.rounded.Done +import androidx.compose.material.icons.rounded.PhotoSizeSelectSmall +import androidx.compose.material.icons.rounded.RadioButtonUnchecked +import androidx.compose.material.icons.rounded.RestartAlt import androidx.compose.material.icons.rounded.Settings +import androidx.compose.material.icons.rounded.SwapHoriz 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 +import androidx.compose.material3.FilledIconButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton @@ -48,16 +63,26 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.PointerEventPass +import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.coerceAtMost import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.isUnspecified import androidx.compose.ui.zIndex +import de.mm20.launcher2.ktx.isAtLeastApiLevel import de.mm20.launcher2.preferences.ClockWidgetColors import de.mm20.launcher2.preferences.ClockWidgetStyle +import de.mm20.launcher2.ui.BuildConfig import de.mm20.launcher2.ui.R import de.mm20.launcher2.ui.base.LocalAppWidgetHost +import de.mm20.launcher2.ui.component.DragResizeHandle +import de.mm20.launcher2.ui.ktx.toDp import de.mm20.launcher2.ui.launcher.sheets.WidgetPickerSheet +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.widgets.AppWidget @@ -68,235 +93,315 @@ fun WatchFaceSelector( styles: List, compact: Boolean, colors: ClockWidgetColors, + themeColors: Boolean, selected: ClockWidgetStyle?, onSelect: (ClockWidgetStyle) -> Unit, ) { val context = LocalContext.current var showWidgetPicker by rememberSaveable { mutableStateOf(false) } + var resizeCustomWidget by remember { mutableStateOf(false) } + + val lightBackground = + colors == ClockWidgetColors.Dark || colors == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current Surface( modifier = Modifier .fillMaxWidth() - .padding(vertical = 16.dp, horizontal = 32.dp), - color = if (colors == ClockWidgetColors.Dark || colors == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current) { + .padding(vertical = 16.dp, horizontal = 0.dp), + color = if (lightBackground) { if (LocalDarkTheme.current) MaterialTheme.colorScheme.inverseSurface else MaterialTheme.colorScheme.surfaceContainer } else { if (LocalDarkTheme.current) MaterialTheme.colorScheme.surfaceContainer else MaterialTheme.colorScheme.inverseSurface }, shape = MaterialTheme.shapes.medium, ) { - Column( - modifier = Modifier, - ) { - val pagerState = rememberPagerState( - initialPage = styles.indexOfFirst { it.javaClass == selected?.javaClass } - .coerceAtLeast(0), + AnimatedContent(resizeCustomWidget) { resize -> + if (resize && selected is ClockWidgetStyle.Custom) { + ResizeCustomWidget( + style = selected, + compact = compact, + themeColors = themeColors, + lightBackground = lightBackground, + onChange = { onSelect(it) }, + onExit = { resizeCustomWidget = false } + ) + return@AnimatedContent + } + Column( + modifier = Modifier, ) { - styles.size - } - - LaunchedEffect(pagerState.currentPage) { - val newStyle = styles[pagerState.currentPage] - if (newStyle.javaClass == selected?.javaClass) return@LaunchedEffect - onSelect(newStyle) - } - - val scope = rememberCoroutineScope() - - Box { - androidx.compose.animation.AnimatedVisibility( - selected is ClockWidgetStyle.Digital1 || selected is ClockWidgetStyle.Custom, - modifier = Modifier - .align(Alignment.TopEnd) - .zIndex(1f), - enter = scaleIn(), - exit = scaleOut(), + val pagerState = rememberPagerState( + initialPage = styles.indexOfFirst { it.javaClass == selected?.javaClass } + .coerceAtLeast(0), ) { - var showStyleSettings by remember { mutableStateOf(false) } - IconButton( - onClick = { showStyleSettings = true }, + styles.size + } + + LaunchedEffect(pagerState.currentPage) { + val newStyle = styles[pagerState.currentPage] + if (newStyle.javaClass == selected?.javaClass) return@LaunchedEffect + onSelect(newStyle) + } + + val scope = rememberCoroutineScope() + + Box { + androidx.compose.animation.AnimatedVisibility( + selected is ClockWidgetStyle.Digital1 || (selected is ClockWidgetStyle.Custom && selected.widgetId != null), modifier = Modifier - .padding(4.dp) + .align(Alignment.TopEnd) + .zIndex(1f), + enter = scaleIn(), + exit = scaleOut(), ) { - Icon(Icons.Rounded.Tune, null) - DropdownMenu( - expanded = showStyleSettings, - onDismissRequest = { showStyleSettings = false }) { - if (selected is ClockWidgetStyle.Digital1) { - DropdownMenuItem( - text = { Text(stringResource(R.string.clock_variant_outlined)) }, - leadingIcon = { - if (selected.outlined) { - Icon(Icons.Rounded.Check, null) - } - }, - onClick = { - onSelect(selected.copy(outlined = !selected.outlined)) - } - ) - } - 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) { + var showStyleSettings by remember { mutableStateOf(false) } + IconButton( + onClick = { showStyleSettings = true }, + modifier = Modifier + .padding(4.dp) + ) { + Icon(Icons.Rounded.Tune, null) + DropdownMenu( + expanded = showStyleSettings, + onDismissRequest = { showStyleSettings = false }) { + if (selected is ClockWidgetStyle.Digital1) { DropdownMenuItem( - text = { Text(stringResource(R.string.widget_config_appwidget_configure)) }, + text = { Text(stringResource(R.string.clock_variant_outlined)) }, leadingIcon = { - Icon(Icons.Rounded.Settings, null) + Icon( + if (selected.outlined) Icons.Rounded.CheckCircle + else Icons.Rounded.RadioButtonUnchecked, + 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() - } - ) + onSelect(selected.copy(outlined = !selected.outlined)) } ) } - } - } - } - } - - val darkColors = colors == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current || colors == ClockWidgetColors.Dark - - CompositionLocalProvider( - LocalContentColor provides if (darkColors) { - Color(0, 0, 0, 180) - } else { - Color.White - }, - ) { - - HorizontalPager( - modifier = Modifier.animateContentSize(), - state = pagerState, - verticalAlignment = Alignment.Top, - ) { pageIndex -> - Box( - modifier = Modifier - .fillMaxWidth() - .padding(top = 24.dp, bottom = 8.dp), - contentAlignment = Alignment.TopCenter, - ) { - val currentPageStyle = styles[pageIndex] - if (currentPageStyle.javaClass == selected?.javaClass) { - Clock(selected, compact, darkColors) - } else { - Clock(currentPageStyle, compact, darkColors) - } - } - } - - } - } - - Row( - verticalAlignment = Alignment.CenterVertically - ) { - IconButton( - enabled = pagerState.currentPage > 0, - onClick = { - scope.launch { - pagerState.animateScrollToPage( - pagerState.currentPage - 1, - ) - } - }) { - Icon(Icons.Rounded.ChevronLeft, null) - } - var showStyleDropdown by remember { mutableStateOf(false) } - TextButton( - modifier = Modifier - .weight(1f) - .padding(horizontal = 16.dp), - onClick = { showStyleDropdown = true }, - contentPadding = PaddingValues( - top = 8.dp, - bottom = 8.dp, - start = 16.dp, - end = 12.dp, - ), - colors = ButtonDefaults.textButtonColors( - contentColor = LocalContentColor.current, - ), - ) { - Text( - text = getClockStyleName( - context, - styles[pagerState.currentPage] - ), - textAlign = TextAlign.Center, - ) - Icon( - Icons.Rounded.ArrowDropDown, - null, - modifier = Modifier - .padding(ButtonDefaults.IconSpacing) - .size(ButtonDefaults.IconSize) - ) - DropdownMenu( - expanded = showStyleDropdown, - onDismissRequest = { showStyleDropdown = false } - ) { - for (style in styles.withIndex()) { - DropdownMenuItem( - onClick = { - scope.launch { - pagerState.animateScrollToPage( - style.index, + if (selected is ClockWidgetStyle.Custom) { + DropdownMenuItem( + text = { Text(stringResource(R.string.widget_pick_widget)) }, + leadingIcon = { + Icon(Icons.Rounded.SwapHoriz, null) + }, + onClick = { + showWidgetPicker = true + showStyleSettings = false + } + ) + DropdownMenuItem( + leadingIcon = { + Icon(Icons.Rounded.PhotoSizeSelectSmall, null) + }, + text = { Text(stringResource(R.string.widget_config_appwidget_resize)) }, + onClick = { resizeCustomWidget = true } + ) + 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() + } + ) + } + ) + } + if (BuildConfig.DEBUG) { + DropdownMenuItem( + leadingIcon = { + Icon(Icons.Rounded.RestartAlt, null) + }, + text = { Text("Reset") }, + onClick = { + val widgetId = selected.widgetId + if (widgetId != null) { + appWidgetHost.deleteAppWidgetId(widgetId) + } + onSelect( + ClockWidgetStyle.Custom() + ) + } ) } - showStyleDropdown = false - }, - text = { - Text( - text = getClockStyleName(context, style.value), - ) } - ) + } } } + + val darkColors = + colors == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current || colors == ClockWidgetColors.Dark + + CompositionLocalProvider( + LocalContentColor provides if (darkColors) { + Color(0, 0, 0, 180) + } else { + Color.White + }, + ) { + + HorizontalPager( + modifier = Modifier.animateContentSize(), + state = pagerState, + verticalAlignment = Alignment.Top, + ) { pageIndex -> + val currentPageStyle = styles[pageIndex] + if (currentPageStyle is ClockWidgetStyle.Custom && currentPageStyle.widgetId == null) { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(top = 24.dp, bottom = 8.dp), + contentAlignment = Alignment.TopCenter, + ) { + OutlinedButton( + onClick = { + showWidgetPicker = true + }, + contentPadding = ButtonDefaults.ButtonWithIconContentPadding, + modifier = Modifier + .padding(16.dp) + ) { + Icon( + modifier = Modifier + .padding(end = ButtonDefaults.IconSpacing) + .size(ButtonDefaults.IconSize), + imageVector = Icons.Rounded.Widgets, + contentDescription = null, + ) + Text(stringResource(R.string.widget_pick_widget)) + } + } + } else { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(top = 24.dp, bottom = 8.dp) + .pointerInput(Unit) { + awaitEachGesture { + val event = + awaitFirstDown(pass = PointerEventPass.Initial) + event.consume() + } + }, + contentAlignment = Alignment.TopCenter, + ) { + + if (currentPageStyle.javaClass == selected?.javaClass) { + Clock(selected, compact, darkColors) + } else { + Clock(currentPageStyle, compact, darkColors) + } + } + } + } + + } } - IconButton( - enabled = pagerState.currentPage < pagerState.pageCount - 1, - onClick = { - scope.launch { - pagerState.animateScrollToPage( - pagerState.currentPage + 1, - ) + Row( + verticalAlignment = Alignment.CenterVertically + ) { + IconButton( + enabled = pagerState.currentPage > 0, + onClick = { + scope.launch { + pagerState.animateScrollToPage( + pagerState.currentPage - 1, + ) + } + }) { + Icon(Icons.Rounded.ChevronLeft, null) + } + var showStyleDropdown by remember { mutableStateOf(false) } + TextButton( + modifier = Modifier + .weight(1f) + .padding(horizontal = 16.dp), + onClick = { showStyleDropdown = true }, + contentPadding = PaddingValues( + top = 8.dp, + bottom = 8.dp, + start = 16.dp, + end = 12.dp, + ), + colors = ButtonDefaults.textButtonColors( + contentColor = LocalContentColor.current, + ), + ) { + Text( + text = getClockStyleName( + context, + styles[pagerState.currentPage] + ), + textAlign = TextAlign.Center, + ) + Icon( + Icons.Rounded.ArrowDropDown, + null, + modifier = Modifier + .padding(ButtonDefaults.IconSpacing) + .size(ButtonDefaults.IconSize) + ) + DropdownMenu( + expanded = showStyleDropdown, + onDismissRequest = { showStyleDropdown = false } + ) { + for (style in styles.withIndex()) { + DropdownMenuItem( + onClick = { + scope.launch { + pagerState.animateScrollToPage( + style.index, + ) + } + showStyleDropdown = false + }, + text = { + Text( + text = getClockStyleName(context, style.value), + ) + } + ) + } } - }) { - Icon(Icons.Rounded.ChevronRight, null) + } + + IconButton( + enabled = pagerState.currentPage < pagerState.pageCount - 1, + onClick = { + scope.launch { + pagerState.animateScrollToPage( + pagerState.currentPage + 1, + ) + } + }) { + Icon(Icons.Rounded.ChevronRight, null) + } } } } @@ -311,7 +416,14 @@ fun WatchFaceSelector( if (previousWidgetId != null) { appWidgetHost.deleteAppWidgetId(previousWidgetId) } - onSelect(selected.copy(widgetId = (it as AppWidget).config.widgetId)) + it as AppWidget + onSelect( + selected.copy( + widgetId = it.config.widgetId, + width = it.config.width, + height = it.config.height, + ) + ) }, onDismiss = { showWidgetPicker = false @@ -332,4 +444,146 @@ fun getClockStyleName(context: Context, style: ClockWidgetStyle): String { is ClockWidgetStyle.Custom -> context.getString(R.string.clock_style_custom) else -> "" } +} + +@Composable +private fun ResizeCustomWidget( + style: ClockWidgetStyle.Custom, + compact: Boolean, + themeColors: Boolean, + lightBackground: Boolean, + onChange: (ClockWidgetStyle.Custom) -> Unit, + onExit: () -> Unit = {}, +) { + val context = LocalContext.current + + val widgetId = style.widgetId + + val widgetInfo = remember(widgetId) { + widgetId?.let { + AppWidgetManager.getInstance(context) + .getAppWidgetInfo(it) + } + } + if (widgetId != null && widgetInfo != null) { + val minWidth = when { + compact -> 64.dp + widgetInfo.minResizeWidth in 1..widgetInfo.minWidth -> { + widgetInfo.minResizeWidth.toDp() + } + + else -> { + widgetInfo.minWidth.toDp() + } + } + + val minHeight = when { + compact -> 16.dp + widgetInfo.minResizeHeight in 1..widgetInfo.minHeight -> { + widgetInfo.minResizeHeight.toDp() + } + + else -> { + widgetInfo.minHeight.toDp() + } + } + + val maxWidth = when { + compact -> 200.dp + isAtLeastApiLevel(31) && widgetInfo.maxResizeWidth > 0 -> { + widgetInfo.maxResizeWidth.toDp() + } + + else -> Dp.Unspecified + } + + val maxHeight = when { + compact -> 64.dp + isAtLeastApiLevel(31) && widgetInfo.maxResizeHeight > 0 -> { + widgetInfo.maxResizeHeight.toDp() + } + + else -> Dp.Unspecified + } + + + var resizeWidth by remember(style.widgetId) { + mutableStateOf( + style.width?.dp ?: Dp.Unspecified + ) + } + var resizeHeight by remember(style.widgetId) { mutableStateOf(style.height.dp) } + Box( + modifier = Modifier + .fillMaxSize() + .padding(top = 16.dp, bottom = 64.dp), + contentAlignment = Alignment.TopCenter, + ) { + AppWidgetHost( + widgetInfo = widgetInfo, + widgetId = widgetId, + modifier = Modifier + .then( + when { + compact && resizeWidth.isUnspecified -> Modifier.widthIn(max = 200.dp) + compact && !resizeWidth.isUnspecified -> Modifier.width( + resizeWidth.coerceAtMost( + 200.dp + ) + ) + + !compact && !resizeWidth.isUnspecified -> Modifier.width(resizeWidth) + else -> Modifier.fillMaxWidth() + } + ) + .then( + when { + compact -> Modifier.height(resizeHeight.coerceAtMost(64.dp)) + else -> Modifier.height(resizeHeight) + } + ) + .pointerInput(Unit) { + awaitEachGesture { + val event = awaitFirstDown(pass = PointerEventPass.Initial) + event.consume() + } + }, + borderless = compact, + useThemeColors = themeColors, + onLightBackground = lightBackground, + ) + + DragResizeHandle( + alignment = Alignment.TopCenter, + width = resizeWidth.coerceAtMost(maxWidth), + height = resizeHeight.coerceAtMost(maxHeight), + minWidth = minWidth, + minHeight = minHeight, + maxWidth = maxWidth, + maxHeight = if (compact) 64.dp else Dp.Unspecified, + onResize = { w, h -> + resizeWidth = w + resizeHeight = h + }, + onResizeStopped = { + onChange( + style.copy( + width = resizeWidth.value.toInt(), + height = resizeHeight.value.toInt() + ) + ) + } + ) + + FilledIconButton( + modifier = Modifier + .align(Alignment.BottomEnd) + .padding(8.dp) + .offset(y = 64.dp), + onClick = onExit + ) { + Icon(Icons.Rounded.Done, null) + } + } + } } \ No newline at end of file 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 c7341c6b..f82009f2 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 @@ -1,7 +1,10 @@ package de.mm20.launcher2.ui.launcher.widgets.clock.clocks import android.appwidget.AppWidgetManager +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -21,22 +24,36 @@ fun CustomClock( ) { val widgetId = style.widgetId - if (widgetId == null) { - Text("Hmmm…") - } else { + if (widgetId != null) { val context = LocalContext.current val widgetInfo = remember(widgetId) { AppWidgetManager.getInstance(context) .getAppWidgetInfo(widgetId) } if (widgetInfo != null) { + val width = style.width + val height = style.height AppWidgetHost( widgetInfo = widgetInfo, widgetId = widgetId, useThemeColors = useThemeColor, onLightBackground = darkColors, borderless = compact, - modifier = Modifier.widthIn(max = 250.dp).height(if (compact) 64.dp else 200.dp) + modifier = Modifier + .then( + when { + compact && width == null -> Modifier.widthIn(max = 200.dp) + compact && width != null -> Modifier.width(width.coerceAtMost(200).dp) + !compact && width != null -> Modifier.width(width.dp) + else -> Modifier.fillMaxWidth() + } + ) + .then( + when { + compact -> Modifier.height(height.coerceAtMost(64).dp) + else -> Modifier.height(height.dp) + } + ) ) } } diff --git a/core/i18n/src/main/res/values/strings.xml b/core/i18n/src/main/res/values/strings.xml index 5ae5a124..b6f9c964 100644 --- a/core/i18n/src/main/res/values/strings.xml +++ b/core/i18n/src/main/res/values/strings.xml @@ -843,6 +843,7 @@ Background card Configure widget Drag to resize + Resize Weather integration settings No calendars found Pick widget diff --git a/core/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherSettingsData.kt b/core/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherSettingsData.kt index ddd4d04f..b845ad79 100644 --- a/core/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherSettingsData.kt +++ b/core/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherSettingsData.kt @@ -239,7 +239,11 @@ sealed interface ClockWidgetStyle { @Serializable @SerialName("custom") - data class Custom(val widgetId: Int? = null) : ClockWidgetStyle + data class Custom( + val widgetId: Int? = null, + val width: Int? = null, + val height: Int = 200, + ) : ClockWidgetStyle } @Serializable