Separate lock and home tab (2/2)
Separate the lock and home tab. This way, when swtiching tabs, we no
longer need to remove and create sections.
The major benefit is that there's no flash effect from removing/adding
sections.
Test: https://drive.google.com/file/d/1ZcOUVD5EXA0ZNIhY8mVsMmgBoakSpXwt/view?usp=sharing&resourcekey=0-qKSuCEB9G2gMRV4ltnncSA
Bug: 275724650
Change-Id: Icc5d85919005157cc27edfd7dda43d7436a274d2
diff --git a/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt b/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt
index cf80dc1..925e293 100644
--- a/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt
+++ b/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt
@@ -30,14 +30,6 @@
import kotlinx.coroutines.launch
object ClockCarouselViewBinder {
- /**
- * The binding is used by the view where there is an action executed from another view, e.g.
- * toggling show/hide of the view that the binder is holding.
- */
- interface Binding {
- fun show()
- fun hide()
- }
@JvmStatic
fun bind(
@@ -46,7 +38,7 @@
viewModel: ClockCarouselViewModel,
clockViewFactory: ClockViewFactory,
lifecycleOwner: LifecycleOwner,
- ): Binding {
+ ) {
val singleClockHostView =
singleClockView.requireViewById<FrameLayout>(R.id.single_clock_host_view)
lifecycleOwner.lifecycleScope.launch {
@@ -106,15 +98,5 @@
}
}
)
-
- return object : Binding {
- override fun show() {
- viewModel.showClockCarousel(true)
- }
-
- override fun hide() {
- viewModel.showClockCarousel(false)
- }
- }
}
}
diff --git a/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt b/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
index b5e7c18..dd4c968 100644
--- a/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
+++ b/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
@@ -66,51 +66,50 @@
val colorViewModel = injector.getWallpaperColorsViewModel()
val displayUtils = injector.getDisplayUtils(context)
ScreenPreviewBinder.bind(
- activity = activity,
- previewView = lockScreenView,
- viewModel =
- ScreenPreviewViewModel(
- previewUtils =
- PreviewUtils(
- context = context,
- authority =
- resources.getString(
- R.string.lock_screen_preview_provider_authority,
- ),
- ),
- wallpaperInfoProvider = {
- suspendCancellableCoroutine { continuation ->
- injector
- .getCurrentWallpaperInfoFactory(context)
- .createCurrentWallpaperInfos(
- { homeWallpaper, lockWallpaper, _ ->
- continuation.resume(
- homeWallpaper ?: lockWallpaper,
- null,
- )
- },
- /* forceRefresh= */ true,
- )
- }
- },
- onWallpaperColorChanged = { colors ->
- colorViewModel.setLockWallpaperColors(colors)
- },
- initialExtrasProvider = {
- Bundle().apply {
- // Hide the clock from the system UI rendered preview so we can
- // place the carousel on top of it.
- putBoolean(
- ClockPreviewConstants.KEY_HIDE_CLOCK,
- true,
+ activity = activity,
+ previewView = lockScreenView,
+ viewModel =
+ ScreenPreviewViewModel(
+ previewUtils =
+ PreviewUtils(
+ context = context,
+ authority =
+ resources.getString(
+ R.string.lock_screen_preview_provider_authority,
+ ),
+ ),
+ wallpaperInfoProvider = {
+ suspendCancellableCoroutine { continuation ->
+ injector
+ .getCurrentWallpaperInfoFactory(context)
+ .createCurrentWallpaperInfos(
+ { homeWallpaper, lockWallpaper, _ ->
+ continuation.resume(
+ homeWallpaper ?: lockWallpaper,
+ null,
+ )
+ },
+ /* forceRefresh= */ true,
)
- }
- },
- ),
- lifecycleOwner = this,
- offsetToStart = displayUtils.isSingleDisplayOrUnfoldedHorizontalHinge(activity),
- )
- .show()
+ }
+ },
+ onWallpaperColorChanged = { colors ->
+ colorViewModel.setLockWallpaperColors(colors)
+ },
+ initialExtrasProvider = {
+ Bundle().apply {
+ // Hide the clock from the system UI rendered preview so we can
+ // place the carousel on top of it.
+ putBoolean(
+ ClockPreviewConstants.KEY_HIDE_CLOCK,
+ true,
+ )
+ }
+ },
+ ),
+ lifecycleOwner = this,
+ offsetToStart = displayUtils.isSingleDisplayOrUnfoldedHorizontalHinge(activity),
+ )
ClockSettingsBinder.bind(
view,
diff --git a/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModel.kt b/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModel.kt
index 60a9e85..c01f56a 100644
--- a/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModel.kt
+++ b/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModel.kt
@@ -19,8 +19,6 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
@@ -44,14 +42,7 @@
val seedColor: Flow<Int?> = interactor.seedColor
- private val shouldShowCarousel = MutableStateFlow(false)
- val isCarouselVisible: Flow<Boolean> =
- combine(allClockIds.map { it.size > 1 }.distinctUntilChanged(), shouldShowCarousel) {
- hasMoreThanOneClock,
- shouldShowCarousel ->
- hasMoreThanOneClock && shouldShowCarousel
- }
- .distinctUntilChanged()
+ val isCarouselVisible: Flow<Boolean> = allClockIds.map { it.size > 1 }.distinctUntilChanged()
@OptIn(ExperimentalCoroutinesApi::class)
val selectedIndex: Flow<Int> =
@@ -69,14 +60,8 @@
.mapNotNull { it }
// Handle the case when there is only one clock in the carousel
- private val shouldShowSingleClock = MutableStateFlow(false)
val isSingleClockViewVisible: Flow<Boolean> =
- combine(allClockIds.map { it.size == 1 }.distinctUntilChanged(), shouldShowSingleClock) {
- hasOneClock,
- shouldShowSingleClock ->
- hasOneClock && shouldShowSingleClock
- }
- .distinctUntilChanged()
+ allClockIds.map { it.size == 1 }.distinctUntilChanged()
val clockId: Flow<String> =
allClockIds
@@ -87,11 +72,6 @@
interactor.setSelectedClock(clockId)
}
- fun showClockCarousel(shouldShow: Boolean) {
- shouldShowCarousel.value = shouldShow
- shouldShowSingleClock.value = shouldShow
- }
-
companion object {
const val CLOCKS_EVENT_UPDATE_DELAY_MILLIS: Long = 100
}
diff --git a/src/com/android/customization/picker/preview/ui/section/PreviewWithClockCarouselSectionController.kt b/src/com/android/customization/picker/preview/ui/section/PreviewWithClockCarouselSectionController.kt
index 0303b41..43fb85b 100644
--- a/src/com/android/customization/picker/preview/ui/section/PreviewWithClockCarouselSectionController.kt
+++ b/src/com/android/customization/picker/preview/ui/section/PreviewWithClockCarouselSectionController.kt
@@ -22,7 +22,6 @@
import android.view.View
import android.view.ViewGroup
import android.view.ViewStub
-import androidx.core.view.isVisible
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.android.customization.picker.clock.ui.binder.ClockCarouselViewBinder
@@ -46,7 +45,7 @@
class PreviewWithClockCarouselSectionController(
activity: Activity,
private val lifecycleOwner: LifecycleOwner,
- private val initialScreen: CustomizationSections.Screen,
+ private val screen: CustomizationSections.Screen,
wallpaperInfoFactory: CurrentWallpaperInfoFactory,
colorViewModel: WallpaperColorsViewModel,
displayUtils: DisplayUtils,
@@ -59,7 +58,7 @@
ScreenPreviewSectionController(
activity,
lifecycleOwner,
- initialScreen,
+ screen,
wallpaperInfoFactory,
colorViewModel,
displayUtils,
@@ -67,32 +66,31 @@
wallpaperInteractor,
) {
- private var clockCarouselBinding: ClockCarouselViewBinder.Binding? = null
private var clockColorAndSizeButton: View? = null
override val hideLockScreenClockPreview = true
override fun createView(context: Context): ScreenPreviewView {
val view = super.createView(context)
+ if (screen == CustomizationSections.Screen.LOCK_SCREEN) {
+ val clockColorAndSizeButtonStub: ViewStub =
+ view.requireViewById(R.id.clock_color_and_size_button)
+ clockColorAndSizeButtonStub.layoutResource = R.layout.clock_color_and_size_button
+ clockColorAndSizeButton = clockColorAndSizeButtonStub.inflate() as View
+ clockColorAndSizeButton?.setOnClickListener {
+ navigationController.navigateTo(ClockSettingsFragment())
+ }
- val clockColorAndSizeButtonStub: ViewStub =
- view.requireViewById(R.id.clock_color_and_size_button)
- clockColorAndSizeButtonStub.layoutResource = R.layout.clock_color_and_size_button
- clockColorAndSizeButton = clockColorAndSizeButtonStub.inflate() as View
- clockColorAndSizeButton?.setOnClickListener {
- navigationController.navigateTo(ClockSettingsFragment())
- }
+ val carouselViewStub: ViewStub = view.requireViewById(R.id.clock_carousel_view_stub)
+ carouselViewStub.layoutResource = R.layout.clock_carousel_view
+ val carouselView = carouselViewStub.inflate() as ClockCarouselView
- val carouselViewStub: ViewStub = view.requireViewById(R.id.clock_carousel_view_stub)
- carouselViewStub.layoutResource = R.layout.clock_carousel_view
- val carouselView = carouselViewStub.inflate() as ClockCarouselView
-
- // TODO (b/270716937) We should handle the single clock case in the clock carousel itself
- val singleClockViewStub: ViewStub = view.requireViewById(R.id.single_clock_view_stub)
- singleClockViewStub.layoutResource = R.layout.single_clock_view
- val singleClockView = singleClockViewStub.inflate() as ViewGroup
- lifecycleOwner.lifecycleScope.launch {
- clockCarouselBinding =
+ // TODO (b/270716937) We should handle the single clock case in the clock carousel
+ // itself
+ val singleClockViewStub: ViewStub = view.requireViewById(R.id.single_clock_view_stub)
+ singleClockViewStub.layoutResource = R.layout.single_clock_view
+ val singleClockView = singleClockViewStub.inflate() as ViewGroup
+ lifecycleOwner.lifecycleScope.launch {
ClockCarouselViewBinder.bind(
carouselView = carouselView,
singleClockView = singleClockView,
@@ -100,20 +98,9 @@
clockViewFactory = clockViewFactory,
lifecycleOwner = lifecycleOwner,
)
- onScreenSwitched(
- isOnLockScreen = initialScreen == CustomizationSections.Screen.LOCK_SCREEN
- )
+ }
}
- return view
- }
- override fun onScreenSwitched(isOnLockScreen: Boolean) {
- super.onScreenSwitched(isOnLockScreen)
- clockColorAndSizeButton?.isVisible = isOnLockScreen
- if (isOnLockScreen) {
- clockCarouselBinding?.show()
- } else {
- clockCarouselBinding?.hide()
- }
+ return view
}
}
diff --git a/tests/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModelTest.kt b/tests/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModelTest.kt
index 63f77bd..5bc7461 100644
--- a/tests/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModelTest.kt
+++ b/tests/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModelTest.kt
@@ -75,46 +75,22 @@
}
@Test
- fun setShouldShowCarousel() = runTest {
+ fun multipleClockCase() = runTest {
underTest = ClockCarouselViewModel(ClockPickerInteractor(repositoryWithMultipleClocks))
val observedIsCarouselVisible = collectLastValue(underTest.isCarouselVisible)
+ val observedIsSingleClockViewVisible = collectLastValue(underTest.isSingleClockViewVisible)
advanceTimeBy(ClockCarouselViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
- underTest.showClockCarousel(false)
- assertThat(observedIsCarouselVisible()).isFalse()
- underTest.showClockCarousel(true)
assertThat(observedIsCarouselVisible()).isTrue()
+ assertThat(observedIsSingleClockViewVisible()).isFalse()
}
@Test
- fun shouldNotShowCarouselWhenSingleClock() = runTest {
+ fun singleClockCase() = runTest {
underTest = ClockCarouselViewModel(ClockPickerInteractor(repositoryWithSingleClock))
val observedIsCarouselVisible = collectLastValue(underTest.isCarouselVisible)
- advanceTimeBy(ClockCarouselViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
- underTest.showClockCarousel(false)
- assertThat(observedIsCarouselVisible()).isFalse()
- underTest.showClockCarousel(true)
- assertThat(observedIsCarouselVisible()).isFalse()
- }
-
- @Test
- fun setShouldShowSingleClock() = runTest {
- underTest = ClockCarouselViewModel(ClockPickerInteractor(repositoryWithSingleClock))
val observedIsSingleClockViewVisible = collectLastValue(underTest.isSingleClockViewVisible)
advanceTimeBy(ClockCarouselViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
- underTest.showClockCarousel(false)
- assertThat(observedIsSingleClockViewVisible()).isFalse()
- underTest.showClockCarousel(true)
+ assertThat(observedIsCarouselVisible()).isFalse()
assertThat(observedIsSingleClockViewVisible()).isTrue()
}
-
- @Test
- fun shouldNotShowSingleClockWhenMultipleClocks() = runTest {
- underTest = ClockCarouselViewModel(ClockPickerInteractor(repositoryWithMultipleClocks))
- val observedIsSingleClockViewVisible = collectLastValue(underTest.isSingleClockViewVisible)
- advanceTimeBy(ClockCarouselViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
- underTest.showClockCarousel(false)
- assertThat(observedIsSingleClockViewVisible()).isFalse()
- underTest.showClockCarousel(true)
- assertThat(observedIsSingleClockViewVisible()).isFalse()
- }
}