diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt index e54e2764bb401..c702f5919d1e4 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt @@ -24,6 +24,9 @@ import com.android.settingslib.spa.framework.common.createSettingsPage import com.android.settingslib.spa.gallery.button.ActionButtonPageProvider import com.android.settingslib.spa.gallery.dialog.AlterDialogPageProvider import com.android.settingslib.spa.gallery.home.HomePageProvider +import com.android.settingslib.spa.gallery.itemList.ItemListPageProvider +import com.android.settingslib.spa.gallery.itemList.ItemOperatePageProvider +import com.android.settingslib.spa.gallery.itemList.OperateListPageProvider import com.android.settingslib.spa.gallery.page.ArgumentPageProvider import com.android.settingslib.spa.gallery.page.ChartPageProvider import com.android.settingslib.spa.gallery.page.FooterPageProvider @@ -50,6 +53,8 @@ enum class SettingsPageProviderEnum(val displayName: String) { HOME("home"), PREFERENCE("preference"), ARGUMENT("argument"), + ITEM_LIST("itemList"), + ITEM_OP_PAGE("itemOp"), // Add your SPPs } @@ -76,6 +81,9 @@ class GallerySpaEnvironment(context: Context) : SpaEnvironment(context) { LoadingBarPageProvider, ChartPageProvider, AlterDialogPageProvider, + ItemListPageProvider, + ItemOperatePageProvider, + OperateListPageProvider, ), rootPages = listOf( HomePageProvider.createSettingsPage(), diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt index 5d26b34584874..0878fc0e20733 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt @@ -18,6 +18,7 @@ package com.android.settingslib.spa.gallery.home import android.os.Bundle import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.tooling.preview.Preview import com.android.settingslib.spa.framework.common.SettingsEntry import com.android.settingslib.spa.framework.common.SettingsPageProvider @@ -28,6 +29,7 @@ import com.android.settingslib.spa.gallery.R import com.android.settingslib.spa.gallery.SettingsPageProviderEnum import com.android.settingslib.spa.gallery.button.ActionButtonPageProvider import com.android.settingslib.spa.gallery.dialog.AlterDialogPageProvider +import com.android.settingslib.spa.gallery.itemList.OperateListPageProvider import com.android.settingslib.spa.gallery.page.ArgumentPageModel import com.android.settingslib.spa.gallery.page.ArgumentPageProvider import com.android.settingslib.spa.gallery.page.ChartPageProvider @@ -50,6 +52,7 @@ object HomePageProvider : SettingsPageProvider { override fun buildEntry(arguments: Bundle?): List { return listOf( PreferenceMainPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), + OperateListPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), ArgumentPageProvider.buildInjectEntry("foo")!!.setLink(fromPage = owner).build(), SliderPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), SpinnerPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), @@ -71,8 +74,10 @@ object HomePageProvider : SettingsPageProvider { @Composable override fun Page(arguments: Bundle?) { - HomeScaffold(title = getTitle(arguments)) { - for (entry in buildEntry(arguments)) { + val title = remember { getTitle(arguments) } + val entries = remember { buildEntry(arguments) } + HomeScaffold(title) { + for (entry in entries) { if (entry.owner.isCreateBy(SettingsPageProviderEnum.ARGUMENT.name)) { entry.UiLayout(ArgumentPageModel.buildArgument(intParam = 0)) } else { diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemListPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemListPage.kt new file mode 100644 index 0000000000000..08e645230774e --- /dev/null +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemListPage.kt @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2023 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.itemList + +import android.os.Bundle +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.core.os.bundleOf +import androidx.navigation.NavType +import androidx.navigation.navArgument +import com.android.settingslib.spa.framework.common.EntrySearchData +import com.android.settingslib.spa.framework.common.SettingsEntry +import com.android.settingslib.spa.framework.common.SettingsEntryBuilder +import com.android.settingslib.spa.framework.common.SettingsPageProvider +import com.android.settingslib.spa.framework.common.createSettingsPage +import com.android.settingslib.spa.framework.compose.navigator +import com.android.settingslib.spa.framework.util.getStringArg +import com.android.settingslib.spa.framework.util.navLink +import com.android.settingslib.spa.gallery.SettingsPageProviderEnum +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 OPERATOR_PARAM_NAME = "opParam" + +object ItemListPageProvider : SettingsPageProvider { + override val name = SettingsPageProviderEnum.ITEM_LIST.name + override val displayName = SettingsPageProviderEnum.ITEM_LIST.displayName + override val parameter = listOf( + navArgument(OPERATOR_PARAM_NAME) { type = NavType.StringType }, + ) + + override fun getTitle(arguments: Bundle?): String { + val operation = parameter.getStringArg(OPERATOR_PARAM_NAME, arguments) ?: "NULL" + return "Operation: $operation" + } + + override fun buildEntry(arguments: Bundle?): List { + if (!ItemOperatePageProvider.isValidArgs(arguments)) return emptyList() + val operation = parameter.getStringArg(OPERATOR_PARAM_NAME, arguments)!! + val owner = createSettingsPage(arguments) + return listOf( + ItemOperatePageProvider.buildInjectEntry(operation)!!.setLink(fromPage = owner).build(), + ) + } + + fun buildInjectEntry(opParam: String): SettingsEntryBuilder? { + val arguments = bundleOf(OPERATOR_PARAM_NAME to opParam) + if (!ItemOperatePageProvider.isValidArgs(arguments)) return null + + return SettingsEntryBuilder.createInject( + owner = createSettingsPage(arguments), + displayName = "ItemList_$opParam", + ).setUiLayoutFn { + Preference( + object : PreferenceModel { + override val title = opParam + override val onClick = navigator( + SettingsPageProviderEnum.ITEM_LIST.name + parameter.navLink(it) + ) + } + ) + }.setSearchDataFn { + EntrySearchData(title = "Operation: $opParam") + } + } + + @Composable + override fun Page(arguments: Bundle?) { + val title = remember { getTitle(arguments) } + val entries = remember { buildEntry(arguments) } + val itemList = remember { + // Add logic to get item List during runtime. + listOf("itemFoo", "itemBar", "itemToy") + } + RegularScaffold(title) { + for (item in itemList) { + val rtArgs = ItemOperatePageProvider.genRuntimeArguments(item) + for (entry in entries) { + entry.UiLayout(rtArgs) + } + } + } + } +} diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemOperatePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemOperatePage.kt new file mode 100644 index 0000000000000..8179356e33ef3 --- /dev/null +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemOperatePage.kt @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2023 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.itemList + +import android.os.Bundle +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.core.os.bundleOf +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.SettingsPageProvider +import com.android.settingslib.spa.framework.common.createSettingsPage +import com.android.settingslib.spa.framework.compose.navigator +import com.android.settingslib.spa.framework.util.getStringArg +import com.android.settingslib.spa.framework.util.navLink +import com.android.settingslib.spa.gallery.SettingsPageProviderEnum +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spa.widget.preference.SwitchPreference +import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel + +private const val OPERATOR_PARAM_NAME = "opParam" +private const val ITEM_NAME_PARAM_NAME = "rt_nameParam" +private val ALLOWED_OPERATOR_LIST = listOf("opDnD", "opPiP", "opInstall", "opConnect") + +object ItemOperatePageProvider : SettingsPageProvider { + override val name = SettingsPageProviderEnum.ITEM_OP_PAGE.name + override val displayName = SettingsPageProviderEnum.ITEM_OP_PAGE.displayName + override val parameter = listOf( + navArgument(OPERATOR_PARAM_NAME) { type = NavType.StringType }, + navArgument(ITEM_NAME_PARAM_NAME) { type = NavType.StringType }, + ) + + override fun getTitle(arguments: Bundle?): String { + // Operation name is not a runtime parameter, which should always available + val operation = parameter.getStringArg(OPERATOR_PARAM_NAME, arguments) ?: "opInValid" + // Item name is a runtime parameter, which could be missing + val itemName = parameter.getStringArg(ITEM_NAME_PARAM_NAME, arguments) ?: "[unset]" + return "$operation on $itemName" + } + + override fun buildEntry(arguments: Bundle?): List { + if (!isValidArgs(arguments)) return emptyList() + + val owner = createSettingsPage(arguments) + val entryList = mutableListOf() + entryList.add( + SettingsEntryBuilder.create("ItemName", owner) + .setUiLayoutFn { + // Item name is a runtime parameter, which needs to be read inside UiLayoutFn + val itemName = parameter.getStringArg(ITEM_NAME_PARAM_NAME, it) ?: "NULL" + Preference( + object : PreferenceModel { + override val title = "Item $itemName" + } + ) + }.build() + ) + + // Operation name is not a runtime parameter, which can be read outside. + val opName = parameter.getStringArg(OPERATOR_PARAM_NAME, arguments)!! + entryList.add( + SettingsEntryBuilder.create("ItemOp", owner) + .setUiLayoutFn { + val checked = rememberSaveable { mutableStateOf(false) } + SwitchPreference(remember { + object : SwitchPreferenceModel { + override val title = "Item operation: $opName" + override val checked = checked + override val onCheckedChange = + { newChecked: Boolean -> checked.value = newChecked } + } + }) + }.build(), + ) + return entryList + } + + fun buildInjectEntry(opParam: String): SettingsEntryBuilder? { + val arguments = bundleOf(OPERATOR_PARAM_NAME to opParam) + if (!isValidArgs(arguments)) return null + + return SettingsEntryBuilder.createInject( + owner = createSettingsPage(arguments), + displayName = "ItemOp_$opParam", + ).setUiLayoutFn { + // Item name is a runtime parameter, which needs to be read inside UiLayoutFn + val itemName = parameter.getStringArg(ITEM_NAME_PARAM_NAME, it) ?: "NULL" + Preference( + object : PreferenceModel { + override val title = "item: $itemName" + override val onClick = navigator( + SettingsPageProviderEnum.ITEM_OP_PAGE.name + parameter.navLink(it) + ) + } + ) + } + } + + fun isValidArgs(arguments: Bundle?): Boolean { + val opParam = parameter.getStringArg(OPERATOR_PARAM_NAME, arguments) + return (opParam != null && ALLOWED_OPERATOR_LIST.contains(opParam)) + } + + fun genRuntimeArguments(itemName: String): Bundle { + return bundleOf(ITEM_NAME_PARAM_NAME to itemName) + } +} diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/OperateListPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/OperateListPage.kt new file mode 100644 index 0000000000000..e0baf86119a38 --- /dev/null +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/OperateListPage.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2023 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.itemList + +import android.os.Bundle +import com.android.settingslib.spa.framework.common.SettingsEntry +import com.android.settingslib.spa.framework.common.SettingsEntryBuilder +import com.android.settingslib.spa.framework.common.SettingsPageProvider +import com.android.settingslib.spa.framework.common.createSettingsPage +import com.android.settingslib.spa.framework.compose.navigator +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel + +private const val TITLE = "Operate List Main" + +object OperateListPageProvider : SettingsPageProvider { + override val name = "OpList" + private val owner = createSettingsPage() + + override fun buildEntry(arguments: Bundle?): List { + return listOf( + ItemListPageProvider.buildInjectEntry("opPiP")!!.setLink(fromPage = owner).build(), + ItemListPageProvider.buildInjectEntry("opInstall")!!.setLink(fromPage = owner).build(), + ItemListPageProvider.buildInjectEntry("opDnD")!!.setLink(fromPage = owner).build(), + ItemListPageProvider.buildInjectEntry("opConnect")!!.setLink(fromPage = owner).build(), + ) + } + + override fun getTitle(arguments: Bundle?): String { + return TITLE + } + + fun buildInjectEntry(): SettingsEntryBuilder { + return SettingsEntryBuilder.createInject(owner = owner) + .setUiLayoutFn { + Preference(object : PreferenceModel { + override val title = TITLE + override val onClick = navigator(name) + }) + } + } +} diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt index 42ac1acc09eb7..eca47b6f67ebd 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt @@ -18,6 +18,7 @@ package com.android.settingslib.spa.gallery.page import android.os.Bundle import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.tooling.preview.Preview import com.android.settingslib.spa.framework.common.SettingsEntry import com.android.settingslib.spa.framework.common.SettingsEntryBuilder @@ -101,10 +102,13 @@ object ArgumentPageProvider : SettingsPageProvider { @Composable override fun Page(arguments: Bundle?) { - RegularScaffold(title = getTitle(arguments)) { - for (entry in buildEntry(arguments)) { + val title = remember { getTitle(arguments) } + val entries = remember { buildEntry(arguments) } + val rtArgNext = remember { ArgumentPageModel.buildNextArgument(arguments) } + RegularScaffold(title) { + for (entry in entries) { if (entry.toPage != null) { - entry.UiLayout(ArgumentPageModel.buildNextArgument(arguments)) + entry.UiLayout(rtArgNext) } else { entry.UiLayout() } diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt index 5f15865ff7b9a..5d6aa03ef8b33 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt @@ -132,7 +132,7 @@ class ArgumentPageModel : PageModel() { override val title = PAGE_TITLE override val summary = stateOf(summaryArray.joinToString(", ")) override val onClick = navigator( - SettingsPageProviderEnum.ARGUMENT.displayName + parameter.navLink(arguments) + SettingsPageProviderEnum.ARGUMENT.name + parameter.navLink(arguments) ) } }