diff --git a/app/src/main/java/eu/kanade/presentation/reader/BrightnessOverlay.kt b/app/src/main/java/eu/kanade/presentation/reader/BrightnessOverlay.kt
deleted file mode 100644
index b945906a4..000000000
--- a/app/src/main/java/eu/kanade/presentation/reader/BrightnessOverlay.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-package eu.kanade.presentation.reader
-
-import androidx.annotation.IntRange
-import androidx.compose.foundation.Canvas
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.graphicsLayer
-import kotlin.math.abs
-
-@Composable
-fun BrightnessOverlay(
- @IntRange(from = -100, to = 100) value: Int,
-) {
- if (value >= 0) return
-
- Canvas(
- modifier = Modifier
- .fillMaxSize()
- .graphicsLayer {
- alpha = abs(value) / 100f
- },
- ) {
- drawRect(Color.Black)
- }
-}
diff --git a/app/src/main/java/eu/kanade/presentation/reader/ReaderContentOverlay.kt b/app/src/main/java/eu/kanade/presentation/reader/ReaderContentOverlay.kt
new file mode 100644
index 000000000..a1ef26222
--- /dev/null
+++ b/app/src/main/java/eu/kanade/presentation/reader/ReaderContentOverlay.kt
@@ -0,0 +1,43 @@
+package eu.kanade.presentation.reader
+
+import androidx.annotation.ColorInt
+import androidx.annotation.IntRange
+import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.BlendMode
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.graphicsLayer
+import kotlin.math.abs
+
+@Composable
+fun ReaderContentOverlay(
+ @IntRange(from = -100, to = 100) brightness: Int,
+ @ColorInt color: Int?,
+ colorBlendMode: BlendMode? = BlendMode.SrcOver,
+) {
+ if (brightness < 0) {
+ Canvas(
+ modifier = Modifier
+ .fillMaxSize()
+ .graphicsLayer {
+ alpha = abs(brightness) / 100f
+ },
+ ) {
+ drawRect(Color.Black)
+ }
+ }
+
+ if (color != null) {
+ Canvas(
+ modifier = Modifier
+ .fillMaxSize(),
+ ) {
+ drawRect(
+ color = Color(color),
+ blendMode = colorBlendMode,
+ )
+ }
+ }
+}
diff --git a/app/src/main/java/eu/kanade/presentation/reader/settings/ColorFilterPage.kt b/app/src/main/java/eu/kanade/presentation/reader/settings/ColorFilterPage.kt
index 1e7324956..1c5a9c6fb 100644
--- a/app/src/main/java/eu/kanade/presentation/reader/settings/ColorFilterPage.kt
+++ b/app/src/main/java/eu/kanade/presentation/reader/settings/ColorFilterPage.kt
@@ -1,6 +1,5 @@
package eu.kanade.presentation.reader.settings
-import android.os.Build
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.material3.FilterChip
import androidx.compose.material3.Text
@@ -10,6 +9,7 @@ import androidx.core.graphics.alpha
import androidx.core.graphics.blue
import androidx.core.graphics.green
import androidx.core.graphics.red
+import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences.Companion.ColorFilterMode
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
import tachiyomi.core.preference.getAndSet
import tachiyomi.i18n.MR
@@ -21,25 +21,6 @@ import tachiyomi.presentation.core.util.collectAsState
@Composable
internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel) {
- val colorFilterModes = buildList {
- addAll(
- listOf(
- MR.strings.label_default,
- MR.strings.filter_mode_multiply,
- MR.strings.filter_mode_screen,
- ),
- )
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- addAll(
- listOf(
- MR.strings.filter_mode_overlay,
- MR.strings.filter_mode_lighten,
- MR.strings.filter_mode_darken,
- ),
- )
- }
- }.map { stringResource(it) }
-
val customBrightness by screenModel.preferences.customBrightness().collectAsState()
CheckboxItem(
label = stringResource(MR.strings.pref_custom_brightness),
@@ -118,11 +99,11 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
val colorFilterMode by screenModel.preferences.colorFilterMode().collectAsState()
SettingsChipRow(MR.strings.pref_color_filter_mode) {
- colorFilterModes.mapIndexed { index, it ->
+ ColorFilterMode.mapIndexed { index, it ->
FilterChip(
selected = colorFilterMode == index,
onClick = { screenModel.preferences.colorFilterMode().set(index) },
- label = { Text(it) },
+ label = { Text(stringResource(it.first)) },
)
}
}
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 c70ac7998..701c804f3 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
@@ -34,17 +34,16 @@ import androidx.core.transition.doOnEnd
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
-import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.google.android.material.elevation.SurfaceColors
import com.google.android.material.transition.platform.MaterialContainerTransform
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.OrientationSelectDialog
import eu.kanade.presentation.reader.PageIndicatorText
+import eu.kanade.presentation.reader.ReaderContentOverlay
import eu.kanade.presentation.reader.ReaderPageActionsDialog
import eu.kanade.presentation.reader.ReadingModeSelectDialog
import eu.kanade.presentation.reader.appbars.ReaderAppBars
@@ -337,11 +336,24 @@ class ReaderActivity : BaseActivity() {
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()
val isPagerType = ReadingMode.isPagerType(viewModel.getMangaReadingMode())
val cropEnabled = if (isPagerType) cropBorderPaged else cropBorderWebtoon
+ ReaderContentOverlay(
+ brightness = state.brightnessOverlayValue,
+ color = colorOverlay.takeIf { colorOverlayEnabled },
+ colorBlendMode = colorOverlayBlendMode,
+ )
+
ReaderAppBars(
visible = state.menuVisible,
fullscreen = isFullscreen,
@@ -385,10 +397,6 @@ class ReaderActivity : BaseActivity() {
onClickSettings = viewModel::openSettingsDialog,
)
- BrightnessOverlay(
- value = state.brightnessOverlayValue,
- )
-
if (flashOnPageChange) {
DisplayRefreshHost(
hostState = displayRefreshHost,
@@ -812,24 +820,8 @@ class ReaderActivity : BaseActivity() {
.onEach(::setCustomBrightness)
.launchIn(lifecycleScope)
- readerPreferences.colorFilter().changes()
- .onEach(::setColorFilter)
- .launchIn(lifecycleScope)
-
- readerPreferences.colorFilterMode().changes()
- .onEach { setColorFilter(readerPreferences.colorFilter().get()) }
- .launchIn(lifecycleScope)
-
- merge(
- readerPreferences.grayscale().changes(),
- readerPreferences.invertedColors().changes(),
- )
- .onEach {
- setLayerPaint(
- readerPreferences.grayscale().get(),
- readerPreferences.invertedColors().get(),
- )
- }
+ merge(readerPreferences.grayscale().changes(), readerPreferences.invertedColors().changes())
+ .onEach { setLayerPaint(readerPreferences.grayscale().get(), readerPreferences.invertedColors().get()) }
.launchIn(lifecycleScope)
readerPreferences.fullscreen().changes()
@@ -899,20 +891,6 @@ class ReaderActivity : BaseActivity() {
}
}
- /**
- * Sets the color filter overlay according to [enabled].
- */
- private fun setColorFilter(enabled: Boolean) {
- if (enabled) {
- readerPreferences.colorFilterValue().changes()
- .sample(100)
- .onEach(::setColorFilterValue)
- .launchIn(lifecycleScope)
- } else {
- binding.colorOverlay.isVisible = false
- }
- }
-
/**
* Sets the brightness of the screen. Range is [-75, 100].
* From -75 to -1 a semi-transparent black view is overlaid with the minimum brightness.
@@ -934,15 +912,6 @@ class ReaderActivity : BaseActivity() {
viewModel.setBrightnessOverlayValue(value)
}
-
- /**
- * Sets the color filter [value].
- */
- private fun setColorFilterValue(value: Int) {
- binding.colorOverlay.isVisible = true
- binding.colorOverlay.setFilterColor(value, readerPreferences.colorFilterMode().get())
- }
-
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/ReaderColorFilterView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderColorFilterView.kt
deleted file mode 100644
index 6266ab239..000000000
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderColorFilterView.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-package eu.kanade.tachiyomi.ui.reader
-
-import android.content.Context
-import android.graphics.Canvas
-import android.graphics.Paint
-import android.graphics.PorterDuff
-import android.util.AttributeSet
-import android.view.View
-import androidx.core.graphics.toXfermode
-
-class ReaderColorFilterView(
- context: Context,
- attrs: AttributeSet? = null,
-) : View(context, attrs) {
-
- private val colorFilterPaint: Paint = Paint()
-
- fun setFilterColor(color: Int, filterMode: Int) {
- colorFilterPaint.color = color
- colorFilterPaint.xfermode = when (filterMode) {
- 1 -> PorterDuff.Mode.MULTIPLY
- 2 -> PorterDuff.Mode.SCREEN
- 3 -> PorterDuff.Mode.OVERLAY
- 4 -> PorterDuff.Mode.LIGHTEN
- 5 -> PorterDuff.Mode.DARKEN
- else -> PorterDuff.Mode.SRC_OVER
- }.toXfermode()
-
- invalidate()
- }
-
- override fun onDraw(canvas: Canvas) {
- super.onDraw(canvas)
- canvas.drawPaint(colorFilterPaint)
- }
-}
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 59ab00d00..95faea7d1 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
@@ -1,5 +1,7 @@
package eu.kanade.tachiyomi.ui.reader.setting
+import android.os.Build
+import androidx.compose.ui.graphics.BlendMode
import dev.icerock.moko.resources.StringResource
import tachiyomi.core.preference.PreferenceStore
import tachiyomi.core.preference.getEnum
@@ -217,5 +219,24 @@ class ReaderPreferences(
MR.strings.zoom_start_right,
MR.strings.zoom_start_center,
)
+
+ val ColorFilterMode = buildList {
+ addAll(
+ listOf(
+ MR.strings.label_default to BlendMode.SrcOver,
+ MR.strings.filter_mode_multiply to BlendMode.Modulate,
+ MR.strings.filter_mode_screen to BlendMode.Screen,
+ ),
+ )
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ addAll(
+ listOf(
+ MR.strings.filter_mode_overlay to BlendMode.Overlay,
+ MR.strings.filter_mode_lighten to BlendMode.Lighten,
+ MR.strings.filter_mode_darken to BlendMode.Darken,
+ ),
+ )
+ }
+ }
}
}
diff --git a/app/src/main/res/layout/reader_activity.xml b/app/src/main/res/layout/reader_activity.xml
index 331e89649..2969e103b 100644
--- a/app/src/main/res/layout/reader_activity.xml
+++ b/app/src/main/res/layout/reader_activity.xml
@@ -22,12 +22,6 @@
-
-