diff options
3 files changed, 47 insertions, 22 deletions
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResizeableItemFrame.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResizeableItemFrame.kt index fda46b855a65..ef62eb726e2b 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResizeableItemFrame.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResizeableItemFrame.kt @@ -30,6 +30,8 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -52,12 +54,11 @@ import com.android.systemui.communal.ui.viewmodel.ResizeableItemFrameViewModel import com.android.systemui.lifecycle.rememberViewModel import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.filterNotNull @Composable private fun UpdateGridLayoutInfo( viewModel: ResizeableItemFrameViewModel, - index: Int, + key: String, gridState: LazyGridState, minItemSpan: Int, gridContentPadding: PaddingValues, @@ -67,7 +68,7 @@ private fun UpdateGridLayoutInfo( LaunchedEffect( density, viewModel, - index, + key, gridState, minItemSpan, gridContentPadding, @@ -85,9 +86,8 @@ private fun UpdateGridLayoutInfo( snapshotFlow { gridState.layoutInfo.maxSpan }, snapshotFlow { gridState.layoutInfo.viewportSize.height }, snapshotFlow { - gridState.layoutInfo.visibleItemsInfo.firstOrNull { it.index == index } - } - .filterNotNull(), + gridState.layoutInfo.visibleItemsInfo.firstOrNull { it.key == key } + }, ::Triple, ) .collectLatest { (maxItemSpan, viewportHeightPx, itemInfo) -> @@ -97,8 +97,8 @@ private fun UpdateGridLayoutInfo( viewportHeightPx, maxItemSpan, minItemSpan, - itemInfo.row, - itemInfo.span, + itemInfo?.row, + itemInfo?.span, ) } } @@ -161,7 +161,7 @@ private fun BoxScope.DragHandle( */ @Composable fun ResizableItemFrame( - index: Int, + key: String, gridState: LazyGridState, minItemSpan: Int, gridContentPadding: PaddingValues, @@ -177,6 +177,7 @@ fun ResizableItemFrame( content: @Composable () -> Unit, ) { val brush = SolidColor(outlineColor) + val onResizeUpdated by rememberUpdatedState(onResize) val viewModel = rememberViewModel(traceName = "ResizeableItemFrame.viewModel") { ResizeableItemFrameViewModel() @@ -230,13 +231,15 @@ fun ResizableItemFrame( UpdateGridLayoutInfo( viewModel, - index, + key, gridState, minItemSpan, gridContentPadding, verticalArrangement, ) - LaunchedEffect(viewModel) { viewModel.resizeInfo.collectLatest(onResize) } + LaunchedEffect(viewModel) { + viewModel.resizeInfo.collectLatest { info -> onResizeUpdated(info) } + } } } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModelTest.kt index e1946fc7bc6f..f0d88ab41ad4 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModelTest.kt @@ -254,6 +254,23 @@ class ResizeableItemFrameViewModelTest : SysuiTestCase() { assertThat(resizeInfo).isEqualTo(ResizeInfo(-1, DragHandle.BOTTOM)) } + @Test + fun testRowInfoBecomesNull_revertsBackToDefault() = + testScope.runTest { + val gridLayout = singleSpanGrid.copy(maxItemSpan = 3, currentRow = 1) + updateGridLayout(gridLayout) + + val topState = underTest.topDragState + assertThat(topState.anchors.toList()).containsExactly(0 to 0f, -1 to -30f) + + val bottomState = underTest.bottomDragState + assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f, 1 to 30f) + + updateGridLayout(gridLayout.copy(currentRow = null)) + assertThat(topState.anchors.toList()).containsExactly(0 to 0f) + assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f) + } + @Test(expected = IllegalArgumentException::class) fun testIllegalState_maxSpanSmallerThanMinSpan() = testScope.runTest { @@ -317,7 +334,7 @@ class ResizeableItemFrameViewModelTest : SysuiTestCase() { val viewportHeightPx: Int, val maxItemSpan: Int, val minItemSpan: Int, - val currentRow: Int, - val currentSpan: Int, + val currentRow: Int?, + val currentSpan: Int?, ) } diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModel.kt index 7aad33da97b6..87fcdd7b97ee 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModel.kt @@ -25,8 +25,7 @@ import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.dropWhile -import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge @@ -45,7 +44,10 @@ data class ResizeInfo( val spans: Int, /** The drag handle which was used to resize the element. */ val fromHandle: DragHandle, -) +) { + /** Whether we are expanding. If false, then we are shrinking. */ + val isExpanding = spans > 0 +} class ResizeableItemFrameViewModel : ExclusiveActivatable() { private data class GridLayoutInfo( @@ -73,7 +75,7 @@ class ResizeableItemFrameViewModel : ExclusiveActivatable() { snapshotFlow { bottomDragState.settledValue } .map { ResizeInfo(it, DragHandle.BOTTOM) }, ) - .dropWhile { it.spans == 0 } + .filter { it.spans != 0 } .distinctUntilChanged() /** @@ -86,9 +88,13 @@ class ResizeableItemFrameViewModel : ExclusiveActivatable() { viewportHeightPx: Int, maxItemSpan: Int, minItemSpan: Int, - currentRow: Int, - currentSpan: Int, + currentRow: Int?, + currentSpan: Int?, ) { + if (currentSpan == null || currentRow == null) { + gridLayoutInfo.value = null + return + } require(maxItemSpan >= minItemSpan) { "Maximum item span of $maxItemSpan cannot be less than the minimum span of $minItemSpan" } @@ -114,10 +120,10 @@ class ResizeableItemFrameViewModel : ExclusiveActivatable() { private fun calculateAnchorsForHandle( handle: DragHandle, - layoutInfo: GridLayoutInfo, + layoutInfo: GridLayoutInfo?, ): DraggableAnchors<Int> { - if (!isDragAllowed(handle, layoutInfo)) { + if (layoutInfo == null || !isDragAllowed(handle, layoutInfo)) { return DraggableAnchors { 0 at 0f } } @@ -188,7 +194,6 @@ class ResizeableItemFrameViewModel : ExclusiveActivatable() { override suspend fun onActivated(): Nothing { coroutineScope("ResizeableItemFrameViewModel.onActivated") { gridLayoutInfo - .filterNotNull() .onEach { layoutInfo -> topDragState.updateAnchors( calculateAnchorsForHandle(DragHandle.TOP, layoutInfo) |