Add PageModel framework, and use it in ArgumentPageModel.

Bug: 244122804
Test: manual - build Spa gallery
Change-Id: I7079bfdcf84820a1d499be3efe65f9a046d7ab08
This commit is contained in:
Zekan Qian
2022-09-05 12:05:57 +08:00
parent dccbbc0b58
commit 77b718efa8
5 changed files with 206 additions and 90 deletions

View File

@@ -47,16 +47,8 @@ object SpaEnvironment {
FooterPageProvider,
),
rootPageData = listOf(
SettingsPage(HomePageProvider.name),
SettingsPage(
ArgumentPageProvider.name,
ArgumentPageProvider.buildArgument("foo")
),
SettingsPage(
ArgumentPageProvider.name,
ArgumentPageProvider.buildArgument("bar")
),
)
SettingsPage(HomePageProvider.name)
) + ArgumentPageProvider.buildRootPages()
)
}

View File

@@ -19,64 +19,47 @@ 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.SettingsEntry
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
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
private const val TITLE = "Sample page with arguments"
private const val STRING_PARAM_NAME = "stringParam"
private const val INT_PARAM_NAME = "intParam"
object ArgumentPageProvider : SettingsPageProvider {
override val name = "Argument"
override val name = ArgumentPageModel.name
override val parameter = listOf(
navArgument(STRING_PARAM_NAME) { type = NavType.StringType },
navArgument(INT_PARAM_NAME) { type = NavType.IntType },
)
override val parameter = ArgumentPageModel.parameter
override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
if (!parameter.isValid(arguments)) return emptyList()
if (!ArgumentPageModel.isValidArgument(arguments)) return emptyList()
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 =
parameter.getStringArg(STRING_PARAM_NAME, arguments)!!.toState()
})
}
entryList.add(stringParamEntry.build())
entryList.add(
SettingsEntryBuilder.create("string_param", owner)
// Set attributes
.setIsAllowSearch(true)
.setUiLayoutFn {
// Set ui rendering
Preference(ArgumentPageModel.create(arguments).genStringParamPreferenceModel())
}.build()
)
val intParamEntry = SettingsEntryBuilder.create("int_param", owner)
intParamEntry.setUiLayoutFn {
Preference(object : PreferenceModel {
override val title = "Int param value"
override val summary =
parameter.getIntArg(INT_PARAM_NAME, arguments)!!.toString().toState()
})
}
entryList.add(intParamEntry.build())
entryList.add(
SettingsEntryBuilder.create("int_param", owner)
// Set attributes
.setIsAllowSearch(true)
.setUiLayoutFn {
// Set ui rendering
Preference(ArgumentPageModel.create(arguments).genIntParamPreferenceModel())
}.build()
)
val intParam = parameter.getIntArg(INT_PARAM_NAME, arguments)
val entryFoo = buildInjectEntry(buildNextArgument("foo", intParam))
val entryBar = buildInjectEntry(buildNextArgument("bar", intParam))
val entryFoo = buildInjectEntry(ArgumentPageModel.buildNextArgument("foo", arguments))
val entryBar = buildInjectEntry(ArgumentPageModel.buildNextArgument("bar", arguments))
if (entryFoo != null) entryList.add(entryFoo.setLink(fromPage = owner).build())
if (entryBar != null) entryList.add(entryBar.setLink(fromPage = owner).build())
@@ -84,30 +67,33 @@ object ArgumentPageProvider : SettingsPageProvider {
}
private fun buildInjectEntry(arguments: Bundle?): SettingsEntryBuilder? {
if (!parameter.isValid(arguments)) return null
if (!ArgumentPageModel.isValidArgument(arguments)) return null
val seBuilder =
SettingsEntryBuilder.createInject(name, parameter.normalize(arguments))
seBuilder.setIsAllowSearch(false)
return SettingsEntryBuilder.createInject(name, parameter.normalize(arguments))
// Set attributes
.setIsAllowSearch(false)
.setUiLayoutFn {
// Set ui rendering
Preference(ArgumentPageModel.create(arguments).genInjectPreferenceModel())
}
}
seBuilder.setUiLayoutFn {
val summaryArray = listOf(
"$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 + parameter.navLink(arguments))
})
}
return seBuilder
fun buildRootPages(): List<SettingsPage> {
return listOf(
SettingsPage(
ArgumentPageModel.name,
ArgumentPageModel.buildArgument("foo")
),
SettingsPage(
ArgumentPageModel.name,
ArgumentPageModel.buildArgument("bar")
),
)
}
@Composable
override fun Page(arguments: Bundle?) {
RegularScaffold(title = TITLE) {
RegularScaffold(title = ArgumentPageModel.create(arguments).genPageTitle()) {
for (entry in buildEntry(arguments)) {
entry.uiLayout()
}
@@ -116,21 +102,8 @@ object ArgumentPageProvider : SettingsPageProvider {
@Composable
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)
buildInjectEntry(ArgumentPageModel.buildArgument(stringParam, intParam))
?.build()?.uiLayout?.let { it() }
}
}
@@ -139,12 +112,7 @@ object ArgumentPageProvider : SettingsPageProvider {
private fun ArgumentPagePreview() {
SettingsTheme {
ArgumentPageProvider.Page(
ArgumentPageProvider.buildArgument(stringParam = "foo", intParam = 0)
ArgumentPageModel.buildArgument(stringParam = "foo", intParam = 0)
)
}
}
private fun List<NamedNavArgument>.isValid(arguments: Bundle?): Boolean {
val stringParam = getStringArg(STRING_PARAM_NAME, arguments)
return (stringParam != null && listOf("foo", "bar").contains(stringParam))
}

View File

@@ -0,0 +1,123 @@
/*
* 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.page
import android.os.Bundle
import android.util.Log
import androidx.compose.runtime.Composable
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavType
import androidx.navigation.navArgument
import com.android.settingslib.spa.framework.common.PageModel
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.framework.compose.stateOf
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.widget.preference.PreferenceModel
private const val TITLE = "Sample page with arguments"
private const val STRING_PARAM_NAME = "stringParam"
private const val INT_PARAM_NAME = "intParam"
class ArgumentPageModel : PageModel() {
companion object {
const val name = "Argument"
val parameter = listOf(
navArgument(STRING_PARAM_NAME) { type = NavType.StringType },
navArgument(INT_PARAM_NAME) { type = NavType.IntType },
)
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
}
fun buildNextArgument(newStringParam: String, arguments: Bundle? = null): Bundle {
val intParam = parameter.getIntArg(INT_PARAM_NAME, arguments)
return if (intParam == null)
buildArgument(newStringParam)
else
buildArgument(newStringParam, intParam + 1)
}
fun isValidArgument(arguments: Bundle?): Boolean {
val stringParam = parameter.getStringArg(STRING_PARAM_NAME, arguments)
return (stringParam != null && listOf("foo", "bar").contains(stringParam))
}
@Composable
fun create(arguments: Bundle?): ArgumentPageModel {
val pageModel: ArgumentPageModel = viewModel(key = arguments.toString())
pageModel.initOnce(arguments)
return pageModel
}
}
private val title = TITLE
private var arguments: Bundle? = null
private var stringParam: String? = null
private var intParam: Int? = null
override fun initialize(arguments: Bundle?) {
logMsg("init with args " + arguments.toString())
this.arguments = arguments
stringParam = parameter.getStringArg(STRING_PARAM_NAME, arguments)
intParam = parameter.getIntArg(INT_PARAM_NAME, arguments)
}
@Composable
fun genPageTitle(): String {
return title
}
@Composable
fun genStringParamPreferenceModel(): PreferenceModel {
return object : PreferenceModel {
override val title = "String param value"
override val summary = stateOf(stringParam!!)
}
}
@Composable
fun genIntParamPreferenceModel(): PreferenceModel {
return object : PreferenceModel {
override val title = "Int param value"
override val summary = stateOf(intParam!!.toString())
}
}
@Composable
fun genInjectPreferenceModel(): PreferenceModel {
val summaryArray = listOf(
"$STRING_PARAM_NAME=" + stringParam!!,
"$INT_PARAM_NAME=" + intParam!!
)
return object : PreferenceModel {
override val title = genPageTitle()
override val summary = stateOf(summaryArray.joinToString(", "))
override val onClick = navigator(name + parameter.navLink(arguments))
}
}
}
private fun logMsg(message: String) {
Log.d("ArgumentPageModel", message)
}

View File

@@ -0,0 +1,33 @@
/*
* 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.lifecycle.ViewModel
open class PageModel : ViewModel() {
var initialized = false
fun initOnce(arguments: Bundle?) {
// Initialize only once
if (initialized) return
initialized = true
initialize(arguments)
}
open fun initialize(arguments: Bundle?) {}
}

View File

@@ -19,7 +19,7 @@ package com.android.settingslib.spa.framework.common
import android.util.Log
import java.util.LinkedList
const val MAX_ENTRY_SIZE = 5000
private const val MAX_ENTRY_SIZE = 5000
/**
* The repository to maintain all Settings entries