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

Commit 0d5e6b2f authored by George Lin's avatar George Lin
Browse files

Shape options

Add shape options to the list

Test: Manually tested. See bug.
Bug: 362237825
Flag: com.android.systemui.shared.new_customization_picker_ui
Change-Id: I6c3c8841af18670ea43c0a35c98c2aa71f9afca4
parent 66db6b86
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -21,6 +21,14 @@
    android:layout_height="64dp"
    android:clipChildren="false">

    <ImageView
        android:id="@id/selection_border"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/option_item_border"
        android:alpha="0"
        android:importantForAccessibility="no" />

    <ImageView
        android:id="@id/background"
        android:layout_width="match_parent"
+19 −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.grid.ui.viewmodel

data class ShapeIconViewModel(val key: String, val path: String)
+72 −7
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.android.customization.picker.common.ui.view.SingleRowListItemSpacing
import com.android.customization.picker.grid.ui.binder.GridIconViewBinder
import com.android.customization.picker.grid.ui.viewmodel.GridIconViewModel
import com.android.customization.picker.grid.ui.viewmodel.ShapeIconViewModel
import com.android.themepicker.R
import com.android.wallpaper.customization.ui.util.ThemePickerCustomizationOptionUtil.ThemePickerHomeCustomizationOption.APP_SHAPE_GRID
import com.android.wallpaper.customization.ui.viewmodel.ShapeGridFloatingSheetHeightsViewModel
@@ -82,16 +83,24 @@ object ShapeGridFloatingSheetBinder {
                    shouldAnimateColor = { optionsViewModel.selectedOption.value == APP_SHAPE_GRID },
                )
                .also { tabs.setAdapter(it) }

        val floatingSheetContainer =
            view.requireViewById<ViewGroup>(R.id.shape_grid_floating_sheet_content_container)

        val shapeContent = view.requireViewById<View>(R.id.app_shape_container)
        val shapeOptionListAdapter =
            createShapeOptionItemAdapter(view.context, lifecycleOwner, backgroundDispatcher)
        val shapeOptionList =
            view.requireViewById<RecyclerView>(R.id.shape_options).also {
                it.initShapeOptionList(view.context, shapeOptionListAdapter)
            }

        val gridContent = view.requireViewById<View>(R.id.app_grid_container)
        val adapter = createOptionItemAdapter(view.context, lifecycleOwner, backgroundDispatcher)
        val gridOptionListAdapter =
            createGridOptionItemAdapter(view.context, lifecycleOwner, backgroundDispatcher)
        val gridOptionList =
            view.requireViewById<RecyclerView>(R.id.grid_options).also {
                it.initGridOptionList(view.context, adapter)
                it.initGridOptionList(view.context, gridOptionListAdapter)
            }

        // Get the shape content height when it is ready
@@ -168,8 +177,8 @@ object ShapeGridFloatingSheetBinder {
                }

                launch {
                    viewModel.optionItems.collect { options ->
                        adapter.setItems(options) {
                    viewModel.gridOptions.collect { options ->
                        gridOptionListAdapter.setItems(options) {
                            val indexToFocus =
                                options.indexOfFirst { it.isSelected.value }.coerceAtLeast(0)
                            (gridOptionList.layoutManager as LinearLayoutManager).scrollToPosition(
@@ -178,11 +187,68 @@ object ShapeGridFloatingSheetBinder {
                        }
                    }
                }

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

    private fun createOptionItemAdapter(
    private fun createShapeOptionItemAdapter(
        context: Context,
        lifecycleOwner: LifecycleOwner,
        backgroundDispatcher: CoroutineDispatcher,
    ): OptionItemAdapter<ShapeIconViewModel> =
        OptionItemAdapter(
            layoutResourceId = R.layout.shape_option,
            lifecycleOwner = lifecycleOwner,
            backgroundDispatcher = backgroundDispatcher,
            foregroundTintSpec =
                OptionItemBinder.TintSpec(
                    selectedColor =
                        context.getColor(com.android.wallpaper.R.color.system_on_surface),
                    unselectedColor =
                        context.getColor(com.android.wallpaper.R.color.system_on_surface),
                ),
            bindIcon = { foregroundView: View, shapeIcon: ShapeIconViewModel ->
                val imageView = foregroundView as? ImageView
                imageView?.let { ShapeIconViewBinder.bind(imageView, shapeIcon) }
            },
        )

    private fun RecyclerView.initShapeOptionList(
        context: Context,
        adapter: OptionItemAdapter<ShapeIconViewModel>,
    ) {
        apply {
            this.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
            addItemDecoration(
                SingleRowListItemSpacing(
                    edgeItemSpacePx =
                        context.resources.getDimensionPixelSize(
                            R.dimen.floating_sheet_content_horizontal_padding
                        ),
                    itemHorizontalSpacePx =
                        context.resources.getDimensionPixelSize(
                            com.android.themepicker.R.dimen
                                .floating_sheet_list_item_horizontal_space
                        ),
                )
            )
            this.adapter = adapter
        }
    }

    private fun createGridOptionItemAdapter(
        context: Context,
        lifecycleOwner: LifecycleOwner,
        backgroundDispatcher: CoroutineDispatcher,
@@ -214,8 +280,7 @@ object ShapeGridFloatingSheetBinder {
                SingleRowListItemSpacing(
                    edgeItemSpacePx =
                        context.resources.getDimensionPixelSize(
                            com.android.themepicker.R.dimen
                                .floating_sheet_content_horizontal_padding
                            R.dimen.floating_sheet_content_horizontal_padding
                        ),
                    itemHorizontalSpacePx =
                        context.resources.getDimensionPixelSize(
+27 −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.wallpaper.customization.ui.binder

import android.widget.ImageView
import com.android.customization.picker.grid.ui.viewmodel.ShapeIconViewModel
import com.android.wallpaper.customization.ui.view.ShapeTileDrawable

object ShapeIconViewBinder {
    fun bind(view: ImageView, shapeIcon: ShapeIconViewModel) {
        view.setImageDrawable(ShapeTileDrawable(shapeIcon.path))
    }
}
+71 −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.wallpaper.customization.ui.view

import android.graphics.Canvas
import android.graphics.ColorFilter
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.Path
import android.graphics.PixelFormat
import android.graphics.Rect
import android.graphics.drawable.Drawable
import androidx.core.graphics.PathParser

/**
 * Drawable that draws a shape tile with a given path.
 *
 * @param path Path of the shape assuming drawing on a 100x100 canvas.
 */
class ShapeTileDrawable(path: String) : Drawable() {

    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    private val path = PathParser.createPathFromPathData(path)
    // The path scaled with regard to the update of drawable bounds
    private val scaledPath = Path(this.path)
    private val scaleMatrix = Matrix()

    override fun onBoundsChange(bounds: Rect) {
        super.onBoundsChange(bounds)
        scaleMatrix.setScale(bounds.width() / PATH_SIZE, bounds.height() / PATH_SIZE)
        path.transform(scaleMatrix, scaledPath)
    }

    override fun draw(canvas: Canvas) {
        canvas.drawPath(scaledPath, paint)
    }

    override fun setAlpha(alpha: Int) {
        paint.alpha = alpha
    }

    override fun setColorFilter(colorFilter: ColorFilter?) {
        paint.setColorFilter(colorFilter)
    }

    @Deprecated(
        "getOpacity() is deprecated",
        ReplaceWith("setAlpha(int)", "android.graphics.drawable.Drawable"),
    )
    override fun getOpacity(): Int {
        return PixelFormat.TRANSLUCENT
    }

    companion object {
        const val PATH_SIZE = 100f
    }
}
Loading