Make more sliders discrete and ensure they don't look out of place (#1840)

Also cleanup the underlying code
This commit is contained in:
AntsyLich 2025-03-09 12:28:24 +06:00 committed by GitHub
parent 7913679f9d
commit 4f06c1cc09
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 89 additions and 65 deletions

View File

@ -25,6 +25,7 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co
- Display staff information on Anilist tracker search results ([@NarwhalHorns](https://github.com/NarwhalHorns)) ([#1810](https://github.com/mihonapp/mihon/pull/1810))
### Changed
- Sliders UI
- Apply "Downloaded only" filter to all entries regardless of favourite status ([@NGB-Was-Taken](https://github.com/NGB-Was-Taken)) ([#1603](https://github.com/mihonapp/mihon/pull/1603))
- Ignore hidden files/folders for Local Source chapter list ([@BrutuZ](https://github.com/BrutuZ)) ([#1763](https://github.com/mihonapp/mihon/pull/1763))
- Migrate to newer Bangumi API ([@MajorTanya](https://github.com/MajorTanya)) ([#1748](https://github.com/mihonapp/mihon/pull/1748))

View File

@ -252,9 +252,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
@ -50,10 +51,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

@ -141,9 +141,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,
@ -154,9 +152,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,
@ -342,8 +338,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

@ -98,24 +98,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

@ -153,10 +153,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

@ -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
@ -172,25 +173,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,
@ -214,7 +239,7 @@ fun SliderItem(
onChange(it)
haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove)
},
valueRange = min..max,
valueRange = valueRange,
steps = steps,
)
}
@ -224,15 +249,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,