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
This commit is contained in:
AntsyLich 2025-03-09 12:28:24 +06:00 committed by Jobobby04
parent 7f71296e1c
commit aad2bf4645
12 changed files with 92 additions and 86 deletions

View File

@ -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 {

View File

@ -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 },

View File

@ -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<*> -> {

View File

@ -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

View File

@ -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 = {

View File

@ -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)

View File

@ -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) {

View File

@ -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)

View File

@ -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<ALStaffEdge>,
)
@Serializable
data class ALStaffEdge(
val role: String,
val node: ALStaffNode,
)
@Serializable
data class ALStaffNode(
val name: ALItemTitle,
)

View File

@ -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

View File

@ -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 },
)
}
}

View File

@ -17,8 +17,8 @@ fun Slider(
onValueChange: (Int) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
valueRange: ClosedRange<Int> = 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,