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

Commit ce62a17f authored by Catherine Liang's avatar Catherine Liang
Browse files

Add default and minimal icon style options

Flag: com.android.systemui.shared.extendible_theme_manager
Bug: 397782741
Test: manually verified with flag on and off
Test: manually verified with scenarios of style or shape not available
Change-Id: Iebd05ff15317ac7ce69c91d0a72fd872994f47c4
parent 82aa8d5f
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -151,6 +151,14 @@
        [CHAR LIMIT=15] -->
    <string name="app_icons_theme_themed">themed</string>

    <!-- Label for an icon style option that applies no theming to app icons when selected.
        [CHAR LIMIT=15] -->
    <string name="app_icons_style_default">Default</string>

    <!-- Label for an icon style option that applies a monochrome theme to app icons when selected.
        [CHAR LIMIT=15] -->
    <string name="app_icons_style_minimal">Minimal</string>

    <!-- Title of a tab to change the app icon shape [CHAR LIMIT=15] -->
    <string name="app_icons_shape">Shape</string>

+18 −2
Original line number Diff line number Diff line
@@ -12,13 +12,13 @@
 * 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.grid.domain.interactor
package com.android.customization.picker.icon.domain.interactor

import com.android.customization.model.grid.ShapeOptionModel
import com.android.customization.picker.grid.data.repository.ShapeRepository
import com.android.customization.picker.icon.shared.model.IconStyle
import com.android.customization.picker.themedicon.data.repository.ThemedIconRepository
import javax.inject.Inject
import javax.inject.Singleton
@@ -45,6 +45,22 @@ constructor(

    val isThemedIconEnabled: Flow<Boolean> = themedIconRepository.isActivated

    val iconStyles =
        isThemedIconAvailable.map { isThemedIconAvailable ->
            // TODO (b/397782741): introduce different icon styles depending on repository
            var styles = IconStyle.entries.toList()
            if (!isThemedIconAvailable) styles = styles.filter { it != IconStyle.MONOCHROME }
            styles
        }

    val selectedIconStyle =
        isThemedIconEnabled.map {
            when (it) {
                true -> IconStyle.MONOCHROME
                false -> IconStyle.DEFAULT
            }
        }

    suspend fun applyThemedIconEnabled(enabled: Boolean) =
        themedIconRepository.setThemedIconEnabled(enabled)

+24 −0
Original line number Diff line number Diff line
/*
 * 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.customization.picker.icon.shared.model

import com.android.themepicker.R

enum class IconStyle(val nameResId: Int) {
    DEFAULT(R.string.app_icons_style_default),
    MONOCHROME(R.string.app_icons_style_minimal),
}
+61 −5
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.wallpaper.customization.ui.binder

import android.content.Context
import android.content.res.ColorStateList
import android.graphics.drawable.AdaptiveIconDrawable
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
@@ -32,6 +33,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.customization.picker.common.ui.view.SingleRowListItemSpacing
import com.android.customization.picker.grid.ui.viewmodel.ShapeIconViewModel
import com.android.customization.picker.icon.shared.model.IconStyle
import com.android.themepicker.R
import com.android.wallpaper.config.BaseFlags
import com.android.wallpaper.customization.ui.util.ThemePickerCustomizationOptionUtil.ThemePickerHomeCustomizationOption.APP_ICONS
@@ -112,7 +114,20 @@ object AppIconFloatingSheetBinder {
            )
        val shapeOptionList =
            view.requireViewById<RecyclerView>(R.id.shape_options).also {
                it.initShapeOptionList(view.context, shapeOptionListAdapter)
                it.initOptionList(view.context, shapeOptionListAdapter)
            }

        val styleOptionListAdapter =
            createStyleOptionItemAdapter(
                context = view.context,
                colorUpdateViewModel = colorUpdateViewModel,
                shouldAnimateColor = isFloatingSheetActive,
                lifecycleOwner = lifecycleOwner,
                backgroundDispatcher = backgroundDispatcher,
            )
        val styleOptionList =
            view.requireViewById<RecyclerView>(R.id.icon_style_options).also {
                it.initOptionList(view.context, styleOptionListAdapter)
            }

        val themedIconsSwitch = view.requireViewById<MaterialSwitch>(R.id.themed_icon_toggle)
@@ -137,6 +152,17 @@ object AppIconFloatingSheetBinder {
                if (isExtendibleThemeManager) {
                    themedIconEntry.isVisible = false

                    launch {
                        viewModel.styleOptions.collect { options ->
                            styleOptionListAdapter.setItems(options) {
                                val indexToFocus =
                                    options.indexOfFirst { it.isSelected.value }.coerceAtLeast(0)
                                (styleOptionList.layoutManager as LinearLayoutManager)
                                    .scrollToPosition(indexToFocus)
                            }
                        }
                    }

                    launch {
                        viewModel.tabs.collect {
                            if (it.size > 1) {
@@ -245,6 +271,39 @@ object AppIconFloatingSheetBinder {
        }
    }

    private fun createStyleOptionItemAdapter(
        context: Context,
        colorUpdateViewModel: ColorUpdateViewModel,
        shouldAnimateColor: () -> Boolean,
        lifecycleOwner: LifecycleOwner,
        backgroundDispatcher: CoroutineDispatcher,
    ): OptionItemAdapter2<IconStyle> {
        val previewIconPackageName = context.resources.getString(R.string.camera_package)
        val appIconDrawable = ShapeIconViewBinder.loadAppIcon(context, previewIconPackageName)
        return OptionItemAdapter2(
            layoutResourceId = R.layout.icon_style_option2,
            lifecycleOwner = lifecycleOwner,
            backgroundDispatcher = backgroundDispatcher,
            bindPayload = { view: View, iconStyle: IconStyle ->
                val imageView = view.findViewById(R.id.foreground) as? ImageView
                val disposableHandle =
                    imageView?.let {
                        ShapeIconViewBinder.bindPreviewIcon(
                            view = it,
                            appIconDrawable = appIconDrawable as? AdaptiveIconDrawable,
                            isThemed = iconStyle == IconStyle.MONOCHROME,
                            colorUpdateViewModel = colorUpdateViewModel,
                            shouldAnimateColor = shouldAnimateColor,
                            lifecycleOwner = lifecycleOwner,
                        )
                    }
                return@OptionItemAdapter2 disposableHandle
            },
            colorUpdateViewModel = WeakReference(colorUpdateViewModel),
            shouldAnimateColor = shouldAnimateColor,
        )
    }

    private fun createShapeOptionItemAdapter(
        colorUpdateViewModel: ColorUpdateViewModel,
        shouldAnimateColor: () -> Boolean,
@@ -264,10 +323,7 @@ object AppIconFloatingSheetBinder {
            shouldAnimateColor = shouldAnimateColor,
        )

    private fun RecyclerView.initShapeOptionList(
        context: Context,
        adapter: OptionItemAdapter2<ShapeIconViewModel>,
    ) {
    private fun RecyclerView.initOptionList(context: Context, adapter: OptionItemAdapter2<*>) {
        apply {
            this.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
            addItemDecoration(
+2 −2
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ object ShapeIconViewBinder {
    fun bindPreviewIcon(
        view: ImageView,
        appIconDrawable: AdaptiveIconDrawable?,
        shapeIcon: ShapeIconViewModel,
        shapeIcon: ShapeIconViewModel? = null,
        isThemed: Boolean,
        colorUpdateViewModel: ColorUpdateViewModel,
        shouldAnimateColor: () -> Boolean,
@@ -48,7 +48,7 @@ object ShapeIconViewBinder {
        val shapeTileDrawable =
            ShapeTileDrawable(
                context = view.context,
                path = shapeIcon.path,
                path = shapeIcon?.path,
                icon = appIconDrawable,
                isThemed = isThemed,
            )
Loading