diff options
author | 2025-03-13 06:39:25 +0000 | |
---|---|---|
committer | 2025-03-20 01:02:26 +0000 | |
commit | a1fbc8da8d3dfde09e89adf131877961fe9d62c5 (patch) | |
tree | cfa4f9e44e77e46d7fb029a8be9ddfee4143d2c0 | |
parent | c74a0961123efd89b350476e6d7a49b623e1d798 (diff) |
Center glanceable hub widgets vertically in the window
Adjust grid padding and gutter values for compact screen sizes in
portrait and landscape orientation.
In CommunalContent, center communal grid vertically in window using
even top and bottom margins.
Bug: b/399688758
Test: on foldable and tablet
Flag: com.android.systemui.communal_responsive_grid
Change-Id: I3949d39b867b5bce1f0f6e42ac0c55bf40160941
2 files changed, 87 insertions, 10 deletions
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt index 0181928317e1..1a0fb0afd385 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt @@ -16,6 +16,7 @@ package com.android.systemui.communal.ui.compose +import android.content.res.Configuration import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -23,6 +24,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.layout.Layout +import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntRect @@ -66,6 +68,7 @@ constructor( @Composable fun ContentScope.Content(modifier: Modifier = Modifier) { CommunalTouchableSurface(viewModel = viewModel, modifier = modifier) { + val orientation = LocalConfiguration.current.orientation Layout( modifier = Modifier.fillMaxSize(), content = { @@ -150,13 +153,29 @@ constructor( val bottomAreaPlaceable = bottomAreaMeasurable.measure(noMinConstraints) + val communalGridMaxHeight: Int + val communalGridPositionY: Int + if (Flags.communalResponsiveGrid()) { + val communalGridVerticalMargin = constraints.maxHeight - lockIconBounds.top + // Bias the widgets up by a small offset for visual balance in landscape + // orientation + val verticalOffset = + (if (orientation == Configuration.ORIENTATION_LANDSCAPE) (-3).dp else 0.dp) + .roundToPx() + // Use even top and bottom margin for grid to be centered in maxHeight (window) + communalGridMaxHeight = constraints.maxHeight - communalGridVerticalMargin * 2 + communalGridPositionY = communalGridVerticalMargin + verticalOffset + } else { + communalGridMaxHeight = lockIconBounds.top + communalGridPositionY = 0 + } val communalGridPlaceable = communalGridMeasurable.measure( - noMinConstraints.copy(maxHeight = lockIconBounds.top) + noMinConstraints.copy(maxHeight = communalGridMaxHeight) ) layout(constraints.maxWidth, constraints.maxHeight) { - communalGridPlaceable.place(x = 0, y = 0) + communalGridPlaceable.place(x = 0, y = communalGridPositionY) lockIconPlaceable.place(x = lockIconBounds.left, y = lockIconBounds.top) val bottomAreaTop = constraints.maxHeight - bottomAreaPlaceable.height diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt index 835dd7aa9f24..ad2a32e030bb 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt @@ -54,7 +54,10 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.calculateStartPadding +import androidx.compose.foundation.layout.displayCutout import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -76,8 +79,8 @@ import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.TextAutoSize import androidx.compose.foundation.text.BasicText +import androidx.compose.foundation.text.TextAutoSize import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add @@ -99,6 +102,8 @@ import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass +import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect @@ -174,6 +179,7 @@ import com.android.compose.animation.Easings.Emphasized import com.android.compose.animation.scene.ContentScope import com.android.compose.modifiers.thenIf import com.android.compose.ui.graphics.painter.rememberDrawablePainter +import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.internal.R.dimen.system_app_widget_background_radius import com.android.systemui.Flags import com.android.systemui.Flags.communalResponsiveGrid @@ -254,6 +260,7 @@ fun CommunalHub( val windowMetrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(context) val screenWidth = windowMetrics.bounds.width() val layoutDirection = LocalLayoutDirection.current + if (viewModel.isEditMode) { ObserveNewWidgetAddedEffect(communalContent, gridState, viewModel) } else { @@ -757,11 +764,33 @@ fun calculateWidgetSize( } @Composable +private fun horizontalPaddingWithInsets(padding: Dp): Dp { + val orientation = LocalConfiguration.current.orientation + val displayCutoutPaddings = WindowInsets.displayCutout.asPaddingValues() + val horizontalDisplayCutoutPadding = + remember(orientation, displayCutoutPaddings) { + if (orientation == Configuration.ORIENTATION_LANDSCAPE) { + maxOf( + // Top in portrait becomes startPadding (or endPadding) in landscape + displayCutoutPaddings.calculateTopPadding(), + // Bottom in portrait becomes endPadding (or startPadding) in landscape + displayCutoutPaddings.calculateBottomPadding(), + ) + } else { + 0.dp + } + } + return padding + horizontalDisplayCutoutPadding +} + +@Composable private fun HorizontalGridWrapper( minContentPadding: PaddingValues, gridState: LazyGridState, dragDropState: GridDragDropState?, setContentOffset: (offset: Offset) -> Unit, + minHorizontalArrangement: Dp, + minVerticalArrangement: Dp, modifier: Modifier = Modifier, content: LazyGridScope.(sizeInfo: SizeInfo?) -> Unit, ) { @@ -775,8 +804,8 @@ private fun HorizontalGridWrapper( state = gridState, flingBehavior = flingBehavior, minContentPadding = minContentPadding, - minHorizontalArrangement = Dimensions.ItemSpacing, - minVerticalArrangement = Dimensions.ItemSpacing, + minHorizontalArrangement = minHorizontalArrangement, + minVerticalArrangement = minVerticalArrangement, setContentOffset = setContentOffset, // Temporarily disable user gesture scrolling while dragging a widget to prevent // conflicts between the drag and scroll gestures. Programmatic scrolling remains @@ -833,6 +862,7 @@ private fun BoxScope.CommunalHubLazyGrid( Modifier.align(Alignment.TopStart).onGloballyPositioned { setGridCoordinates(it) } var list = communalContent var dragDropState: GridDragDropState? = null + var arrangementSpacing = Dimensions.ItemSpacing if (viewModel.isEditMode && viewModel is CommunalEditModeViewModel) { list = contentListState.list // for drag & drop operations within the communal hub grid @@ -866,6 +896,9 @@ private fun BoxScope.CommunalHubLazyGrid( Box(Modifier.fillMaxSize().dragAndDropTarget(dragAndDropTargetState)) {} } else if (communalResponsiveGrid()) { gridModifier = gridModifier.fillMaxSize() + if (isCompactWindow()) { + arrangementSpacing = Dimensions.ItemSpacingCompact + } } else { gridModifier = gridModifier.height(hubDimensions.GridHeight) } @@ -875,6 +908,8 @@ private fun BoxScope.CommunalHubLazyGrid( gridState = gridState, dragDropState = dragDropState, minContentPadding = minContentPadding, + minHorizontalArrangement = arrangementSpacing, + minVerticalArrangement = arrangementSpacing, setContentOffset = setContentOffset, ) { sizeInfo -> /** Override spans based on the responsive grid size */ @@ -1839,11 +1874,21 @@ private fun nonScalableTextSize(sizeInDp: Dp) = with(LocalDensity.current) { siz @Composable private fun gridContentPadding(isEditMode: Boolean, toolbarSize: IntSize?): PaddingValues { if (!isEditMode || toolbarSize == null) { - return PaddingValues( - start = Dimensions.ItemSpacing, - end = Dimensions.ItemSpacing, - top = hubDimensions.GridTopSpacing, - ) + return if (communalResponsiveGrid()) { + val horizontalPaddings: Dp = + if (isCompactWindow()) { + horizontalPaddingWithInsets(Dimensions.ItemSpacingCompact) + } else { + Dimensions.ItemSpacing + } + PaddingValues(start = horizontalPaddings, end = horizontalPaddings) + } else { + PaddingValues( + start = Dimensions.ItemSpacing, + end = Dimensions.ItemSpacing, + top = hubDimensions.GridTopSpacing, + ) + } } val context = LocalContext.current val density = LocalDensity.current @@ -1870,6 +1915,16 @@ private fun gridContentPadding(isEditMode: Boolean, toolbarSize: IntSize?): Padd } } +/** Compact size in landscape or portrait */ +@Composable +fun isCompactWindow(): Boolean { + val windowSizeClass = LocalWindowSizeClass.current + return remember(windowSizeClass) { + windowSizeClass.widthSizeClass == WindowWidthSizeClass.Compact || + windowSizeClass.heightSizeClass == WindowHeightSizeClass.Compact + } +} + private fun CommunalContentSize.FixedSize.dp(): Dp { return when (this) { CommunalContentSize.FixedSize.FULL -> Dimensions.CardHeightFull @@ -1911,6 +1966,9 @@ class Dimensions(val context: Context, val config: Configuration) { val CardHeightFull get() = 530.adjustedDp + val ItemSpacingCompact + get() = 12.adjustedDp + val ItemSpacing get() = if (communalResponsiveGrid()) 32.adjustedDp else 50.adjustedDp |