Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4bfcd10c authored by Prince Donkor's avatar Prince Donkor Committed by Android (Google) Code Review
Browse files

Merge "Dismissing Customize Widgets pop up after time out" into main

parents 3c4501a6 6572c6b8
Loading
Loading
Loading
Loading
+21 −18
Original line number Diff line number Diff line
@@ -132,6 +132,7 @@ import com.android.systemui.communal.ui.compose.extensions.observeTaps
import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
import com.android.systemui.communal.ui.viewmodel.CommunalEditModeViewModel
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.communal.ui.viewmodel.PopupType
import com.android.systemui.communal.widgets.WidgetConfigurator
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
@@ -148,8 +149,7 @@ fun CommunalHub(
    onEditDone: (() -> Unit)? = null,
) {
    val communalContent by viewModel.communalContent.collectAsState(initial = emptyList())
    val isPopupOnDismissCtaShowing by
        viewModel.isPopupOnDismissCtaShowing.collectAsState(initial = false)
    val currentPopup by viewModel.currentPopup.collectAsState(initial = null)
    var removeButtonCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
    var toolbarSize: IntSize? by remember { mutableStateOf(null) }
    var gridCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
@@ -161,7 +161,6 @@ fun CommunalHub(
    val removeButtonEnabled by remember {
        derivedStateOf { selectedKey.value != null || reorderingWidgets }
    }
    var isButtonToEditWidgetsShowing by remember { mutableStateOf(false) }
    val isEmptyState by viewModel.isEmptyState.collectAsState(initial = false)

    val contentPadding = gridContentPadding(viewModel.isEditMode, toolbarSize)
@@ -214,7 +213,7 @@ fun CommunalHub(
                                        communalContent[index] is
                                            CommunalContentModel.CtaTileInViewMode
                                ) {
                                    isButtonToEditWidgetsShowing = true
                                    viewModel.onShowCustomizeWidgetButton()
                                }
                                val key =
                                    index?.let { keyAtIndexIfEditable(communalContent, index) }
@@ -290,19 +289,23 @@ fun CommunalHub(
            )
        }

        if (isPopupOnDismissCtaShowing) {
            PopupOnDismissCtaTile(viewModel::onHidePopupAfterDismissCta)
        if (currentPopup != null) {
            when (currentPopup) {
                PopupType.CtaTile -> {
                    PopupOnDismissCtaTile(viewModel::onHidePopup)
                }

        if (isButtonToEditWidgetsShowing) {
                PopupType.CustomizeWidgetButton -> {
                    ButtonToEditWidgets(
                        onClick = {
                    isButtonToEditWidgetsShowing = false
                            viewModel.onHidePopup()
                            viewModel.onOpenWidgetEditor(selectedKey.value)
                        },
                onHide = { isButtonToEditWidgetsShowing = false },
                        onHide = { viewModel.onHidePopup()}
                    )
                }
                null -> {}
            }
        }

        if (viewModel is CommunalViewModel && dialogFactory != null) {
            val isEnableWidgetDialogShowing by
@@ -679,11 +682,11 @@ private fun ButtonToEditWidgets(
}

@Composable
private fun PopupOnDismissCtaTile(onHidePopupAfterDismissCta: () -> Unit) {
private fun PopupOnDismissCtaTile(onHidePopup: () -> Unit) {
    Popup(
        alignment = Alignment.TopCenter,
        offset = IntOffset(0, 40),
        onDismissRequest = onHidePopupAfterDismissCta
        onDismissRequest = onHidePopup
    ) {
        val colors = LocalAndroidColorScheme.current
        Row(
+34 −7
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel.Companion.POPUP_AUTO_HIDE_TIMEOUT_MS
import com.android.systemui.communal.ui.viewmodel.PopupType
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED
@@ -247,7 +248,7 @@ class CommunalViewModelTest(flags: FlagsParameterization?) : SysuiTestCase() {
            tutorialRepository.setTutorialSettingState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED)

            val communalContent by collectLastValue(underTest.communalContent)
            val isPopupOnDismissCtaShowing by collectLastValue(underTest.isPopupOnDismissCtaShowing)
            val currentPopup by collectLastValue(underTest.currentPopup)

            assertThat(communalContent?.size).isEqualTo(1)
            assertThat(communalContent?.get(0))
@@ -257,11 +258,11 @@ class CommunalViewModelTest(flags: FlagsParameterization?) : SysuiTestCase() {

            // hide CTA tile and show the popup
            assertThat(communalContent).isEmpty()
            assertThat(isPopupOnDismissCtaShowing).isEqualTo(true)
            assertThat(currentPopup).isEqualTo(PopupType.CtaTile)

            // hide popup after time elapsed
            advanceTimeBy(POPUP_AUTO_HIDE_TIMEOUT_MS)
            assertThat(isPopupOnDismissCtaShowing).isEqualTo(false)
            assertThat(currentPopup).isNull()
        }

    @Test
@@ -269,14 +270,40 @@ class CommunalViewModelTest(flags: FlagsParameterization?) : SysuiTestCase() {
        testScope.runTest {
            tutorialRepository.setTutorialSettingState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED)

            val isPopupOnDismissCtaShowing by collectLastValue(underTest.isPopupOnDismissCtaShowing)
            val currentPopup by collectLastValue(underTest.currentPopup)

            underTest.onDismissCtaTile()
            assertThat(isPopupOnDismissCtaShowing).isEqualTo(true)
            assertThat(currentPopup).isEqualTo(PopupType.CtaTile)

            // dismiss the popup directly
            underTest.onHidePopupAfterDismissCta()
            assertThat(isPopupOnDismissCtaShowing).isEqualTo(false)
            underTest.onHidePopup()
            assertThat(currentPopup).isNull()
        }

    @Test
    fun customizeWidgetButton_showsThenHidesAfterTimeout() =
        testScope.runTest {
            tutorialRepository.setTutorialSettingState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED)
            val currentPopup by collectLastValue(underTest.currentPopup)

            assertThat(currentPopup).isNull()
            underTest.onShowCustomizeWidgetButton()
            assertThat(currentPopup).isEqualTo(PopupType.CustomizeWidgetButton)
            advanceTimeBy(POPUP_AUTO_HIDE_TIMEOUT_MS)
            assertThat(currentPopup).isNull()
        }

    @Test
    fun customizeWidgetButton_onDismiss_hidesImmediately() =
        testScope.runTest {
            tutorialRepository.setTutorialSettingState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED)
            val currentPopup by collectLastValue(underTest.currentPopup)

            underTest.onShowCustomizeWidgetButton()
            assertThat(currentPopup).isEqualTo(PopupType.CustomizeWidgetButton)

            underTest.onHidePopup()
            assertThat(currentPopup).isNull()
        }

    @Test
+7 −4
Original line number Diff line number Diff line
@@ -88,14 +88,14 @@ abstract class BaseCommunalViewModel(
    /** Whether in edit mode for the communal hub. */
    open val isEditMode = false

    /** Whether the popup message triggered by dismissing the CTA tile is showing. */
    open val isPopupOnDismissCtaShowing: Flow<Boolean> = flowOf(false)
    /** Whether the type of popup currently showing */
    open val currentPopup: Flow<PopupType?> = flowOf(null)

    /** Whether the communal hub is empty with no widget available. */
    open val isEmptyState: Flow<Boolean> = flowOf(false)

    /** Hide the popup message triggered by dismissing the CTA tile. */
    open fun onHidePopupAfterDismissCta() {}
    /** Called as the UI request to dismiss the any displaying popup */
    open fun onHidePopup() {}

    /** Called as the UI requests deleting a widget. */
    open fun onDeleteWidget(id: Int) {}
@@ -127,6 +127,9 @@ abstract class BaseCommunalViewModel(
    /** Called as the user cancels dragging a widget to reorder. */
    open fun onReorderWidgetCancel() {}

    /** Called as the user request to show the customize widget button. */
    open fun onShowCustomizeWidgetButton() {}

    /** Set the key of the currently selected item */
    fun setSelectedKey(key: String?) {
        _selectedKey.value = key
+27 −24
Original line number Diff line number Diff line
@@ -90,9 +90,8 @@ constructor(
            .distinctUntilChanged()
            .onEach { logger.d("isEmptyState: $it") }

    private val _isPopupOnDismissCtaShowing: MutableStateFlow<Boolean> = MutableStateFlow(false)
    override val isPopupOnDismissCtaShowing: Flow<Boolean> =
        _isPopupOnDismissCtaShowing.asStateFlow()
    private val _currentPopup: MutableStateFlow<PopupType?> = MutableStateFlow(null)
    override val currentPopup: Flow<PopupType?> = _currentPopup.asStateFlow()

    private val _isEnableWidgetDialogShowing: MutableStateFlow<Boolean> = MutableStateFlow(false)
    val isEnableWidgetDialogShowing: Flow<Boolean> = _isEnableWidgetDialogShowing.asStateFlow()
@@ -124,14 +123,16 @@ constructor(
    override fun onDismissCtaTile() {
        scope.launch {
            communalInteractor.dismissCtaTile()
            setPopupOnDismissCtaVisibility(true)
            schedulePopupHiding()
            setCurrentPopupType(PopupType.CtaTile)
        }
    }

    override fun onHidePopupAfterDismissCta() {
        cancelDelayedPopupHiding()
        setPopupOnDismissCtaVisibility(false)
    override fun onShowCustomizeWidgetButton() {
        setCurrentPopupType(PopupType.CustomizeWidgetButton)
    }

    override fun onHidePopup() {
        setCurrentPopupType(null)
    }

    override fun onOpenEnableWidgetDialog() {
@@ -168,26 +169,23 @@ constructor(
        _isEnableWorkProfileDialogShowing.value = isVisible
    }

    private fun setPopupOnDismissCtaVisibility(isVisible: Boolean) {
        _isPopupOnDismissCtaShowing.value = isVisible
    }

    private var delayedHidePopupJob: Job? = null
    private fun setCurrentPopupType(popupType: PopupType?) {
        _currentPopup.value = popupType
        delayedHideCurrentPopupJob?.cancel()

    private fun schedulePopupHiding() {
        cancelDelayedPopupHiding()
        delayedHidePopupJob =
        if (popupType != null) {
            delayedHideCurrentPopupJob =
                scope.launch {
                    delay(POPUP_AUTO_HIDE_TIMEOUT_MS)
                onHidePopupAfterDismissCta()
                    setCurrentPopupType(null)
                }
        } else {
            delayedHideCurrentPopupJob = null
        }

    private fun cancelDelayedPopupHiding() {
        delayedHidePopupJob?.cancel()
        delayedHidePopupJob = null
    }

    private var delayedHideCurrentPopupJob: Job? = null

    /** Whether we can transition to a new scene based on a user gesture. */
    fun canChangeScene(): Boolean {
        return !shadeInteractor.isAnyFullyExpanded.value
@@ -197,3 +195,8 @@ constructor(
        const val POPUP_AUTO_HIDE_TIMEOUT_MS = 12000L
    }
}

sealed class PopupType {
    object CtaTile : PopupType()
    object CustomizeWidgetButton : PopupType()
}