Loading packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingState.kt +5 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,11 @@ class ResizingState(tileSpec: TileSpec, startsAsIcon: Boolean) { anchoredDraggableState.animateTo(if (isIcon) QSDragAnchor.Icon else QSDragAnchor.Large) } suspend fun toggleCurrentValue() { val isIcon = anchoredDraggableState.currentValue == QSDragAnchor.Icon updateCurrentValue(!isIcon) } fun progress(): Float = anchoredDraggableState.progress(QSDragAnchor.Icon, QSDragAnchor.Large) /** Loading packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt +7 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.spring import androidx.compose.foundation.Canvas import androidx.compose.foundation.clickable import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.anchoredDraggable import androidx.compose.foundation.layout.Box Loading @@ -32,6 +33,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawWithContent Loading @@ -50,6 +52,7 @@ import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.ResizingDotSize import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.SelectedBorderWidth import kotlin.math.roundToInt import kotlinx.coroutines.launch /** * Places a dot to handle resizing drag events. Use this on tiles to resize. Loading Loading @@ -88,6 +91,7 @@ private fun ResizingHandle(enabled: Boolean, state: ResizingState, modifier: Mod // Manually creating the touch target around the resizing dot to ensure that the next tile // does not receive the touch input accidentally. val minTouchTargetSize = LocalMinimumInteractiveComponentSize.current val scope = rememberCoroutineScope() Box( modifier .layout { measurable, constraints -> Loading @@ -106,6 +110,9 @@ private fun ResizingHandle(enabled: Boolean, state: ResizingState, modifier: Mod state = state.anchoredDraggableState, orientation = Orientation.Horizontal, ) .clickable(enabled = enabled, interactionSource = null, indication = null) { scope.launch { state.toggleCurrentValue() } } ) { ResizingDot(enabled = enabled, modifier = Modifier.align(Alignment.Center)) } Loading packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt +47 −6 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.click import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.performClick Loading Loading @@ -73,7 +74,7 @@ class ResizingTest : SysuiTestCase() { } @Test fun toggleIconTile_shouldBeLarge() { fun toggleIconTileWithA11yAction_shouldBeLarge() { var tiles by mutableStateOf(TestEditTiles) val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2) composeRule.setContent { Loading @@ -89,7 +90,7 @@ class ResizingTest : SysuiTestCase() { } @Test fun toggleLargeTile_shouldBeIcon() { fun toggleLargeTileWithA11yAction_shouldBeIcon() { var tiles by mutableStateOf(TestEditTiles) val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2) composeRule.setContent { Loading @@ -105,7 +106,7 @@ class ResizingTest : SysuiTestCase() { } @Test fun resizedLarge_shouldBeIcon() { fun tapOnIconResizingHandle_shouldBeLarge() { var tiles by mutableStateOf(TestEditTiles) val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2) composeRule.setContent { Loading @@ -116,12 +117,32 @@ class ResizingTest : SysuiTestCase() { composeRule .onNodeWithContentDescription("tileA") .performClick() // Select .performTouchInput { // Resize down swipeRight() .performTouchInput { // Tap on resizing handle click(centerRight) } composeRule.waitForIdle() assertThat(tiles.find { it.tile.tileSpec.spec == "tileA" }?.width).isEqualTo(2) } @Test fun tapOnLargeResizingHandle_shouldBeIcon() { var tiles by mutableStateOf(TestEditTiles) val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2) composeRule.setContent { EditTileGridUnderTest(listState) { spec, toIcon -> tiles = tiles.resize(spec, toIcon) } } composeRule.waitForIdle() composeRule .onNodeWithContentDescription("tileD_large") .performClick() // Select .performTouchInput { // Tap on resizing handle click(centerRight) } composeRule.waitForIdle() assertThat(tiles.find { it.tile.tileSpec.spec == "tileA" }?.width).isEqualTo(1) assertThat(tiles.find { it.tile.tileSpec.spec == "tileD_large" }?.width).isEqualTo(1) } @Test Loading @@ -133,6 +154,26 @@ class ResizingTest : SysuiTestCase() { } composeRule.waitForIdle() composeRule .onNodeWithContentDescription("tileA") .performClick() // Select .performTouchInput { // Resize up swipeRight(startX = right, endX = right * 2) } composeRule.waitForIdle() assertThat(tiles.find { it.tile.tileSpec.spec == "tileA" }?.width).isEqualTo(2) } @Test fun resizedLarge_shouldBeIcon() { var tiles by mutableStateOf(TestEditTiles) val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2) composeRule.setContent { EditTileGridUnderTest(listState) { spec, toIcon -> tiles = tiles.resize(spec, toIcon) } } composeRule.waitForIdle() composeRule .onNodeWithContentDescription("tileD_large") .performClick() // Select Loading Loading
packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingState.kt +5 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,11 @@ class ResizingState(tileSpec: TileSpec, startsAsIcon: Boolean) { anchoredDraggableState.animateTo(if (isIcon) QSDragAnchor.Icon else QSDragAnchor.Large) } suspend fun toggleCurrentValue() { val isIcon = anchoredDraggableState.currentValue == QSDragAnchor.Icon updateCurrentValue(!isIcon) } fun progress(): Float = anchoredDraggableState.progress(QSDragAnchor.Icon, QSDragAnchor.Large) /** Loading
packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt +7 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.spring import androidx.compose.foundation.Canvas import androidx.compose.foundation.clickable import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.anchoredDraggable import androidx.compose.foundation.layout.Box Loading @@ -32,6 +33,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawWithContent Loading @@ -50,6 +52,7 @@ import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.ResizingDotSize import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.SelectedBorderWidth import kotlin.math.roundToInt import kotlinx.coroutines.launch /** * Places a dot to handle resizing drag events. Use this on tiles to resize. Loading Loading @@ -88,6 +91,7 @@ private fun ResizingHandle(enabled: Boolean, state: ResizingState, modifier: Mod // Manually creating the touch target around the resizing dot to ensure that the next tile // does not receive the touch input accidentally. val minTouchTargetSize = LocalMinimumInteractiveComponentSize.current val scope = rememberCoroutineScope() Box( modifier .layout { measurable, constraints -> Loading @@ -106,6 +110,9 @@ private fun ResizingHandle(enabled: Boolean, state: ResizingState, modifier: Mod state = state.anchoredDraggableState, orientation = Orientation.Horizontal, ) .clickable(enabled = enabled, interactionSource = null, indication = null) { scope.launch { state.toggleCurrentValue() } } ) { ResizingDot(enabled = enabled, modifier = Modifier.align(Alignment.Center)) } Loading
packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt +47 −6 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.click import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.performClick Loading Loading @@ -73,7 +74,7 @@ class ResizingTest : SysuiTestCase() { } @Test fun toggleIconTile_shouldBeLarge() { fun toggleIconTileWithA11yAction_shouldBeLarge() { var tiles by mutableStateOf(TestEditTiles) val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2) composeRule.setContent { Loading @@ -89,7 +90,7 @@ class ResizingTest : SysuiTestCase() { } @Test fun toggleLargeTile_shouldBeIcon() { fun toggleLargeTileWithA11yAction_shouldBeIcon() { var tiles by mutableStateOf(TestEditTiles) val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2) composeRule.setContent { Loading @@ -105,7 +106,7 @@ class ResizingTest : SysuiTestCase() { } @Test fun resizedLarge_shouldBeIcon() { fun tapOnIconResizingHandle_shouldBeLarge() { var tiles by mutableStateOf(TestEditTiles) val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2) composeRule.setContent { Loading @@ -116,12 +117,32 @@ class ResizingTest : SysuiTestCase() { composeRule .onNodeWithContentDescription("tileA") .performClick() // Select .performTouchInput { // Resize down swipeRight() .performTouchInput { // Tap on resizing handle click(centerRight) } composeRule.waitForIdle() assertThat(tiles.find { it.tile.tileSpec.spec == "tileA" }?.width).isEqualTo(2) } @Test fun tapOnLargeResizingHandle_shouldBeIcon() { var tiles by mutableStateOf(TestEditTiles) val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2) composeRule.setContent { EditTileGridUnderTest(listState) { spec, toIcon -> tiles = tiles.resize(spec, toIcon) } } composeRule.waitForIdle() composeRule .onNodeWithContentDescription("tileD_large") .performClick() // Select .performTouchInput { // Tap on resizing handle click(centerRight) } composeRule.waitForIdle() assertThat(tiles.find { it.tile.tileSpec.spec == "tileA" }?.width).isEqualTo(1) assertThat(tiles.find { it.tile.tileSpec.spec == "tileD_large" }?.width).isEqualTo(1) } @Test Loading @@ -133,6 +154,26 @@ class ResizingTest : SysuiTestCase() { } composeRule.waitForIdle() composeRule .onNodeWithContentDescription("tileA") .performClick() // Select .performTouchInput { // Resize up swipeRight(startX = right, endX = right * 2) } composeRule.waitForIdle() assertThat(tiles.find { it.tile.tileSpec.spec == "tileA" }?.width).isEqualTo(2) } @Test fun resizedLarge_shouldBeIcon() { var tiles by mutableStateOf(TestEditTiles) val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2) composeRule.setContent { EditTileGridUnderTest(listState) { spec, toIcon -> tiles = tiles.resize(spec, toIcon) } } composeRule.waitForIdle() composeRule .onNodeWithContentDescription("tileD_large") .performClick() // Select Loading