Merge "Change slider background bar color" into main
diff --git a/src/com/android/customization/picker/color/domain/interactor/ColorPickerInteractor.kt b/src/com/android/customization/picker/color/domain/interactor/ColorPickerInteractor.kt
index d3b2eba..e7759ce 100644
--- a/src/com/android/customization/picker/color/domain/interactor/ColorPickerInteractor.kt
+++ b/src/com/android/customization/picker/color/domain/interactor/ColorPickerInteractor.kt
@@ -20,6 +20,8 @@
import com.android.customization.picker.color.shared.model.ColorOptionModel
import javax.inject.Provider
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.onEach
/** Single entry-point for all application state and business logic related to system color. */
class ColorPickerInteractor(
@@ -30,20 +32,28 @@
/**
* The newly selected color option for overwriting the current active option during an
- * optimistic update, the value is set to null when update fails
+ * optimistic update, the value is set to null when update completes
*/
- val activeColorOption = MutableStateFlow<ColorOptionModel?>(null)
+ private val _selectingColorOption = MutableStateFlow<ColorOptionModel?>(null)
+ val selectingColorOption = _selectingColorOption.asStateFlow()
/** List of wallpaper and preset color options on the device, categorized by Color Type */
- val colorOptions = repository.colorOptions
+ val colorOptions =
+ repository.colorOptions.onEach {
+ // Reset optimistic update value when colorOptions updates
+ _selectingColorOption.value = null
+ }
suspend fun select(colorOptionModel: ColorOptionModel) {
- activeColorOption.value = colorOptionModel
+ _selectingColorOption.value = colorOptionModel
try {
+ // Do not reset optimistic update selection on selection success because UI color is not
+ // actually updated until the picker restarts. Wait to do so when updated color options
+ // become available
repository.select(colorOptionModel)
snapshotRestorer.get().storeSnapshot(colorOptionModel)
} catch (e: Exception) {
- activeColorOption.value = null
+ _selectingColorOption.value = null
}
}
diff --git a/src/com/android/customization/picker/color/ui/viewmodel/ColorPickerViewModel.kt b/src/com/android/customization/picker/color/ui/viewmodel/ColorPickerViewModel.kt
index 32e9362..52df31a 100644
--- a/src/com/android/customization/picker/color/ui/viewmodel/ColorPickerViewModel.kt
+++ b/src/com/android/customization/picker/color/ui/viewmodel/ColorPickerViewModel.kt
@@ -31,11 +31,9 @@
import kotlin.math.min
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -95,122 +93,97 @@
/** The list of all color options mapped by their color type */
private val allColorOptions:
Flow<Map<ColorType, List<OptionItemViewModel<ColorOptionIconViewModel>>>> =
- interactor.colorOptions
- .map { colorOptions ->
- colorOptions
- .map { colorOptionEntry ->
- colorOptionEntry.key to
- colorOptionEntry.value.map { colorOptionModel ->
- val colorOption: ColorOptionImpl =
- colorOptionModel.colorOption as ColorOptionImpl
- val lightThemeColors =
- colorOption.previewInfo.resolveColors(/* darkTheme= */ false)
- val darkThemeColors =
- colorOption.previewInfo.resolveColors(/* darkTheme= */ true)
- val isSelectedFlow: StateFlow<Boolean> =
- interactor.activeColorOption
- .map {
- it?.colorOption?.isEquivalent(
- colorOptionModel.colorOption
- )
- ?: colorOptionModel.isSelected
- }
- .stateIn(viewModelScope)
- OptionItemViewModel<ColorOptionIconViewModel>(
- key =
- MutableStateFlow(colorOptionModel.key) as StateFlow<String>,
- payload =
- ColorOptionIconViewModel(
- lightThemeColor0 = lightThemeColors[0],
- lightThemeColor1 = lightThemeColors[1],
- lightThemeColor2 = lightThemeColors[2],
- lightThemeColor3 = lightThemeColors[3],
- darkThemeColor0 = darkThemeColors[0],
- darkThemeColor1 = darkThemeColors[1],
- darkThemeColor2 = darkThemeColors[2],
- darkThemeColor3 = darkThemeColors[3],
- ),
- text =
- Text.Loaded(
- colorOption.getContentDescription(context).toString()
- ),
- isTextUserVisible = false,
- isSelected = isSelectedFlow,
- onClicked =
- isSelectedFlow.map { isSelected ->
- if (isSelected) {
- null
- } else {
- {
- viewModelScope.launch {
- interactor.select(colorOptionModel)
- logger.logThemeColorApplied(
- colorOptionModel.colorOption
- .sourceForLogging,
- colorOptionModel.colorOption
- .styleForLogging,
- colorOptionModel.colorOption
- .seedColorForLogging,
- )
- }
+ interactor.colorOptions.map { colorOptions ->
+ colorOptions
+ .map { colorOptionEntry ->
+ colorOptionEntry.key to
+ colorOptionEntry.value.map { colorOptionModel ->
+ val colorOption: ColorOptionImpl =
+ colorOptionModel.colorOption as ColorOptionImpl
+ val lightThemeColors =
+ colorOption.previewInfo.resolveColors(/* darkTheme= */ false)
+ val darkThemeColors =
+ colorOption.previewInfo.resolveColors(/* darkTheme= */ true)
+ val isSelectedFlow: StateFlow<Boolean> =
+ interactor.selectingColorOption
+ .map {
+ it?.colorOption?.isEquivalent(colorOptionModel.colorOption)
+ ?: colorOptionModel.isSelected
+ }
+ .stateIn(viewModelScope)
+ OptionItemViewModel<ColorOptionIconViewModel>(
+ key = MutableStateFlow(colorOptionModel.key) as StateFlow<String>,
+ payload =
+ ColorOptionIconViewModel(
+ lightThemeColor0 = lightThemeColors[0],
+ lightThemeColor1 = lightThemeColors[1],
+ lightThemeColor2 = lightThemeColors[2],
+ lightThemeColor3 = lightThemeColors[3],
+ darkThemeColor0 = darkThemeColors[0],
+ darkThemeColor1 = darkThemeColors[1],
+ darkThemeColor2 = darkThemeColors[2],
+ darkThemeColor3 = darkThemeColors[3],
+ ),
+ text =
+ Text.Loaded(
+ colorOption.getContentDescription(context).toString()
+ ),
+ isTextUserVisible = false,
+ isSelected = isSelectedFlow,
+ onClicked =
+ isSelectedFlow.map { isSelected ->
+ if (isSelected) {
+ null
+ } else {
+ {
+ viewModelScope.launch {
+ interactor.select(colorOptionModel)
+ logger.logThemeColorApplied(
+ colorOptionModel.colorOption
+ .sourceForLogging,
+ colorOptionModel.colorOption
+ .styleForLogging,
+ colorOptionModel.colorOption
+ .seedColorForLogging,
+ )
}
}
- },
- )
- }
- }
- .toMap()
- }
- .shareIn(
- scope = viewModelScope,
- started = SharingStarted.WhileSubscribed(),
- replay = 1,
- )
+ }
+ },
+ )
+ }
+ }
+ .toMap()
+ }
/** The list of all available color options for the selected Color Type. */
val colorOptions: Flow<List<OptionItemViewModel<ColorOptionIconViewModel>>> =
combine(allColorOptions, selectedColorTypeTabId) {
- allColorOptions:
- Map<ColorType, List<OptionItemViewModel<ColorOptionIconViewModel>>>,
- selectedColorTypeIdOrNull ->
- val selectedColorTypeId = selectedColorTypeIdOrNull ?: ColorType.WALLPAPER_COLOR
- allColorOptions[selectedColorTypeId]!!
- }
- .shareIn(
- scope = viewModelScope,
- started = SharingStarted.Eagerly,
- replay = 1,
- )
+ allColorOptions: Map<ColorType, List<OptionItemViewModel<ColorOptionIconViewModel>>>,
+ selectedColorTypeIdOrNull ->
+ val selectedColorTypeId = selectedColorTypeIdOrNull ?: ColorType.WALLPAPER_COLOR
+ allColorOptions[selectedColorTypeId]!!
+ }
/** The list of color options for the color section */
val colorSectionOptions: Flow<List<OptionItemViewModel<ColorOptionIconViewModel>>> =
- allColorOptions
- .map { allColorOptions ->
- val wallpaperOptions = allColorOptions[ColorType.WALLPAPER_COLOR]
- val presetOptions = allColorOptions[ColorType.PRESET_COLOR]
- val subOptions =
- wallpaperOptions!!.subList(
- 0,
- min(COLOR_SECTION_OPTION_SIZE, wallpaperOptions.size)
+ allColorOptions.map { allColorOptions ->
+ val wallpaperOptions = allColorOptions[ColorType.WALLPAPER_COLOR]
+ val presetOptions = allColorOptions[ColorType.PRESET_COLOR]
+ val subOptions =
+ wallpaperOptions!!.subList(0, min(COLOR_SECTION_OPTION_SIZE, wallpaperOptions.size))
+ // Add additional options based on preset colors if size of wallpaper color options is
+ // less than COLOR_SECTION_OPTION_SIZE
+ val additionalSubOptions =
+ presetOptions!!.subList(
+ 0,
+ min(
+ max(0, COLOR_SECTION_OPTION_SIZE - wallpaperOptions.size),
+ presetOptions.size,
)
- // Add additional options based on preset colors if size of wallpaper color options
- // is
- // less than COLOR_SECTION_OPTION_SIZE
- val additionalSubOptions =
- presetOptions!!.subList(
- 0,
- min(
- max(0, COLOR_SECTION_OPTION_SIZE - wallpaperOptions.size),
- presetOptions.size,
- )
- )
- subOptions + additionalSubOptions
- }
- .shareIn(
- scope = viewModelScope,
- started = SharingStarted.WhileSubscribed(),
- replay = 1,
- )
+ )
+ subOptions + additionalSubOptions
+ }
class Factory(
private val context: Context,