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

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

Merge "Support dynamic spinner options for App List"

parents 90bde743 9162ec18
Loading
Loading
Loading
Loading
+9 −6
Original line number Diff line number Diff line
@@ -19,9 +19,11 @@ 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.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.tooling.preview.Preview
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPage
@@ -32,6 +34,7 @@ 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
import com.android.settingslib.spa.widget.ui.SpinnerOption

private const val TITLE = "Sample Spinner"

@@ -55,16 +58,16 @@ object SpinnerPageProvider : SettingsPageProvider {
    @Composable
    override fun Page(arguments: Bundle?) {
        RegularScaffold(title = getTitle(arguments)) {
            val selectedIndex = rememberSaveable { mutableStateOf(0) }
            var selectedId by rememberSaveable { mutableStateOf(1) }
            Spinner(
                options = (1..3).map { "Option $it" },
                selectedIndex = selectedIndex.value,
                setIndex = { selectedIndex.value = it },
                options = (1..3).map { SpinnerOption(id = it, text = "Option $it") },
                selectedId = selectedId,
                setId = { selectedId = it },
            )
            Preference(object : PreferenceModel {
                override val title = "Selected index"
                override val title = "Selected id"
                override val summary = remember {
                    derivedStateOf { selectedIndex.value.toString() }
                    derivedStateOf { selectedId.toString() }
                }
            })
        }
+4 −3
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.settingslib.spa.screenshot

import com.android.settingslib.spa.widget.ui.Spinner
import com.android.settingslib.spa.widget.ui.SpinnerOption
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -43,9 +44,9 @@ class SpinnerScreenshotTest(emulationSpec: DeviceEmulationSpec) {
    fun test() {
        screenshotRule.screenshotTest("spinner") {
            Spinner(
                options = (1..3).map { "Option $it" },
                selectedIndex = 0,
                setIndex = {},
                options = (1..3).map { SpinnerOption(id = it, text = "Option $it") },
                selectedId = 1,
                setId = {},
            )
        }
    }
+16 −11
Original line number Diff line number Diff line
@@ -45,8 +45,13 @@ import androidx.compose.ui.unit.dp
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.framework.theme.SettingsTheme

data class SpinnerOption(
    val id: Int,
    val text: String,
)

@Composable
fun Spinner(options: List<String>, selectedIndex: Int, setIndex: (index: Int) -> Unit) {
fun Spinner(options: List<SpinnerOption>, selectedId: Int?, setId: (id: Int) -> Unit) {
    if (options.isEmpty()) {
        return
    }
@@ -68,7 +73,7 @@ fun Spinner(options: List<String>, selectedIndex: Int, setIndex: (index: Int) ->
            ),
            contentPadding = contentPadding,
        ) {
            SpinnerText(options[selectedIndex])
            SpinnerText(options.find { it.id == selectedId })
            Icon(
                imageVector = when {
                    expanded -> Icons.Outlined.ArrowDropUp
@@ -83,18 +88,18 @@ fun Spinner(options: List<String>, selectedIndex: Int, setIndex: (index: Int) ->
            modifier = Modifier.background(SettingsTheme.colorScheme.spinnerItemContainer),
            offset = DpOffset(x = 0.dp, y = 4.dp),
        ) {
            options.forEachIndexed { index, option ->
            for (option in options) {
                DropdownMenuItem(
                    text = {
                        SpinnerText(
                            text = option,
                            option = option,
                            modifier = Modifier.padding(end = 24.dp),
                            color = SettingsTheme.colorScheme.onSpinnerItemContainer,
                        )
                    },
                    onClick = {
                        expanded = false
                        setIndex(index)
                        setId(option.id)
                    },
                    contentPadding = contentPadding,
                )
@@ -105,12 +110,12 @@ fun Spinner(options: List<String>, selectedIndex: Int, setIndex: (index: Int) ->

@Composable
private fun SpinnerText(
    text: String,
    option: SpinnerOption?,
    modifier: Modifier = Modifier,
    color: Color = Color.Unspecified,
) {
    Text(
        text = text,
        text = option?.text ?: "",
        modifier = modifier.padding(end = SettingsDimension.itemPaddingEnd),
        color = color,
        style = MaterialTheme.typography.labelLarge,
@@ -121,11 +126,11 @@ private fun SpinnerText(
@Composable
private fun SpinnerPreview() {
    SettingsTheme {
        var selectedIndex by rememberSaveable { mutableStateOf(0) }
        var selectedId by rememberSaveable { mutableStateOf(1) }
        Spinner(
            options = (1..3).map { "Option $it" },
            selectedIndex = selectedIndex,
            setIndex = { selectedIndex = it },
            options = (1..3).map { SpinnerOption(id = it, text = "Option $it") },
            selectedId = selectedId,
            setId = { selectedId = it },
        )
    }
}
+10 −10
Original line number Diff line number Diff line
@@ -36,28 +36,28 @@ class SpinnerTest {

    @Test
    fun spinner_initialState() {
        var selectedIndex by mutableStateOf(0)
        var selectedId by mutableStateOf(1)
        composeTestRule.setContent {
            Spinner(
                options = (1..3).map { "Option $it" },
                selectedIndex = selectedIndex,
                setIndex = { selectedIndex = it },
                options = (1..3).map { SpinnerOption(id = it, text = "Option $it") },
                selectedId = selectedId,
                setId = { selectedId = it },
            )
        }

        composeTestRule.onNodeWithText("Option 1").assertIsDisplayed()
        composeTestRule.onNodeWithText("Option 2").assertDoesNotExist()
        assertThat(selectedIndex).isEqualTo(0)
        assertThat(selectedId).isEqualTo(1)
    }

    @Test
    fun spinner_canChangeState() {
        var selectedIndex by mutableStateOf(0)
        var selectedId by mutableStateOf(1)
        composeTestRule.setContent {
            Spinner(
                options = (1..3).map { "Option $it" },
                selectedIndex = selectedIndex,
                setIndex = { selectedIndex = it },
                options = (1..3).map { SpinnerOption(id = it, text = "Option $it") },
                selectedId = selectedId,
                setId = { selectedId = it },
            )
        }

@@ -66,6 +66,6 @@ class SpinnerTest {

        composeTestRule.onNodeWithText("Option 1").assertDoesNotExist()
        composeTestRule.onNodeWithText("Option 2").assertIsDisplayed()
        assertThat(selectedIndex).isEqualTo(1)
        assertThat(selectedId).isEqualTo(2)
    }
}
+5 −2
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ import android.content.pm.ApplicationInfo
import android.icu.text.CollationKey
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import com.android.settingslib.spa.widget.ui.SpinnerOption
import com.android.settingslib.spaprivileged.template.app.AppListItem
import com.android.settingslib.spaprivileged.template.app.AppListItemModel
import kotlinx.coroutines.flow.Flow
@@ -23,7 +24,7 @@ interface AppListModel<T : AppRecord> {
     *
     * Default no spinner will be shown.
     */
    fun getSpinnerOptions(): List<String> = emptyList()
    fun getSpinnerOptions(recordList: List<T>): List<SpinnerOption> = emptyList()

    /**
     * Loads the extra info for the App List, and generates the [AppRecord] List.
@@ -42,8 +43,10 @@ interface AppListModel<T : AppRecord> {
     * This function is called when the App List's loading is finished and displayed to the user.
     *
     * Could do some pre-cache here.
     *
     * @return true to enable pre-fetching app labels.
     */
    suspend fun onFirstLoaded(recordList: List<T>) {}
    suspend fun onFirstLoaded(recordList: List<T>) = false

    /**
     * Gets the comparator to sort the App List.
Loading