Add MainSwitchPreference for SpaLib

Temporarily use material3's Checkbox instead of Switch, before the
androidx.compose.material3_material3 library is updated to date.

Bug: 235727273
Test: Unit test & Manual with Codelab App
Change-Id: I62824111769b3edac42b4cc686186c2bc1a3f7a2
This commit is contained in:
Chaohui Wang
2022-09-06 15:11:14 +08:00
parent 17f6e5b69c
commit 04bee186de
6 changed files with 262 additions and 0 deletions

View File

@@ -25,6 +25,7 @@ import com.android.settingslib.spa.gallery.page.FooterPageProvider
import com.android.settingslib.spa.gallery.page.IllustrationPageProvider
import com.android.settingslib.spa.gallery.page.SettingsPagerPageProvider
import com.android.settingslib.spa.gallery.page.SliderPageProvider
import com.android.settingslib.spa.gallery.preference.MainSwitchPreferencePageProvider
import com.android.settingslib.spa.gallery.preference.PreferenceMainPageProvider
import com.android.settingslib.spa.gallery.preference.PreferencePageProvider
import com.android.settingslib.spa.gallery.preference.SwitchPreferencePageProvider
@@ -40,6 +41,7 @@ object SpaEnvironment {
PreferenceMainPageProvider,
PreferencePageProvider,
SwitchPreferencePageProvider,
MainSwitchPreferencePageProvider,
TwoTargetSwitchPreferencePageProvider,
ArgumentPageProvider,
SliderPageProvider,

View File

@@ -0,0 +1,93 @@
/*
* 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.preference
import android.os.Bundle
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.tooling.preview.Preview
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.framework.theme.SettingsTheme
import com.android.settingslib.spa.widget.preference.MainSwitchPreference
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
private const val TITLE = "Sample MainSwitchPreference"
object MainSwitchPreferencePageProvider : SettingsPageProvider {
override val name = "MainSwitchPreference"
@Composable
override fun Page(arguments: Bundle?) {
MainSwitchPreferencePage()
}
@Composable
fun EntryItem() {
Preference(object : PreferenceModel {
override val title = TITLE
override val onClick = navigator(name)
})
}
}
@Composable
private fun MainSwitchPreferencePage() {
RegularScaffold(title = TITLE) {
SampleMainSwitchPreference()
SampleNotChangeableMainSwitchPreference()
}
}
@Composable
private fun SampleMainSwitchPreference() {
val checked = rememberSaveable { mutableStateOf(false) }
MainSwitchPreference(remember {
object : SwitchPreferenceModel {
override val title = "MainSwitchPreference"
override val checked = checked
override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked }
}
})
}
@Composable
private fun SampleNotChangeableMainSwitchPreference() {
val checked = rememberSaveable { mutableStateOf(true) }
MainSwitchPreference(remember {
object : SwitchPreferenceModel {
override val title = "Not changeable"
override val changeable = stateOf(false)
override val checked = checked
override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked }
}
})
}
@Preview(showBackground = true)
@Composable
private fun MainSwitchPreferencePagePreview() {
SettingsTheme {
MainSwitchPreferencePage()
}
}

View File

@@ -48,6 +48,7 @@ private fun PreferenceMain() {
RegularScaffold(title = TITLE) {
PreferencePageProvider.EntryItem()
SwitchPreferencePageProvider.EntryItem()
MainSwitchPreferencePageProvider.EntryItem()
TwoTargetSwitchPreferencePageProvider.EntryItem()
}
}

View File

@@ -21,4 +21,6 @@ import androidx.compose.ui.unit.dp
object SettingsShape {
val CornerMedium = RoundedCornerShape(12.dp)
val CornerLarge = RoundedCornerShape(24.dp)
}

View File

@@ -0,0 +1,71 @@
/*
* 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.widget.preference
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.android.settingslib.spa.framework.compose.toState
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.framework.theme.SettingsShape
import com.android.settingslib.spa.framework.theme.SettingsTheme
@Composable
fun MainSwitchPreference(model: SwitchPreferenceModel) {
Surface(
modifier = Modifier.padding(SettingsDimension.itemPaddingEnd),
color = when (model.checked.value) {
true -> MaterialTheme.colorScheme.primaryContainer
else -> MaterialTheme.colorScheme.secondaryContainer
},
shape = SettingsShape.CornerLarge,
) {
InternalSwitchPreference(
title = model.title,
checked = model.checked,
changeable = model.changeable,
onCheckedChange = model.onCheckedChange,
paddingStart = 20.dp,
paddingEnd = 20.dp,
paddingVertical = 18.dp,
)
}
}
@Preview
@Composable
fun MainSwitchPreferencePreview() {
SettingsTheme {
Column {
MainSwitchPreference(object : SwitchPreferenceModel {
override val title = "Use Dark theme"
override val checked = true.toState()
override val onCheckedChange: (Boolean) -> Unit = {}
})
MainSwitchPreference(object : SwitchPreferenceModel {
override val title = "Use Dark theme"
override val checked = false.toState()
override val onCheckedChange: (Boolean) -> Unit = {}
})
}
}
}

View File

@@ -0,0 +1,93 @@
/*
* 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.widget.preference
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsOff
import androidx.compose.ui.test.assertIsOn
import androidx.compose.ui.test.isToggleable
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 com.android.settingslib.spa.framework.compose.stateOf
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
private const val TITLE = "Title"
@RunWith(AndroidJUnit4::class)
class MainSwitchPreferenceTest {
@get:Rule
val composeTestRule = createComposeRule()
@Test
fun title_displayed() {
composeTestRule.setContent {
TestMainSwitchPreference(changeable = true)
}
composeTestRule.onNodeWithText(TITLE).assertIsDisplayed()
}
@Test
fun toggleable_initialStateIsCorrect() {
composeTestRule.setContent {
TestMainSwitchPreference(changeable = true)
}
composeTestRule.onNode(isToggleable()).assertIsOff()
}
@Test
fun click_changeable_withEffect() {
composeTestRule.setContent {
TestMainSwitchPreference(changeable = true)
}
composeTestRule.onNodeWithText(TITLE).performClick()
composeTestRule.onNode(isToggleable()).assertIsOn()
}
@Test
fun click_notChangeable_noEffect() {
composeTestRule.setContent {
TestMainSwitchPreference(changeable = false)
}
composeTestRule.onNodeWithText(TITLE).performClick()
composeTestRule.onNode(isToggleable()).assertIsOff()
}
}
@Composable
private fun TestMainSwitchPreference(changeable: Boolean) {
val checked = rememberSaveable { mutableStateOf(false) }
MainSwitchPreference(remember {
object : SwitchPreferenceModel {
override val title = TITLE
override val checked = checked
override val changeable = stateOf(changeable)
override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked }
}
})
}