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

Commit e56d4415 authored by George Lin's avatar George Lin
Browse files

Introduce the divider for the option list

The divider is to divider different groups of option items

Test: Manually tested. See bug.
Bug: 391610027
Flag: com.android.systemui.shared.new_customization_picker_ui
Change-Id: I64aafffa9292be53288c378dd8d7cffcc5c9dfa1
parent 11e7da85
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
     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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <size android:width="2dp" android:height="28dp" />
    <corners android:radius="1dp" />
    <solid android:color="@color/system_on_surface_variant" />
</shape>
+1 −1
Original line number Diff line number Diff line
@@ -186,7 +186,7 @@
    <dimen name="floating_sheet_tab_toolbar_vertical_margin">8dp</dimen>
    <dimen name="floating_sheet_tab_clock_font_toolbar_top_margin">16dp</dimen>
    <dimen name="floating_sheet_tab_clock_font_toolbar_bottom_margin">8dp</dimen>
    <dimen name="floating_sheet_list_item_horizontal_space">4dp</dimen>
    <dimen name="floating_sheet_list_item_horizontal_space">8dp</dimen>
    <dimen name="floating_sheet_grid_list_item_horizontal_space">10dp</dimen>
    <dimen name="floating_sheet_list_item_vertical_space">4dp</dimen>
    <dimen name="floating_sheet_clock_style_option_size">80dp</dimen>
+65 −13
Original line number Diff line number Diff line
@@ -15,15 +15,27 @@
 */
package com.android.customization.picker.common.ui.view

import android.graphics.Canvas
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.view.View
import androidx.recyclerview.widget.RecyclerView

/** Item spacing used by the horizontal RecyclerView with only 1 row. */
/**
 * Item spacing used by the horizontal RecyclerView with only 1 row.
 *
 * @param dividerIndex Index of the item that a divider will be drawn on the right.
 */
class SingleRowListItemSpacing(
    private val edgeItemSpacePx: Int,
    private val itemHorizontalSpacePx: Int,
    private val dividerIndex: Int = -1,
    private val dividerDrawable: Drawable? = null,
) : RecyclerView.ItemDecoration() {

    private val dividerWidth = dividerDrawable?.intrinsicWidth ?: 0
    private val dividerHeight = dividerDrawable?.intrinsicHeight ?: 0

    override fun getItemOffsets(
        outRect: Rect,
        view: View,
@@ -33,18 +45,58 @@ class SingleRowListItemSpacing(
        val itemIndex = parent.getChildAdapterPosition(view)
        val itemCount = parent.adapter?.itemCount ?: 0
        val isRtl = parent.layoutManager?.layoutDirection == View.LAYOUT_DIRECTION_RTL
        when (itemIndex) {
            0 -> {
                outRect.left = if (!isRtl) edgeItemSpacePx else itemHorizontalSpacePx
                outRect.right = if (isRtl) edgeItemSpacePx else itemHorizontalSpacePx

        val isFirstItem = itemIndex == 0
        val startSpace = if (isFirstItem) edgeItemSpacePx else 0

        val isLastItem = itemIndex == itemCount - 1
        val isDivider = itemIndex == dividerIndex && dividerDrawable != null && dividerHeight > 0
        val itemSpaceWithDividerConsideration =
            if (isDivider) itemHorizontalSpacePx * 2 + dividerWidth else itemHorizontalSpacePx
        val endSpace = if (isLastItem) edgeItemSpacePx else itemSpaceWithDividerConsideration

        if (isRtl) {
            outRect.right = startSpace
            outRect.left = endSpace
        } else {
            outRect.left = startSpace
            outRect.right = endSpace
        }
    }
            itemCount - 1 -> {
                outRect.right = if (!isRtl) edgeItemSpacePx else itemHorizontalSpacePx
                outRect.left = if (isRtl) edgeItemSpacePx else itemHorizontalSpacePx

    override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        super.onDrawOver(c, parent, state)

        if (dividerDrawable == null || dividerHeight <= 0) return

        val parentPaddedHeight = parent.height - parent.paddingTop - parent.paddingBottom
        val actualDrawableHeight = minOf(dividerHeight, parentPaddedHeight)
        val dividerTop = parent.paddingTop + (parentPaddedHeight - actualDrawableHeight) / 2
        val dividerBottom = dividerTop + actualDrawableHeight

        val isRtl = parent.layoutManager?.layoutDirection == View.LAYOUT_DIRECTION_RTL

        for (i in 0 until parent.childCount) {
            val child = parent.getChildAt(i)
            val position = parent.getChildAdapterPosition(child)

            if (position == RecyclerView.NO_POSITION) continue

            if (position == dividerIndex) {
                val params = child.layoutParams as RecyclerView.LayoutParams
                val dividerLeft: Int
                val dividerRight: Int
                if (isRtl) {
                    dividerRight = child.left - params.leftMargin - itemHorizontalSpacePx
                    dividerLeft = dividerRight - dividerWidth
                } else {
                    dividerLeft = child.right + params.rightMargin + itemHorizontalSpacePx
                    dividerRight = dividerLeft + dividerWidth
                }
            else -> {
                outRect.left = itemHorizontalSpacePx
                outRect.right = itemHorizontalSpacePx
                dividerDrawable.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom)
                dividerDrawable.draw(c)
                // Break as we only want to draw one such divider.
                break
            }
        }
    }
+21 −10
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.view.ViewGroup
import android.view.ViewTreeObserver.OnGlobalLayoutListener
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
@@ -45,6 +46,7 @@ import com.android.wallpaper.customization.ui.viewmodel.ClockFloatingSheetHeight
import com.android.wallpaper.customization.ui.viewmodel.ClockPickerViewModel.ClockStyleModel
import com.android.wallpaper.customization.ui.viewmodel.ClockPickerViewModel.Tab
import com.android.wallpaper.customization.ui.viewmodel.ThemePickerCustomizationOptionsViewModel
import com.android.wallpaper.picker.category.ui.binder.SectionsBinder.removeItemDecorations
import com.android.wallpaper.picker.customization.ui.binder.ColorUpdateBinder
import com.android.wallpaper.picker.customization.ui.view.FloatingToolbar
import com.android.wallpaper.picker.customization.ui.view.adapter.FloatingToolbarTabAdapter
@@ -350,10 +352,29 @@ object ClockFloatingSheetBinder {
                launch {
                    viewModel.clockStyleOptions.collect { styleOptions ->
                        clockStyleAdapter.setItems(styleOptions) {
                            val dividerIndex =
                                styleOptions.indexOfLast { it.payload?.hasPresets ?: false }
                            var indexToFocus = styleOptions.indexOfFirst { it.isSelected.value }
                            indexToFocus = if (indexToFocus < 0) 0 else indexToFocus
                            (clockStyleList.layoutManager as LinearLayoutManager)
                                .scrollToPositionWithOffset(indexToFocus, 0)
                            clockStyleList.removeItemDecorations()
                            clockStyleList.addItemDecoration(
                                SingleRowListItemSpacing(
                                    view.context.resources.getDimensionPixelSize(
                                        R.dimen.floating_sheet_content_horizontal_padding
                                    ),
                                    view.context.resources.getDimensionPixelSize(
                                        R.dimen.floating_sheet_list_item_horizontal_space
                                    ),
                                    dividerIndex = dividerIndex,
                                    dividerDrawable =
                                        ContextCompat.getDrawable(
                                            view.context,
                                            R.drawable.option_list_grouping_divider,
                                        ),
                                )
                            )
                        }
                    }
                }
@@ -466,16 +487,6 @@ object ClockFloatingSheetBinder {
    ) {
        this.adapter = adapter
        layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
        addItemDecoration(
            SingleRowListItemSpacing(
                context.resources.getDimensionPixelSize(
                    R.dimen.floating_sheet_content_horizontal_padding
                ),
                context.resources.getDimensionPixelSize(
                    R.dimen.floating_sheet_list_item_horizontal_space
                ),
            )
        )
    }

    private fun createClockColorOptionItemAdapter(
+8 −7
Original line number Diff line number Diff line
@@ -148,11 +148,11 @@ constructor(
            overridingClock != null && overridingClock.clockId != selectedClock.clockId
        }

    suspend fun getIsShadeLayoutWide() = clockPickerInteractor.getIsShadeLayoutWide()
    private suspend fun getIsShadeLayoutWide() = clockPickerInteractor.getIsShadeLayoutWide()

    suspend fun getUdfpsLocation() = clockPickerInteractor.getUdfpsLocation()
    private suspend fun getUdfpsLocation() = clockPickerInteractor.getUdfpsLocation()

    data class ClockStyleModel(val thumbnail: Drawable)
    data class ClockStyleModel(val thumbnail: Drawable, val hasPresets: Boolean)

    @OptIn(ExperimentalCoroutinesApi::class)
    val clockStyleOptions: StateFlow<List<OptionItemViewModel2<ClockStyleModel>>> =
@@ -162,8 +162,8 @@ constructor(
                delay(CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
                val allClockMap = allClocks.groupBy { it.axisPresetConfig != null }
                buildList {
                    allClockMap[true]?.map { add(it.toOption(resources)) }
                    allClockMap[false]?.map { add(it.toOption(resources)) }
                    allClockMap[true]?.map { add(it.toOption(resources, true)) }
                    allClockMap[false]?.map { add(it.toOption(resources, false)) }
                }
            }
            // makes sure that the operations above this statement are executed on I/O dispatcher
@@ -249,14 +249,15 @@ constructor(
        }

    private suspend fun ClockMetadataModel.toOption(
        resources: Resources
        resources: Resources,
        hasPresets: Boolean,
    ): OptionItemViewModel2<ClockStyleModel> {
        val isSelectedFlow = previewingClock.map { it.clockId == clockId }.stateIn(viewModelScope)
        val contentDescription =
            resources.getString(R.string.select_clock_action_description, description)
        return OptionItemViewModel2<ClockStyleModel>(
            key = MutableStateFlow(clockId) as StateFlow<String>,
            payload = ClockStyleModel(thumbnail = thumbnail),
            payload = ClockStyleModel(thumbnail = thumbnail, hasPresets = hasPresets),
            text = Text.Loaded(contentDescription),
            isTextUserVisible = false,
            isSelected = isSelectedFlow,