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

Commit 6572c6b8 authored by Prince's avatar Prince
Browse files

Dismissing Customize Widgets pop up after time out

Test: atest CommunalViewModelTest
Flag: ACONFIG com.android.systemui.communal_hub TEAMFOOD
Fixes: 322540417
Change-Id: Icb72d3d7024dff0ba2a799082268a660c1a8c510
parent 1e5e9b7b
Loading
Loading
Loading
Loading
+21 −18
Original line number Original line 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.BaseCommunalViewModel
import com.android.systemui.communal.ui.viewmodel.CommunalEditModeViewModel
import com.android.systemui.communal.ui.viewmodel.CommunalEditModeViewModel
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
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.communal.widgets.WidgetConfigurator
import com.android.systemui.res.R
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
@@ -148,8 +149,7 @@ fun CommunalHub(
    onEditDone: (() -> Unit)? = null,
    onEditDone: (() -> Unit)? = null,
) {
) {
    val communalContent by viewModel.communalContent.collectAsState(initial = emptyList())
    val communalContent by viewModel.communalContent.collectAsState(initial = emptyList())
    val isPopupOnDismissCtaShowing by
    val currentPopup by viewModel.currentPopup.collectAsState(initial = null)
        viewModel.isPopupOnDismissCtaShowing.collectAsState(initial = false)
    var removeButtonCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
    var removeButtonCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
    var toolbarSize: IntSize? by remember { mutableStateOf(null) }
    var toolbarSize: IntSize? by remember { mutableStateOf(null) }
    var gridCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
    var gridCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
@@ -161,7 +161,6 @@ fun CommunalHub(
    val removeButtonEnabled by remember {
    val removeButtonEnabled by remember {
        derivedStateOf { selectedKey.value != null || reorderingWidgets }
        derivedStateOf { selectedKey.value != null || reorderingWidgets }
    }
    }
    var isButtonToEditWidgetsShowing by remember { mutableStateOf(false) }
    val isEmptyState by viewModel.isEmptyState.collectAsState(initial = false)
    val isEmptyState by viewModel.isEmptyState.collectAsState(initial = false)


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


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

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


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


@Composable
@Composable
private fun PopupOnDismissCtaTile(onHidePopupAfterDismissCta: () -> Unit) {
private fun PopupOnDismissCtaTile(onHidePopup: () -> Unit) {
    Popup(
    Popup(
        alignment = Alignment.TopCenter,
        alignment = Alignment.TopCenter,
        offset = IntOffset(0, 40),
        offset = IntOffset(0, 40),
        onDismissRequest = onHidePopupAfterDismissCta
        onDismissRequest = onHidePopup
    ) {
    ) {
        val colors = LocalAndroidColorScheme.current
        val colors = LocalAndroidColorScheme.current
        Row(
        Row(
+34 −7
Original line number Original line 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.shared.model.CommunalWidgetContentModel
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
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.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.coroutines.collectLastValue
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED
import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED
@@ -237,7 +238,7 @@ class CommunalViewModelTest : SysuiTestCase() {
            tutorialRepository.setTutorialSettingState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED)
            tutorialRepository.setTutorialSettingState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED)


            val communalContent by collectLastValue(underTest.communalContent)
            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?.size).isEqualTo(1)
            assertThat(communalContent?.get(0))
            assertThat(communalContent?.get(0))
@@ -247,11 +248,11 @@ class CommunalViewModelTest : SysuiTestCase() {


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


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


    @Test
    @Test
@@ -259,14 +260,40 @@ class CommunalViewModelTest : SysuiTestCase() {
        testScope.runTest {
        testScope.runTest {
            tutorialRepository.setTutorialSettingState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED)
            tutorialRepository.setTutorialSettingState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED)


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


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


            // dismiss the popup directly
            // dismiss the popup directly
            underTest.onHidePopupAfterDismissCta()
            underTest.onHidePopup()
            assertThat(isPopupOnDismissCtaShowing).isEqualTo(false)
            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
    @Test
+7 −4
Original line number Original line Diff line number Diff line
@@ -88,14 +88,14 @@ abstract class BaseCommunalViewModel(
    /** Whether in edit mode for the communal hub. */
    /** Whether in edit mode for the communal hub. */
    open val isEditMode = false
    open val isEditMode = false


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


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


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


    /** Called as the UI requests deleting a widget. */
    /** Called as the UI requests deleting a widget. */
    open fun onDeleteWidget(id: Int) {}
    open fun onDeleteWidget(id: Int) {}
@@ -127,6 +127,9 @@ abstract class BaseCommunalViewModel(
    /** Called as the user cancels dragging a widget to reorder. */
    /** Called as the user cancels dragging a widget to reorder. */
    open fun onReorderWidgetCancel() {}
    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 */
    /** Set the key of the currently selected item */
    fun setSelectedKey(key: String?) {
    fun setSelectedKey(key: String?) {
        _selectedKey.value = key
        _selectedKey.value = key
+27 −24
Original line number Original line Diff line number Diff line
@@ -90,9 +90,8 @@ constructor(
            .distinctUntilChanged()
            .distinctUntilChanged()
            .onEach { logger.d("isEmptyState: $it") }
            .onEach { logger.d("isEmptyState: $it") }


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


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


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

    override fun onHidePopup() {
        setCurrentPopupType(null)
    }
    }


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


    private fun setPopupOnDismissCtaVisibility(isVisible: Boolean) {
    private fun setCurrentPopupType(popupType: PopupType?) {
        _isPopupOnDismissCtaShowing.value = isVisible
        _currentPopup.value = popupType
    }
        delayedHideCurrentPopupJob?.cancel()

    private var delayedHidePopupJob: Job? = null


    private fun schedulePopupHiding() {
        if (popupType != null) {
        cancelDelayedPopupHiding()
            delayedHideCurrentPopupJob =
        delayedHidePopupJob =
                scope.launch {
                scope.launch {
                    delay(POPUP_AUTO_HIDE_TIMEOUT_MS)
                    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. */
    /** Whether we can transition to a new scene based on a user gesture. */
    fun canChangeScene(): Boolean {
    fun canChangeScene(): Boolean {
        return !shadeInteractor.isAnyFullyExpanded.value
        return !shadeInteractor.isAnyFullyExpanded.value
@@ -197,3 +195,8 @@ constructor(
        const val POPUP_AUTO_HIDE_TIMEOUT_MS = 12000L
        const val POPUP_AUTO_HIDE_TIMEOUT_MS = 12000L
    }
    }
}
}

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