Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1b26885b authored by Catherine Liang's avatar Catherine Liang Committed by Android (Google) Code Review
Browse files

Merge "Refactor color picker to better track selected option (1/2)" into main

parents 9d43457e 878a2ac3
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ public class ColorCustomizationManager implements CustomizationManager<ColorOpti
    private String mCurrentStyle;
    private WallpaperColors mHomeWallpaperColors;
    private WallpaperColors mLockWallpaperColors;
    private SettingsChangedListener mListener;

    /** Returns the {@link ColorCustomizationManager} instance. */
    public static ColorCustomizationManager getInstance(Context context,
@@ -116,6 +117,7 @@ public class ColorCustomizationManager implements CustomizationManager<ColorOpti
        mProvider = provider;
        mContentResolver = contentResolver;
        mExecutorService = executorService;
        mListener = null;
        ContentObserver observer = new ContentObserver(/* handler= */ null) {
            @Override
            public void onChange(boolean selfChange, Uri uri) {
@@ -127,6 +129,9 @@ public class ColorCustomizationManager implements CustomizationManager<ColorOpti
                    mCurrentOverlays = null;
                    mCurrentStyle = null;
                    mCurrentSource = null;
                    if (mListener != null) {
                        mListener.onSettingsChanged();
                    }
                }
            }
        };
@@ -314,4 +319,19 @@ public class ColorCustomizationManager implements CustomizationManager<ColorOpti
        }
        return overlayPackages;
    }

    /**
     * Sets a listener that is called when ColorCustomizationManager is updated.
     */
    public void setListener(SettingsChangedListener listener) {
        mListener = listener;
    }

    /**
     * A listener for listening to when ColorCustomizationManager is updated.
     */
    public interface SettingsChangedListener {
        /** */
        void onSettingsChanged();
    }
}
+36 −0
Original line number Diff line number Diff line
/*
 * 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.customization.picker.color.data.repository

import com.android.customization.model.color.ColorOption
import com.android.customization.picker.color.shared.model.ColorType
import kotlinx.coroutines.flow.Flow

/**
 * Abstracts access to application state related to functionality for selecting, picking, or setting
 * system color.
 */
interface ColorPickerRepository2 {
    /** List of wallpaper and preset color options on the device, categorized by Color Type */
    val colorOptions: Flow<Map<ColorType, List<ColorOption>>>

    /** The system selected color option from the generated list of color options */
    val selectedColorOption: Flow<ColorOption?>

    /** Selects a color option with optimistic update */
    suspend fun select(colorOption: ColorOption)
}
+160 −0
Original line number Diff line number Diff line
/*
 * 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.customization.picker.color.data.repository

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.picker.di.modules.BackgroundDispatcher
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.coroutines.CoroutineScope
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.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.suspendCancellableCoroutine

@Singleton
class ColorPickerRepositoryImpl2
@Inject
constructor(
    @BackgroundDispatcher private val scope: CoroutineScope,
    wallpaperColorsRepository: WallpaperColorsRepository,
    private val colorManager: ColorCustomizationManager,
) : ColorPickerRepository2 {

    private val homeWallpaperColors: StateFlow<WallpaperColorsModel?> =
        wallpaperColorsRepository.homeWallpaperColors
    private val lockWallpaperColors: StateFlow<WallpaperColorsModel?> =
        wallpaperColorsRepository.lockWallpaperColors

    override val colorOptions: Flow<Map<ColorType, List<ColorOption>>> =
        combine(homeWallpaperColors, lockWallpaperColors) { homeColors, lockColors ->
                homeColors to lockColors
            }
            .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.fetchOptions(
                        object : CustomizationManager.OptionsFetchedListener<ColorOption> {
                            override fun onOptionsLoaded(options: MutableList<ColorOption>?) {
                                val wallpaperColorOptions: MutableList<ColorOption> =
                                    mutableListOf()
                                val presetColorOptions: MutableList<ColorOption> = mutableListOf()
                                options?.forEach { option ->
                                    when ((option as ColorOptionImpl).type) {
                                        ColorType.WALLPAPER_COLOR ->
                                            wallpaperColorOptions.add(option)
                                        ColorType.PRESET_COLOR -> presetColorOptions.add(option)
                                    }
                                }
                                continuation.resumeWith(
                                    Result.success(
                                        mapOf(
                                            ColorType.WALLPAPER_COLOR to wallpaperColorOptions,
                                            ColorType.PRESET_COLOR to presetColorOptions,
                                        )
                                    )
                                )
                            }

                            override fun onError(throwable: Throwable?) {
                                Log.e(TAG, "Error loading theme bundles", throwable)
                                continuation.resumeWith(
                                    Result.failure(
                                        throwable ?: Throwable("Error loading theme bundles")
                                    )
                                )
                            }
                        },
                        /* reload= */ false,
                    )
                }
            }

    private val settingsChanged = callbackFlow {
        trySend(Unit)
        colorManager.setListener { trySend(Unit) }
        awaitClose { colorManager.setListener(null) }
    }

    override val selectedColorOption =
        combine(colorOptions, settingsChanged) { options, _ ->
                options.forEach { (_, optionsByType) ->
                    optionsByType.forEach {
                        if (it.isActive(colorManager)) {
                            return@combine it
                        }
                    }
                }
                return@combine null
            }
            .stateIn(scope = scope, started = SharingStarted.WhileSubscribed(), initialValue = null)

    override suspend fun select(colorOption: ColorOption) {
        suspendCancellableCoroutine { continuation ->
            colorManager.apply(
                colorOption,
                object : CustomizationManager.Callback {
                    override fun onSuccess() {
                        continuation.resumeWith(Result.success(Unit))
                    }

                    override fun onError(throwable: Throwable?) {
                        Log.w(TAG, "Apply theme with error", throwable)
                        continuation.resumeWith(
                            Result.failure(throwable ?: Throwable("Error loading theme bundles"))
                        )
                    }
                },
            )
        }
    }

    companion object {
        private const val TAG = "ColorPickerRepositoryImpl"
    }
}
+35 −0
Original line number Diff line number Diff line
/*
 * 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.customization.picker.color.domain.interactor

import com.android.customization.model.color.ColorOption
import com.android.customization.picker.color.data.repository.ColorPickerRepository2
import javax.inject.Inject
import javax.inject.Singleton

/** Single entry-point for all application state and business logic related to system color. */
@Singleton
class ColorPickerInteractor2 @Inject constructor(private val repository: ColorPickerRepository2) {
    val selectedColorOption = repository.selectedColorOption

    /** List of wallpaper and preset color options on the device, categorized by Color Type */
    val colorOptions = repository.colorOptions

    suspend fun select(colorOption: ColorOption) {
        repository.select(colorOption)
    }
}
+4 −4
Original line number Diff line number Diff line
@@ -93,11 +93,11 @@ object ColorsFloatingSheetBinder {
                }

                launch {
                    viewModel.previewingColorOption.collect { colorModel ->
                        if (colorModel != null) {
                    viewModel.previewingColorOption.collect { colorOption ->
                        if (colorOption != null) {
                            colorUpdateViewModel.previewColors(
                                colorModel.colorOption.seedColor,
                                colorModel.colorOption.style,
                                colorOption.seedColor,
                                colorOption.style,
                            )
                        } else colorUpdateViewModel.resetPreview()
                    }
Loading