瀏覽代碼

Reader grayscale filter (closes #2822)

arkon 3 年之前
父節點
當前提交
908c9bc624

+ 2 - 0
app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt

@@ -49,6 +49,8 @@ object PreferenceKeys {
 
     const val colorFilterMode = "color_filter_mode"
 
+    const val grayscale = "pref_grayscale"
+
     const val defaultReadingMode = "pref_default_reading_mode_key"
 
     const val defaultOrientationType = "pref_default_orientation_type_key"

+ 2 - 0
app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt

@@ -121,6 +121,8 @@ class PreferencesHelper(val context: Context) {
 
     fun colorFilterMode() = flowPrefs.getInt(Keys.colorFilterMode, 0)
 
+    fun grayscale() = flowPrefs.getBoolean(Keys.grayscale, false)
+
     fun defaultReadingMode() = prefs.getInt(Keys.defaultReadingMode, ReadingModeType.RIGHT_TO_LEFT.flagValue)
 
     fun defaultOrientationType() = prefs.getInt(Keys.defaultOrientationType, OrientationType.FREE.flagValue)

+ 23 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt

@@ -8,12 +8,16 @@ import android.content.Context
 import android.content.Intent
 import android.graphics.Bitmap
 import android.graphics.Color
+import android.graphics.ColorMatrix
+import android.graphics.ColorMatrixColorFilter
+import android.graphics.Paint
 import android.os.Build
 import android.os.Bundle
 import android.view.KeyEvent
 import android.view.Menu
 import android.view.MenuItem
 import android.view.MotionEvent
+import android.view.View.LAYER_TYPE_HARDWARE
 import android.view.WindowManager
 import android.view.animation.Animation
 import android.view.animation.AnimationUtils
@@ -789,6 +793,16 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
      */
     private inner class ReaderConfig {
 
+        private val grayscalePaint by lazy {
+            Paint().apply {
+                colorFilter = ColorMatrixColorFilter(
+                    ColorMatrix().apply {
+                        setSaturation(0f)
+                    }
+                )
+            }
+        }
+
         /**
          * Initializes the reader subscriptions.
          */
@@ -827,6 +841,10 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
             preferences.colorFilterMode().asFlow()
                 .onEach { setColorFilter(preferences.colorFilter().get()) }
                 .launchIn(lifecycleScope)
+
+            preferences.grayscale().asFlow()
+                .onEach { setGrayscale(it) }
+                .launchIn(lifecycleScope)
         }
 
         /**
@@ -934,5 +952,10 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
             binding.colorOverlay.isVisible = true
             binding.colorOverlay.setFilterColor(value, preferences.colorFilterMode().get())
         }
+
+        private fun setGrayscale(enabled: Boolean) {
+            val paint = if (enabled) grayscalePaint else null
+            binding.viewerContainer.setLayerType(LAYER_TYPE_HARDWARE, paint)
+        }
     }
 }

+ 5 - 15
app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderColorFilterSettings.kt

@@ -14,7 +14,7 @@ import androidx.lifecycle.lifecycleScope
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.databinding.ReaderColorFilterSettingsBinding
 import eu.kanade.tachiyomi.ui.reader.ReaderActivity
-import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener
+import eu.kanade.tachiyomi.util.preference.bindToPreference
 import eu.kanade.tachiyomi.widget.SimpleSeekBarListener
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
@@ -63,20 +63,10 @@ class ReaderColorFilterSettings @JvmOverloads constructor(context: Context, attr
         binding.seekbarColorFilterBlue.progress = argb[3]
 
         // Set listeners
-        binding.switchColorFilter.isChecked = preferences.colorFilter().get()
-        binding.switchColorFilter.setOnCheckedChangeListener { _, isChecked ->
-            preferences.colorFilter().set(isChecked)
-        }
-
-        binding.customBrightness.isChecked = preferences.customBrightness().get()
-        binding.customBrightness.setOnCheckedChangeListener { _, isChecked ->
-            preferences.customBrightness().set(isChecked)
-        }
-
-        binding.colorFilterMode.onItemSelectedListener = IgnoreFirstSpinnerListener { position ->
-            preferences.colorFilterMode().set(position)
-        }
-        binding.colorFilterMode.setSelection(preferences.colorFilterMode().get(), false)
+        binding.switchColorFilter.bindToPreference(preferences.colorFilter())
+        binding.customBrightness.bindToPreference(preferences.customBrightness())
+        binding.colorFilterMode.bindToPreference(preferences.colorFilterMode())
+        binding.grayscale.bindToPreference(preferences.grayscale())
 
         binding.seekbarColorFilterAlpha.setOnSeekBarChangeListener(
             object : SimpleSeekBarListener() {

+ 98 - 92
app/src/main/res/layout/reader_color_filter_settings.xml

@@ -3,8 +3,7 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:padding="16dp">
+    android:layout_height="wrap_content">
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:layout_width="match_parent"
@@ -17,12 +16,25 @@
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:text="@string/pref_custom_color_filter"
+            android:paddingStart="16dp"
+            android:paddingEnd="16dp"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintTop_toTopOf="parent" />
 
         <!-- Red filter -->
 
+        <TextView
+            android:id="@+id/txt_color_filter_red_symbol"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingStart="16dp"
+            android:text="@string/color_filter_r_value"
+            android:textAppearance="@style/TextAppearance.Medium.SubHeading"
+            app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_red"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_red" />
+
         <SeekBar
             android:id="@+id/seekbar_color_filter_red"
             android:layout_width="0dp"
@@ -30,33 +42,36 @@
             android:layout_marginStart="8dp"
             android:layout_marginEnd="8dp"
             android:max="255"
-            android:padding="@dimen/material_component_text_fields_floating_label_padding_between_label_and_input_text"
+            android:padding="8dp"
             app:layout_constraintEnd_toStartOf="@id/txt_color_filter_red_value"
             app:layout_constraintStart_toEndOf="@id/color_filter_symbols_barrier"
             app:layout_constraintTop_toBottomOf="@id/switch_color_filter" />
 
-        <TextView
-            android:id="@+id/txt_color_filter_red_symbol"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/color_filter_r_value"
-            android:textAppearance="@style/TextAppearance.Medium.SubHeading"
-            app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_red"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_red" />
-
         <TextView
             android:id="@+id/txt_color_filter_red_value"
             android:layout_width="30dp"
             android:layout_height="wrap_content"
             android:layout_alignParentEnd="true"
+            android:layout_marginEnd="16dp"
             android:textAppearance="@style/TextAppearance.Medium.SubHeading"
             app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_red"
             app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_red" />
+            app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_red"
+            tools:text="255" />
 
         <!-- Green filter -->
 
+        <TextView
+            android:id="@+id/txt_color_filter_green_symbol"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingStart="16dp"
+            android:text="@string/color_filter_g_value"
+            android:textAppearance="@style/TextAppearance.Medium.SubHeading"
+            app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_green"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_green" />
+
         <SeekBar
             android:id="@+id/seekbar_color_filter_green"
             android:layout_width="0dp"
@@ -64,33 +79,36 @@
             android:layout_marginStart="8dp"
             android:layout_marginEnd="8dp"
             android:max="255"
-            android:padding="@dimen/material_component_text_fields_floating_label_padding_between_label_and_input_text"
+            android:padding="8dp"
             app:layout_constraintEnd_toStartOf="@id/txt_color_filter_green_value"
             app:layout_constraintStart_toEndOf="@id/color_filter_symbols_barrier"
             app:layout_constraintTop_toBottomOf="@id/seekbar_color_filter_red" />
 
-        <TextView
-            android:id="@+id/txt_color_filter_green_symbol"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/color_filter_g_value"
-            android:textAppearance="@style/TextAppearance.Medium.SubHeading"
-            app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_green"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_green" />
-
         <TextView
             android:id="@+id/txt_color_filter_green_value"
             android:layout_width="30dp"
             android:layout_height="wrap_content"
             android:layout_alignParentEnd="true"
+            android:layout_marginEnd="16dp"
             android:textAppearance="@style/TextAppearance.Medium.SubHeading"
             app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_green"
             app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_green" />
+            app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_green"
+            tools:text="255" />
 
         <!-- Blue filter -->
 
+        <TextView
+            android:id="@+id/txt_color_filter_blue_symbol"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/color_filter_b_value"
+            android:paddingStart="16dp"
+            android:textAppearance="@style/TextAppearance.Medium.SubHeading"
+            app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_blue"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_blue" />
+
         <SeekBar
             android:id="@+id/seekbar_color_filter_blue"
             android:layout_width="0dp"
@@ -98,33 +116,36 @@
             android:layout_marginStart="8dp"
             android:layout_marginEnd="8dp"
             android:max="255"
-            android:padding="@dimen/material_component_text_fields_floating_label_padding_between_label_and_input_text"
+            android:padding="8dp"
             app:layout_constraintEnd_toStartOf="@id/txt_color_filter_blue_value"
             app:layout_constraintStart_toEndOf="@id/color_filter_symbols_barrier"
             app:layout_constraintTop_toBottomOf="@id/seekbar_color_filter_green" />
 
-        <TextView
-            android:id="@+id/txt_color_filter_blue_symbol"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/color_filter_b_value"
-            android:textAppearance="@style/TextAppearance.Medium.SubHeading"
-            app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_blue"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_blue" />
-
         <TextView
             android:id="@+id/txt_color_filter_blue_value"
             android:layout_width="30dp"
             android:layout_height="wrap_content"
             android:layout_alignParentEnd="true"
+            android:layout_marginEnd="16dp"
             android:textAppearance="@style/TextAppearance.Medium.SubHeading"
             app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_blue"
             app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_blue" />
+            app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_blue"
+            tools:text="255" />
 
         <!-- Alpha filter -->
 
+        <TextView
+            android:id="@+id/txt_color_filter_alpha_symbol"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingStart="16dp"
+            android:text="@string/color_filter_a_value"
+            android:textAppearance="@style/TextAppearance.Medium.SubHeading"
+            app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_alpha"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_alpha" />
+
         <SeekBar
             android:id="@+id/seekbar_color_filter_alpha"
             android:layout_width="0dp"
@@ -132,51 +153,45 @@
             android:layout_marginStart="8dp"
             android:layout_marginEnd="8dp"
             android:max="255"
-            android:padding="@dimen/material_component_text_fields_floating_label_padding_between_label_and_input_text"
+            android:padding="8dp"
             app:layout_constraintEnd_toStartOf="@id/txt_color_filter_alpha_value"
             app:layout_constraintStart_toEndOf="@id/color_filter_symbols_barrier"
             app:layout_constraintTop_toBottomOf="@id/seekbar_color_filter_blue" />
 
-        <TextView
-            android:id="@+id/txt_color_filter_alpha_symbol"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/color_filter_a_value"
-            android:textAppearance="@style/TextAppearance.Medium.SubHeading"
-            app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_alpha"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_alpha" />
-
         <TextView
             android:id="@+id/txt_color_filter_alpha_value"
             android:layout_width="30dp"
             android:layout_height="wrap_content"
+            android:layout_marginEnd="16dp"
             android:layout_alignParentEnd="true"
             android:textAppearance="@style/TextAppearance.Medium.SubHeading"
             app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_alpha"
             app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_alpha" />
+            app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_alpha"
+            tools:text="255" />
 
         <!-- 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_constraintBaseline_toBaselineOf="@id/color_filter_mode"
-            app:layout_constraintEnd_toStartOf="@id/color_filter_mode"
-            app:layout_constraintStart_toStartOf="parent" />
-
-        <androidx.appcompat.widget.AppCompatSpinner
+        <eu.kanade.tachiyomi.widget.MaterialSpinnerView
             android:id="@+id/color_filter_mode"
-            android:layout_width="0dp"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginTop="16dp"
             android:entries="@array/color_filter_modes"
-            app:layout_constraintEnd_toStartOf="@id/spinner_end"
-            app:layout_constraintStart_toEndOf="@id/verticalcenter"
-            app:layout_constraintTop_toBottomOf="@id/seekbar_color_filter_alpha" />
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/seekbar_color_filter_alpha"
+            app:title="@string/pref_color_filter_mode" />
+
+        <!-- Grayscale -->
+
+        <com.google.android.material.switchmaterial.SwitchMaterial
+            android:id="@+id/grayscale"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingEnd="16dp"
+            android:paddingStart="16dp"
+            android:text="@string/pref_grayscale"
+            android:textColor="?android:attr/textColorSecondary"
+            app:layout_constraintTop_toBottomOf="@id/color_filter_mode" />
 
         <!-- Brightness -->
 
@@ -185,11 +200,25 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginTop="16dp"
+            android:paddingEnd="16dp"
+            android:paddingStart="16dp"
             android:text="@string/pref_custom_brightness"
-            app:layout_constraintTop_toBottomOf="@id/color_filter_mode_text" />
+            app:layout_constraintTop_toBottomOf="@id/grayscale" />
 
         <!-- Brightness value -->
 
+        <androidx.appcompat.widget.AppCompatImageView
+            android:id="@+id/txt_brightness_seekbar_icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingStart="16dp"
+            android:textAppearance="@style/TextAppearance.Medium.SubHeading"
+            android:tint="?attr/colorOnBackground"
+            app:layout_constraintBottom_toBottomOf="@id/brightness_seekbar"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="@id/brightness_seekbar"
+            app:srcCompat="@drawable/ic_brightness_5_24dp" />
+
         <eu.kanade.tachiyomi.widget.NegativeSeekBar
             android:id="@+id/brightness_seekbar"
             android:layout_width="0dp"
@@ -203,25 +232,16 @@
             app:max_seek="100"
             app:min_seek="-75" />
 
-        <androidx.appcompat.widget.AppCompatImageView
-            android:id="@+id/txt_brightness_seekbar_icon"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:textAppearance="@style/TextAppearance.Medium.SubHeading"
-            android:tint="?attr/colorOnBackground"
-            app:layout_constraintBottom_toBottomOf="@id/brightness_seekbar"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toTopOf="@id/brightness_seekbar"
-            app:srcCompat="@drawable/ic_brightness_5_24dp" />
-
         <TextView
             android:id="@+id/txt_brightness_seekbar_value"
             android:layout_width="30dp"
             android:layout_height="wrap_content"
+            android:layout_marginEnd="16dp"
             android:textAppearance="@style/TextAppearance.Medium.SubHeading"
             app:layout_constraintBottom_toBottomOf="@id/brightness_seekbar"
             app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintTop_toTopOf="@id/brightness_seekbar" />
+            app:layout_constraintTop_toTopOf="@id/brightness_seekbar"
+            tools:text="50" />
 
         <androidx.constraintlayout.widget.Barrier
             android:id="@+id/color_filter_symbols_barrier"
@@ -230,20 +250,6 @@
             app:barrierDirection="end"
             app:constraint_referenced_ids="txt_color_filter_alpha_symbol,txt_color_filter_blue_symbol,txt_color_filter_red_symbol,txt_color_filter_green_symbol" />
 
-        <androidx.constraintlayout.widget.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.widget.Space
-            android:id="@+id/spinner_end"
-            android:layout_width="16dp"
-            android:layout_height="0dp"
-            app:layout_constraintStart_toEndOf="parent"
-            tools:ignore="MissingConstraints" />
-
     </androidx.constraintlayout.widget.ConstraintLayout>
 
 </androidx.core.widget.NestedScrollView>

+ 1 - 0
app/src/main/res/values/strings.xml

@@ -271,6 +271,7 @@
     <string name="pref_true_color_summary">Reduces banding, but impacts performance</string>
     <string name="pref_crop_borders">Crop borders</string>
     <string name="pref_custom_brightness">Custom brightness</string>
+    <string name="pref_grayscale">Grayscale</string>
     <string name="pref_custom_color_filter">Custom color filter</string>
     <string name="pref_color_filter_mode">Color filter blend mode</string>
     <string name="filter_mode_default">Default</string>