Add horizontal appwidget resizing
This commit is contained in:
parent
7056c5963a
commit
1a45ae9003
@ -0,0 +1,183 @@
|
|||||||
|
package de.mm20.launcher2.ui.component
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.gestures.Orientation
|
||||||
|
import androidx.compose.foundation.gestures.draggable
|
||||||
|
import androidx.compose.foundation.gestures.rememberDraggableState
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
|
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.requiredHeight
|
||||||
|
import androidx.compose.foundation.layout.requiredSize
|
||||||
|
import androidx.compose.foundation.layout.requiredWidth
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.rounded.UnfoldMore
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.rotate
|
||||||
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.coerceIn
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.isUnspecified
|
||||||
|
|
||||||
|
enum class ResizeAxis {
|
||||||
|
Horizontal,
|
||||||
|
Vertical,
|
||||||
|
Both,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DragResizeHandle(
|
||||||
|
resizeAxis: ResizeAxis = ResizeAxis.Both,
|
||||||
|
alignment: Alignment = Alignment.TopStart,
|
||||||
|
minWidth: Dp = 0.dp,
|
||||||
|
minHeight: Dp = 0.dp,
|
||||||
|
maxWidth: Dp = Dp.Infinity,
|
||||||
|
maxHeight: Dp = Dp.Infinity,
|
||||||
|
snapToMeasuredWidth: Boolean = false,
|
||||||
|
snapToMeasuredHeight: Boolean = false,
|
||||||
|
width: Dp = Dp.Unspecified,
|
||||||
|
height: Dp = Dp.Unspecified,
|
||||||
|
onResize: (width: Dp, height: Dp) -> Unit,
|
||||||
|
onResizeStopped: () -> Unit = { },
|
||||||
|
) {
|
||||||
|
BoxWithConstraints(
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
val measuredWidth = this.maxWidth
|
||||||
|
val measuredHeight = this.maxHeight
|
||||||
|
|
||||||
|
val density = LocalDensity.current
|
||||||
|
|
||||||
|
val hapticFeedback = LocalHapticFeedback.current
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.then(if (width.isUnspecified) Modifier.fillMaxWidth() else Modifier.requiredWidth(width))
|
||||||
|
.then(if (height.isUnspecified) Modifier.fillMaxHeight() else Modifier.requiredHeight(height))
|
||||||
|
.align(alignment)
|
||||||
|
.border(1.dp, color = MaterialTheme.colorScheme.primary, MaterialTheme.shapes.small)
|
||||||
|
) {
|
||||||
|
if (resizeAxis == ResizeAxis.Both || resizeAxis == ResizeAxis.Horizontal) {
|
||||||
|
val horizontalDragState = rememberDraggableState {
|
||||||
|
val currentWidth = if (width.isUnspecified) measuredWidth else width
|
||||||
|
val dragDelta =
|
||||||
|
when (alignment) {
|
||||||
|
Alignment.Center, Alignment.TopCenter, Alignment.BottomCenter -> it * 2
|
||||||
|
else -> it
|
||||||
|
}
|
||||||
|
|
||||||
|
val newWidth = (currentWidth + with(density) { dragDelta.toDp() }).coerceIn(
|
||||||
|
minWidth,
|
||||||
|
maxWidth
|
||||||
|
)
|
||||||
|
|
||||||
|
if (snapToMeasuredWidth &&
|
||||||
|
maxWidth >= measuredWidth &&
|
||||||
|
newWidth > measuredWidth - 16.dp &&
|
||||||
|
dragDelta > 0
|
||||||
|
) {
|
||||||
|
if (!width.isUnspecified) {
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.TextHandleMove)
|
||||||
|
onResize(Dp.Unspecified, height)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
onResize(newWidth, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Box(
|
||||||
|
Modifier
|
||||||
|
.align(Alignment.CenterEnd)
|
||||||
|
.draggable(
|
||||||
|
state = horizontalDragState,
|
||||||
|
orientation = Orientation.Horizontal,
|
||||||
|
onDragStopped = {
|
||||||
|
onResizeStopped()
|
||||||
|
},
|
||||||
|
startDragImmediately = true,
|
||||||
|
)
|
||||||
|
.requiredSize(128.dp)
|
||||||
|
.offset(x = 64.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(MaterialTheme.colorScheme.primary, CircleShape)
|
||||||
|
.padding(8.dp)
|
||||||
|
.rotate(90f)
|
||||||
|
.align(Alignment.Center),
|
||||||
|
imageVector = Icons.Rounded.UnfoldMore,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.onPrimary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resizeAxis == ResizeAxis.Both || resizeAxis == ResizeAxis.Vertical) {
|
||||||
|
val verticalDragState = rememberDraggableState {
|
||||||
|
val currentHeight = if (height.isUnspecified) measuredHeight else height
|
||||||
|
val dragDelta =
|
||||||
|
when (alignment) {
|
||||||
|
Alignment.Center, Alignment.CenterStart, Alignment.CenterEnd -> it * 2
|
||||||
|
else -> it
|
||||||
|
}
|
||||||
|
val newHeight = (currentHeight + with(density) { dragDelta.toDp() }).coerceIn(
|
||||||
|
minHeight,
|
||||||
|
maxHeight
|
||||||
|
)
|
||||||
|
|
||||||
|
if (snapToMeasuredHeight &&
|
||||||
|
maxHeight >= measuredHeight &&
|
||||||
|
newHeight > measuredHeight - 16.dp &&
|
||||||
|
dragDelta > 0
|
||||||
|
) {
|
||||||
|
if (!height.isUnspecified) {
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.TextHandleMove)
|
||||||
|
onResize(width, Dp.Unspecified)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
onResize(width, newHeight)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Box(
|
||||||
|
Modifier
|
||||||
|
.align(Alignment.BottomCenter)
|
||||||
|
.draggable(
|
||||||
|
state = verticalDragState,
|
||||||
|
orientation = Orientation.Vertical,
|
||||||
|
onDragStopped = {
|
||||||
|
onResizeStopped()
|
||||||
|
},
|
||||||
|
startDragImmediately = true,
|
||||||
|
)
|
||||||
|
.requiredSize(128.dp)
|
||||||
|
.offset(y = 64.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(MaterialTheme.colorScheme.primary, CircleShape)
|
||||||
|
.padding(8.dp)
|
||||||
|
.align(Alignment.Center),
|
||||||
|
imageVector = Icons.Rounded.UnfoldMore,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.onPrimary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,6 +15,8 @@ import androidx.browser.customtabs.CustomTabsIntent
|
|||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.gestures.Orientation
|
import androidx.compose.foundation.gestures.Orientation
|
||||||
|
import androidx.compose.foundation.gestures.awaitEachGesture
|
||||||
|
import androidx.compose.foundation.gestures.awaitFirstDown
|
||||||
import androidx.compose.foundation.gestures.draggable
|
import androidx.compose.foundation.gestures.draggable
|
||||||
import androidx.compose.foundation.gestures.rememberDraggableState
|
import androidx.compose.foundation.gestures.rememberDraggableState
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
@ -26,6 +28,7 @@ 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.padding
|
||||||
import androidx.compose.foundation.layout.requiredSize
|
import androidx.compose.foundation.layout.requiredSize
|
||||||
|
import androidx.compose.foundation.layout.requiredWidth
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
@ -65,13 +68,17 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
|
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.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.isUnspecified
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import de.mm20.launcher2.calendar.CalendarRepository
|
import de.mm20.launcher2.calendar.CalendarRepository
|
||||||
import de.mm20.launcher2.calendar.UserCalendar
|
import de.mm20.launcher2.calendar.UserCalendar
|
||||||
@ -82,6 +89,7 @@ import de.mm20.launcher2.permissions.PermissionsManager
|
|||||||
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.BottomSheetDialog
|
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||||
|
import de.mm20.launcher2.ui.component.DragResizeHandle
|
||||||
import de.mm20.launcher2.ui.component.LargeMessage
|
import de.mm20.launcher2.ui.component.LargeMessage
|
||||||
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
||||||
import de.mm20.launcher2.ui.component.preferences.CheckboxPreference
|
import de.mm20.launcher2.ui.component.preferences.CheckboxPreference
|
||||||
@ -338,111 +346,58 @@ fun ColumnScope.ConfigureAppWidget(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var dragDelta by remember { mutableStateOf(0) }
|
|
||||||
Column {
|
Column {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clip(MaterialTheme.shapes.medium)
|
.padding(bottom = 64.dp)
|
||||||
.background(MaterialTheme.colorScheme.surfaceVariant)
|
.background(MaterialTheme.colorScheme.surfaceVariant, MaterialTheme.shapes.medium)
|
||||||
) {
|
) {
|
||||||
|
var resizeWidth by remember {
|
||||||
|
mutableStateOf(widget.config.width?.dp ?: Dp.Unspecified)
|
||||||
|
}
|
||||||
|
|
||||||
|
var resizeHeight by remember {
|
||||||
|
mutableStateOf(widget.config.height.dp)
|
||||||
|
}
|
||||||
|
|
||||||
AppWidgetHost(
|
AppWidgetHost(
|
||||||
widgetInfo = widgetInfo,
|
widgetInfo = widgetInfo,
|
||||||
widgetId = widget.config.widgetId,
|
widgetId = widget.config.widgetId,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier
|
||||||
height = widget.config.height + dragDelta,
|
.clip(MaterialTheme.shapes.medium)
|
||||||
|
.then(if (resizeWidth.isUnspecified) Modifier.fillMaxWidth() else Modifier.requiredWidth(resizeWidth))
|
||||||
|
.height(resizeHeight)
|
||||||
|
.align(Alignment.TopCenter)
|
||||||
|
.pointerInput(Unit) {
|
||||||
|
awaitEachGesture {
|
||||||
|
val event = awaitFirstDown(pass = PointerEventPass.Initial)
|
||||||
|
event.consume()
|
||||||
|
}
|
||||||
|
},
|
||||||
borderless = widget.config.borderless,
|
borderless = widget.config.borderless,
|
||||||
useThemeColors = widget.config.themeColors,
|
useThemeColors = widget.config.themeColors,
|
||||||
onLightBackground = (!LocalDarkTheme.current && widget.config.background) || LocalPreferDarkContentOverWallpaper.current
|
onLightBackground = (!LocalDarkTheme.current && widget.config.background) || LocalPreferDarkContentOverWallpaper.current
|
||||||
)
|
)
|
||||||
}
|
DragResizeHandle(
|
||||||
val density = LocalDensity.current
|
alignment = Alignment.TopCenter,
|
||||||
val draggableState = rememberDraggableState {
|
height = resizeHeight,
|
||||||
dragDelta = (dragDelta + it / density.density).roundToInt()
|
width = resizeWidth,
|
||||||
.coerceIn(
|
snapToMeasuredWidth = true,
|
||||||
-widget.config.height + 1,
|
onResize = { w, h ->
|
||||||
500 - widget.config.height
|
resizeWidth = w
|
||||||
)
|
resizeHeight = h
|
||||||
}
|
},
|
||||||
Row(
|
onResizeStopped = {
|
||||||
modifier = Modifier
|
onWidgetUpdated(
|
||||||
.padding(top = 8.dp, bottom = 16.dp)
|
widget.copy(
|
||||||
.padding(horizontal = 8.dp)
|
config = widget.config.copy(
|
||||||
.fillMaxWidth(),
|
height = resizeHeight.value.roundToInt(),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
width = resizeWidth.takeIf { it != Dp.Unspecified }?.value?.roundToInt()
|
||||||
) {
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
val tooltipState = rememberTooltipState()
|
|
||||||
TooltipBox(
|
|
||||||
state = tooltipState,
|
|
||||||
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
|
|
||||||
tooltip = {
|
|
||||||
PlainTooltip {
|
|
||||||
Text(stringResource(R.string.widget_config_appwidget_resize_hint))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(end = 16.dp)
|
|
||||||
.clip(MaterialTheme.shapes.small)
|
|
||||||
.background(MaterialTheme.colorScheme.primaryContainer)
|
|
||||||
.height(36.dp)
|
|
||||||
.width(48.dp)
|
|
||||||
.draggable(
|
|
||||||
state = draggableState,
|
|
||||||
orientation = Orientation.Vertical,
|
|
||||||
onDragStopped = {
|
|
||||||
onWidgetUpdated(
|
|
||||||
widget.copy(
|
|
||||||
config = widget.config.copy(
|
|
||||||
height = widget.config.height + dragDelta
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
dragDelta = 0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.clickable {
|
|
||||||
scope.launch {
|
|
||||||
tooltipState.show()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Rounded.UnfoldMore,
|
|
||||||
contentDescription = null,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
var textFieldValue by remember(widget.config.height) { mutableStateOf(widget.config.height.toString()) }
|
|
||||||
OutlinedTextField(
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(1f)
|
|
||||||
.padding(bottom = 8.dp),
|
|
||||||
value = (widget.config.height + dragDelta).toString(),
|
|
||||||
onValueChange = {
|
|
||||||
val intValue = it.toIntOrNull()
|
|
||||||
if (intValue == null) textFieldValue = ""
|
|
||||||
else if (intValue in 1..1000) {
|
|
||||||
onWidgetUpdated(
|
|
||||||
widget.copy(
|
|
||||||
config = widget.config.copy(
|
|
||||||
height = intValue
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
textFieldValue = intValue.toString()
|
)
|
||||||
}
|
}
|
||||||
},
|
|
||||||
label = { Text(stringResource(R.string.widget_config_appwidget_height)) },
|
|
||||||
suffix = { Text("dp") },
|
|
||||||
keyboardOptions = KeyboardOptions(
|
|
||||||
keyboardType = KeyboardType.Number,
|
|
||||||
imeAction = ImeAction.Done
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
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.height
|
||||||
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
|
||||||
@ -32,11 +33,10 @@ fun CustomClock(
|
|||||||
AppWidgetHost(
|
AppWidgetHost(
|
||||||
widgetInfo = widgetInfo,
|
widgetInfo = widgetInfo,
|
||||||
widgetId = widgetId,
|
widgetId = widgetId,
|
||||||
height = if (compact) 64 else 200,
|
|
||||||
useThemeColors = useThemeColor,
|
useThemeColors = useThemeColor,
|
||||||
onLightBackground = darkColors,
|
onLightBackground = darkColors,
|
||||||
borderless = compact,
|
borderless = compact,
|
||||||
modifier = Modifier.widthIn(max = 250.dp)
|
modifier = Modifier.widthIn(max = 250.dp).height(if (compact) 64.dp else 200.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,8 +2,11 @@ package de.mm20.launcher2.ui.launcher.widgets.external
|
|||||||
|
|
||||||
import android.appwidget.AppWidgetHost
|
import android.appwidget.AppWidgetHost
|
||||||
import android.appwidget.AppWidgetManager
|
import android.appwidget.AppWidgetManager
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.requiredWidth
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.rounded.Warning
|
import androidx.compose.material.icons.rounded.Warning
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
@ -15,10 +18,12 @@ import androidx.compose.runtime.mutableStateOf
|
|||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
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.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.isUnspecified
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.Banner
|
import de.mm20.launcher2.ui.component.Banner
|
||||||
import de.mm20.launcher2.ui.ktx.toPixels
|
import de.mm20.launcher2.ui.ktx.toPixels
|
||||||
@ -90,14 +95,22 @@ fun AppWidget(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
AppWidgetHost(
|
val width = widget.config.width
|
||||||
widgetId = widget.config.widgetId,
|
Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
|
||||||
widgetInfo = widgetInfo,
|
AppWidgetHost(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
widgetId = widget.config.widgetId,
|
||||||
height = widget.config.height,
|
widgetInfo = widgetInfo,
|
||||||
borderless = widget.config.borderless,
|
modifier = Modifier
|
||||||
useThemeColors = widget.config.themeColors,
|
.then(
|
||||||
onLightBackground = lightBackground,
|
if (width == null) Modifier.fillMaxWidth() else Modifier.requiredWidth(
|
||||||
)
|
width.dp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.height(widget.config.height.dp),
|
||||||
|
borderless = widget.config.borderless,
|
||||||
|
useThemeColors = widget.config.themeColors,
|
||||||
|
onLightBackground = lightBackground,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,10 +1,8 @@
|
|||||||
package de.mm20.launcher2.ui.launcher.widgets.external
|
package de.mm20.launcher2.ui.launcher.widgets.external
|
||||||
|
|
||||||
import android.appwidget.AppWidgetHost
|
|
||||||
import android.appwidget.AppWidgetProviderInfo
|
import android.appwidget.AppWidgetProviderInfo
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
|
||||||
import android.util.SparseIntArray
|
import android.util.SparseIntArray
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@ -12,6 +10,7 @@ import android.widget.ListView
|
|||||||
import android.widget.ScrollView
|
import android.widget.ScrollView
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.material3.ColorScheme
|
import androidx.compose.material3.ColorScheme
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
@ -33,7 +32,6 @@ import kotlin.math.roundToInt
|
|||||||
fun AppWidgetHost(
|
fun AppWidgetHost(
|
||||||
widgetInfo: AppWidgetProviderInfo,
|
widgetInfo: AppWidgetProviderInfo,
|
||||||
widgetId: Int,
|
widgetId: Int,
|
||||||
height: Int,
|
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
borderless: Boolean = false,
|
borderless: Boolean = false,
|
||||||
useThemeColors: Boolean = false,
|
useThemeColors: Boolean = false,
|
||||||
@ -44,12 +42,15 @@ fun AppWidgetHost(
|
|||||||
val colorScheme = MaterialTheme.colorScheme
|
val colorScheme = MaterialTheme.colorScheme
|
||||||
val appWidgetHost = LocalAppWidgetHost.current
|
val appWidgetHost = LocalAppWidgetHost.current
|
||||||
|
|
||||||
BoxWithConstraints {
|
BoxWithConstraints(
|
||||||
|
modifier = modifier,
|
||||||
|
) {
|
||||||
val maxWidth = maxWidth
|
val maxWidth = maxWidth
|
||||||
|
val maxHeight = maxHeight
|
||||||
key(widgetId) {
|
key(widgetId) {
|
||||||
AndroidView(
|
AndroidView(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.height(height.dp),
|
.fillMaxSize(),
|
||||||
factory = {
|
factory = {
|
||||||
val view = appWidgetHost.createView(it.applicationContext, widgetId, widgetInfo)
|
val view = appWidgetHost.createView(it.applicationContext, widgetId, widgetInfo)
|
||||||
enableNestedScroll(view)
|
enableNestedScroll(view)
|
||||||
@ -71,9 +72,9 @@ fun AppWidgetHost(
|
|||||||
it.updateAppWidgetSize(
|
it.updateAppWidgetSize(
|
||||||
null,
|
null,
|
||||||
maxWidth.value.roundToInt(),
|
maxWidth.value.roundToInt(),
|
||||||
height,
|
maxHeight.value.roundToInt(),
|
||||||
maxWidth.value.roundToInt(),
|
maxWidth.value.roundToInt(),
|
||||||
height,
|
maxHeight.value.roundToInt(),
|
||||||
)
|
)
|
||||||
it.setPadding(padding)
|
it.setPadding(padding)
|
||||||
// Workaround to force update of the widget view
|
// Workaround to force update of the widget view
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import java.util.UUID
|
|||||||
data class AppWidgetConfig(
|
data class AppWidgetConfig(
|
||||||
val widgetId: Int,
|
val widgetId: Int,
|
||||||
val height: Int,
|
val height: Int,
|
||||||
|
val width: Int? = null,
|
||||||
val borderless: Boolean = false,
|
val borderless: Boolean = false,
|
||||||
val background: Boolean = true,
|
val background: Boolean = true,
|
||||||
val themeColors: Boolean = true,
|
val themeColors: Boolean = true,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user