summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Ioana Alexandru <aioana@google.com> 2023-11-17 17:40:28 +0100
committer Ioana Alexandru <aioana@google.com> 2023-11-22 13:53:36 +0100
commitd6c74b3a3231f96a2a62b03a48a470e9e4522268 (patch)
tree7d262063f1e7fd1ac954d88b660351b81861f413
parent7f3c67b18a946f59b06d4947881ed49447a7c51b (diff)
Make FooterViewModel children hold flows.
Instead of the parent view holding a flow of the child view, it makes more sense for the child view to hold a flow of the visibility instead. That way we're not triggering updates unnecessarily. The footer view already knows to ignore duplicate updates for fields, but if we can avoid triggering a downstream listener that's a small win for performance. Plus it avoids holding constant values in a flow unnecessarily. Bug: 293167744 Test: manual + FooterViewModelTest Flag: ACONFIG com.systemui.notifications_footer_refactor_flag DEVELOPMENT Change-Id: Ic512b2fbdeb1d99c4aeeab1500221ae17d3e1087
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterButtonViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterMessageViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt56
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt24
5 files changed, 58 insertions, 58 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt
index 0299114e0afc..e0eee96d8f0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt
@@ -34,34 +34,38 @@ object FooterViewBinder {
viewModel: FooterViewModel,
clearAllNotifications: View.OnClickListener,
): DisposableHandle {
- // Listen for changes when the view is attached.
+ // Bind the resource IDs
+ footer.setMessageString(viewModel.message.messageId)
+ footer.setMessageIcon(viewModel.message.iconId)
+ footer.setClearAllButtonText(viewModel.clearAllButton.labelId)
+ footer.setClearAllButtonDescription(viewModel.clearAllButton.accessibilityDescriptionId)
+
+ // Bind the click listeners
+ footer.setClearAllButtonClickListener(clearAllNotifications)
+
+ // Listen for visibility changes when the view is attached.
return footer.repeatWhenAttached {
lifecycleScope.launch {
- viewModel.clearAllButton.collect { button ->
- if (button.isVisible.isAnimating) {
+ viewModel.clearAllButton.isVisible.collect { isVisible ->
+ if (isVisible.isAnimating) {
footer.setClearAllButtonVisible(
- button.isVisible.value,
+ isVisible.value,
/* animate = */ true,
) { _ ->
- button.isVisible.stopAnimating()
+ isVisible.stopAnimating()
}
} else {
footer.setClearAllButtonVisible(
- button.isVisible.value,
+ isVisible.value,
/* animate = */ false,
)
}
- footer.setClearAllButtonText(button.labelId)
- footer.setClearAllButtonDescription(button.accessibilityDescriptionId)
- footer.setClearAllButtonClickListener(clearAllNotifications)
}
}
lifecycleScope.launch {
- viewModel.message.collect { message ->
- footer.setFooterLabelVisible(message.visible)
- footer.setMessageString(message.messageId)
- footer.setMessageIcon(message.iconId)
+ viewModel.message.isVisible.collect { visible ->
+ footer.setFooterLabelVisible(visible)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterButtonViewModel.kt
index ea5abeff7042..244555a3d73b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterButtonViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterButtonViewModel.kt
@@ -18,9 +18,10 @@ package com.android.systemui.statusbar.notification.footer.ui.viewmodel
import android.annotation.StringRes
import com.android.systemui.util.ui.AnimatedValue
+import kotlinx.coroutines.flow.Flow
data class FooterButtonViewModel(
@StringRes val labelId: Int,
@StringRes val accessibilityDescriptionId: Int,
- val isVisible: AnimatedValue<Boolean>,
+ val isVisible: Flow<AnimatedValue<Boolean>>,
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterMessageViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterMessageViewModel.kt
index bc912fb106f0..85cd397a3749 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterMessageViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterMessageViewModel.kt
@@ -18,10 +18,11 @@ package com.android.systemui.statusbar.notification.footer.ui.viewmodel
import android.annotation.DrawableRes
import android.annotation.StringRes
+import kotlinx.coroutines.flow.StateFlow
/** A ViewModel for the string message that can be shown in the footer. */
data class FooterMessageViewModel(
@StringRes val messageId: Int,
@DrawableRes val iconId: Int,
- val visible: Boolean,
+ val isVisible: StateFlow<Boolean>,
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt
index 721bea1086e6..e6b0abcfad65 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt
@@ -30,9 +30,7 @@ import dagger.Module
import dagger.Provides
import java.util.Optional
import javax.inject.Provider
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
/** ViewModel for [FooterView]. */
@@ -41,36 +39,32 @@ class FooterViewModel(
seenNotificationsInteractor: SeenNotificationsInteractor,
shadeInteractor: ShadeInteractor,
) {
- val clearAllButton: Flow<FooterButtonViewModel> =
- activeNotificationsInteractor.hasClearableNotifications
- .sample(
- combine(
- shadeInteractor.isShadeFullyExpanded,
- shadeInteractor.isShadeTouchable,
- ::Pair
- )
- .onStart { emit(Pair(false, false)) }
- ) { hasClearableNotifications, (isShadeFullyExpanded, animationsEnabled) ->
- val shouldAnimate = isShadeFullyExpanded && animationsEnabled
- AnimatableEvent(hasClearableNotifications, shouldAnimate)
- }
- .toAnimatedValueFlow()
- .map { visible ->
- FooterButtonViewModel(
- labelId = R.string.clear_all_notifications_text,
- accessibilityDescriptionId = R.string.accessibility_clear_all,
- isVisible = visible,
- )
- }
+ val clearAllButton: FooterButtonViewModel =
+ FooterButtonViewModel(
+ labelId = R.string.clear_all_notifications_text,
+ accessibilityDescriptionId = R.string.accessibility_clear_all,
+ isVisible =
+ activeNotificationsInteractor.hasClearableNotifications
+ .sample(
+ combine(
+ shadeInteractor.isShadeFullyExpanded,
+ shadeInteractor.isShadeTouchable,
+ ::Pair
+ )
+ .onStart { emit(Pair(false, false)) }
+ ) { hasClearableNotifications, (isShadeFullyExpanded, animationsEnabled) ->
+ val shouldAnimate = isShadeFullyExpanded && animationsEnabled
+ AnimatableEvent(hasClearableNotifications, shouldAnimate)
+ }
+ .toAnimatedValueFlow(),
+ )
- val message: Flow<FooterMessageViewModel> =
- seenNotificationsInteractor.hasFilteredOutSeenNotifications.map { hasFilteredOutNotifs ->
- FooterMessageViewModel(
- messageId = R.string.unlock_to_see_notif_text,
- iconId = R.drawable.ic_friction_lock_closed,
- visible = hasFilteredOutNotifs,
- )
- }
+ val message: FooterMessageViewModel =
+ FooterMessageViewModel(
+ messageId = R.string.unlock_to_see_notif_text,
+ iconId = R.drawable.ic_friction_lock_closed,
+ isVisible = seenNotificationsInteractor.hasFilteredOutSeenNotifications,
+ )
}
@Module
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
index 94dcf7a18514..0ba820f0972a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
@@ -116,27 +116,27 @@ class FooterViewModelTest : SysuiTestCase() {
@Test
fun testMessageVisible_whenFilteredNotifications() =
testComponent.runTest {
- val message by collectLastValue(footerViewModel.message)
+ val visible by collectLastValue(footerViewModel.message.isVisible)
activeNotificationListRepository.hasFilteredOutSeenNotifications.value = true
- assertThat(message?.visible).isTrue()
+ assertThat(visible).isTrue()
}
@Test
fun testMessageVisible_whenNoFilteredNotifications() =
testComponent.runTest {
- val message by collectLastValue(footerViewModel.message)
+ val visible by collectLastValue(footerViewModel.message.isVisible)
activeNotificationListRepository.hasFilteredOutSeenNotifications.value = false
- assertThat(message?.visible).isFalse()
+ assertThat(visible).isFalse()
}
@Test
fun testClearAllButtonVisible_whenHasClearableNotifs() =
testComponent.runTest {
- val button by collectLastValue(footerViewModel.clearAllButton)
+ val visible by collectLastValue(footerViewModel.clearAllButton.isVisible)
activeNotificationListRepository.notifStats.value =
NotifStats(
@@ -148,13 +148,13 @@ class FooterViewModelTest : SysuiTestCase() {
)
runCurrent()
- assertThat(button?.isVisible?.value).isTrue()
+ assertThat(visible?.value).isTrue()
}
@Test
fun testClearAllButtonVisible_whenHasNoClearableNotifs() =
testComponent.runTest {
- val button by collectLastValue(footerViewModel.clearAllButton)
+ val visible by collectLastValue(footerViewModel.clearAllButton.isVisible)
activeNotificationListRepository.notifStats.value =
NotifStats(
@@ -166,13 +166,13 @@ class FooterViewModelTest : SysuiTestCase() {
)
runCurrent()
- assertThat(button?.isVisible?.value).isFalse()
+ assertThat(visible?.value).isFalse()
}
@Test
fun testClearAllButtonAnimating_whenShadeExpandedAndTouchable() =
testComponent.runTest {
- val button by collectLastValue(footerViewModel.clearAllButton)
+ val visible by collectLastValue(footerViewModel.clearAllButton.isVisible)
runCurrent()
// WHEN shade is expanded
@@ -200,13 +200,13 @@ class FooterViewModelTest : SysuiTestCase() {
runCurrent()
// THEN button visibility should animate
- assertThat(button?.isVisible?.isAnimating).isTrue()
+ assertThat(visible?.isAnimating).isTrue()
}
@Test
fun testClearAllButtonAnimating_whenShadeNotExpanded() =
testComponent.runTest {
- val button by collectLastValue(footerViewModel.clearAllButton)
+ val visible by collectLastValue(footerViewModel.clearAllButton.isVisible)
runCurrent()
// WHEN shade is collapsed
@@ -234,6 +234,6 @@ class FooterViewModelTest : SysuiTestCase() {
runCurrent()
// THEN button visibility should not animate
- assertThat(button?.isVisible?.isAnimating).isFalse()
+ assertThat(visible?.isAnimating).isFalse()
}
}