Loading packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt +48 −31 Original line number Diff line number Diff line Loading @@ -130,12 +130,11 @@ fun CommunalHub( val gridState = rememberLazyGridState() val contentListState = rememberContentListState(widgetConfigurator, communalContent, viewModel) val reorderingWidgets by viewModel.reorderingWidgets.collectAsState() val selectedIndex = viewModel.selectedIndex.collectAsState() val selectedKey = viewModel.selectedKey.collectAsState() val removeButtonEnabled by remember { derivedStateOf { selectedIndex.value != null || reorderingWidgets } derivedStateOf { selectedKey.value != null || reorderingWidgets } } val (isButtonToEditWidgetsShowing, setIsButtonToEditWidgetsShowing) = remember { mutableStateOf(false) } var isButtonToEditWidgetsShowing by remember { mutableStateOf(false) } val contentPadding = gridContentPadding(viewModel.isEditMode, toolbarSize) val contentOffset = beforeContentPadding(contentPadding).toOffset() Loading @@ -150,22 +149,30 @@ fun CommunalHub( if (!viewModel.isEditMode) return@pointerInput observeTapsWithoutConsuming { offset -> val adjustedOffset = offset - contentOffset val index = gridState.layoutInfo.visibleItemsInfo .firstItemAtOffset(adjustedOffset) ?.index val newIndex = if (index?.let(contentListState::isItemEditable) == true) { index } else { null } viewModel.setSelectedIndex(newIndex) val index = firstIndexAtOffset(gridState, adjustedOffset) val key = index?.let { keyAtIndexIfEditable(contentListState.list, index) } viewModel.setSelectedKey(key) } } .thenIf(!viewModel.isEditMode) { Modifier.pointerInput(Unit) { detectLongPressGesture { offset -> setIsButtonToEditWidgetsShowing(true) } Modifier.pointerInput( gridState, contentOffset, communalContent, gridCoordinates ) { detectLongPressGesture { offset -> isButtonToEditWidgetsShowing = true // Deduct both grid offset relative to its container and content offset. val adjustedOffset = gridCoordinates?.let { offset - it.positionInWindow() - contentOffset } val index = adjustedOffset?.let { firstIndexAtOffset(gridState, it) } val key = index?.let { keyAtIndexIfEditable(communalContent, index) } viewModel.setSelectedKey(key) } } }, ) { Loading @@ -186,7 +193,7 @@ fun CommunalHub( onOpenWidgetPicker = onOpenWidgetPicker, gridState = gridState, contentListState = contentListState, selectedIndex = selectedIndex, selectedKey = selectedKey, widgetConfigurator = widgetConfigurator, ) Loading @@ -198,10 +205,14 @@ fun CommunalHub( onEditDone = onEditDone, onOpenWidgetPicker = onOpenWidgetPicker, onRemoveClicked = { selectedIndex.value?.let { index -> contentListState.onRemove(index) val index = selectedKey.value?.let { key -> contentListState.list.indexOfFirst { it.key == key } } index?.let { contentListState.onRemove(it) contentListState.onSaveList() viewModel.setSelectedIndex(null) viewModel.setSelectedKey(null) } }, removeEnabled = removeButtonEnabled Loading @@ -219,10 +230,10 @@ fun CommunalHub( if (isButtonToEditWidgetsShowing) { ButtonToEditWidgets( onClick = { setIsButtonToEditWidgetsShowing(false) viewModel.onOpenWidgetEditor() isButtonToEditWidgetsShowing = false viewModel.onOpenWidgetEditor(selectedKey.value) }, onHide = { setIsButtonToEditWidgetsShowing(false) }, onHide = { isButtonToEditWidgetsShowing = false }, ) } Loading @@ -244,7 +255,7 @@ private fun BoxScope.CommunalHubLazyGrid( communalContent: List<CommunalContentModel>, viewModel: BaseCommunalViewModel, contentPadding: PaddingValues, selectedIndex: State<Int?>, selectedKey: State<String?>, contentOffset: Offset, gridState: LazyGridState, contentListState: ContentListState, Loading @@ -253,7 +264,8 @@ private fun BoxScope.CommunalHubLazyGrid( onOpenWidgetPicker: (() -> Unit)? = null, widgetConfigurator: WidgetConfigurator?, ) { var gridModifier = Modifier.align(Alignment.CenterStart) var gridModifier = Modifier.align(Alignment.CenterStart).onGloballyPositioned { setGridCoordinates(it) } var list = communalContent var dragDropState: GridDragDropState? = null if (viewModel.isEditMode && viewModel is CommunalEditModeViewModel) { Loading @@ -266,10 +278,7 @@ private fun BoxScope.CommunalHubLazyGrid( updateDragPositionForRemove = updateDragPositionForRemove ) gridModifier = gridModifier .fillMaxSize() .dragContainer(dragDropState, contentOffset, viewModel) .onGloballyPositioned { setGridCoordinates(it) } gridModifier.fillMaxSize().dragContainer(dragDropState, contentOffset, viewModel) // for widgets dropped from other activities val dragAndDropTargetState = rememberDragAndDropTargetState( Loading Loading @@ -307,7 +316,8 @@ private fun BoxScope.CommunalHubLazyGrid( list[index].size.dp().value, ) if (viewModel.isEditMode && dragDropState != null) { val selected by remember(index) { derivedStateOf { index == selectedIndex.value } } val selected by remember(index) { derivedStateOf { list[index].key == selectedKey.value } } DraggableItem( dragDropState = dragDropState, selected = selected, Loading Loading @@ -832,6 +842,13 @@ private fun CommunalContentSize.dp(): Dp { } } private fun firstIndexAtOffset(gridState: LazyGridState, offset: Offset): Int? = gridState.layoutInfo.visibleItemsInfo.firstItemAtOffset(offset)?.index /** Returns the key of item if it's editable at the given index. Only widget is editable. */ private fun keyAtIndexIfEditable(list: List<CommunalContentModel>, index: Int): String? = if (index in list.indices && list[index].isWidget()) list[index].key else null data class ContentPaddingInPx(val start: Float, val top: Float) { fun toOffset(): Offset = Offset(start, top) } Loading packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt +8 −0 Original line number Diff line number Diff line Loading @@ -633,6 +633,14 @@ class CommunalInteractorTest : SysuiTestCase() { verify(editWidgetsActivityStarter).startActivity() } @Test fun showWidgetEditor_withPreselectedKey_startsActivity() = testScope.runTest { val widgetKey = CommunalContentModel.KEY.widget(123) underTest.showWidgetEditor(preselectedKey = widgetKey) verify(editWidgetsActivityStarter).startActivity(widgetKey) } private fun smartspaceTimer(id: String, timestamp: Long = 0L): SmartspaceTarget { val timer = mock(SmartspaceTarget::class.java) whenever(timer.smartspaceTargetId).thenReturn(id) Loading packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt +13 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,19 @@ class CommunalEditModeViewModelTest : SysuiTestCase() { .isInstanceOf(CommunalContentModel.CtaTileInEditMode::class.java) } @Test fun selectedKey_onReorderWidgets_isCleared() = testScope.runTest { val selectedKey by collectLastValue(underTest.selectedKey) val key = CommunalContentModel.KEY.widget(123) underTest.setSelectedKey(key) assertThat(selectedKey).isEqualTo(key) underTest.onReorderWidgetStart() assertThat(selectedKey).isNull() } @Test fun reorderWidget_uiEventLogging_start() { underTest.onReorderWidgetStart() Loading packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +2 −2 Original line number Diff line number Diff line Loading @@ -176,8 +176,8 @@ constructor( } /** Show the widget editor Activity. */ fun showWidgetEditor() { editWidgetsActivityStarter.startActivity() fun showWidgetEditor(preselectedKey: String? = null) { editWidgetsActivityStarter.startActivity(preselectedKey) } /** Dismiss the CTA tile from the hub in view mode. */ Loading packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt +2 −0 Original line number Diff line number Diff line Loading @@ -128,4 +128,6 @@ sealed interface CommunalContentModel { } } } fun isWidget() = this is Widget } Loading
packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt +48 −31 Original line number Diff line number Diff line Loading @@ -130,12 +130,11 @@ fun CommunalHub( val gridState = rememberLazyGridState() val contentListState = rememberContentListState(widgetConfigurator, communalContent, viewModel) val reorderingWidgets by viewModel.reorderingWidgets.collectAsState() val selectedIndex = viewModel.selectedIndex.collectAsState() val selectedKey = viewModel.selectedKey.collectAsState() val removeButtonEnabled by remember { derivedStateOf { selectedIndex.value != null || reorderingWidgets } derivedStateOf { selectedKey.value != null || reorderingWidgets } } val (isButtonToEditWidgetsShowing, setIsButtonToEditWidgetsShowing) = remember { mutableStateOf(false) } var isButtonToEditWidgetsShowing by remember { mutableStateOf(false) } val contentPadding = gridContentPadding(viewModel.isEditMode, toolbarSize) val contentOffset = beforeContentPadding(contentPadding).toOffset() Loading @@ -150,22 +149,30 @@ fun CommunalHub( if (!viewModel.isEditMode) return@pointerInput observeTapsWithoutConsuming { offset -> val adjustedOffset = offset - contentOffset val index = gridState.layoutInfo.visibleItemsInfo .firstItemAtOffset(adjustedOffset) ?.index val newIndex = if (index?.let(contentListState::isItemEditable) == true) { index } else { null } viewModel.setSelectedIndex(newIndex) val index = firstIndexAtOffset(gridState, adjustedOffset) val key = index?.let { keyAtIndexIfEditable(contentListState.list, index) } viewModel.setSelectedKey(key) } } .thenIf(!viewModel.isEditMode) { Modifier.pointerInput(Unit) { detectLongPressGesture { offset -> setIsButtonToEditWidgetsShowing(true) } Modifier.pointerInput( gridState, contentOffset, communalContent, gridCoordinates ) { detectLongPressGesture { offset -> isButtonToEditWidgetsShowing = true // Deduct both grid offset relative to its container and content offset. val adjustedOffset = gridCoordinates?.let { offset - it.positionInWindow() - contentOffset } val index = adjustedOffset?.let { firstIndexAtOffset(gridState, it) } val key = index?.let { keyAtIndexIfEditable(communalContent, index) } viewModel.setSelectedKey(key) } } }, ) { Loading @@ -186,7 +193,7 @@ fun CommunalHub( onOpenWidgetPicker = onOpenWidgetPicker, gridState = gridState, contentListState = contentListState, selectedIndex = selectedIndex, selectedKey = selectedKey, widgetConfigurator = widgetConfigurator, ) Loading @@ -198,10 +205,14 @@ fun CommunalHub( onEditDone = onEditDone, onOpenWidgetPicker = onOpenWidgetPicker, onRemoveClicked = { selectedIndex.value?.let { index -> contentListState.onRemove(index) val index = selectedKey.value?.let { key -> contentListState.list.indexOfFirst { it.key == key } } index?.let { contentListState.onRemove(it) contentListState.onSaveList() viewModel.setSelectedIndex(null) viewModel.setSelectedKey(null) } }, removeEnabled = removeButtonEnabled Loading @@ -219,10 +230,10 @@ fun CommunalHub( if (isButtonToEditWidgetsShowing) { ButtonToEditWidgets( onClick = { setIsButtonToEditWidgetsShowing(false) viewModel.onOpenWidgetEditor() isButtonToEditWidgetsShowing = false viewModel.onOpenWidgetEditor(selectedKey.value) }, onHide = { setIsButtonToEditWidgetsShowing(false) }, onHide = { isButtonToEditWidgetsShowing = false }, ) } Loading @@ -244,7 +255,7 @@ private fun BoxScope.CommunalHubLazyGrid( communalContent: List<CommunalContentModel>, viewModel: BaseCommunalViewModel, contentPadding: PaddingValues, selectedIndex: State<Int?>, selectedKey: State<String?>, contentOffset: Offset, gridState: LazyGridState, contentListState: ContentListState, Loading @@ -253,7 +264,8 @@ private fun BoxScope.CommunalHubLazyGrid( onOpenWidgetPicker: (() -> Unit)? = null, widgetConfigurator: WidgetConfigurator?, ) { var gridModifier = Modifier.align(Alignment.CenterStart) var gridModifier = Modifier.align(Alignment.CenterStart).onGloballyPositioned { setGridCoordinates(it) } var list = communalContent var dragDropState: GridDragDropState? = null if (viewModel.isEditMode && viewModel is CommunalEditModeViewModel) { Loading @@ -266,10 +278,7 @@ private fun BoxScope.CommunalHubLazyGrid( updateDragPositionForRemove = updateDragPositionForRemove ) gridModifier = gridModifier .fillMaxSize() .dragContainer(dragDropState, contentOffset, viewModel) .onGloballyPositioned { setGridCoordinates(it) } gridModifier.fillMaxSize().dragContainer(dragDropState, contentOffset, viewModel) // for widgets dropped from other activities val dragAndDropTargetState = rememberDragAndDropTargetState( Loading Loading @@ -307,7 +316,8 @@ private fun BoxScope.CommunalHubLazyGrid( list[index].size.dp().value, ) if (viewModel.isEditMode && dragDropState != null) { val selected by remember(index) { derivedStateOf { index == selectedIndex.value } } val selected by remember(index) { derivedStateOf { list[index].key == selectedKey.value } } DraggableItem( dragDropState = dragDropState, selected = selected, Loading Loading @@ -832,6 +842,13 @@ private fun CommunalContentSize.dp(): Dp { } } private fun firstIndexAtOffset(gridState: LazyGridState, offset: Offset): Int? = gridState.layoutInfo.visibleItemsInfo.firstItemAtOffset(offset)?.index /** Returns the key of item if it's editable at the given index. Only widget is editable. */ private fun keyAtIndexIfEditable(list: List<CommunalContentModel>, index: Int): String? = if (index in list.indices && list[index].isWidget()) list[index].key else null data class ContentPaddingInPx(val start: Float, val top: Float) { fun toOffset(): Offset = Offset(start, top) } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt +8 −0 Original line number Diff line number Diff line Loading @@ -633,6 +633,14 @@ class CommunalInteractorTest : SysuiTestCase() { verify(editWidgetsActivityStarter).startActivity() } @Test fun showWidgetEditor_withPreselectedKey_startsActivity() = testScope.runTest { val widgetKey = CommunalContentModel.KEY.widget(123) underTest.showWidgetEditor(preselectedKey = widgetKey) verify(editWidgetsActivityStarter).startActivity(widgetKey) } private fun smartspaceTimer(id: String, timestamp: Long = 0L): SmartspaceTarget { val timer = mock(SmartspaceTarget::class.java) whenever(timer.smartspaceTargetId).thenReturn(id) Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt +13 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,19 @@ class CommunalEditModeViewModelTest : SysuiTestCase() { .isInstanceOf(CommunalContentModel.CtaTileInEditMode::class.java) } @Test fun selectedKey_onReorderWidgets_isCleared() = testScope.runTest { val selectedKey by collectLastValue(underTest.selectedKey) val key = CommunalContentModel.KEY.widget(123) underTest.setSelectedKey(key) assertThat(selectedKey).isEqualTo(key) underTest.onReorderWidgetStart() assertThat(selectedKey).isNull() } @Test fun reorderWidget_uiEventLogging_start() { underTest.onReorderWidgetStart() Loading
packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +2 −2 Original line number Diff line number Diff line Loading @@ -176,8 +176,8 @@ constructor( } /** Show the widget editor Activity. */ fun showWidgetEditor() { editWidgetsActivityStarter.startActivity() fun showWidgetEditor(preselectedKey: String? = null) { editWidgetsActivityStarter.startActivity(preselectedKey) } /** Dismiss the CTA tile from the hub in view mode. */ Loading
packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt +2 −0 Original line number Diff line number Diff line Loading @@ -128,4 +128,6 @@ sealed interface CommunalContentModel { } } } fun isWidget() = this is Widget }