summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SettingsLib/Spa/gallery/res/values/strings.xml5
-rw-r--r--packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt20
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BasePreference.kt11
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt6
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt36
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/PreferenceTest.kt79
6 files changed, 145 insertions, 12 deletions
diff --git a/packages/SettingsLib/Spa/gallery/res/values/strings.xml b/packages/SettingsLib/Spa/gallery/res/values/strings.xml
index 0d08d682b4ac..0d1a1fe312e2 100644
--- a/packages/SettingsLib/Spa/gallery/res/values/strings.xml
+++ b/packages/SettingsLib/Spa/gallery/res/values/strings.xml
@@ -19,4 +19,9 @@
<string name="app_label" translatable="false">Gallery</string>
<!-- Gallery App name. [DO NOT TRANSLATE] -->
<string name="app_name" translatable="false">SpaLib Gallery</string>
+
+ <!-- Title for single line summary preference. [DO NOT TRANSLATE] -->
+ <string name="single_line_summary_preference_title" translatable="false">Preference (singleLineSummary = true)</string>
+ <!-- Summary for single line summary preference. [DO NOT TRANSLATE] -->
+ <string name="single_line_summary_preference_summary" translatable="false">A very long summary to show case a preference which only shows a single line summary.</string>
</resources>
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
index af30e79f45b5..f7f01eaa4a93 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
@@ -24,12 +24,15 @@ import androidx.compose.material.icons.outlined.TouchApp
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.remember
+import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
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.compose.toState
import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.gallery.R
import com.android.settingslib.spa.gallery.SettingsPageProviderEnum
import com.android.settingslib.spa.gallery.createSettingsPage
import com.android.settingslib.spa.gallery.preference.PreferencePageModel.Companion.ASYNC_PREFERENCE_TITLE
@@ -55,6 +58,7 @@ object PreferencePageProvider : SettingsPageProvider {
enum class EntryEnum(val displayName: String) {
SIMPLE_PREFERENCE("preference"),
SUMMARY_PREFERENCE("preference_with_summary"),
+ SINGLE_LINE_SUMMARY_PREFERENCE("preference_with_single_line_summary"),
DISABLED_PREFERENCE("preference_disable"),
ASYNC_SUMMARY_PREFERENCE("preference_with_async_summary"),
MANUAL_UPDATE_PREFERENCE("preference_actionable"),
@@ -92,6 +96,7 @@ object PreferencePageProvider : SettingsPageProvider {
}
.build()
)
+ entryList.add(singleLineSummaryEntry())
entryList.add(
createEntry(EntryEnum.DISABLED_PREFERENCE)
.setIsAllowSearch(true)
@@ -163,6 +168,21 @@ object PreferencePageProvider : SettingsPageProvider {
return entryList
}
+ private fun singleLineSummaryEntry() = createEntry(EntryEnum.SINGLE_LINE_SUMMARY_PREFERENCE)
+ .setIsAllowSearch(true)
+ .setUiLayoutFn {
+ Preference(
+ model = object : PreferenceModel {
+ override val title: String =
+ stringResource(R.string.single_line_summary_preference_title)
+ override val summary =
+ stringResource(R.string.single_line_summary_preference_summary).toState()
+ },
+ singleLineSummary = true,
+ )
+ }
+ .build()
+
fun buildInjectEntry(): SettingsEntryBuilder {
return SettingsEntryBuilder.createInject(owner = owner)
.setIsAllowSearch(true)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BasePreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BasePreference.kt
index 4b2c8e41a388..c75f41b30d3e 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BasePreference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BasePreference.kt
@@ -34,7 +34,8 @@ internal fun BasePreference(
title: String,
summary: State<String>,
modifier: Modifier = Modifier,
- icon: (@Composable () -> Unit)? = null,
+ singleLineSummary: Boolean = false,
+ icon: @Composable (() -> Unit)? = null,
enabled: State<Boolean> = true.toState(),
paddingStart: Dp = SettingsDimension.itemPaddingStart,
paddingEnd: Dp = SettingsDimension.itemPaddingEnd,
@@ -43,7 +44,13 @@ internal fun BasePreference(
) {
BaseLayout(
title = title,
- subTitle = { SettingsBody(summary) },
+ subTitle = {
+ if (singleLineSummary) {
+ SettingsBody(body = summary, maxLines = 1)
+ } else {
+ SettingsBody(body = summary)
+ }
+ },
modifier = modifier,
icon = icon,
enabled = enabled,
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt
index 47abc87327ad..b900b6413d0a 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt
@@ -101,7 +101,10 @@ interface PreferenceModel {
* Data is provided through [PreferenceModel].
*/
@Composable
-fun Preference(model: PreferenceModel) {
+fun Preference(
+ model: PreferenceModel,
+ singleLineSummary: Boolean = false,
+) {
val modifier = remember(model.enabled.value, model.onClick) {
model.onClick?.let { onClick ->
Modifier.clickable(enabled = model.enabled.value, onClick = onClick)
@@ -110,6 +113,7 @@ fun Preference(model: PreferenceModel) {
BasePreference(
title = model.title,
summary = model.summary,
+ singleLineSummary = singleLineSummary,
modifier = modifier,
icon = model.icon,
enabled = model.enabled,
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt
index 59b413cef56e..123354f371f3 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt
@@ -17,13 +17,19 @@
package com.android.settingslib.spa.widget.ui
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.width
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.android.settingslib.spa.framework.theme.SettingsTheme
@Composable
fun SettingsTitle(title: State<String>) {
@@ -40,17 +46,25 @@ fun SettingsTitle(title: String) {
}
@Composable
-fun SettingsBody(body: State<String>) {
- SettingsBody(body.value)
+fun SettingsBody(
+ body: State<String>,
+ maxLines: Int = Int.MAX_VALUE,
+) {
+ SettingsBody(body = body.value, maxLines = maxLines)
}
@Composable
-fun SettingsBody(body: String) {
+fun SettingsBody(
+ body: String,
+ maxLines: Int = Int.MAX_VALUE,
+) {
if (body.isNotEmpty()) {
Text(
text = body,
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.bodyMedium,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = maxLines,
)
}
}
@@ -68,3 +82,19 @@ fun PlaceholderTitle(title: String) {
)
}
}
+
+@Preview
+@Composable
+private fun BasePreferencePreview() {
+ SettingsTheme {
+ Column(Modifier.width(100.dp)) {
+ SettingsBody(
+ body = "Long long long long long long text",
+ )
+ SettingsBody(
+ body = "Long long long long long long text",
+ maxLines = 1,
+ )
+ }
+ }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/PreferenceTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/PreferenceTest.kt
index a92f8713308f..06936e155b06 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/PreferenceTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/PreferenceTest.kt
@@ -16,17 +16,27 @@
package com.android.settingslib.spa.widget.preference
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.width
+import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.derivedStateOf
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.platform.LocalDensity
+import androidx.compose.ui.test.assertHeightIsAtLeast
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.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.framework.compose.toState
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.fail
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -40,11 +50,61 @@ class PreferenceTest {
fun title_displayed() {
composeTestRule.setContent {
Preference(object : PreferenceModel {
- override val title = "Preference"
+ override val title = TITLE
})
}
- composeTestRule.onNodeWithText("Preference").assertIsDisplayed()
+ composeTestRule.onNodeWithText(TITLE).assertIsDisplayed()
+ }
+
+ @Test
+ fun longSummary_notSingleLine_atLeastTwoLinesHeight() {
+ var lineHeightDp: Dp = Dp.Unspecified
+
+ composeTestRule.setContent {
+ Box(Modifier.width(BOX_WIDTH)) {
+ Preference(object : PreferenceModel {
+ override val title = TITLE
+ override val summary = LONG_SUMMARY.toState()
+ })
+ }
+ lineHeightDp = with(LocalDensity.current) {
+ MaterialTheme.typography.bodyMedium.lineHeight.toDp()
+ }
+ }
+
+ composeTestRule.onNodeWithText(LONG_SUMMARY).assertHeightIsAtLeast(lineHeightDp.times(2))
+ }
+
+ @Test
+ fun longSummary_notSingleLine_onlyOneLineHeight() {
+ var lineHeightDp: Dp = Dp.Unspecified
+
+ composeTestRule.setContent {
+ Box(Modifier.width(BOX_WIDTH)) {
+ Preference(
+ model = object : PreferenceModel {
+ override val title = TITLE
+ override val summary = LONG_SUMMARY.toState()
+ },
+ singleLineSummary = true,
+ )
+ }
+ lineHeightDp = with(LocalDensity.current) {
+ MaterialTheme.typography.bodyMedium.lineHeight.toDp()
+ }
+ }
+
+ val summaryNode = composeTestRule.onNodeWithText(LONG_SUMMARY)
+ try {
+ // There is no assertHeightIsAtMost, so use the assertHeightIsAtLeast and catch the
+ // expected exception.
+ summaryNode.assertHeightIsAtLeast(lineHeightDp.times(2))
+ } catch (e: AssertionError) {
+ assertThat(e).hasMessageThat().contains("height")
+ return
+ }
+ fail("Expect AssertionError")
}
@Test
@@ -52,13 +112,13 @@ class PreferenceTest {
composeTestRule.setContent {
var count by remember { mutableStateOf(0) }
Preference(object : PreferenceModel {
- override val title = "Preference"
+ override val title = TITLE
override val summary = derivedStateOf { count.toString() }
override val onClick: (() -> Unit) = { count++ }
})
}
- composeTestRule.onNodeWithText("Preference").performClick()
+ composeTestRule.onNodeWithText(TITLE).performClick()
composeTestRule.onNodeWithText("1").assertIsDisplayed()
}
@@ -67,14 +127,21 @@ class PreferenceTest {
composeTestRule.setContent {
var count by remember { mutableStateOf(0) }
Preference(object : PreferenceModel {
- override val title = "Preference"
+ override val title = TITLE
override val summary = derivedStateOf { count.toString() }
override val enabled = false.toState()
override val onClick: (() -> Unit) = { count++ }
})
}
- composeTestRule.onNodeWithText("Preference").performClick()
+ composeTestRule.onNodeWithText(TITLE).performClick()
composeTestRule.onNodeWithText("0").assertIsDisplayed()
}
+
+ companion object {
+ private const val TITLE = "Title"
+ private const val LONG_SUMMARY =
+ "Long long long long long long long long long long long long long long long summary"
+ private val BOX_WIDTH = 100.dp
+ }
}