diff options
author | 2023-09-08 01:54:52 +0000 | |
---|---|---|
committer | 2023-09-08 01:54:52 +0000 | |
commit | d3965882d85bc4f57c9e01c5ebda70498218cfc5 (patch) | |
tree | 62c24c0b042178c9d71f09f40edcafd9d934cab9 | |
parent | 3e5da2007c3b72a42a8027df05a1a207ec7d0b23 (diff) | |
parent | febe9889489fc16c0ce8ffa44a6026465059ea24 (diff) |
Merge "Create new editor in spa." into main
12 files changed, 899 insertions, 0 deletions
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 11a89566a2a8..4a252a91b12f 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 @@ -23,10 +23,14 @@ import com.android.settingslib.spa.framework.common.SpaEnvironment import com.android.settingslib.spa.framework.common.createSettingsPage import com.android.settingslib.spa.gallery.button.ActionButtonPageProvider import com.android.settingslib.spa.gallery.dialog.AlertDialogPageProvider +import com.android.settingslib.spa.gallery.editor.EditorMainPageProvider +import com.android.settingslib.spa.gallery.editor.SettingsExposedDropdownMenuBoxPageProvider +import com.android.settingslib.spa.gallery.editor.SettingsExposedDropdownMenuCheckBoxProvider 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.editor.SettingsOutlinedTextFieldPageProvider import com.android.settingslib.spa.gallery.page.ArgumentPageProvider import com.android.settingslib.spa.gallery.page.ChartPageProvider import com.android.settingslib.spa.gallery.page.FooterPageProvider @@ -84,6 +88,10 @@ class GallerySpaEnvironment(context: Context) : SpaEnvironment(context) { ItemListPageProvider, ItemOperatePageProvider, OperateListPageProvider, + EditorMainPageProvider, + SettingsOutlinedTextFieldPageProvider, + SettingsExposedDropdownMenuBoxPageProvider, + SettingsExposedDropdownMenuCheckBoxProvider, ), rootPages = listOf( HomePageProvider.createSettingsPage(), diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/EditorMainPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/EditorMainPageProvider.kt new file mode 100644 index 000000000000..b74af213a058 --- /dev/null +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/EditorMainPageProvider.kt @@ -0,0 +1,58 @@ +/* + * 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.editor + +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 = "Category: Editor" + +object EditorMainPageProvider : SettingsPageProvider { + override val name = "EditorMain" + private val owner = createSettingsPage() + + override fun buildEntry(arguments: Bundle?): List<SettingsEntry> { + return listOf( + SettingsOutlinedTextFieldPageProvider.buildInjectEntry().setLink(fromPage = owner) + .build(), + SettingsExposedDropdownMenuBoxPageProvider.buildInjectEntry().setLink(fromPage = owner) + .build(), + SettingsExposedDropdownMenuCheckBoxProvider.buildInjectEntry().setLink(fromPage = owner) + .build(), + ) + } + + fun buildInjectEntry(): SettingsEntryBuilder { + return SettingsEntryBuilder.createInject(owner = owner) + .setUiLayoutFn { + Preference(object : PreferenceModel { + override val title = TITLE + override val onClick = navigator(name) + }) + } + } + + override fun getTitle(arguments: Bundle?): String { + return TITLE + } +} diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsExposedDropdownMenuBoxPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsExposedDropdownMenuBoxPageProvider.kt new file mode 100644 index 000000000000..6d22e6abf7e3 --- /dev/null +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsExposedDropdownMenuBoxPageProvider.kt @@ -0,0 +1,77 @@ +/* + * 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.editor + +import android.os.Bundle +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +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.SettingsPageProvider +import com.android.settingslib.spa.framework.common.createSettingsPage +import com.android.settingslib.spa.framework.compose.navigator +import com.android.settingslib.spa.framework.theme.SettingsTheme +import com.android.settingslib.spa.widget.editor.SettingsExposedDropdownMenuBox +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 SettingsExposedDropdownMenuBox" + +object SettingsExposedDropdownMenuBoxPageProvider : SettingsPageProvider { + override val name = "SettingsExposedDropdownMenuBox" + private const val exposedDropdownMenuBoxLabel = "ExposedDropdownMenuBoxLabel" + + override fun getTitle(arguments: Bundle?): String { + return TITLE + } + + @Composable + override fun Page(arguments: Bundle?) { + var selectedItem by remember { mutableStateOf("item1") } + val options = listOf("item1", "item2", "item3") + RegularScaffold(title = TITLE) { + SettingsExposedDropdownMenuBox( + label = exposedDropdownMenuBoxLabel, + options = options, + selectedOptionText = selectedItem, + enabled = true, + onselectedOptionTextChange = { selectedItem = it }) + } + } + + fun buildInjectEntry(): SettingsEntryBuilder { + return SettingsEntryBuilder.createInject(owner = createSettingsPage()) + .setUiLayoutFn { + Preference(object : PreferenceModel { + override val title = TITLE + override val onClick = navigator(name) + }) + } + } +} + +@Preview(showBackground = true) +@Composable +private fun SettingsExposedDropdownMenuBoxPagePreview() { + SettingsTheme { + SettingsExposedDropdownMenuBoxPageProvider.Page(null) + } +} diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsExposedDropdownMenuCheckBoxProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsExposedDropdownMenuCheckBoxProvider.kt new file mode 100644 index 000000000000..292e002779f5 --- /dev/null +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsExposedDropdownMenuCheckBoxProvider.kt @@ -0,0 +1,73 @@ +/* + * 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.editor + +import android.os.Bundle +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.remember +import androidx.compose.ui.tooling.preview.Preview +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.theme.SettingsTheme +import com.android.settingslib.spa.widget.editor.SettingsExposedDropdownMenuCheckBox +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 SettingsExposedDropdownMenuCheckBox" + +object SettingsExposedDropdownMenuCheckBoxProvider : SettingsPageProvider { + override val name = "SettingsExposedDropdownMenuCheckBox" + private const val exposedDropdownMenuCheckBoxLabel = "ExposedDropdownMenuCheckBoxLabel" + private val options = listOf("item1", "item2", "item3") + private val selectedOptionsState1 = mutableStateListOf("item1", "item2") + + override fun getTitle(arguments: Bundle?): String { + return TITLE + } + + @Composable + override fun Page(arguments: Bundle?) { + RegularScaffold(title = TITLE) { + SettingsExposedDropdownMenuCheckBox(label = exposedDropdownMenuCheckBoxLabel, + options = options, + selectedOptionsState = remember { selectedOptionsState1 }, + enabled = true, + onselectedOptionStateChange = {}) + } + } + + fun buildInjectEntry(): SettingsEntryBuilder { + return SettingsEntryBuilder.createInject(owner = createSettingsPage()).setUiLayoutFn { + Preference(object : PreferenceModel { + override val title = TITLE + override val onClick = navigator(name) + }) + } + } +} + +@Preview(showBackground = true) +@Composable +private fun SettingsExposedDropdownMenuCheckBoxPagePreview() { + SettingsTheme { + SettingsExposedDropdownMenuCheckBoxProvider.Page(null) + } +}
\ No newline at end of file diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsOutlinedTextFieldPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsOutlinedTextFieldPageProvider.kt new file mode 100644 index 000000000000..54fa5a95d812 --- /dev/null +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsOutlinedTextFieldPageProvider.kt @@ -0,0 +1,74 @@ +/* + * 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.editor + +import android.os.Bundle +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +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.SettingsPageProvider +import com.android.settingslib.spa.framework.common.createSettingsPage +import com.android.settingslib.spa.framework.compose.navigator +import com.android.settingslib.spa.framework.theme.SettingsTheme +import com.android.settingslib.spa.widget.editor.SettingsOutlinedTextField +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 SettingsOutlinedTextField" + +object SettingsOutlinedTextFieldPageProvider : SettingsPageProvider { + override val name = "SettingsOutlinedTextField" + + override fun getTitle(arguments: Bundle?): String { + return TITLE + } + + @Composable + override fun Page(arguments: Bundle?) { + var value by remember { mutableStateOf("Enabled Value") } + RegularScaffold(title = TITLE) { + SettingsOutlinedTextField( + value = value, + label = "OutlinedTextField Enabled", + enabled = true, + onTextChange = {value = it}) + } + } + + fun buildInjectEntry(): SettingsEntryBuilder { + return SettingsEntryBuilder.createInject(owner = createSettingsPage()) + .setUiLayoutFn { + Preference(object : PreferenceModel { + override val title = TITLE + override val onClick = navigator(name) + }) + } + } +} + +@Preview(showBackground = true) +@Composable +private fun SettingsOutlinedTextFieldPagePreview() { + SettingsTheme { + SettingsOutlinedTextFieldPageProvider.Page(null) + } +}
\ No newline at end of file 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/HomePageProvider.kt index c60ebfdb1bd3..bb311a52052a 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/HomePageProvider.kt @@ -29,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.AlertDialogPageProvider +import com.android.settingslib.spa.gallery.editor.EditorMainPageProvider import com.android.settingslib.spa.gallery.itemList.OperateListPageProvider import com.android.settingslib.spa.gallery.page.ArgumentPageModel import com.android.settingslib.spa.gallery.page.ArgumentPageProvider @@ -65,6 +66,7 @@ object HomePageProvider : SettingsPageProvider { LoadingBarPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), ChartPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), AlertDialogPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), + EditorMainPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), ) } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBox.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBox.kt new file mode 100644 index 000000000000..d7bbf0871f71 --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBox.kt @@ -0,0 +1,107 @@ +/* + * 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.widget.editor + +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExposedDropdownMenuDefaults +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.android.settingslib.spa.framework.theme.SettingsDimension +import androidx.compose.material3.ExposedDropdownMenuBox +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.tooling.preview.Preview +import com.android.settingslib.spa.framework.theme.SettingsTheme + +@Composable +@OptIn(ExperimentalMaterial3Api::class) +fun SettingsExposedDropdownMenuBox( + label: String, + options: List<String>, + selectedOptionText: String, + enabled: Boolean, + onselectedOptionTextChange: (String) -> Unit, +) { + var expanded by remember { mutableStateOf(false) } + ExposedDropdownMenuBox( + expanded = expanded, + onExpandedChange = { expanded = it }, + modifier = Modifier + .padding(SettingsDimension.itemPadding), + ) { + OutlinedTextField( + // The `menuAnchor` modifier must be passed to the text field for correctness. + modifier = Modifier + .menuAnchor() + .fillMaxWidth(), + value = selectedOptionText, + onValueChange = onselectedOptionTextChange, + label = { Text(text = label) }, + trailingIcon = { + ExposedDropdownMenuDefaults.TrailingIcon( + expanded = expanded + ) + }, + singleLine = true, + readOnly = true, + enabled = enabled + ) + if (options.isNotEmpty()) { + ExposedDropdownMenu( + expanded = expanded, + modifier = Modifier + .fillMaxWidth(), + onDismissRequest = { expanded = false }, + ) { + options.forEach { option -> + DropdownMenuItem( + text = { Text(option) }, + onClick = { + onselectedOptionTextChange(option) + expanded = false + }, + contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding, + ) + } + } + } + } +} + +@Preview +@Composable +private fun SettingsExposedDropdownMenuBoxsPreview() { + val item1 = "item1" + val item2 = "item2" + val item3 = "item3" + val options = listOf(item1, item2, item3) + SettingsTheme { + SettingsExposedDropdownMenuBox( + label = "ExposedDropdownMenuBoxLabel", + options = options, + selectedOptionText = item1, + enabled = true, + onselectedOptionTextChange = {}) + } +}
\ No newline at end of file diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuCheckBox.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuCheckBox.kt new file mode 100644 index 000000000000..6b3ae772f224 --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuCheckBox.kt @@ -0,0 +1,131 @@ +/* + * 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.widget.editor + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Checkbox +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExposedDropdownMenuBox +import androidx.compose.material3.ExposedDropdownMenuDefaults +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshots.SnapshotStateList +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.onSizeChanged +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.android.settingslib.spa.framework.theme.SettingsDimension +import com.android.settingslib.spa.framework.theme.SettingsTheme + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SettingsExposedDropdownMenuCheckBox( + label: String, + options: List<String>, + selectedOptionsState: SnapshotStateList<String>, + enabled: Boolean, + onselectedOptionStateChange: (String) -> Unit, +) { + var dropDownWidth by remember { mutableStateOf(0) } + var expanded by remember { mutableStateOf(false) } + ExposedDropdownMenuBox( + expanded = expanded, + onExpandedChange = { expanded = it }, + modifier = Modifier.width(350.dp).padding( + horizontal = SettingsDimension.itemPaddingEnd, + vertical = SettingsDimension.itemPaddingVertical + ).onSizeChanged { + dropDownWidth = it.width + }, + ) { + OutlinedTextField( + // The `menuAnchor` modifier must be passed to the text field for correctness. + modifier = Modifier.menuAnchor().fillMaxWidth(), + value = selectedOptionsState.joinToString(", "), + onValueChange = onselectedOptionStateChange, + label = { Text(text = label) }, + trailingIcon = { + ExposedDropdownMenuDefaults.TrailingIcon( + expanded = expanded + ) + }, + readOnly = true, + enabled = enabled + ) + if (options.isNotEmpty()) { + ExposedDropdownMenu( + expanded = expanded, + modifier = Modifier.fillMaxWidth() + .width(with(LocalDensity.current) { dropDownWidth.toDp() }), + onDismissRequest = { expanded = false }, + ) { + options.forEach { option -> + TextButton(modifier = Modifier.fillMaxHeight().fillMaxWidth(), onClick = { + if (selectedOptionsState.contains(option)) { + selectedOptionsState.remove( + option + ) + } else { + selectedOptionsState.add( + option + ) + } + }) { + Row( + modifier = Modifier.fillMaxHeight().fillMaxWidth(), + horizontalArrangement = Arrangement.Start, + verticalAlignment = Alignment.CenterVertically + ) { + Checkbox(checked = selectedOptionsState.contains( + option + ), onCheckedChange = {}) + Text(text = option) + } + } + } + } + } + } +} + +@Preview +@Composable +private fun ActionButtonsPreview() { + val options = listOf("item1", "item2", "item3") + val selectedOptionsState = remember { mutableStateListOf("item1", "item2") } + SettingsTheme { + SettingsExposedDropdownMenuCheckBox(label = "label", + options = options, + selectedOptionsState = selectedOptionsState, + enabled = true, + onselectedOptionStateChange = {}) + } +}
\ No newline at end of file diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsOutlinedTextField.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsOutlinedTextField.kt new file mode 100644 index 000000000000..3819a1075adb --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsOutlinedTextField.kt @@ -0,0 +1,66 @@ +/* + * 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.widget.editor + +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.android.settingslib.spa.framework.theme.SettingsDimension +import com.android.settingslib.spa.framework.theme.SettingsTheme + +@Composable +fun SettingsOutlinedTextField( + value: String, + label: String, + singleLine: Boolean = true, + enabled: Boolean = true, + onTextChange: (String) -> Unit, +) { + OutlinedTextField( + modifier = Modifier + .fillMaxWidth() + .padding(SettingsDimension.itemPadding), + value = value, + onValueChange = onTextChange, + label = { + Text(text = label) + }, + singleLine = singleLine, + enabled = enabled, + ) +} + +@Preview +@Composable +private fun SettingsOutlinedTextFieldPreview() { + var value by remember { mutableStateOf("Enabled Value") } + SettingsTheme { + SettingsOutlinedTextField( + value = value, + label = "OutlinedTextField Enabled", + enabled = true, + onTextChange = {value = it}) + } +}
\ No newline at end of file diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBoxTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBoxTest.kt new file mode 100644 index 000000000000..09f59457b32d --- /dev/null +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBoxTest.kt @@ -0,0 +1,94 @@ +/* + * 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.widget.editor + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class SettingsExposedDropdownMenuBoxTest { + @get:Rule + val composeTestRule = createComposeRule() + private val options = listOf("item1", "item2", "item3") + private val item2 = "item2" + private val exposedDropdownMenuBoxLabel = "ExposedDropdownMenuBoxLabel" + + @Test + fun exposedDropdownMenuBoxs_displayed() { + composeTestRule.setContent { + var selectedItem by remember { mutableStateOf("item1") } + SettingsExposedDropdownMenuBox( + label = exposedDropdownMenuBoxLabel, + options = options, + selectedOptionText = selectedItem, + enabled = true, + onselectedOptionTextChange = {selectedItem = it}) + } + composeTestRule.onNodeWithText(exposedDropdownMenuBoxLabel, substring = true) + .assertIsDisplayed() + } + + @Test + fun exposedDropdownMenuBoxs_expanded() { + composeTestRule.setContent { + var selectedItem by remember { mutableStateOf("item1") } + SettingsExposedDropdownMenuBox( + label = exposedDropdownMenuBoxLabel, + options = options, + selectedOptionText = selectedItem, + enabled = true, + onselectedOptionTextChange = {selectedItem = it}) + } + composeTestRule.onNodeWithText(item2, substring = true) + .assertDoesNotExist() + composeTestRule.onNodeWithText(exposedDropdownMenuBoxLabel, substring = true) + .performClick() + composeTestRule.onNodeWithText(item2, substring = true) + .assertIsDisplayed() + } + + @Test + fun exposedDropdownMenuBoxs_valueChanged() { + composeTestRule.setContent { + var selectedItem by remember { mutableStateOf("item1") } + SettingsExposedDropdownMenuBox( + label = exposedDropdownMenuBoxLabel, + options = options, + selectedOptionText = selectedItem, + enabled = true, + onselectedOptionTextChange = {selectedItem = it}) + } + composeTestRule.onNodeWithText(item2, substring = true) + .assertDoesNotExist() + composeTestRule.onNodeWithText(exposedDropdownMenuBoxLabel, substring = true) + .performClick() + composeTestRule.onNodeWithText(item2, substring = true) + .performClick() + composeTestRule.onNodeWithText(item2, substring = true) + .assertIsDisplayed() + } +}
\ No newline at end of file diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuCheckBoxTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuCheckBoxTest.kt new file mode 100644 index 000000000000..58bc72213a1b --- /dev/null +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuCheckBoxTest.kt @@ -0,0 +1,111 @@ +/* + * 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.widget.editor + +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.remember +import androidx.compose.ui.test.SemanticsNodeInteraction +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.hasText +import androidx.compose.ui.test.isFocused +import androidx.compose.ui.test.junit4.ComposeContentTestRule +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class SettingsExposedDropdownMenuCheckBoxTest { + @get:Rule + val composeTestRule = createComposeRule() + private val item1 = "item1" + private val item2 = "item2" + private val item3 = "item3" + private val options = listOf(item1, item2, item3) + private val selectedOptionsState1 = mutableStateListOf(item1, item2) + private val exposedDropdownMenuCheckBoxLabel = "ExposedDropdownMenuCheckBoxLabel" + + @Test + fun exposedDropdownMenuCheckBox_displayed() { + composeTestRule.setContent { + SettingsExposedDropdownMenuCheckBox(label = exposedDropdownMenuCheckBoxLabel, + options = options, + selectedOptionsState = remember { selectedOptionsState1 }, + enabled = true, + onselectedOptionStateChange = {}) + } + composeTestRule.onNodeWithText( + exposedDropdownMenuCheckBoxLabel, substring = true + ).assertIsDisplayed() + } + + @Test + fun exposedDropdownMenuCheckBox_expanded() { + composeTestRule.setContent { + SettingsExposedDropdownMenuCheckBox(label = exposedDropdownMenuCheckBoxLabel, + options = options, + selectedOptionsState = remember { selectedOptionsState1 }, + enabled = true, + onselectedOptionStateChange = {}) + } + composeTestRule.onNodeWithText(item3, substring = true).assertDoesNotExist() + composeTestRule.onNodeWithText(exposedDropdownMenuCheckBoxLabel, substring = true) + .performClick() + composeTestRule.onNodeWithText(item3, substring = true).assertIsDisplayed() + } + + @Test + fun exposedDropdownMenuCheckBox_valueAdded() { + composeTestRule.setContent { + SettingsExposedDropdownMenuCheckBox(label = exposedDropdownMenuCheckBoxLabel, + options = options, + selectedOptionsState = remember { selectedOptionsState1 }, + enabled = true, + onselectedOptionStateChange = {}) + } + composeTestRule.onNodeWithText(item3, substring = true).assertDoesNotExist() + composeTestRule.onNodeWithText(exposedDropdownMenuCheckBoxLabel, substring = true) + .performClick() + composeTestRule.onNodeWithText(item3, substring = true).performClick() + composeTestRule.onFocusedText(item3).assertIsDisplayed() + } + + @Test + fun exposedDropdownMenuCheckBox_valueDeleted() { + composeTestRule.setContent { + SettingsExposedDropdownMenuCheckBox(label = exposedDropdownMenuCheckBoxLabel, + options = options, + selectedOptionsState = remember { selectedOptionsState1 }, + enabled = true, + onselectedOptionStateChange = {}) + } + composeTestRule.onNodeWithText(item2, substring = true).assertIsDisplayed() + composeTestRule.onNodeWithText(exposedDropdownMenuCheckBoxLabel, substring = true) + .performClick() + composeTestRule.onNotFocusedText(item2).performClick() + composeTestRule.onFocusedText(item2).assertDoesNotExist() + } +} + +fun ComposeContentTestRule.onFocusedText(text: String): SemanticsNodeInteraction = + onNode(isFocused() and hasText(text, substring = true)) + +fun ComposeContentTestRule.onNotFocusedText(text: String): SemanticsNodeInteraction = + onNode(!isFocused() and hasText(text, substring = true))
\ No newline at end of file diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsOutlinedTextFieldsTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsOutlinedTextFieldsTest.kt new file mode 100644 index 000000000000..5eff1a29e12c --- /dev/null +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsOutlinedTextFieldsTest.kt @@ -0,0 +1,98 @@ +/* + * 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.widget.editor + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.assertIsEnabled +import androidx.compose.ui.test.assertIsNotEnabled +import androidx.compose.ui.test.assertTextContains +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performTextReplacement +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class SettingsOutlinedTextFieldsTest { + @get:Rule + val composeTestRule = createComposeRule() + private val outlinedTextFieldLabel = "OutlinedTextField Enabled" + private val enabledValue = "Enabled Value" + private val disabledValue = "Disabled Value" + private val valueChanged = "Value Changed" + + @Test + fun outlinedTextField_displayed() { + composeTestRule.setContent { + SettingsOutlinedTextField( + value = enabledValue, + label = outlinedTextFieldLabel, + enabled = true, + onTextChange = {}) + } + composeTestRule.onNodeWithText(outlinedTextFieldLabel, substring = true) + .assertIsDisplayed() + } + + @Test + fun outlinedTextFields_enabled() { + composeTestRule.setContent { + SettingsOutlinedTextField( + value = enabledValue, + label = outlinedTextFieldLabel, + enabled = true, + onTextChange = {}) + } + composeTestRule.onNodeWithText(outlinedTextFieldLabel, substring = true) + .assertIsEnabled() + } + + @Test + fun outlinedTextFields_disabled() { + composeTestRule.setContent { + SettingsOutlinedTextField( + value = disabledValue, + label = outlinedTextFieldLabel, + enabled = false, + onTextChange = {}) + } + composeTestRule.onNodeWithText(outlinedTextFieldLabel, substring = true) + .assertIsNotEnabled() + } + + @Test + fun outlinedTextFields_inputValue() { + composeTestRule.setContent { + var value by remember { mutableStateOf(enabledValue) } + SettingsOutlinedTextField( + value = value, + label = outlinedTextFieldLabel, + enabled = true, + onTextChange = { value = it }) + } + composeTestRule.onNodeWithText(outlinedTextFieldLabel, substring = true) + .performTextReplacement(valueChanged) + composeTestRule.onNodeWithText(outlinedTextFieldLabel, substring = true) + .assertTextContains(valueChanged) + } +} |