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:
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()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user