diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 518ca72c6..05c1417c0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -256,7 +256,6 @@ dependencies { implementation(libs.directionalviewpager) { exclude(group = "androidx.viewpager", module = "viewpager") } - implementation(libs.insetter) implementation(libs.richeditor.compose) implementation(libs.aboutLibraries.compose) implementation(libs.bundles.voyager) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt index 2f7a91dcf..0dc2f5b27 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt @@ -1,6 +1,5 @@ package eu.kanade.presentation.more.settings.screen -import android.os.Build import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.getValue @@ -12,6 +11,7 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerConfig +import eu.kanade.tachiyomi.util.system.hasDisplayCutout import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.toImmutableMap @@ -137,9 +137,7 @@ object SettingsReaderScreen : SearchableSettings { Preference.PreferenceItem.SwitchPreference( preference = readerPreferences.cutoutShort(), title = stringResource(MR.strings.pref_cutout_short), - enabled = fullscreen && - Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && - LocalView.current.rootWindowInsets?.displayCutout != null, // has cutout + enabled = LocalView.current.hasDisplayCutout() && fullscreen, ), Preference.PreferenceItem.SwitchPreference( preference = readerPreferences.keepScreenOn(), diff --git a/app/src/main/java/eu/kanade/presentation/reader/PageIndicatorText.kt b/app/src/main/java/eu/kanade/presentation/reader/ReaderPageIndicator.kt similarity index 81% rename from app/src/main/java/eu/kanade/presentation/reader/PageIndicatorText.kt rename to app/src/main/java/eu/kanade/presentation/reader/ReaderPageIndicator.kt index d561d2d8c..4befd4828 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/PageIndicatorText.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/ReaderPageIndicator.kt @@ -6,6 +6,7 @@ import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.text.TextStyle @@ -15,13 +16,12 @@ import androidx.compose.ui.unit.sp import eu.kanade.presentation.theme.TachiyomiPreviewTheme @Composable -fun PageIndicatorText( - // SY --> - currentPage: String, - // SY <-- +fun ReaderPageIndicator( + currentPage: Int, totalPages: Int, + modifier: Modifier = Modifier, ) { - if (currentPage.isEmpty() || totalPages <= 0) return + if (currentPage <= 0 || totalPages <= 0) return val text = "$currentPage / $totalPages" @@ -38,6 +38,7 @@ fun PageIndicatorText( Box( contentAlignment = Alignment.Center, + modifier = modifier, ) { Text( text = text, @@ -52,10 +53,10 @@ fun PageIndicatorText( @PreviewLightDark @Composable -private fun PageIndicatorTextPreview() { +private fun ReaderPageIndicatorPreview() { TachiyomiPreviewTheme { Surface { - PageIndicatorText(currentPage = "10", totalPages = 69) + ReaderPageIndicator(currentPage = 10, totalPages = 69) } } } 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 index 3b8e50e08..715c62712 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt @@ -2,10 +2,13 @@ package eu.kanade.presentation.reader.appbars import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutHorizontally import androidx.compose.animation.slideOutVertically +import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement @@ -13,10 +16,13 @@ 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.WindowInsets import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.material3.MaterialTheme import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable @@ -36,7 +42,8 @@ import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer import kotlinx.collections.immutable.ImmutableSet import tachiyomi.presentation.core.components.material.padding -private val animationSpec = tween(200) +private val readerBarsSlideAnimationSpec = tween(200) +private val readerBarsFadeAnimationSpec = tween(150) // SY --> enum class NavBarType { @@ -65,7 +72,6 @@ fun BoxIgnoreLayoutDirection(modifier: Modifier, content: @Composable BoxScope.( @Composable fun ReaderAppBars( visible: Boolean, - fullscreen: Boolean, mangaTitle: String?, chapterTitle: String?, @@ -122,11 +128,7 @@ fun ReaderAppBars( .surfaceColorAtElevation(3.dp) .copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f) - val modifierWithInsetsPadding = if (fullscreen) { - Modifier.systemBarsPadding() - } else { - Modifier - } + val modifierWithInsetsPadding = Modifier.systemBarsPadding() // SY --> BoxIgnoreLayoutDirection( @@ -136,11 +138,11 @@ fun ReaderAppBars( visible = visible && navBarType == NavBarType.VerticalLeft, enter = slideInHorizontally( initialOffsetX = { -it }, - animationSpec = animationSpec, + animationSpec = readerBarsSlideAnimationSpec, ), exit = slideOutHorizontally( targetOffsetX = { -it }, - animationSpec = animationSpec, + animationSpec = readerBarsSlideAnimationSpec, ), modifier = modifierWithInsetsPadding .padding(bottom = 48.dp, top = 120.dp) @@ -164,11 +166,11 @@ fun ReaderAppBars( visible = visible && navBarType == NavBarType.VerticalRight, enter = slideInHorizontally( initialOffsetX = { it }, - animationSpec = animationSpec, + animationSpec = readerBarsSlideAnimationSpec, ), exit = slideOutHorizontally( targetOffsetX = { it }, - animationSpec = animationSpec, + animationSpec = readerBarsSlideAnimationSpec, ), modifier = modifierWithInsetsPadding .padding(bottom = 48.dp, top = 120.dp) @@ -196,16 +198,17 @@ fun ReaderAppBars( visible = visible, enter = slideInVertically( initialOffsetY = { -it }, - animationSpec = animationSpec, - ), + animationSpec = readerBarsSlideAnimationSpec, + ) + fadeIn(animationSpec = readerBarsFadeAnimationSpec), exit = slideOutVertically( targetOffsetY = { -it }, - animationSpec = animationSpec, - ), + animationSpec = readerBarsSlideAnimationSpec, + ) + fadeOut(animationSpec = readerBarsFadeAnimationSpec), ) { // SY --> Column(modifierWithInsetsPadding) { // SY <-- + // TODO: Use ReaderTopBar AppBar( modifier = /*SY --> */ Modifier /*SY <-- */ .clickable(onClick = onClickTopAppBar), @@ -265,12 +268,12 @@ fun ReaderAppBars( visible = visible, enter = slideInVertically( initialOffsetY = { it }, - animationSpec = animationSpec, - ), + animationSpec = readerBarsSlideAnimationSpec, + ) + fadeIn(animationSpec = readerBarsFadeAnimationSpec), exit = slideOutVertically( targetOffsetY = { it }, - animationSpec = animationSpec, - ), + animationSpec = readerBarsSlideAnimationSpec, + ) + fadeOut(animationSpec = readerBarsFadeAnimationSpec), ) { Column( modifier = modifierWithInsetsPadding, @@ -291,11 +294,10 @@ fun ReaderAppBars( ) } - BottomReaderBar( + ReaderBottomBar( // SY --> enabledButtons = enabledButtons, // SY <-- - backgroundColor = backgroundColor, readingMode = readingMode, onClickReadingMode = onClickReadingMode, orientation = orientation, @@ -313,6 +315,12 @@ fun ReaderAppBars( onClickShare = onShare, onClickPageLayout = onClickPageLayout, onClickShiftPage = onClickShiftPage, + // <-- SY + modifier = Modifier + .fillMaxWidth() + .background(backgroundColor) + .padding(horizontal = MaterialTheme.padding.small) + .windowInsetsPadding(WindowInsets.navigationBars) ) } } diff --git a/app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderBottomBar.kt similarity index 94% rename from app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt rename to app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderBottomBar.kt index 813dec0cb..3ef9df6d5 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderBottomBar.kt @@ -1,10 +1,7 @@ package eu.kanade.presentation.reader.appbars -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.FormatListNumbered import androidx.compose.material.icons.outlined.Public @@ -16,8 +13,8 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.res.painterResource -import androidx.compose.ui.unit.dp import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.reader.setting.ReaderBottomButton import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation @@ -28,11 +25,10 @@ import tachiyomi.i18n.sy.SYMR import tachiyomi.presentation.core.i18n.stringResource @Composable -fun BottomReaderBar( +fun ReaderBottomBar( // SY --> enabledButtons: ImmutableSet, // SY <-- - backgroundColor: Color, readingMode: ReadingMode, onClickReadingMode: () -> Unit, orientation: ReaderOrientation, @@ -51,12 +47,11 @@ fun BottomReaderBar( onClickPageLayout: () -> Unit, onClickShiftPage: () -> Unit, // SY <-- + modifier: Modifier = Modifier, ) { Row( - modifier = Modifier - .fillMaxWidth() - .background(backgroundColor) - .padding(8.dp), + modifier = modifier + .pointerInput(Unit) {}, horizontalArrangement = Arrangement.SpaceEvenly, verticalAlignment = Alignment.CenterVertically, ) { diff --git a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderTopBar.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderTopBar.kt new file mode 100644 index 000000000..9d783af7b --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderTopBar.kt @@ -0,0 +1,83 @@ +package eu.kanade.presentation.reader.appbars + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Bookmark +import androidx.compose.material.icons.outlined.BookmarkBorder +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import eu.kanade.presentation.components.AppBar +import eu.kanade.presentation.components.AppBarActions +import kotlinx.collections.immutable.persistentListOf +import tachiyomi.i18n.MR +import tachiyomi.presentation.core.i18n.stringResource + +@Composable +fun ReaderTopBar( + mangaTitle: String?, + chapterTitle: String?, + navigateUp: () -> Unit, + bookmarked: Boolean, + onToggleBookmarked: () -> Unit, + onOpenInWebView: (() -> Unit)?, + onOpenInBrowser: (() -> Unit)?, + onShare: (() -> Unit)?, + modifier: Modifier = Modifier, +) { + AppBar( + modifier = modifier, + backgroundColor = Color.Transparent, + title = mangaTitle, + subtitle = chapterTitle, + navigateUp = navigateUp, + actions = { + AppBarActions( + actions = persistentListOf().builder() + .apply { + add( + AppBar.Action( + title = stringResource( + if (bookmarked) { + MR.strings.action_remove_bookmark + } else { + MR.strings.action_bookmark + }, + ), + icon = if (bookmarked) { + Icons.Outlined.Bookmark + } else { + Icons.Outlined.BookmarkBorder + }, + onClick = onToggleBookmarked, + ), + ) + onOpenInWebView?.let { + add( + AppBar.OverflowAction( + title = stringResource(MR.strings.action_open_in_web_view), + onClick = it, + ), + ) + } + onOpenInBrowser?.let { + add( + AppBar.OverflowAction( + title = stringResource(MR.strings.action_open_in_browser), + onClick = it, + ), + ) + } + onShare?.let { + add( + AppBar.OverflowAction( + title = stringResource(MR.strings.action_share), + onClick = it, + ), + ) + } + } + .build(), + ) + }, + ) +} diff --git a/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt b/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt index 9b56f3036..c6f91c9b0 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt @@ -6,8 +6,10 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.ui.platform.LocalView import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel +import eu.kanade.tachiyomi.util.system.hasDisplayCutout import tachiyomi.i18n.MR import tachiyomi.i18n.sy.SYMR import tachiyomi.presentation.core.components.CheckboxItem @@ -85,7 +87,8 @@ internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) { pref = screenModel.preferences.fullscreen(), ) - if (screenModel.hasDisplayCutout && screenModel.preferences.fullscreen().get()) { + val isFullscreen by screenModel.preferences.fullscreen().collectAsState() + if (LocalView.current.hasDisplayCutout() && isFullscreen) { CheckboxItem( label = stringResource(MR.strings.pref_cutout_short), pref = screenModel.preferences.cutoutShort(), 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 8fff423b7..96ec1fc30 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 @@ -1,7 +1,6 @@ package eu.kanade.tachiyomi.ui.reader import android.annotation.SuppressLint -import android.app.Activity import android.app.assist.AssistContent import android.content.ClipData import android.content.ClipboardManager @@ -21,25 +20,33 @@ import android.view.View import android.view.View.LAYER_TYPE_HARDWARE import android.view.WindowManager import android.widget.Toast +import androidx.activity.SystemBarStyle +import androidx.activity.enableEdgeToEdge import androidx.activity.viewModels import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.material3.AlertDialog import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Text import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.unit.dp import androidx.core.content.getSystemService -import androidx.core.graphics.ColorUtils +import androidx.core.graphics.Insets import androidx.core.net.toUri import androidx.core.transition.doOnEnd +import androidx.core.view.ViewCompat import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsControllerCompat @@ -47,18 +54,16 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView -import com.google.android.material.elevation.SurfaceColors import com.google.android.material.transition.platform.MaterialContainerTransform import com.hippo.unifile.UniFile -import dev.chrisbanes.insetter.applyInsetter import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.manga.model.readingMode import eu.kanade.presentation.reader.ChapterListDialog import eu.kanade.presentation.reader.DisplayRefreshHost import eu.kanade.presentation.reader.OrientationSelectDialog -import eu.kanade.presentation.reader.PageIndicatorText import eu.kanade.presentation.reader.ReaderContentOverlay import eu.kanade.presentation.reader.ReaderPageActionsDialog +import eu.kanade.presentation.reader.ReaderPageIndicator import eu.kanade.presentation.reader.ReadingModeSelectDialog import eu.kanade.presentation.reader.appbars.NavBarType import eu.kanade.presentation.reader.appbars.ReaderAppBars @@ -135,7 +140,12 @@ class ReaderActivity : BaseActivity() { companion object { - fun newIntent(context: Context, mangaId: Long?, chapterId: Long?/* SY --> */, page: Int? = null/* SY <-- */): Intent { + fun newIntent( + context: Context, + mangaId: Long?, + chapterId: Long?, + /* SY --> */ page: Int? = null, /* SY <-- */ + ): Intent { return Intent(context, ReaderActivity::class.java).apply { putExtra("manga", mangaId) putExtra("chapter", chapterId) @@ -159,8 +169,6 @@ class ReaderActivity : BaseActivity() { val viewModel by viewModels() private var assistUrl: String? = null - private val hasCutout by lazy { hasDisplayCutout() } - // SY --> private val sourceManager = Injekt.get() // SY <-- @@ -174,7 +182,7 @@ class ReaderActivity : BaseActivity() { private var readingModeToast: Toast? = null private val displayRefreshHost = DisplayRefreshHost() - private val windowInsetsController by lazy { WindowInsetsControllerCompat(window, binding.root) } + private val windowInsetsController by lazy { WindowInsetsControllerCompat(window, window.decorView) } private var loadingIndicator: ReaderProgressIndicator? = null @@ -188,7 +196,7 @@ class ReaderActivity : BaseActivity() { registerSecureActivity(this) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { overrideActivityTransition( - Activity.OVERRIDE_TRANSITION_OPEN, + OVERRIDE_TRANSITION_OPEN, R.anim.shared_axis_x_push_enter, R.anim.shared_axis_x_push_exit, ) @@ -197,10 +205,17 @@ class ReaderActivity : BaseActivity() { overridePendingTransition(R.anim.shared_axis_x_push_enter, R.anim.shared_axis_x_push_exit) } + enableEdgeToEdge(navigationBarStyle = SystemBarStyle.auto(Color.TRANSPARENT, Color.TRANSPARENT)) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + window.isNavigationBarContrastEnforced = false + } + windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + super.onCreate(savedInstanceState) binding = ReaderActivityBinding.inflate(layoutInflater) setContentView(binding.root) + binding.setComposeOverlay() if (viewModel.needsInit()) { val manga = intent.extras?.getLong("manga", -1) ?: -1L @@ -226,7 +241,8 @@ class ReaderActivity : BaseActivity() { } config = ReaderConfig() - initializeMenu() + setMenuVisibility(viewModel.state.value.menuVisible) + enableExhAutoScroll() // Finish when incognito mode is disabled preferences.incognitoMode().changes() @@ -260,21 +276,27 @@ class ReaderActivity : BaseActivity() { ReaderViewModel.Event.ReloadViewerChapters -> { viewModel.state.value.viewerChapters?.let(::setChapters) } + ReaderViewModel.Event.PageChanged -> { displayRefreshHost.flash() } + is ReaderViewModel.Event.SetOrientation -> { setOrientation(event.orientation) } + is ReaderViewModel.Event.SavedImage -> { onSaveImageResult(event.result) } + is ReaderViewModel.Event.ShareImage -> { onShareImageResult(event.uri, event.page /* SY --> */, event.secondPage /* SY <-- */) } + is ReaderViewModel.Event.CopyImage -> { onCopyImageResult(event.uri) } + is ReaderViewModel.Event.SetCoverResult -> { onSetAsCoverResult(event.result) } @@ -283,6 +305,160 @@ class ReaderActivity : BaseActivity() { .launchIn(lifecycleScope) } + private fun ReaderActivityBinding.setComposeOverlay(): Unit = composeOverlay.setComposeContent { + val state by viewModel.state.collectAsState() + val showPageNumber by readerPreferences.showPageNumber().collectAsState() + val isFullscreen by readerPreferences.fullscreen().collectAsState() + val settingsScreenModel = remember { + ReaderSettingsScreenModel( + readerState = viewModel.state, + onChangeReadingMode = viewModel::setMangaReadingMode, + onChangeOrientation = viewModel::setMangaOrientationType, + ) + } + + Box(modifier = Modifier.fillMaxSize()) { + if (!state.menuVisible && showPageNumber) { + ReaderPageIndicator( + currentPage = state.currentPage, + totalPages = state.totalPages, + modifier = Modifier + .align(Alignment.BottomCenter) + .then(if (isFullscreen) Modifier else Modifier.navigationBarsPadding()), + ) + } + + ContentOverlay(state = state) + + AppBars(state = state) + } + + val onDismissRequest = viewModel::closeDialog + when (state.dialog) { + is ReaderViewModel.Dialog.Loading -> { + AlertDialog( + onDismissRequest = {}, + confirmButton = {}, + text = { + Row( + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + CircularProgressIndicator() + Text(stringResource(MR.strings.loading)) + } + }, + ) + } + + is ReaderViewModel.Dialog.Settings -> { + ReaderSettingsDialog( + onDismissRequest = onDismissRequest, + onShowMenus = { setMenuVisibility(true) }, + onHideMenus = { setMenuVisibility(false) }, + screenModel = settingsScreenModel, + ) + } + + is ReaderViewModel.Dialog.ReadingModeSelect -> { + ReadingModeSelectDialog( + onDismissRequest = onDismissRequest, + screenModel = settingsScreenModel, + onChange = { stringRes -> + menuToggleToast?.cancel() + if (!readerPreferences.showReadingMode().get()) { + menuToggleToast = toast(stringRes) + } + }, + ) + } + + is ReaderViewModel.Dialog.OrientationModeSelect -> { + OrientationSelectDialog( + onDismissRequest = onDismissRequest, + screenModel = settingsScreenModel, + onChange = { stringRes -> + menuToggleToast?.cancel() + menuToggleToast = toast(stringRes) + }, + ) + } + + is ReaderViewModel.Dialog.PageActions -> { + ReaderPageActionsDialog( + onDismissRequest = onDismissRequest, + onSetAsCover = viewModel::setAsCover, + onShare = viewModel::shareImage, + onSave = viewModel::saveImage, + onShareCombined = viewModel::shareImages, + onSaveCombined = viewModel::saveImages, + hasExtraPage = (state.dialog as? ReaderViewModel.Dialog.PageActions)?.extraPage != null, + ) + } + + is ReaderViewModel.Dialog.ChapterList -> { + var chapters by remember { + mutableStateOf(viewModel.getChapters().toImmutableList()) + } + ChapterListDialog( + onDismissRequest = onDismissRequest, + screenModel = settingsScreenModel, + chapters = chapters, + onClickChapter = { + viewModel.loadNewChapterFromDialog(it) + onDismissRequest() + }, + onBookmark = { chapter -> + viewModel.toggleBookmark(chapter.id, !chapter.bookmark) + chapters = chapters.map { + if (it.chapter.id == chapter.id) { + it.copy(chapter = chapter.copy(bookmark = !chapter.bookmark)) + } else { + it + } + }.toImmutableList() + }, + state.dateRelativeTime, + ) + } + // SY --> + ReaderViewModel.Dialog.AutoScrollHelp -> AlertDialog( + onDismissRequest = onDismissRequest, + confirmButton = { + TextButton(onClick = onDismissRequest) { + Text(text = stringResource(MR.strings.action_ok)) + } + }, + title = { Text(text = stringResource(SYMR.strings.eh_autoscroll_help)) }, + text = { Text(text = stringResource(SYMR.strings.eh_autoscroll_help_message)) }, + ) + + ReaderViewModel.Dialog.BoostPageHelp -> AlertDialog( + onDismissRequest = onDismissRequest, + confirmButton = { + TextButton(onClick = onDismissRequest) { + Text(text = stringResource(MR.strings.action_ok)) + } + }, + title = { Text(text = stringResource(SYMR.strings.eh_boost_page_help)) }, + text = { Text(text = stringResource(SYMR.strings.eh_boost_page_help_message)) }, + ) + + ReaderViewModel.Dialog.RetryAllHelp -> AlertDialog( + onDismissRequest = onDismissRequest, + confirmButton = { + TextButton(onClick = onDismissRequest) { + Text(text = stringResource(MR.strings.action_ok)) + } + }, + title = { Text(text = stringResource(SYMR.strings.eh_retry_all_help)) }, + text = { Text(text = stringResource(SYMR.strings.eh_retry_all_help_message)) }, + ) + // SY <-- + null -> {} + } + } + /** * Called when the activity is destroyed. Cleans up the viewer, configuration and any view. */ @@ -334,7 +510,7 @@ class ReaderActivity : BaseActivity() { super.finish() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { overrideActivityTransition( - Activity.OVERRIDE_TRANSITION_CLOSE, + OVERRIDE_TRANSITION_CLOSE, R.anim.shared_axis_x_pop_enter, R.anim.shared_axis_x_pop_exit, ) @@ -372,308 +548,147 @@ class ReaderActivity : BaseActivity() { return handled || super.dispatchGenericMotionEvent(event) } - /** - * Initializes the reader menu. It sets up click listeners and the initial visibility. - */ - private fun initializeMenu() { - binding.pageNumber.setComposeContent { - val state by viewModel.state.collectAsState() - val showPageNumber by viewModel.readerPreferences.showPageNumber().collectAsState() + @Composable + private fun ContentOverlay(state: ReaderViewModel.State) { + val flashOnPageChange by readerPreferences.flashOnPageChange().collectAsState() - if (!state.menuVisible && showPageNumber) { - PageIndicatorText( - // SY --> - currentPage = state.currentPageText, - // SY <-- - totalPages = state.totalPages, - ) - } + val colorOverlayEnabled by readerPreferences.colorFilter().collectAsState() + val colorOverlay by readerPreferences.colorFilterValue().collectAsState() + val colorOverlayMode by readerPreferences.colorFilterMode().collectAsState() + val colorOverlayBlendMode = remember(colorOverlayMode) { + ReaderPreferences.ColorFilterMode.getOrNull(colorOverlayMode)?.second } - binding.dialogRoot.setComposeContent { - val state by viewModel.state.collectAsState() - val settingsScreenModel = remember { - ReaderSettingsScreenModel( - readerState = viewModel.state, - hasDisplayCutout = hasCutout, - onChangeReadingMode = viewModel::setMangaReadingMode, - onChangeOrientation = viewModel::setMangaOrientationType, - ) - } - - if (!ifSourcesLoaded()) { - return@setComposeContent - } - - val isHttpSource = viewModel.getSource() is HttpSource - val isFullscreen by readerPreferences.fullscreen().collectAsState() - val flashOnPageChange by readerPreferences.flashOnPageChange().collectAsState() - - val colorOverlayEnabled by readerPreferences.colorFilter().collectAsState() - val colorOverlay by readerPreferences.colorFilterValue().collectAsState() - val colorOverlayMode by readerPreferences.colorFilterMode().collectAsState() - val colorOverlayBlendMode = remember(colorOverlayMode) { - ReaderPreferences.ColorFilterMode.getOrNull(colorOverlayMode)?.second - } - - val cropBorderPaged by readerPreferences.cropBorders().collectAsState() - val cropBorderWebtoon by readerPreferences.cropBordersWebtoon().collectAsState() - // SY --> - val readingMode = viewModel.getMangaReadingMode() - val isPagerType = ReadingMode.isPagerType(readingMode) - val isWebtoon = ReadingMode.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().changes().map { it.toImmutableSet() } - .collectAsState(persistentSetOf()) - 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 <-- - - ReaderContentOverlay( - brightness = state.brightnessOverlayValue, - color = colorOverlay.takeIf { colorOverlayEnabled }, - colorBlendMode = colorOverlayBlendMode, - ) - - ReaderAppBars( - visible = state.menuVisible, - fullscreen = isFullscreen, - - mangaTitle = state.manga?.title, - chapterTitle = state.currentChapter?.chapter?.name, - navigateUp = onBackPressedDispatcher::onBackPressed, - onClickTopAppBar = ::openMangaScreen, - // bookmarked = state.bookmarked, - // onToggleBookmarked = viewModel::toggleChapterBookmark, - onOpenInWebView = ::openChapterInWebView.takeIf { isHttpSource }, - onOpenInBrowser = ::openChapterInBrowser.takeIf { isHttpSource }, - onShare = ::shareChapter.takeIf { isHttpSource }, - - viewer = state.viewer, - onNextChapter = ::loadNextChapter, - enabledNext = state.viewerChapters?.nextChapter != null, - onPreviousChapter = ::loadPreviousChapter, - enabledPrevious = state.viewerChapters?.prevChapter != null, - currentPage = state.currentPage, - totalPages = state.totalPages, - onPageIndexChange = { - isScrollingThroughPages = true - moveToPageIndex(it) - }, - - readingMode = ReadingMode.fromPreference( - viewModel.getMangaReadingMode(resolveDefault = false), - ), - onClickReadingMode = viewModel::openReadingModeSelectDialog, - orientation = ReaderOrientation.fromPreference( - viewModel.getMangaOrientation(resolveDefault = false), - ), - onClickOrientation = viewModel::openOrientationModeSelectDialog, - cropEnabled = cropEnabled, - onClickCropBorder = { - val enabled = viewModel.toggleCropBorders() - menuToggleToast?.cancel() - menuToggleToast = toast(if (enabled) MR.strings.on else MR.strings.off) - }, - onClickSettings = viewModel::openSettingsDialog, - // SY --> - isExhToolsVisible = state.ehUtilsVisible, - onSetExhUtilsVisibility = viewModel::showEhUtils, - isAutoScroll = state.autoScroll, - isAutoScrollEnabled = state.isAutoScrollEnabled, - onToggleAutoscroll = viewModel::toggleAutoScroll, - autoScrollFrequency = state.ehAutoscrollFreq, - onSetAutoScrollFrequency = viewModel::setAutoScrollFrequency, - onClickAutoScrollHelp = viewModel::openAutoScrollHelpDialog, - onClickRetryAll = ::exhRetryAll, - onClickRetryAllHelp = viewModel::openRetryAllHelp, - onClickBoostPage = ::exhBoostPage, - onClickBoostPageHelp = viewModel::openBoostPageHelp, - currentPageText = state.currentPageText, - navBarType = navBarType, - enabledButtons = readerBottomButtons, - currentReadingMode = ReadingMode.fromPreference( - viewModel.getMangaReadingMode(resolveDefault = true), - ), - dualPageSplitEnabled = dualPageSplitPaged, - doublePages = state.doublePages, - onClickChapterList = viewModel::openChapterListDialog, - 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 <-- - ) - - if (flashOnPageChange) { - DisplayRefreshHost( - hostState = displayRefreshHost, - ) - } - - val onDismissRequest = viewModel::closeDialog - when (state.dialog) { - is ReaderViewModel.Dialog.Loading -> { - AlertDialog( - onDismissRequest = {}, - confirmButton = {}, - text = { - Row( - horizontalArrangement = Arrangement.spacedBy(16.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - CircularProgressIndicator() - Text(stringResource(MR.strings.loading)) - } - }, - ) - } - is ReaderViewModel.Dialog.Settings -> { - ReaderSettingsDialog( - onDismissRequest = onDismissRequest, - onShowMenus = { setMenuVisibility(true) }, - onHideMenus = { setMenuVisibility(false) }, - screenModel = settingsScreenModel, - ) - } - is ReaderViewModel.Dialog.ReadingModeSelect -> { - ReadingModeSelectDialog( - onDismissRequest = onDismissRequest, - screenModel = settingsScreenModel, - onChange = { stringRes -> - menuToggleToast?.cancel() - if (!readerPreferences.showReadingMode().get()) { - menuToggleToast = toast(stringRes) - } - }, - ) - } - is ReaderViewModel.Dialog.OrientationModeSelect -> { - OrientationSelectDialog( - onDismissRequest = onDismissRequest, - screenModel = settingsScreenModel, - onChange = { stringRes -> - menuToggleToast?.cancel() - menuToggleToast = toast(stringRes) - }, - ) - } - is ReaderViewModel.Dialog.PageActions -> { - ReaderPageActionsDialog( - onDismissRequest = onDismissRequest, - onSetAsCover = viewModel::setAsCover, - onShare = viewModel::shareImage, - onSave = viewModel::saveImage, - onShareCombined = viewModel::shareImages, - onSaveCombined = viewModel::saveImages, - hasExtraPage = (state.dialog as? ReaderViewModel.Dialog.PageActions)?.extraPage != null, - ) - } - is ReaderViewModel.Dialog.ChapterList -> { - var chapters by remember { - mutableStateOf(viewModel.getChapters().toImmutableList()) - } - ChapterListDialog( - onDismissRequest = onDismissRequest, - screenModel = settingsScreenModel, - chapters = chapters, - onClickChapter = { - viewModel.loadNewChapterFromDialog(it) - onDismissRequest() - }, - onBookmark = { chapter -> - viewModel.toggleBookmark(chapter.id, !chapter.bookmark) - chapters = chapters.map { - if (it.chapter.id == chapter.id) { - it.copy(chapter = chapter.copy(bookmark = !chapter.bookmark)) - } else { - it - } - }.toImmutableList() - }, - state.dateRelativeTime, - ) - } - // SY --> - ReaderViewModel.Dialog.AutoScrollHelp -> AlertDialog( - onDismissRequest = onDismissRequest, - confirmButton = { - TextButton(onClick = onDismissRequest) { - Text(text = stringResource(MR.strings.action_ok)) - } - }, - title = { Text(text = stringResource(SYMR.strings.eh_autoscroll_help)) }, - text = { Text(text = stringResource(SYMR.strings.eh_autoscroll_help_message)) }, - ) - ReaderViewModel.Dialog.BoostPageHelp -> AlertDialog( - onDismissRequest = onDismissRequest, - confirmButton = { - TextButton(onClick = onDismissRequest) { - Text(text = stringResource(MR.strings.action_ok)) - } - }, - title = { Text(text = stringResource(SYMR.strings.eh_boost_page_help)) }, - text = { Text(text = stringResource(SYMR.strings.eh_boost_page_help_message)) }, - ) - ReaderViewModel.Dialog.RetryAllHelp -> AlertDialog( - onDismissRequest = onDismissRequest, - confirmButton = { - TextButton(onClick = onDismissRequest) { - Text(text = stringResource(MR.strings.action_ok)) - } - }, - title = { Text(text = stringResource(SYMR.strings.eh_retry_all_help)) }, - text = { Text(text = stringResource(SYMR.strings.eh_retry_all_help_message)) }, - ) - // SY <-- - null -> {} - } - } - - val toolbarColor = ColorUtils.setAlphaComponent( - SurfaceColors.SURFACE_2.getColor(this), - if (isNightMode()) 230 else 242, // 90% dark 95% light + ReaderContentOverlay( + brightness = state.brightnessOverlayValue, + color = colorOverlay.takeIf { colorOverlayEnabled }, + colorBlendMode = colorOverlayBlendMode, ) - @Suppress("DEPRECATION") - window.statusBarColor = toolbarColor - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { - @Suppress("DEPRECATION") - window.navigationBarColor = toolbarColor + + if (flashOnPageChange) { + DisplayRefreshHost(hostState = displayRefreshHost) + } + } + + @Composable + fun AppBars(state: ReaderViewModel.State) { + if (!ifSourcesLoaded()) { + return } - // Set initial visibility - setMenuVisibility(viewModel.state.value.menuVisible) + val isHttpSource = viewModel.getSource() is HttpSource - enableExhAutoScroll() + val cropBorderPaged by readerPreferences.cropBorders().collectAsState() + val cropBorderWebtoon by readerPreferences.cropBordersWebtoon().collectAsState() + val isPagerType = ReadingMode.isPagerType(viewModel.getMangaReadingMode()) + + // SY --> + val readingMode = viewModel.getMangaReadingMode() + val isWebtoon = ReadingMode.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().changes().map { it.toImmutableSet() } + .collectAsState(persistentSetOf()) + 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, + + mangaTitle = state.manga?.title, + chapterTitle = state.currentChapter?.chapter?.name, + navigateUp = onBackPressedDispatcher::onBackPressed, + onClickTopAppBar = ::openMangaScreen, + // bookmarked = state.bookmarked, + // onToggleBookmarked = viewModel::toggleChapterBookmark, + onOpenInWebView = ::openChapterInWebView.takeIf { isHttpSource }, + onOpenInBrowser = ::openChapterInBrowser.takeIf { isHttpSource }, + onShare = ::shareChapter.takeIf { isHttpSource }, + + viewer = state.viewer, + onNextChapter = ::loadNextChapter, + enabledNext = state.viewerChapters?.nextChapter != null, + onPreviousChapter = ::loadPreviousChapter, + enabledPrevious = state.viewerChapters?.prevChapter != null, + currentPage = state.currentPage, + totalPages = state.totalPages, + onPageIndexChange = { + isScrollingThroughPages = true + moveToPageIndex(it) + }, + + readingMode = ReadingMode.fromPreference( + viewModel.getMangaReadingMode(resolveDefault = false), + ), + onClickReadingMode = viewModel::openReadingModeSelectDialog, + orientation = ReaderOrientation.fromPreference( + viewModel.getMangaOrientation(resolveDefault = false), + ), + onClickOrientation = viewModel::openOrientationModeSelectDialog, + cropEnabled = cropEnabled, + onClickCropBorder = { + val enabled = viewModel.toggleCropBorders() + menuToggleToast?.cancel() + menuToggleToast = toast(if (enabled) MR.strings.on else MR.strings.off) + }, + onClickSettings = viewModel::openSettingsDialog, + // SY --> + isExhToolsVisible = state.ehUtilsVisible, + onSetExhUtilsVisibility = viewModel::showEhUtils, + isAutoScroll = state.autoScroll, + isAutoScrollEnabled = state.isAutoScrollEnabled, + onToggleAutoscroll = viewModel::toggleAutoScroll, + autoScrollFrequency = state.ehAutoscrollFreq, + onSetAutoScrollFrequency = viewModel::setAutoScrollFrequency, + onClickAutoScrollHelp = viewModel::openAutoScrollHelpDialog, + onClickRetryAll = ::exhRetryAll, + onClickRetryAllHelp = viewModel::openRetryAllHelp, + onClickBoostPage = ::exhBoostPage, + onClickBoostPageHelp = viewModel::openBoostPageHelp, + currentPageText = state.currentPageText, + navBarType = navBarType, + enabledButtons = readerBottomButtons, + currentReadingMode = ReadingMode.fromPreference( + viewModel.getMangaReadingMode(resolveDefault = true), + ), + dualPageSplitEnabled = dualPageSplitPaged, + doublePages = state.doublePages, + onClickChapterList = viewModel::openChapterListDialog, + 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 <-- + ) } private fun enableExhAutoScroll() { @@ -777,7 +792,8 @@ class ReaderActivity : BaseActivity() { private fun exhCurrentpage(): ReaderPage? { val viewer = viewModel.state.value.viewer - val currentPage = (((viewer as? PagerViewer)?.currentPage ?: (viewer as? WebtoonViewer)?.currentPage) as? ReaderPage)?.index + val currentPage = + (((viewer as? PagerViewer)?.currentPage ?: (viewer as? WebtoonViewer)?.currentPage) as? ReaderPage)?.index return currentPage?.let { viewModel.state.value.viewerChapters?.currChapter?.pages?.getOrNull(it) } } @@ -820,7 +836,7 @@ class ReaderActivity : BaseActivity() { } } } - // EXH <-- +// EXH <-- /** * Sets the visibility of the menu according to [visible]. @@ -829,13 +845,8 @@ class ReaderActivity : BaseActivity() { viewModel.showMenus(visible) if (visible) { windowInsetsController.show(WindowInsetsCompat.Type.systemBars()) - window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) - } else { - if (readerPreferences.fullscreen().get()) { - windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()) - windowInsetsController.systemBarsBehavior = - WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE - } + } else if (readerPreferences.fullscreen().get()) { + windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()) } } @@ -933,7 +944,7 @@ class ReaderActivity : BaseActivity() { try { readingModeToast?.cancel() readingModeToast = toast(ReadingMode.fromPreference(mode).stringRes) - } catch (e: ArrayIndexOutOfBoundsException) { + } catch (_: ArrayIndexOutOfBoundsException) { logcat(LogPriority.ERROR) { "Unknown reading mode: $mode" } } } @@ -1148,6 +1159,7 @@ class ReaderActivity : BaseActivity() { is ReaderViewModel.SaveImageResult.Success -> { toast(MR.strings.picture_saved) } + is ReaderViewModel.SaveImageResult.Error -> { logcat(LogPriority.ERROR, result.error) } @@ -1182,15 +1194,24 @@ class ReaderActivity : BaseActivity() { * Updates viewer inset depending on fullscreen reader preferences. */ private fun updateViewerInset(fullscreen: Boolean) { - viewModel.state.value.viewer?.getView()?.applyInsetter { - if (!fullscreen) { - type(navigationBars = true, statusBars = true) { - padding() - } - } + val view = viewModel.state.value.viewer?.getView() ?: return + + view.applyInsetsPadding(ViewCompat.getRootWindowInsets(view), fullscreen) + ViewCompat.setOnApplyWindowInsetsListener(view) { view, windowInsets -> + view.applyInsetsPadding(windowInsets, fullscreen) + windowInsets } } + private fun View.applyInsetsPadding(windowInsets: WindowInsetsCompat?, fullscreen: Boolean) { + val insets = if (!fullscreen) { + windowInsets?.getInsets(WindowInsetsCompat.Type.systemBars()) ?: Insets.NONE + } else { + Insets.NONE + } + setPadding(insets.left, insets.top, insets.right, insets.bottom) + } + /** * Class that handles the user preferences of the reader. */ @@ -1290,6 +1311,7 @@ class ReaderActivity : BaseActivity() { PagerConfig.PageLayout.AUTOMATIC -> resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE + else -> false }, true, @@ -1330,15 +1352,13 @@ class ReaderActivity : BaseActivity() { } private fun setCutoutShort(enabled: Boolean) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) return + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P ) return + if (!window.decorView.hasDisplayCutout()) return window.attributes.layoutInDisplayCutoutMode = when (enabled) { true -> WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES false -> WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER } - - // Trigger relayout - setMenuVisibility(viewModel.state.value.menuVisible) } /** @@ -1378,15 +1398,18 @@ class ReaderActivity : BaseActivity() { value > 0 -> { value / 100f } + value < 0 -> { 0.01f } + else -> WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE } window.attributes = window.attributes.apply { screenBrightness = readerBrightness } viewModel.setBrightnessOverlayValue(value) } + private fun setLayerPaint(grayscale: Boolean, invertedColors: Boolean) { val paint = if (grayscale || invertedColors) getCombinedPaint(grayscale, invertedColors) else null binding.viewerContainer.setLayerType(LAYER_TYPE_HARDWARE, paint) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsScreenModel.kt index 5f107c388..790984bea 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsScreenModel.kt @@ -13,7 +13,6 @@ import uy.kohesive.injekt.api.get class ReaderSettingsScreenModel( readerState: StateFlow, - val hasDisplayCutout: Boolean, val onChangeReadingMode: (ReadingMode) -> Unit, val onChangeOrientation: (ReaderOrientation) -> Unit, val preferences: ReaderPreferences = Injekt.get(), diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/DisplayExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/DisplayExtensions.kt index f051ccbc8..fa5d6c2d8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/DisplayExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/DisplayExtensions.kt @@ -1,9 +1,9 @@ package eu.kanade.tachiyomi.util.system -import android.app.Activity import android.content.Context import android.content.res.Configuration import android.os.Build +import android.view.View import eu.kanade.domain.ui.UiPreferences import eu.kanade.domain.ui.model.TabletUiMode import uy.kohesive.injekt.Injekt @@ -57,11 +57,11 @@ fun Context.isNightMode(): Boolean { /** * Checks whether if the device has a display cutout (i.e. notch, camera cutout, etc.). * - * Only works in Android 9+. + * Only relevant from Android 9 to Android 14. */ -fun Activity.hasDisplayCutout(): Boolean { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && - window.decorView.rootWindowInsets?.displayCutout != null +fun View.hasDisplayCutout(): Boolean { + return Build.VERSION.SDK_INT in Build.VERSION_CODES.P..Build.VERSION_CODES.UPSIDE_DOWN_CAKE && + rootWindowInsets?.displayCutout != null } /** diff --git a/app/src/main/res/layout/reader_activity.xml b/app/src/main/res/layout/reader_activity.xml index ed289767a..e759ba454 100755 --- a/app/src/main/res/layout/reader_activity.xml +++ b/app/src/main/res/layout/reader_activity.xml @@ -13,12 +13,6 @@ android:layout_height="match_parent" android:descendantFocusability="blocksDescendants" /> - - diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 82cc80d46..9fb1b0ff4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -60,7 +60,6 @@ material = "com.google.android.material:material:1.12.0" flexible-adapter-core = "com.github.arkon.FlexibleAdapter:flexible-adapter:c8013533" photoview = "com.github.chrisbanes:PhotoView:2.3.0" directionalviewpager = "com.github.tachiyomiorg:DirectionalViewPager:1.0.0" -insetter = "dev.chrisbanes.insetter:insetter:0.6.1" compose-materialmotion = "io.github.fornewid:material-motion-compose-core:2.0.1" compose-webview = "io.github.kevinnzou:compose-webview:0.33.6" compose-grid = "io.woong.compose.grid:grid:1.2.2"