summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Ale Nijamkin <nijamkin@google.com> 2024-08-14 01:56:08 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-08-14 01:56:08 +0000
commitd3e206a85bba7c3cb0e15c8bac06b49829bc0dd0 (patch)
tree2c7bfead7e6861e0a13b09eea47ce0dbbffed2cf
parentcd6cccb57223f88b63677a110daef8792fa55b5d (diff)
parentc1b875b54c6406f03fefa8ea778933736585f151 (diff)
Merge "[flexiglass] QS scene view-model is a SysUiViewModel" into main
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt21
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneActionsViewModelTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt)98
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModelTest.kt126
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneActionsViewModel.kt88
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModel.kt (renamed from packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt)66
5 files changed, 266 insertions, 133 deletions
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 12edd049c0e1..9db8bf14e5e0 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -92,7 +92,8 @@ import com.android.systemui.notifications.ui.composable.NotificationStackCutoffG
import com.android.systemui.qs.footer.ui.compose.FooterActionsWithAnimatedVisibility
import com.android.systemui.qs.ui.composable.QuickSettings.SharedValues.MediaLandscapeTopOffset
import com.android.systemui.qs.ui.composable.QuickSettings.SharedValues.MediaOffset.InQS
-import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel
+import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneActionsViewModel
+import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneContentViewModel
import com.android.systemui.res.R
import com.android.systemui.scene.session.ui.composable.SaveableSession
import com.android.systemui.scene.shared.model.Scenes
@@ -120,8 +121,9 @@ class QuickSettingsScene
constructor(
private val shadeSession: SaveableSession,
private val notificationStackScrollView: Lazy<NotificationScrollView>,
- private val viewModel: QuickSettingsSceneViewModel,
private val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory,
+ private val actionsViewModelFactory: QuickSettingsSceneActionsViewModel.Factory,
+ private val contentViewModelFactory: QuickSettingsSceneContentViewModel.Factory,
private val tintedIconManagerFactory: TintedIconManager.Factory,
private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
private val statusBarIconController: StatusBarIconController,
@@ -130,8 +132,16 @@ constructor(
) : ComposableScene {
override val key = Scenes.QuickSettings
+ private val actionsViewModel: QuickSettingsSceneActionsViewModel by lazy {
+ actionsViewModelFactory.create()
+ }
+
override val destinationScenes: Flow<Map<UserAction, UserActionResult>> =
- viewModel.destinationScenes
+ actionsViewModel.actions
+
+ override suspend fun activate() {
+ actionsViewModel.activate()
+ }
@Composable
override fun SceneScope.Content(
@@ -139,7 +149,7 @@ constructor(
) {
QuickSettingsScene(
notificationStackScrollView = notificationStackScrollView.get(),
- viewModel = viewModel,
+ viewModelFactory = contentViewModelFactory,
notificationsPlaceholderViewModel =
rememberViewModel { notificationsPlaceholderViewModelFactory.create() },
createTintedIconManager = tintedIconManagerFactory::create,
@@ -156,7 +166,7 @@ constructor(
@Composable
private fun SceneScope.QuickSettingsScene(
notificationStackScrollView: NotificationScrollView,
- viewModel: QuickSettingsSceneViewModel,
+ viewModelFactory: QuickSettingsSceneContentViewModel.Factory,
notificationsPlaceholderViewModel: NotificationsPlaceholderViewModel,
createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager,
createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController,
@@ -168,6 +178,7 @@ private fun SceneScope.QuickSettingsScene(
) {
val cutoutLocation = LocalDisplayCutout.current.location
+ val viewModel = rememberViewModel { viewModelFactory.create() }
val brightnessMirrorViewModel = rememberViewModel {
viewModel.brightnessMirrorViewModelFactory.create()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneActionsViewModelTest.kt
index 036380853a71..f26a9db56450 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneActionsViewModelTest.kt
@@ -36,11 +36,7 @@ import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintA
import com.android.systemui.keyguard.domain.interactor.keyguardEnabledInteractor
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.kosmos.testScope
-import com.android.systemui.media.controls.data.repository.mediaFilterRepository
-import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor
-import com.android.systemui.media.controls.shared.model.MediaData
-import com.android.systemui.qs.FooterActionsController
-import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
+import com.android.systemui.lifecycle.activateIn
import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter
import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.sceneBackInteractor
@@ -49,41 +45,29 @@ import com.android.systemui.scene.domain.resolver.homeSceneFamilyResolver
import com.android.systemui.scene.domain.startable.sceneContainerStartable
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.settings.brightness.ui.viewmodel.brightnessMirrorViewModelFactory
-import com.android.systemui.shade.ui.viewmodel.shadeHeaderViewModelFactory
import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
@SmallTest
@RunWith(AndroidJUnit4::class)
@RunWithLooper
@EnableSceneContainer
-class QuickSettingsSceneViewModelTest : SysuiTestCase() {
+class QuickSettingsSceneActionsViewModelTest : SysuiTestCase() {
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val qsFlexiglassAdapter = FakeQSSceneAdapter({ mock() })
- private val footerActionsViewModel = mock<FooterActionsViewModel>()
- private val footerActionsViewModelFactory =
- mock<FooterActionsViewModel.Factory> {
- whenever(create(any())).thenReturn(footerActionsViewModel)
- }
- private val footerActionsController = mock<FooterActionsController>()
private val sceneInteractor = kosmos.sceneInteractor
private val sceneBackInteractor = kosmos.sceneBackInteractor
private val sceneContainerStartable = kosmos.sceneContainerStartable
- private lateinit var underTest: QuickSettingsSceneViewModel
+ private lateinit var underTest: QuickSettingsSceneActionsViewModel
@Before
fun setUp() {
@@ -91,22 +75,18 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
sceneContainerStartable.start()
underTest =
- QuickSettingsSceneViewModel(
- brightnessMirrorViewModelFactory = kosmos.brightnessMirrorViewModelFactory,
- shadeHeaderViewModelFactory = kosmos.shadeHeaderViewModelFactory,
+ QuickSettingsSceneActionsViewModel(
qsSceneAdapter = qsFlexiglassAdapter,
- footerActionsViewModelFactory = footerActionsViewModelFactory,
- footerActionsController = footerActionsController,
sceneBackInteractor = sceneBackInteractor,
- mediaCarouselInteractor = kosmos.mediaCarouselInteractor,
)
+ underTest.activateIn(testScope)
}
@Test
fun destinations_whenNotCustomizing_unlocked() =
testScope.runTest {
overrideResource(R.bool.config_use_split_notification_shade, false)
- val destinations by collectLastValue(underTest.destinationScenes)
+ val actions by collectLastValue(underTest.actions)
val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene)
qsFlexiglassAdapter.setCustomizing(false)
kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
@@ -116,7 +96,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
SuccessFingerprintAuthenticationStatus(0, true)
)
- assertThat(destinations)
+ assertThat(actions)
.isEqualTo(
mapOf(
Back to UserActionResult(Scenes.Shade),
@@ -135,7 +115,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
testScope.runTest {
overrideResource(R.bool.config_use_split_notification_shade, false)
qsFlexiglassAdapter.setCustomizing(false)
- val destinations by collectLastValue(underTest.destinationScenes)
+ val actions by collectLastValue(underTest.actions)
val currentScene by collectLastValue(sceneInteractor.currentScene)
val backScene by collectLastValue(sceneBackInteractor.backScene)
@@ -145,7 +125,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
assertThat(backScene).isEqualTo(Scenes.Lockscreen)
- assertThat(destinations)
+ assertThat(actions)
.isEqualTo(
mapOf(
Back to UserActionResult(Scenes.Lockscreen),
@@ -164,7 +144,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
testScope.runTest {
overrideResource(R.bool.config_use_split_notification_shade, false)
qsFlexiglassAdapter.setCustomizing(false)
- val destinations by collectLastValue(underTest.destinationScenes)
+ val actions by collectLastValue(underTest.actions)
val currentScene by collectLastValue(sceneInteractor.currentScene)
val backScene by collectLastValue(sceneBackInteractor.backScene)
@@ -176,7 +156,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
assertThat(currentScene).isEqualTo(Scenes.Gone)
assertThat(backScene).isNull()
- assertThat(destinations)
+ assertThat(actions)
.isEqualTo(
mapOf(
Back to UserActionResult(Scenes.Shade),
@@ -194,7 +174,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
fun destinations_whenNotCustomizing_authMethodSwipe_lockscreenNotDismissed() =
testScope.runTest {
overrideResource(R.bool.config_use_split_notification_shade, false)
- val destinations by collectLastValue(underTest.destinationScenes)
+ val actions by collectLastValue(underTest.actions)
val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene)
qsFlexiglassAdapter.setCustomizing(false)
kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true)
@@ -202,7 +182,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
AuthenticationMethodModel.None
)
- assertThat(destinations)
+ assertThat(actions)
.isEqualTo(
mapOf(
Back to UserActionResult(Scenes.Shade),
@@ -220,17 +200,17 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
fun destinations_whenCustomizing_noDestinations() =
testScope.runTest {
overrideResource(R.bool.config_use_split_notification_shade, false)
- val destinations by collectLastValue(underTest.destinationScenes)
+ val actions by collectLastValue(underTest.actions)
qsFlexiglassAdapter.setCustomizing(true)
- assertThat(destinations).isEmpty()
+ assertThat(actions).isEmpty()
}
@Test
fun destinations_whenNotCustomizing_inSplitShade_unlocked() =
testScope.runTest {
overrideResource(R.bool.config_use_split_notification_shade, true)
- val destinations by collectLastValue(underTest.destinationScenes)
+ val actions by collectLastValue(underTest.actions)
val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene)
qsFlexiglassAdapter.setCustomizing(false)
kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
@@ -240,7 +220,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
SuccessFingerprintAuthenticationStatus(0, true)
)
- assertThat(destinations)
+ assertThat(actions)
.isEqualTo(
mapOf(
Back to UserActionResult(Scenes.Shade),
@@ -258,49 +238,9 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
fun destinations_whenCustomizing_inSplitShade_noDestinations() =
testScope.runTest {
overrideResource(R.bool.config_use_split_notification_shade, true)
- val destinations by collectLastValue(underTest.destinationScenes)
+ val actions by collectLastValue(underTest.actions)
qsFlexiglassAdapter.setCustomizing(true)
- assertThat(destinations).isEmpty()
- }
-
- @Test
- fun gettingViewModelInitializesControllerOnlyOnce() {
- underTest.getFooterActionsViewModel(mock())
- underTest.getFooterActionsViewModel(mock())
-
- verify(footerActionsController, times(1)).init()
- }
-
- @Test
- fun addAndRemoveMedia_mediaVisibilityIsUpdated() =
- testScope.runTest {
- kosmos.fakeFeatureFlagsClassic.set(Flags.MEDIA_RETAIN_RECOMMENDATIONS, false)
- val isMediaVisible by collectLastValue(underTest.isMediaVisible)
- val userMedia = MediaData(active = true)
-
- assertThat(isMediaVisible).isFalse()
-
- kosmos.mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
-
- assertThat(isMediaVisible).isTrue()
-
- kosmos.mediaFilterRepository.removeSelectedUserMediaEntry(userMedia.instanceId)
-
- assertThat(isMediaVisible).isFalse()
- }
-
- @Test
- fun addInactiveMedia_mediaVisibilityIsUpdated() =
- testScope.runTest {
- kosmos.fakeFeatureFlagsClassic.set(Flags.MEDIA_RETAIN_RECOMMENDATIONS, false)
- val isMediaVisible by collectLastValue(underTest.isMediaVisible)
- val userMedia = MediaData(active = false)
-
- assertThat(isMediaVisible).isFalse()
-
- kosmos.mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
-
- assertThat(isMediaVisible).isTrue()
+ assertThat(actions).isEmpty()
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModelTest.kt
new file mode 100644
index 000000000000..956353845506
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModelTest.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.ui.viewmodel
+
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.flags.Flags
+import com.android.systemui.flags.fakeFeatureFlagsClassic
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.lifecycle.activateIn
+import com.android.systemui.media.controls.data.repository.mediaFilterRepository
+import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor
+import com.android.systemui.media.controls.shared.model.MediaData
+import com.android.systemui.qs.FooterActionsController
+import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
+import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter
+import com.android.systemui.scene.domain.startable.sceneContainerStartable
+import com.android.systemui.settings.brightness.ui.viewmodel.brightnessMirrorViewModelFactory
+import com.android.systemui.shade.ui.viewmodel.shadeHeaderViewModelFactory
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@RunWithLooper
+@EnableSceneContainer
+class QuickSettingsSceneContentViewModelTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val qsFlexiglassAdapter = FakeQSSceneAdapter({ mock() })
+ private val footerActionsViewModel = mock<FooterActionsViewModel>()
+ private val footerActionsViewModelFactory =
+ mock<FooterActionsViewModel.Factory> {
+ whenever(create(any())).thenReturn(footerActionsViewModel)
+ }
+ private val footerActionsController = mock<FooterActionsController>()
+
+ private val sceneContainerStartable = kosmos.sceneContainerStartable
+
+ private lateinit var underTest: QuickSettingsSceneContentViewModel
+
+ @Before
+ fun setUp() {
+ kosmos.fakeFeatureFlagsClassic.set(Flags.NEW_NETWORK_SLICE_UI, false)
+
+ sceneContainerStartable.start()
+ underTest =
+ QuickSettingsSceneContentViewModel(
+ brightnessMirrorViewModelFactory = kosmos.brightnessMirrorViewModelFactory,
+ shadeHeaderViewModelFactory = kosmos.shadeHeaderViewModelFactory,
+ qsSceneAdapter = qsFlexiglassAdapter,
+ footerActionsViewModelFactory = footerActionsViewModelFactory,
+ footerActionsController = footerActionsController,
+ mediaCarouselInteractor = kosmos.mediaCarouselInteractor,
+ )
+ underTest.activateIn(testScope)
+ }
+
+ @Test
+ fun gettingViewModelInitializesControllerOnlyOnce() {
+ underTest.getFooterActionsViewModel(mock())
+ underTest.getFooterActionsViewModel(mock())
+
+ verify(footerActionsController, times(1)).init()
+ }
+
+ @Test
+ fun addAndRemoveMedia_mediaVisibilityIsUpdated() =
+ testScope.runTest {
+ kosmos.fakeFeatureFlagsClassic.set(Flags.MEDIA_RETAIN_RECOMMENDATIONS, false)
+ val isMediaVisible by collectLastValue(underTest.isMediaVisible)
+ val userMedia = MediaData(active = true)
+
+ assertThat(isMediaVisible).isFalse()
+
+ kosmos.mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
+
+ assertThat(isMediaVisible).isTrue()
+
+ kosmos.mediaFilterRepository.removeSelectedUserMediaEntry(userMedia.instanceId)
+
+ assertThat(isMediaVisible).isFalse()
+ }
+
+ @Test
+ fun addInactiveMedia_mediaVisibilityIsUpdated() =
+ testScope.runTest {
+ kosmos.fakeFeatureFlagsClassic.set(Flags.MEDIA_RETAIN_RECOMMENDATIONS, false)
+ val isMediaVisible by collectLastValue(underTest.isMediaVisible)
+ val userMedia = MediaData(active = false)
+
+ assertThat(isMediaVisible).isFalse()
+
+ kosmos.mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
+
+ assertThat(isMediaVisible).isTrue()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneActionsViewModel.kt
new file mode 100644
index 000000000000..af55f5a9a968
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneActionsViewModel.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.ui.viewmodel
+
+import com.android.compose.animation.scene.Back
+import com.android.compose.animation.scene.Edge
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.SwipeDirection
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
+import com.android.systemui.qs.ui.adapter.QSSceneAdapter
+import com.android.systemui.scene.domain.interactor.SceneBackInteractor
+import com.android.systemui.scene.shared.model.SceneFamilies
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.ui.viewmodel.SceneActionsViewModel
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+
+/**
+ * Models the UI state needed to figure out which user actions can trigger navigation from the quick
+ * settings scene to other scenes.
+ *
+ * Different from [QuickSettingsSceneContentViewModel] that models UI state needed for rendering the
+ * content of the quick settings scene.
+ */
+class QuickSettingsSceneActionsViewModel
+@AssistedInject
+constructor(
+ private val qsSceneAdapter: QSSceneAdapter,
+ sceneBackInteractor: SceneBackInteractor,
+) : SceneActionsViewModel() {
+
+ private val backScene: Flow<SceneKey> =
+ sceneBackInteractor.backScene
+ .filter { it != Scenes.QuickSettings }
+ .map { it ?: Scenes.Shade }
+
+ override suspend fun hydrateActions(setActions: (Map<UserAction, UserActionResult>) -> Unit) {
+ combine(
+ qsSceneAdapter.isCustomizerShowing,
+ backScene,
+ ) { isCustomizing, backScene ->
+ buildMap<UserAction, UserActionResult> {
+ if (isCustomizing) {
+ // TODO(b/332749288) Empty map so there are no back handlers and back can
+ // close
+ // customizer
+
+ // TODO(b/330200163) Add an Up from Bottom to be able to collapse the shade
+ // while customizing
+ } else {
+ put(Back, UserActionResult(backScene))
+ put(Swipe(SwipeDirection.Up), UserActionResult(backScene))
+ put(
+ Swipe(fromSource = Edge.Bottom, direction = SwipeDirection.Up),
+ UserActionResult(SceneFamilies.Home),
+ )
+ }
+ }
+ }
+ .collectLatest { actions -> setActions(actions) }
+ }
+
+ @AssistedFactory
+ interface Factory {
+ fun create(): QuickSettingsSceneActionsViewModel
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModel.kt
index 7258882e9ffa..55b8f5f0ca98 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModel.kt
@@ -17,71 +17,34 @@
package com.android.systemui.qs.ui.viewmodel
import androidx.lifecycle.LifecycleOwner
-import com.android.compose.animation.scene.Back
-import com.android.compose.animation.scene.Edge
-import com.android.compose.animation.scene.SceneKey
-import com.android.compose.animation.scene.Swipe
-import com.android.compose.animation.scene.SwipeDirection
-import com.android.compose.animation.scene.UserAction
-import com.android.compose.animation.scene.UserActionResult
-import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.lifecycle.SysUiViewModel
import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor
import com.android.systemui.qs.FooterActionsController
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
import com.android.systemui.qs.ui.adapter.QSSceneAdapter
-import com.android.systemui.scene.domain.interactor.SceneBackInteractor
-import com.android.systemui.scene.shared.model.SceneFamilies
-import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.settings.brightness.ui.viewModel.BrightnessMirrorViewModel
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
import java.util.concurrent.atomic.AtomicBoolean
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.map
-/** Models UI state and handles user input for the quick settings scene. */
-@SysUISingleton
-class QuickSettingsSceneViewModel
-@Inject
+/**
+ * Models UI state needed for rendering the content of the quick settings scene.
+ *
+ * Different from [QuickSettingsSceneActionsViewModel] that models the UI state needed to figure out
+ * which user actions can trigger navigation to other scenes.
+ */
+class QuickSettingsSceneContentViewModel
+@AssistedInject
constructor(
val brightnessMirrorViewModelFactory: BrightnessMirrorViewModel.Factory,
val shadeHeaderViewModelFactory: ShadeHeaderViewModel.Factory,
val qsSceneAdapter: QSSceneAdapter,
private val footerActionsViewModelFactory: FooterActionsViewModel.Factory,
private val footerActionsController: FooterActionsController,
- sceneBackInteractor: SceneBackInteractor,
val mediaCarouselInteractor: MediaCarouselInteractor,
-) {
- private val backScene: Flow<SceneKey> =
- sceneBackInteractor.backScene
- .filter { it != Scenes.QuickSettings }
- .map { it ?: Scenes.Shade }
-
- val destinationScenes: Flow<Map<UserAction, UserActionResult>> =
- combine(
- qsSceneAdapter.isCustomizerShowing,
- backScene,
- ) { isCustomizing, backScene ->
- buildMap<UserAction, UserActionResult> {
- if (isCustomizing) {
- // TODO(b/332749288) Empty map so there are no back handlers and back can close
- // customizer
-
- // TODO(b/330200163) Add an Up from Bottom to be able to collapse the shade
- // while customizing
- } else {
- put(Back, UserActionResult(backScene))
- put(Swipe(SwipeDirection.Up), UserActionResult(backScene))
- put(
- Swipe(fromSource = Edge.Bottom, direction = SwipeDirection.Up),
- UserActionResult(SceneFamilies.Home),
- )
- }
- }
- }
+) : SysUiViewModel() {
val isMediaVisible: StateFlow<Boolean> = mediaCarouselInteractor.hasAnyMediaOrRecommendation
@@ -93,4 +56,9 @@ constructor(
}
return footerActionsViewModelFactory.create(lifecycleOwner)
}
+
+ @AssistedFactory
+ interface Factory {
+ fun create(): QuickSettingsSceneContentViewModel
+ }
}