diff options
| author | 2022-08-15 15:06:03 +0000 | |
|---|---|---|
| committer | 2022-08-15 15:06:03 +0000 | |
| commit | 2e962bc5e96739cd6adc5e70ff6b33aa21287bfd (patch) | |
| tree | a10feb9f7a0d11076d0b711915dfd101a49586d3 | |
| parent | 30f37734240433883d957ddb3aeb36a514dec47e (diff) | |
| parent | 2b942b0394d94c22644f9dfc9b595cec26006aef (diff) | |
Merge changes Id5a3990b,I3121f9a3
* changes:
Add Footer for SpaLib
Add SwitchPreference for SpaLib
12 files changed, 580 insertions, 3 deletions
diff --git a/packages/SettingsLib/Spa/codelab/src/com/android/settingslib/spa/codelab/page/FooterPage.kt b/packages/SettingsLib/Spa/codelab/src/com/android/settingslib/spa/codelab/page/FooterPage.kt new file mode 100644 index 000000000000..9fcbff843203 --- /dev/null +++ b/packages/SettingsLib/Spa/codelab/src/com/android/settingslib/spa/codelab/page/FooterPage.kt @@ -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.codelab.page + +import android.os.Bundle +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.android.settingslib.spa.framework.api.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.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spa.widget.ui.Footer + +object FooterPageProvider : SettingsPageProvider { + override val name = "Footer" + + @Composable + override fun Page(arguments: Bundle?) { + FooterPage() + } + + @Composable + fun EntryItem() { + Preference(object : PreferenceModel { + override val title = "Sample Footer" + override val onClick = navigator(name) + }) + } +} + +@Composable +private fun FooterPage() { + Column(Modifier.verticalScroll(rememberScrollState())) { + Preference(remember { + object : PreferenceModel { + override val title = "Some Preference" + override val summary = stateOf("Some summary") + } + }) + Footer(footerText = "Footer text always at the end of page.") + } +} + +@Preview(showBackground = true) +@Composable +private fun FooterPagePreview() { + SettingsTheme { + FooterPage() + } +} diff --git a/packages/SettingsLib/Spa/codelab/src/com/android/settingslib/spa/codelab/page/HomePage.kt b/packages/SettingsLib/Spa/codelab/src/com/android/settingslib/spa/codelab/page/HomePage.kt index 171a16118052..57a69c4be22f 100644 --- a/packages/SettingsLib/Spa/codelab/src/com/android/settingslib/spa/codelab/page/HomePage.kt +++ b/packages/SettingsLib/Spa/codelab/src/com/android/settingslib/spa/codelab/page/HomePage.kt @@ -50,10 +50,11 @@ private fun HomePage() { ) PreferencePageProvider.EntryItem() - + SwitchPreferencePageProvider.EntryItem() ArgumentPageProvider.EntryItem(stringParam = "foo", intParam = 0) SliderPageProvider.EntryItem() + FooterPageProvider.EntryItem() } } diff --git a/packages/SettingsLib/Spa/codelab/src/com/android/settingslib/spa/codelab/page/PageRepository.kt b/packages/SettingsLib/Spa/codelab/src/com/android/settingslib/spa/codelab/page/PageRepository.kt index c24541a903da..54c588ab18f0 100644 --- a/packages/SettingsLib/Spa/codelab/src/com/android/settingslib/spa/codelab/page/PageRepository.kt +++ b/packages/SettingsLib/Spa/codelab/src/com/android/settingslib/spa/codelab/page/PageRepository.kt @@ -21,6 +21,7 @@ import com.android.settingslib.spa.framework.api.SettingsPageRepository object Destinations { const val Home = "Home" const val Preference = "Preference" + const val SwitchPreference = "SwitchPreference" const val Argument = "Argument" const val Slider = "Slider" } @@ -29,8 +30,10 @@ val codelabPageRepository = SettingsPageRepository( allPages = listOf( HomePageProvider, PreferencePageProvider, + SwitchPreferencePageProvider, ArgumentPageProvider, SliderPageProvider, + FooterPageProvider, ), startDestination = Destinations.Home, ) diff --git a/packages/SettingsLib/Spa/codelab/src/com/android/settingslib/spa/codelab/page/SwitchPreferencePage.kt b/packages/SettingsLib/Spa/codelab/src/com/android/settingslib/spa/codelab/page/SwitchPreferencePage.kt new file mode 100644 index 000000000000..b566afa84d42 --- /dev/null +++ b/packages/SettingsLib/Spa/codelab/src/com/android/settingslib/spa/codelab/page/SwitchPreferencePage.kt @@ -0,0 +1,129 @@ +/* + * 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.codelab.page + +import android.os.Bundle +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.produceState +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.android.settingslib.spa.framework.api.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.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 +import kotlinx.coroutines.delay + +object SwitchPreferencePageProvider : SettingsPageProvider { + override val name = Destinations.SwitchPreference + + @Composable + override fun Page(arguments: Bundle?) { + SwitchPreferencePage() + } + + @Composable + fun EntryItem() { + Preference(object : PreferenceModel { + override val title = "Sample SwitchPreference" + override val onClick = navigator(Destinations.SwitchPreference) + }) + } +} + +@Composable +private fun SwitchPreferencePage() { + Column(Modifier.verticalScroll(rememberScrollState())) { + SampleSwitchPreference() + SampleSwitchPreferenceWithSummary() + SampleSwitchPreferenceWithAsyncSummary() + SampleNotChangeableSwitchPreference() + } +} + +@Composable +private fun SampleSwitchPreference() { + val checked = rememberSaveable { mutableStateOf(false) } + SwitchPreference(remember { + object : SwitchPreferenceModel { + override val title = "SwitchPreference" + override val checked = checked + override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked } + } + }) +} + +@Composable +private fun SampleSwitchPreferenceWithSummary() { + val checked = rememberSaveable { mutableStateOf(true) } + SwitchPreference(remember { + object : SwitchPreferenceModel { + override val title = "SwitchPreference" + override val summary = stateOf("With summary") + override val checked = checked + override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked } + } + }) +} + +@Composable +private fun SampleSwitchPreferenceWithAsyncSummary() { + val checked = rememberSaveable { mutableStateOf(true) } + val summary = produceState(initialValue = " ") { + delay(1000L) + value = "Async summary" + } + SwitchPreference(remember { + object : SwitchPreferenceModel { + override val title = "SwitchPreference" + override val summary = summary + override val checked = checked + override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked } + } + }) +} + +@Composable +private fun SampleNotChangeableSwitchPreference() { + val checked = rememberSaveable { mutableStateOf(true) } + SwitchPreference(remember { + object : SwitchPreferenceModel { + override val title = "SwitchPreference" + override val summary = stateOf("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 SwitchPreferencePagePreview() { + SettingsTheme { + SwitchPreferencePage() + } +} diff --git a/packages/SettingsLib/Spa/spa/Android.bp b/packages/SettingsLib/Spa/spa/Android.bp index 463c0765943f..3c8d91edc05b 100644 --- a/packages/SettingsLib/Spa/spa/Android.bp +++ b/packages/SettingsLib/Spa/spa/Android.bp @@ -31,6 +31,9 @@ android_library { "androidx.navigation_navigation-compose", "com.google.android.material_material", ], - kotlincflags: ["-Xjvm-default=all"], + kotlincflags: [ + "-Xjvm-default=all", + "-Xopt-in=kotlin.RequiresOptIn", + ], min_sdk_version: "31", } diff --git a/packages/SettingsLib/Spa/spa/build.gradle b/packages/SettingsLib/Spa/spa/build.gradle index 62f74d052471..ad69da314735 100644 --- a/packages/SettingsLib/Spa/spa/build.gradle +++ b/packages/SettingsLib/Spa/spa/build.gradle @@ -43,7 +43,7 @@ android { } kotlinOptions { jvmTarget = '1.8' - freeCompilerArgs = ["-Xjvm-default=all"] + freeCompilerArgs = ["-Xjvm-default=all", "-Xopt-in=kotlin.RequiresOptIn"] } buildFeatures { compose true diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt index 9a67c12dfd0b..e1ca69bd7940 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt @@ -20,6 +20,7 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.ui.unit.dp object SettingsDimension { + val itemIconSize = 24.dp val itemIconContainerSize = 72.dp val itemPaddingStart = 24.dp val itemPaddingEnd = 16.dp diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SwitchPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SwitchPreference.kt new file mode 100644 index 000000000000..0dab0dfe1d6d --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SwitchPreference.kt @@ -0,0 +1,146 @@ +/* + * 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.LocalIndication +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.selection.toggleable +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import com.android.settingslib.spa.framework.compose.stateOf +import com.android.settingslib.spa.framework.compose.toState +import com.android.settingslib.spa.framework.theme.SettingsDimension +import com.android.settingslib.spa.framework.theme.SettingsTheme +import com.android.settingslib.spa.widget.ui.SettingsSwitch + +/** + * The widget model for [SwitchPreference] widget. + */ +interface SwitchPreferenceModel { + /** + * The title of this [SwitchPreference]. + */ + val title: String + + /** + * The summary of this [SwitchPreference]. + */ + val summary: State<String> + get() = stateOf("") + + /** + * Indicates whether this [SwitchPreference] is checked. + * + * This can be `null` during the data loading before the data is available. + */ + val checked: State<Boolean?> + + /** + * Indicates whether this [SwitchPreference] is changeable. + * + * Not changeable [SwitchPreference] will be displayed in disabled style. + */ + val changeable: State<Boolean> + get() = stateOf(true) + + /** + * The switch change handler of this [SwitchPreference]. + * + * If `null`, this [SwitchPreference] is not [toggleable]. + */ + val onCheckedChange: ((newChecked: Boolean) -> Unit)? +} + +/** + * SwitchPreference widget. + * + * Data is provided through [SwitchPreferenceModel]. + */ +@Composable +fun SwitchPreference(model: SwitchPreferenceModel) { + InternalSwitchPreference( + title = model.title, + summary = model.summary, + checked = model.checked, + changeable = model.changeable, + onCheckedChange = model.onCheckedChange, + ) +} + +@Composable +internal fun InternalSwitchPreference( + title: String, + summary: State<String> = "".toState(), + checked: State<Boolean?>, + changeable: State<Boolean> = true.toState(), + paddingStart: Dp = SettingsDimension.itemPaddingStart, + paddingEnd: Dp = SettingsDimension.itemPaddingEnd, + paddingVertical: Dp = SettingsDimension.itemPaddingVertical, + onCheckedChange: ((newChecked: Boolean) -> Unit)?, +) { + val checkedValue = checked.value + val indication = LocalIndication.current + val modifier = remember(checkedValue) { + if (checkedValue != null && onCheckedChange != null) { + Modifier.toggleable( + value = checkedValue, + interactionSource = MutableInteractionSource(), + indication = indication, + enabled = changeable.value, + role = Role.Switch, + onValueChange = onCheckedChange, + ) + } else Modifier + } + BasePreference( + title = title, + summary = summary, + modifier = modifier, + enabled = changeable, + paddingStart = paddingStart, + paddingEnd = paddingEnd, + paddingVertical = paddingVertical, + ) { + SettingsSwitch(checked = checked, changeable = changeable) + } +} + +@Preview +@Composable +private fun SwitchPreferencePreview() { + SettingsTheme { + Column { + InternalSwitchPreference( + title = "Use Dark theme", + checked = true.toState(), + onCheckedChange = {}, + ) + InternalSwitchPreference( + title = "Use Dark theme", + summary = "Summary".toState(), + checked = false.toState(), + onCheckedChange = {}, + ) + } + } +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Footer.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Footer.kt new file mode 100644 index 000000000000..41fd03b08563 --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Footer.kt @@ -0,0 +1,47 @@ +/* + * 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.ui + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Info +import androidx.compose.runtime.Composable +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 Footer(footerText: String) { + if (footerText.isEmpty()) return + Column(Modifier.padding(SettingsDimension.itemPadding)) { + SettingsIcon(imageVector = Icons.Outlined.Info, contentDescription = null) + Spacer(modifier = Modifier.height(SettingsDimension.itemPaddingVertical)) + SettingsBody(footerText) + } +} + +@Preview +@Composable +private fun FooterPreview() { + SettingsTheme { + Footer("Footer text always at the end of page.") + } +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Icon.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Icon.kt new file mode 100644 index 000000000000..cb08cdb20885 --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Icon.kt @@ -0,0 +1,38 @@ +/* + * 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.ui + +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import com.android.settingslib.spa.framework.theme.SettingsDimension + +@Composable +fun SettingsIcon( + imageVector: ImageVector, + contentDescription: String?, +) { + Icon( + imageVector = imageVector, + contentDescription = contentDescription, + modifier = Modifier.size(SettingsDimension.itemIconSize), + tint = MaterialTheme.colorScheme.onSurface, + ) +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Switch.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Switch.kt new file mode 100644 index 000000000000..45d5f6baa9cb --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Switch.kt @@ -0,0 +1,47 @@ +/* + * 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.ui + +import androidx.compose.material3.Checkbox +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SettingsSwitch( + checked: State<Boolean?>, + changeable: State<Boolean>, + onCheckedChange: ((newChecked: Boolean) -> Unit)? = null, +) { + // TODO: Replace Checkbox with Switch when the androidx.compose.material3_material3 library is + // updated to date. + val checkedValue = checked.value + if (checkedValue != null) { + Checkbox( + checked = checkedValue, + onCheckedChange = onCheckedChange, + enabled = changeable.value, + ) + } else { + Checkbox( + checked = false, + onCheckedChange = null, + enabled = false, + ) + } +} diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/SwitchPreferenceTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/SwitchPreferenceTest.kt new file mode 100644 index 000000000000..d6c8fbc9dc9e --- /dev/null +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/SwitchPreferenceTest.kt @@ -0,0 +1,91 @@ +/* + * 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 + +@RunWith(AndroidJUnit4::class) +class SwitchPreferenceTest { + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun title_displayed() { + composeTestRule.setContent { + TestSwitchPreference(changeable = true) + } + + composeTestRule.onNodeWithText("SwitchPreference").assertIsDisplayed() + } + + @Test + fun toggleable_initialStateIsCorrect() { + composeTestRule.setContent { + TestSwitchPreference(changeable = true) + } + + composeTestRule.onNode(isToggleable()).assertIsOff() + } + + @Test + fun click_changeable_withEffect() { + composeTestRule.setContent { + TestSwitchPreference(changeable = true) + } + + composeTestRule.onNodeWithText("SwitchPreference").performClick() + composeTestRule.onNode(isToggleable()).assertIsOn() + } + + @Test + fun click_notChangeable_noEffect() { + composeTestRule.setContent { + TestSwitchPreference(changeable = false) + } + + composeTestRule.onNodeWithText("SwitchPreference").performClick() + composeTestRule.onNode(isToggleable()).assertIsOff() + } +} + +@Composable +private fun TestSwitchPreference(changeable: Boolean) { + val checked = rememberSaveable { mutableStateOf(false) } + SwitchPreference(remember { + object : SwitchPreferenceModel { + override val title = "SwitchPreference" + override val checked = checked + override val changeable = stateOf(changeable) + override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked } + } + }) +} |