From 63f4034a7f6d9e0936812a65b6f11418ffb3e41a Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+antsylich@users.noreply.github.com> Date: Sat, 1 Nov 2025 18:32:06 +0545 Subject: [PATCH] Add subtitle support to slider preference and general cleanup (#2635) (cherry picked from commit f36c259c1faf2ee4a108fd98a5d27d93014ba34c) --- .../library/LibrarySettingsDialog.kt | 2 +- .../presentation/more/settings/Preference.kt | 41 ++++++++-------- .../more/settings/PreferenceItem.kt | 11 +++-- .../more/settings/PreferenceScreen.kt | 2 +- .../settings/screen/SettingsReaderScreen.kt | 21 +++------ .../settings/screen/SettingsSearchScreen.kt | 2 +- .../settings/screen/debug/DebugInfoScreen.kt | 2 +- .../reader/settings/GeneralSettingsPage.kt | 4 +- .../reader/settings/ReadingModePage.kt | 2 +- .../core/components/SettingsItems.kt | 47 ++++++++++++------- 10 files changed, 71 insertions(+), 63 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt index 62d710aa7..21e3c895b 100644 --- a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt @@ -313,7 +313,7 @@ private fun ColumnScope.DisplayPage( value = columns, valueRange = 0..10, label = stringResource(MR.strings.pref_library_columns), - valueText = if (columns > 0) { + valueString = if (columns > 0) { columns.toString() } else { stringResource(MR.strings.label_auto) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/Preference.kt b/app/src/main/java/eu/kanade/presentation/more/settings/Preference.kt index 904f9b388..356a7271a 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/Preference.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/Preference.kt @@ -15,13 +15,13 @@ sealed class Preference { abstract val title: String abstract val enabled: Boolean - sealed class PreferenceItem : Preference() { + sealed class PreferenceItem : Preference() { // SY --> abstract val subtitle: CharSequence? // SY <-- abstract val icon: ImageVector? - abstract val onValueChanged: suspend (value: T) -> Boolean + abstract val onValueChanged: suspend (value: T) -> R /** * A basic [PreferenceItem] that only displays texts. @@ -31,9 +31,9 @@ sealed class Preference { override val subtitle: CharSequence? = null, override val enabled: Boolean = true, val onClick: (() -> Unit)? = null, - ) : PreferenceItem() { + ) : PreferenceItem() { override val icon: ImageVector? = null - override val onValueChanged: suspend (value: String) -> Boolean = { true } + override val onValueChanged: suspend (value: String) -> Unit = {} } /** @@ -45,7 +45,7 @@ sealed class Preference { override val subtitle: CharSequence? = null, override val enabled: Boolean = true, override val onValueChanged: suspend (value: Boolean) -> Boolean = { true }, - ) : PreferenceItem() { + ) : PreferenceItem() { override val icon: ImageVector? = null } @@ -55,12 +55,13 @@ sealed class Preference { data class SliderPreference( val value: Int, override val title: String, + override val subtitle: String? = null, + val valueString: String? = null, val valueRange: IntProgression = 0..1, @IntRange(from = 0) val steps: Int = with(valueRange) { (last - first) - 1 }, - override val subtitle: String? = null, override val enabled: Boolean = true, - override val onValueChanged: suspend (value: Int) -> Boolean = { true }, - ) : PreferenceItem() { + override val onValueChanged: suspend (value: Int) -> Unit = {}, + ) : PreferenceItem() { override val icon: ImageVector? = null } @@ -78,7 +79,7 @@ sealed class Preference { override val icon: ImageVector? = null, override val enabled: Boolean = true, override val onValueChanged: suspend (value: T) -> Boolean = { true }, - ) : PreferenceItem() { + ) : PreferenceItem() { internal fun internalSet(value: Any) = preference.set(value as T) internal suspend fun internalOnValueChanged(value: Any) = onValueChanged(value as T) @@ -99,8 +100,8 @@ sealed class Preference { { v, e -> subtitle?.format(e[v]) }, override val icon: ImageVector? = null, override val enabled: Boolean = true, - override val onValueChanged: suspend (value: String) -> Boolean = { true }, - ) : PreferenceItem() + override val onValueChanged: suspend (value: String) -> Unit = {}, + ) : PreferenceItem() /** * A [PreferenceItem] that displays a list of entries as a dialog. @@ -124,7 +125,7 @@ sealed class Preference { override val icon: ImageVector? = null, override val enabled: Boolean = true, override val onValueChanged: suspend (value: Set) -> Boolean = { true }, - ) : PreferenceItem>() + ) : PreferenceItem, Boolean>() /** * A [PreferenceItem] that shows a EditText in the dialog. @@ -135,7 +136,7 @@ sealed class Preference { override val subtitle: String? = "%s", override val enabled: Boolean = true, override val onValueChanged: suspend (value: String) -> Boolean = { true }, - ) : PreferenceItem() { + ) : PreferenceItem() { override val icon: ImageVector? = null } @@ -146,31 +147,31 @@ sealed class Preference { val tracker: Tracker, val login: () -> Unit, val logout: () -> Unit, - ) : PreferenceItem() { + ) : PreferenceItem() { override val title: String = "" override val enabled: Boolean = true override val subtitle: String? = null override val icon: ImageVector? = null - override val onValueChanged: suspend (value: String) -> Boolean = { true } + override val onValueChanged: suspend (value: String) -> Unit = {} } data class InfoPreference( override val title: String, - ) : PreferenceItem() { + ) : PreferenceItem() { override val enabled: Boolean = true override val subtitle: String? = null override val icon: ImageVector? = null - override val onValueChanged: suspend (value: String) -> Boolean = { true } + override val onValueChanged: suspend (value: String) -> Unit = {} } data class CustomPreference( override val title: String, val content: @Composable () -> Unit, - ) : PreferenceItem() { + ) : PreferenceItem() { override val enabled: Boolean = true override val subtitle: String? = null override val icon: ImageVector? = null - override val onValueChanged: suspend (value: Unit) -> Boolean = { true } + override val onValueChanged: suspend (value: Unit) -> Unit = {} } } @@ -178,6 +179,6 @@ sealed class Preference { override val title: String, override val enabled: Boolean = true, - val preferenceItems: ImmutableList>, + val preferenceItems: ImmutableList>, ) : Preference() } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceItem.kt b/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceItem.kt index 74515e98e..cc4d81d9f 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceItem.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceItem.kt @@ -35,7 +35,7 @@ val LocalPreferenceMinHeight = compositionLocalOf(structuralEqualityPolicy()) { @Composable fun StatusWrapper( - item: Preference.PreferenceItem<*>, + item: Preference.PreferenceItem<*, *>, highlightKey: String?, content: @Composable () -> Unit, ) { @@ -56,7 +56,7 @@ fun StatusWrapper( @Composable internal fun PreferenceItem( - item: Preference.PreferenceItem<*>, + item: Preference.PreferenceItem<*, *>, highlightKey: String?, ) { val scope = rememberCoroutineScope() @@ -83,17 +83,18 @@ internal fun PreferenceItem( } is Preference.PreferenceItem.SliderPreference -> { BaseSliderItem( - label = item.title, value = item.value, valueRange = item.valueRange, - valueText = item.subtitle.takeUnless { it.isNullOrEmpty() } ?: item.value.toString(), steps = item.steps, - labelStyle = MaterialTheme.typography.titleLarge.copy(fontSize = TitleFontSize), + title = item.title, + subtitle = item.subtitle, + valueString = item.valueString.takeUnless { it.isNullOrEmpty() } ?: item.value.toString(), onChange = { scope.launch { item.onValueChanged(it) } }, + titleStyle = MaterialTheme.typography.titleLarge.copy(fontSize = TitleFontSize), modifier = Modifier.padding( horizontal = PrefsHorizontalPadding, vertical = PrefsVerticalPadding, diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScreen.kt index 26b4086b8..e0938738f 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScreen.kt @@ -71,7 +71,7 @@ fun PreferenceScreen( } // Create Preference Item - is Preference.PreferenceItem<*> -> item { + is Preference.PreferenceItem<*, *> -> item { PreferenceItem( item = preference, highlightKey = highlightKey, diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt index 5bbffdd55..2f7a91dcf 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt @@ -177,23 +177,17 @@ object SettingsReaderScreen : SearchableSettings { value = flashMillis / ReaderPreferences.MILLI_CONVERSION, valueRange = 1..15, title = stringResource(MR.strings.pref_flash_duration), - subtitle = stringResource(MR.strings.pref_flash_duration_summary, flashMillis), + valueString = stringResource(MR.strings.pref_flash_duration_summary, flashMillis), enabled = flashPageState, - onValueChanged = { - flashMillisPref.set(it * ReaderPreferences.MILLI_CONVERSION) - true - }, + onValueChanged = { flashMillisPref.set(it * ReaderPreferences.MILLI_CONVERSION) }, ), Preference.PreferenceItem.SliderPreference( value = flashInterval, valueRange = 1..10, title = stringResource(MR.strings.pref_flash_page_interval), - subtitle = pluralStringResource(MR.plurals.pref_pages, flashInterval, flashInterval), + valueString = pluralStringResource(MR.plurals.pref_pages, flashInterval, flashInterval), enabled = flashPageState, - onValueChanged = { - flashIntervalPref.set(it) - true - }, + onValueChanged = { flashIntervalPref.set(it) }, ), Preference.PreferenceItem.ListPreference( preference = flashColorPref, @@ -382,11 +376,8 @@ object SettingsReaderScreen : SearchableSettings { it.WEBTOON_PADDING_MIN..it.WEBTOON_PADDING_MAX }, title = stringResource(MR.strings.pref_webtoon_side_padding), - subtitle = numberFormat.format(webtoonSidePadding / 100f), - onValueChanged = { - webtoonSidePaddingPref.set(it) - true - }, + valueString = numberFormat.format(webtoonSidePadding / 100f), + onValueChanged = { webtoonSidePaddingPref.set(it) }, ), Preference.PreferenceItem.ListPreference( preference = readerPreferences.readerHideThreshold(), diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt index 2b14c3203..99dc4477a 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt @@ -183,7 +183,7 @@ private fun SearchResult( emptySequence() } } - is Preference.PreferenceItem<*> -> sequenceOf(null to p) + is Preference.PreferenceItem<*, *> -> sequenceOf(null to p) } } // Don't show info preference diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/DebugInfoScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/DebugInfoScreen.kt index d44ee1319..d4a12415c 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/DebugInfoScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/DebugInfoScreen.kt @@ -98,7 +98,7 @@ class DebugInfoScreen : Screen() { } private fun getDeviceInfoGroup(): Preference.PreferenceGroup { - val items = persistentListOf>().mutate { + val items = persistentListOf>().mutate { it.add( Preference.PreferenceItem.TextPreference( title = "Model", diff --git a/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt b/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt index 9b9dfb641..9b56f3036 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt @@ -122,7 +122,7 @@ internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) { value = flashMillis / ReaderPreferences.MILLI_CONVERSION, valueRange = 1..15, label = stringResource(MR.strings.pref_flash_duration), - valueText = stringResource(MR.strings.pref_flash_duration_summary, flashMillis), + valueString = stringResource(MR.strings.pref_flash_duration_summary, flashMillis), onChange = { flashMillisPref.set(it * ReaderPreferences.MILLI_CONVERSION) }, pillColor = MaterialTheme.colorScheme.surfaceContainerHighest, ) @@ -130,7 +130,7 @@ internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) { value = flashInterval, valueRange = 1..10, label = stringResource(MR.strings.pref_flash_page_interval), - valueText = pluralStringResource(MR.plurals.pref_pages, flashInterval, flashInterval), + valueString = pluralStringResource(MR.plurals.pref_pages, flashInterval, flashInterval), onChange = { flashIntervalPref.set(it) }, diff --git a/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt b/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt index 1970b0d27..fce1f856f 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt @@ -196,7 +196,7 @@ private fun ColumnScope.WebtoonViewerSettings(screenModel: ReaderSettingsScreenM value = webtoonSidePadding, valueRange = ReaderPreferences.let { it.WEBTOON_PADDING_MIN..it.WEBTOON_PADDING_MAX }, label = stringResource(MR.strings.pref_webtoon_side_padding), - valueText = numberFormat.format(webtoonSidePadding / 100f), + valueString = numberFormat.format(webtoonSidePadding / 100f), onChange = { screenModel.preferences.webtoonSidePadding().set(it) }, diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt index 0085bc60c..a0c67a78f 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt @@ -60,6 +60,7 @@ import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.theme.header import tachiyomi.presentation.core.util.collectAsState +import tachiyomi.presentation.core.util.secondaryItemAlpha object SettingsItemsPaddings { val Horizontal = 24.dp @@ -179,7 +180,7 @@ fun SliderItem( label: String, onChange: (Int) -> Unit, steps: Int = with(valueRange) { (last - first) - 1 }, - valueText: String = value.toString(), + valueString: String = value.toString(), labelStyle: TextStyle = MaterialTheme.typography.bodyMedium, pillColor: Color = MaterialTheme.colorScheme.surfaceContainerHigh, ) { @@ -187,10 +188,10 @@ fun SliderItem( value = value, valueRange = valueRange, steps = steps, - label = label, - valueText = valueText, + title = label, + valueString = valueString, onChange = onChange, - labelStyle = labelStyle, + titleStyle = labelStyle, pillColor = pillColor, modifier = Modifier.padding( horizontal = SettingsItemsPaddings.Horizontal, @@ -203,12 +204,14 @@ fun SliderItem( fun BaseSliderItem( value: Int, valueRange: IntProgression, - label: String, + title: String, onChange: (Int) -> Unit, modifier: Modifier = Modifier, + subtitle: String? = null, steps: Int = with(valueRange) { (last - first) - 1 }, - valueText: String = value.toString(), - labelStyle: TextStyle = MaterialTheme.typography.bodyMedium, + valueString: String = value.toString(), + titleStyle: TextStyle = MaterialTheme.typography.titleLarge, + subtitleStyle: TextStyle = MaterialTheme.typography.bodySmall, pillColor: Color = MaterialTheme.colorScheme.surfaceContainerHigh, ) { val haptic = LocalHapticFeedback.current @@ -222,13 +225,21 @@ fun BaseSliderItem( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small), ) { - Text( - text = label, - style = labelStyle, - modifier = Modifier.weight(1f), - ) + Column(modifier = Modifier.weight(1f)) { + Text( + text = title, + style = titleStyle, + ) + if (subtitle != null) { + Text( + text = subtitle, + style = subtitleStyle, + modifier = Modifier.secondaryItemAlpha(), + ) + } + } Pill( - text = valueText, + text = valueString, style = MaterialTheme.typography.bodyMedium, color = pillColor, ) @@ -252,12 +263,16 @@ fun SliderItemPreview() { MaterialTheme(if (isSystemInDarkTheme()) darkColorScheme() else lightColorScheme()) { var value by remember { mutableIntStateOf(0) } Surface { - SliderItem( + BaseSliderItem( value = value, valueRange = 0..10, - label = "Item per row", - valueText = if (value == 0) "Auto" else value.toString(), + title = "Item per row", + valueString = if (value == 0) "Auto" else value.toString(), onChange = { value = it }, + modifier = Modifier.padding( + horizontal = SettingsItemsPaddings.Horizontal, + vertical = SettingsItemsPaddings.Vertical, + ), ) } }