diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/ColorFilterSetting.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/ColorFilterSetting.kt index 9f3748086..daad2a195 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/ColorFilterSetting.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/ColorFilterSetting.kt @@ -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, ) } } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/ReaderScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/ReaderScreen.kt index ff7c36576..044277437 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/ReaderScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/ReaderScreen.kt @@ -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 -> diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/SliderPagerDoubleSync.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/SliderPagerDoubleSync.kt index bffcfe743..ed6b2ea08 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/SliderPagerDoubleSync.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/SliderPagerDoubleSync.kt @@ -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 { diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/WebtoonViewer.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/WebtoonViewer.kt index b683d2b3f..be1160423 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/WebtoonViewer.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/WebtoonViewer.kt @@ -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( diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/Widget.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/Widget.kt index aa57a1700..a3fc75c7c 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/Widget.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/Widget.kt @@ -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) { fun SliderChoice( startSlot: @Composable () -> Unit, endSlot: @Composable () -> Unit, - range: IntRange, - field: MutableState, + 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() } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt index 5cf1f7736..814550a87 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt @@ -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() } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/DownloadScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/DownloadScreen.kt index 41436f274..d33d52b63 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/DownloadScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/DownloadScreen.kt @@ -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() diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/EhScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/EhScreen.kt index 0182348f0..8a7b29ced 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/EhScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/EhScreen.kt @@ -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) { diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/PreferenceWidgets.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/PreferenceWidgets.kt index ce7af1dfb..75b02145b 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/PreferenceWidgets.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/PreferenceWidgets.kt @@ -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, 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, 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, diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/PrivacyScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/PrivacyScreen.kt index a0e916f5c..babb3f222 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/PrivacyScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/PrivacyScreen.kt @@ -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(), ) } diff --git a/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/ChapterNavigator.kt b/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/ChapterNavigator.kt index f77549b66..a1806b218 100644 --- a/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/ChapterNavigator.kt +++ b/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/ChapterNavigator.kt @@ -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, diff --git a/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/ReaderAppBars.kt b/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/ReaderAppBars.kt index d0d7a788e..c667c7fa9 100644 --- a/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/ReaderAppBars.kt +++ b/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/ReaderAppBars.kt @@ -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, diff --git a/app/src/main/kotlin/me/zhanghai/compose/preference/IntSliderPreference.kt b/app/src/main/kotlin/me/zhanghai/compose/preference/IntSliderPreference.kt index d371e996b..1382c1fe2 100644 --- a/app/src/main/kotlin/me/zhanghai/compose/preference/IntSliderPreference.kt +++ b/app/src/main/kotlin/me/zhanghai/compose/preference/IntSliderPreference.kt @@ -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, + 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 diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index 37f1fa8a9..24c7498e0 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -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) diff --git a/core/ui/src/commonMain/kotlin/com/ehviewer/core/ui/component/Slider.kt b/core/ui/src/commonMain/kotlin/com/ehviewer/core/ui/component/Slider.kt index 94e135a81..47c77d6a9 100644 --- a/core/ui/src/commonMain/kotlin/com/ehviewer/core/ui/component/Slider.kt +++ b/core/ui/src/commonMain/kotlin/com/ehviewer/core/ui/component/Slider.kt @@ -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, 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) }