Handle reader cutout setting with Insets to support Android 15+ (mihonapp/mihon#2640)
(cherry picked from commit 0e0b6d92833f8e4f3aebdcc1f7c8c175084175d6) Fix extra padding appearing in reader after user interactions (mihonapp/mihon#2669) (cherry picked from commit aa300cb53ea3a02b63c3b3f3fca60d5e7533a8f1)
This commit is contained in:
parent
26b1331750
commit
4affedcf5a
5 changed files with 49 additions and 45 deletions
|
|
@ -146,7 +146,7 @@ object SettingsReaderScreen : SearchableSettings {
|
|||
title = stringResource(MR.strings.pref_fullscreen),
|
||||
),
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
preference = readerPreferences.cutoutShort(),
|
||||
preference = readerPreferences.drawUnderCutout(),
|
||||
title = stringResource(MR.strings.pref_cutout_short),
|
||||
enabled = LocalView.current.hasDisplayCutout() && fullscreen,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
package eu.kanade.presentation.reader.settings
|
||||
|
||||
import androidx.activity.compose.LocalActivity
|
||||
import androidx.compose.material3.FilterChip
|
||||
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
|
||||
|
|
@ -87,10 +87,10 @@ internal fun GeneralPage(screenModel: ReaderSettingsScreenModel) {
|
|||
)
|
||||
|
||||
val isFullscreen by screenModel.preferences.fullscreen().collectAsState()
|
||||
if (LocalView.current.hasDisplayCutout() && isFullscreen) {
|
||||
if (LocalActivity.current?.hasDisplayCutout() == true && isFullscreen) {
|
||||
CheckboxItem(
|
||||
label = stringResource(MR.strings.pref_cutout_short),
|
||||
pref = screenModel.preferences.cutoutShort(),
|
||||
pref = screenModel.preferences.drawUnderCutout(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ 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.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
|
|
@ -54,7 +53,6 @@ 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
|
||||
import androidx.lifecycle.Lifecycle
|
||||
|
|
@ -107,7 +105,6 @@ import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerViewer
|
|||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.VerticalPagerViewer
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer
|
||||
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
||||
import eu.kanade.tachiyomi.util.system.hasDisplayCutout
|
||||
import eu.kanade.tachiyomi.util.system.isNightMode
|
||||
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||
import eu.kanade.tachiyomi.util.system.toShareIntent
|
||||
|
|
@ -127,7 +124,6 @@ import kotlinx.coroutines.flow.filterNotNull
|
|||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.merge
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.sample
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -221,7 +217,7 @@ 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))
|
||||
enableEdgeToEdge()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
window.isNavigationBarContrastEnforced = false
|
||||
}
|
||||
|
|
@ -330,7 +326,6 @@ class ReaderActivity : BaseActivity() {
|
|||
// KMK <--
|
||||
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,
|
||||
|
|
@ -348,7 +343,7 @@ class ReaderActivity : BaseActivity() {
|
|||
totalPages = state.totalPages,
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.then(if (isFullscreen) Modifier else Modifier.navigationBarsPadding()),
|
||||
.navigationBarsPadding(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -968,7 +963,7 @@ class ReaderActivity : BaseActivity() {
|
|||
binding.viewerContainer.removeAllViews()
|
||||
}
|
||||
viewModel.onViewerLoaded(newViewer)
|
||||
updateViewerInset(readerPreferences.fullscreen().get())
|
||||
updateViewerInset(readerPreferences.fullscreen().get(), readerPreferences.drawUnderCutout().get())
|
||||
binding.viewerContainer.addView(newViewer.getView())
|
||||
|
||||
// SY -->
|
||||
|
|
@ -1294,22 +1289,29 @@ class ReaderActivity : BaseActivity() {
|
|||
/**
|
||||
* Updates viewer inset depending on fullscreen reader preferences.
|
||||
*/
|
||||
private fun updateViewerInset(fullscreen: Boolean) {
|
||||
val view = viewModel.state.value.viewer?.getView() ?: return
|
||||
private fun updateViewerInset(fullscreen: Boolean, drawUnderCutout: Boolean) {
|
||||
if (!::binding.isInitialized) return
|
||||
val view = binding.viewerContainer
|
||||
|
||||
view.applyInsetsPadding(ViewCompat.getRootWindowInsets(view), fullscreen)
|
||||
view.applyInsetsPadding(ViewCompat.getRootWindowInsets(view), fullscreen, drawUnderCutout)
|
||||
ViewCompat.setOnApplyWindowInsetsListener(view) { view, windowInsets ->
|
||||
view.applyInsetsPadding(windowInsets, fullscreen)
|
||||
view.applyInsetsPadding(windowInsets, fullscreen, drawUnderCutout)
|
||||
windowInsets
|
||||
}
|
||||
}
|
||||
|
||||
private fun View.applyInsetsPadding(windowInsets: WindowInsetsCompat?, fullscreen: Boolean) {
|
||||
val insets = if (!fullscreen) {
|
||||
windowInsets?.getInsets(WindowInsetsCompat.Type.systemBars()) ?: Insets.NONE
|
||||
} else {
|
||||
Insets.NONE
|
||||
private fun View.applyInsetsPadding(
|
||||
windowInsets: WindowInsetsCompat?,
|
||||
fullscreen: Boolean,
|
||||
drawUnderCutout: Boolean,
|
||||
) {
|
||||
val insets = when {
|
||||
!fullscreen -> windowInsets?.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
!drawUnderCutout -> windowInsets?.getInsets(WindowInsetsCompat.Type.displayCutout())
|
||||
else -> null
|
||||
}
|
||||
?: Insets.NONE
|
||||
|
||||
setPadding(insets.left, insets.top, insets.right, insets.bottom)
|
||||
}
|
||||
|
||||
|
|
@ -1365,10 +1367,6 @@ class ReaderActivity : BaseActivity() {
|
|||
.onEach { setDisplayProfile(it) }
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
readerPreferences.cutoutShort().changes()
|
||||
.onEach(::setCutoutShort)
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
readerPreferences.keepScreenOn().changes()
|
||||
.onEach(::setKeepScreenOn)
|
||||
.launchIn(lifecycleScope)
|
||||
|
|
@ -1377,14 +1375,21 @@ class ReaderActivity : BaseActivity() {
|
|||
.onEach(::setCustomBrightness)
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
merge(readerPreferences.grayscale().changes(), readerPreferences.invertedColors().changes())
|
||||
.onEach { setLayerPaint(readerPreferences.grayscale().get(), readerPreferences.invertedColors().get()) }
|
||||
combine(
|
||||
readerPreferences.grayscale().changes(),
|
||||
readerPreferences.invertedColors().changes(),
|
||||
) { grayscale, invertedColors -> grayscale to invertedColors }
|
||||
.onEach { (grayscale, invertedColors) ->
|
||||
setLayerPaint(grayscale, invertedColors)
|
||||
}
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
readerPreferences.fullscreen().changes()
|
||||
.onEach {
|
||||
WindowCompat.setDecorFitsSystemWindows(window, !it)
|
||||
updateViewerInset(it)
|
||||
combine(
|
||||
readerPreferences.fullscreen().changes(),
|
||||
readerPreferences.drawUnderCutout().changes(),
|
||||
) { fullscreen, drawUnderCutout -> fullscreen to drawUnderCutout }
|
||||
.onEach { (fullscreen, drawUnderCutout) ->
|
||||
updateViewerInset(fullscreen, drawUnderCutout)
|
||||
}
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
|
|
@ -1451,16 +1456,6 @@ class ReaderActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun setCutoutShort(enabled: Boolean) {
|
||||
if (!window.decorView.hasDisplayCutout()) return
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
window.attributes.layoutInDisplayCutoutMode = when (enabled) {
|
||||
true -> WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
||||
false -> WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the keep screen on mode according to [enabled].
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class ReaderPreferences(
|
|||
|
||||
fun fullscreen() = preferenceStore.getBoolean("fullscreen", true)
|
||||
|
||||
fun cutoutShort() = preferenceStore.getBoolean("cutout_short", true)
|
||||
fun drawUnderCutout() = preferenceStore.getBoolean("cutout_short", true)
|
||||
|
||||
fun keepScreenOn() = preferenceStore.getBoolean("pref_keep_screen_on_key", false)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package eu.kanade.tachiyomi.util.system
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
|
|
@ -57,11 +58,19 @@ fun Context.isNightMode(): Boolean {
|
|||
/**
|
||||
* Checks whether if the device has a display cutout (i.e. notch, camera cutout, etc.).
|
||||
*
|
||||
* Only relevant from Android 9 to Android 14.
|
||||
* Only works on Android 9+.
|
||||
*/
|
||||
fun Activity.hasDisplayCutout(): Boolean {
|
||||
return window.decorView.hasDisplayCutout()
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether if the device has a display cutout (i.e. notch, camera cutout, etc.).
|
||||
*
|
||||
* Only works on Android 9+.
|
||||
*/
|
||||
fun View.hasDisplayCutout(): Boolean {
|
||||
return Build.VERSION.SDK_INT in Build.VERSION_CODES.P..Build.VERSION_CODES.UPSIDE_DOWN_CAKE &&
|
||||
rootWindowInsets?.displayCutout != null
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && rootWindowInsets?.displayCutout != null
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in a new issue