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 e4ac76681..750f8138d 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
@@ -64,6 +64,11 @@ object SettingsReaderScreen : SearchableSettings {
pref = readerPref.pageTransitions(),
title = stringResource(R.string.pref_page_transitions),
),
+ Preference.PreferenceItem.SwitchPreference(
+ pref = readerPref.flashOnPageChange(),
+ title = stringResource(R.string.pref_flash_page),
+ subtitle = stringResource(R.string.pref_flash_page_summ),
+ ),
getDisplayGroup(readerPreferences = readerPref),
getReadingGroup(readerPreferences = readerPref),
getPagedGroup(readerPreferences = readerPref),
diff --git a/app/src/main/java/eu/kanade/presentation/reader/DisplayRefreshHost.kt b/app/src/main/java/eu/kanade/presentation/reader/DisplayRefreshHost.kt
new file mode 100644
index 000000000..018dbb948
--- /dev/null
+++ b/app/src/main/java/eu/kanade/presentation/reader/DisplayRefreshHost.kt
@@ -0,0 +1,45 @@
+package eu.kanade.presentation.reader
+
+import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import kotlinx.coroutines.delay
+
+@Stable
+class DisplayRefreshHost {
+
+ internal var currentDisplayRefresh by mutableStateOf(false)
+
+ fun flash() {
+ currentDisplayRefresh = true
+ }
+}
+
+@Composable
+fun DisplayRefreshHost(
+ hostState: DisplayRefreshHost,
+ modifier: Modifier = Modifier,
+) {
+ val currentDisplayRefresh = hostState.currentDisplayRefresh
+ LaunchedEffect(currentDisplayRefresh) {
+ if (currentDisplayRefresh) {
+ delay(200)
+ hostState.currentDisplayRefresh = false
+ }
+ }
+
+ if (currentDisplayRefresh) {
+ Canvas(
+ modifier = modifier.fillMaxSize(),
+ ) {
+ drawRect(Color.White)
+ }
+ }
+}
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 8d165ec76..5fe65eb2f 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
@@ -68,4 +68,9 @@ internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) {
label = stringResource(R.string.pref_page_transitions),
pref = screenModel.preferences.pageTransitions(),
)
+
+ CheckboxItem(
+ label = stringResource(R.string.pref_flash_page),
+ pref = screenModel.preferences.flashOnPageChange(),
+ )
}
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 1b8784d1a..9580af393 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
@@ -43,6 +43,7 @@ import com.google.android.material.transition.platform.MaterialContainerTransfor
import dev.chrisbanes.insetter.applyInsetter
import eu.kanade.domain.base.BasePreferences
import eu.kanade.presentation.reader.BrightnessOverlay
+import eu.kanade.presentation.reader.DisplayRefreshHost
import eu.kanade.presentation.reader.OrientationModeSelectDialog
import eu.kanade.presentation.reader.PageIndicatorText
import eu.kanade.presentation.reader.ReaderPageActionsDialog
@@ -122,6 +123,7 @@ class ReaderActivity : BaseActivity() {
private var menuToggleToast: Toast? = null
private var readingModeToast: Toast? = null
+ private val displayRefreshHost = DisplayRefreshHost()
private val windowInsetsController by lazy { WindowInsetsControllerCompat(window, binding.root) }
@@ -197,6 +199,9 @@ class ReaderActivity : BaseActivity() {
ReaderViewModel.Event.ReloadViewerChapters -> {
viewModel.state.value.viewerChapters?.let(::setChapters)
}
+ ReaderViewModel.Event.PageChanged -> {
+ displayRefreshHost.flash()
+ }
is ReaderViewModel.Event.SetOrientation -> {
setOrientation(event.orientation)
}
@@ -323,6 +328,7 @@ class ReaderActivity : BaseActivity() {
val isHttpSource = viewModel.getSource() is HttpSource
val isFullscreen by readerPreferences.fullscreen().collectAsState()
+ val flashOnPageChange by readerPreferences.flashOnPageChange().collectAsState()
val cropBorderPaged by readerPreferences.cropBorders().collectAsState()
val cropBorderWebtoon by readerPreferences.cropBordersWebtoon().collectAsState()
@@ -375,6 +381,12 @@ class ReaderActivity : BaseActivity() {
value = state.brightnessOverlayValue,
)
+ if (flashOnPageChange) {
+ DisplayRefreshHost(
+ hostState = displayRefreshHost,
+ )
+ }
+
val onDismissRequest = viewModel::closeDialog
when (state.dialog) {
is ReaderViewModel.Dialog.Loading -> {
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt
index d1c91b62a..201c2eaa3 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt
@@ -429,6 +429,8 @@ class ReaderViewModel @JvmOverloads constructor(
if (inDownloadRange) {
downloadNextChapters()
}
+
+ eventChannel.trySend(Event.PageChanged)
}
private fun downloadNextChapters() {
@@ -917,6 +919,7 @@ class ReaderViewModel @JvmOverloads constructor(
sealed interface Event {
data object ReloadViewerChapters : Event
+ data object PageChanged : Event
data class SetOrientation(val orientation: Int) : Event
data class SetCoverResult(val result: SetAsCoverResult) : Event
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt
index faf75d0ba..ab38911f8 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt
@@ -13,6 +13,8 @@ class ReaderPreferences(
fun pageTransitions() = preferenceStore.getBoolean("pref_enable_transitions_key", true)
+ fun flashOnPageChange() = preferenceStore.getBoolean("pref_reader_flash", false)
+
fun doubleTapAnimSpeed() = preferenceStore.getInt("pref_double_tap_anim_speed", 500)
fun showPageNumber() = preferenceStore.getBoolean("pref_show_page_number_key", true)
diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml
index 76fa240b7..642f4ce7d 100644
--- a/i18n/src/main/res/values/strings.xml
+++ b/i18n/src/main/res/values/strings.xml
@@ -333,6 +333,8 @@
Double tap to zoom
Show content in cutout area
Animate page transitions
+ Flash white on page change
+ Reduces ghosting on e-ink displays
Double tap animation speed
Show page number
Show reading mode