diff --git a/app/src/main/java/eu/kanade/presentation/reader/BottomReaderBar.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt similarity index 99% rename from app/src/main/java/eu/kanade/presentation/reader/BottomReaderBar.kt rename to app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt index 5525a60b6..5a93e74f1 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/BottomReaderBar.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt @@ -1,4 +1,4 @@ -package eu.kanade.presentation.reader +package eu.kanade.presentation.reader.appbars import androidx.compose.foundation.background import androidx.compose.foundation.isSystemInDarkTheme diff --git a/app/src/main/java/eu/kanade/presentation/reader/ChapterNavigator.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/ChapterNavigator.kt similarity index 99% rename from app/src/main/java/eu/kanade/presentation/reader/ChapterNavigator.kt rename to app/src/main/java/eu/kanade/presentation/reader/appbars/ChapterNavigator.kt index ff11dd3c5..dc95064a9 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/ChapterNavigator.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/ChapterNavigator.kt @@ -1,4 +1,4 @@ -package eu.kanade.presentation.reader +package eu.kanade.presentation.reader.appbars import androidx.compose.foundation.background import androidx.compose.foundation.interaction.MutableInteractionSource diff --git a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt new file mode 100644 index 000000000..c465a92cd --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt @@ -0,0 +1,211 @@ +package eu.kanade.presentation.reader.appbars + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.tween +import androidx.compose.animation.slideInHorizontally +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutHorizontally +import androidx.compose.animation.slideOutVertically +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp +import eu.kanade.tachiyomi.ui.reader.setting.OrientationType +import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType +import eu.kanade.tachiyomi.ui.reader.viewer.Viewer +import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer + +private val animationSpec = tween(200) + +// SY --> +enum class NavBarType { + VerticalRight, + VerticalLeft, + Bottom, +} + +@Composable +fun BoxIgnoreLayoutDirection(modifier: Modifier, content: @Composable BoxScope.() -> Unit) { + val layoutDirection = LocalLayoutDirection.current + CompositionLocalProvider( + LocalLayoutDirection provides LayoutDirection.Ltr + ) { + Box(modifier) { + CompositionLocalProvider( + LocalLayoutDirection provides layoutDirection + ) { + content() + } + } + } +} +// SY <-- + +@Composable +fun ReaderAppBars( + visible: Boolean, + viewer: Viewer?, + + onNextChapter: () -> Unit, + enabledNext: Boolean, + onPreviousChapter: () -> Unit, + enabledPrevious: Boolean, + currentPage: Int, + totalPages: Int, + onSliderValueChange: (Int) -> Unit, + + readingMode: ReadingModeType, + onClickReadingMode: () -> Unit, + orientationMode: OrientationType, + onClickOrientationMode: () -> Unit, + cropEnabled: Boolean, + onClickCropBorder: () -> Unit, + onClickSettings: () -> Unit, + // SY --> + navBarType: NavBarType, + currentPageText: String, + enabledButtons: Set, + isHttpSource: Boolean, + dualPageSplitEnabled: Boolean, + doublePages: Boolean, + onClickChapterList: () -> Unit, + onClickWebView: () -> Unit, + onClickShare: () -> Unit, + onClickPageLayout: () -> Unit, + onClickShiftPage: () -> Unit, + +) { + val isRtl = viewer is R2LPagerViewer + + + // SY --> + BoxIgnoreLayoutDirection( + Modifier.fillMaxWidth() + ) { + AnimatedVisibility( + visible = visible && navBarType == NavBarType.VerticalLeft, + enter = slideInHorizontally( + initialOffsetX = { -it }, + animationSpec = animationSpec, + ), + exit = slideOutHorizontally( + targetOffsetX = { -it }, + animationSpec = animationSpec, + ), + modifier = Modifier.padding(bottom = 48.dp, top = 120.dp) + .align(Alignment.TopStart) + ) { + ChapterNavigator( + isRtl = isRtl, + onNextChapter = onNextChapter, + enabledNext = enabledNext, + onPreviousChapter = onPreviousChapter, + enabledPrevious = enabledPrevious, + currentPage = currentPage, + totalPages = totalPages, + onSliderValueChange = onSliderValueChange, + isVerticalSlider = true, + currentPageText = currentPageText, + ) + } + + AnimatedVisibility( + visible = visible && navBarType == NavBarType.VerticalRight, + enter = slideInHorizontally( + initialOffsetX = { it }, + animationSpec = animationSpec, + ), + exit = slideOutHorizontally( + targetOffsetX = { it }, + animationSpec = animationSpec, + ), + modifier = Modifier.padding(bottom = 48.dp, top = 120.dp) + .align(Alignment.TopEnd) + ) { + ChapterNavigator( + isRtl = isRtl, + onNextChapter = onNextChapter, + enabledNext = enabledNext, + onPreviousChapter = onPreviousChapter, + enabledPrevious = enabledPrevious, + currentPage = currentPage, + totalPages = totalPages, + onSliderValueChange = onSliderValueChange, + isVerticalSlider = true, + currentPageText = currentPageText, + ) + } + // SY <-- + Column( + modifier = Modifier.fillMaxHeight(), + verticalArrangement = Arrangement.SpaceBetween, + ) { + Spacer(modifier = Modifier.weight(1f)) + + AnimatedVisibility( + visible = visible, + enter = slideInVertically( + initialOffsetY = { it }, + animationSpec = animationSpec, + ), + exit = slideOutVertically( + targetOffsetY = { it }, + animationSpec = animationSpec, + ), + ) { + Column( + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + if (navBarType == NavBarType.Bottom) { + ChapterNavigator( + isRtl = isRtl, + onNextChapter = onNextChapter, + enabledNext = enabledNext, + onPreviousChapter = onPreviousChapter, + enabledPrevious = enabledPrevious, + currentPage = currentPage, + totalPages = totalPages, + onSliderValueChange = onSliderValueChange, + isVerticalSlider = false, + currentPageText = currentPageText, + ) + } + + BottomReaderBar( + // SY --> + enabledButtons = enabledButtons, + // SY <-- + readingMode = readingMode, + onClickReadingMode = onClickReadingMode, + orientationMode = orientationMode, + onClickOrientationMode = onClickOrientationMode, + cropEnabled = cropEnabled, + onClickCropBorder = onClickCropBorder, + onClickSettings = onClickSettings, + // SY --> + isHttpSource = isHttpSource, + dualPageSplitEnabled = dualPageSplitEnabled, + doublePages = doublePages, + onClickChapterList = onClickChapterList, + onClickWebView = onClickWebView, + onClickShare = onClickShare, + onClickPageLayout = onClickPageLayout, + onClickShiftPage = onClickShiftPage + ) + } + } + } + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index 140656115..5d7e6b4a4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -27,21 +27,14 @@ import android.view.WindowManager import android.view.animation.Animation import android.view.animation.AnimationUtils import android.widget.CompoundButton -import android.widget.RelativeLayout import android.widget.TextView import android.widget.Toast import androidx.activity.viewModels -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.core.tween -import androidx.compose.animation.slideInVertically -import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.material3.AlertDialog import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Text -import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -69,13 +62,13 @@ import com.google.android.material.transition.platform.MaterialContainerTransfor import dev.chrisbanes.insetter.applyInsetter import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.manga.model.readingModeType -import eu.kanade.presentation.reader.BottomReaderBar import eu.kanade.presentation.reader.ChapterListDialog -import eu.kanade.presentation.reader.ChapterNavigator import eu.kanade.presentation.reader.OrientationModeSelectDialog import eu.kanade.presentation.reader.PageIndicatorText import eu.kanade.presentation.reader.ReaderPageActionsDialog import eu.kanade.presentation.reader.ReadingModeSelectDialog +import eu.kanade.presentation.reader.appbars.NavBarType +import eu.kanade.presentation.reader.appbars.ReaderAppBars import eu.kanade.presentation.reader.settings.ReaderSettingsDialog import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.notification.NotificationReceiver @@ -98,7 +91,6 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerConfig import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerViewer -import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer import eu.kanade.tachiyomi.ui.reader.viewer.pager.VerticalPagerViewer import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer import eu.kanade.tachiyomi.ui.webview.WebViewActivity @@ -458,9 +450,9 @@ class ReaderActivity : BaseActivity() { margin(top = true, horizontal = true) } } - binding.readerMenuBottom.applyInsetter { + binding.dialogRoot.applyInsetter { type(navigationBars = true) { - margin(bottom = true, horizontal = true) + margin(vertical = true, horizontal = true) } } @@ -501,6 +493,112 @@ class ReaderActivity : BaseActivity() { ) } + val cropBorderPaged by readerPreferences.cropBorders().collectAsState() + val cropBorderWebtoon by readerPreferences.cropBordersWebtoon().collectAsState() + // SY --> + val readingMode = viewModel.getMangaReadingMode() + val isPagerType = ReadingModeType.isPagerType(readingMode) + val isWebtoon = ReadingModeType.WEBTOON.flagValue == readingMode + val cropBorderContinuousVertical by readerPreferences.cropBordersContinuousVertical().collectAsState() + val cropEnabled = if (isPagerType) { + cropBorderPaged + } else if (isWebtoon) { + cropBorderWebtoon + } else { + cropBorderContinuousVertical + } + val readerBottomButtons by readerPreferences.readerBottomButtons().collectAsState() + val dualPageSplitPaged by readerPreferences.dualPageSplitPaged().collectAsState() + + val forceHorizontalSeekbar by readerPreferences.forceHorizontalSeekbar().collectAsState() + val landscapeVerticalSeekbar by readerPreferences.landscapeVerticalSeekbar().collectAsState() + val leftHandedVerticalSeekbar by readerPreferences.leftVerticalSeekbar().collectAsState() + val configuration = LocalConfiguration.current + val verticalSeekbarLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE && landscapeVerticalSeekbar + val verticalSeekbarHorizontal = configuration.orientation == Configuration.ORIENTATION_PORTRAIT + val viewerIsVertical = (state.viewer is WebtoonViewer || state.viewer is VerticalPagerViewer) + val showVerticalSeekbar = !forceHorizontalSeekbar && (verticalSeekbarLandscape || verticalSeekbarHorizontal) && viewerIsVertical + val navBarType = when { + !showVerticalSeekbar -> NavBarType.Bottom + leftHandedVerticalSeekbar -> NavBarType.VerticalLeft + else -> NavBarType.VerticalRight + + } + // SY <-- + + + ReaderAppBars( + visible = state.menuVisible, + viewer = state.viewer, + + onNextChapter = ::loadNextChapter, + enabledNext = state.viewerChapters?.nextChapter != null, + onPreviousChapter = ::loadPreviousChapter, + enabledPrevious = state.viewerChapters?.prevChapter != null, + currentPage = state.currentPage, + totalPages = state.totalPages, + onSliderValueChange = { + isScrollingThroughPages = true + moveToPageIndex(it) + }, + + readingMode = ReadingModeType.fromPreference( + viewModel.getMangaReadingMode( + resolveDefault = false, + ), + ), + onClickReadingMode = viewModel::openReadingModeSelectDialog, + orientationMode = OrientationType.fromPreference( + viewModel.getMangaOrientationType( + resolveDefault = false, + ), + ), + onClickOrientationMode = viewModel::openOrientationModeSelectDialog, + cropEnabled = cropEnabled, + onClickCropBorder = { + val enabled = viewModel.toggleCropBorders() + + menuToggleToast?.cancel() + menuToggleToast = toast( + if (enabled) { + R.string.on + } else { + R.string.off + }, + ) + }, + onClickSettings = viewModel::openSettingsDialog, + // SY --> + currentPageText = state.currentPageText, + navBarType = navBarType, + enabledButtons = readerBottomButtons, + isHttpSource = remember { + viewModel.getSource() != null + }, + dualPageSplitEnabled = dualPageSplitPaged, + doublePages = state.doublePages, + onClickChapterList = viewModel::openChapterListDialog, + onClickWebView = ::openChapterInWebView, + onClickShare = { + assistUrl?.let { + val intent = it.toUri().toShareIntent(this@ReaderActivity, type = "text/plain") + startActivity(Intent.createChooser(intent, getString(R.string.action_share))) + } + }, + onClickPageLayout = { + if (readerPreferences.pageLayout().get() == PagerConfig.PageLayout.AUTOMATIC) { + (viewModel.state.value.viewer as? PagerViewer)?.config?.let { config -> + config.doublePages = !config.doublePages + reloadChapters(config.doublePages, true) + } + } else { + readerPreferences.pageLayout().set(1 - readerPreferences.pageLayout().get()) + } + }, + onClickShiftPage = ::shiftDoublePages, + // SY <-- + ) + val onDismissRequest = viewModel::closeDialog when (state.dialog) { is ReaderViewModel.Dialog.Loading -> { @@ -589,141 +687,6 @@ class ReaderActivity : BaseActivity() { } // SY --> - val sliderContent: @Composable (Boolean) -> Unit = a@{ isVertical -> - val state by viewModel.state.collectAsState() - if (state.viewer == null) return@a - - val forceHorizontalSeekbar by readerPreferences.forceHorizontalSeekbar().collectAsState() - val landscapeVerticalSeekbar by readerPreferences.landscapeVerticalSeekbar().collectAsState() - val configuration = LocalConfiguration.current - val verticalSeekbarLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE && landscapeVerticalSeekbar - val verticalSeekbarHorizontal = configuration.orientation == Configuration.ORIENTATION_PORTRAIT - val viewerIsVertical = (state.viewer is WebtoonViewer || state.viewer is VerticalPagerViewer) - val showVerticalSeekbar = !forceHorizontalSeekbar && (verticalSeekbarLandscape || verticalSeekbarHorizontal) && viewerIsVertical - if ((isVertical && !showVerticalSeekbar) || (!isVertical && showVerticalSeekbar)) { - return@a - } - - val isRtl = state.viewer is R2LPagerViewer - - ChapterNavigator( - isRtl = isRtl, - // SY --> - isVerticalSlider = isVertical, - // SY <-- - onNextChapter = ::loadNextChapter, - enabledNext = state.viewerChapters?.nextChapter != null, - onPreviousChapter = ::loadPreviousChapter, - enabledPrevious = state.viewerChapters?.prevChapter != null, - currentPage = state.currentPage, - // SY --> - currentPageText = state.currentPageText, - // SY <-- - totalPages = state.totalPages, - onSliderValueChange = { - isScrollingThroughPages = true - moveToPageIndex(it) - }, - ) - } - - // Init listeners on bottom menu - binding.readerNavVert.setComposeContent { - sliderContent(true) - } - - binding.readerMenuBottom.setComposeContent { - val state by viewModel.state.collectAsState() - - if (state.viewer == null) return@setComposeContent - - val cropBorderPaged by readerPreferences.cropBorders().collectAsState() - val cropBorderWebtoon by readerPreferences.cropBordersWebtoon().collectAsState() - val cropBorderContinuousVertical by readerPreferences.cropBordersContinuousVertical().collectAsState() - val readingMode = viewModel.getMangaReadingMode() - val isPagerType = ReadingModeType.isPagerType(readingMode) - val isWebtoon = ReadingModeType.WEBTOON.flagValue == readingMode - val cropEnabled = if (isPagerType) { - cropBorderPaged - } else if (isWebtoon) { - cropBorderWebtoon - } else { - cropBorderContinuousVertical - } - val readerBottomButtons by readerPreferences.readerBottomButtons().collectAsState() - val dualPageSplitPaged by readerPreferences.dualPageSplitPaged().collectAsState() - - AnimatedVisibility( - visible = state.menuVisible, - enter = slideInVertically( - initialOffsetY = { it }, - animationSpec = tween(200), - ), - exit = slideOutVertically( - targetOffsetY = { it }, - animationSpec = tween(200), - ), - ) { - Column( - verticalArrangement = Arrangement.spacedBy(8.dp), - ) { - // SY --> - sliderContent(false) - // SY <-- - - BottomReaderBar( - // SY --> - enabledButtons = readerBottomButtons, - // SY <-- - readingMode = ReadingModeType.fromPreference(viewModel.getMangaReadingMode(resolveDefault = false)), - onClickReadingMode = viewModel::openReadingModeSelectDialog, - orientationMode = OrientationType.fromPreference(viewModel.getMangaOrientationType(resolveDefault = false)), - onClickOrientationMode = viewModel::openOrientationModeSelectDialog, - cropEnabled = cropEnabled, - onClickCropBorder = { - val enabled = viewModel.toggleCropBorders() - - menuToggleToast?.cancel() - menuToggleToast = toast( - if (enabled) { - R.string.on - } else { - R.string.off - }, - ) - }, - onClickSettings = viewModel::openSettingsDialog, - // SY --> - isHttpSource = remember { - viewModel.getSource() != null - }, - dualPageSplitEnabled = dualPageSplitPaged, - doublePages = state.doublePages, - onClickChapterList = viewModel::openChapterListDialog, - onClickWebView = ::openChapterInWebView, - onClickShare = { - assistUrl?.let { - val intent = it.toUri().toShareIntent(this@ReaderActivity, type = "text/plain") - startActivity(Intent.createChooser(intent, getString(R.string.action_share))) - } - }, - onClickPageLayout = { - if (readerPreferences.pageLayout().get() == PagerConfig.PageLayout.AUTOMATIC) { - (viewModel.state.value.viewer as? PagerViewer)?.config?.let { config -> - config.doublePages = !config.doublePages - reloadChapters(config.doublePages, true) - } - } else { - readerPreferences.pageLayout().set(1 - readerPreferences.pageLayout().get()) - } - }, - onClickShiftPage = ::shiftDoublePages, - // SY <-- - ) - } - } - } - initDropdownMenu() // SY <-- @@ -1038,22 +1001,6 @@ class ReaderActivity : BaseActivity() { showReadingModeToast(viewModel.getMangaReadingMode()) } - // SY --> - binding.readerNavVert.isVisible = !readerPreferences.forceHorizontalSeekbar().get() && - ( - ( - resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE && readerPreferences.landscapeVerticalSeekbar().get() - ) || - resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT - ) && - (viewModel.state.value.viewer is WebtoonViewer || viewModel.state.value.viewer is VerticalPagerViewer) - - val params = binding.readerNavVert.layoutParams as RelativeLayout.LayoutParams - if (readerPreferences.leftVerticalSeekbar().get() && binding.readerNavVert.isVisible) { - params.removeRule(RelativeLayout.ALIGN_PARENT_END) - binding.readerNavVert.layoutParams = params - } - // SY <-- supportActionBar?.title = manga.title loadingIndicator = ReaderProgressIndicator(this) diff --git a/app/src/main/res/layout/reader_activity.xml b/app/src/main/res/layout/reader_activity.xml index edeee713b..c6d2cef9b 100755 --- a/app/src/main/res/layout/reader_activity.xml +++ b/app/src/main/res/layout/reader_activity.xml @@ -181,53 +181,6 @@ - - - - - - - - - - - -