Merge "[TP] Clock color picker" into tm-qpr-dev am: c98daa6009 am: 3916a74e39
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/ThemePicker/+/21343479
Change-Id: Ic2f23079b8908669029cdb967db01901c4639cff
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/res/layout/fragment_clock_settings.xml b/res/layout/fragment_clock_settings.xml
index 13cec45..696d6eb 100644
--- a/res/layout/fragment_clock_settings.xml
+++ b/res/layout/fragment_clock_settings.xml
@@ -19,11 +19,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
-
<FrameLayout
android:id="@+id/section_header_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
+
<include layout="@layout/section_header" />
</FrameLayout>
@@ -95,15 +95,34 @@
<FrameLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:paddingTop="16dp">
- <androidx.recyclerview.widget.RecyclerView
- android:id="@id/affordances"
+ <FrameLayout
+ android:id="@+id/color_options_container"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:clipToPadding="false"
- android:paddingHorizontal="16dp"
- android:visibility="gone"/>
+ android:layout_height="wrap_content">
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/color_options"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipToPadding="false"
+ android:paddingHorizontal="16dp" />
+
+ <!--
+ This is just 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.
+ -->
+ <include
+ layout="@layout/color_option_with_background"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="invisible" />
+ </FrameLayout>
<com.android.customization.picker.clock.ui.view.ClockSizeRadioButtonGroup
android:id="@+id/clock_size_radio_button_group"
diff --git a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepository.kt b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepository.kt
index c7fa2c5..1904197 100644
--- a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepository.kt
+++ b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepository.kt
@@ -33,5 +33,7 @@
fun setSelectedClock(clockId: String)
+ fun setClockColor(color: Int?)
+
fun setClockSize(size: ClockSize)
}
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 f6b0514..9e140aa 100644
--- a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
+++ b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
@@ -43,7 +43,7 @@
registry
.getClocks()
.filter { "NOT_IN_USE" !in it.clockId }
- .map { it.toModel() }
+ .map { it.toModel(null) }
.toTypedArray()
/** The currently-selected clock. */
@@ -56,7 +56,7 @@
registry
.getClocks()
.find { clockMetadata -> clockMetadata.clockId == currentClockId }
- ?.toModel()
+ ?.toModel(registry.seedColor)
if (model == null) {
Log.w(
TAG,
@@ -77,6 +77,10 @@
registry.currentClockId = clockId
}
+ override fun setClockColor(color: Int?) {
+ registry.seedColor = color
+ }
+
// TODO(b/262924055): Use the shared system UI component to query the clock size
private val _selectedClockSize = MutableStateFlow(ClockSize.DYNAMIC)
override val selectedClockSize: Flow<ClockSize> = _selectedClockSize.asStateFlow()
@@ -85,8 +89,8 @@
_selectedClockSize.value = size
}
- private fun ClockMetadata.toModel(): ClockMetadataModel {
- return ClockMetadataModel(clockId = clockId, name = name)
+ private fun ClockMetadata.toModel(color: Int?): ClockMetadataModel {
+ return ClockMetadataModel(clockId = clockId, name = name, color = color)
}
companion object {
diff --git a/src/com/android/customization/picker/clock/domain/interactor/ClockPickerInteractor.kt b/src/com/android/customization/picker/clock/domain/interactor/ClockPickerInteractor.kt
index 627c4a9..846ea21 100644
--- a/src/com/android/customization/picker/clock/domain/interactor/ClockPickerInteractor.kt
+++ b/src/com/android/customization/picker/clock/domain/interactor/ClockPickerInteractor.kt
@@ -21,6 +21,7 @@
import com.android.customization.picker.clock.shared.ClockSize
import com.android.customization.picker.clock.shared.model.ClockMetadataModel
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
/**
* Interactor for accessing application clock settings, as well as selecting and configuring custom
@@ -31,12 +32,18 @@
val selectedClock: Flow<ClockMetadataModel> = repository.selectedClock
+ val selectedClockColor: Flow<Int?> = repository.selectedClock.map { clock -> clock.color }
+
val selectedClockSize: Flow<ClockSize> = repository.selectedClockSize
fun setSelectedClock(clockId: String) {
repository.setSelectedClock(clockId)
}
+ fun setClockColor(color: Int?) {
+ repository.setClockColor(color)
+ }
+
fun setClockSize(size: ClockSize) {
repository.setClockSize(size)
}
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 ea84d2b..acbc792 100644
--- a/src/com/android/customization/picker/clock/shared/model/ClockMetadataModel.kt
+++ b/src/com/android/customization/picker/clock/shared/model/ClockMetadataModel.kt
@@ -21,4 +21,5 @@
data class ClockMetadataModel(
val clockId: String,
val name: String,
+ val color: Int?,
)
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 9a94a69..b460bc1 100644
--- a/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
+++ b/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
@@ -28,6 +28,7 @@
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.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.launch
@@ -40,6 +41,7 @@
lifecycleOwner: LifecycleOwner,
) {
val tabView: RecyclerView = view.requireViewById(R.id.tabs)
+ val colorOptionContainer = view.requireViewById<View>(R.id.color_options_container)
val sizeOptions =
view.requireViewById<ClockSizeRadioButtonGroup>(R.id.clock_size_radio_button_group)
@@ -55,6 +57,13 @@
}
}
+ val colorOptionContainerView: RecyclerView = view.requireViewById(R.id.color_options)
+ val colorOptionAdapter = ColorOptionAdapter()
+ colorOptionContainerView.adapter = colorOptionAdapter
+ colorOptionContainerView.layoutManager =
+ LinearLayoutManager(view.context, RecyclerView.HORIZONTAL, false)
+ colorOptionContainerView.addItemDecoration(ItemSpacing(ItemSpacing.ITEM_SPACING_DP))
+
lifecycleOwner.lifecycleScope.launch {
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
launch { viewModel.tabs.collect { tabAdapter.setItems(it) } }
@@ -63,9 +72,11 @@
viewModel.selectedTabPosition.collect { tab ->
when (tab) {
ClockSettingsViewModel.Tab.COLOR -> {
+ colorOptionContainer.isVisible = true
sizeOptions.isInvisible = true
}
ClockSettingsViewModel.Tab.SIZE -> {
+ colorOptionContainer.isInvisible = true
sizeOptions.isVisible = true
}
}
@@ -73,6 +84,12 @@
}
launch {
+ viewModel.colorOptions.collect { colorOptions ->
+ colorOptionAdapter.setItems(colorOptions)
+ }
+ }
+
+ launch {
viewModel.selectedClockSize.collect { size ->
when (size) {
ClockSize.DYNAMIC -> {
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 8c0925f..11e0273 100644
--- a/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt
+++ b/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt
@@ -16,8 +16,10 @@
package com.android.customization.picker.clock.ui.viewmodel
import android.content.Context
+import android.graphics.Color
import com.android.customization.picker.clock.domain.interactor.ClockPickerInteractor
import com.android.customization.picker.clock.shared.ClockSize
+import com.android.customization.picker.color.ui.viewmodel.ColorOptionViewModel
import com.android.wallpaper.R
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -33,6 +35,47 @@
SIZE,
}
+ val colorOptions: Flow<List<ColorOptionViewModel>> =
+ interactor.selectedClockColor.map { selectedColor ->
+ buildList {
+ // TODO (b/241966062) Change design of the placeholder for default theme color
+ add(
+ ColorOptionViewModel(
+ color0 = Color.TRANSPARENT,
+ color1 = Color.TRANSPARENT,
+ color2 = Color.TRANSPARENT,
+ color3 = Color.TRANSPARENT,
+ contentDescription = "description",
+ isSelected = selectedColor == null,
+ onClick =
+ if (selectedColor == null) {
+ null
+ } else {
+ { interactor.setClockColor(null) }
+ },
+ )
+ )
+ COLOR_LIST.forEach { color ->
+ add(
+ ColorOptionViewModel(
+ color0 = color,
+ color1 = color,
+ color2 = color,
+ color3 = color,
+ contentDescription = "description",
+ isSelected = selectedColor == color,
+ onClick =
+ if (selectedColor == color) {
+ null
+ } else {
+ { interactor.setClockColor(color) }
+ },
+ )
+ )
+ }
+ }
+ }
+
val selectedClockSize: Flow<ClockSize> = interactor.selectedClockSize
fun setClockSize(size: ClockSize) {
@@ -66,4 +109,10 @@
),
)
}
+
+ companion object {
+ // TODO (b/241966062) The color integers here are temporary for dev purposes. We need to
+ // finalize the overridden colors.
+ val COLOR_LIST = listOf(-2563329, -8775, -1777665, -5442872)
+ }
}
diff --git a/src/com/android/customization/picker/common/ui/view/ItemSpacing.kt b/src/com/android/customization/picker/common/ui/view/ItemSpacing.kt
index cbf9e97..ca689aa 100644
--- a/src/com/android/customization/picker/common/ui/view/ItemSpacing.kt
+++ b/src/com/android/customization/picker/common/ui/view/ItemSpacing.kt
@@ -44,6 +44,6 @@
companion object {
const val TAB_ITEM_SPACING_DP = 12
- const val AFFORDANCE_ITEM_SPACING_DP = 8
+ const val ITEM_SPACING_DP = 8
}
}
diff --git a/src/com/android/customization/picker/quickaffordance/ui/binder/KeyguardQuickAffordancePickerBinder.kt b/src/com/android/customization/picker/quickaffordance/ui/binder/KeyguardQuickAffordancePickerBinder.kt
index f03fda3..af5cd13 100644
--- a/src/com/android/customization/picker/quickaffordance/ui/binder/KeyguardQuickAffordancePickerBinder.kt
+++ b/src/com/android/customization/picker/quickaffordance/ui/binder/KeyguardQuickAffordancePickerBinder.kt
@@ -66,7 +66,7 @@
affordancesView.adapter = affordancesAdapter
affordancesView.layoutManager =
LinearLayoutManager(view.context, RecyclerView.HORIZONTAL, false)
- affordancesView.addItemDecoration(ItemSpacing(ItemSpacing.AFFORDANCE_ITEM_SPACING_DP))
+ affordancesView.addItemDecoration(ItemSpacing(ItemSpacing.ITEM_SPACING_DP))
var dialog: Dialog? = null
diff --git a/tests/src/com/android/customization/picker/clock/data/repository/FakeClockPickerRepository.kt b/tests/src/com/android/customization/picker/clock/data/repository/FakeClockPickerRepository.kt
index af045d5..c201527 100644
--- a/tests/src/com/android/customization/picker/clock/data/repository/FakeClockPickerRepository.kt
+++ b/tests/src/com/android/customization/picker/clock/data/repository/FakeClockPickerRepository.kt
@@ -20,21 +20,30 @@
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
class FakeClockPickerRepository : ClockPickerRepository {
override val allClocks: Array<ClockMetadataModel> = fakeClocks
- private val _selectedClock = MutableStateFlow(fakeClocks[0])
- override val selectedClock: Flow<ClockMetadataModel> = _selectedClock.asStateFlow()
+ private val _selectedClockId = MutableStateFlow(fakeClocks[0].clockId)
+ private val _clockColor = MutableStateFlow<Int?>(null)
+ override val selectedClock: Flow<ClockMetadataModel> =
+ combine(_selectedClockId, _clockColor) { selectedClockId, clockColor ->
+ val selectedClock = allClocks.find { clock -> clock.clockId == selectedClockId }
+ checkNotNull(selectedClock)
+ ClockMetadataModel(selectedClock.clockId, selectedClock.name, clockColor)
+ }
private val _selectedClockSize = MutableStateFlow(ClockSize.LARGE)
override val selectedClockSize: Flow<ClockSize> = _selectedClockSize.asStateFlow()
override fun setSelectedClock(clockId: String) {
- val clock = fakeClocks.find { it.clockId == clockId }
- checkNotNull(clock)
- _selectedClock.value = clock
+ _selectedClockId.value = clockId
+ }
+
+ override fun setClockColor(color: Int?) {
+ _clockColor.value = color
}
override fun setClockSize(size: ClockSize) {
@@ -44,10 +53,10 @@
companion object {
val fakeClocks =
arrayOf(
- ClockMetadataModel("clock0", "clock0"),
- ClockMetadataModel("clock1", "clock1"),
- ClockMetadataModel("clock2", "clock2"),
- ClockMetadataModel("clock3", "clock3"),
+ ClockMetadataModel("clock0", "clock0", null),
+ ClockMetadataModel("clock1", "clock1", null),
+ ClockMetadataModel("clock2", "clock2", null),
+ ClockMetadataModel("clock3", "clock3", null),
)
}
}
diff --git a/tests/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsTabViewModelTest.kt b/tests/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsTabViewModelTest.kt
index 63bdd7b..a484027 100644
--- a/tests/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsTabViewModelTest.kt
+++ b/tests/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsTabViewModelTest.kt
@@ -44,6 +44,17 @@
}
@Test
+ fun setClockColor() = runTest {
+ val observedClockColorOptions = collectLastValue(underTest.colorOptions)
+ assertThat(observedClockColorOptions()!![0].isSelected).isTrue()
+ assertThat(observedClockColorOptions()!![0].onClick).isNull()
+
+ observedClockColorOptions()!![1].onClick?.invoke()
+ assertThat(observedClockColorOptions()!![1].isSelected).isTrue()
+ assertThat(observedClockColorOptions()!![1].onClick).isNull()
+ }
+
+ @Test
fun setClockSize() = runTest {
val observedClockSize = collectLastValue(underTest.selectedClockSize)
underTest.setClockSize(ClockSize.DYNAMIC)