From aad2bf46455eb2c2b0e8e5d2feec460a92db8079 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Sun, 9 Mar 2025 12:28:24 +0600 Subject: [PATCH] Make more sliders discrete and ensure they don't look out of place (#1840) Also cleanup the underlying code (cherry picked from commit 4f06c1cc09d15245b26b8a862738cb6a859fedcc) # Conflicts: # CHANGELOG.md --- .../library/LibrarySettingsDialog.kt | 4 +- .../presentation/more/settings/Preference.kt | 6 +- .../more/settings/PreferenceItem.kt | 20 +++++-- .../screen/SettingsAppearanceScreen.kt | 3 +- .../settings/screen/SettingsReaderScreen.kt | 13 ++--- .../reader/settings/ColorFilterPage.kt | 31 +++++----- .../reader/settings/GeneralSettingsPage.kt | 8 +-- .../reader/settings/ReadingModePage.kt | 5 +- .../data/track/anilist/dto/ALMangaMetadata.kt | 18 +----- .../data/track/anilist/dto/ALSearchItem.kt | 6 +- .../core/components/SettingsItems.kt | 58 +++++++++++++------ .../core/components/material/Slider.kt | 6 +- 12 files changed, 92 insertions(+), 86 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 37d129efb..a33570785 100644 --- a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt @@ -310,9 +310,9 @@ private fun ColumnScope.DisplayPage( val columns by columnPreference.collectAsState() SliderItem( - label = stringResource(MR.strings.pref_library_columns), - max = 10, value = columns, + valueRange = 0..10, + label = stringResource(MR.strings.pref_library_columns), valueText = if (columns > 0) { columns.toString() } else { 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 231bf8fef..904f9b388 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 @@ -1,5 +1,6 @@ package eu.kanade.presentation.more.settings +import androidx.annotation.IntRange import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.graphics.vector.ImageVector @@ -53,10 +54,9 @@ sealed class Preference { */ data class SliderPreference( val value: Int, - val max: Int, - val min: Int = 0, - val steps: Int = 0, override val title: String, + 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 }, 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 9f97d3a83..74515e98e 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 @@ -5,6 +5,7 @@ import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically +import androidx.compose.foundation.layout.padding import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider @@ -13,16 +14,20 @@ import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.structuralEqualityPolicy +import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import eu.kanade.presentation.more.settings.widget.EditTextPreferenceWidget import eu.kanade.presentation.more.settings.widget.InfoWidget import eu.kanade.presentation.more.settings.widget.ListPreferenceWidget import eu.kanade.presentation.more.settings.widget.MultiSelectListPreferenceWidget +import eu.kanade.presentation.more.settings.widget.PrefsHorizontalPadding +import eu.kanade.presentation.more.settings.widget.PrefsVerticalPadding import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget +import eu.kanade.presentation.more.settings.widget.TitleFontSize import eu.kanade.presentation.more.settings.widget.TrackingPreferenceWidget import kotlinx.coroutines.launch -import tachiyomi.presentation.core.components.SliderItem +import tachiyomi.presentation.core.components.BaseSliderItem import tachiyomi.presentation.core.util.collectAsState val LocalPreferenceHighlighted = compositionLocalOf(structuralEqualityPolicy()) { false } @@ -77,19 +82,22 @@ internal fun PreferenceItem( ) } is Preference.PreferenceItem.SliderPreference -> { - SliderItem( + BaseSliderItem( label = item.title, - min = item.min, - max = item.max, - steps = item.steps, 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), onChange = { scope.launch { item.onValueChanged(it) } }, - labelStyle = MaterialTheme.typography.titleLarge, + modifier = Modifier.padding( + horizontal = PrefsHorizontalPadding, + vertical = PrefsVerticalPadding, + ), ) } is Preference.PreferenceItem.ListPreference<*> -> { diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAppearanceScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAppearanceScreen.kt index fd28b33ad..11536b7ea 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAppearanceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAppearanceScreen.kt @@ -189,8 +189,7 @@ object SettingsAppearanceScreen : SearchableSettings { } else { stringResource(MR.strings.disabled) }, - min = 0, - max = 10, + valueRange = 0..10, onValueChanged = { uiPreferences.previewsRowCount().set(it) true 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 c160aafb7..99fef94cc 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 @@ -175,9 +175,7 @@ object SettingsReaderScreen : SearchableSettings { ), Preference.PreferenceItem.SliderPreference( value = flashMillis / ReaderPreferences.MILLI_CONVERSION, - max = 15, - min = 1, - steps = 13, + valueRange = 1..15, title = stringResource(MR.strings.pref_flash_duration), subtitle = stringResource(MR.strings.pref_flash_duration_summary, flashMillis), enabled = flashPageState, @@ -188,9 +186,7 @@ object SettingsReaderScreen : SearchableSettings { ), Preference.PreferenceItem.SliderPreference( value = flashInterval, - max = 10, - min = 1, - steps = 8, + valueRange = 1..10, title = stringResource(MR.strings.pref_flash_page_interval), subtitle = pluralStringResource(MR.plurals.pref_pages, flashInterval, flashInterval), enabled = flashPageState, @@ -389,8 +385,9 @@ object SettingsReaderScreen : SearchableSettings { ), Preference.PreferenceItem.SliderPreference( value = webtoonSidePadding, - max = ReaderPreferences.WEBTOON_PADDING_MAX, - min = ReaderPreferences.WEBTOON_PADDING_MIN, + valueRange = ReaderPreferences.let { + it.WEBTOON_PADDING_MIN..it.WEBTOON_PADDING_MAX + }, title = stringResource(MR.strings.pref_webtoon_side_padding), subtitle = numberFormat.format(webtoonSidePadding / 100f), onValueChanged = { diff --git a/app/src/main/java/eu/kanade/presentation/reader/settings/ColorFilterPage.kt b/app/src/main/java/eu/kanade/presentation/reader/settings/ColorFilterPage.kt index 211a9e853..d0017aa41 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/settings/ColorFilterPage.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/settings/ColorFilterPage.kt @@ -37,11 +37,10 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel) if (customBrightness) { val customBrightnessValue by screenModel.preferences.customBrightnessValue().collectAsState() SliderItem( - label = stringResource(MR.strings.pref_custom_brightness), - min = -75, - max = 100, value = customBrightnessValue, - valueText = customBrightnessValue.toString(), + valueRange = -75..100, + steps = 0, + label = stringResource(MR.strings.pref_custom_brightness), onChange = { screenModel.preferences.customBrightnessValue().set(it) }, pillColor = MaterialTheme.colorScheme.surfaceContainerHighest, ) @@ -55,10 +54,10 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel) if (colorFilter) { val colorFilterValue by screenModel.preferences.colorFilterValue().collectAsState() SliderItem( - label = stringResource(MR.strings.color_filter_r_value), - max = 255, value = colorFilterValue.red, - valueText = colorFilterValue.red.toString(), + valueRange = 0..255, + steps = 0, + label = stringResource(MR.strings.color_filter_r_value), onChange = { newRValue -> screenModel.preferences.colorFilterValue().getAndSet { getColorValue(it, newRValue, RED_MASK, 16) @@ -67,10 +66,10 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel) pillColor = MaterialTheme.colorScheme.surfaceContainerHighest, ) SliderItem( - label = stringResource(MR.strings.color_filter_g_value), - max = 255, value = colorFilterValue.green, - valueText = colorFilterValue.green.toString(), + valueRange = 0..255, + steps = 0, + label = stringResource(MR.strings.color_filter_g_value), onChange = { newGValue -> screenModel.preferences.colorFilterValue().getAndSet { getColorValue(it, newGValue, GREEN_MASK, 8) @@ -79,10 +78,10 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel) pillColor = MaterialTheme.colorScheme.surfaceContainerHighest, ) SliderItem( - label = stringResource(MR.strings.color_filter_b_value), - max = 255, value = colorFilterValue.blue, - valueText = colorFilterValue.blue.toString(), + valueRange = 0..255, + steps = 0, + label = stringResource(MR.strings.color_filter_b_value), onChange = { newBValue -> screenModel.preferences.colorFilterValue().getAndSet { getColorValue(it, newBValue, BLUE_MASK, 0) @@ -91,10 +90,10 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel) pillColor = MaterialTheme.colorScheme.surfaceContainerHighest, ) SliderItem( - label = stringResource(MR.strings.color_filter_a_value), - max = 255, value = colorFilterValue.alpha, - valueText = colorFilterValue.alpha.toString(), + valueRange = 0..255, + steps = 0, + label = stringResource(MR.strings.color_filter_a_value), onChange = { newAValue -> screenModel.preferences.colorFilterValue().getAndSet { getColorValue(it, newAValue, ALPHA_MASK, 24) 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 81f61538e..9b9dfb641 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 @@ -120,24 +120,20 @@ internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) { if (flashPageState) { SliderItem( value = flashMillis / ReaderPreferences.MILLI_CONVERSION, + valueRange = 1..15, label = stringResource(MR.strings.pref_flash_duration), valueText = stringResource(MR.strings.pref_flash_duration_summary, flashMillis), onChange = { flashMillisPref.set(it * ReaderPreferences.MILLI_CONVERSION) }, - min = 1, - max = 15, - steps = 13, pillColor = MaterialTheme.colorScheme.surfaceContainerHighest, ) SliderItem( value = flashInterval, + valueRange = 1..10, label = stringResource(MR.strings.pref_flash_page_interval), valueText = pluralStringResource(MR.plurals.pref_pages, flashInterval, flashInterval), onChange = { flashIntervalPref.set(it) }, - min = 1, - max = 10, - steps = 8, pillColor = MaterialTheme.colorScheme.surfaceContainerHighest, ) SettingsChipRow(MR.strings.pref_flash_with) { 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 dcfe3b880..1970b0d27 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 @@ -193,10 +193,9 @@ private fun ColumnScope.WebtoonViewerSettings(screenModel: ReaderSettingsScreenM val webtoonSidePadding by screenModel.preferences.webtoonSidePadding().collectAsState() SliderItem( - label = stringResource(MR.strings.pref_webtoon_side_padding), - min = ReaderPreferences.WEBTOON_PADDING_MIN, - max = ReaderPreferences.WEBTOON_PADDING_MAX, 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), onChange = { screenModel.preferences.webtoonSidePadding().set(it) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALMangaMetadata.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALMangaMetadata.kt index 65b6c839d..b9dc74eda 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALMangaMetadata.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALMangaMetadata.kt @@ -17,24 +17,8 @@ data class ALMangaMetadataData( @Serializable data class ALMangaMetadataMedia( val id: Long, - val title: ALItemTitle, + val title: ALStaffName, val coverImage: ItemCover, val description: String?, val staff: ALStaff, ) - -@Serializable -data class ALStaff( - val edges: List, -) - -@Serializable -data class ALStaffEdge( - val role: String, - val node: ALStaffNode, -) - -@Serializable -data class ALStaffNode( - val name: ALItemTitle, -) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALSearchItem.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALSearchItem.kt index 610900816..b1d614d6d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALSearchItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALSearchItem.kt @@ -58,9 +58,9 @@ data class ALStaffNode( @Serializable data class ALStaffName( - val userPreferred: String?, - val native: String?, - val full: String?, + val userPreferred: String? = null, + val native: String? = null, + val full: String? = null, ) { operator fun invoke(): String? { return userPreferred ?: full ?: native 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 62d0a723d..0085bc60c 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 @@ -36,6 +36,7 @@ import androidx.compose.material3.darkColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue @@ -173,25 +174,49 @@ fun RadioItem(label: String, selected: Boolean, onClick: () -> Unit) { @Composable fun SliderItem( - label: String, value: Int, - valueText: String, + valueRange: IntProgression, + label: String, onChange: (Int) -> Unit, - max: Int, - min: Int = 0, - steps: Int = 0, + steps: Int = with(valueRange) { (last - first) - 1 }, + valueText: String = value.toString(), + labelStyle: TextStyle = MaterialTheme.typography.bodyMedium, + pillColor: Color = MaterialTheme.colorScheme.surfaceContainerHigh, +) { + BaseSliderItem( + value = value, + valueRange = valueRange, + steps = steps, + label = label, + valueText = valueText, + onChange = onChange, + labelStyle = labelStyle, + pillColor = pillColor, + modifier = Modifier.padding( + horizontal = SettingsItemsPaddings.Horizontal, + vertical = SettingsItemsPaddings.Vertical, + ), + ) +} + +@Composable +fun BaseSliderItem( + value: Int, + valueRange: IntProgression, + label: String, + onChange: (Int) -> Unit, + modifier: Modifier = Modifier, + steps: Int = with(valueRange) { (last - first) - 1 }, + valueText: String = value.toString(), labelStyle: TextStyle = MaterialTheme.typography.bodyMedium, pillColor: Color = MaterialTheme.colorScheme.surfaceContainerHigh, ) { val haptic = LocalHapticFeedback.current - Column( modifier = Modifier .fillMaxWidth() - .padding( - horizontal = SettingsItemsPaddings.Horizontal, - vertical = SettingsItemsPaddings.Vertical, - ), + .then(modifier), + verticalArrangement = Arrangement.spacedBy(2.dp), ) { Row( verticalAlignment = Alignment.CenterVertically, @@ -215,7 +240,7 @@ fun SliderItem( onChange(it) haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) }, - valueRange = min..max, + valueRange = valueRange, steps = steps, ) } @@ -225,15 +250,14 @@ fun SliderItem( @PreviewLightDark fun SliderItemPreview() { MaterialTheme(if (isSystemInDarkTheme()) darkColorScheme() else lightColorScheme()) { + var value by remember { mutableIntStateOf(0) } Surface { SliderItem( + value = value, + valueRange = 0..10, label = "Item per row", - valueText = "Auto", - value = 0, - onChange = {}, - min = 0, - max = 10, - steps = 8, + valueText = if (value == 0) "Auto" else value.toString(), + onChange = { value = it }, ) } } diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Slider.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Slider.kt index e590c3327..66f2124a2 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Slider.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Slider.kt @@ -17,8 +17,8 @@ fun Slider( onValueChange: (Int) -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, - valueRange: ClosedRange = 0..1, - @IntRange(from = 0) steps: Int = 0, + valueRange: IntProgression = 0..1, + @IntRange(from = 0) steps: Int = with(valueRange) { (last - first) - 1 }, onValueChangeFinished: (() -> Unit)? = null, colors: SliderColors = SliderDefaults.colors(), interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, @@ -38,7 +38,7 @@ fun Slider( onValueChange = { onValueChange(it.roundToInt()) }, modifier = modifier, enabled = enabled, - valueRange = with(valueRange) { start.toFloat()..endInclusive.toFloat() }, + valueRange = with(valueRange) { first.toFloat()..last.toFloat() }, steps = steps, onValueChangeFinished = onValueChangeFinished, colors = colors,