mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-21 18:51:49 +01:00
Migrate ReaderColorFilterView to Compose
This commit is contained in:
parent
ccadfc8fe5
commit
5b2a099203
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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)) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
@ -331,11 +330,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,
|
||||||
@ -378,10 +390,6 @@ class ReaderActivity : BaseActivity() {
|
|||||||
onClickSettings = viewModel::openSettingsDialog,
|
onClickSettings = viewModel::openSettingsDialog,
|
||||||
)
|
)
|
||||||
|
|
||||||
BrightnessOverlay(
|
|
||||||
value = state.brightnessOverlayValue,
|
|
||||||
)
|
|
||||||
|
|
||||||
if (flashOnPageChange) {
|
if (flashOnPageChange) {
|
||||||
DisplayRefreshHost(
|
DisplayRefreshHost(
|
||||||
hostState = displayRefreshHost,
|
hostState = displayRefreshHost,
|
||||||
@ -805,14 +813,6 @@ class ReaderActivity : BaseActivity() {
|
|||||||
.onEach(::setCustomBrightness)
|
.onEach(::setCustomBrightness)
|
||||||
.launchIn(lifecycleScope)
|
.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())
|
merge(readerPreferences.grayscale().changes(), readerPreferences.invertedColors().changes())
|
||||||
.onEach { setLayerPaint(readerPreferences.grayscale().get(), readerPreferences.invertedColors().get()) }
|
.onEach { setLayerPaint(readerPreferences.grayscale().get(), readerPreferences.invertedColors().get()) }
|
||||||
.launchIn(lifecycleScope)
|
.launchIn(lifecycleScope)
|
||||||
@ -884,20 +884,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.
|
||||||
@ -919,15 +905,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)
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
||||||
@ -178,5 +180,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,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,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"
|
||||||
|
Loading…
Reference in New Issue
Block a user