Merge "Add grid icon for wallpaper picker" into main
diff --git a/Android.bp b/Android.bp
index 58e6413..5efee51 100644
--- a/Android.bp
+++ b/Android.bp
@@ -74,6 +74,17 @@
"androidx.recyclerview_recyclerview",
"SystemUICustomizationLib",
"hilt_android",
+ // Compose
+ "PlatformComposeCore",
+ "androidx.activity_activity-compose",
+ "androidx.compose.foundation_foundation",
+ "androidx.compose.foundation_foundation-layout",
+ "androidx.compose.material3_material3",
+ "androidx.compose.runtime_runtime",
+ "androidx.compose.ui_ui",
+ "androidx.compose.ui_ui-tooling",
+ "androidx.lifecycle_lifecycle-runtime-compose",
+ "androidx.lifecycle_lifecycle-viewmodel-compose",
],
srcs: [
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 2c4355f..5ddf84c 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -7,7 +7,5 @@
[Hook Scripts]
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
-flag_hook = ${REPO_ROOT}/frameworks/base/packages/SystemUI/flag_check.py --msg=${PREUPLOAD_COMMIT_MESSAGE} --files=${PREUPLOAD_FILES} --project=${REPO_PATH}
-
[Tool Paths]
ktfmt = ${REPO_ROOT}/external/ktfmt/ktfmt.sh
diff --git a/res/layout/floating_sheet_clock_color_content.xml b/res/layout/floating_sheet_clock_color_content.xml
index acd274a..79e5b9a 100644
--- a/res/layout/floating_sheet_clock_color_content.xml
+++ b/res/layout/floating_sheet_clock_color_content.xml
@@ -16,6 +16,7 @@
<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:paddingVertical="@dimen/floating_sheet_content_vertical_padding"
@@ -69,16 +70,15 @@
android:clipToPadding="false" />
</FrameLayout>
- <SeekBar
+ <com.google.android.material.slider.Slider
android:id="@+id/clock_color_slider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingHorizontal="@dimen/floating_sheet_content_horizontal_padding"
android:minHeight="@dimen/touch_target_min_height"
- android:thumb="@null"
android:contentDescription="@string/accessibility_clock_slider_description"
- android:background="@null"
- android:progressDrawable="@drawable/saturation_progress_drawable"
- android:splitTrack="false" />
+ app:trackHeight="@dimen/slider_track_height"
+ app:thumbHeight="@dimen/slider_thumb_height"
+ android:theme="@style/Theme.Material3.DynamicColors.DayNight" />
</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/floating_sheet_clock_font_content.xml b/res/layout/floating_sheet_clock_font_content.xml
index 164b625..ba6c70c 100644
--- a/res/layout/floating_sheet_clock_font_content.xml
+++ b/res/layout/floating_sheet_clock_font_content.xml
@@ -40,7 +40,7 @@
style="@style/CustomizationOptionEntryTitleTextStyle"
android:text="@string/tab_placeholder_text" />
- <SeekBar
+ <com.google.android.material.slider.Slider
android:id="@+id/clock_axis_slider1"
android:layout_width="0dp"
android:layout_height="wrap_content"
@@ -50,10 +50,9 @@
app:layout_constraintStart_toEndOf="@+id/clock_axis_slider_name1"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginVertical="@dimen/clock_axis_control_slider_row_margin_vertical"
- android:background="@null"
- android:progressDrawable="@drawable/saturation_progress_drawable"
- android:splitTrack="false"
- android:thumb="@null" />
+ app:trackHeight="@dimen/slider_track_height"
+ app:thumbHeight="@dimen/slider_thumb_height"
+ android:theme="@style/Theme.Material3.DynamicColors.DayNight" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier1"
@@ -77,7 +76,7 @@
style="@style/CustomizationOptionEntryTitleTextStyle"
android:text="@string/tab_placeholder_text" />
- <SeekBar
+ <com.google.android.material.slider.Slider
android:id="@+id/clock_axis_slider2"
android:layout_width="0dp"
android:layout_height="wrap_content"
@@ -87,10 +86,9 @@
app:layout_constraintStart_toEndOf="@+id/clock_axis_slider_name2"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginVertical="@dimen/clock_axis_control_slider_row_margin_vertical"
- android:background="@null"
- android:progressDrawable="@drawable/saturation_progress_drawable"
- android:splitTrack="false"
- android:thumb="@null" />
+ app:trackHeight="@dimen/slider_track_height"
+ app:thumbHeight="@dimen/slider_thumb_height"
+ android:theme="@style/Theme.Material3.DynamicColors.DayNight" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier2"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 756ae2d..819f7e3 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -212,4 +212,8 @@
<dimen name="clock_axis_control_slider_row_margin_vertical">10dp</dimen>
<dimen name="clock_axis_control_switch_row_margin_vertical">8dp</dimen>
<dimen name="clock_font_apply_padding_start">8dp</dimen>
+
+ <!-- Shared dimensions for Material 3 sliders -->
+ <dimen name="slider_track_height">24dp</dimen>
+ <dimen name="slider_thumb_height">36dp</dimen>
</resources>
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 9508fa1..db38342 100644
--- a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
+++ b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
@@ -104,7 +104,7 @@
/** The currently-selected clock. This also emits the clock color information. */
override val selectedClock: Flow<ClockMetadataModel> =
- callbackFlow {
+ callbackFlow<ClockMetadataModel?> {
fun send() {
val activeClockId = registry.activeClockId
val metadata = registry.settings?.metadata
@@ -146,6 +146,9 @@
}
.flowOn(mainDispatcher)
.mapNotNull { it }
+ // Make this a shared flow to prevent ClockRegistry.registerClockChangeListener from
+ // being called every time this flow is collected, since ClockRegistry is a singleton.
+ .shareIn(mainScope, SharingStarted.WhileSubscribed(), 1)
override suspend fun setSelectedClock(clockId: String) {
registry.mutateSetting { oldSettings ->
diff --git a/src/com/android/customization/picker/clock/data/repository/ClockRegistryProvider.kt b/src/com/android/customization/picker/clock/data/repository/ClockRegistryProvider.kt
index 15d9088..3c3926f 100644
--- a/src/com/android/customization/picker/clock/data/repository/ClockRegistryProvider.kt
+++ b/src/com/android/customization/picker/clock/data/repository/ClockRegistryProvider.kt
@@ -19,7 +19,6 @@
import android.content.ComponentName
import android.content.Context
import android.view.LayoutInflater
-import com.android.systemui.Flags
import com.android.systemui.plugins.Plugin
import com.android.systemui.plugins.PluginManager
import com.android.systemui.shared.clocks.ClockRegistry
@@ -30,6 +29,7 @@
import com.android.systemui.shared.plugins.PluginManagerImpl
import com.android.systemui.shared.plugins.PluginPrefs
import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager_Factory
+import com.android.wallpaper.config.BaseFlags
import java.util.concurrent.Executors
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@@ -45,19 +45,20 @@
private val backgroundDispatcher: CoroutineDispatcher,
) {
private val clockRegistry: ClockRegistry by lazy {
+ val flags = BaseFlags.get()
ClockRegistry(
context,
createPluginManager(context),
coroutineScope,
mainDispatcher,
backgroundDispatcher,
- isEnabled = true,
+ isEnabled = flags.isCustomClocksEnabled(context),
handleAllUsers = false,
DefaultClockProvider(
ctx = context,
layoutInflater = LayoutInflater.from(context),
resources = context.resources,
- isClockReactiveVariantsEnabled = Flags.clockReactiveVariants(),
+ isClockReactiveVariantsEnabled = flags.isClockReactiveVariantsEnabled(),
),
keepAllLoaded = true,
subTag = "Picker",
@@ -93,7 +94,7 @@
override fun setDisabled(
component: ComponentName,
- @PluginEnabler.DisableReason reason: Int
+ @PluginEnabler.DisableReason reason: Int,
) = Unit
override fun isEnabled(component: ComponentName): Boolean {
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 8a2edfb..8414960 100644
--- a/src/com/android/customization/picker/clock/shared/model/ClockMetadataModel.kt
+++ b/src/com/android/customization/picker/clock/shared/model/ClockMetadataModel.kt
@@ -35,6 +35,8 @@
@ColorInt val seedColor: Int?,
) {
companion object {
+ const val MIN_COLOR_TONE_PROGRESS = 0
+ const val MAX_COLOR_TONE_PROGRESS = 100
const val DEFAULT_COLOR_TONE_PROGRESS = 75
}
}
diff --git a/src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt b/src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt
index 0ed0362..27bc42c 100644
--- a/src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt
+++ b/src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt
@@ -30,6 +30,7 @@
import androidx.core.view.doOnPreDraw
import androidx.core.view.get
import androidx.core.view.isNotEmpty
+import androidx.core.view.isVisible
import com.android.customization.picker.clock.shared.ClockSize
import com.android.customization.picker.clock.ui.viewmodel.ClockCarouselItemViewModel
import com.android.systemui.plugins.clocks.ClockController
@@ -57,6 +58,7 @@
val clockCarousel = LayoutInflater.from(context).inflate(R.layout.clock_carousel, this)
carousel = clockCarousel.requireViewById(R.id.carousel)
motionLayout = clockCarousel.requireViewById(R.id.motion_container)
+ motionLayout.isVisible = false
motionLayout.contentDescription = context.getString(R.string.custom_clocks_label)
clockViewScale =
TypedValue().let {
@@ -133,6 +135,11 @@
onClockSelected: (clock: ClockCarouselItemViewModel) -> Unit,
isTwoPaneAndSmallWidth: Boolean,
) {
+ if (clocks.isEmpty()) {
+ // Hide the carousel if clock list is empty
+ motionLayout.isVisible = false
+ return
+ }
if (isTwoPaneAndSmallWidth) {
overrideScreenPreviewWidth()
}
@@ -311,6 +318,7 @@
) {}
}
)
+ motionLayout.isVisible = true
}
fun setSelectedClockIndex(index: Int) {
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 52521d6..88e3f80 100644
--- a/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt
+++ b/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt
@@ -31,6 +31,8 @@
import com.android.customization.picker.color.shared.model.ColorOptionModel
import com.android.customization.picker.color.shared.model.ColorType
import com.android.customization.picker.color.ui.viewmodel.ColorOptionIconViewModel
+import com.android.systemui.monet.ColorScheme
+import com.android.systemui.monet.Style
import com.android.themepicker.R
import com.android.wallpaper.picker.common.text.ui.viewmodel.Text
import com.android.wallpaper.picker.option.ui.viewmodel.OptionItemViewModel
@@ -140,6 +142,16 @@
}
colorMap.values.forEachIndexed { index, colorModel ->
+ // Adjust clock colors for light theme for better color contrast
+ val lightThemeColor =
+ ColorScheme(
+ /* seed= */ colorModel.color,
+ /* darkTheme= */ false,
+ /* style= */ if (colorModel.colorId == "GRAY") Style.MONOCHROMATIC
+ else Style.RAINBOW,
+ )
+ .accent1
+ .getAtTone(450f)
val isSelectedFlow =
selectedColorId
.map { colorMap.keys.indexOf(it) == index }
@@ -150,10 +162,10 @@
key = MutableStateFlow(colorModel.colorId) as StateFlow<String>,
payload =
ColorOptionIconViewModel(
- lightThemeColor0 = colorModel.color,
- lightThemeColor1 = colorModel.color,
- lightThemeColor2 = colorModel.color,
- lightThemeColor3 = colorModel.color,
+ lightThemeColor0 = lightThemeColor,
+ lightThemeColor1 = lightThemeColor,
+ lightThemeColor2 = lightThemeColor,
+ lightThemeColor3 = lightThemeColor,
darkThemeColor0 = colorModel.color,
darkThemeColor1 = colorModel.color,
darkThemeColor2 = colorModel.color,
diff --git a/src/com/android/customization/picker/color/data/repository/ColorPickerRepositoryImpl2.kt b/src/com/android/customization/picker/color/data/repository/ColorPickerRepositoryImpl2.kt
index 5e90b41..96f9368 100644
--- a/src/com/android/customization/picker/color/data/repository/ColorPickerRepositoryImpl2.kt
+++ b/src/com/android/customization/picker/color/data/repository/ColorPickerRepositoryImpl2.kt
@@ -16,14 +16,18 @@
*/
package com.android.customization.picker.color.data.repository
+import android.app.WallpaperColors
+import android.app.WallpaperManager
+import android.os.Handler
+import android.os.Looper
import android.util.Log
import com.android.customization.model.CustomizationManager
import com.android.customization.model.color.ColorCustomizationManager
import com.android.customization.model.color.ColorOption
import com.android.customization.model.color.ColorOptionImpl
import com.android.customization.picker.color.shared.model.ColorType
-import com.android.wallpaper.picker.customization.data.repository.WallpaperColorsRepository
-import com.android.wallpaper.picker.customization.shared.model.WallpaperColorsModel
+import com.android.wallpaper.model.Screen
+import com.android.wallpaper.picker.customization.data.content.WallpaperClient
import com.android.wallpaper.picker.di.modules.BackgroundDispatcher
import javax.inject.Inject
import javax.inject.Singleton
@@ -31,11 +35,11 @@
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.suspendCancellableCoroutine
@Singleton
@@ -43,41 +47,41 @@
@Inject
constructor(
@BackgroundDispatcher private val scope: CoroutineScope,
- wallpaperColorsRepository: WallpaperColorsRepository,
private val colorManager: ColorCustomizationManager,
+ client: WallpaperClient,
) : ColorPickerRepository2 {
- private val homeWallpaperColors: StateFlow<WallpaperColorsModel?> =
- wallpaperColorsRepository.homeWallpaperColors
- private val lockWallpaperColors: StateFlow<WallpaperColorsModel?> =
- wallpaperColorsRepository.lockWallpaperColors
+ private val wallpaperColorsCallback: Flow<Pair<Screen, WallpaperColors?>> =
+ callbackFlow {
+ trySend(Pair(Screen.HOME_SCREEN, client.getWallpaperColors(Screen.HOME_SCREEN)))
+ trySend(Pair(Screen.LOCK_SCREEN, client.getWallpaperColors(Screen.LOCK_SCREEN)))
+ val listener = { colors: WallpaperColors?, which: Int ->
+ if (which and WallpaperManager.FLAG_SYSTEM != 0) {
+ trySend(Pair(Screen.HOME_SCREEN, colors))
+ }
+ if (which and WallpaperManager.FLAG_LOCK != 0) {
+ trySend(Pair(Screen.LOCK_SCREEN, colors))
+ }
+ }
+ client.addOnColorsChangedListener(listener, Handler(Looper.getMainLooper()))
+ awaitClose { client.removeOnColorsChangedListener(listener) }
+ }
+ // Make this a shared flow to make sure only one listener is added.
+ .shareIn(scope = scope, started = SharingStarted.WhileSubscribed(), replay = 1)
+ private val homeWallpaperColors: Flow<WallpaperColors?> =
+ wallpaperColorsCallback
+ .filter { (screen, _) -> screen == Screen.HOME_SCREEN }
+ .map { (_, colors) -> colors }
+ private val lockWallpaperColors: Flow<WallpaperColors?> =
+ wallpaperColorsCallback
+ .filter { (screen, _) -> screen == Screen.LOCK_SCREEN }
+ .map { (_, colors) -> colors }
override val colorOptions: Flow<Map<ColorType, List<ColorOption>>> =
- combine(homeWallpaperColors, lockWallpaperColors) { homeColors, lockColors ->
- homeColors to lockColors
- }
+ combine(homeWallpaperColors, lockWallpaperColors, ::Pair)
.map { (homeColors, lockColors) ->
suspendCancellableCoroutine { continuation ->
- if (
- homeColors is WallpaperColorsModel.Loading ||
- lockColors is WallpaperColorsModel.Loading
- ) {
- continuation.resumeWith(
- Result.success(
- mapOf(
- ColorType.WALLPAPER_COLOR to listOf(),
- ColorType.PRESET_COLOR to listOf(),
- )
- )
- )
- return@suspendCancellableCoroutine
- }
- val homeColorsLoaded = homeColors as WallpaperColorsModel.Loaded
- val lockColorsLoaded = lockColors as WallpaperColorsModel.Loaded
- colorManager.setWallpaperColors(
- homeColorsLoaded.colors,
- lockColorsLoaded.colors,
- )
+ colorManager.setWallpaperColors(homeColors, lockColors)
colorManager.fetchOptions(
object : CustomizationManager.OptionsFetchedListener<ColorOption> {
override fun onOptionsLoaded(options: MutableList<ColorOption>?) {
@@ -114,12 +118,17 @@
)
}
}
+ .shareIn(scope = scope, started = SharingStarted.WhileSubscribed(), replay = 1)
- private val settingsChanged = callbackFlow {
- trySend(Unit)
- colorManager.setListener { trySend(Unit) }
- awaitClose { colorManager.setListener(null) }
- }
+ private val settingsChanged =
+ callbackFlow {
+ trySend(Unit)
+ colorManager.setListener { trySend(Unit) }
+ awaitClose { colorManager.setListener(null) }
+ }
+ // Make this a shared flow to prevent colorManager.setListener from being called
+ // every time this flow is collected, since colorManager is a singleton.
+ .shareIn(scope = scope, started = SharingStarted.WhileSubscribed(), replay = 1)
override val selectedColorOption =
combine(colorOptions, settingsChanged) { options, _ ->
@@ -132,7 +141,7 @@
}
return@combine null
}
- .stateIn(scope = scope, started = SharingStarted.WhileSubscribed(), initialValue = null)
+ .shareIn(scope = scope, started = SharingStarted.WhileSubscribed(), replay = 1)
override suspend fun select(colorOption: ColorOption) {
suspendCancellableCoroutine { continuation ->
@@ -155,6 +164,6 @@
}
companion object {
- private const val TAG = "ColorPickerRepositoryImpl"
+ private const val TAG = "ColorPickerRepositoryImpl2"
}
}
diff --git a/src/com/android/customization/picker/color/ui/binder/ColorSectionViewBinder.kt b/src/com/android/customization/picker/color/ui/binder/ColorSectionViewBinder.kt
index 88b7d39..2558d8f 100644
--- a/src/com/android/customization/picker/color/ui/binder/ColorSectionViewBinder.kt
+++ b/src/com/android/customization/picker/color/ui/binder/ColorSectionViewBinder.kt
@@ -129,15 +129,14 @@
)
}
val optionSelectedView = itemView.requireViewById<ImageView>(R.id.option_selected)
- val colorView: View = itemView.requireViewById(R.id.option_tile)
- colorView.isClickable = true
- colorView.isFocusable = true
+ itemView.isClickable = true
+ itemView.isFocusable = true
lifecycleOwner.lifecycleScope.launch {
launch {
item.isSelected.collect { isSelected ->
optionSelectedView.isVisible = isSelected
- colorView.isSelected = isSelected
+ itemView.isSelected = isSelected
}
}
launch {
diff --git a/src/com/android/wallpaper/customization/ui/binder/ClockFloatingSheetBinder.kt b/src/com/android/wallpaper/customization/ui/binder/ClockFloatingSheetBinder.kt
index 480ae11..9dca30c 100644
--- a/src/com/android/wallpaper/customization/ui/binder/ClockFloatingSheetBinder.kt
+++ b/src/com/android/wallpaper/customization/ui/binder/ClockFloatingSheetBinder.kt
@@ -27,7 +27,6 @@
import android.view.ViewTreeObserver.OnGlobalLayoutListener
import android.widget.FrameLayout
import android.widget.ImageView
-import android.widget.SeekBar
import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
@@ -37,6 +36,7 @@
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.customization.picker.clock.shared.ClockSize
+import com.android.customization.picker.clock.shared.model.ClockMetadataModel
import com.android.customization.picker.color.ui.binder.ColorOptionIconBinder2
import com.android.customization.picker.color.ui.view.ColorOptionIconView2
import com.android.customization.picker.color.ui.viewmodel.ColorOptionIconViewModel
@@ -57,7 +57,10 @@
import com.android.wallpaper.picker.customization.ui.viewmodel.ColorUpdateViewModel
import com.android.wallpaper.picker.option.ui.adapter.OptionItemAdapter2
import com.google.android.material.materialswitch.MaterialSwitch
+import com.google.android.material.slider.LabelFormatter
+import com.google.android.material.slider.Slider
import java.lang.ref.WeakReference
+import kotlin.math.roundToInt
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -157,20 +160,17 @@
layoutManager =
LinearLayoutManager(appContext, LinearLayoutManager.HORIZONTAL, false)
}
- val clockColorSlider: SeekBar = view.requireViewById(R.id.clock_color_slider)
- clockColorSlider.setOnSeekBarChangeListener(
- object : SeekBar.OnSeekBarChangeListener {
- override fun onProgressChanged(p0: SeekBar?, progress: Int, fromUser: Boolean) {
- if (fromUser) {
- viewModel.onSliderProgressChanged(progress)
- }
+ val clockColorSlider: Slider = view.requireViewById(R.id.clock_color_slider)
+ clockColorSlider.apply {
+ valueFrom = ClockMetadataModel.MIN_COLOR_TONE_PROGRESS.toFloat()
+ valueTo = ClockMetadataModel.MAX_COLOR_TONE_PROGRESS.toFloat()
+ labelBehavior = LabelFormatter.LABEL_GONE
+ addOnChangeListener { _, value, fromUser ->
+ if (fromUser) {
+ viewModel.onSliderProgressChanged(value.roundToInt())
}
-
- override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit
-
- override fun onStopTrackingTouch(seekBar: SeekBar?) = Unit
}
- )
+ }
// Clock size switch
val clockSizeSwitch =
@@ -312,7 +312,7 @@
launch {
viewModel.previewingSliderProgress.collect { progress ->
- clockColorSlider.setProgress(progress, true)
+ clockColorSlider.value = progress.toFloat()
}
}
@@ -401,7 +401,7 @@
lifecycleOwner.lifecycleScope.launch {
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
- viewModel.selectedClockFontAxes.filterNotNull().collect { fontAxes ->
+ viewModel.previewingClockFontAxes.filterNotNull().collect { fontAxes ->
// This data flow updates only when a new clock style is selected. We
// initiate the clock font content with regard to that clock style.
sliderViewMap.clear()
diff --git a/src/com/android/wallpaper/customization/ui/binder/ThemePickerCustomizationOptionBinder.kt b/src/com/android/wallpaper/customization/ui/binder/ThemePickerCustomizationOptionBinder.kt
index cf29ce0..307c893 100644
--- a/src/com/android/wallpaper/customization/ui/binder/ThemePickerCustomizationOptionBinder.kt
+++ b/src/com/android/wallpaper/customization/ui/binder/ThemePickerCustomizationOptionBinder.kt
@@ -43,6 +43,7 @@
import com.android.systemui.plugins.clocks.ClockPreviewConfig
import com.android.systemui.shared.Flags
import com.android.themepicker.R
+import com.android.wallpaper.config.BaseFlags
import com.android.wallpaper.customization.ui.util.ThemePickerCustomizationOptionUtil.ThemePickerHomeCustomizationOption
import com.android.wallpaper.customization.ui.util.ThemePickerCustomizationOptionUtil.ThemePickerLockCustomizationOption
import com.android.wallpaper.customization.ui.viewmodel.ThemePickerCustomizationOptionsViewModel
@@ -56,6 +57,7 @@
import com.android.wallpaper.picker.customization.ui.viewmodel.ColorUpdateViewModel
import com.android.wallpaper.picker.customization.ui.viewmodel.CustomizationOptionsViewModel
import com.android.wallpaper.picker.customization.ui.viewmodel.CustomizationPickerViewModel2
+import com.android.wallpaper.picker.data.WallpaperModel
import com.google.android.material.materialswitch.MaterialSwitch
import javax.inject.Inject
import javax.inject.Singleton
@@ -82,6 +84,7 @@
navigateToMoreLockScreenSettingsActivity: () -> Unit,
navigateToColorContrastSettingsActivity: () -> Unit,
navigateToLockScreenNotificationsSettingsActivity: () -> Unit,
+ navigateToPreviewScreen: ((wallpaperModel: WallpaperModel) -> Unit)?,
) {
defaultCustomizationOptionsBinder.bind(
view,
@@ -95,8 +98,11 @@
navigateToMoreLockScreenSettingsActivity,
navigateToColorContrastSettingsActivity,
navigateToLockScreenNotificationsSettingsActivity,
+ navigateToPreviewScreen,
)
+ val isComposeRefactorEnabled = BaseFlags.get().isComposeRefactorEnabled()
+
val optionsViewModel =
viewModel.customizationOptionsViewModel as ThemePickerCustomizationOptionsViewModel
@@ -372,16 +378,18 @@
)
}
- customizationOptionFloatingSheetViewMap
- ?.get(ThemePickerHomeCustomizationOption.COLORS)
- ?.let {
- ColorsFloatingSheetBinder.bind(
- it,
- optionsViewModel,
- colorUpdateViewModel,
- lifecycleOwner,
- )
- }
+ if (!isComposeRefactorEnabled) {
+ customizationOptionFloatingSheetViewMap
+ ?.get(ThemePickerHomeCustomizationOption.COLORS)
+ ?.let {
+ ColorsFloatingSheetBinder.bind(
+ it,
+ optionsViewModel,
+ colorUpdateViewModel,
+ lifecycleOwner,
+ )
+ }
+ }
customizationOptionFloatingSheetViewMap
?.get(ThemePickerHomeCustomizationOption.APP_SHAPE_GRID)
diff --git a/src/com/android/wallpaper/customization/ui/compose/ColorFloatingSheet.kt b/src/com/android/wallpaper/customization/ui/compose/ColorFloatingSheet.kt
new file mode 100644
index 0000000..c81811d
--- /dev/null
+++ b/src/com/android/wallpaper/customization/ui/compose/ColorFloatingSheet.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.compose
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.lazy.LazyRow
+import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.android.compose.theme.PlatformTheme
+import com.android.themepicker.R
+
+@Preview
+@Composable
+fun ColorFloatingSheet() {
+ // TODO (b/391927276): figure out how to animate color scheme changes
+ PlatformTheme {
+ val colorScheme = MaterialTheme.colorScheme
+ // TODO (b/391927276): replace placeholder colors with actual values
+ val colorsList = remember {
+ mutableStateListOf(
+ Color.Red,
+ Color.Green,
+ Color.Blue,
+ Color.Cyan,
+ Color.Magenta,
+ Color.Yellow,
+ Color.Black,
+ )
+ }
+ Box(
+ modifier =
+ Modifier.fillMaxWidth()
+ .padding(horizontal = 16.dp)
+ .clip(shape = RoundedCornerShape(28.dp))
+ .drawBehind { drawRect(colorScheme.surfaceBright) }
+ ) {
+ Column(modifier = Modifier.padding(vertical = 20.dp)) {
+ Text(
+ modifier = Modifier.padding(horizontal = 20.dp),
+ text = stringResource(R.string.wallpaper_color_subheader),
+ color = colorScheme.onSurface,
+ )
+
+ Spacer(modifier = Modifier.height(16.dp))
+
+ LazyRow(
+ contentPadding = PaddingValues(horizontal = 20.dp),
+ horizontalArrangement = Arrangement.spacedBy(4.dp),
+ ) {
+ items(colorsList) { color ->
+ Box(
+ modifier =
+ Modifier.size(
+ dimensionResource(R.dimen.floating_sheet_color_option_size)
+ )
+ ) {
+ ColorOptionIcon(color)
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun ColorOptionIcon(color: Color) {
+ Box(modifier = Modifier.clip(CircleShape).fillMaxSize().drawBehind { drawRect(color) })
+}
diff --git a/src/com/android/wallpaper/customization/ui/util/ThemePickerCustomizationOptionUtil.kt b/src/com/android/wallpaper/customization/ui/util/ThemePickerCustomizationOptionUtil.kt
index ec38af5..922384a 100644
--- a/src/com/android/wallpaper/customization/ui/util/ThemePickerCustomizationOptionUtil.kt
+++ b/src/com/android/wallpaper/customization/ui/util/ThemePickerCustomizationOptionUtil.kt
@@ -16,26 +16,33 @@
package com.android.wallpaper.customization.ui.util
+import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.LinearLayout
+import androidx.compose.ui.platform.ComposeView
import com.android.customization.picker.mode.shared.util.DarkModeLifecycleUtil
import com.android.themepicker.R
+import com.android.wallpaper.config.BaseFlags
+import com.android.wallpaper.customization.ui.compose.ColorFloatingSheet
import com.android.wallpaper.model.Screen
import com.android.wallpaper.model.Screen.HOME_SCREEN
import com.android.wallpaper.model.Screen.LOCK_SCREEN
import com.android.wallpaper.picker.customization.ui.util.CustomizationOptionUtil
import com.android.wallpaper.picker.customization.ui.util.DefaultCustomizationOptionUtil
+import dagger.hilt.android.qualifiers.ActivityContext
import dagger.hilt.android.scopes.ActivityScoped
import javax.inject.Inject
@ActivityScoped
class ThemePickerCustomizationOptionUtil
@Inject
-constructor(private val defaultCustomizationOptionUtil: DefaultCustomizationOptionUtil) :
- CustomizationOptionUtil {
+constructor(
+ private val defaultCustomizationOptionUtil: DefaultCustomizationOptionUtil,
+ @ActivityContext private val context: Context,
+) : CustomizationOptionUtil {
// Instantiate DarkModeLifecycleUtil for it to observe lifecycle and update DarkModeRepository
@Inject lateinit var darkModeLifecycleUtil: DarkModeLifecycleUtil
@@ -143,6 +150,7 @@
): Map<CustomizationOptionUtil.CustomizationOption, View> {
val map =
defaultCustomizationOptionUtil.initFloatingSheet(bottomSheetContainer, layoutInflater)
+ val isComposeRefactorEnabled = BaseFlags.get().isComposeRefactorEnabled()
return buildMap {
putAll(map)
put(
@@ -165,11 +173,15 @@
)
put(
ThemePickerHomeCustomizationOption.COLORS,
- inflateFloatingSheet(
- ThemePickerHomeCustomizationOption.COLORS,
- bottomSheetContainer,
- layoutInflater,
- )
+ if (isComposeRefactorEnabled) {
+ ComposeView(context).apply { setContent { ColorFloatingSheet() } }
+ } else {
+ inflateFloatingSheet(
+ ThemePickerHomeCustomizationOption.COLORS,
+ bottomSheetContainer,
+ layoutInflater,
+ )
+ }
.also { bottomSheetContainer.addView(it) },
)
put(
diff --git a/src/com/android/wallpaper/customization/ui/view/ClockFontSliderViewHolder.kt b/src/com/android/wallpaper/customization/ui/view/ClockFontSliderViewHolder.kt
index 8bdf073..fb14342 100644
--- a/src/com/android/wallpaper/customization/ui/view/ClockFontSliderViewHolder.kt
+++ b/src/com/android/wallpaper/customization/ui/view/ClockFontSliderViewHolder.kt
@@ -16,12 +16,13 @@
package com.android.wallpaper.customization.ui.view
-import android.widget.SeekBar
import android.widget.TextView
import androidx.core.view.isInvisible
import com.android.systemui.plugins.clocks.ClockFontAxis
+import com.google.android.material.slider.LabelFormatter
+import com.google.android.material.slider.Slider
-class ClockFontSliderViewHolder(val name: TextView, val slider: SeekBar) {
+class ClockFontSliderViewHolder(val name: TextView, val slider: Slider) {
fun setIsVisible(isVisible: Boolean) {
name.isInvisible = !isVisible
@@ -31,30 +32,19 @@
fun initView(clockFontAxis: ClockFontAxis, onFontAxisValueUpdated: (value: Float) -> Unit) {
name.text = clockFontAxis.name
slider.apply {
- max = clockFontAxis.maxValue.toInt()
- min = clockFontAxis.minValue.toInt()
- progress = clockFontAxis.currentValue.toInt()
- setOnSeekBarChangeListener(
- object : SeekBar.OnSeekBarChangeListener {
- override fun onProgressChanged(
- seekBar: SeekBar?,
- progress: Int,
- fromUser: Boolean,
- ) {
- if (fromUser) {
- onFontAxisValueUpdated.invoke(progress.toFloat())
- }
- }
-
- override fun onStartTrackingTouch(seekBar: SeekBar?) {}
-
- override fun onStopTrackingTouch(seekBar: SeekBar?) {}
+ valueFrom = clockFontAxis.minValue
+ valueTo = clockFontAxis.maxValue
+ value = clockFontAxis.currentValue
+ labelBehavior = LabelFormatter.LABEL_GONE
+ addOnChangeListener { _, value, fromUser ->
+ if (fromUser) {
+ onFontAxisValueUpdated.invoke(value)
}
- )
+ }
}
}
fun setValue(value: Float) {
- slider.progress = value.toInt()
+ slider.value = value
}
}
diff --git a/src/com/android/wallpaper/customization/ui/viewmodel/ClockOptionItemViewModel.kt b/src/com/android/wallpaper/customization/ui/viewmodel/ClockOptionItemViewModel.kt
deleted file mode 100644
index cd223a0..0000000
--- a/src/com/android/wallpaper/customization/ui/viewmodel/ClockOptionItemViewModel.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wallpaper.customization.ui.viewmodel
-
-import android.graphics.drawable.Drawable
-
-data class ClockOptionItemViewModel(
- val clockId: String,
- val isSelected: Boolean,
- val contentDescription: String,
- val thumbnail: Drawable,
-)
diff --git a/src/com/android/wallpaper/customization/ui/viewmodel/ClockPickerViewModel.kt b/src/com/android/wallpaper/customization/ui/viewmodel/ClockPickerViewModel.kt
index f3be2eb..7fe81ed 100644
--- a/src/com/android/wallpaper/customization/ui/viewmodel/ClockPickerViewModel.kt
+++ b/src/com/android/wallpaper/customization/ui/viewmodel/ClockPickerViewModel.kt
@@ -187,14 +187,13 @@
// Clock font axis
private val overrideClockFontAxisMap = MutableStateFlow<Map<String, Float>>(emptyMap())
- val selectedClockFontAxes =
+ val previewingClockFontAxes =
previewingClock
.map { clock -> clock.fontAxes }
- .stateIn(viewModelScope, SharingStarted.Eagerly, null)
+ .shareIn(viewModelScope, SharingStarted.WhileSubscribed(), 1)
private val selectedClockFontAxisMap =
- selectedClockFontAxes
- .filterNotNull()
- .map { fontAxes -> fontAxes.associate { it.key to it.currentValue } }
+ selectedClock
+ .map { clock -> clock.fontAxes.associate { it.key to it.currentValue } }
.shareIn(viewModelScope, SharingStarted.WhileSubscribed(), 1)
private val isFontAxisMapEdited =
combine(overrideClockFontAxisMap, selectedClockFontAxisMap) {
@@ -432,9 +431,10 @@
isClockColorEdited ||
isSliderProgressEdited
}
-
+ private val onApplyClicked: MutableStateFlow<Boolean> = MutableStateFlow(false)
val onApply: Flow<(suspend () -> Unit)?> =
combine(
+ onApplyClicked,
isEdited,
previewingClock,
previewingClockSize,
@@ -442,14 +442,16 @@
previewingSliderProgress,
previewingClockFontAxisMap,
) { array ->
- val isEdited: Boolean = array[0] as Boolean
- val clock: ClockMetadataModel = array[1] as ClockMetadataModel
- val size: ClockSize = array[2] as ClockSize
- val previewingColorId: String = array[3] as String
- val previewProgress: Int = array[4] as Int
- val axisMap: Map<String, Float> = array[5] as Map<String, Float>
- if (isEdited) {
+ val onApplyClicked: Boolean = array[0] as Boolean
+ val isEdited: Boolean = array[1] as Boolean
+ val clock: ClockMetadataModel = array[2] as ClockMetadataModel
+ val size: ClockSize = array[3] as ClockSize
+ val previewingColorId: String = array[4] as String
+ val previewProgress: Int = array[5] as Int
+ val axisMap: Map<String, Float> = array[6] as Map<String, Float>
+ if (isEdited && !onApplyClicked) {
{
+ this.onApplyClicked.value = true
clockPickerInteractor.applyClock(
clockId = clock.clockId,
size = size,
@@ -477,6 +479,7 @@
overridingSliderProgress.value = null
overrideClockFontAxisMap.value = emptyMap()
_selectedTab.value = Tab.STYLE
+ onApplyClicked.value = false
}
companion object {
diff --git a/src/com/android/wallpaper/customization/ui/viewmodel/ClockSizeOptionViewModel.kt b/src/com/android/wallpaper/customization/ui/viewmodel/ClockSizeOptionViewModel.kt
deleted file mode 100644
index de2c54a..0000000
--- a/src/com/android/wallpaper/customization/ui/viewmodel/ClockSizeOptionViewModel.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wallpaper.customization.ui.viewmodel
-
-import com.android.customization.picker.clock.shared.ClockSize
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.StateFlow
-
-data class ClockSizeOptionViewModel(
- val size: ClockSize,
- val isSelected: StateFlow<Boolean>,
- val onClicked: Flow<(() -> Unit)?>,
-)