Refactor for upstream Slider api changes

This commit is contained in:
Dude so hot committed 2026-10-08 03:44:12 +08:00
1 parent 5c406ac8b0
commit baf8333b70
15 files changed
+96 -115

No files matched your search

@@ -10,10 +10,6 @@ import androidx.compose.material.icons.filled.Brightness5
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringArrayResource
import androidx.compose.ui.res.stringResource
@@ -23,6 +19,8 @@ import androidx.core.graphics.green
import androidx.core.graphics.red
import com.ehviewer.core.i18n.R
import com.ehviewer.core.ui.component.RollingNumber
import com.ehviewer.core.ui.component.rememberIntPrefSliderState
import com.ehviewer.core.ui.component.rememberIntSliderState
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
@@ -34,12 +32,11 @@ fun ColorFilterSetting() = Column(modifier = Modifier.verticalScroll(rememberScr
field = customBrightness,
)
AnimatedVisibility(visible = customBrightness.value) {
val brightness = Settings.customBrightnessValue.asMutableState()
val brightness = rememberIntPrefSliderState(Settings.customBrightnessValue, -75..100)
SliderChoice(
startSlot = { Icon(imageVector = Icons.Default.Brightness5, contentDescription = null) },
endSlot = { RollingNumber(number = brightness.value, length = 3) },
range = -75..100,
field = brightness,
state = brightness,
)
}
val colorFilter = Settings.colorFilter.asMutableState()
@@ -48,40 +45,32 @@ fun ColorFilterSetting() = Column(modifier = Modifier.verticalScroll(rememberScr
field = colorFilter,
)
AnimatedVisibility(visible = colorFilter.value) {
var color by Settings.colorFilterValue.asMutableState()
val rf = remember { mutableIntStateOf(color.red) }
val r by rf
val gf = remember { mutableIntStateOf(color.green) }
val g by gf
val bf = remember { mutableIntStateOf(color.blue) }
val b by bf
val af = remember { mutableIntStateOf(color.alpha) }
val a by af
color = (a shl 24) or (r shl 16) or (g shl 8) or (b)
var color by Settings.colorFilterValue
val r = rememberIntSliderState(color.red, 0..255)
val g = rememberIntSliderState(color.green, 0..255)
val b = rememberIntSliderState(color.blue, 0..255)
val a = rememberIntSliderState(color.alpha, 0..255)
color = (a.value shl 24) or (r.value shl 16) or (g.value shl 8) or (b.value)
Column {
SliderChoice(
startSlot = { Text(text = "R") },
endSlot = { RollingNumber(number = r, length = 3) },
range = 0..255,
field = rf,
endSlot = { RollingNumber(number = r.value, length = 3) },
state = r,
)
SliderChoice(
startSlot = { Text(text = "G") },
endSlot = { RollingNumber(number = g, length = 3) },
range = 0..255,
field = gf,
endSlot = { RollingNumber(number = g.value, length = 3) },
state = g,
)
SliderChoice(
startSlot = { Text(text = "B") },
endSlot = { RollingNumber(number = b, length = 3) },
range = 0..255,
field = bf,
endSlot = { RollingNumber(number = b.value, length = 3) },
state = b,
)
SliderChoice(
startSlot = { Text(text = "A") },
endSlot = { RollingNumber(number = a, length = 3) },
range = 0..255,
field = af,
endSlot = { RollingNumber(number = a.value, length = 3) },
state = a,
)
}
}
@@ -18,7 +18,6 @@ import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.lazy.layout.LazyLayoutCacheWindow
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.BottomSheetDefaults
@@ -93,6 +92,7 @@ import eu.kanade.tachiyomi.ui.reader.ReaderContentOverlay
import eu.kanade.tachiyomi.ui.reader.ReaderPageSheetMeta
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
import kotlin.coroutines.resume
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.merge
@@ -215,9 +215,9 @@ fun ReaderScreen(pageLoader: PageLoader, info: BaseGalleryInfo?) {
uiController.showTransientSystemBarsBySwipe = false
}
}
val lazyListState = rememberLazyListState(LazyLayoutCacheWindow(SCROLL_FRACTION, SCROLL_FRACTION), pageLoader.startPage)
val lazyListState = rememberLazyListState(pageLoader.startPage)
val pagerState = rememberPagerState(pageLoader.startPage) { pageLoader.size }
val syncState = rememberSliderPagerDoubleSyncState(lazyListState, pagerState, pageLoader)
val sync = rememberSliderPagerDoubleSyncState(lazyListState, pagerState, pageLoader)
var appbarVisible by remember { mutableStateOf(false) }
val isWebtoon by rememberUpdatedState(ReadingModeType.isWebtoon(readingMode))
val focusRequester = remember { FocusRequester() }
@@ -232,7 +232,7 @@ fun ReaderScreen(pageLoader: PageLoader, info: BaseGalleryInfo?) {
LaunchedEffect(Unit) {
focusRequester.requestFocus()
}
syncState.Sync(isWebtoon) { appbarVisible = false }
sync.Sync(isWebtoon) { appbarVisible = false }
val bgColor by collectBackgroundColorAsState()
val isDarkTheme = isSystemInDarkTheme()
LaunchedEffect(isDarkTheme) {
@@ -293,10 +293,10 @@ fun ReaderScreen(pageLoader: PageLoader, info: BaseGalleryInfo?) {
onNavigationModeChange = { showNavigationOverlay = true },
onSelectPage = onSelectPage,
onMenuRegionClick = { appbarVisible = !appbarVisible },
modifier = Modifier.background(bgColor).pointerInput(syncState) {
modifier = Modifier.background(bgColor).pointerInput(sync) {
awaitEachGesture {
waitForUpOrCancellation()
syncState.reset()
sync.reset()
showNavigationOverlay = false
}
}.fillMaxSize().windowInsetsPadding(insets),
@@ -324,7 +324,7 @@ fun ReaderScreen(pageLoader: PageLoader, info: BaseGalleryInfo?) {
)
if (brightness) {
LaunchedEffect(Unit) {
Settings.customBrightnessValue.valueFlow().sample(100)
Settings.customBrightnessValue.valueFlow().sample(100.milliseconds)
.onCompletion { activity.setCustomBrightnessValue(0) }
.collect { activity.setCustomBrightnessValue(it) }
}
@@ -333,7 +333,7 @@ fun ReaderScreen(pageLoader: PageLoader, info: BaseGalleryInfo?) {
if (showPageNumber && !appbarVisible) {
CompositionLocalProvider(LocalTextStyle provides MaterialTheme.typography.bodySmall) {
PageIndicatorText(
currentPage = syncState.sliderValue,
currentPage = sync.slider.value,
totalPages = pageLoader.size,
modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding(),
)
@@ -344,9 +344,9 @@ fun ReaderScreen(pageLoader: PageLoader, info: BaseGalleryInfo?) {
title = pageLoader.title,
isRtl = readingMode == ReadingModeType.RIGHT_TO_LEFT,
showSeekBar = showSeekbar,
currentPage = syncState.sliderValue,
slider = sync.slider,
totalPages = pageLoader.size,
onSliderValueChange = syncState::sliderScrollTo,
onSliderValueChange = sync::sliderScrollTo,
onClickSettings = {
launch {
dialog { cont ->
@@ -6,11 +6,11 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.Stable
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
import androidx.compose.runtime.snapshotFlow
import com.ehviewer.core.ui.component.IntSliderState
import com.hippo.ehviewer.gallery.PageLoader
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.drop
@@ -23,12 +23,11 @@ class SliderPagerDoubleSync(
private val pageLoader: PageLoader,
) {
private var sliderFollowPager by mutableStateOf(true)
var sliderValue by mutableIntStateOf(pageLoader.startPage + 1)
private set
val slider = IntSliderState(pageLoader.startPage + 1, 1..pageLoader.size)
fun sliderScrollTo(index: Int) {
sliderFollowPager = false
sliderValue = index.coerceIn(1, pageLoader.size)
slider.value = index
}
fun reset() {
@@ -50,7 +49,7 @@ class SliderPagerDoubleSync(
@Composable
fun Sync(webtoon: Boolean, onPageSelected: () -> Unit) {
val currentIndexFlow = remember(webtoon) {
val initialIndex = sliderValue - 1
val initialIndex = slider.value - 1
sliderFollowPager = if (webtoon) {
lazyListState.firstVisibleItemIndex == initialIndex
} else {
@@ -61,14 +60,14 @@ class SliderPagerDoubleSync(
if (sliderFollowPager) {
LaunchedEffect(currentIndexFlow) {
currentIndexFlow.drop(1).collect { index ->
sliderValue = index + 1
slider.value = index + 1
pageLoader.startPage = index
onPageSelected()
}
}
} else {
LaunchedEffect(webtoon) {
snapshotFlow { sliderValue - 1 }.collectLatest { index ->
snapshotFlow { slider.value - 1 }.collectLatest { index ->
if (webtoon) {
lazyListState.scrollToItem(index)
} else {
@@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.layout.LazyLayoutCacheWindow
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@@ -81,6 +82,7 @@ fun WebtoonViewer(
state = lazyListState,
contentPadding = PaddingValues(horizontal = sidePadding),
verticalArrangement = Arrangement.spacedBy(if (withGaps) 15.dp else 0.dp),
cacheWindow = LazyLayoutCacheWindow(SCROLL_FRACTION, SCROLL_FRACTION),
) {
items(items, key = { it.index }) { page ->
PagerItem(
@@ -25,6 +25,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.ehviewer.core.ui.component.IntSliderState
import com.ehviewer.core.ui.component.Slider
@Composable
@@ -84,20 +85,17 @@ fun SwitchChoice(title: String, field: MutableState<Boolean>) {
fun SliderChoice(
startSlot: @Composable () -> Unit,
endSlot: @Composable () -> Unit,
range: IntRange,
field: MutableState<Int>,
state: IntSliderState,
) {
var value by field
Row(
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically,
) {
startSlot()
Slider(
value = value,
onValueChange = { value = it },
state = state,
onValueChange = { state.value = it },
modifier = Modifier.weight(1f).padding(8.dp),
valueRange = range,
)
endSlot()
}
@@ -63,6 +63,7 @@ import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import java.io.File
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.merge
@@ -214,7 +215,7 @@ fun AnimatedVisibilityScope.AdvancedScreen(navigator: DestinationsNavigator) = S
step = 3,
title = stringResource(id = R.string.settings_advanced_hardware_bitmap_threshold),
summary = stringResource(id = R.string.settings_advanced_hardware_bitmap_threshold_summary),
state = Settings.hardwareBitmapThreshold.asMutableState(),
pref = Settings.hardwareBitmapThreshold,
)
}
SwitchPreference(
@@ -289,7 +290,7 @@ fun AnimatedVisibilityScope.AdvancedScreen(navigator: DestinationsNavigator) = S
EhDB.putLocalFavorites(result.galleryInfoList)
launchSnackbar(string(R.string.settings_advanced_backup_favorite_start, status))
if (result.next != null) {
delay(Settings.downloadDelay.value.toLong())
delay(Settings.downloadDelay.value.milliseconds)
favListUrlBuilder.setIndex(result.next, true)
doBackup()
}
@@ -195,7 +195,7 @@ fun AnimatedVisibilityScope.DownloadScreen(navigator: DestinationsNavigator) = S
maxValue = 10,
minValue = MIN_SPEED_LEVEL,
title = stringResource(id = R.string.settings_download_timeout_speed),
state = Settings.timeoutSpeed.asMutableState(),
pref = Settings.timeoutSpeed,
display = ::speedLevelToSpeed,
)
val preloadImage = Settings.preloadImage.asMutableState()
@@ -193,7 +193,7 @@ fun AnimatedVisibilityScope.EhScreen(navigator: DestinationsNavigator) = Screen(
minValue = 20,
step = 7,
title = stringResource(id = R.string.list_tile_thumb_size),
state = Settings.listThumbSize.asMutableState(),
pref = Settings.listThumbSize,
)
SimpleMenuPreferenceInt(
title = stringResource(id = R.string.settings_eh_detail_size),
@@ -207,7 +207,7 @@ fun AnimatedVisibilityScope.EhScreen(navigator: DestinationsNavigator) = Screen(
maxValue = 10,
minValue = 1,
title = stringResource(id = R.string.settings_eh_thumb_columns),
state = Settings.thumbColumns.asMutableState(),
pref = Settings.thumbColumns,
)
SwitchPreference(
title = stringResource(id = R.string.settings_eh_show_gallery_pages),
@@ -235,7 +235,7 @@ fun AnimatedVisibilityScope.EhScreen(navigator: DestinationsNavigator) = Screen(
minValue = -101,
title = stringResource(id = R.string.settings_eh_show_gallery_comment_threshold),
summary = stringResource(id = R.string.settings_eh_show_gallery_comment_threshold_summary),
state = Settings.commentThreshold.asMutableState(),
pref = Settings.commentThreshold,
)
}
if (EhTagDatabase.translatable) {
@@ -21,7 +21,9 @@ import androidx.compose.ui.res.integerArrayResource
import androidx.compose.ui.res.stringArrayResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import com.ehviewer.core.preferences.PrefDelegate
import com.ehviewer.core.ui.component.RollingNumber
import com.ehviewer.core.ui.component.rememberIntPrefSliderState
import com.hippo.ehviewer.ui.openBrowser
import com.hippo.ehviewer.util.ProgressDialog
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
@@ -71,19 +73,16 @@ fun SwitchPreference(title: String, summary: String? = null, state: MutableState
}
@Composable
fun IntSliderPreference(maxValue: Int, minValue: Int = 0, step: Int = maxValue - minValue - 1, title: String, summary: String? = null, state: MutableState<Int>, enabled: Boolean = true, display: (Int) -> Int = { it }) {
val sliderState = remember { mutableIntStateOf(state.value) }
fun IntSliderPreference(maxValue: Int, minValue: Int = 0, step: Int = maxValue - minValue - 1, title: String, summary: String? = null, pref: PrefDelegate<Int>, enabled: Boolean = true, display: (Int) -> Int = { it }) {
val state = rememberIntPrefSliderState(pref, minValue..maxValue, step)
IntSliderPreference(
state = state,
title = { Text(title) },
valueRange = minValue..maxValue,
valueSteps = step,
sliderState = sliderState,
enabled = enabled,
summary = summary?.let { { Text(it) } },
valueText = {
RollingNumber(
number = display(sliderState.intValue),
number = display(state.value),
color = MaterialTheme.colorScheme.onSurface,
style = MaterialTheme.typography.bodyLarge,
length = 5,
@@ -9,6 +9,7 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
@@ -17,6 +18,7 @@ import com.ehviewer.core.util.launch
import com.hippo.ehviewer.EhApplication.Companion.searchDatabase
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
import com.hippo.ehviewer.collectAsState
import com.hippo.ehviewer.ui.Screen
import com.hippo.ehviewer.ui.isAuthenticationSupported
import com.hippo.ehviewer.ui.main.NavigationIcon
@@ -48,17 +50,17 @@ fun AnimatedVisibilityScope.PrivacyScreen(navigator: DestinationsNavigator) = Sc
enabled = isAuthenticationSupported(),
)
AnimatedVisibility(visible = security.value) {
val securityDelay = Settings.securityDelay.asMutableState()
val summary = if (securityDelay.value == 0) {
val delay by Settings.securityDelay.collectAsState()
val summary = if (delay == 0) {
stringResource(id = R.string.settings_privacy_require_unlock_delay_summary_immediately)
} else {
stringResource(id = R.string.settings_privacy_require_unlock_delay_summary, securityDelay.value)
stringResource(id = R.string.settings_privacy_require_unlock_delay_summary, delay)
}
IntSliderPreference(
maxValue = 30,
title = stringResource(id = R.string.settings_privacy_require_unlock_delay),
summary = summary,
state = securityDelay,
pref = Settings.securityDelay,
enabled = isAuthenticationSupported(),
)
}
@@ -19,6 +19,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import com.ehviewer.core.ui.component.IntSliderState
import com.ehviewer.core.ui.component.Slider
import com.ehviewer.core.ui.component.defaultMaxTickCount
import com.ehviewer.core.ui.util.HapticFeedbackType
@@ -29,7 +30,7 @@ import com.ehviewer.core.ui.util.rememberHapticFeedback
@Composable
fun ChapterNavigator(
isRtl: Boolean,
currentPage: Int,
slider: IntSliderState,
totalPages: Int,
onSliderValueChange: (Int) -> Unit,
containerColor: Color,
@@ -40,14 +41,13 @@ fun ChapterNavigator(
modifier = Modifier.padding(horizontal = horizontalPadding).clip(CircleShape).background(containerColor).padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text(text = "$currentPage")
val steps = totalPages - 2
Text(text = "${slider.value}")
val maxTickCount = defaultMaxTickCount()
val interactionSource = remember { MutableInteractionSource() }
if (steps < maxTickCount) {
if (slider.state.steps < maxTickCount) {
val sliderDragged by interactionSource.collectIsDraggedAsState()
val hapticFeedback = rememberHapticFeedback()
LaunchedEffect(currentPage) {
LaunchedEffect(slider.value) {
if (sliderDragged) {
hapticFeedback.performHapticFeedback(HapticFeedbackType.MOVE)
}
@@ -55,9 +55,7 @@ fun ChapterNavigator(
}
Slider(
modifier = Modifier.weight(1f).padding(horizontal = 8.dp),
value = currentPage,
valueRange = 1..totalPages,
steps = steps,
state = slider,
onValueChange = onSliderValueChange,
maxTickCount = maxTickCount,
interactionSource = interactionSource,
@@ -23,6 +23,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import com.ehviewer.core.ui.component.IntSliderState
import com.hippo.ehviewer.ui.main.NavigationIcon
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
@@ -35,7 +36,7 @@ fun BoxScope.ReaderAppBars(
title: String,
isRtl: Boolean,
showSeekBar: Boolean,
currentPage: Int,
slider: IntSliderState,
totalPages: Int,
onSliderValueChange: (Int) -> Unit,
onClickSettings: () -> Unit,
@@ -65,7 +66,7 @@ fun BoxScope.ReaderAppBars(
if (showSeekBar && totalPages > 1) {
ChapterNavigator(
isRtl = isRtl,
currentPage = currentPage,
slider = slider,
totalPages = totalPages,
onSliderValueChange = onSliderValueChange,
containerColor = backgroundColor,
@@ -21,39 +21,21 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableIntState
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import com.ehviewer.core.ui.component.IntSliderState
import com.ehviewer.core.ui.component.Slider
@Composable
fun IntSliderPreference(
state: MutableState<Int>,
state: IntSliderState,
title: @Composable () -> Unit,
modifier: Modifier = Modifier,
valueRange: IntRange = 0..1,
valueSteps: Int = 0,
sliderState: MutableIntState = remember { mutableIntStateOf(state.value) },
enabled: Boolean = true,
icon: @Composable (() -> Unit)? = null,
summary: @Composable (() -> Unit)? = null,
valueText: @Composable (() -> Unit)? = null,
) {
var value by state
var sliderValue by sliderState
var lastValue by remember { mutableIntStateOf(value) }
SideEffect {
if (value != lastValue) {
sliderValue = value
lastValue = value
}
}
Preference(
title = title,
modifier = modifier,
@@ -64,13 +46,10 @@ fun IntSliderPreference(
summary?.invoke()
Row(verticalAlignment = Alignment.CenterVertically) {
Slider(
value = sliderValue,
onValueChange = { sliderValue = it },
state = state,
onValueChange = { state.value = it },
modifier = Modifier.weight(1f),
enabled = enabled,
valueRange = valueRange,
steps = valueSteps,
onValueChangeFinished = { value = sliderValue },
)
if (valueText != null) {
val theme = LocalPreferenceTheme.current
+1
View File
@@ -7,6 +7,7 @@ kotlin {
commonMain {
dependencies {
api(projects.core.common)
api(projects.core.data)
api(libs.compose.material3)
api(libs.compose.material.icons.extended)
api(libs.compose.material3.adaptive)
@@ -5,6 +5,7 @@ import androidx.compose.material3.Slider
import androidx.compose.material3.SliderColors
import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.SliderDefaults.drawStopIndicator
import androidx.compose.material3.SliderState
import androidx.compose.material3.rememberSliderState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
@@ -16,30 +17,41 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalWindowInfo
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.util.fastRoundToInt
import com.ehviewer.core.preferences.PrefDelegate
class IntSliderState(val state: SliderState) {
constructor(value: Int, range: IntRange, steps: Int = range.last - range.first - 1) : this(SliderState(value.toFloat(), steps, range.first.toFloat()..range.last.toFloat()))
var value: Int
get() = state.value.fastRoundToInt()
set(value) {
state.value = value.toFloat()
}
}
@Composable
fun rememberIntSliderState(value: Int, range: IntRange, steps: Int = range.last - range.first - 1): IntSliderState {
val state = rememberSliderState(value.toFloat(), steps, range.first.toFloat()..range.last.toFloat())
return remember(range, steps) { IntSliderState(state) }
}
@Composable
fun rememberIntPrefSliderState(value: PrefDelegate<Int>, range: IntRange, steps: Int = range.last - range.first - 1) = rememberIntSliderState(value.value, range, steps).also { value.value = it.value }
@Composable
fun Slider(
value: Int,
state: IntSliderState,
onValueChange: (Int) -> Unit,
valueRange: IntRange,
modifier: Modifier = Modifier,
enabled: Boolean = true,
steps: Int = valueRange.last - valueRange.first - 1,
maxTickCount: Int = defaultMaxTickCount(),
onValueChangeFinished: (() -> Unit)? = null,
colors: SliderColors = SliderDefaults.colors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
) {
val state = rememberSliderState(value.toFloat(), steps, valueRange.first.toFloat()..valueRange.last.toFloat())
Slider(
state = state,
onValueChange = {
onValueChange(it.fastRoundToInt())
state.value = it
},
state = state.state,
onValueChange = { onValueChange(it.fastRoundToInt()) },
modifier = modifier,
enabled = enabled,
onValueChangeFinished = onValueChangeFinished,
colors = colors,
interactionSource = interactionSource,
track = { state ->
@@ -48,7 +60,7 @@ fun Slider(
trackCornerSize = Dp.Unspecified,
enabled = enabled,
colors = colors,
drawTick = if (steps < maxTickCount) {
drawTick = if (state.steps < maxTickCount) {
{ offset, color ->
drawStopIndicator(offset = offset, color = color, size = SliderDefaults.TickSize)
}