Yellow color filter in reader
This commit is contained in:
@@ -42,6 +42,7 @@ import org.koitharu.kotatsu.core.db.migrations.Migration23To24
|
||||
import org.koitharu.kotatsu.core.db.migrations.Migration24To23
|
||||
import org.koitharu.kotatsu.core.db.migrations.Migration24To25
|
||||
import org.koitharu.kotatsu.core.db.migrations.Migration25To26
|
||||
import org.koitharu.kotatsu.core.db.migrations.Migration26To27
|
||||
import org.koitharu.kotatsu.core.db.migrations.Migration2To3
|
||||
import org.koitharu.kotatsu.core.db.migrations.Migration3To4
|
||||
import org.koitharu.kotatsu.core.db.migrations.Migration4To5
|
||||
@@ -69,7 +70,7 @@ import org.koitharu.kotatsu.tracker.data.TrackEntity
|
||||
import org.koitharu.kotatsu.tracker.data.TrackLogEntity
|
||||
import org.koitharu.kotatsu.tracker.data.TracksDao
|
||||
|
||||
const val DATABASE_VERSION = 26
|
||||
const val DATABASE_VERSION = 27
|
||||
|
||||
@Database(
|
||||
entities = [
|
||||
@@ -140,6 +141,7 @@ fun getDatabaseMigrations(context: Context): Array<Migration> = arrayOf(
|
||||
Migration24To23(),
|
||||
Migration24To25(),
|
||||
Migration25To26(),
|
||||
Migration26To27(),
|
||||
)
|
||||
|
||||
fun MangaDatabase(context: Context): MangaDatabase = Room
|
||||
|
||||
@@ -26,6 +26,7 @@ data class MangaPrefsEntity(
|
||||
@ColumnInfo(name = "cf_contrast") val cfContrast: Float,
|
||||
@ColumnInfo(name = "cf_invert") val cfInvert: Boolean,
|
||||
@ColumnInfo(name = "cf_grayscale") val cfGrayscale: Boolean,
|
||||
@ColumnInfo(name = "cf_book") val cfBookEffect: Boolean,
|
||||
@ColumnInfo(name = "title_override") val titleOverride: String?,
|
||||
@ColumnInfo(name = "cover_override") val coverUrlOverride: String?,
|
||||
@ColumnInfo(name = "content_rating_override") val contentRatingOverride: String?,
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.koitharu.kotatsu.core.db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
class Migration26To27 : Migration(26, 27) {
|
||||
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
db.execSQL("ALTER TABLE preferences ADD COLUMN cf_book INTEGER NOT NULL DEFAULT 0")
|
||||
}
|
||||
}
|
||||
@@ -197,8 +197,14 @@ class MangaDataRepository @Inject constructor(
|
||||
}
|
||||
|
||||
private fun MangaPrefsEntity.getColorFilterOrNull(): ReaderColorFilter? {
|
||||
return if (cfBrightness != 0f || cfContrast != 0f || cfInvert || cfGrayscale) {
|
||||
ReaderColorFilter(cfBrightness, cfContrast, cfInvert, cfGrayscale)
|
||||
return if (cfBrightness != 0f || cfContrast != 0f || cfInvert || cfGrayscale || cfBookEffect) {
|
||||
ReaderColorFilter(
|
||||
brightness = cfBrightness,
|
||||
contrast = cfContrast,
|
||||
isInverted = cfInvert,
|
||||
isGrayscale = cfGrayscale,
|
||||
isBookBackground = cfBookEffect
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
@@ -219,10 +225,11 @@ class MangaDataRepository @Inject constructor(
|
||||
private fun newEntity(mangaId: Long) = MangaPrefsEntity(
|
||||
mangaId = mangaId,
|
||||
mode = -1,
|
||||
cfBrightness = 0f,
|
||||
cfContrast = 0f,
|
||||
cfInvert = false,
|
||||
cfGrayscale = false,
|
||||
cfBrightness = ReaderColorFilter.EMPTY.brightness,
|
||||
cfContrast = ReaderColorFilter.EMPTY.contrast,
|
||||
cfInvert = ReaderColorFilter.EMPTY.isInverted,
|
||||
cfGrayscale = ReaderColorFilter.EMPTY.isGrayscale,
|
||||
cfBookEffect = ReaderColorFilter.EMPTY.isBookBackground,
|
||||
titleOverride = null,
|
||||
coverUrlOverride = null,
|
||||
contentRatingOverride = null,
|
||||
|
||||
@@ -401,19 +401,29 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
||||
|
||||
var readerColorFilter: ReaderColorFilter?
|
||||
get() = runCatching {
|
||||
val brightness = prefs.getFloat(KEY_CF_BRIGHTNESS, ReaderColorFilter.EMPTY.brightness)
|
||||
val contrast = prefs.getFloat(KEY_CF_CONTRAST, ReaderColorFilter.EMPTY.contrast)
|
||||
val inverted = prefs.getBoolean(KEY_CF_INVERTED, ReaderColorFilter.EMPTY.isInverted)
|
||||
val grayscale = prefs.getBoolean(KEY_CF_GRAYSCALE, ReaderColorFilter.EMPTY.isGrayscale)
|
||||
ReaderColorFilter(brightness, contrast, inverted, grayscale).takeUnless { it.isEmpty }
|
||||
ReaderColorFilter(
|
||||
brightness = prefs.getFloat(KEY_CF_BRIGHTNESS, ReaderColorFilter.EMPTY.brightness),
|
||||
contrast = prefs.getFloat(KEY_CF_CONTRAST, ReaderColorFilter.EMPTY.contrast),
|
||||
isInverted = prefs.getBoolean(KEY_CF_INVERTED, ReaderColorFilter.EMPTY.isInverted),
|
||||
isGrayscale = prefs.getBoolean(KEY_CF_GRAYSCALE, ReaderColorFilter.EMPTY.isGrayscale),
|
||||
isBookBackground = prefs.getBoolean(KEY_CF_BOOK, ReaderColorFilter.EMPTY.isBookBackground),
|
||||
).takeUnless { it.isEmpty }
|
||||
}.getOrNull()
|
||||
set(value) {
|
||||
prefs.edit {
|
||||
val cf = value ?: ReaderColorFilter.EMPTY
|
||||
putFloat(KEY_CF_BRIGHTNESS, cf.brightness)
|
||||
putFloat(KEY_CF_CONTRAST, cf.contrast)
|
||||
putBoolean(KEY_CF_INVERTED, cf.isInverted)
|
||||
putBoolean(KEY_CF_GRAYSCALE, cf.isGrayscale)
|
||||
if (value != null) {
|
||||
putFloat(KEY_CF_BRIGHTNESS, value.brightness)
|
||||
putFloat(KEY_CF_CONTRAST, value.contrast)
|
||||
putBoolean(KEY_CF_INVERTED, value.isInverted)
|
||||
putBoolean(KEY_CF_GRAYSCALE, value.isGrayscale)
|
||||
putBoolean(KEY_CF_BOOK, value.isBookBackground)
|
||||
} else {
|
||||
remove(KEY_CF_BRIGHTNESS)
|
||||
remove(KEY_CF_CONTRAST)
|
||||
remove(KEY_CF_INVERTED)
|
||||
remove(KEY_CF_GRAYSCALE)
|
||||
remove(KEY_CF_BOOK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -740,6 +750,7 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
||||
const val KEY_CF_CONTRAST = "cf_contrast"
|
||||
const val KEY_CF_INVERTED = "cf_inverted"
|
||||
const val KEY_CF_GRAYSCALE = "cf_grayscale"
|
||||
const val KEY_CF_BOOK = "cf_book"
|
||||
const val KEY_PAGES_TAB = "pages_tab"
|
||||
const val KEY_DETAILS_TAB = "details_tab"
|
||||
const val KEY_DETAILS_LAST_TAB = "details_last_tab"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.koitharu.kotatsu.reader.domain
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.graphics.ColorMatrix
|
||||
import android.graphics.ColorMatrixColorFilter
|
||||
|
||||
@@ -8,10 +10,11 @@ data class ReaderColorFilter(
|
||||
val contrast: Float,
|
||||
val isInverted: Boolean,
|
||||
val isGrayscale: Boolean,
|
||||
val isBookBackground: Boolean,
|
||||
) {
|
||||
|
||||
val isEmpty: Boolean
|
||||
get() = !isGrayscale && !isInverted && brightness == 0f && contrast == 0f
|
||||
get() = !isGrayscale && !isInverted && !isBookBackground && brightness == 0f && contrast == 0f
|
||||
|
||||
fun toColorFilter(): ColorMatrixColorFilter {
|
||||
val cm = ColorMatrix()
|
||||
@@ -23,9 +26,19 @@ data class ReaderColorFilter(
|
||||
}
|
||||
cm.setBrightness(brightness)
|
||||
cm.setContrast(contrast)
|
||||
if (isBookBackground) {
|
||||
cm.addBookEffect()
|
||||
}
|
||||
return ColorMatrixColorFilter(cm)
|
||||
}
|
||||
|
||||
fun getBackgroundTint(): ColorStateList? = if (isBookBackground) {
|
||||
val color = Color.rgb(255, 255, (255 * BOOK_BLUE_FACTOR).toInt())
|
||||
ColorStateList.valueOf(color)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
private fun ColorMatrix.setBrightness(brightness: Float) {
|
||||
val scale = brightness + 1f
|
||||
val matrix = ColorMatrix()
|
||||
@@ -60,13 +73,26 @@ data class ReaderColorFilter(
|
||||
setSaturation(0f)
|
||||
}
|
||||
|
||||
private fun ColorMatrix.addBookEffect() {
|
||||
val removeBlueMatrix = floatArrayOf(
|
||||
1f, 0f, 0f, 0f, 0f,
|
||||
0f, 1f, 0f, 0f, 0f,
|
||||
0f, 0f, BOOK_BLUE_FACTOR, 0f, 0f,
|
||||
0f, 0f, 0f, 1f, 0f,
|
||||
)
|
||||
postConcat(ColorMatrix(removeBlueMatrix))
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val BOOK_BLUE_FACTOR = 0.92f
|
||||
|
||||
val EMPTY = ReaderColorFilter(
|
||||
brightness = 0.0f,
|
||||
contrast = 0.0f,
|
||||
isInverted = false,
|
||||
isGrayscale = false,
|
||||
isBookBackground = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ class ColorFilterConfigActivity :
|
||||
viewBinding.sliderBrightness.setLabelFormatter(formatter)
|
||||
viewBinding.switchInvert.setOnCheckedChangeListener(this)
|
||||
viewBinding.switchGrayscale.setOnCheckedChangeListener(this)
|
||||
viewBinding.switchBook.setOnCheckedChangeListener(this)
|
||||
viewBinding.buttonDone.setOnClickListener(this)
|
||||
viewBinding.buttonReset.setOnClickListener(this)
|
||||
|
||||
@@ -93,6 +94,7 @@ class ColorFilterConfigActivity :
|
||||
when (buttonView.id) {
|
||||
R.id.switch_invert -> viewModel.setInversion(isChecked)
|
||||
R.id.switch_grayscale -> viewModel.setGrayscale(isChecked)
|
||||
R.id.switch_book -> viewModel.setBookEffect(isChecked)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,6 +122,7 @@ class ColorFilterConfigActivity :
|
||||
viewBinding.sliderContrast.setValueRounded(readerColorFilter?.contrast ?: 0f)
|
||||
viewBinding.switchInvert.setChecked(readerColorFilter?.isInverted == true, false)
|
||||
viewBinding.switchGrayscale.setChecked(readerColorFilter?.isGrayscale == true, false)
|
||||
viewBinding.switchBook.setChecked(readerColorFilter?.isBookBackground == true, false)
|
||||
viewBinding.imageViewAfter.colorFilter = readerColorFilter?.toColorFilter()
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,10 @@ class ColorFilterConfigViewModel @Inject constructor(
|
||||
updateColorFilter { it.copy(isGrayscale = grayscale) }
|
||||
}
|
||||
|
||||
fun setBookEffect(book: Boolean) {
|
||||
updateColorFilter { it.copy(isBookBackground = book) }
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
colorFilter.value = null
|
||||
}
|
||||
|
||||
@@ -57,6 +57,11 @@ data class ReaderSettings(
|
||||
|
||||
fun applyBackground(view: View) {
|
||||
view.background = background.resolve(view.context)
|
||||
view.backgroundTintList = if (background.isLight(view.context)) {
|
||||
colorFilter?.getBackgroundTint()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun isPagesCropEnabled(isWebtoon: Boolean) = if (isWebtoon) {
|
||||
|
||||
@@ -191,6 +191,18 @@
|
||||
app:layout_constraintStart_toEndOf="@id/guideline_vertical"
|
||||
app:layout_constraintTop_toBottomOf="@id/textView_contrast" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/switch_book"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/margin_normal"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/book_effect"
|
||||
android:textAppearance="?textAppearanceTitleMedium"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/guideline_vertical"
|
||||
app:layout_constraintTop_toBottomOf="@id/slider_contrast" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
@@ -170,15 +170,26 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/textView_contrast" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/switch_book"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/book_effect"
|
||||
android:textAppearance="?textAppearanceTitleMedium"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/slider_contrast" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_reset"
|
||||
style="?materialButtonOutlinedStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/reset"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/slider_contrast" />
|
||||
app:layout_constraintTop_toBottomOf="@id/switch_book" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
@@ -853,4 +853,5 @@
|
||||
<string name="reader_multitask_summary">Allows you to keep multiple readers with different manga open at the same time</string>
|
||||
<string name="theme_name_itsuka">Itsuka</string>
|
||||
<string name="theme_name_totoro">Totoro</string>
|
||||
<string name="book_effect">Yellowish background (blue filter)</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user