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

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

Merge "Do not expand when SettingsDropdownBox disabled" into main

parents 0758f426 4803b1d5
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -27,7 +27,7 @@ import com.android.settingslib.spa.gallery.chart.ChartPageProvider
import com.android.settingslib.spa.gallery.dialog.DialogMainPageProvider
import com.android.settingslib.spa.gallery.dialog.DialogMainPageProvider
import com.android.settingslib.spa.gallery.dialog.NavDialogProvider
import com.android.settingslib.spa.gallery.dialog.NavDialogProvider
import com.android.settingslib.spa.gallery.editor.EditorMainPageProvider
import com.android.settingslib.spa.gallery.editor.EditorMainPageProvider
import com.android.settingslib.spa.gallery.editor.SettingsExposedDropdownMenuBoxPageProvider
import com.android.settingslib.spa.gallery.editor.SettingsDropdownBoxPageProvider
import com.android.settingslib.spa.gallery.editor.SettingsDropdownCheckBoxProvider
import com.android.settingslib.spa.gallery.editor.SettingsDropdownCheckBoxProvider
import com.android.settingslib.spa.gallery.home.HomePageProvider
import com.android.settingslib.spa.gallery.home.HomePageProvider
import com.android.settingslib.spa.gallery.itemList.ItemListPageProvider
import com.android.settingslib.spa.gallery.itemList.ItemListPageProvider
@@ -99,7 +99,7 @@ class GallerySpaEnvironment(context: Context) : SpaEnvironment(context) {
                OperateListPageProvider,
                OperateListPageProvider,
                EditorMainPageProvider,
                EditorMainPageProvider,
                SettingsOutlinedTextFieldPageProvider,
                SettingsOutlinedTextFieldPageProvider,
                SettingsExposedDropdownMenuBoxPageProvider,
                SettingsDropdownBoxPageProvider,
                SettingsDropdownCheckBoxProvider,
                SettingsDropdownCheckBoxProvider,
                SettingsTextFieldPasswordPageProvider,
                SettingsTextFieldPasswordPageProvider,
                SearchScaffoldPageProvider,
                SearchScaffoldPageProvider,
+1 −1
Original line number Original line Diff line number Diff line
@@ -35,7 +35,7 @@ object EditorMainPageProvider : SettingsPageProvider {
        return listOf(
        return listOf(
            SettingsOutlinedTextFieldPageProvider.buildInjectEntry().setLink(fromPage = owner)
            SettingsOutlinedTextFieldPageProvider.buildInjectEntry().setLink(fromPage = owner)
                .build(),
                .build(),
            SettingsExposedDropdownMenuBoxPageProvider.buildInjectEntry().setLink(fromPage = owner)
            SettingsDropdownBoxPageProvider.buildInjectEntry().setLink(fromPage = owner)
                .build(),
                .build(),
            SettingsDropdownCheckBoxProvider.buildInjectEntry().setLink(fromPage = owner)
            SettingsDropdownCheckBoxProvider.buildInjectEntry().setLink(fromPage = owner)
                .build(),
                .build(),
+40 −15
Original line number Original line Diff line number Diff line
@@ -28,16 +28,15 @@ import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.framework.theme.SettingsTheme
import com.android.settingslib.spa.framework.theme.SettingsTheme
import com.android.settingslib.spa.widget.editor.SettingsExposedDropdownMenuBox
import com.android.settingslib.spa.widget.editor.SettingsDropdownBox
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
import com.android.settingslib.spa.widget.scaffold.RegularScaffold


private const val TITLE = "Sample SettingsExposedDropdownMenuBox"
private const val TITLE = "Sample SettingsDropdownBox"


object SettingsExposedDropdownMenuBoxPageProvider : SettingsPageProvider {
object SettingsDropdownBoxPageProvider : SettingsPageProvider {
    override val name = "SettingsExposedDropdownMenuBox"
    override val name = "SettingsDropdownBox"
    private const val exposedDropdownMenuBoxLabel = "ExposedDropdownMenuBoxLabel"


    override fun getTitle(arguments: Bundle?): String {
    override fun getTitle(arguments: Bundle?): String {
        return TITLE
        return TITLE
@@ -45,16 +44,42 @@ object SettingsExposedDropdownMenuBoxPageProvider : SettingsPageProvider {


    @Composable
    @Composable
    override fun Page(arguments: Bundle?) {
    override fun Page(arguments: Bundle?) {
        var selectedItem by remember { mutableIntStateOf(-1) }
        val options = listOf("item1", "item2", "item3")
        RegularScaffold(title = TITLE) {
        RegularScaffold(title = TITLE) {
            SettingsExposedDropdownMenuBox(
            Regular()
                label = exposedDropdownMenuBoxLabel,
            NotEnabled()
                options = options,
            Empty()
        }
    }

    @Composable
    private fun Regular() {
        var selectedItem by remember { mutableIntStateOf(-1) }
        SettingsDropdownBox(
            label = "SettingsDropdownBox",
            options = listOf("item1", "item2", "item3"),
            selectedOptionIndex = selectedItem,
        ) { selectedItem = it }
    }

    @Composable
    private fun NotEnabled() {
        var selectedItem by remember { mutableIntStateOf(0) }
        SettingsDropdownBox(
            label = "Not enabled",
            options = listOf("item1", "item2", "item3"),
            enabled = false,
            selectedOptionIndex = selectedItem,
            selectedOptionIndex = selectedItem,
                enabled = true,
        ) { selectedItem = it }
                onselectedOptionTextChange = { selectedItem = it })
    }
    }

    @Composable
    private fun Empty() {
        var selectedItem by remember { mutableIntStateOf(-1) }
        SettingsDropdownBox(
            label = "Empty",
            options = emptyList(),
            selectedOptionIndex = selectedItem,
        ) { selectedItem = it }
    }
    }


    fun buildInjectEntry(): SettingsEntryBuilder {
    fun buildInjectEntry(): SettingsEntryBuilder {
@@ -70,8 +95,8 @@ object SettingsExposedDropdownMenuBoxPageProvider : SettingsPageProvider {


@Preview(showBackground = true)
@Preview(showBackground = true)
@Composable
@Composable
private fun SettingsExposedDropdownMenuBoxPagePreview() {
private fun SettingsDropdownBoxPagePreview() {
    SettingsTheme {
    SettingsTheme {
        SettingsExposedDropdownMenuBoxPageProvider.Page(null)
        SettingsDropdownBoxPageProvider.Page(null)
    }
    }
}
}
+32 −55
Original line number Original line Diff line number Diff line
/*
/*
 * Copyright (C) 2023 The Android Open Source Project
 * Copyright (C) 2024 The Android Open Source Project
 *
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * you may not use this file except in compliance with the License.
@@ -19,7 +19,6 @@ package com.android.settingslib.spa.widget.editor
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.width
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.ExposedDropdownMenuDefaults
@@ -31,80 +30,58 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.dp
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.framework.theme.SettingsTheme


@Composable
internal interface DropdownTextBoxScope {
    fun dismiss()
}

@OptIn(ExperimentalMaterial3Api::class)
@OptIn(ExperimentalMaterial3Api::class)
fun SettingsExposedDropdownMenuBox(
@Composable
internal fun DropdownTextBox(
    label: String,
    label: String,
    options: List<String>,
    text: String,
    selectedOptionIndex: Int,
    enabled: Boolean = true,
    enabled: Boolean,
    errorMessage: String? = null,
    onselectedOptionTextChange: (Int) -> Unit,
    content: @Composable DropdownTextBoxScope.() -> Unit,
) {
) {
    var expanded by remember { mutableStateOf(false) }
    var expanded by remember { mutableStateOf(false) }
    val scope = remember {
        object : DropdownTextBoxScope {
            override fun dismiss() {
                expanded = false
            }
        }
    }
    ExposedDropdownMenuBox(
    ExposedDropdownMenuBox(
        expanded = expanded,
        expanded = expanded,
        onExpandedChange = { expanded = it },
        onExpandedChange = { expanded = enabled && it },
        modifier = Modifier
        modifier = Modifier
            .width(350.dp)
            .padding(SettingsDimension.menuFieldPadding)
            .padding(SettingsDimension.menuFieldPadding),
            .width(Width),
    ) {
    ) {
        OutlinedTextField(
        OutlinedTextField(
            // The `menuAnchor` modifier must be passed to the text field for correctness.
            // The `menuAnchor` modifier must be passed to the text field for correctness.
            modifier = Modifier
            modifier = Modifier
                .menuAnchor()
                .menuAnchor()
                .fillMaxWidth(),
                .fillMaxWidth(),
            value = options.getOrElse(selectedOptionIndex) { "" },
            value = text,
            onValueChange = { },
            onValueChange = { },
            label = { Text(text = label) },
            label = { Text(text = label) },
            trailingIcon = {
            trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
                ExposedDropdownMenuDefaults.TrailingIcon(
                    expanded = expanded
                )
            },
            singleLine = true,
            singleLine = true,
            readOnly = true,
            readOnly = true,
            enabled = enabled
            enabled = enabled,
            isError = errorMessage != null,
            supportingText = errorMessage?.let { { Text(text = it) } },
        )
        )
        if (options.isNotEmpty()) {
        ExposedDropdownMenu(
        ExposedDropdownMenu(
            expanded = expanded,
            expanded = expanded,
                modifier = Modifier
            modifier = Modifier.width(Width),
                    .fillMaxWidth(),
            onDismissRequest = { expanded = false },
            onDismissRequest = { expanded = false },
            ) {
        ) { scope.content() }
                options.forEach { option ->
                    DropdownMenuItem(
                        text = { Text(option) },
                        onClick = {
                            onselectedOptionTextChange(options.indexOf(option))
                            expanded = false
                        },
                        contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
                    )
                }
            }
        }
    }
    }
}
}


@Preview
private val Width = 310.dp
@Composable
private fun SettingsExposedDropdownMenuBoxsPreview() {
    val item1 = "item1"
    val item2 = "item2"
    val item3 = "item3"
    val options = listOf(item1, item2, item3)
    SettingsTheme {
        SettingsExposedDropdownMenuBox(
            label = "ExposedDropdownMenuBoxLabel",
            options = options,
            selectedOptionIndex = 0,
            enabled = true,
            onselectedOptionTextChange = {})
    }
}
 No newline at end of file
+69 −0
Original line number Original line 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.settingslib.spa.widget.editor

import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.android.settingslib.spa.framework.theme.SettingsTheme

@Composable
@OptIn(ExperimentalMaterial3Api::class)
fun SettingsDropdownBox(
    label: String,
    options: List<String>,
    selectedOptionIndex: Int,
    enabled: Boolean = true,
    onSelectedOptionChange: (Int) -> Unit,
) {
    DropdownTextBox(
        label = label,
        text = options.getOrElse(selectedOptionIndex) { "" },
        enabled = enabled && options.isNotEmpty(),
    ) {
        options.forEachIndexed { index, option ->
            DropdownMenuItem(
                text = { Text(option) },
                onClick = {
                    dismiss()
                    onSelectedOptionChange(index)
                },
                contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
            )
        }
    }
}

@Preview
@Composable
private fun SettingsDropdownBoxPreview() {
    val item1 = "item1"
    val item2 = "item2"
    val item3 = "item3"
    val options = listOf(item1, item2, item3)
    SettingsTheme {
        SettingsDropdownBox(
            label = "ExposedDropdownMenuBoxLabel",
            options = options,
            selectedOptionIndex = 0,
            enabled = true,
        ) {}
    }
}
Loading