Add step slider for presets
Add a step slider for clock presets. This is only handling showing and
hiding the slider when choosing different clock styles.
Test: Maually tested. See bug.
Bug: 395647577
Flag: com.android.systemui.shared.new_customization_picker_ui
Change-Id: I47753873a13c1dddfaf4bd2d4b367a2f91dbd917
diff --git a/res/layout/floating_sheet_clock_style_content.xml b/res/layout/floating_sheet_clock_style_content.xml
index 2dc9b33..259f376 100644
--- a/res/layout/floating_sheet_clock_style_content.xml
+++ b/res/layout/floating_sheet_clock_style_content.xml
@@ -13,33 +13,56 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:orientation="vertical"
android:paddingVertical="@dimen/floating_sheet_content_vertical_padding"
android:clipToPadding="false"
android:clipChildren="false">
- <!--
- This is an invisible placeholder put in place so that the parent keeps its height
- stable as the RecyclerView updates from 0 items to N items. Keeping it stable allows
- the layout logic to keep the size of the preview container stable as well, which
- bodes well for setting up the SurfaceView for remote rendering without changing its
- size after the content is loaded into the RecyclerView.
-
- It's critical for any TextViews inside the included layout to have text.
- -->
- <include
- layout="@layout/clock_style_option"
- android:layout_width="@dimen/floating_sheet_clock_style_option_size"
- android:layout_height="@dimen/floating_sheet_clock_style_option_size"
- android:visibility="invisible" />
-
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/clock_style_list"
+ <FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:clipChildren="false"
- android:clipToPadding="false"/>
-</FrameLayout>
+ android:clipToPadding="false"
+ android:clipChildren="false">
+
+ <!--
+ This is an invisible placeholder put in place so that the parent keeps its height
+ stable as the RecyclerView updates from 0 items to N items. Keeping it stable allows
+ the layout logic to keep the size of the preview container stable as well, which
+ bodes well for setting up the SurfaceView for remote rendering without changing its
+ size after the content is loaded into the RecyclerView.
+
+ It's critical for any TextViews inside the included layout to have text.
+ -->
+ <include
+ layout="@layout/clock_style_option"
+ android:layout_width="@dimen/floating_sheet_clock_style_option_size"
+ android:layout_height="@dimen/floating_sheet_clock_style_option_size"
+ android:visibility="invisible" />
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/clock_style_list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false"/>
+ </FrameLayout>
+
+ <com.google.android.material.slider.Slider
+ android:id="@+id/clock_axis_preset_slider"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/accessibility_min_height"
+ android:layout_marginTop="@dimen/clock_axis_control_slider_row_margin_vertical"
+ android:valueFrom="0.0"
+ android:valueTo="100.0"
+ android:stepSize="10.0"
+ app:trackHeight="@dimen/slider_track_height"
+ app:thumbHeight="@dimen/slider_thumb_height"
+ app:labelBehavior="gone"
+ android:theme="@style/Theme.Material3.DynamicColors.DayNight" />
+</LinearLayout>
+
diff --git a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
index 9342ab5..e810c8a 100644
--- a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
+++ b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
@@ -22,6 +22,7 @@
import androidx.annotation.IntRange
import com.android.customization.picker.clock.shared.ClockSize
import com.android.customization.picker.clock.shared.model.ClockMetadataModel
+import com.android.systemui.plugins.clocks.AxisPresetConfig
import com.android.systemui.plugins.clocks.ClockAxisStyle
import com.android.systemui.plugins.clocks.ClockFontAxis
import com.android.systemui.plugins.clocks.ClockId
@@ -74,6 +75,7 @@
thumbnail = clockConfig.thumbnail,
isReactiveToTone = clockConfig.isReactiveToTone,
fontAxes = clockConfig.axes,
+ axisPresetConfig = clockConfig.presetConfig,
)
} else {
null
@@ -120,6 +122,7 @@
thumbnail = it.thumbnail,
isReactiveToTone = it.isReactiveToTone,
fontAxes = it.axes,
+ axisPresetConfig = it.presetConfig,
selectedColorId = metadata?.getSelectedColorId(),
colorTone =
metadata?.getColorTone()
@@ -225,6 +228,7 @@
thumbnail: Drawable,
isReactiveToTone: Boolean,
fontAxes: List<ClockFontAxis>,
+ axisPresetConfig: AxisPresetConfig?,
selectedColorId: String? = null,
@IntRange(from = 0, to = 100) colorTone: Int = 0,
@ColorInt seedColor: Int? = null,
@@ -236,6 +240,7 @@
thumbnail = thumbnail,
isReactiveToTone = isReactiveToTone,
fontAxes = fontAxes,
+ axisPresetConfig = axisPresetConfig,
selectedColorId = selectedColorId,
colorToneProgress = colorTone,
seedColor = seedColor,
diff --git a/src/com/android/customization/picker/clock/shared/model/ClockMetadataModel.kt b/src/com/android/customization/picker/clock/shared/model/ClockMetadataModel.kt
index 8414960..a839ffe 100644
--- a/src/com/android/customization/picker/clock/shared/model/ClockMetadataModel.kt
+++ b/src/com/android/customization/picker/clock/shared/model/ClockMetadataModel.kt
@@ -20,6 +20,7 @@
import android.graphics.drawable.Drawable
import androidx.annotation.ColorInt
import androidx.annotation.IntRange
+import com.android.systemui.plugins.clocks.AxisPresetConfig
import com.android.systemui.plugins.clocks.ClockFontAxis
/** Model for clock metadata. */
@@ -30,6 +31,7 @@
val thumbnail: Drawable,
val isReactiveToTone: Boolean,
val fontAxes: List<ClockFontAxis>,
+ val axisPresetConfig: AxisPresetConfig?, // Null indicates the preset list should be disabled.
val selectedColorId: String?,
@IntRange(from = 0, to = 100) val colorToneProgress: Int,
@ColorInt val seedColor: Int?,
diff --git a/src/com/android/wallpaper/customization/ui/binder/ClockFloatingSheetBinder.kt b/src/com/android/wallpaper/customization/ui/binder/ClockFloatingSheetBinder.kt
index c08bafa..d141f30 100644
--- a/src/com/android/wallpaper/customization/ui/binder/ClockFloatingSheetBinder.kt
+++ b/src/com/android/wallpaper/customization/ui/binder/ClockFloatingSheetBinder.kt
@@ -85,7 +85,7 @@
val appContext = view.context.applicationContext
val isFloatingSheetActive = { optionsViewModel.selectedOption.value == CLOCK }
- val tabs = view.requireViewById<FloatingToolbar>(R.id.floating_toolbar)
+ val tabs: FloatingToolbar = view.requireViewById(R.id.floating_toolbar)
val tabContainer =
tabs.findViewById<ViewGroup>(com.android.wallpaper.R.id.floating_toolbar_tab_container)
ColorUpdateBinder.bind(
@@ -103,8 +103,8 @@
)
.also { tabs.setAdapter(it) }
- val floatingSheetContainer =
- view.requireViewById<ViewGroup>(R.id.floating_sheet_content_container)
+ val floatingSheetContainer: ViewGroup =
+ view.requireViewById(R.id.floating_sheet_content_container)
ColorUpdateBinder.bind(
setColor = { color ->
DrawableCompat.setTint(
@@ -118,7 +118,7 @@
)
// Clock style
- val clockStyleContent = view.requireViewById<View>(R.id.clock_floating_sheet_style_content)
+ val clockStyleContent: View = view.requireViewById(R.id.clock_floating_sheet_style_content)
val isClockStyleActive = {
isFloatingSheetActive() && viewModel.selectedTab.value == Tab.STYLE
}
@@ -128,13 +128,14 @@
shouldAnimateColor = isClockStyleActive,
lifecycleOwner = lifecycleOwner,
)
- val clockStyleList =
- view.requireViewById<RecyclerView>(R.id.clock_style_list).apply {
- initStyleList(appContext, clockStyleAdapter)
- }
+ val clockStyleList: RecyclerView = view.requireViewById(R.id.clock_style_list)
+ clockStyleList.initStyleList(appContext, clockStyleAdapter)
+ val axisPresetSlider: Slider =
+ clockStyleContent.requireViewById(R.id.clock_axis_preset_slider)
// Clock color
- val clockColorContent = view.requireViewById<View>(R.id.clock_floating_sheet_color_content)
+ val clockColorContent: View = view.requireViewById(R.id.clock_floating_sheet_color_content)
+
val clockColorAdapter =
createClockColorOptionItemAdapter(
uiMode = view.resources.configuration.uiMode,
@@ -142,21 +143,19 @@
shouldAnimateColor = isFloatingSheetActive,
lifecycleOwner = lifecycleOwner,
)
- val clockColorList =
- view.requireViewById<RecyclerView>(R.id.clock_color_list).apply {
- adapter = clockColorAdapter
- layoutManager =
- LinearLayoutManager(appContext, LinearLayoutManager.HORIZONTAL, false)
- }
- val clockColorSlider: Slider =
- view.requireViewById<Slider>(R.id.clock_color_slider).also {
- SliderColorBinder.bind(
- slider = it,
- colorUpdateViewModel = colorUpdateViewModel,
- shouldAnimateColor = isFloatingSheetActive,
- lifecycleOwner = lifecycleOwner,
- )
- }
+ val clockColorList: RecyclerView = view.requireViewById(R.id.clock_color_list)
+ clockColorList.adapter = clockColorAdapter
+ clockColorList.layoutManager =
+ LinearLayoutManager(appContext, LinearLayoutManager.HORIZONTAL, false)
+
+ val clockColorSlider: Slider = view.requireViewById(R.id.clock_color_slider)
+ SliderColorBinder.bind(
+ slider = clockColorSlider,
+ colorUpdateViewModel = colorUpdateViewModel,
+ shouldAnimateColor = isFloatingSheetActive,
+ lifecycleOwner = lifecycleOwner,
+ )
+
clockColorSlider.apply {
valueFrom = ClockMetadataModel.MIN_COLOR_TONE_PROGRESS.toFloat()
valueTo = ClockMetadataModel.MAX_COLOR_TONE_PROGRESS.toFloat()
@@ -192,9 +191,9 @@
)
// Clock size
- val clockSizeContent = view.requireViewById<View>(R.id.clock_floating_sheet_size_content)
- val clockSizeSwitch =
- clockSizeContent.requireViewById<MaterialSwitch>(R.id.clock_style_clock_size_switch)
+ val clockSizeContent: View = view.requireViewById(R.id.clock_floating_sheet_size_content)
+ val clockSizeSwitch: MaterialSwitch =
+ clockSizeContent.requireViewById(R.id.clock_style_clock_size_switch)
ColorUpdateBinder.bind(
setColor = { color ->
clockSizeContent
@@ -221,11 +220,14 @@
override fun onGlobalLayout() {
if (
clockStyleContent.height != 0 &&
+ axisPresetSlider.height != 0 &&
+ _clockFloatingSheetHeights.value.axisPresetSliderHeight == null &&
_clockFloatingSheetHeights.value.clockStyleContentHeight == null
) {
_clockFloatingSheetHeights.value =
_clockFloatingSheetHeights.value.copy(
- clockStyleContentHeight = clockStyleContent.height
+ clockStyleContentHeight = clockStyleContent.height,
+ axisPresetSliderHeight = axisPresetSlider.height,
)
clockStyleContent.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
@@ -268,60 +270,82 @@
)
lifecycleOwner.lifecycleScope.launch {
- var currentContent: View = clockStyleContent
+ var currentTab: Tab = Tab.STYLE
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
launch { viewModel.tabs.collect { tabAdapter.submitList(it) } }
launch {
- combine(clockFloatingSheetHeights, viewModel.selectedTab, ::Pair).collect {
- (heights, selectedTab) ->
- val (
- clockStyleContentHeight,
- clockColorContentHeight,
- clockSizeContentHeight) =
- heights
- clockStyleContentHeight ?: return@collect
- clockColorContentHeight ?: return@collect
- clockSizeContentHeight ?: return@collect
+ combine(
+ clockFloatingSheetHeights,
+ viewModel.selectedTab,
+ viewModel.shouldShowPresetSlider,
+ ::Triple,
+ )
+ .collect { (heights, selectedTab, shouldShowPresetSlider) ->
+ val (
+ clockStyleContentHeight,
+ clockColorContentHeight,
+ clockSizeContentHeight,
+ axisPresetSliderHeight) =
+ heights
+ clockStyleContentHeight ?: return@collect
+ clockColorContentHeight ?: return@collect
+ clockSizeContentHeight ?: return@collect
+ axisPresetSliderHeight ?: return@collect
- val fromHeight = floatingSheetContainer.height
- val toHeight =
- when (selectedTab) {
- Tab.STYLE -> clockStyleContentHeight
- Tab.COLOR -> clockColorContentHeight
- Tab.SIZE -> clockSizeContentHeight
- }
- // Start to animate the content height
- ValueAnimator.ofInt(fromHeight, toHeight)
- .apply {
- addUpdateListener { valueAnimator ->
- val value = valueAnimator.animatedValue as Int
- floatingSheetContainer.layoutParams =
- floatingSheetContainer.layoutParams.apply { height = value }
- currentContent.alpha = getAlpha(fromHeight, toHeight, value)
+ val fromHeight = floatingSheetContainer.height
+ val toHeight =
+ when (selectedTab) {
+ Tab.STYLE ->
+ if (shouldShowPresetSlider) clockStyleContentHeight
+ else clockStyleContentHeight - axisPresetSliderHeight
+ Tab.COLOR -> clockColorContentHeight
+ Tab.SIZE -> clockSizeContentHeight
}
- duration = ANIMATION_DURATION
- addListener(
- object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator) {
- clockStyleContent.isVisible = selectedTab == Tab.STYLE
- clockStyleContent.alpha = 1f
- clockColorContent.isVisible = selectedTab == Tab.COLOR
- clockColorContent.alpha = 1f
- clockSizeContent.isVisible = selectedTab == Tab.SIZE
- clockSizeContent.alpha = 1f
- currentContent =
- when (selectedTab) {
- Tab.STYLE -> clockStyleContent
- Tab.COLOR -> clockColorContent
- Tab.SIZE -> clockSizeContent
- }
+ val currentContent: View =
+ when (currentTab) {
+ Tab.STYLE -> clockStyleContent
+ Tab.COLOR -> clockColorContent
+ Tab.SIZE -> clockSizeContent
+ }
+ val shouldCurrentContentFadeOut = currentTab != selectedTab
+ // Start to animate the content height
+ ValueAnimator.ofInt(fromHeight, toHeight)
+ .apply {
+ addUpdateListener { valueAnimator ->
+ val value = valueAnimator.animatedValue as Int
+ floatingSheetContainer.layoutParams =
+ floatingSheetContainer.layoutParams.apply {
+ height = value
+ }
+ if (shouldCurrentContentFadeOut) {
+ currentContent.alpha =
+ getAlpha(fromHeight, toHeight, value)
}
}
- )
- }
- .start()
- }
+ duration = ANIMATION_DURATION
+ addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ clockStyleContent.isVisible =
+ selectedTab == Tab.STYLE
+ clockStyleContent.alpha = 1f
+ clockColorContent.isVisible =
+ selectedTab == Tab.COLOR
+ clockColorContent.alpha = 1f
+ clockSizeContent.isVisible = selectedTab == Tab.SIZE
+ clockSizeContent.alpha = 1f
+ }
+ }
+ )
+ }
+ .start()
+ currentTab = selectedTab
+ }
+ }
+
+ launch {
+ viewModel.shouldShowPresetSlider.collect { axisPresetSlider.isVisible = it }
}
launch {
@@ -440,10 +464,8 @@
layoutResourceId = R.layout.color_option2,
lifecycleOwner = lifecycleOwner,
bindPayload = { itemView: View, colorIcon: ColorOptionIconViewModel ->
- val colorOptionIconView =
- itemView.requireViewById<ColorOptionIconView2>(
- com.android.wallpaper.R.id.background
- )
+ val colorOptionIconView: ColorOptionIconView2 =
+ itemView.requireViewById(com.android.wallpaper.R.id.background)
val night = uiMode and UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES
val binding =
ColorOptionIconBinder2.bind(
diff --git a/src/com/android/wallpaper/customization/ui/viewmodel/ClockFloatingSheetHeightsViewModel.kt b/src/com/android/wallpaper/customization/ui/viewmodel/ClockFloatingSheetHeightsViewModel.kt
index 42ed420..fcfec5f 100644
--- a/src/com/android/wallpaper/customization/ui/viewmodel/ClockFloatingSheetHeightsViewModel.kt
+++ b/src/com/android/wallpaper/customization/ui/viewmodel/ClockFloatingSheetHeightsViewModel.kt
@@ -20,4 +20,5 @@
val clockStyleContentHeight: Int? = null,
val clockColorContentHeight: Int? = null,
val clockSizeContentHeight: Int? = null,
+ val axisPresetSliderHeight: Int? = null,
)
diff --git a/src/com/android/wallpaper/customization/ui/viewmodel/ClockPickerViewModel.kt b/src/com/android/wallpaper/customization/ui/viewmodel/ClockPickerViewModel.kt
index 5ab54fd..cd2183a 100644
--- a/src/com/android/wallpaper/customization/ui/viewmodel/ClockPickerViewModel.kt
+++ b/src/com/android/wallpaper/customization/ui/viewmodel/ClockPickerViewModel.kt
@@ -156,7 +156,7 @@
.mapLatest { allClocks ->
// Delay to avoid the case that the full list of clocks is not initiated.
delay(CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
- val allClockMap = allClocks.groupBy { it.fontAxes.isNotEmpty() }
+ val allClockMap = allClocks.groupBy { it.axisPresetConfig != null }
buildList {
allClockMap[true]?.map { add(it.toOption(resources)) }
allClockMap[false]?.map { add(it.toOption(resources)) }
@@ -168,6 +168,8 @@
.flowOn(backgroundDispatcher.limitedParallelism(1))
.stateIn(viewModelScope, SharingStarted.Eagerly, emptyList())
+ val shouldShowPresetSlider: Flow<Boolean> = previewingClock.map { it.axisPresetConfig != null }
+
private suspend fun ClockMetadataModel.toOption(
resources: Resources
): OptionItemViewModel2<ClockStyleModel> {
diff --git a/tests/robotests/src/com/android/customization/picker/clock/data/repository/FakeClockPickerRepository.kt b/tests/robotests/src/com/android/customization/picker/clock/data/repository/FakeClockPickerRepository.kt
index fd2c801..83f49d6 100644
--- a/tests/robotests/src/com/android/customization/picker/clock/data/repository/FakeClockPickerRepository.kt
+++ b/tests/robotests/src/com/android/customization/picker/clock/data/repository/FakeClockPickerRepository.kt
@@ -61,6 +61,7 @@
thumbnail = ColorDrawable(0),
isReactiveToTone = selectedClock.isReactiveToTone,
fontAxes = fontAxes,
+ axisPresetConfig = null,
selectedColorId = selectedColor,
colorToneProgress = colorTone,
seedColor = seedColor,
@@ -121,6 +122,7 @@
true,
listOf(buildFakeAxis(0)),
null,
+ null,
50,
null,
),
@@ -132,6 +134,7 @@
true,
listOf(buildFakeAxis(1)),
null,
+ null,
50,
null,
),
@@ -143,6 +146,7 @@
true,
listOf(buildFakeAxis(2)),
null,
+ null,
50,
null,
),
@@ -154,6 +158,7 @@
false,
listOf(buildFakeAxis(3)),
null,
+ null,
50,
null,
),
diff --git a/tests/robotests/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModelTest.kt b/tests/robotests/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModelTest.kt
index 0386c85..f8e6a94 100644
--- a/tests/robotests/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModelTest.kt
+++ b/tests/robotests/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModelTest.kt
@@ -61,6 +61,7 @@
thumbnail = ColorDrawable(0),
isReactiveToTone = true,
fontAxes = listOf(),
+ axisPresetConfig = null,
selectedColorId = null,
colorToneProgress = ClockMetadataModel.DEFAULT_COLOR_TONE_PROGRESS,
seedColor = null,