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 <whatever@tagkong.com>
This commit is contained in:
renovate[bot]andGG Bond authored and GitHub committed 2024-03-05 16:19:21 +00:00
1 parent 1dcf4e7f46
commit 3ecfd83f1e
9 files changed
+241 -78

No files matched your search

@@ -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) {
@@ -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")
@@ -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(),
)
}
@@ -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(),
)
}
}
}
@@ -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),
)
}
}
@@ -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()
}
}
}
@@ -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)
@@ -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)
}
}
}
@@ -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<Boolean>) {
)
}
}
@Composable
fun SliderChoice(
startSlot: @Composable () -> Unit,
endSlot: @Composable () -> Unit,
range: IntRange,
field: MutableState<Int>,
) {
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()
}
}