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

Commit fa76527f authored by Catherine Liang's avatar Catherine Liang
Browse files

Fix dismiss dialog shows on dark mode apply (2/2)

Flag: com.android.systemui.shared.new_customization_picker_ui
Bug: 388730120
Test: manually verified by applying dark mode and color
Change-Id: Iefa318507fec4a5998c37ae235e44a5a310b6f36
parent 8a79ce3f
Loading
Loading
Loading
Loading
+25 −3
Original line number Diff line number Diff line
@@ -18,17 +18,26 @@ package com.android.customization.picker.mode.ui.viewmodel

import com.android.customization.module.logging.ThemesUserEventLogger
import com.android.customization.picker.mode.domain.interactor.DarkModeInteractor
import com.android.wallpaper.picker.customization.ui.viewmodel.ColorUpdateViewModel
import dagger.hilt.android.scopes.ViewModelScoped
import javax.inject.Inject
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.launch

@ViewModelScoped
class DarkModeViewModel
@Inject
constructor(private val interactor: DarkModeInteractor, private val logger: ThemesUserEventLogger) {
constructor(
    private val colorUpdateViewModel: ColorUpdateViewModel,
    private val interactor: DarkModeInteractor,
    private val logger: ThemesUserEventLogger,
) {
    private val isDarkMode = interactor.isDarkMode
    val isEnabled = interactor.isEnabled

@@ -54,9 +63,22 @@ constructor(private val interactor: DarkModeInteractor, private val logger: Them
        combine(overridingIsDarkMode, isDarkMode, isEnabled) { override, current, isEnabled ->
            if (override != null && override != current && isEnabled) {
                {
                    interactor.setIsDarkMode(override)
                    coroutineScope {
                        launch { interactor.setIsDarkMode(override) }
                        // Dark mode change also invokes a color update. Suspend until both dark
                        // mode and color are updated.
                        combine(
                                // Omit the first value which is emitted on subscribe.
                                isDarkMode.drop(1).take(1),
                                colorUpdateViewModel.systemColorsUpdatedNoReplay.take(1),
                                ::Pair,
                            )
                            .collect { (_, _) ->
                                return@collect
                            }
                        logger.logDarkThemeApplied(override)
                    }
                }
            } else null
        }

+12 −9
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import dagger.assisted.AssistedInject
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.android.scopes.ViewModelScoped
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -169,7 +170,8 @@ constructor(
                    null
                } else {
                    {
                        interactor.select(it)
                        coroutineScope {
                            launch { interactor.select(it) }
                            // Suspend until first color update
                            colorUpdateViewModel.systemColorsUpdatedNoReplay.take(1).collect {
                                return@collect
@@ -183,6 +185,7 @@ constructor(
                    }
                }
            }
        }

    fun resetPreview() {
        overridingColorOption.value = null
+30 −7
Original line number Diff line number Diff line
@@ -16,20 +16,27 @@

package com.android.customization.picker.mode.ui.viewmodel

import android.content.Context
import androidx.test.platform.app.InstrumentationRegistry
import com.android.customization.module.logging.TestThemesUserEventLogger
import com.android.customization.picker.mode.data.repository.DarkModeRepository
import com.android.customization.picker.mode.data.repository.DarkModeStateRepository
import com.android.customization.picker.mode.domain.interactor.DarkModeInteractor
import com.android.wallpaper.picker.customization.ui.viewmodel.ColorUpdateViewModel
import com.android.wallpaper.testing.FakePowerManager
import com.android.wallpaper.testing.FakeUiModeManager
import com.android.wallpaper.testing.collectLastValue
import com.google.common.truth.Truth.assertThat
import dagger.hilt.android.internal.lifecycle.RetainedLifecycleImpl
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import javax.inject.Inject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.setMain
import org.junit.Before
@@ -46,20 +53,26 @@ class DarkModeViewModelTest {

    @Inject lateinit var uiModeManager: FakeUiModeManager
    @Inject lateinit var powerManager: FakePowerManager
    @Inject lateinit var darkModeStateRepository: DarkModeStateRepository
    @Inject lateinit var darkModeRepository: DarkModeRepository
    @Inject lateinit var darkModeInteractor: DarkModeInteractor
    @Inject lateinit var logger: TestThemesUserEventLogger
    private lateinit var darkModeViewModel: DarkModeViewModel

    @Inject lateinit var testDispatcher: TestDispatcher
    @Inject lateinit var testScope: TestScope

    private lateinit var context: Context
    private lateinit var colorUpdateViewModel: ColorUpdateViewModel
    private lateinit var darkModeViewModel: DarkModeViewModel

    @Before
    fun setUp() {
        hiltRule.inject()
        Dispatchers.setMain(testDispatcher)

        darkModeViewModel = DarkModeViewModel(darkModeInteractor, logger)
        context = InstrumentationRegistry.getInstrumentation().targetContext
        colorUpdateViewModel =
            ColorUpdateViewModel(context, RetainedLifecycleImpl(), darkModeStateRepository)
        darkModeViewModel = DarkModeViewModel(colorUpdateViewModel, darkModeInteractor, logger)
    }

    @Test
@@ -141,10 +154,9 @@ class DarkModeViewModelTest {
            uiModeManager.setNightModeActivated(false)
            darkModeRepository.refreshIsDarkMode()
            val getToggleDarkMode = collectLastValue(darkModeViewModel.toggleDarkMode)
            val onApply = collectLastValue(darkModeViewModel.onApply)

            getToggleDarkMode()?.invoke()
            onApply()?.invoke()
            applyDarkMode()

            assertThat(logger.useDarkTheme).isTrue()
        }
@@ -156,12 +168,23 @@ class DarkModeViewModelTest {
            uiModeManager.setNightModeActivated(false)
            darkModeRepository.refreshIsDarkMode()
            val getToggleDarkMode = collectLastValue(darkModeViewModel.toggleDarkMode)
            val onApply = collectLastValue(darkModeViewModel.onApply)

            getToggleDarkMode()?.invoke()
            onApply()?.invoke()
            applyDarkMode()

            assertThat(uiModeManager.getIsNightModeActivated()).isTrue()
        }
    }

    /** Simulates a user applying the previewing dark mode, and the apply completes. */
    private fun TestScope.applyDarkMode() {
        val onApply = collectLastValue(darkModeViewModel.onApply)()
        testScope.launch { onApply?.invoke() }
        // Run coroutine launched in DarkModeViewModel#onApply
        runCurrent()
        // Simulate dark mode and color update config change
        colorUpdateViewModel.updateDarkModeAndColors()
        // Run coroutine launched in colorUpdateViewModel#updateColors
        runCurrent()
    }
}