Rework slider UI

Fixes #1474
This commit is contained in:
AntsyLich 2025-02-05 23:37:30 +06:00
parent d592ab2e87
commit e8c9cb2c2e
No known key found for this signature in database
11 changed files with 95 additions and 22 deletions

View File

@ -9,6 +9,7 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material3.FilterChip
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
@ -259,11 +260,12 @@ private fun ColumnScope.DisplayPage(
max = 10,
value = columns,
valueText = if (columns > 0) {
stringResource(MR.strings.pref_library_columns_per_row, columns)
columns.toString()
} else {
stringResource(MR.strings.label_default)
stringResource(MR.strings.label_auto)
},
onChange = columnPreference::set,
pillColor = MaterialTheme.colorScheme.surfaceContainerHighest,
)
}

View File

@ -49,8 +49,9 @@ sealed class Preference {
*/
data class SliderPreference(
val value: Int,
val min: Int = 0,
val max: Int,
val min: Int = 0,
val steps: Int = 0,
override val title: String = "",
override val subtitle: String? = null,
override val icon: ImageVector? = null,

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.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.collectAsState
@ -76,11 +77,11 @@ internal fun PreferenceItem(
)
}
is Preference.PreferenceItem.SliderPreference -> {
// TODO: use different composable?
SliderItem(
label = item.title,
min = item.min,
max = item.max,
steps = item.steps,
value = item.value,
valueText = item.subtitle.takeUnless { it.isNullOrEmpty() } ?: item.value.toString(),
onChange = {
@ -88,6 +89,7 @@ internal fun PreferenceItem(
item.onValueChanged(it)
}
},
labelStyle = MaterialTheme.typography.titleLarge,
)
}
is Preference.PreferenceItem.ListPreference<*> -> {

View File

@ -143,6 +143,7 @@ object SettingsReaderScreen : SearchableSettings {
value = flashMillis / ReaderPreferences.MILLI_CONVERSION,
min = 1,
max = 15,
steps = 13,
title = stringResource(MR.strings.pref_flash_duration),
subtitle = stringResource(MR.strings.pref_flash_duration_summary, flashMillis),
onValueChanged = {
@ -155,6 +156,7 @@ object SettingsReaderScreen : SearchableSettings {
value = flashInterval,
min = 1,
max = 10,
steps = 8,
title = stringResource(MR.strings.pref_flash_page_interval),
subtitle = pluralStringResource(MR.plurals.pref_pages, flashInterval, flashInterval),
onValueChanged = {

View File

@ -2,6 +2,7 @@ package eu.kanade.presentation.reader.settings
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.material3.FilterChip
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@ -42,6 +43,7 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
value = customBrightnessValue,
valueText = customBrightnessValue.toString(),
onChange = { screenModel.preferences.customBrightnessValue().set(it) },
pillColor = MaterialTheme.colorScheme.surfaceContainerHighest,
)
}
@ -62,6 +64,7 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
getColorValue(it, newRValue, RED_MASK, 16)
}
},
pillColor = MaterialTheme.colorScheme.surfaceContainerHighest,
)
SliderItem(
label = stringResource(MR.strings.color_filter_g_value),
@ -73,6 +76,7 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
getColorValue(it, newGValue, GREEN_MASK, 8)
}
},
pillColor = MaterialTheme.colorScheme.surfaceContainerHighest,
)
SliderItem(
label = stringResource(MR.strings.color_filter_b_value),
@ -84,6 +88,7 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
getColorValue(it, newBValue, BLUE_MASK, 0)
}
},
pillColor = MaterialTheme.colorScheme.surfaceContainerHighest,
)
SliderItem(
label = stringResource(MR.strings.color_filter_a_value),
@ -95,6 +100,7 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
getColorValue(it, newAValue, ALPHA_MASK, 24)
}
},
pillColor = MaterialTheme.colorScheme.surfaceContainerHighest,
)
val colorFilterMode by screenModel.preferences.colorFilterMode().collectAsState()

View File

@ -2,6 +2,7 @@ package eu.kanade.presentation.reader.settings
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.material3.FilterChip
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@ -102,6 +103,8 @@ internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) {
onChange = { flashMillisPref.set(it * ReaderPreferences.MILLI_CONVERSION) },
min = 1,
max = 15,
steps = 13,
pillColor = MaterialTheme.colorScheme.surfaceContainerHighest,
)
SliderItem(
value = flashInterval,
@ -112,6 +115,8 @@ internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) {
},
min = 1,
max = 10,
steps = 8,
pillColor = MaterialTheme.colorScheme.surfaceContainerHighest,
)
SettingsChipRow(MR.strings.pref_flash_with) {
flashColors.map { (labelRes, value) ->

View File

@ -2,6 +2,7 @@ package eu.kanade.presentation.reader.settings
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.material3.FilterChip
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
@ -160,6 +161,7 @@ private fun ColumnScope.WebtoonViewerSettings(screenModel: ReaderSettingsScreenM
onChange = {
screenModel.preferences.webtoonSidePadding().set(it)
},
pillColor = MaterialTheme.colorScheme.surfaceContainerHighest,
)
CheckboxItem(

View File

@ -38,6 +38,7 @@
<string name="label_help">Help</string>
<string name="label_default">Default</string>
<string name="label_warning">Warning</string>
<string name="label_auto">Auto</string>
<!-- Shared labels -->
<string name="label_started">Started</string>
@ -267,8 +268,7 @@
<!-- Library section -->
<string name="pref_category_display">Display</string>
<string name="pref_library_columns">Grid size</string>
<string name="pref_library_columns_per_row">%d per row</string>
<string name="pref_library_columns">Items per row</string>
<string name="portrait">Portrait</string>
<string name="landscape">Landscape</string>
@ -471,10 +471,10 @@
<string name="rotation_landscape">Landscape</string>
<string name="rotation_force_portrait">Locked portrait</string>
<string name="rotation_force_landscape">Locked landscape</string>
<string name="color_filter_r_value">R</string>
<string name="color_filter_g_value">G</string>
<string name="color_filter_b_value">B</string>
<string name="color_filter_a_value">A</string>
<string name="color_filter_r_value">Red</string>
<string name="color_filter_g_value">Green</string>
<string name="color_filter_b_value">Blue</string>
<string name="color_filter_a_value">Alpha</string>
<string name="pref_always_show_chapter_transition">Always show chapter transition</string>
<string name="pref_category_reading_mode">Reading mode</string>
<string name="pref_category_reading">Reading</string>

View File

@ -10,6 +10,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
@ -19,7 +20,7 @@ fun Pill(
modifier: Modifier = Modifier,
color: Color = MaterialTheme.colorScheme.surfaceContainerHigh,
contentColor: Color = MaterialTheme.colorScheme.onSurface,
fontSize: TextUnit = LocalTextStyle.current.fontSize,
style: TextStyle = LocalTextStyle.current,
) {
Surface(
modifier = modifier
@ -35,9 +36,27 @@ fun Pill(
) {
Text(
text = text,
fontSize = fontSize,
maxLines = 1,
style = style,
)
}
}
}
@Composable
fun Pill(
text: String,
modifier: Modifier = Modifier,
color: Color = MaterialTheme.colorScheme.surfaceContainerHigh,
contentColor: Color = MaterialTheme.colorScheme.onSurface,
fontSize: TextUnit = LocalTextStyle.current.fontSize,
) {
val style = LocalTextStyle.current
Pill(
text = text,
modifier = modifier,
color = color,
contentColor = contentColor,
style = MaterialTheme.typography.bodyMedium.copy(fontSize = fontSize),
)
}

View File

@ -1,6 +1,7 @@
package tachiyomi.presentation.core.components
import androidx.compose.foundation.clickable
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.FlowRow
@ -29,7 +30,10 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuAnchorType
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -37,9 +41,12 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import dev.icerock.moko.resources.StringResource
import tachiyomi.core.common.preference.Preference
@ -171,29 +178,36 @@ fun SliderItem(
onChange: (Int) -> Unit,
max: Int,
min: Int = 0,
steps: Int = 0,
labelStyle: TextStyle = MaterialTheme.typography.bodyMedium,
pillColor: Color = MaterialTheme.colorScheme.surfaceContainerHigh,
) {
val haptic = LocalHapticFeedback.current
Row(
Column(
modifier = Modifier
.fillMaxWidth()
.padding(
horizontal = SettingsItemsPaddings.Horizontal,
vertical = SettingsItemsPaddings.Vertical,
),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(24.dp),
) {
Column(modifier = Modifier.weight(0.5f)) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
) {
Text(
text = label,
style = MaterialTheme.typography.bodyMedium,
style = labelStyle,
modifier = Modifier.weight(1f),
)
Pill(
text = valueText,
style = MaterialTheme.typography.bodyMedium,
color = pillColor,
)
Text(valueText)
}
Slider(
modifier = Modifier.weight(1.5f),
value = value,
onValueChange = f@{
if (it == value) return@f
@ -201,10 +215,29 @@ fun SliderItem(
haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove)
},
valueRange = min..max,
steps = steps,
)
}
}
@Composable
@PreviewLightDark
fun SliderItemPreview() {
MaterialTheme(if (isSystemInDarkTheme()) darkColorScheme() else lightColorScheme()) {
Surface {
SliderItem(
label = "Item per row",
valueText = "Auto",
value = 0,
onChange = {},
min = 0,
max = 10,
steps = 8,
)
}
}
}
@Composable
fun SelectItem(
label: String,

View File

@ -9,6 +9,7 @@ import androidx.compose.material3.SliderState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import kotlin.math.roundToInt
@Composable
fun Slider(
@ -17,7 +18,7 @@ fun Slider(
modifier: Modifier = Modifier,
enabled: Boolean = true,
valueRange: ClosedRange<Int> = 0..1,
@IntRange(from = 0) steps: Int = with(valueRange) { (endInclusive - start) - 1 },
@IntRange(from = 0) steps: Int = 0,
onValueChangeFinished: (() -> Unit)? = null,
colors: SliderColors = SliderDefaults.colors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
@ -34,7 +35,7 @@ fun Slider(
) {
Slider(
value = value.toFloat(),
onValueChange = { onValueChange(it.toInt()) },
onValueChange = { onValueChange(it.roundToInt()) },
modifier = modifier,
enabled = enabled,
valueRange = with(valueRange) { start.toFloat()..endInclusive.toFloat() },