Add vertical chapter navigator for long strip mode (#3377)

This commit is contained in:
AntsyLich
2026-06-04 01:54:52 +06:00
committed by GitHub
parent d28c605a89
commit a330258f6a
8 changed files with 273 additions and 47 deletions
+1
View File
@@ -13,6 +13,7 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co
## [Unreleased] ## [Unreleased]
### Added ### Added
- Add support for `tachiyomix` extension index format ([@AntsyLich](https://github.com/AntsyLich)) ([#3349](https://github.com/mihonapp/mihon/pull/3349)) - Add support for `tachiyomix` extension index format ([@AntsyLich](https://github.com/AntsyLich)) ([#3349](https://github.com/mihonapp/mihon/pull/3349))
- Add vertical chapter navigator for long strip mode ([@AntsyLich](https://github.com/AntsyLich)) ([#3377](https://github.com/mihonapp/mihon/pull/3377))
### Changed ### Changed
- Change all reference of extension repo to extension store ([@AntsyLich](https://github.com/AntsyLich)) ([#3349](https://github.com/mihonapp/mihon/pull/3349)) - Change all reference of extension repo to extension store ([@AntsyLich](https://github.com/AntsyLich)) ([#3349](https://github.com/mihonapp/mihon/pull/3349))
@@ -74,8 +74,8 @@ object SettingsReaderScreen : SearchableSettings {
@Composable @Composable
private fun getDisplayGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup { private fun getDisplayGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
val fullscreenPref = readerPreferences.fullscreen val fullscreen by readerPreferences.fullscreen.collectAsState()
val fullscreen by fullscreenPref.collectAsState() val verticalNavigatorForLongStrip by readerPreferences.verticalNavigatorForLongStrip.collectAsState()
return Preference.PreferenceGroup( return Preference.PreferenceGroup(
title = stringResource(MR.strings.pref_category_display), title = stringResource(MR.strings.pref_category_display),
preferenceItems = persistentListOf( preferenceItems = persistentListOf(
@@ -97,7 +97,7 @@ object SettingsReaderScreen : SearchableSettings {
title = stringResource(MR.strings.pref_reader_theme), title = stringResource(MR.strings.pref_reader_theme),
), ),
Preference.PreferenceItem.SwitchPreference( Preference.PreferenceItem.SwitchPreference(
preference = fullscreenPref, preference = readerPreferences.fullscreen,
title = stringResource(MR.strings.pref_fullscreen), title = stringResource(MR.strings.pref_fullscreen),
), ),
Preference.PreferenceItem.SwitchPreference( Preference.PreferenceItem.SwitchPreference(
@@ -113,6 +113,15 @@ object SettingsReaderScreen : SearchableSettings {
preference = readerPreferences.showPageNumber, preference = readerPreferences.showPageNumber,
title = stringResource(MR.strings.pref_show_page_number), title = stringResource(MR.strings.pref_show_page_number),
), ),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.verticalNavigatorForLongStrip,
title = stringResource(MR.strings.pref_webtoon_vertical_navigator),
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.verticalNavigatorOnLeft,
title = stringResource(MR.strings.pref_webtoon_vertical_navigator_on_left),
enabled = verticalNavigatorForLongStrip,
),
), ),
) )
} }
@@ -4,13 +4,16 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.slideOutVertically import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
@@ -21,14 +24,16 @@ import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import eu.kanade.presentation.reader.components.ChapterNavigator import eu.kanade.presentation.reader.components.ChapterNavigator
import eu.kanade.presentation.reader.components.ChapterNavigatorType
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
import eu.kanade.tachiyomi.ui.reader.viewer.Viewer
import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer
import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.components.material.padding
private val readerBarsSlideAnimationSpec = tween<IntOffset>(200) private val readerBarsSlideAnimationSpec = tween<IntOffset>(200)
@@ -48,7 +53,7 @@ fun ReaderAppBars(
onOpenInBrowser: (() -> Unit)?, onOpenInBrowser: (() -> Unit)?,
onShare: (() -> Unit)?, onShare: (() -> Unit)?,
viewer: Viewer?, chapterNavigatorType: ChapterNavigatorType,
onNextChapter: () -> Unit, onNextChapter: () -> Unit,
enabledNext: Boolean, enabledNext: Boolean,
onPreviousChapter: () -> Unit, onPreviousChapter: () -> Unit,
@@ -65,7 +70,6 @@ fun ReaderAppBars(
onClickCropBorder: () -> Unit, onClickCropBorder: () -> Unit,
onClickSettings: () -> Unit, onClickSettings: () -> Unit,
) { ) {
val isRtl = viewer is R2LPagerViewer
val backgroundColor = MaterialTheme.colorScheme val backgroundColor = MaterialTheme.colorScheme
.surfaceColorAtElevation(3.dp) .surfaceColorAtElevation(3.dp)
.copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f) .copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f)
@@ -73,10 +77,8 @@ fun ReaderAppBars(
Column(modifier = Modifier.fillMaxHeight()) { Column(modifier = Modifier.fillMaxHeight()) {
AnimatedVisibility( AnimatedVisibility(
visible = visible, visible = visible,
enter = slideInVertically(initialOffsetY = { -it }, animationSpec = readerBarsSlideAnimationSpec) + enter = slideInVertically(readerBarsSlideAnimationSpec) { -it } + fadeIn(readerBarsFadeAnimationSpec),
fadeIn(animationSpec = readerBarsFadeAnimationSpec), exit = slideOutVertically(readerBarsSlideAnimationSpec) { -it } + fadeOut(readerBarsFadeAnimationSpec),
exit = slideOutVertically(targetOffsetY = { -it }, animationSpec = readerBarsSlideAnimationSpec) +
fadeOut(animationSpec = readerBarsFadeAnimationSpec),
) { ) {
ReaderTopBar( ReaderTopBar(
modifier = Modifier modifier = Modifier
@@ -93,26 +95,55 @@ fun ReaderAppBars(
) )
} }
Spacer(modifier = Modifier.weight(1f)) if (!chapterNavigatorType.isHorizontal()) {
val sliderOnLeft = chapterNavigatorType == ChapterNavigatorType.VERTICAL_LEFT
CompositionLocalProvider(
LocalLayoutDirection provides if (sliderOnLeft) LayoutDirection.Ltr else LayoutDirection.Rtl,
) {
Row(modifier = Modifier.weight(1f)) {
AnimatedVisibility(
visible = visible,
enter = slideInHorizontally(readerBarsSlideAnimationSpec) { if (sliderOnLeft) -it else it } +
fadeIn(readerBarsFadeAnimationSpec),
exit = slideOutHorizontally(readerBarsSlideAnimationSpec) { if (sliderOnLeft) -it else it } +
fadeOut(readerBarsFadeAnimationSpec),
) {
ChapterNavigator(
type = chapterNavigatorType,
onNextChapter = onNextChapter,
enabledNext = enabledNext,
onPreviousChapter = onPreviousChapter,
enabledPrevious = enabledPrevious,
currentPage = currentPage,
totalPages = totalPages,
onPageIndexChange = onPageIndexChange,
)
}
Spacer(modifier = Modifier.weight(1f))
}
}
} else {
Spacer(Modifier.weight(1f))
}
AnimatedVisibility( AnimatedVisibility(
visible = visible, visible = visible,
enter = slideInVertically(initialOffsetY = { it }, animationSpec = readerBarsSlideAnimationSpec) + enter = slideInVertically(readerBarsSlideAnimationSpec) { it } + fadeIn(readerBarsFadeAnimationSpec),
fadeIn(animationSpec = readerBarsFadeAnimationSpec), exit = slideOutVertically(readerBarsSlideAnimationSpec) { it } + fadeOut(readerBarsFadeAnimationSpec),
exit = slideOutVertically(targetOffsetY = { it }, animationSpec = readerBarsSlideAnimationSpec) +
fadeOut(animationSpec = readerBarsFadeAnimationSpec),
) { ) {
Column(verticalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small)) { Column(verticalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small)) {
ChapterNavigator( if (chapterNavigatorType.isHorizontal()) {
isRtl = isRtl, ChapterNavigator(
onNextChapter = onNextChapter, type = chapterNavigatorType,
enabledNext = enabledNext, onNextChapter = onNextChapter,
onPreviousChapter = onPreviousChapter, enabledNext = enabledNext,
enabledPrevious = enabledPrevious, onPreviousChapter = onPreviousChapter,
currentPage = currentPage, enabledPrevious = enabledPrevious,
totalPages = totalPages, currentPage = currentPage,
onPageIndexChange = onPageIndexChange, totalPages = totalPages,
) onPageIndexChange = onPageIndexChange,
)
}
ReaderBottomBar( ReaderBottomBar(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -5,8 +5,10 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsDraggedAsState import androidx.compose.foundation.interaction.collectIsDraggedAsState
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
@@ -15,9 +17,14 @@ import androidx.compose.material.icons.outlined.SkipNext
import androidx.compose.material.icons.outlined.SkipPrevious import androidx.compose.material.icons.outlined.SkipPrevious
import androidx.compose.material3.FilledIconButton import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButtonColors
import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Slider
import androidx.compose.material3.SliderState
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.VerticalSlider
import androidx.compose.material3.rememberSliderState
import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
@@ -29,22 +36,34 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import eu.kanade.presentation.theme.TachiyomiPreviewTheme import eu.kanade.presentation.theme.TachiyomiPreviewTheme
import eu.kanade.presentation.util.isTabletUi import eu.kanade.presentation.util.isTabletUi
import tachiyomi.i18n.MR import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Slider
import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.i18n.stringResource
import kotlin.math.roundToInt
enum class ChapterNavigatorType {
HORIZONTAL_LTR,
HORIZONTAL_RTL,
VERTICAL_LEFT,
VERTICAL_RIGHT,
;
fun isHorizontal() = this in setOf(HORIZONTAL_LTR, HORIZONTAL_RTL)
}
@Composable @Composable
fun ChapterNavigator( fun ChapterNavigator(
isRtl: Boolean, type: ChapterNavigatorType,
onNextChapter: () -> Unit, onNextChapter: () -> Unit,
enabledNext: Boolean, enabledNext: Boolean,
onPreviousChapter: () -> Unit, onPreviousChapter: () -> Unit,
@@ -53,11 +72,27 @@ fun ChapterNavigator(
totalPages: Int, totalPages: Int,
onPageIndexChange: (Int) -> Unit, onPageIndexChange: (Int) -> Unit,
) { ) {
val isTabletUi = isTabletUi()
val horizontalPadding = if (isTabletUi) 24.dp else 8.dp
val layoutDirection = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr
val haptic = LocalHapticFeedback.current val haptic = LocalHapticFeedback.current
val state = rememberSliderState(
value = currentPage.toFloat(),
steps = totalPages - 2,
valueRange = 1f..totalPages.toFloat(),
)
state.value = currentPage.toFloat()
state.onValueChange = { onPageIndexChange(it.roundToInt() - 1) }
val interactionSource = remember { MutableInteractionSource() }
val sliderDragged by interactionSource.collectIsDraggedAsState()
LaunchedEffect(currentPage) {
if (sliderDragged) {
haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove)
}
}
val isTabletUi = isTabletUi()
val mainAxisPadding = if (isTabletUi) 24.dp else 8.dp
// Match with toolbar background color set in ReaderActivity // Match with toolbar background color set in ReaderActivity
val backgroundColor = MaterialTheme.colorScheme val backgroundColor = MaterialTheme.colorScheme
.surfaceColorAtElevation(3.dp) .surfaceColorAtElevation(3.dp)
@@ -67,12 +102,61 @@ fun ChapterNavigator(
disabledContainerColor = backgroundColor, disabledContainerColor = backgroundColor,
) )
if (type.isHorizontal()) {
ChapterNavigator(
isRtl = type == ChapterNavigatorType.HORIZONTAL_RTL,
state = state,
onNextChapter = onNextChapter,
enabledNext = enabledNext,
onPreviousChapter = onPreviousChapter,
enabledPrevious = enabledPrevious,
currentPage = currentPage,
totalPages = totalPages,
interactionSource = interactionSource,
mainAxisPadding = mainAxisPadding,
backgroundColor = backgroundColor,
buttonColor = buttonColor,
)
} else {
VerticalChapterNavigator(
state = state,
onNextChapter = onNextChapter,
enabledNext = enabledNext,
onPreviousChapter = onPreviousChapter,
enabledPrevious = enabledPrevious,
currentPage = currentPage,
totalPages = totalPages,
interactionSource = interactionSource,
mainAxisPadding = mainAxisPadding,
backgroundColor = backgroundColor,
buttonColor = buttonColor,
)
}
}
@Composable
fun ChapterNavigator(
isRtl: Boolean,
state: SliderState,
onNextChapter: () -> Unit,
enabledNext: Boolean,
onPreviousChapter: () -> Unit,
enabledPrevious: Boolean,
currentPage: Int,
totalPages: Int,
interactionSource: MutableInteractionSource,
mainAxisPadding: Dp,
backgroundColor: Color,
buttonColor: IconButtonColors,
) {
val layoutDirection = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr
// We explicitly handle direction based on the reader viewer rather than the system direction // We explicitly handle direction based on the reader viewer rather than the system direction
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = horizontalPadding), .padding(horizontal = mainAxisPadding),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
FilledIconButton( FilledIconButton(
@@ -104,23 +188,11 @@ fun ChapterNavigator(
Text(text = totalPages.toString(), color = Color.Transparent) Text(text = totalPages.toString(), color = Color.Transparent)
} }
val interactionSource = remember { MutableInteractionSource() }
val sliderDragged by interactionSource.collectIsDraggedAsState()
LaunchedEffect(currentPage) {
if (sliderDragged) {
haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove)
}
}
Slider( Slider(
state = state,
modifier = Modifier modifier = Modifier
.weight(1f) .weight(1f)
.padding(horizontal = 8.dp), .padding(horizontal = 8.dp),
value = currentPage,
valueRange = 1..totalPages,
onValueChange = f@{
if (it == currentPage) return@f
onPageIndexChange(it - 1)
},
interactionSource = interactionSource, interactionSource = interactionSource,
) )
@@ -147,13 +219,84 @@ fun ChapterNavigator(
} }
} }
@Composable
fun VerticalChapterNavigator(
state: SliderState,
onNextChapter: () -> Unit,
enabledNext: Boolean,
onPreviousChapter: () -> Unit,
enabledPrevious: Boolean,
currentPage: Int,
totalPages: Int,
interactionSource: MutableInteractionSource,
mainAxisPadding: Dp,
backgroundColor: Color,
buttonColor: IconButtonColors,
) {
Column(
modifier = Modifier
.fillMaxHeight()
.padding(vertical = mainAxisPadding),
horizontalAlignment = Alignment.CenterHorizontally,
) {
FilledIconButton(
enabled = enabledPrevious,
onClick = onPreviousChapter,
colors = buttonColor,
) {
Icon(
imageVector = Icons.Outlined.SkipPrevious,
contentDescription = stringResource(MR.strings.action_previous_chapter),
modifier = Modifier.rotate(90f),
)
}
if (totalPages > 1) {
Column(
modifier = Modifier
.weight(1f)
.clip(RoundedCornerShape(24.dp))
.background(backgroundColor)
.padding(vertical = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(text = currentPage.toString())
VerticalSlider(
state = state,
modifier = Modifier
.weight(1f)
.padding(vertical = 8.dp),
interactionSource = interactionSource,
)
Text(text = totalPages.toString())
}
} else {
Spacer(Modifier.weight(1f))
}
FilledIconButton(
enabled = enabledNext,
onClick = onNextChapter,
colors = buttonColor,
) {
Icon(
imageVector = Icons.Outlined.SkipNext,
contentDescription = stringResource(MR.strings.action_next_chapter),
modifier = Modifier.rotate(90f),
)
}
}
}
@Preview @Preview
@Composable @Composable
private fun ChapterNavigatorPreview() { private fun ChapterNavigatorPreview() {
var currentPage by remember { mutableIntStateOf(1) } var currentPage by remember { mutableIntStateOf(1) }
TachiyomiPreviewTheme { TachiyomiPreviewTheme {
ChapterNavigator( ChapterNavigator(
isRtl = false, type = ChapterNavigatorType.VERTICAL_RIGHT,
onNextChapter = {}, onNextChapter = {},
enabledNext = true, enabledNext = true,
onPreviousChapter = {}, onPreviousChapter = {},
@@ -61,6 +61,19 @@ internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) {
pref = screenModel.preferences.showPageNumber, pref = screenModel.preferences.showPageNumber,
) )
val verticalNavigatorForLongStrip by screenModel.preferences.verticalNavigatorForLongStrip.collectAsState()
CheckboxItem(
label = stringResource(MR.strings.pref_webtoon_vertical_navigator),
pref = screenModel.preferences.verticalNavigatorForLongStrip,
)
if (verticalNavigatorForLongStrip) {
CheckboxItem(
label = stringResource(MR.strings.pref_webtoon_vertical_navigator_on_left),
pref = screenModel.preferences.verticalNavigatorOnLeft,
)
}
CheckboxItem( CheckboxItem(
label = stringResource(MR.strings.pref_fullscreen), label = stringResource(MR.strings.pref_fullscreen),
pref = screenModel.preferences.fullscreen, pref = screenModel.preferences.fullscreen,
@@ -56,6 +56,7 @@ import eu.kanade.presentation.reader.ReaderPageActionsDialog
import eu.kanade.presentation.reader.ReaderPageIndicator import eu.kanade.presentation.reader.ReaderPageIndicator
import eu.kanade.presentation.reader.ReadingModeSelectDialog import eu.kanade.presentation.reader.ReadingModeSelectDialog
import eu.kanade.presentation.reader.appbars.ReaderAppBars import eu.kanade.presentation.reader.appbars.ReaderAppBars
import eu.kanade.presentation.reader.components.ChapterNavigatorType
import eu.kanade.presentation.reader.settings.ReaderSettingsDialog import eu.kanade.presentation.reader.settings.ReaderSettingsDialog
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.coil.TachiyomiImageDecoder import eu.kanade.tachiyomi.data.coil.TachiyomiImageDecoder
@@ -76,6 +77,7 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator
import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer
import eu.kanade.tachiyomi.ui.webview.WebViewActivity import eu.kanade.tachiyomi.ui.webview.WebViewActivity
import eu.kanade.tachiyomi.util.system.isNightMode import eu.kanade.tachiyomi.util.system.isNightMode
import eu.kanade.tachiyomi.util.system.openInBrowser import eu.kanade.tachiyomi.util.system.openInBrowser
@@ -458,6 +460,9 @@ class ReaderActivity : BaseActivity() {
val isPagerType = ReadingMode.isPagerType(viewModel.getMangaReadingMode()) val isPagerType = ReadingMode.isPagerType(viewModel.getMangaReadingMode())
val cropEnabled = if (isPagerType) cropBorderPaged else cropBorderWebtoon val cropEnabled = if (isPagerType) cropBorderPaged else cropBorderWebtoon
val verticalNavigatorForLongStrip by readerPreferences.verticalNavigatorForLongStrip.collectAsState()
val verticalNavigatorOnLeft by readerPreferences.verticalNavigatorOnLeft.collectAsState()
ReaderAppBars( ReaderAppBars(
visible = state.menuVisible, visible = state.menuVisible,
@@ -471,7 +476,19 @@ class ReaderActivity : BaseActivity() {
onOpenInBrowser = ::openChapterInBrowser.takeIf { isHttpSource }, onOpenInBrowser = ::openChapterInBrowser.takeIf { isHttpSource },
onShare = ::shareChapter.takeIf { isHttpSource }, onShare = ::shareChapter.takeIf { isHttpSource },
viewer = state.viewer, chapterNavigatorType = if (isPagerType || !verticalNavigatorForLongStrip) {
if (state.viewer is R2LPagerViewer) {
ChapterNavigatorType.HORIZONTAL_RTL
} else {
ChapterNavigatorType.HORIZONTAL_LTR
}
} else {
if (verticalNavigatorOnLeft) {
ChapterNavigatorType.VERTICAL_LEFT
} else {
ChapterNavigatorType.VERTICAL_RIGHT
}
},
onNextChapter = ::loadNextChapter, onNextChapter = ::loadNextChapter,
enabledNext = state.viewerChapters?.nextChapter != null, enabledNext = state.viewerChapters?.nextChapter != null,
onPreviousChapter = ::loadPreviousChapter, onPreviousChapter = ::loadPreviousChapter,
@@ -28,6 +28,16 @@ class ReaderPreferences(
val showPageNumber: Preference<Boolean> = preferenceStore.getBoolean("pref_show_page_number_key", true) val showPageNumber: Preference<Boolean> = preferenceStore.getBoolean("pref_show_page_number_key", true)
val verticalNavigatorForLongStrip: Preference<Boolean> = preferenceStore.getBoolean(
"pref_webtoon_vertical_navigator",
true,
)
val verticalNavigatorOnLeft: Preference<Boolean> = preferenceStore.getBoolean(
"pref_webtoon_vertical_navigator_on_left",
false,
)
val showReadingMode: Preference<Boolean> = preferenceStore.getBoolean("pref_show_reading_mode", true) val showReadingMode: Preference<Boolean> = preferenceStore.getBoolean("pref_show_reading_mode", true)
val fullscreen: Preference<Boolean> = preferenceStore.getBoolean("fullscreen", true) val fullscreen: Preference<Boolean> = preferenceStore.getBoolean("fullscreen", true)
@@ -400,6 +400,8 @@
<string name="pref_flash_style_white_black">White and Black</string> <string name="pref_flash_style_white_black">White and Black</string>
<string name="pref_double_tap_anim_speed">Double tap animation speed</string> <string name="pref_double_tap_anim_speed">Double tap animation speed</string>
<string name="pref_show_page_number">Show page number</string> <string name="pref_show_page_number">Show page number</string>
<string name="pref_webtoon_vertical_navigator">Use vertical navigator for long strip reading</string>
<string name="pref_webtoon_vertical_navigator_on_left">Place vertical navigator on the left side</string>
<string name="pref_show_reading_mode">Show reading mode</string> <string name="pref_show_reading_mode">Show reading mode</string>
<string name="pref_show_reading_mode_summary">Briefly show current mode when reader is opened</string> <string name="pref_show_reading_mode_summary">Briefly show current mode when reader is opened</string>
<string name="pref_hardware_bitmap_threshold">Custom hardware bitmap threshold</string> <string name="pref_hardware_bitmap_threshold">Custom hardware bitmap threshold</string>