Merge "Defines SettingsEntry and use it in ArgumentPage"
This commit is contained in:
@@ -21,6 +21,10 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.navArgument
|
||||
import com.android.settingslib.spa.framework.common.PageArguments
|
||||
import com.android.settingslib.spa.framework.common.SettingsEntry
|
||||
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
|
||||
import com.android.settingslib.spa.framework.common.SettingsPageBuilder
|
||||
import com.android.settingslib.spa.framework.common.SettingsPageProvider
|
||||
import com.android.settingslib.spa.framework.compose.navigator
|
||||
import com.android.settingslib.spa.framework.compose.toState
|
||||
@@ -41,41 +45,72 @@ object ArgumentPageProvider : SettingsPageProvider {
|
||||
navArgument(INT_PARAM_NAME) { type = NavType.IntType },
|
||||
)
|
||||
|
||||
override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
|
||||
val pageArgs = PageArguments(ArgumentPageProvider.arguments, arguments)
|
||||
if (!pageArgs.isValid()) return emptyList()
|
||||
|
||||
val owner = SettingsPageBuilder.create(name, pageArgs.normalize()).build()
|
||||
val entryList = mutableListOf<SettingsEntry>()
|
||||
val stringParamEntry = SettingsEntryBuilder.create("string_param", owner)
|
||||
stringParamEntry.setUiLayoutFn {
|
||||
Preference(object : PreferenceModel {
|
||||
override val title = "String param value"
|
||||
override val summary = pageArgs.getStringArg(STRING_PARAM_NAME)!!.toState()
|
||||
})
|
||||
}
|
||||
entryList.add(stringParamEntry.build())
|
||||
|
||||
val intParamEntry = SettingsEntryBuilder.create("int_param", owner)
|
||||
intParamEntry.setUiLayoutFn {
|
||||
Preference(object : PreferenceModel {
|
||||
override val title = "Int param value"
|
||||
override val summary = pageArgs.getIntArg(INT_PARAM_NAME)!!.toString().toState()
|
||||
})
|
||||
}
|
||||
entryList.add(intParamEntry.build())
|
||||
|
||||
val entryFoo = buildInjectEntry(pageArgs.buildNextArg("foo"))
|
||||
val entryBar = buildInjectEntry(pageArgs.buildNextArg("bar"))
|
||||
if (entryFoo != null) entryList.add(entryFoo.setLink(fromPage = owner).build())
|
||||
if (entryBar != null) entryList.add(entryBar.setLink(fromPage = owner).build())
|
||||
|
||||
return entryList
|
||||
}
|
||||
|
||||
private fun buildInjectEntry(arguments: Bundle?): SettingsEntryBuilder? {
|
||||
val pageArgs = PageArguments(ArgumentPageProvider.arguments, arguments)
|
||||
if (!pageArgs.isValid()) return null
|
||||
|
||||
val seBuilder = SettingsEntryBuilder.createLinkTo("injection", name, pageArgs.normalize())
|
||||
seBuilder.setIsAllowSearch(false)
|
||||
|
||||
seBuilder.setUiLayoutFn {
|
||||
val summaryArray = listOf(
|
||||
"$STRING_PARAM_NAME=" + pageArgs.getStringArg(STRING_PARAM_NAME)!!,
|
||||
"$INT_PARAM_NAME=" + pageArgs.getIntArg(INT_PARAM_NAME)!!
|
||||
)
|
||||
Preference(object : PreferenceModel {
|
||||
override val title = TITLE
|
||||
override val summary = summaryArray.joinToString(", ").toState()
|
||||
override val onClick = navigator(name + pageArgs.navLink())
|
||||
})
|
||||
}
|
||||
|
||||
return seBuilder
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Page(arguments: Bundle?) {
|
||||
ArgumentPage(
|
||||
stringParam = arguments!!.getString(STRING_PARAM_NAME, "default"),
|
||||
intParam = arguments.getInt(INT_PARAM_NAME),
|
||||
)
|
||||
RegularScaffold(title = TITLE) {
|
||||
for (entry in buildEntry(arguments)) {
|
||||
entry.uiLayout()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EntryItem(stringParam: String, intParam: Int) {
|
||||
Preference(object : PreferenceModel {
|
||||
override val title = TITLE
|
||||
override val summary =
|
||||
"$STRING_PARAM_NAME=$stringParam, $INT_PARAM_NAME=$intParam".toState()
|
||||
override val onClick = navigator("$name/$stringParam/$intParam")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ArgumentPage(stringParam: String, intParam: Int) {
|
||||
RegularScaffold(title = TITLE) {
|
||||
Preference(object : PreferenceModel {
|
||||
override val title = "String param value"
|
||||
override val summary = stringParam.toState()
|
||||
})
|
||||
|
||||
Preference(object : PreferenceModel {
|
||||
override val title = "Int param value"
|
||||
override val summary = intParam.toString().toState()
|
||||
})
|
||||
|
||||
ArgumentPageProvider.EntryItem(stringParam = "foo", intParam = intParam + 1)
|
||||
|
||||
ArgumentPageProvider.EntryItem(stringParam = "bar", intParam = intParam + 1)
|
||||
buildInjectEntry(buildArgument(stringParam, intParam))?.build()?.uiLayout?.let { it() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +118,26 @@ fun ArgumentPage(stringParam: String, intParam: Int) {
|
||||
@Composable
|
||||
private fun ArgumentPagePreview() {
|
||||
SettingsTheme {
|
||||
ArgumentPage(stringParam = "foo", intParam = 0)
|
||||
ArgumentPageProvider.Page(buildArgument(stringParam = "foo", intParam = 0))
|
||||
}
|
||||
}
|
||||
|
||||
private fun PageArguments.isValid(): Boolean {
|
||||
val stringParam = getStringArg(STRING_PARAM_NAME)
|
||||
return (stringParam != null && listOf("foo", "bar").contains(stringParam))
|
||||
}
|
||||
|
||||
private fun PageArguments.buildNextArg(stringParam: String): Bundle {
|
||||
val intParam = getIntArg(INT_PARAM_NAME)
|
||||
return if (intParam == null)
|
||||
buildArgument(stringParam)
|
||||
else
|
||||
buildArgument(stringParam, intParam + 1)
|
||||
}
|
||||
|
||||
private fun buildArgument(stringParam: String, intParam: Int? = null): Bundle {
|
||||
val args = Bundle()
|
||||
args.putString(STRING_PARAM_NAME, stringParam)
|
||||
if (intParam != null) args.putInt(INT_PARAM_NAME, intParam)
|
||||
return args
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.framework.common
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.navigation.NamedNavArgument
|
||||
import androidx.navigation.NavType
|
||||
|
||||
class PageArguments(
|
||||
private val navArgsDef: List<NamedNavArgument>,
|
||||
private val rawArgs: Bundle?
|
||||
) {
|
||||
fun normalize(): Bundle {
|
||||
if (rawArgs == null) return Bundle.EMPTY
|
||||
val normArgs = Bundle()
|
||||
for (navArg in navArgsDef) {
|
||||
when (navArg.argument.type) {
|
||||
NavType.StringType -> {
|
||||
val value = rawArgs.getString(navArg.name)
|
||||
if (value != null) normArgs.putString(navArg.name, value)
|
||||
}
|
||||
NavType.IntType -> {
|
||||
if (rawArgs.containsKey(navArg.name))
|
||||
normArgs.putInt(navArg.name, rawArgs.getInt(navArg.name))
|
||||
}
|
||||
}
|
||||
}
|
||||
return normArgs
|
||||
}
|
||||
|
||||
fun navLink(): String{
|
||||
if (rawArgs == null) return ""
|
||||
val argsArray = mutableListOf<String>()
|
||||
for (navArg in navArgsDef) {
|
||||
when (navArg.argument.type) {
|
||||
NavType.StringType -> {
|
||||
argsArray.add(rawArgs.getString(navArg.name, ""))
|
||||
}
|
||||
NavType.IntType -> {
|
||||
argsArray.add(rawArgs.getInt(navArg.name).toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
return argsArray.joinToString("") {arg -> "/$arg" }
|
||||
}
|
||||
|
||||
fun getStringArg(key: String): String? {
|
||||
if (rawArgs != null && rawArgs.containsKey(key)) {
|
||||
return rawArgs.getString(key)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun getIntArg(key: String): Int? {
|
||||
if (rawArgs != null && rawArgs.containsKey(key)) {
|
||||
return rawArgs.getInt(key)
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* 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.framework.common
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
/**
|
||||
* Defines data of one Settings entry for Settings search.
|
||||
*/
|
||||
data class SearchData(val keyword: String = "")
|
||||
|
||||
/**
|
||||
* Defines data of one Settings entry for UI rendering.
|
||||
*/
|
||||
data class UiData(val title: String = "")
|
||||
|
||||
/**
|
||||
* Defines data to identify a Settings page.
|
||||
*/
|
||||
data class SettingsPage(val name: String = "", val args: Bundle = Bundle.EMPTY)
|
||||
|
||||
/**
|
||||
* Defines data of a Settings entry.
|
||||
*/
|
||||
data class SettingsEntry(
|
||||
val name: String,
|
||||
val owner: SettingsPage,
|
||||
|
||||
// Generates the unique id of this entry
|
||||
val uniqueId: String,
|
||||
|
||||
// Defines linking of Settings entries
|
||||
val fromPage: SettingsPage? = null,
|
||||
val toPage: SettingsPage? = null,
|
||||
|
||||
/**
|
||||
* ========================================
|
||||
* Defines entry attributes here.
|
||||
* ========================================
|
||||
*/
|
||||
val isAllowSearch: Boolean,
|
||||
|
||||
/**
|
||||
* ========================================
|
||||
* Defines entry APIs to get data here.
|
||||
* ========================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* API to get Search related data for this entry.
|
||||
* Returns null if this entry is not available for the search at the moment.
|
||||
*/
|
||||
val searchData: () -> SearchData? = { null },
|
||||
|
||||
/**
|
||||
* API to get UI related data for this entry.
|
||||
* Returns null if the entry is not render-able.
|
||||
*/
|
||||
val uiData: () -> UiData? = { null },
|
||||
|
||||
/**
|
||||
* API to Render UI of this entry directly. For now, we use it in the internal injection, to
|
||||
* support the case that the injection page owner wants to maintain both data and UI of the
|
||||
* injected entry. In the long term, we may deprecate the @Composable Page() API in SPP, and
|
||||
* use each entries' UI rendering function in the page instead.
|
||||
*/
|
||||
val uiLayout: (@Composable () -> Unit) = {},
|
||||
)
|
||||
|
||||
/**
|
||||
* The helper to build a Settings Page instance.
|
||||
*/
|
||||
class SettingsPageBuilder(private val name: String) {
|
||||
private val arguments = Bundle()
|
||||
|
||||
fun pushArgs(args: Bundle?): SettingsPageBuilder {
|
||||
if (args != null) arguments.putAll(args)
|
||||
return this
|
||||
}
|
||||
|
||||
fun pushArg(argName: String, argValue: String?): SettingsPageBuilder {
|
||||
if (argValue != null) this.arguments.putString(argName, argValue)
|
||||
return this
|
||||
}
|
||||
|
||||
fun pushArg(argName: String, argValue: Int?): SettingsPageBuilder {
|
||||
if (argValue != null) this.arguments.putInt(argName, argValue)
|
||||
return this
|
||||
}
|
||||
|
||||
fun build(): SettingsPage {
|
||||
return SettingsPage(name, arguments)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun create(name: String, args: Bundle? = null): SettingsPageBuilder {
|
||||
return SettingsPageBuilder(name).apply {
|
||||
pushArgs(args)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The helper to build a Settings Entry instance.
|
||||
*/
|
||||
class SettingsEntryBuilder(private val name: String, private val owner: SettingsPage) {
|
||||
private var uniqueId: String? = null
|
||||
private var fromPage: SettingsPage? = null
|
||||
private var toPage: SettingsPage? = null
|
||||
private var isAllowSearch: Boolean? = null
|
||||
|
||||
private var searchDataFn: () -> SearchData? = { null }
|
||||
private var uiLayoutFn: (@Composable () -> Unit) = {}
|
||||
|
||||
fun build(): SettingsEntry {
|
||||
return SettingsEntry(
|
||||
name = name,
|
||||
owner = owner,
|
||||
uniqueId = computeUniqueId(),
|
||||
|
||||
// linking data
|
||||
fromPage = fromPage,
|
||||
toPage = toPage,
|
||||
|
||||
// attributes
|
||||
isAllowSearch = computeSearchable(),
|
||||
|
||||
// functions
|
||||
searchData = searchDataFn,
|
||||
uiLayout = uiLayoutFn,
|
||||
)
|
||||
}
|
||||
|
||||
fun setLink(
|
||||
fromPage: SettingsPage? = null,
|
||||
toPage: SettingsPage? = null
|
||||
): SettingsEntryBuilder {
|
||||
if (fromPage != null) this.fromPage = fromPage
|
||||
if (toPage != null) this.toPage = toPage
|
||||
return this
|
||||
}
|
||||
|
||||
fun setIsAllowSearch(isAllowSearch: Boolean): SettingsEntryBuilder {
|
||||
this.isAllowSearch = isAllowSearch
|
||||
return this
|
||||
}
|
||||
|
||||
fun setSearchDataFn(fn: () -> SearchData?): SettingsEntryBuilder {
|
||||
this.searchDataFn = fn
|
||||
return this
|
||||
}
|
||||
|
||||
fun setUiLayoutFn(fn: @Composable () -> Unit): SettingsEntryBuilder {
|
||||
this.uiLayoutFn = fn
|
||||
return this
|
||||
}
|
||||
|
||||
private fun computeUniqueId(): String = uniqueId ?: (name + owner.toString())
|
||||
|
||||
private fun computeSearchable(): Boolean = isAllowSearch ?: false
|
||||
|
||||
companion object {
|
||||
fun create(
|
||||
entryName: String,
|
||||
ownerPageName: String,
|
||||
ownerPageArgs: Bundle? = null
|
||||
): SettingsEntryBuilder {
|
||||
val owner = SettingsPageBuilder.create(ownerPageName, ownerPageArgs)
|
||||
return SettingsEntryBuilder(entryName, owner.build())
|
||||
}
|
||||
|
||||
fun create(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
|
||||
return SettingsEntryBuilder(entryName, owner)
|
||||
}
|
||||
|
||||
fun createLinkTo(
|
||||
entryName: String,
|
||||
ownerPageName: String,
|
||||
ownerPageArgs: Bundle? = null
|
||||
): SettingsEntryBuilder {
|
||||
val owner = SettingsPageBuilder.create(ownerPageName, ownerPageArgs)
|
||||
return SettingsEntryBuilder(entryName, owner.build()).setLink(toPage = owner.build())
|
||||
}
|
||||
|
||||
fun createLinkTo(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
|
||||
return SettingsEntryBuilder(entryName, owner).setLink(toPage = owner)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,5 +36,5 @@ interface SettingsPageProvider {
|
||||
@Composable
|
||||
fun Page(arguments: Bundle?)
|
||||
|
||||
// fun buildEntry( arguments: Bundle?) : List<entry>
|
||||
fun buildEntry(arguments: Bundle?): List<SettingsEntry> = emptyList()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user