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

Commit e72160b1 authored by Chaohui Wang's avatar Chaohui Wang Committed by Android (Google) Code Review
Browse files

Merge "Add Spinner for SpaLib"

parents b60df67d 6bd37b86
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -24,6 +24,7 @@ import com.android.settingslib.spa.gallery.page.PreferencePageProvider
import com.android.settingslib.spa.gallery.page.SettingsPagerPageProvider
import com.android.settingslib.spa.gallery.page.SettingsPagerPageProvider
import com.android.settingslib.spa.gallery.page.SliderPageProvider
import com.android.settingslib.spa.gallery.page.SliderPageProvider
import com.android.settingslib.spa.gallery.page.SwitchPreferencePageProvider
import com.android.settingslib.spa.gallery.page.SwitchPreferencePageProvider
import com.android.settingslib.spa.gallery.ui.SpinnerPageProvider


val galleryPageProviders = SettingsPageProviderRepository(
val galleryPageProviders = SettingsPageProviderRepository(
    allPagesList = listOf(
    allPagesList = listOf(
@@ -32,6 +33,7 @@ val galleryPageProviders = SettingsPageProviderRepository(
        SwitchPreferencePageProvider,
        SwitchPreferencePageProvider,
        ArgumentPageProvider,
        ArgumentPageProvider,
        SliderPageProvider,
        SliderPageProvider,
        SpinnerPageProvider,
        SettingsPagerPageProvider,
        SettingsPagerPageProvider,
        FooterPageProvider,
        FooterPageProvider,
    ),
    ),
+2 −0
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@ import com.android.settingslib.spa.gallery.page.PreferencePageProvider
import com.android.settingslib.spa.gallery.page.SettingsPagerPageProvider
import com.android.settingslib.spa.gallery.page.SettingsPagerPageProvider
import com.android.settingslib.spa.gallery.page.SliderPageProvider
import com.android.settingslib.spa.gallery.page.SliderPageProvider
import com.android.settingslib.spa.gallery.page.SwitchPreferencePageProvider
import com.android.settingslib.spa.gallery.page.SwitchPreferencePageProvider
import com.android.settingslib.spa.gallery.ui.SpinnerPageProvider
import com.android.settingslib.spa.widget.scaffold.HomeScaffold
import com.android.settingslib.spa.widget.scaffold.HomeScaffold


object HomePageProvider : SettingsPageProvider {
object HomePageProvider : SettingsPageProvider {
@@ -48,6 +49,7 @@ private fun HomePage() {
        ArgumentPageProvider.EntryItem(stringParam = "foo", intParam = 0)
        ArgumentPageProvider.EntryItem(stringParam = "foo", intParam = 0)


        SliderPageProvider.EntryItem()
        SliderPageProvider.EntryItem()
        SpinnerPageProvider.EntryItem()
        SettingsPagerPageProvider.EntryItem()
        SettingsPagerPageProvider.EntryItem()
        FooterPageProvider.EntryItem()
        FooterPageProvider.EntryItem()
    }
    }
+75 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2022 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.settingslib.spa.gallery.ui

import android.os.Bundle
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.tooling.preview.Preview
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.framework.theme.SettingsTheme
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
import com.android.settingslib.spa.widget.ui.Spinner

private const val TITLE = "Sample Spinner"

object SpinnerPageProvider : SettingsPageProvider {
    override val name = "Spinner"

    @Composable
    override fun Page(arguments: Bundle?) {
        SpinnerPage()
    }

    @Composable
    fun EntryItem() {
        Preference(object : PreferenceModel {
            override val title = TITLE
            override val onClick = navigator(name)
        })
    }
}

@Composable
private fun SpinnerPage() {
    RegularScaffold(title = TITLE) {
        val selectedIndex = rememberSaveable { mutableStateOf(0) }
        Spinner(
            options = (1..3).map { "Option $it" },
            selectedIndex = selectedIndex.value,
            setIndex = { selectedIndex.value = it },
        )
        Preference(object : PreferenceModel {
            override val title = "Selected index"
            override val summary = remember { derivedStateOf { selectedIndex.value.toString() } }
        })
    }
}

@Preview(showBackground = true)
@Composable
private fun SpinnerPagePreview() {
    SettingsTheme {
        SpinnerPage()
    }
}
+12 −0
Original line number Original line Diff line number Diff line
@@ -31,6 +31,10 @@ data class SettingsColorScheme(
    val secondaryText: Color = Color.Unspecified,
    val secondaryText: Color = Color.Unspecified,
    val primaryContainer: Color = Color.Unspecified,
    val primaryContainer: Color = Color.Unspecified,
    val onPrimaryContainer: Color = Color.Unspecified,
    val onPrimaryContainer: Color = Color.Unspecified,
    val spinnerHeaderContainer: Color = Color.Unspecified,
    val onSpinnerHeaderContainer: Color = Color.Unspecified,
    val spinnerItemContainer: Color = Color.Unspecified,
    val onSpinnerItemContainer: Color = Color.Unspecified,
)
)


internal val LocalColorScheme = staticCompositionLocalOf { SettingsColorScheme() }
internal val LocalColorScheme = staticCompositionLocalOf { SettingsColorScheme() }
@@ -65,6 +69,10 @@ private fun dynamicLightColorScheme(context: Context): SettingsColorScheme {
        secondaryText = tonalPalette.neutralVariant30,
        secondaryText = tonalPalette.neutralVariant30,
        primaryContainer = tonalPalette.primary90,
        primaryContainer = tonalPalette.primary90,
        onPrimaryContainer = tonalPalette.neutral10,
        onPrimaryContainer = tonalPalette.neutral10,
        spinnerHeaderContainer = tonalPalette.primary90,
        onSpinnerHeaderContainer = tonalPalette.neutral10,
        spinnerItemContainer = tonalPalette.secondary90,
        onSpinnerItemContainer = tonalPalette.neutralVariant30,
    )
    )
}
}


@@ -87,5 +95,9 @@ private fun dynamicDarkColorScheme(context: Context): SettingsColorScheme {
        secondaryText = tonalPalette.neutralVariant80,
        secondaryText = tonalPalette.neutralVariant80,
        primaryContainer = tonalPalette.secondary90,
        primaryContainer = tonalPalette.secondary90,
        onPrimaryContainer = tonalPalette.neutral10,
        onPrimaryContainer = tonalPalette.neutral10,
        spinnerHeaderContainer = tonalPalette.primary90,
        onSpinnerHeaderContainer = tonalPalette.neutral10,
        spinnerItemContainer = tonalPalette.secondary90,
        onSpinnerItemContainer = tonalPalette.neutralVariant30,
    )
    )
}
}
+131 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2022 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.settingslib.spa.widget.ui

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.ArrowDropDown
import androidx.compose.material.icons.outlined.ArrowDropUp
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.framework.theme.SettingsTheme

@Composable
fun Spinner(options: List<String>, selectedIndex: Int, setIndex: (index: Int) -> Unit) {
    if (options.isEmpty()) {
        return
    }

    var expanded by rememberSaveable { mutableStateOf(false) }

    Box(
        modifier = Modifier
            .padding(SettingsDimension.itemPadding)
            .selectableGroup(),
    ) {
        val contentPadding = PaddingValues(horizontal = SettingsDimension.itemPaddingEnd)
        Button(
            onClick = { expanded = true },
            modifier = Modifier.height(36.dp),
            colors = ButtonDefaults.buttonColors(
                containerColor = SettingsTheme.colorScheme.spinnerHeaderContainer,
                contentColor = SettingsTheme.colorScheme.onSpinnerHeaderContainer,
            ),
            contentPadding = contentPadding,
        ) {
            SpinnerText(options[selectedIndex])
            Icon(
                imageVector = when {
                    expanded -> Icons.Outlined.ArrowDropUp
                    else -> Icons.Outlined.ArrowDropDown
                },
                contentDescription = null,
            )
        }
        DropdownMenu(
            expanded = expanded,
            onDismissRequest = { expanded = false },
            modifier = Modifier.background(SettingsTheme.colorScheme.spinnerItemContainer),
            offset = DpOffset(x = 0.dp, y = 4.dp),
        ) {
            options.forEachIndexed { index, option ->
                DropdownMenuItem(
                    text = {
                        SpinnerText(
                            text = option,
                            modifier = Modifier.padding(end = 24.dp),
                            color = SettingsTheme.colorScheme.onSpinnerItemContainer,
                        )
                    },
                    onClick = {
                        expanded = false
                        setIndex(index)
                    },
                    contentPadding = contentPadding,
                )
            }
        }
    }
}

@Composable
private fun SpinnerText(
    text: String,
    modifier: Modifier = Modifier,
    color: Color = Color.Unspecified,
) {
    Text(
        text = text,
        modifier = modifier.padding(end = SettingsDimension.itemPaddingEnd),
        color = color,
        style = MaterialTheme.typography.labelLarge,
    )
}

@Preview(showBackground = true)
@Composable
private fun SpinnerPreview() {
    SettingsTheme {
        var selectedIndex by rememberSaveable { mutableStateOf(0) }
        Spinner(
            options = (1..3).map { "Option $it" },
            selectedIndex = selectedIndex,
            setIndex = { selectedIndex = it },
        )
    }
}
Loading