Add color filter blend modes (#2013)
* Add color filter blend modes * Only show modes supported by currently used API level. * Fix arrays.xml for API level <=27.
This commit is contained in:
parent
5840a3e1e2
commit
021dde66eb
12 changed files with 116 additions and 6 deletions
|
@ -29,6 +29,8 @@ object PreferenceKeys {
|
||||||
|
|
||||||
const val colorFilterValue = "color_filter_value"
|
const val colorFilterValue = "color_filter_value"
|
||||||
|
|
||||||
|
const val colorFilterMode = "color_filter_mode"
|
||||||
|
|
||||||
const val defaultViewer = "pref_default_viewer_key"
|
const val defaultViewer = "pref_default_viewer_key"
|
||||||
|
|
||||||
const val imageScaleType = "pref_image_scale_type_key"
|
const val imageScaleType = "pref_image_scale_type_key"
|
||||||
|
|
|
@ -57,6 +57,8 @@ class PreferencesHelper(val context: Context) {
|
||||||
|
|
||||||
fun colorFilterValue() = rxPrefs.getInteger(Keys.colorFilterValue, 0)
|
fun colorFilterValue() = rxPrefs.getInteger(Keys.colorFilterValue, 0)
|
||||||
|
|
||||||
|
fun colorFilterMode() = rxPrefs.getInteger(Keys.colorFilterMode, 0)
|
||||||
|
|
||||||
fun defaultViewer() = prefs.getInt(Keys.defaultViewer, 1)
|
fun defaultViewer() = prefs.getInt(Keys.defaultViewer, 1)
|
||||||
|
|
||||||
fun imageScaleType() = rxPrefs.getInteger(Keys.imageScaleType, 1)
|
fun imageScaleType() = rxPrefs.getInteger(Keys.imageScaleType, 1)
|
||||||
|
|
|
@ -574,6 +574,9 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
|
||||||
|
|
||||||
subscriptions += preferences.colorFilter().asObservable()
|
subscriptions += preferences.colorFilter().asObservable()
|
||||||
.subscribe { setColorFilter(it) }
|
.subscribe { setColorFilter(it) }
|
||||||
|
|
||||||
|
subscriptions += preferences.colorFilterMode().asObservable()
|
||||||
|
.subscribe { setColorFilter(preferences.colorFilter().getOrDefault()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -722,7 +725,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
|
||||||
*/
|
*/
|
||||||
private fun setColorFilterValue(value: Int) {
|
private fun setColorFilterValue(value: Int) {
|
||||||
color_overlay.visibility = View.VISIBLE
|
color_overlay.visibility = View.VISIBLE
|
||||||
color_overlay.setBackgroundColor(value)
|
color_overlay.setFilterColor(value, preferences.colorFilterMode().getOrDefault())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
import eu.kanade.tachiyomi.util.plusAssign
|
import eu.kanade.tachiyomi.util.plusAssign
|
||||||
|
import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener
|
||||||
import eu.kanade.tachiyomi.widget.SimpleSeekBarListener
|
import eu.kanade.tachiyomi.widget.SimpleSeekBarListener
|
||||||
import kotlinx.android.synthetic.main.reader_color_filter.*
|
import kotlinx.android.synthetic.main.reader_color_filter.*
|
||||||
import kotlinx.android.synthetic.main.reader_color_filter_sheet.*
|
import kotlinx.android.synthetic.main.reader_color_filter_sheet.*
|
||||||
|
@ -54,6 +55,9 @@ class ReaderColorFilterSheet(activity: ReaderActivity) : BottomSheetDialog(activ
|
||||||
subscriptions += preferences.colorFilter().asObservable()
|
subscriptions += preferences.colorFilter().asObservable()
|
||||||
.subscribe { setColorFilter(it, view) }
|
.subscribe { setColorFilter(it, view) }
|
||||||
|
|
||||||
|
subscriptions += preferences.colorFilterMode().asObservable()
|
||||||
|
.subscribe { setColorFilter(preferences.colorFilter().getOrDefault(), view) }
|
||||||
|
|
||||||
subscriptions += preferences.customBrightness().asObservable()
|
subscriptions += preferences.customBrightness().asObservable()
|
||||||
.subscribe { setCustomBrightness(it, view) }
|
.subscribe { setCustomBrightness(it, view) }
|
||||||
|
|
||||||
|
@ -84,6 +88,11 @@ class ReaderColorFilterSheet(activity: ReaderActivity) : BottomSheetDialog(activ
|
||||||
preferences.customBrightness().set(isChecked)
|
preferences.customBrightness().set(isChecked)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
color_filter_mode.onItemSelectedListener = IgnoreFirstSpinnerListener { position ->
|
||||||
|
preferences.colorFilterMode().set(position)
|
||||||
|
}
|
||||||
|
color_filter_mode.setSelection(preferences.colorFilterMode().getOrDefault(), false)
|
||||||
|
|
||||||
seekbar_color_filter_alpha.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
|
seekbar_color_filter_alpha.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
|
||||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||||
if (fromUser) {
|
if (fromUser) {
|
||||||
|
@ -248,7 +257,7 @@ class ReaderColorFilterSheet(activity: ReaderActivity) : BottomSheetDialog(activ
|
||||||
*/
|
*/
|
||||||
private fun setColorFilterValue(@ColorInt color: Int, view: View) = with(view) {
|
private fun setColorFilterValue(@ColorInt color: Int, view: View) = with(view) {
|
||||||
color_overlay.visibility = View.VISIBLE
|
color_overlay.visibility = View.VISIBLE
|
||||||
color_overlay.setBackgroundColor(color)
|
color_overlay.setFilterColor(color, preferences.colorFilterMode().getOrDefault())
|
||||||
setValues(color, view)
|
setValues(color, view)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package eu.kanade.tachiyomi.ui.reader
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.*
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
|
||||||
|
class ReaderColorFilterView(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet? = null
|
||||||
|
) : View(context, attrs) {
|
||||||
|
|
||||||
|
private val colorFilterPaint: Paint = Paint()
|
||||||
|
|
||||||
|
fun setFilterColor(color: Int, filterMode: Int) {
|
||||||
|
colorFilterPaint.setColor(color)
|
||||||
|
colorFilterPaint.xfermode = PorterDuffXfermode(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
|
||||||
|
})
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDraw(canvas: Canvas) {
|
||||||
|
super.onDraw(canvas)
|
||||||
|
canvas.drawPaint(colorFilterPaint)
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,7 +29,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<View
|
<eu.kanade.tachiyomi.ui.reader.ReaderColorFilterView
|
||||||
android:id="@+id/color_overlay"
|
android:id="@+id/color_overlay"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
|
@ -111,7 +111,7 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:visibility="gone"/>
|
android:visibility="gone"/>
|
||||||
|
|
||||||
<View
|
<eu.kanade.tachiyomi.ui.reader.ReaderColorFilterView
|
||||||
android:id="@+id/color_overlay"
|
android:id="@+id/color_overlay"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|
|
@ -6,6 +6,12 @@
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:padding="16dp">
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<android.support.v4.widget.Space
|
||||||
|
android:id="@+id/spinner_end"
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintLeft_toRightOf="parent" />
|
||||||
|
|
||||||
<!-- Color filter -->
|
<!-- Color filter -->
|
||||||
|
|
||||||
<android.support.v7.widget.SwitchCompat
|
<android.support.v7.widget.SwitchCompat
|
||||||
|
@ -157,6 +163,27 @@
|
||||||
app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_alpha"
|
app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_alpha"
|
||||||
app:layout_constraintRight_toRightOf="parent"/>
|
app:layout_constraintRight_toRightOf="parent"/>
|
||||||
|
|
||||||
|
<!-- Filter mode -->
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/color_filter_mode_text"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/pref_color_filter_mode"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toLeftOf="@id/color_filter_mode"
|
||||||
|
app:layout_constraintBaseline_toBaselineOf="@id/color_filter_mode"/>
|
||||||
|
|
||||||
|
<android.support.v7.widget.AppCompatSpinner
|
||||||
|
android:id="@+id/color_filter_mode"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:entries="@array/color_filter_modes"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/seekbar_color_filter_alpha"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/verticalcenter"
|
||||||
|
app:layout_constraintRight_toRightOf="@id/spinner_end" />
|
||||||
|
|
||||||
<!-- Brightness -->
|
<!-- Brightness -->
|
||||||
|
|
||||||
<android.support.v7.widget.SwitchCompat
|
<android.support.v7.widget.SwitchCompat
|
||||||
|
@ -165,7 +192,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:text="@string/pref_custom_brightness"
|
android:text="@string/pref_custom_brightness"
|
||||||
app:layout_constraintTop_toBottomOf="@id/seekbar_color_filter_alpha"/>
|
app:layout_constraintTop_toBottomOf="@id/color_filter_mode_text"/>
|
||||||
|
|
||||||
<!-- Brightness value -->
|
<!-- Brightness value -->
|
||||||
|
|
||||||
|
@ -202,4 +229,11 @@
|
||||||
app:layout_constraintBottom_toBottomOf="@id/brightness_seekbar"
|
app:layout_constraintBottom_toBottomOf="@id/brightness_seekbar"
|
||||||
app:layout_constraintRight_toRightOf="parent"/>
|
app:layout_constraintRight_toRightOf="parent"/>
|
||||||
|
|
||||||
|
<android.support.constraint.Guideline
|
||||||
|
android:id="@+id/verticalcenter"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintGuide_percent="0.5" />
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
</android.support.constraint.ConstraintLayout>
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<View
|
<eu.kanade.tachiyomi.ui.reader.ReaderColorFilterView
|
||||||
android:id="@+id/color_overlay"
|
android:id="@+id/color_overlay"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|
15
app/src/main/res/values-v28/arrays.xml
Normal file
15
app/src/main/res/values-v28/arrays.xml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<string-array name="color_filter_modes">
|
||||||
|
<item>@string/filter_mode_default</item>
|
||||||
|
<item>@string/filter_mode_multiply</item>
|
||||||
|
<item>@string/filter_mode_screen</item>
|
||||||
|
|
||||||
|
<!-- Attributes specific for SDK 28 and up -->
|
||||||
|
<item>@string/filter_mode_overlay</item>
|
||||||
|
<item>@string/filter_mode_lighten</item>
|
||||||
|
<item>@string/filter_mode_darken</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
</resources>
|
|
@ -102,4 +102,10 @@
|
||||||
<item>2</item>
|
<item>2</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="color_filter_modes">
|
||||||
|
<item>@string/filter_mode_default</item>
|
||||||
|
<item>@string/filter_mode_multiply</item>
|
||||||
|
<item>@string/filter_mode_screen</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -178,6 +178,13 @@
|
||||||
<string name="pref_crop_borders">Crop borders</string>
|
<string name="pref_crop_borders">Crop borders</string>
|
||||||
<string name="pref_custom_brightness">Use custom brightness</string>
|
<string name="pref_custom_brightness">Use custom brightness</string>
|
||||||
<string name="pref_custom_color_filter">Use custom color filter</string>
|
<string name="pref_custom_color_filter">Use custom color filter</string>
|
||||||
|
<string name="pref_color_filter_mode">Color filter blend mode</string>
|
||||||
|
<string name="filter_mode_default">Default</string>
|
||||||
|
<string name="filter_mode_overlay">Overlay</string>
|
||||||
|
<string name="filter_mode_multiply">Multiply</string>
|
||||||
|
<string name="filter_mode_screen">Screen</string>
|
||||||
|
<string name="filter_mode_lighten">Dodge / Lighten</string>
|
||||||
|
<string name="filter_mode_darken">Burn / Darken</string>
|
||||||
<string name="pref_keep_screen_on">Keep screen on</string>
|
<string name="pref_keep_screen_on">Keep screen on</string>
|
||||||
<string name="pref_skip_read_chapters">Skip chapters marked read</string>
|
<string name="pref_skip_read_chapters">Skip chapters marked read</string>
|
||||||
<string name="pref_reader_navigation">Navigation</string>
|
<string name="pref_reader_navigation">Navigation</string>
|
||||||
|
|
Reference in a new issue