Make reader edge-to-edge (#1908)

(cherry picked from commit 5f0c4606681cd59b38ae0855c7827e149fa5488c)

# Conflicts:
#	CHANGELOG.md
#	app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt
#	app/src/main/java/eu/kanade/presentation/reader/ReaderPageIndicator.kt
#	app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt
#	app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderBottomBar.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
This commit is contained in:
AntsyLich
2025-11-02 19:26:33 +05:45
committed by NGB-Was-Taken
parent c99ddbe10f
commit 8e6b5b8bee
12 changed files with 487 additions and 385 deletions
-1
View File
@@ -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)
@@ -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(),
@@ -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)
}
}
}
@@ -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<IntOffset>(200)
private val readerBarsSlideAnimationSpec = tween<IntOffset>(200)
private val readerBarsFadeAnimationSpec = tween<Float>(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)
)
}
}
@@ -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<String>,
// 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,
) {
@@ -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<AppBar.AppBarAction>().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(),
)
},
)
}
@@ -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(),
@@ -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<ReaderViewModel>()
private var assistUrl: String? = null
private val hasCutout by lazy { hasDisplayCutout() }
// SY -->
private val sourceManager = Injekt.get<SourceManager>()
// 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)
@@ -13,7 +13,6 @@ import uy.kohesive.injekt.api.get
class ReaderSettingsScreenModel(
readerState: StateFlow<ReaderViewModel.State>,
val hasDisplayCutout: Boolean,
val onChangeReadingMode: (ReadingMode) -> Unit,
val onChangeOrientation: (ReaderOrientation) -> Unit,
val preferences: ReaderPreferences = Injekt.get(),
@@ -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
}
/**
+1 -7
View File
@@ -13,12 +13,6 @@
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants" />
<androidx.compose.ui.platform.ComposeView
android:id="@+id/page_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal" />
</FrameLayout>
<eu.kanade.tachiyomi.ui.reader.ReaderNavigationOverlayView
@@ -30,7 +24,7 @@
android:visibility="gone" />
<androidx.compose.ui.platform.ComposeView
android:id="@+id/dialog_root"
android:id="@+id/compose_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent" />
-1
View File
@@ -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"