[TP] Handle quick update from slider
When sliding, the color updates are frequent. We do not allow quick
updates to the settings. So we will handle the color changes at the UI
level.
1. Replace the clock preview on the lock screen with an overlay clock
view
2. Implements the frequent color updates to the view
Test: Manually tested that the view quickly respond to the slider
Bug: 270097085
Change-Id: Ib78058d0dabaeea8cdbe1eed4516ecf02c76b904
diff --git a/res/layout/fragment_clock_settings.xml b/res/layout/fragment_clock_settings.xml
index 088ec2a..5208222 100644
--- a/res/layout/fragment_clock_settings.xml
+++ b/res/layout/fragment_clock_settings.xml
@@ -41,6 +41,11 @@
android:layout_height="match_parent"
android:layout_gravity="center" />
+ <FrameLayout
+ android:id="@+id/clock_host_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center" />
</com.android.wallpaper.picker.DisplayAspectRatioFrameLayout>
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 6c72a5b..026e333 100644
--- a/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt
+++ b/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt
@@ -15,7 +15,6 @@
*/
package com.android.customization.picker.clock.ui.binder
-import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.view.isVisible
@@ -24,6 +23,7 @@
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.android.customization.picker.clock.ui.view.ClockCarouselView
+import com.android.customization.picker.clock.ui.view.ClockViewFactory
import com.android.customization.picker.clock.ui.viewmodel.ClockCarouselViewModel
import com.android.wallpaper.R
import kotlinx.coroutines.launch
@@ -43,7 +43,7 @@
carouselView: ClockCarouselView,
singleClockView: ViewGroup,
viewModel: ClockCarouselViewModel,
- clockViewFactory: (clockId: String) -> View,
+ clockViewFactory: ClockViewFactory,
lifecycleOwner: LifecycleOwner,
): Binding {
val singleClockHostView =
@@ -56,7 +56,7 @@
viewModel.allClockIds.collect { allClockIds ->
carouselView.setUpClockCarouselView(
clockIds = allClockIds,
- onGetClockPreview = clockViewFactory,
+ onGetClockPreview = { clockId -> clockViewFactory.getView(clockId) },
onClockSelected = { clockId -> viewModel.setSelectedClock(clockId) },
)
}
@@ -69,13 +69,17 @@
}
launch {
+ viewModel.seedColor.collect { clockViewFactory.updateColorForAllClocks(it) }
+ }
+
+ launch {
viewModel.isSingleClockViewVisible.collect { singleClockView.isVisible = it }
}
launch {
viewModel.clockId.collect { clockId ->
singleClockHostView.removeAllViews()
- val clockView = clockViewFactory(clockId)
+ val clockView = clockViewFactory.getView(clockId)
// The clock view might still be attached to an existing parent. Detach
// before adding to another parent.
(clockView.parent as? ViewGroup)?.removeView(clockView)
diff --git a/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt b/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
index 62d7217..b63fd27 100644
--- a/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
+++ b/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
@@ -16,6 +16,8 @@
package com.android.customization.picker.clock.ui.binder
import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
import android.widget.SeekBar
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
@@ -28,10 +30,12 @@
import com.android.customization.picker.clock.shared.ClockSize
import com.android.customization.picker.clock.ui.adapter.ClockSettingsTabAdapter
import com.android.customization.picker.clock.ui.view.ClockSizeRadioButtonGroup
+import com.android.customization.picker.clock.ui.view.ClockViewFactory
import com.android.customization.picker.clock.ui.viewmodel.ClockSettingsViewModel
import com.android.customization.picker.color.ui.adapter.ColorOptionAdapter
import com.android.customization.picker.common.ui.view.ItemSpacing
import com.android.wallpaper.R
+import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.launch
/** Bind between the clock settings screen and its view model. */
@@ -39,8 +43,11 @@
fun bind(
view: View,
viewModel: ClockSettingsViewModel,
+ clockViewFactory: ClockViewFactory,
lifecycleOwner: LifecycleOwner,
) {
+ val clockHostView: FrameLayout = view.requireViewById(R.id.clock_host_view)
+
val tabView: RecyclerView = view.requireViewById(R.id.tabs)
val tabAdapter = ClockSettingsTabAdapter()
tabView.adapter = tabAdapter
@@ -82,6 +89,25 @@
val colorOptionContainer = view.requireViewById<View>(R.id.color_picker_container)
lifecycleOwner.lifecycleScope.launch {
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+ launch {
+ viewModel.selectedClockId
+ .mapNotNull { it }
+ .collect { clockId ->
+ val clockView = clockViewFactory.getView(clockId)
+ (clockView.parent as? ViewGroup)?.removeView(clockView)
+ clockHostView.removeAllViews()
+ clockHostView.addView(clockView)
+ }
+ }
+
+ launch {
+ viewModel.seedColor.collect { seedColor ->
+ viewModel.selectedClockId.value?.let { selectedClockId ->
+ clockViewFactory.updateColor(selectedClockId, seedColor)
+ }
+ }
+ }
+
launch { viewModel.tabs.collect { tabAdapter.setItems(it) } }
launch {
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 9b6d737..ef1a5ef 100644
--- a/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
+++ b/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
@@ -24,6 +24,7 @@
import androidx.lifecycle.get
import com.android.customization.module.ThemePickerInjector
import com.android.customization.picker.clock.ui.binder.ClockSettingsBinder
+import com.android.systemui.shared.clocks.shared.model.ClockPreviewConstants
import com.android.wallpaper.R
import com.android.wallpaper.module.InjectorProvider
import com.android.wallpaper.picker.AppbarFragment
@@ -95,6 +96,16 @@
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.isOnWallpaperDisplay(activity),
@@ -111,6 +122,7 @@
),
)
.get(),
+ injector.getClockViewFactory(activity),
this@ClockSettingsFragment,
)
diff --git a/src/com/android/customization/picker/clock/ui/view/ClockViewFactory.kt b/src/com/android/customization/picker/clock/ui/view/ClockViewFactory.kt
index 488dd08..59b3a71 100644
--- a/src/com/android/customization/picker/clock/ui/view/ClockViewFactory.kt
+++ b/src/com/android/customization/picker/clock/ui/view/ClockViewFactory.kt
@@ -17,6 +17,7 @@
import android.app.Activity
import android.view.View
+import androidx.annotation.ColorInt
import com.android.systemui.plugins.ClockController
import com.android.systemui.shared.clocks.ClockRegistry
import com.android.wallpaper.R
@@ -32,6 +33,16 @@
return (clockControllers[clockId] ?: initClockController(clockId)).largeClock.view
}
+ fun updateColorForAllClocks(@ColorInt seedColor: Int?) {
+ clockControllers.values.forEach { it.events.onSeedColorChanged(seedColor = seedColor) }
+ }
+
+ fun updateColor(clockId: String, @ColorInt seedColor: Int?) {
+ return (clockControllers[clockId] ?: initClockController(clockId))
+ .events
+ .onSeedColorChanged(seedColor)
+ }
+
private fun initClockController(clockId: String): ClockController {
val controller =
registry.createExampleClock(clockId).also { it?.initialize(activity.resources, 0f, 0f) }
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 8fe9dca..60a9e85 100644
--- a/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModel.kt
+++ b/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModel.kt
@@ -42,6 +42,8 @@
allClocks.map { it.clockId }
}
+ val seedColor: Flow<Int?> = interactor.seedColor
+
private val shouldShowCarousel = MutableStateFlow(false)
val isCarouselVisible: Flow<Boolean> =
combine(allClockIds.map { it.size > 1 }.distinctUntilChanged(), shouldShowCarousel) {
diff --git a/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt b/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt
index 06fd2af..21d39f4 100644
--- a/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt
+++ b/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt
@@ -57,6 +57,11 @@
SIZE,
}
+ val selectedClockId: StateFlow<String?> =
+ clockPickerInteractor.selectedClockId
+ .distinctUntilChanged()
+ .stateIn(viewModelScope, SharingStarted.Eagerly, null)
+
val selectedColor: StateFlow<Int?> =
clockPickerInteractor.selectedColor.stateIn(viewModelScope, SharingStarted.Eagerly, null)
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 0b197b4..700439b 100644
--- a/src/com/android/customization/picker/preview/ui/section/PreviewWithClockCarouselSectionController.kt
+++ b/src/com/android/customization/picker/preview/ui/section/PreviewWithClockCarouselSectionController.kt
@@ -79,7 +79,7 @@
carouselView = carouselView,
singleClockView = singleClockView,
viewModel = clockCarouselViewModel,
- clockViewFactory = { clockId -> clockViewFactory.getView(clockId) },
+ clockViewFactory = clockViewFactory,
lifecycleOwner = lifecycleOwner,
)
onScreenSwitched(