Allow resizing of custom clock widgets
This commit is contained in:
parent
64002c9f38
commit
38c048ec03
@ -163,7 +163,7 @@ fun ClockWidget(
|
|||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.then(if (fillScreenHeight) Modifier.weight(1f) else Modifier)
|
.then(if (fillScreenHeight) Modifier.weight(1f) else Modifier)
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth().padding(horizontal = 24.dp),
|
||||||
contentAlignment = when (alignment) {
|
contentAlignment = when (alignment) {
|
||||||
ClockWidgetAlignment.Center -> Alignment.Center
|
ClockWidgetAlignment.Center -> Alignment.Center
|
||||||
ClockWidgetAlignment.Top -> Alignment.TopCenter
|
ClockWidgetAlignment.Top -> Alignment.TopCenter
|
||||||
@ -408,6 +408,7 @@ fun ConfigureClockWidgetSheet(
|
|||||||
styles = availableStyles,
|
styles = availableStyles,
|
||||||
compact = compact!!,
|
compact = compact!!,
|
||||||
colors = color!!,
|
colors = color!!,
|
||||||
|
themeColors = useAccentColor,
|
||||||
selected = style,
|
selected = style,
|
||||||
onSelect = {
|
onSelect = {
|
||||||
viewModel.setClockStyle(it)
|
viewModel.setClockStyle(it)
|
||||||
|
|||||||
@ -5,34 +5,49 @@ import android.app.ActivityOptions
|
|||||||
import android.appwidget.AppWidgetManager
|
import android.appwidget.AppWidgetManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.util.Log
|
import androidx.compose.animation.AnimatedContent
|
||||||
import androidx.compose.animation.animateContentSize
|
import androidx.compose.animation.animateContentSize
|
||||||
import androidx.compose.animation.scaleIn
|
import androidx.compose.animation.scaleIn
|
||||||
import androidx.compose.animation.scaleOut
|
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.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
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.padding
|
||||||
import androidx.compose.foundation.layout.size
|
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.HorizontalPager
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.rounded.ArrowDropDown
|
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.ChevronLeft
|
||||||
import androidx.compose.material.icons.rounded.ChevronRight
|
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.Settings
|
||||||
|
import androidx.compose.material.icons.rounded.SwapHoriz
|
||||||
import androidx.compose.material.icons.rounded.Tune
|
import androidx.compose.material.icons.rounded.Tune
|
||||||
import androidx.compose.material.icons.rounded.Widgets
|
import androidx.compose.material.icons.rounded.Widgets
|
||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
import androidx.compose.material3.DropdownMenu
|
import androidx.compose.material3.DropdownMenu
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
|
import androidx.compose.material3.FilledIconButton
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.OutlinedButton
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
@ -48,16 +63,26 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.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.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
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.dp
|
||||||
|
import androidx.compose.ui.unit.isUnspecified
|
||||||
import androidx.compose.ui.zIndex
|
import androidx.compose.ui.zIndex
|
||||||
|
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||||
import de.mm20.launcher2.preferences.ClockWidgetColors
|
import de.mm20.launcher2.preferences.ClockWidgetColors
|
||||||
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||||
|
import de.mm20.launcher2.ui.BuildConfig
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.base.LocalAppWidgetHost
|
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.sheets.WidgetPickerSheet
|
||||||
|
import de.mm20.launcher2.ui.launcher.widgets.external.AppWidgetHost
|
||||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||||
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
|
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
|
||||||
import de.mm20.launcher2.widgets.AppWidget
|
import de.mm20.launcher2.widgets.AppWidget
|
||||||
@ -68,24 +93,41 @@ fun WatchFaceSelector(
|
|||||||
styles: List<ClockWidgetStyle>,
|
styles: List<ClockWidgetStyle>,
|
||||||
compact: Boolean,
|
compact: Boolean,
|
||||||
colors: ClockWidgetColors,
|
colors: ClockWidgetColors,
|
||||||
|
themeColors: Boolean,
|
||||||
selected: ClockWidgetStyle?,
|
selected: ClockWidgetStyle?,
|
||||||
onSelect: (ClockWidgetStyle) -> Unit,
|
onSelect: (ClockWidgetStyle) -> Unit,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
var showWidgetPicker by rememberSaveable { mutableStateOf(false) }
|
var showWidgetPicker by rememberSaveable { mutableStateOf(false) }
|
||||||
|
var resizeCustomWidget by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
val lightBackground =
|
||||||
|
colors == ClockWidgetColors.Dark || colors == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current
|
||||||
|
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 16.dp, horizontal = 32.dp),
|
.padding(vertical = 16.dp, horizontal = 0.dp),
|
||||||
color = if (colors == ClockWidgetColors.Dark || colors == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current) {
|
color = if (lightBackground) {
|
||||||
if (LocalDarkTheme.current) MaterialTheme.colorScheme.inverseSurface else MaterialTheme.colorScheme.surfaceContainer
|
if (LocalDarkTheme.current) MaterialTheme.colorScheme.inverseSurface else MaterialTheme.colorScheme.surfaceContainer
|
||||||
} else {
|
} else {
|
||||||
if (LocalDarkTheme.current) MaterialTheme.colorScheme.surfaceContainer else MaterialTheme.colorScheme.inverseSurface
|
if (LocalDarkTheme.current) MaterialTheme.colorScheme.surfaceContainer else MaterialTheme.colorScheme.inverseSurface
|
||||||
},
|
},
|
||||||
shape = MaterialTheme.shapes.medium,
|
shape = MaterialTheme.shapes.medium,
|
||||||
) {
|
) {
|
||||||
|
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(
|
Column(
|
||||||
modifier = Modifier,
|
modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
@ -106,7 +148,7 @@ fun WatchFaceSelector(
|
|||||||
|
|
||||||
Box {
|
Box {
|
||||||
androidx.compose.animation.AnimatedVisibility(
|
androidx.compose.animation.AnimatedVisibility(
|
||||||
selected is ClockWidgetStyle.Digital1 || selected is ClockWidgetStyle.Custom,
|
selected is ClockWidgetStyle.Digital1 || (selected is ClockWidgetStyle.Custom && selected.widgetId != null),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.TopEnd)
|
.align(Alignment.TopEnd)
|
||||||
.zIndex(1f),
|
.zIndex(1f),
|
||||||
@ -127,9 +169,11 @@ fun WatchFaceSelector(
|
|||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text(stringResource(R.string.clock_variant_outlined)) },
|
text = { Text(stringResource(R.string.clock_variant_outlined)) },
|
||||||
leadingIcon = {
|
leadingIcon = {
|
||||||
if (selected.outlined) {
|
Icon(
|
||||||
Icon(Icons.Rounded.Check, null)
|
if (selected.outlined) Icons.Rounded.CheckCircle
|
||||||
}
|
else Icons.Rounded.RadioButtonUnchecked,
|
||||||
|
null
|
||||||
|
)
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
onSelect(selected.copy(outlined = !selected.outlined))
|
onSelect(selected.copy(outlined = !selected.outlined))
|
||||||
@ -140,13 +184,20 @@ fun WatchFaceSelector(
|
|||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text(stringResource(R.string.widget_pick_widget)) },
|
text = { Text(stringResource(R.string.widget_pick_widget)) },
|
||||||
leadingIcon = {
|
leadingIcon = {
|
||||||
Icon(Icons.Rounded.Widgets, null)
|
Icon(Icons.Rounded.SwapHoriz, null)
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
showWidgetPicker = true
|
showWidgetPicker = true
|
||||||
showStyleSettings = false
|
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 widget = remember(selected.widgetId) {
|
||||||
val id = selected.widgetId ?: return@remember null
|
val id = selected.widgetId ?: return@remember null
|
||||||
AppWidgetManager.getInstance(context)
|
AppWidgetManager.getInstance(context)
|
||||||
@ -181,12 +232,30 @@ fun WatchFaceSelector(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
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()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val darkColors = colors == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current || colors == ClockWidgetColors.Dark
|
val darkColors =
|
||||||
|
colors == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current || colors == ClockWidgetColors.Dark
|
||||||
|
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
LocalContentColor provides if (darkColors) {
|
LocalContentColor provides if (darkColors) {
|
||||||
@ -201,13 +270,47 @@ fun WatchFaceSelector(
|
|||||||
state = pagerState,
|
state = pagerState,
|
||||||
verticalAlignment = Alignment.Top,
|
verticalAlignment = Alignment.Top,
|
||||||
) { pageIndex ->
|
) { pageIndex ->
|
||||||
|
val currentPageStyle = styles[pageIndex]
|
||||||
|
if (currentPageStyle is ClockWidgetStyle.Custom && currentPageStyle.widgetId == null) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(top = 24.dp, bottom = 8.dp),
|
.padding(top = 24.dp, bottom = 8.dp),
|
||||||
contentAlignment = Alignment.TopCenter,
|
contentAlignment = Alignment.TopCenter,
|
||||||
) {
|
) {
|
||||||
val currentPageStyle = styles[pageIndex]
|
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) {
|
if (currentPageStyle.javaClass == selected?.javaClass) {
|
||||||
Clock(selected, compact, darkColors)
|
Clock(selected, compact, darkColors)
|
||||||
} else {
|
} else {
|
||||||
@ -215,6 +318,7 @@ fun WatchFaceSelector(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -301,6 +405,7 @@ fun WatchFaceSelector(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (showWidgetPicker && selected is ClockWidgetStyle.Custom) {
|
if (showWidgetPicker && selected is ClockWidgetStyle.Custom) {
|
||||||
val previousWidgetId = selected.widgetId
|
val previousWidgetId = selected.widgetId
|
||||||
@ -311,7 +416,14 @@ fun WatchFaceSelector(
|
|||||||
if (previousWidgetId != null) {
|
if (previousWidgetId != null) {
|
||||||
appWidgetHost.deleteAppWidgetId(previousWidgetId)
|
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 = {
|
onDismiss = {
|
||||||
showWidgetPicker = false
|
showWidgetPicker = false
|
||||||
@ -333,3 +445,145 @@ fun getClockStyleName(context: Context, style: ClockWidgetStyle): String {
|
|||||||
else -> ""
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,10 @@
|
|||||||
package de.mm20.launcher2.ui.launcher.widgets.clock.clocks
|
package de.mm20.launcher2.ui.launcher.widgets.clock.clocks
|
||||||
|
|
||||||
import android.appwidget.AppWidgetManager
|
import android.appwidget.AppWidgetManager
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
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.foundation.layout.widthIn
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@ -21,22 +24,36 @@ fun CustomClock(
|
|||||||
) {
|
) {
|
||||||
val widgetId = style.widgetId
|
val widgetId = style.widgetId
|
||||||
|
|
||||||
if (widgetId == null) {
|
if (widgetId != null) {
|
||||||
Text("Hmmm…")
|
|
||||||
} else {
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val widgetInfo = remember(widgetId) {
|
val widgetInfo = remember(widgetId) {
|
||||||
AppWidgetManager.getInstance(context)
|
AppWidgetManager.getInstance(context)
|
||||||
.getAppWidgetInfo(widgetId)
|
.getAppWidgetInfo(widgetId)
|
||||||
}
|
}
|
||||||
if (widgetInfo != null) {
|
if (widgetInfo != null) {
|
||||||
|
val width = style.width
|
||||||
|
val height = style.height
|
||||||
AppWidgetHost(
|
AppWidgetHost(
|
||||||
widgetInfo = widgetInfo,
|
widgetInfo = widgetInfo,
|
||||||
widgetId = widgetId,
|
widgetId = widgetId,
|
||||||
useThemeColors = useThemeColor,
|
useThemeColors = useThemeColor,
|
||||||
onLightBackground = darkColors,
|
onLightBackground = darkColors,
|
||||||
borderless = compact,
|
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)
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -843,6 +843,7 @@
|
|||||||
<string name="widget_config_appwidget_background">Background card</string>
|
<string name="widget_config_appwidget_background">Background card</string>
|
||||||
<string name="widget_config_appwidget_configure">Configure widget</string>
|
<string name="widget_config_appwidget_configure">Configure widget</string>
|
||||||
<string name="widget_config_appwidget_resize_hint">Drag to resize</string>
|
<string name="widget_config_appwidget_resize_hint">Drag to resize</string>
|
||||||
|
<string name="widget_config_appwidget_resize">Resize</string>
|
||||||
<string name="widget_config_weather_integration_settings">Weather integration settings</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_config_calendar_no_calendars">No calendars found</string>
|
||||||
<string name="widget_pick_widget">Pick widget</string>
|
<string name="widget_pick_widget">Pick widget</string>
|
||||||
|
|||||||
@ -239,7 +239,11 @@ sealed interface ClockWidgetStyle {
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("custom")
|
@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
|
@Serializable
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user