refactor(app): Migrate ReaderColorFilterView to Compose

This commit is contained in:
arkon 2023-12-03 15:34:52 -05:00 committed by Claudemirovsky
parent 8f3aee8c01
commit d9594919aa
No known key found for this signature in database
GPG key ID: 82AE76162407356E
7 changed files with 83 additions and 138 deletions

View file

@ -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)
}
}

View file

@ -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,
)
}
}
}

View file

@ -1,6 +1,5 @@
package eu.kanade.presentation.reader.settings package eu.kanade.presentation.reader.settings
import android.os.Build
import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.material3.FilterChip import androidx.compose.material3.FilterChip
import androidx.compose.material3.Text import androidx.compose.material3.Text
@ -10,6 +9,7 @@ import androidx.core.graphics.alpha
import androidx.core.graphics.blue import androidx.core.graphics.blue
import androidx.core.graphics.green import androidx.core.graphics.green
import androidx.core.graphics.red import androidx.core.graphics.red
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences.Companion.ColorFilterMode
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
import tachiyomi.core.preference.getAndSet import tachiyomi.core.preference.getAndSet
import tachiyomi.i18n.MR import tachiyomi.i18n.MR
@ -21,25 +21,6 @@ import tachiyomi.presentation.core.util.collectAsState
@Composable @Composable
internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel) { 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() val customBrightness by screenModel.preferences.customBrightness().collectAsState()
CheckboxItem( CheckboxItem(
label = stringResource(MR.strings.pref_custom_brightness), label = stringResource(MR.strings.pref_custom_brightness),
@ -118,11 +99,11 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
val colorFilterMode by screenModel.preferences.colorFilterMode().collectAsState() val colorFilterMode by screenModel.preferences.colorFilterMode().collectAsState()
SettingsChipRow(MR.strings.pref_color_filter_mode) { SettingsChipRow(MR.strings.pref_color_filter_mode) {
colorFilterModes.mapIndexed { index, it -> ColorFilterMode.mapIndexed { index, it ->
FilterChip( FilterChip(
selected = colorFilterMode == index, selected = colorFilterMode == index,
onClick = { screenModel.preferences.colorFilterMode().set(index) }, onClick = { screenModel.preferences.colorFilterMode().set(index) },
label = { Text(it) }, label = { Text(stringResource(it.first)) },
) )
} }
} }

View file

@ -34,17 +34,16 @@ import androidx.core.transition.doOnEnd
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat import androidx.core.view.WindowInsetsControllerCompat
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.google.android.material.elevation.SurfaceColors import com.google.android.material.elevation.SurfaceColors
import com.google.android.material.transition.platform.MaterialContainerTransform import com.google.android.material.transition.platform.MaterialContainerTransform
import dev.chrisbanes.insetter.applyInsetter import dev.chrisbanes.insetter.applyInsetter
import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.base.BasePreferences
import eu.kanade.presentation.reader.BrightnessOverlay
import eu.kanade.presentation.reader.DisplayRefreshHost import eu.kanade.presentation.reader.DisplayRefreshHost
import eu.kanade.presentation.reader.OrientationSelectDialog import eu.kanade.presentation.reader.OrientationSelectDialog
import eu.kanade.presentation.reader.PageIndicatorText import eu.kanade.presentation.reader.PageIndicatorText
import eu.kanade.presentation.reader.ReaderContentOverlay
import eu.kanade.presentation.reader.ReaderPageActionsDialog import eu.kanade.presentation.reader.ReaderPageActionsDialog
import eu.kanade.presentation.reader.ReadingModeSelectDialog import eu.kanade.presentation.reader.ReadingModeSelectDialog
import eu.kanade.presentation.reader.appbars.ReaderAppBars import eu.kanade.presentation.reader.appbars.ReaderAppBars
@ -337,11 +336,24 @@ class ReaderActivity : BaseActivity() {
val isFullscreen by readerPreferences.fullscreen().collectAsState() val isFullscreen by readerPreferences.fullscreen().collectAsState()
val flashOnPageChange by readerPreferences.flashOnPageChange().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 cropBorderPaged by readerPreferences.cropBorders().collectAsState()
val cropBorderWebtoon by readerPreferences.cropBordersWebtoon().collectAsState() val cropBorderWebtoon by readerPreferences.cropBordersWebtoon().collectAsState()
val isPagerType = ReadingMode.isPagerType(viewModel.getMangaReadingMode()) val isPagerType = ReadingMode.isPagerType(viewModel.getMangaReadingMode())
val cropEnabled = if (isPagerType) cropBorderPaged else cropBorderWebtoon val cropEnabled = if (isPagerType) cropBorderPaged else cropBorderWebtoon
ReaderContentOverlay(
brightness = state.brightnessOverlayValue,
color = colorOverlay.takeIf { colorOverlayEnabled },
colorBlendMode = colorOverlayBlendMode,
)
ReaderAppBars( ReaderAppBars(
visible = state.menuVisible, visible = state.menuVisible,
fullscreen = isFullscreen, fullscreen = isFullscreen,
@ -385,10 +397,6 @@ class ReaderActivity : BaseActivity() {
onClickSettings = viewModel::openSettingsDialog, onClickSettings = viewModel::openSettingsDialog,
) )
BrightnessOverlay(
value = state.brightnessOverlayValue,
)
if (flashOnPageChange) { if (flashOnPageChange) {
DisplayRefreshHost( DisplayRefreshHost(
hostState = displayRefreshHost, hostState = displayRefreshHost,
@ -812,24 +820,8 @@ class ReaderActivity : BaseActivity() {
.onEach(::setCustomBrightness) .onEach(::setCustomBrightness)
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
readerPreferences.colorFilter().changes() merge(readerPreferences.grayscale().changes(), readerPreferences.invertedColors().changes())
.onEach(::setColorFilter) .onEach { setLayerPaint(readerPreferences.grayscale().get(), readerPreferences.invertedColors().get()) }
.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(),
)
}
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
readerPreferences.fullscreen().changes() 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]. * 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. * 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) 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) { private fun setLayerPaint(grayscale: Boolean, invertedColors: Boolean) {
val paint = if (grayscale || invertedColors) getCombinedPaint(grayscale, invertedColors) else null val paint = if (grayscale || invertedColors) getCombinedPaint(grayscale, invertedColors) else null
binding.viewerContainer.setLayerType(LAYER_TYPE_HARDWARE, paint) binding.viewerContainer.setLayerType(LAYER_TYPE_HARDWARE, paint)

View file

@ -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)
}
}

View file

@ -1,5 +1,7 @@
package eu.kanade.tachiyomi.ui.reader.setting package eu.kanade.tachiyomi.ui.reader.setting
import android.os.Build
import androidx.compose.ui.graphics.BlendMode
import dev.icerock.moko.resources.StringResource import dev.icerock.moko.resources.StringResource
import tachiyomi.core.preference.PreferenceStore import tachiyomi.core.preference.PreferenceStore
import tachiyomi.core.preference.getEnum import tachiyomi.core.preference.getEnum
@ -217,5 +219,24 @@ class ReaderPreferences(
MR.strings.zoom_start_right, MR.strings.zoom_start_right,
MR.strings.zoom_start_center, 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,
),
)
}
}
} }
} }

View file

@ -22,12 +22,6 @@
</FrameLayout> </FrameLayout>
<eu.kanade.tachiyomi.ui.reader.ReaderColorFilterView
android:id="@+id/color_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<eu.kanade.tachiyomi.ui.reader.ReaderNavigationOverlayView <eu.kanade.tachiyomi.ui.reader.ReaderNavigationOverlayView
android:id="@+id/navigation_overlay" android:id="@+id/navigation_overlay"
android:layout_width="match_parent" android:layout_width="match_parent"