From 3ecfd83f1e73bcde1b359b7f70f2fd08bff3720d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <99822064+revonateB0T@users.noreply.github.com> Date: Wed, 6 Mar 2024 00:19:21 +0800 Subject: [PATCH] Remaining GeneralSettings Layout (#857) * PlaceHolder * Implement * ConfigureKeepScreenOn * Implement * Remaining general layout * Remove zIndex * Add ReaderContentOverlay * Stub for ColorFilterSetting * Implement ColorFilterSetting * Introduce SliderChoice * Refine naming --------- Co-authored-by: GG Bond --- .../kotlin/com/hippo/ehviewer/Settings.kt | 12 +- .../ehviewer/ui/reader/ColorFilterSetting.kt | 29 +++++ .../com/hippo/ehviewer/ui/reader/General.kt | 27 ---- .../ehviewer/ui/reader/GeneralSetting.kt | 72 +++++++++++ .../hippo/ehviewer/ui/reader/ReaderScreen.kt | 116 +++++++++++------- .../hippo/ehviewer/ui/reader/SettingsPager.kt | 2 +- .../ui/reader/SliderPagerDoubleSync.kt | 7 +- .../com/hippo/ehviewer/ui/reader/Utils.kt | 29 +++++ .../com/hippo/ehviewer/ui/reader/Widget.kt | 25 ++++ 9 files changed, 241 insertions(+), 78 deletions(-) create mode 100644 app/src/main/kotlin/com/hippo/ehviewer/ui/reader/ColorFilterSetting.kt delete mode 100644 app/src/main/kotlin/com/hippo/ehviewer/ui/reader/General.kt create mode 100644 app/src/main/kotlin/com/hippo/ehviewer/ui/reader/GeneralSetting.kt create mode 100644 app/src/main/kotlin/com/hippo/ehviewer/ui/reader/Utils.kt diff --git a/app/src/main/kotlin/com/hippo/ehviewer/Settings.kt b/app/src/main/kotlin/com/hippo/ehviewer/Settings.kt index e6da812a3..7964ffd68 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/Settings.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/Settings.kt @@ -176,6 +176,8 @@ object Settings : DataStorePreferences(null) { var touchSlopFactor by intPref("touch_slop", 3) // Tachiyomi Reader + var newReader by boolPref("new_compose_reader", false) + val cropBorder = boolPref("crop_borders", false) val colorFilter = boolPref("pref_color_filter_key", false) val colorFilterValue = intPref("color_filter_value", 0) @@ -186,8 +188,16 @@ object Settings : DataStorePreferences(null) { val orientationMode = intPref("pref_default_orientation_type_key", OrientationType.FREE.flagValue) val showReaderSeekbar = boolPref("pref_show_reader_seekbar", true) val showPageNumber = boolPref("pref_show_page_number_key", true) - var newReader by boolPref("new_compose_reader", false) val readerTheme = intPref("pref_reader_theme_key", 1) + val doubleTapToZoom = boolPref("pref_double_tap_to_zoom", true) + val fullscreen = boolPref("fullscreen", true) + val cutoutShort = boolPref("cutout_short", true) + val keepScreenOn = boolPref("pref_keep_screen_on_key", true) + val readerLongTapAction = boolPref("reader_long_tap", true) + val pageTransitions = boolPref("pref_enable_transitions_key", true) + val readWithVolumeKeys = boolPref("reader_volume_keys", false) + val readWithVolumeKeysInterval = intPref("reader_volume_keys_interval", 0) + val readWithVolumeKeysInverted = boolPref("reader_volume_keys_inverted", false) init { if ("CN" == Locale.getDefault().country) { 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 new file mode 100644 index 000000000..bd8ee4ba8 --- /dev/null +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/ColorFilterSetting.kt @@ -0,0 +1,29 @@ +package com.hippo.ehviewer.ui.reader + +import androidx.compose.foundation.layout.Column +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringArrayResource +import androidx.compose.ui.res.stringResource +import com.hippo.ehviewer.R +import com.hippo.ehviewer.Settings +import com.hippo.ehviewer.asMutableState + +@Composable +fun ColorFilterSetting() = Column { + SwitchChoice( + title = stringResource(id = R.string.pref_custom_brightness), + field = Settings.customBrightness.asMutableState(), + ) + SwitchChoice( + title = stringResource(id = R.string.pref_custom_color_filter), + field = Settings.colorFilter.asMutableState(), + ) + SpinnerChoice( + title = stringResource(id = R.string.pref_color_filter_mode), + entries = stringArrayResource(id = R.array.color_filter_modes), + values = colorFilterValues, + field = Settings.colorFilterMode.asMutableState(), + ) +} + +private val colorFilterValues = arrayOf("0", "1", "2", "3", "4", "5") diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/General.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/General.kt deleted file mode 100644 index 275f407b4..000000000 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/General.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.hippo.ehviewer.ui.reader - -import androidx.compose.foundation.layout.Column -import androidx.compose.runtime.Composable -import androidx.compose.ui.res.stringArrayResource -import androidx.compose.ui.res.stringResource -import com.hippo.ehviewer.R -import com.hippo.ehviewer.Settings -import com.hippo.ehviewer.asMutableState - -@Composable -fun ReaderGeneralSetting() = Column { - SpinnerChoice( - title = stringResource(id = R.string.pref_reader_theme), - entries = stringArrayResource(id = R.array.reader_themes), - values = stringArrayResource(id = R.array.reader_themes_values), - field = Settings.readerTheme.asMutableState(), - ) - SwitchChoice( - title = stringResource(id = R.string.pref_show_page_number), - field = Settings.showPageNumber.asMutableState(), - ) - SwitchChoice( - title = stringResource(id = R.string.pref_show_reader_seekbar), - field = Settings.showReaderSeekbar.asMutableState(), - ) -} diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/GeneralSetting.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/GeneralSetting.kt new file mode 100644 index 000000000..5e54b7e65 --- /dev/null +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/GeneralSetting.kt @@ -0,0 +1,72 @@ +package com.hippo.ehviewer.ui.reader + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.layout.Column +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringArrayResource +import androidx.compose.ui.res.stringResource +import com.hippo.ehviewer.R +import com.hippo.ehviewer.Settings +import com.hippo.ehviewer.asMutableState + +@Composable +fun ReaderGeneralSetting() = Column { + SpinnerChoice( + title = stringResource(id = R.string.pref_reader_theme), + entries = stringArrayResource(id = R.array.reader_themes), + values = stringArrayResource(id = R.array.reader_themes_values), + field = Settings.readerTheme.asMutableState(), + ) + SwitchChoice( + title = stringResource(id = R.string.pref_show_page_number), + field = Settings.showPageNumber.asMutableState(), + ) + SwitchChoice( + title = stringResource(id = R.string.pref_show_reader_seekbar), + field = Settings.showReaderSeekbar.asMutableState(), + ) + SwitchChoice( + title = stringResource(id = R.string.pref_double_tap_to_zoom), + field = Settings.doubleTapToZoom.asMutableState(), + ) + SwitchChoice( + title = stringResource(id = R.string.pref_fullscreen), + field = Settings.fullscreen.asMutableState(), + ) + SwitchChoice( + title = stringResource(id = R.string.pref_cutout_short), + field = Settings.cutoutShort.asMutableState(), + ) + SwitchChoice( + title = stringResource(id = R.string.pref_keep_screen_on), + field = Settings.keepScreenOn.asMutableState(), + ) + SwitchChoice( + title = stringResource(id = R.string.pref_read_with_long_tap), + field = Settings.readerLongTapAction.asMutableState(), + ) + SwitchChoice( + title = stringResource(id = R.string.pref_page_transitions), + field = Settings.pageTransitions.asMutableState(), + ) + val volume = Settings.readWithVolumeKeys.asMutableState() + SwitchChoice( + title = stringResource(id = R.string.settings_read_volume_page), + field = volume, + ) + AnimatedVisibility(visible = volume.value) { + Column { + SliderChoice( + startSlot = { Text(text = stringResource(id = R.string.settings_read_volume_page_fast)) }, + endSlot = { Text(text = stringResource(id = R.string.settings_read_volume_page_slow)) }, + range = 0..9, + field = Settings.readWithVolumeKeysInterval.asMutableState(), + ) + SwitchChoice( + title = stringResource(id = R.string.settings_read_reverse_volume), + field = Settings.readWithVolumeKeysInverted.asMutableState(), + ) + } + } +} 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 449ebda01..3d8060bff 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 @@ -24,10 +24,10 @@ 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.BlendMode import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.util.VelocityTrackerAddPointsFix import androidx.compose.ui.res.colorResource -import androidx.compose.ui.zIndex import com.hippo.ehviewer.R import com.hippo.ehviewer.Settings import com.hippo.ehviewer.client.data.BaseGalleryInfo @@ -43,11 +43,13 @@ import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.navigation.DestinationsNavigator import eu.kanade.tachiyomi.ui.reader.PageIndicatorText import eu.kanade.tachiyomi.ui.reader.ReaderAppBars +import eu.kanade.tachiyomi.ui.reader.ReaderContentOverlay import eu.kanade.tachiyomi.ui.reader.ReaderPageSheetMeta import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType import eu.kanade.tachiyomi.util.lang.launchIO import kotlin.coroutines.resume import kotlinx.coroutines.launch +import moe.tarsin.kt.unreachable @Destination @Composable @@ -62,6 +64,7 @@ fun ReaderScreen(info: BaseGalleryInfo, page: Int = -1, navigator: DestinationsN } LockDrawer(true) + ConfigureKeepScreenOn() val pageLoader = remember { val archive = DownloadManager.getDownloadInfo(info.gid)?.archiveFile archive?.let { ArchivePageLoader(it, info.gid, page) } ?: EhPageLoader(info, page) @@ -86,6 +89,71 @@ fun ReaderScreen(info: BaseGalleryInfo, page: Int = -1, navigator: DestinationsN syncState.Sync() Box { var appbarVisible by remember { mutableStateOf(false) } + val bgColor by collectBackgroundColorAsState() + GalleryPager( + type = readingMode, + pagerState = pagerState, + lazyListState = lazyListState, + pageLoader = pageLoader, + onSelectPage = { page -> + if (Settings.readerLongTapAction.value) { + launch { + dialog { cont -> + fun dispose() = cont.resume(Unit) + val state = rememberModalBottomSheetState() + ModalBottomSheet( + onDismissRequest = { dispose() }, + sheetState = state, + windowInsets = WindowInsets(0), + ) { + ReaderPageSheetMeta( + retry = { pageLoader.retryPage(page.index) }, + retryOrigin = { pageLoader.retryPage(page.index, true) }, + share = { launchIO { with(pageLoader) { shareImage(page, info) } } }, + copy = { launchIO { with(pageLoader) { copy(page) } } }, + save = { launchIO { with(pageLoader) { save(page) } } }, + saveTo = { launchIO { with(pageLoader) { saveTo(page) } } }, + dismiss = { launch { state.hide().also { dispose() } } }, + ) + Spacer(modifier = Modifier.navigationBarsPadding()) + } + } + } + } + }, + onMenuRegionClick = { appbarVisible = !appbarVisible }, + modifier = Modifier.background(bgColor), + ) + val brightness by Settings.customBrightness.collectAsState() + val brightnessValue by Settings.customBrightnessValue.collectAsState() + val colorOverlayEnabled by Settings.colorFilter.collectAsState() + val colorOverlay by Settings.colorFilterValue.collectAsState() + val colorOverlayMode by Settings.colorFilterMode.collectAsState { + when (it) { + 0 -> BlendMode.SrcOver + 1 -> BlendMode.Multiply + 2 -> BlendMode.Screen + 3 -> BlendMode.Overlay + 4 -> BlendMode.Lighten + 5 -> BlendMode.Darken + else -> unreachable() + } + } + ReaderContentOverlay( + brightness = { brightnessValue }.takeIf { brightness && brightnessValue < 0 }, + color = { colorOverlay }.takeIf { colorOverlayEnabled }, + colorBlendMode = colorOverlayMode, + ) + val showPageNumber by Settings.showPageNumber.collectAsState() + if (showPageNumber) { + CompositionLocalProvider(LocalTextStyle provides MaterialTheme.typography.bodySmall) { + PageIndicatorText( + currentPage = syncState.sliderValue, + totalPages = pageLoader.size, + modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding(), + ) + } + } ReaderAppBars( visible = appbarVisible, isRtl = readingMode == ReadingModeType.RIGHT_TO_LEFT, @@ -97,10 +165,8 @@ fun ReaderScreen(info: BaseGalleryInfo, page: Int = -1, navigator: DestinationsN launch { dialog { cont -> fun dispose() = cont.resume(Unit) - val state = rememberModalBottomSheetState() ModalBottomSheet( onDismissRequest = { dispose() }, - sheetState = state, dragHandle = null, windowInsets = WindowInsets(0), ) { @@ -110,50 +176,6 @@ fun ReaderScreen(info: BaseGalleryInfo, page: Int = -1, navigator: DestinationsN } } }, - modifier = Modifier.zIndex(1f), - ) - val showPageNumber by Settings.showPageNumber.collectAsState() - if (showPageNumber) { - CompositionLocalProvider(LocalTextStyle provides MaterialTheme.typography.bodySmall) { - PageIndicatorText( - currentPage = syncState.sliderValue, - totalPages = pageLoader.size, - modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding().zIndex(0.5f), - ) - } - } - val bgColor by collectBackgroundColorAsState() - GalleryPager( - type = readingMode, - pagerState = pagerState, - lazyListState = lazyListState, - pageLoader = pageLoader, - onSelectPage = { page -> - launch { - dialog { cont -> - fun dispose() = cont.resume(Unit) - val state = rememberModalBottomSheetState() - ModalBottomSheet( - onDismissRequest = { dispose() }, - sheetState = state, - windowInsets = WindowInsets(0), - ) { - ReaderPageSheetMeta( - retry = { pageLoader.retryPage(page.index) }, - retryOrigin = { pageLoader.retryPage(page.index, true) }, - share = { launchIO { with(pageLoader) { shareImage(page, info) } } }, - copy = { launchIO { with(pageLoader) { copy(page) } } }, - save = { launchIO { with(pageLoader) { save(page) } } }, - saveTo = { launchIO { with(pageLoader) { saveTo(page) } } }, - dismiss = { launch { state.hide().also { dispose() } } }, - ) - Spacer(modifier = Modifier.navigationBarsPadding()) - } - } - } - }, - onMenuRegionClick = { appbarVisible = !appbarVisible }, - modifier = Modifier.background(bgColor), ) } } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/SettingsPager.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/SettingsPager.kt index 8698cad3d..c29526f1d 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/SettingsPager.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/SettingsPager.kt @@ -49,7 +49,7 @@ fun SettingsPager(modifier: Modifier = Modifier) { when (page) { 0 -> Spacer(modifier = Modifier.size(200.dp)) 1 -> ReaderGeneralSetting() - 2 -> Spacer(modifier = Modifier.size(200.dp)) + 2 -> ColorFilterSetting() } } } 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 c4dce7fd4..732b7066d 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 @@ -12,6 +12,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow +import com.hippo.ehviewer.Settings import com.hippo.ehviewer.gallery.PageLoader2 import kotlin.math.absoluteValue import kotlinx.coroutines.flow.collectLatest @@ -61,7 +62,8 @@ class SliderPagerDoubleSync( } else { LaunchedEffect(Unit) { snapshotFlow { sliderValue - 1 }.collectLatest { index -> - if ((index - pagerState.currentPage).absoluteValue > SMOOTH_SCROLL_THRESHOLD) { + val noAnim = (index - pagerState.currentPage).absoluteValue > SMOOTH_SCROLL_THRESHOLD || !Settings.pageTransitions.value + if (noAnim) { pagerState.scrollToPage(index) } else { pagerState.animateScrollToPage(index) @@ -71,7 +73,8 @@ class SliderPagerDoubleSync( } LaunchedEffect(Unit) { snapshotFlow { sliderValue - 1 }.collectLatest { index -> - if ((index - lazyListState.firstVisibleItemIndex).absoluteValue > SMOOTH_SCROLL_THRESHOLD) { + val noAnim = (index - lazyListState.firstVisibleItemIndex).absoluteValue > SMOOTH_SCROLL_THRESHOLD || !Settings.pageTransitions.value + if (noAnim) { lazyListState.scrollToItem(index) } else { lazyListState.animateScrollToItem(index) diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/Utils.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/Utils.kt new file mode 100644 index 000000000..ed9ddbf2d --- /dev/null +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/Utils.kt @@ -0,0 +1,29 @@ +package com.hippo.ehviewer.ui.reader + +import android.app.Activity +import android.view.Window +import android.view.WindowManager +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.getValue +import com.hippo.ehviewer.Settings +import com.hippo.ehviewer.collectAsState + +private fun Window.updateKeepScreenOn(enabled: Boolean) { + if (enabled) { + addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + } else { + clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + } +} + +@Composable +fun Activity.ConfigureKeepScreenOn() { + val on by Settings.keepScreenOn.collectAsState() + DisposableEffect(on) { + window.updateKeepScreenOn(on) + onDispose { + window.updateKeepScreenOn(false) + } + } +} 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 f3a560ecf..ae62a25a3 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 @@ -13,6 +13,7 @@ import androidx.compose.material.icons.filled.KeyboardArrowDown import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.Icon +import androidx.compose.material3.Slider import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -77,3 +78,27 @@ fun SwitchChoice(title: String, field: MutableState) { ) } } + +@Composable +fun SliderChoice( + startSlot: @Composable () -> Unit, + endSlot: @Composable () -> Unit, + range: IntRange, + field: MutableState, +) { + var value by field + Row( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + startSlot() + Slider( + value = value.toFloat(), + onValueChange = { value = it.toInt() }, + modifier = Modifier.weight(1f).padding(8.dp), + valueRange = (range.first.toFloat())..(range.last.toFloat()), + steps = range.last - range.first - 1, + ) + endSlot() + } +}