Add SettingsEntryRepository with some refactoring
1. Refactor SpaEnvironment, lazy init sppRepo and entryRepo 2. Add SettingsArguments with helper functions for arguments build, which is going to replace arguments in SPP 3. Add rootSettingsPages in SppRepo, which is going to replace rootPageNames (TODO). 4. Add button in HomePage to print pages & entries Bug: 244122804 Test: manual - build Spa gallery Change-Id: Iccc66f0cb7156c8aa2d9793e296c2a1a2b0e277a
This commit is contained in:
@@ -18,4 +18,4 @@ package com.android.settingslib.spa.gallery
|
||||
|
||||
import com.android.settingslib.spa.framework.BrowseActivity
|
||||
|
||||
class MainActivity : BrowseActivity(galleryPageProviders)
|
||||
class MainActivity : BrowseActivity(SpaEnvironment.PageProviderRepository)
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.settingslib.spa.gallery
|
||||
|
||||
import com.android.settingslib.spa.framework.common.SettingsEntryRepository
|
||||
import com.android.settingslib.spa.framework.common.SettingsPage
|
||||
import com.android.settingslib.spa.framework.common.SettingsPageProviderRepository
|
||||
import com.android.settingslib.spa.gallery.home.HomePageProvider
|
||||
import com.android.settingslib.spa.gallery.page.ArgumentPageProvider
|
||||
@@ -28,20 +30,39 @@ import com.android.settingslib.spa.gallery.preference.SwitchPreferencePageProvid
|
||||
import com.android.settingslib.spa.gallery.preference.TwoTargetSwitchPreferencePageProvider
|
||||
import com.android.settingslib.spa.gallery.ui.SpinnerPageProvider
|
||||
|
||||
val galleryPageProviders = SettingsPageProviderRepository(
|
||||
allPagesList = listOf(
|
||||
HomePageProvider,
|
||||
PreferenceMainPageProvider,
|
||||
PreferencePageProvider,
|
||||
SwitchPreferencePageProvider,
|
||||
TwoTargetSwitchPreferencePageProvider,
|
||||
ArgumentPageProvider,
|
||||
SliderPageProvider,
|
||||
SpinnerPageProvider,
|
||||
SettingsPagerPageProvider,
|
||||
FooterPageProvider,
|
||||
),
|
||||
rootPages = listOf(HomePageProvider.name)
|
||||
)
|
||||
object SpaEnvironment {
|
||||
val PageProviderRepository: SettingsPageProviderRepository by
|
||||
lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
|
||||
SettingsPageProviderRepository(
|
||||
allPagesList = listOf(
|
||||
HomePageProvider,
|
||||
PreferenceMainPageProvider,
|
||||
PreferencePageProvider,
|
||||
SwitchPreferencePageProvider,
|
||||
TwoTargetSwitchPreferencePageProvider,
|
||||
ArgumentPageProvider,
|
||||
SliderPageProvider,
|
||||
SpinnerPageProvider,
|
||||
SettingsPagerPageProvider,
|
||||
FooterPageProvider,
|
||||
),
|
||||
rootPageData = listOf(
|
||||
SettingsPage(HomePageProvider.name),
|
||||
SettingsPage(
|
||||
ArgumentPageProvider.name,
|
||||
ArgumentPageProvider.buildArgument("foo")
|
||||
),
|
||||
SettingsPage(
|
||||
ArgumentPageProvider.name,
|
||||
ArgumentPageProvider.buildArgument("bar")
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: add other environment setup here.
|
||||
val EntryRepository: SettingsEntryRepository by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
|
||||
SettingsEntryRepository(PageProviderRepository)
|
||||
}
|
||||
|
||||
// TODO: add other environment setup here.
|
||||
}
|
||||
|
||||
@@ -17,12 +17,15 @@
|
||||
package com.android.settingslib.spa.gallery.home
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.android.settingslib.spa.framework.common.SettingsPageProvider
|
||||
import com.android.settingslib.spa.framework.theme.SettingsTheme
|
||||
import com.android.settingslib.spa.gallery.R
|
||||
import com.android.settingslib.spa.gallery.SpaEnvironment
|
||||
import com.android.settingslib.spa.gallery.page.ArgumentPageProvider
|
||||
import com.android.settingslib.spa.gallery.page.FooterPageProvider
|
||||
import com.android.settingslib.spa.gallery.page.SettingsPagerPageProvider
|
||||
@@ -50,6 +53,17 @@ private fun HomePage() {
|
||||
SpinnerPageProvider.EntryItem()
|
||||
SettingsPagerPageProvider.EntryItem()
|
||||
FooterPageProvider.EntryItem()
|
||||
|
||||
/**
|
||||
* A test button to generate hierarchy.
|
||||
* TODO: remove it once the content provider is ready.
|
||||
*/
|
||||
Button(onClick = {
|
||||
SpaEnvironment.EntryRepository.printAllPages()
|
||||
SpaEnvironment.EntryRepository.printAllEntries()
|
||||
}) {
|
||||
Text(text = "Generate Entry")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,16 +19,20 @@ package com.android.settingslib.spa.gallery.page
|
||||
import android.os.Bundle
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.navigation.NamedNavArgument
|
||||
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.SettingsPage
|
||||
import com.android.settingslib.spa.framework.common.SettingsPageProvider
|
||||
import com.android.settingslib.spa.framework.compose.navigator
|
||||
import com.android.settingslib.spa.framework.compose.toState
|
||||
import com.android.settingslib.spa.framework.theme.SettingsTheme
|
||||
import com.android.settingslib.spa.framework.util.getIntArg
|
||||
import com.android.settingslib.spa.framework.util.getStringArg
|
||||
import com.android.settingslib.spa.framework.util.navLink
|
||||
import com.android.settingslib.spa.framework.util.normalize
|
||||
import com.android.settingslib.spa.widget.preference.Preference
|
||||
import com.android.settingslib.spa.widget.preference.PreferenceModel
|
||||
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
|
||||
@@ -40,22 +44,22 @@ private const val INT_PARAM_NAME = "intParam"
|
||||
object ArgumentPageProvider : SettingsPageProvider {
|
||||
override val name = "Argument"
|
||||
|
||||
override val arguments = listOf(
|
||||
override val parameter = listOf(
|
||||
navArgument(STRING_PARAM_NAME) { type = NavType.StringType },
|
||||
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()
|
||||
if (!parameter.isValid(arguments)) return emptyList()
|
||||
|
||||
val owner = SettingsPageBuilder.create(name, pageArgs.normalize()).build()
|
||||
val owner = SettingsPage(name, parameter.normalize(arguments))
|
||||
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()
|
||||
override val summary =
|
||||
parameter.getStringArg(STRING_PARAM_NAME, arguments)!!.toState()
|
||||
})
|
||||
}
|
||||
entryList.add(stringParamEntry.build())
|
||||
@@ -64,13 +68,15 @@ object ArgumentPageProvider : SettingsPageProvider {
|
||||
intParamEntry.setUiLayoutFn {
|
||||
Preference(object : PreferenceModel {
|
||||
override val title = "Int param value"
|
||||
override val summary = pageArgs.getIntArg(INT_PARAM_NAME)!!.toString().toState()
|
||||
override val summary =
|
||||
parameter.getIntArg(INT_PARAM_NAME, arguments)!!.toString().toState()
|
||||
})
|
||||
}
|
||||
entryList.add(intParamEntry.build())
|
||||
|
||||
val entryFoo = buildInjectEntry(pageArgs.buildNextArg("foo"))
|
||||
val entryBar = buildInjectEntry(pageArgs.buildNextArg("bar"))
|
||||
val intParam = parameter.getIntArg(INT_PARAM_NAME, arguments)
|
||||
val entryFoo = buildInjectEntry(buildNextArgument("foo", intParam))
|
||||
val entryBar = buildInjectEntry(buildNextArgument("bar", intParam))
|
||||
if (entryFoo != null) entryList.add(entryFoo.setLink(fromPage = owner).build())
|
||||
if (entryBar != null) entryList.add(entryBar.setLink(fromPage = owner).build())
|
||||
|
||||
@@ -78,21 +84,21 @@ object ArgumentPageProvider : SettingsPageProvider {
|
||||
}
|
||||
|
||||
private fun buildInjectEntry(arguments: Bundle?): SettingsEntryBuilder? {
|
||||
val pageArgs = PageArguments(ArgumentPageProvider.arguments, arguments)
|
||||
if (!pageArgs.isValid()) return null
|
||||
if (!parameter.isValid(arguments)) return null
|
||||
|
||||
val seBuilder = SettingsEntryBuilder.createLinkTo("injection", name, pageArgs.normalize())
|
||||
val seBuilder =
|
||||
SettingsEntryBuilder.createInject(name, parameter.normalize(arguments))
|
||||
seBuilder.setIsAllowSearch(false)
|
||||
|
||||
seBuilder.setUiLayoutFn {
|
||||
val summaryArray = listOf(
|
||||
"$STRING_PARAM_NAME=" + pageArgs.getStringArg(STRING_PARAM_NAME)!!,
|
||||
"$INT_PARAM_NAME=" + pageArgs.getIntArg(INT_PARAM_NAME)!!
|
||||
"$STRING_PARAM_NAME=" + parameter.getStringArg(STRING_PARAM_NAME, arguments)!!,
|
||||
"$INT_PARAM_NAME=" + parameter.getIntArg(INT_PARAM_NAME, arguments)!!
|
||||
)
|
||||
Preference(object : PreferenceModel {
|
||||
override val title = TITLE
|
||||
override val summary = summaryArray.joinToString(", ").toState()
|
||||
override val onClick = navigator(name + pageArgs.navLink())
|
||||
override val onClick = navigator(name + parameter.navLink(arguments))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -112,32 +118,33 @@ object ArgumentPageProvider : SettingsPageProvider {
|
||||
fun EntryItem(stringParam: String, intParam: Int) {
|
||||
buildInjectEntry(buildArgument(stringParam, intParam))?.build()?.uiLayout?.let { it() }
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
private fun buildNextArgument(stringParam: String, intParam: Int? = null): Bundle {
|
||||
return if (intParam == null)
|
||||
buildArgument(stringParam)
|
||||
else
|
||||
buildArgument(stringParam, intParam + 1)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun ArgumentPagePreview() {
|
||||
SettingsTheme {
|
||||
ArgumentPageProvider.Page(buildArgument(stringParam = "foo", intParam = 0))
|
||||
ArgumentPageProvider.Page(
|
||||
ArgumentPageProvider.buildArgument(stringParam = "foo", intParam = 0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun PageArguments.isValid(): Boolean {
|
||||
val stringParam = getStringArg(STRING_PARAM_NAME)
|
||||
private fun List<NamedNavArgument>.isValid(arguments: Bundle?): Boolean {
|
||||
val stringParam = getStringArg(STRING_PARAM_NAME, arguments)
|
||||
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
|
||||
}
|
||||
|
||||
@@ -27,10 +27,10 @@ import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.android.settingslib.spa.R
|
||||
import com.android.settingslib.spa.framework.common.SettingsPageProvider
|
||||
import com.android.settingslib.spa.framework.common.SettingsPageProviderRepository
|
||||
import com.android.settingslib.spa.framework.compose.localNavController
|
||||
import com.android.settingslib.spa.framework.theme.SettingsTheme
|
||||
import com.android.settingslib.spa.framework.util.navRoute
|
||||
|
||||
open class BrowseActivity(
|
||||
private val sppRepository: SettingsPageProviderRepository,
|
||||
@@ -55,8 +55,8 @@ open class BrowseActivity(
|
||||
NavHost(navController, sppRepository.getDefaultStartPageName()) {
|
||||
for (page in sppRepository.getAllProviders()) {
|
||||
composable(
|
||||
route = page.route,
|
||||
arguments = page.arguments,
|
||||
route = page.name + page.parameter.navRoute(),
|
||||
arguments = page.parameter,
|
||||
) { navBackStackEntry ->
|
||||
page.Page(navBackStackEntry.arguments)
|
||||
}
|
||||
@@ -75,9 +75,6 @@ open class BrowseActivity(
|
||||
}
|
||||
}
|
||||
|
||||
private val SettingsPageProvider.route: String
|
||||
get() = name + arguments.joinToString("") { argument -> "/{${argument.name}}" }
|
||||
|
||||
companion object {
|
||||
const val KEY_DESTINATION = "spa:SpaActivity:destination"
|
||||
}
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,9 @@ package com.android.settingslib.spa.framework.common
|
||||
import android.os.Bundle
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
const val INJECT_ENTRY_NAME = "INJECT"
|
||||
const val ROOT_ENTRY_NAME = "ROOT"
|
||||
|
||||
/**
|
||||
* Defines data of one Settings entry for Settings search.
|
||||
*/
|
||||
@@ -32,18 +35,22 @@ data class UiData(val title: String = "")
|
||||
/**
|
||||
* Defines data to identify a Settings page.
|
||||
*/
|
||||
data class SettingsPage(val name: String = "", val args: Bundle = Bundle.EMPTY)
|
||||
data class SettingsPage(val name: String = "", val args: Bundle? = null) {
|
||||
override fun toString(): String {
|
||||
return name + args?.toString()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines data of a Settings entry.
|
||||
*/
|
||||
data class SettingsEntry(
|
||||
// The unique id of this entry
|
||||
val id: String,
|
||||
|
||||
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,
|
||||
@@ -80,39 +87,13 @@ data class SettingsEntry(
|
||||
* 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)
|
||||
}
|
||||
}
|
||||
) {
|
||||
override fun toString(): String {
|
||||
return listOf(
|
||||
name,
|
||||
owner.toString(),
|
||||
"(${fromPage?.toString()}-${toPage?.toString()})"
|
||||
).joinToString("-")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,9 +111,9 @@ class SettingsEntryBuilder(private val name: String, private val owner: Settings
|
||||
|
||||
fun build(): SettingsEntry {
|
||||
return SettingsEntry(
|
||||
id = computeUniqueId(),
|
||||
name = name,
|
||||
owner = owner,
|
||||
uniqueId = computeUniqueId(),
|
||||
|
||||
// linking data
|
||||
fromPage = fromPage,
|
||||
@@ -171,22 +152,27 @@ class SettingsEntryBuilder(private val name: String, private val owner: Settings
|
||||
return this
|
||||
}
|
||||
|
||||
private fun computeUniqueId(): String = uniqueId ?: (name + owner.toString())
|
||||
private fun computeUniqueId(): String =
|
||||
uniqueId ?: name + owner.toString() + fromPage?.toString() + toPage?.toString()
|
||||
|
||||
private fun computeSearchable(): Boolean = isAllowSearch ?: false
|
||||
|
||||
companion object {
|
||||
fun create(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
|
||||
return SettingsEntryBuilder(entryName, owner)
|
||||
}
|
||||
|
||||
fun create(
|
||||
entryName: String,
|
||||
ownerPageName: String,
|
||||
ownerPageArgs: Bundle? = null
|
||||
): SettingsEntryBuilder {
|
||||
val owner = SettingsPageBuilder.create(ownerPageName, ownerPageArgs)
|
||||
return SettingsEntryBuilder(entryName, owner.build())
|
||||
val owner = SettingsPage(ownerPageName, ownerPageArgs)
|
||||
return create(entryName, owner)
|
||||
}
|
||||
|
||||
fun create(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
|
||||
return SettingsEntryBuilder(entryName, owner)
|
||||
fun createLinkTo(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
|
||||
return create(entryName, owner).setLink(toPage = owner)
|
||||
}
|
||||
|
||||
fun createLinkTo(
|
||||
@@ -194,12 +180,19 @@ class SettingsEntryBuilder(private val name: String, private val owner: Settings
|
||||
ownerPageName: String,
|
||||
ownerPageArgs: Bundle? = null
|
||||
): SettingsEntryBuilder {
|
||||
val owner = SettingsPageBuilder.create(ownerPageName, ownerPageArgs)
|
||||
return SettingsEntryBuilder(entryName, owner.build()).setLink(toPage = owner.build())
|
||||
val owner = SettingsPage(ownerPageName, ownerPageArgs)
|
||||
return createLinkTo(entryName, owner)
|
||||
}
|
||||
|
||||
fun createLinkTo(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
|
||||
return SettingsEntryBuilder(entryName, owner).setLink(toPage = owner)
|
||||
fun createInject(
|
||||
ownerPageName: String,
|
||||
ownerPageArgs: Bundle? = null
|
||||
): SettingsEntryBuilder {
|
||||
return createLinkTo(INJECT_ENTRY_NAME, ownerPageName, ownerPageArgs)
|
||||
}
|
||||
|
||||
fun createRoot(page: SettingsPage): SettingsEntryBuilder {
|
||||
return createLinkTo(ROOT_ENTRY_NAME, page)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.util.Log
|
||||
import java.util.LinkedList
|
||||
|
||||
const val MAX_ENTRY_SIZE = 5000
|
||||
|
||||
/**
|
||||
* The repository to maintain all Settings entries
|
||||
*/
|
||||
class SettingsEntryRepository(sppRepository: SettingsPageProviderRepository) {
|
||||
// Map of entry unique Id to entry
|
||||
private val entryMap: Map<String, SettingsEntry>
|
||||
|
||||
// Map of Settings page to its contained entries.
|
||||
private val pageToEntryListMap: Map<String, List<SettingsEntry>>
|
||||
|
||||
init {
|
||||
logMsg("Initialize")
|
||||
entryMap = mutableMapOf()
|
||||
pageToEntryListMap = mutableMapOf()
|
||||
|
||||
val entryQueue = LinkedList<SettingsEntry>()
|
||||
for (page in sppRepository.getAllRootPages()) {
|
||||
val rootEntry = SettingsEntryBuilder.createRoot(page).build()
|
||||
if (!entryMap.containsKey(rootEntry.id)) {
|
||||
entryQueue.push(rootEntry)
|
||||
entryMap.put(rootEntry.id, rootEntry)
|
||||
}
|
||||
}
|
||||
|
||||
while (entryQueue.isNotEmpty() && entryMap.size < MAX_ENTRY_SIZE) {
|
||||
val entry = entryQueue.pop()
|
||||
val page = entry.toPage
|
||||
if (page == null || pageToEntryListMap.containsKey(page.toString())) continue
|
||||
val spp = sppRepository.getProviderOrNull(page.name) ?: continue
|
||||
val newEntries = spp.buildEntry(page.args)
|
||||
pageToEntryListMap[page.toString()] = newEntries
|
||||
for (newEntry in newEntries) {
|
||||
if (!entryMap.containsKey(newEntry.id)) {
|
||||
entryQueue.push(newEntry)
|
||||
entryMap.put(newEntry.id, newEntry)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun printAllPages() {
|
||||
for (entry in pageToEntryListMap.entries) {
|
||||
logMsg("page: ${entry.key} with ${entry.value.size} entries")
|
||||
}
|
||||
}
|
||||
|
||||
fun printAllEntries() {
|
||||
for (entry in entryMap.values) {
|
||||
logMsg("entry: $entry")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun logMsg(message: String) {
|
||||
Log.d("EntryRepo", message)
|
||||
}
|
||||
@@ -28,8 +28,8 @@ interface SettingsPageProvider {
|
||||
/** The page name without arguments. */
|
||||
val name: String
|
||||
|
||||
/** The page arguments, default is no arguments. */
|
||||
val arguments: List<NamedNavArgument>
|
||||
/** The page parameters, default is no parameters. */
|
||||
val parameter: List<NamedNavArgument>
|
||||
get() = emptyList()
|
||||
|
||||
/** The [Composable] used to render this page. */
|
||||
|
||||
@@ -18,22 +18,33 @@ package com.android.settingslib.spa.framework.common
|
||||
|
||||
class SettingsPageProviderRepository(
|
||||
allPagesList: List<SettingsPageProvider>,
|
||||
private val rootPages: List<String>
|
||||
private val rootPages: List<String> = emptyList(),
|
||||
// TODO: deprecate rootPages above
|
||||
private val rootPageData: List<SettingsPage> = emptyList(),
|
||||
) {
|
||||
// Maintains all SPA page providers.
|
||||
private val allPages: Map<String, SettingsPageProvider> = allPagesList.associateBy { it.name }
|
||||
// Map of page name to its provider.
|
||||
private val pageProviderMap: Map<String, SettingsPageProvider> =
|
||||
allPagesList.associateBy { it.name }
|
||||
|
||||
fun getDefaultStartPageName(): String {
|
||||
return rootPages.getOrElse(0) {
|
||||
return ""
|
||||
if (rootPageData.isNotEmpty()) {
|
||||
return rootPageData[0].name
|
||||
} else {
|
||||
return rootPages.getOrElse(0) {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getAllRootPages(): Collection<SettingsPage> {
|
||||
return rootPageData
|
||||
}
|
||||
|
||||
fun getAllProviders(): Collection<SettingsPageProvider> {
|
||||
return allPages.values
|
||||
return pageProviderMap.values
|
||||
}
|
||||
|
||||
fun getProviderOrNull(name: String): SettingsPageProvider? {
|
||||
return allPages[name]
|
||||
return pageProviderMap[name]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.util
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.navigation.NamedNavArgument
|
||||
import androidx.navigation.NavType
|
||||
|
||||
fun List<NamedNavArgument>.navRoute(): String {
|
||||
return this.joinToString("") { argument -> "/{${argument.name}}" }
|
||||
}
|
||||
|
||||
fun List<NamedNavArgument>.navLink(arguments: Bundle? = null): String {
|
||||
if (arguments == null) return ""
|
||||
val argsArray = mutableListOf<String>()
|
||||
for (navArg in this) {
|
||||
when (navArg.argument.type) {
|
||||
NavType.StringType -> {
|
||||
argsArray.add(arguments.getString(navArg.name, ""))
|
||||
}
|
||||
NavType.IntType -> {
|
||||
argsArray.add(arguments.getInt(navArg.name).toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
return argsArray.joinToString("") { arg -> "/$arg" }
|
||||
}
|
||||
|
||||
fun List<NamedNavArgument>.normalize(arguments: Bundle? = null): Bundle {
|
||||
if (arguments == null) return Bundle.EMPTY
|
||||
val normArgs = Bundle()
|
||||
for (navArg in this) {
|
||||
when (navArg.argument.type) {
|
||||
NavType.StringType -> {
|
||||
val value = arguments.getString(navArg.name)
|
||||
if (value != null) normArgs.putString(navArg.name, value)
|
||||
}
|
||||
NavType.IntType -> {
|
||||
if (arguments.containsKey(navArg.name))
|
||||
normArgs.putInt(navArg.name, arguments.getInt(navArg.name))
|
||||
}
|
||||
}
|
||||
}
|
||||
return normArgs
|
||||
}
|
||||
|
||||
fun List<NamedNavArgument>.getStringArg(name: String, arguments: Bundle? = null): String? {
|
||||
if (this.containsStringArg(name) && arguments != null) {
|
||||
return arguments.getString(name)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun List<NamedNavArgument>.getIntArg(name: String, arguments: Bundle? = null): Int? {
|
||||
if (this.containsIntArg(name) && arguments != null && arguments.containsKey(name)) {
|
||||
return arguments.getInt(name)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun List<NamedNavArgument>.containsStringArg(name: String): Boolean {
|
||||
for (navArg in this) {
|
||||
if (navArg.argument.type == NavType.StringType && navArg.name == name) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun List<NamedNavArgument>.containsIntArg(name: String): Boolean {
|
||||
for (navArg in this) {
|
||||
if (navArg.argument.type == NavType.IntType && navArg.name == name) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -47,7 +47,7 @@ internal class TogglePermissionAppInfoPageProvider(
|
||||
) : SettingsPageProvider {
|
||||
override val name = NAME
|
||||
|
||||
override val arguments = listOf(
|
||||
override val parameter = listOf(
|
||||
navArgument(PERMISSION) { type = NavType.StringType },
|
||||
navArgument(PACKAGE_NAME) { type = NavType.StringType },
|
||||
navArgument(USER_ID) { type = NavType.IntType },
|
||||
|
||||
@@ -42,7 +42,7 @@ internal class TogglePermissionAppListPageProvider(
|
||||
) : SettingsPageProvider {
|
||||
override val name = NAME
|
||||
|
||||
override val arguments = listOf(
|
||||
override val parameter = listOf(
|
||||
navArgument(PERMISSION) { type = NavType.StringType },
|
||||
)
|
||||
|
||||
@@ -81,6 +81,7 @@ internal class TogglePermissionAppListPageProvider(
|
||||
* Expose route to enable enter from non-SPA pages.
|
||||
*/
|
||||
internal fun getRoute(permissionType: String) = "$NAME/$permissionType"
|
||||
|
||||
@Composable
|
||||
internal fun navigator(permissionType: String) = navigator(route = getRoute(permissionType))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user