diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e5d92b0e3..e662f0327 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -135,7 +135,7 @@
android:label="@string/sync" />
+ android:label="@string/color_correction" />
{
+ return db.preferencesDao.observe(mangaId)
+ .map { it?.getColorFilterOrNull() }
+ .distinctUntilChanged()
+ }
+
suspend fun findMangaById(mangaId: Long): Manga? {
return db.mangaDao.find(mangaId)?.toManga()
}
@@ -71,6 +92,14 @@ class MangaDataRepository @Inject constructor(
return db.tagsDao.findTags(source.name).toMangaTags()
}
+ private fun MangaPrefsEntity.getColorFilterOrNull(): ReaderColorFilter? {
+ return if (cfBrightness != 0f || cfContrast != 0f) {
+ ReaderColorFilter(cfBrightness, cfContrast)
+ } else {
+ null
+ }
+ }
+
/**
* Automatic determine type of manga by page size
* @return ReaderMode.WEBTOON if page is wide
@@ -104,6 +133,13 @@ class MangaDataRepository @Inject constructor(
return size.width * MIN_WEBTOON_RATIO < size.height
}
+ private fun newEntity(mangaId: Long) = MangaPrefsEntity(
+ mangaId = mangaId,
+ mode = -1,
+ cfBrightness = 0f,
+ cfContrast = 0f,
+ )
+
companion object {
suspend fun getImageMimeType(file: File): String? = runInterruptible(Dispatchers.IO) {
diff --git a/app/src/main/java/org/koitharu/kotatsu/core/db/MangaDatabase.kt b/app/src/main/java/org/koitharu/kotatsu/core/db/MangaDatabase.kt
index 5cbc17385..cdc781bfb 100644
--- a/app/src/main/java/org/koitharu/kotatsu/core/db/MangaDatabase.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/core/db/MangaDatabase.kt
@@ -35,7 +35,7 @@ import org.koitharu.kotatsu.tracker.data.TrackLogEntity
import org.koitharu.kotatsu.tracker.data.TracksDao
import org.koitharu.kotatsu.utils.ext.processLifecycleScope
-const val DATABASE_VERSION = 14
+const val DATABASE_VERSION = 15
@Database(
entities = [
@@ -86,6 +86,7 @@ val databaseMigrations: Array
Migration11To12(),
Migration12To13(),
Migration13To14(),
+ Migration14To15(),
)
fun MangaDatabase(context: Context): MangaDatabase = Room
diff --git a/app/src/main/java/org/koitharu/kotatsu/core/db/dao/PreferencesDao.kt b/app/src/main/java/org/koitharu/kotatsu/core/db/dao/PreferencesDao.kt
index 9a957b206..b0c48b39c 100644
--- a/app/src/main/java/org/koitharu/kotatsu/core/db/dao/PreferencesDao.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/core/db/dao/PreferencesDao.kt
@@ -1,6 +1,7 @@
package org.koitharu.kotatsu.core.db.dao
import androidx.room.*
+import kotlinx.coroutines.flow.Flow
import org.koitharu.kotatsu.core.db.entity.MangaPrefsEntity
@Dao
@@ -9,6 +10,9 @@ abstract class PreferencesDao {
@Query("SELECT * FROM preferences WHERE manga_id = :mangaId")
abstract suspend fun find(mangaId: Long): MangaPrefsEntity?
+ @Query("SELECT * FROM preferences WHERE manga_id = :mangaId")
+ abstract fun observe(mangaId: Long): Flow
+
@Insert(onConflict = OnConflictStrategy.IGNORE)
abstract suspend fun insert(pref: MangaPrefsEntity): Long
@@ -21,4 +25,4 @@ abstract class PreferencesDao {
insert(pref)
}
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/core/db/entity/MangaPrefsEntity.kt b/app/src/main/java/org/koitharu/kotatsu/core/db/entity/MangaPrefsEntity.kt
index a09ccd884..a5ccdb765 100644
--- a/app/src/main/java/org/koitharu/kotatsu/core/db/entity/MangaPrefsEntity.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/core/db/entity/MangaPrefsEntity.kt
@@ -12,12 +12,15 @@ import androidx.room.PrimaryKey
entity = MangaEntity::class,
parentColumns = ["manga_id"],
childColumns = ["manga_id"],
- onDelete = ForeignKey.CASCADE
- )
- ]
+ onDelete = ForeignKey.CASCADE,
+ ),
+ ],
)
-class MangaPrefsEntity(
+data class MangaPrefsEntity(
@PrimaryKey(autoGenerate = false)
- @ColumnInfo(name = "manga_id") val mangaId: Long,
- @ColumnInfo(name = "mode") val mode: Int
-)
\ No newline at end of file
+ @ColumnInfo(name = "manga_id")
+ val mangaId: Long,
+ @ColumnInfo(name = "mode") val mode: Int,
+ @ColumnInfo(name = "cf_brightness") val cfBrightness: Float,
+ @ColumnInfo(name = "cf_contrast") val cfContrast: Float,
+)
diff --git a/app/src/main/java/org/koitharu/kotatsu/core/db/migrations/Migration14To15.kt b/app/src/main/java/org/koitharu/kotatsu/core/db/migrations/Migration14To15.kt
new file mode 100644
index 000000000..3dda50a12
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/core/db/migrations/Migration14To15.kt
@@ -0,0 +1,12 @@
+package org.koitharu.kotatsu.core.db.migrations
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+class Migration14To15 : Migration(14, 15) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("ALTER TABLE preferences ADD COLUMN `cf_brightness` REAL NOT NULL DEFAULT 0")
+ database.execSQL("ALTER TABLE preferences ADD COLUMN `cf_contrast` REAL NOT NULL DEFAULT 0")
+ }
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt
index 0805d872e..72ea00cf0 100644
--- a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt
@@ -17,6 +17,7 @@ import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.sync.domain.SyncController
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
import org.koitharu.kotatsu.utils.SingleLiveEvent
+import org.koitharu.kotatsu.utils.asFlowLiveData
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
@HiltViewModel
@@ -32,7 +33,7 @@ class MainViewModel @Inject constructor(
val isResumeEnabled = historyRepository
.observeHasItems()
- .asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, false)
+ .asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false)
val counters = combine(
appUpdateRepository.observeAvailableUpdate(),
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/domain/ReaderColorFilter.kt b/app/src/main/java/org/koitharu/kotatsu/reader/domain/ReaderColorFilter.kt
new file mode 100644
index 000000000..1511a29fc
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/domain/ReaderColorFilter.kt
@@ -0,0 +1,52 @@
+package org.koitharu.kotatsu.reader.domain
+
+import android.graphics.ColorMatrix
+import android.graphics.ColorMatrixColorFilter
+
+class ReaderColorFilter(
+ val brightness: Float,
+ val contrast: Float,
+) {
+
+ val isEmpty: Boolean
+ get() = brightness == 0f && contrast == 0f
+
+ fun toColorFilter(): ColorMatrixColorFilter {
+ val cm = ColorMatrix()
+ val scale = brightness + 1f
+ cm.setScale(scale, scale, scale, 1f)
+ cm.setContrast(contrast)
+ return ColorMatrixColorFilter(cm)
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as ReaderColorFilter
+
+ if (brightness != other.brightness) return false
+ if (contrast != other.contrast) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = brightness.hashCode()
+ result = 31 * result + contrast.hashCode()
+ return result
+ }
+
+ private fun ColorMatrix.setContrast(contrast: Float) {
+ val scale = contrast + 1f
+ val translate = (-.5f * scale + .5f) * 255f
+ val array = floatArrayOf(
+ scale, 0f, 0f, 0f, translate,
+ 0f, scale, 0f, 0f, translate,
+ 0f, 0f, scale, 0f, translate,
+ 0f, 0f, 0f, 1f, 0f,
+ )
+ val matrix = ColorMatrix(array)
+ postConcat(matrix)
+ }
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt
index dc558dc3b..147f8cd9f 100644
--- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt
@@ -31,6 +31,7 @@ import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.reader.data.filterChapters
import org.koitharu.kotatsu.reader.domain.ChaptersLoader
import org.koitharu.kotatsu.reader.domain.PageLoader
+import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
import org.koitharu.kotatsu.reader.ui.pager.ReaderUiState
import org.koitharu.kotatsu.utils.SingleLiveEvent
import org.koitharu.kotatsu.utils.asFlowLiveData
@@ -86,6 +87,14 @@ class ReaderViewModel @AssistedInject constructor(
valueProducer = { isReaderBarEnabled },
)
+ val readerSettings = ReaderSettings(
+ parentScope = viewModelScope,
+ settings = settings,
+ colorFilterFlow = mangaData.flatMapLatest {
+ if (it == null) flowOf(null) else dataRepository.observeColorFilter(it.id)
+ }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, null),
+ )
+
val isScreenshotsBlockEnabled = combine(
mangaData,
settings.observeAsFlow(AppSettings.KEY_SCREENSHOTS_POLICY) { screenshotsPolicy },
@@ -94,8 +103,6 @@ class ReaderViewModel @AssistedInject constructor(
(policy == ScreenshotsPolicy.BLOCK_NSFW && manga != null && manga.isNsfw)
}.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false)
- val onZoomChanged = SingleLiveEvent()
-
val isBookmarkAdded: LiveData = currentState.flatMapLatest { state ->
val manga = mangaData.value
if (state == null || manga == null) {
@@ -108,7 +115,6 @@ class ReaderViewModel @AssistedInject constructor(
init {
loadImpl()
- subscribeToSettings()
}
override fun onCleared() {
@@ -124,7 +130,7 @@ class ReaderViewModel @AssistedInject constructor(
fun switchMode(newMode: ReaderMode) {
launchJob {
val manga = checkNotNull(mangaData.value)
- dataRepository.savePreferences(
+ dataRepository.saveReaderMode(
manga = manga,
mode = newMode,
)
@@ -300,13 +306,6 @@ class ReaderViewModel @AssistedInject constructor(
}
}
- private fun subscribeToSettings() {
- settings.observe()
- .onEach { key ->
- if (key == AppSettings.KEY_ZOOM_MODE) onZoomChanged.postCall(Unit)
- }.launchIn(viewModelScope + Dispatchers.Default)
- }
-
private fun List.trySublist(fromIndex: Int, toIndex: Int): List {
val fromIndexBounded = fromIndex.coerceAtMost(lastIndex)
val toIndexBounded = toIndex.coerceIn(fromIndexBounded, lastIndex)
@@ -331,7 +330,7 @@ class ReaderViewModel @AssistedInject constructor(
val isWebtoon = dataRepository.determineMangaIsWebtoon(repo, pages)
if (isWebtoon) ReaderMode.WEBTOON else defaultMode
}.onSuccess {
- dataRepository.savePreferences(manga, it)
+ dataRepository.saveReaderMode(manga, it)
}.onFailure {
it.printStackTraceDebug()
}.getOrDefault(defaultMode)
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigActivity.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigActivity.kt
index 48ce32c2f..e3953a555 100644
--- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigActivity.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigActivity.kt
@@ -2,40 +2,54 @@ package org.koitharu.kotatsu.reader.ui.colorfilter
import android.content.Context
import android.content.Intent
-import android.graphics.Color
-import android.graphics.LightingColorFilter
+import android.content.res.Resources
import android.os.Bundle
+import android.view.View
import android.view.ViewGroup
import androidx.core.graphics.Insets
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
-import androidx.lifecycle.lifecycleScope
import coil.ImageLoader
import coil.request.ImageRequest
import coil.size.Scale
import coil.size.ViewSizeResolver
+import com.google.android.material.R as materialR
+import com.google.android.material.slider.LabelFormatter
import com.google.android.material.slider.Slider
import dagger.hilt.android.AndroidEntryPoint
-import kotlinx.coroutines.launch
-import org.koitharu.kotatsu.base.ui.BaseActivity
-import org.koitharu.kotatsu.core.model.parcelable.ParcelableMangaPages
-import org.koitharu.kotatsu.core.parser.MangaRepository
-import org.koitharu.kotatsu.databinding.ActivityColorFilterBinding
-import org.koitharu.kotatsu.parsers.model.MangaPage
-import org.koitharu.kotatsu.utils.ext.enqueueWith
-import org.koitharu.kotatsu.utils.ext.referer
import javax.inject.Inject
-import kotlin.math.roundToInt
-import com.google.android.material.R as materialR
+import org.koitharu.kotatsu.R
+import org.koitharu.kotatsu.base.ui.BaseActivity
+import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
+import org.koitharu.kotatsu.core.model.parcelable.ParcelableMangaPages
+import org.koitharu.kotatsu.databinding.ActivityColorFilterBinding
+import org.koitharu.kotatsu.parsers.model.Manga
+import org.koitharu.kotatsu.parsers.model.MangaPage
+import org.koitharu.kotatsu.parsers.util.format
+import org.koitharu.kotatsu.reader.domain.ReaderColorFilter
+import org.koitharu.kotatsu.utils.ext.assistedViewModels
+import org.koitharu.kotatsu.utils.ext.enqueueWith
+import org.koitharu.kotatsu.utils.ext.getParcelableExtraCompat
+import org.koitharu.kotatsu.utils.ext.referer
@AndroidEntryPoint
-class ColorFilterConfigActivity : BaseActivity(), Slider.OnChangeListener {
+class ColorFilterConfigActivity :
+ BaseActivity(),
+ Slider.OnChangeListener,
+ View.OnClickListener {
@Inject
lateinit var coil: ImageLoader
@Inject
- lateinit var mangaRepositoryFacotry: MangaRepository.Factory
+ lateinit var viewModelFactory: ColorFilterConfigViewModel.Factory
+
+ private val viewModel: ColorFilterConfigViewModel by assistedViewModels {
+ viewModelFactory.create(
+ manga = checkNotNull(intent.getParcelableExtraCompat(EXTRA_MANGA)?.manga),
+ page = checkNotNull(intent.getParcelableExtraCompat(EXTRA_PAGES)?.pages?.firstOrNull()),
+ )
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -44,14 +58,38 @@ class ColorFilterConfigActivity : BaseActivity(), Sl
setDisplayHomeAsUpEnabled(true)
setHomeAsUpIndicator(materialR.drawable.abc_ic_clear_material)
}
- binding.sliderLightness.addOnChangeListener(this)
- binding.sliderSaturation.addOnChangeListener(this)
- initPreview()
- updateFilter()
+ binding.sliderBrightness.addOnChangeListener(this)
+ binding.sliderContrast.addOnChangeListener(this)
+ val formatter = PercentLabelFormatter(resources)
+ binding.sliderContrast.setLabelFormatter(formatter)
+ binding.sliderBrightness.setLabelFormatter(formatter)
+ binding.buttonDone.setOnClickListener(this)
+ binding.buttonReset.setOnClickListener(this)
+
+ onBackPressedDispatcher.addCallback(ColorFilterConfigBackPressedDispatcher(this, viewModel))
+
+ viewModel.colorFilter.observe(this, this::onColorFilterChanged)
+ viewModel.isLoading.observe(this, this::onLoadingChanged)
+ viewModel.preview.observe(this, this::onPreviewChanged)
+ viewModel.onDismiss.observe(this) {
+ finishAfterTransition()
+ }
}
override fun onValueChange(slider: Slider, value: Float, fromUser: Boolean) {
- updateFilter()
+ if (fromUser) {
+ when (slider.id) {
+ R.id.slider_brightness -> viewModel.setBrightness(value)
+ R.id.slider_contrast -> viewModel.setContrast(value)
+ }
+ }
+ }
+
+ override fun onClick(v: View) {
+ when (v.id) {
+ R.id.button_done -> viewModel.save()
+ R.id.button_reset -> viewModel.reset()
+ }
}
override fun onWindowInsetsChanged(insets: Insets) {
@@ -67,42 +105,49 @@ class ColorFilterConfigActivity : BaseActivity(), Sl
}
}
- private fun updateFilter() {
-
- fun Int.toColor() = Color.rgb(this, this, this)
-
- val cf = LightingColorFilter(
- binding.sliderSaturation.value.roundToInt().toColor(),
- binding.sliderLightness.value.roundToInt().toColor(),
- )
- binding.imageViewAfter.colorFilter = cf
+ private fun onColorFilterChanged(readerColorFilter: ReaderColorFilter?) {
+ binding.sliderBrightness.value = readerColorFilter?.brightness ?: 0f
+ binding.sliderContrast.value = readerColorFilter?.contrast ?: 0f
+ binding.imageViewAfter.colorFilter = readerColorFilter?.toColorFilter()
}
- private fun initPreview() {
- val page = intent?.getParcelableExtra(EXTRA_PAGES)?.pages?.firstOrNull()
- if (page == null) {
- finishAfterTransition()
- return
- }
- lifecycleScope.launch {
- val repository = mangaRepositoryFacotry.create(page.source)
- val url = repository.getPageUrl(page)
- ImageRequest.Builder(this@ColorFilterConfigActivity)
- .data(url)
- .referer(page.referer)
- .scale(Scale.FILL)
- .size(ViewSizeResolver(binding.imageViewBefore))
- .allowRgb565(false)
- .target(ShadowViewTarget(binding.imageViewBefore, binding.imageViewAfter))
- .enqueueWith(coil)
+ private fun onPreviewChanged(preview: MangaPage?) {
+ if (preview == null) return
+ ImageRequest.Builder(this@ColorFilterConfigActivity)
+ .data(preview.url)
+ .referer(preview.referer)
+ .scale(Scale.FILL)
+ .error(R.drawable.ic_error_placeholder)
+ .size(ViewSizeResolver(binding.imageViewBefore))
+ .allowRgb565(false)
+ .target(ShadowViewTarget(binding.imageViewBefore, binding.imageViewAfter))
+ .enqueueWith(coil)
+ }
+
+ private fun onLoadingChanged(isLoading: Boolean) {
+ binding.sliderContrast.isEnabled = !isLoading
+ binding.sliderBrightness.isEnabled = !isLoading
+ binding.buttonDone.isEnabled = !isLoading
+ }
+
+ private class PercentLabelFormatter(resources: Resources) : LabelFormatter {
+
+ private val pattern = resources.getString(R.string.percent_string_pattern)
+
+ override fun getFormattedValue(value: Float): String {
+ val percent = ((value + 1f) * 100).format(0)
+ return pattern.format(percent)
}
}
companion object {
private const val EXTRA_PAGES = "pages"
+ private const val EXTRA_MANGA = "manga_id"
- fun newIntent(context: Context, page: MangaPage) = Intent(context, ColorFilterConfigActivity::class.java)
- .putExtra(EXTRA_PAGES, ParcelableMangaPages(listOf(page)))
+ fun newIntent(context: Context, manga: Manga, page: MangaPage) =
+ Intent(context, ColorFilterConfigActivity::class.java)
+ .putExtra(EXTRA_MANGA, ParcelableManga(manga, false))
+ .putExtra(EXTRA_PAGES, ParcelableMangaPages(listOf(page)))
}
}
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigBackPressedDispatcher.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigBackPressedDispatcher.kt
new file mode 100644
index 000000000..a7d017c15
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigBackPressedDispatcher.kt
@@ -0,0 +1,39 @@
+package org.koitharu.kotatsu.reader.ui.colorfilter
+
+import android.content.Context
+import android.content.DialogInterface
+import androidx.activity.OnBackPressedCallback
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import org.koitharu.kotatsu.R
+
+class ColorFilterConfigBackPressedDispatcher(
+ private val context: Context,
+ private val viewModel: ColorFilterConfigViewModel,
+) : OnBackPressedCallback(true), DialogInterface.OnClickListener {
+
+ override fun handleOnBackPressed() {
+ if (viewModel.isChanged) {
+ showConfirmation()
+ } else {
+ viewModel.onDismiss.call(Unit)
+ }
+ }
+
+ override fun onClick(dialog: DialogInterface, which: Int) {
+ when (which) {
+ DialogInterface.BUTTON_NEGATIVE -> viewModel.onDismiss.call(Unit)
+ DialogInterface.BUTTON_NEUTRAL -> dialog.dismiss()
+ DialogInterface.BUTTON_POSITIVE -> viewModel.save()
+ }
+ }
+
+ private fun showConfirmation() {
+ MaterialAlertDialogBuilder(context)
+ .setTitle(R.string.color_correction)
+ .setMessage(R.string.text_unsaved_changes_prompt)
+ .setNegativeButton(R.string.discard, this)
+ .setNeutralButton(android.R.string.cancel, this)
+ .setPositiveButton(R.string.save, this)
+ .show()
+ }
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigViewModel.kt
new file mode 100644
index 000000000..36074c4d7
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigViewModel.kt
@@ -0,0 +1,74 @@
+package org.koitharu.kotatsu.reader.ui.colorfilter
+
+import androidx.lifecycle.MutableLiveData
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import org.koitharu.kotatsu.base.domain.MangaDataRepository
+import org.koitharu.kotatsu.base.ui.BaseViewModel
+import org.koitharu.kotatsu.core.parser.MangaRepository
+import org.koitharu.kotatsu.parsers.model.Manga
+import org.koitharu.kotatsu.parsers.model.MangaPage
+import org.koitharu.kotatsu.reader.domain.ReaderColorFilter
+import org.koitharu.kotatsu.utils.SingleLiveEvent
+
+class ColorFilterConfigViewModel @AssistedInject constructor(
+ @Assisted private val manga: Manga,
+ @Assisted page: MangaPage,
+ private val mangaRepositoryFactory: MangaRepository.Factory,
+ private val mangaDataRepository: MangaDataRepository,
+) : BaseViewModel() {
+
+ private var initialColorFilter: ReaderColorFilter? = null
+ val colorFilter = MutableLiveData(null)
+ val onDismiss = SingleLiveEvent()
+ val preview = MutableLiveData(null)
+
+ val isChanged: Boolean
+ get() = colorFilter.value != initialColorFilter
+
+ init {
+ launchLoadingJob {
+ initialColorFilter = mangaDataRepository.getColorFilter(manga.id)
+ colorFilter.value = initialColorFilter
+ }
+ launchLoadingJob {
+ val repository = mangaRepositoryFactory.create(page.source)
+ val url = repository.getPageUrl(page)
+ preview.value = MangaPage(
+ id = page.id,
+ url = url,
+ referer = page.referer,
+ preview = page.preview,
+ source = page.source,
+ )
+ }
+ }
+
+ fun setBrightness(brightness: Float) {
+ val cf = colorFilter.value
+ colorFilter.value = ReaderColorFilter(brightness, cf?.contrast ?: 0f).takeUnless { it.isEmpty }
+ }
+
+ fun setContrast(contrast: Float) {
+ val cf = colorFilter.value
+ colorFilter.value = ReaderColorFilter(cf?.brightness ?: 0f, contrast).takeUnless { it.isEmpty }
+ }
+
+ fun reset() {
+ colorFilter.value = null
+ }
+
+ fun save() {
+ launchLoadingJob {
+ mangaDataRepository.saveColorFilter(manga, colorFilter.value)
+ onDismiss.call(Unit)
+ }
+ }
+
+ @AssistedFactory
+ interface Factory {
+
+ fun create(manga: Manga, page: MangaPage): ColorFilterConfigViewModel
+ }
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/config/ReaderConfigBottomSheet.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/config/ReaderConfigBottomSheet.kt
index 1ba6d2413..0eb155935 100644
--- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/config/ReaderConfigBottomSheet.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/config/ReaderConfigBottomSheet.kt
@@ -84,7 +84,8 @@ class ReaderConfigBottomSheet :
}
R.id.button_color_filter -> {
val page = viewModel.getCurrentPage() ?: return
- startActivity(ColorFilterConfigActivity.newIntent(v.context, page))
+ val manga = viewModel.manga ?: return
+ startActivity(ColorFilterConfigActivity.newIntent(v.context, manga, page))
}
}
}
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/config/ReaderSettings.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/config/ReaderSettings.kt
new file mode 100644
index 000000000..9619e53df
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/config/ReaderSettings.kt
@@ -0,0 +1,68 @@
+package org.koitharu.kotatsu.reader.ui.config
+
+import android.content.SharedPreferences
+import androidx.lifecycle.MediatorLiveData
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.FlowCollector
+import kotlinx.coroutines.flow.StateFlow
+import org.koitharu.kotatsu.core.model.ZoomMode
+import org.koitharu.kotatsu.core.prefs.AppSettings
+import org.koitharu.kotatsu.reader.domain.ReaderColorFilter
+
+class ReaderSettings(
+ private val parentScope: CoroutineScope,
+ private val settings: AppSettings,
+ private val colorFilterFlow: StateFlow,
+) : MediatorLiveData() {
+
+ private val internalObserver = InternalObserver()
+ private var collectJob: Job? = null
+
+ val zoomMode: ZoomMode
+ get() = settings.zoomMode
+
+ val colorFilter: ReaderColorFilter?
+ get() = colorFilterFlow.value
+
+ val isPagesNumbersEnabled: Boolean
+ get() = settings.isPagesNumbersEnabled
+
+ override fun onInactive() {
+ super.onInactive()
+ settings.unsubscribe(internalObserver)
+ collectJob?.cancel()
+ collectJob = null
+ }
+
+ override fun onActive() {
+ super.onActive()
+ settings.subscribe(internalObserver)
+ collectJob?.cancel()
+ collectJob = parentScope.launch {
+ colorFilterFlow.collect(internalObserver)
+ }
+ }
+
+ override fun getValue() = this
+
+ private fun notifyChanged() {
+ value = value
+ }
+
+ private inner class InternalObserver :
+ FlowCollector,
+ SharedPreferences.OnSharedPreferenceChangeListener {
+
+ override suspend fun emit(value: ReaderColorFilter?) {
+ withContext(Dispatchers.Main.immediate) {
+ notifyChanged()
+ }
+ }
+
+ override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
+ if (key == AppSettings.KEY_ZOOM_MODE || key == AppSettings.KEY_PAGES_NUMBERS) {
+ notifyChanged()
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/BasePageHolder.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/BasePageHolder.kt
index d3980c687..0f752c861 100644
--- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/BasePageHolder.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/BasePageHolder.kt
@@ -5,15 +5,15 @@ import androidx.annotation.CallSuper
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
-import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.LayoutPageInfoBinding
import org.koitharu.kotatsu.reader.domain.PageLoader
+import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
abstract class BasePageHolder(
protected val binding: B,
loader: PageLoader,
- settings: AppSettings,
- exceptionResolver: ExceptionResolver
+ settings: ReaderSettings,
+ exceptionResolver: ExceptionResolver,
) : RecyclerView.ViewHolder(binding.root), PageHolderDelegate.Callback {
@Suppress("LeakingThis")
@@ -37,8 +37,16 @@ abstract class BasePageHolder(
protected abstract fun onBind(data: ReaderPage)
+ fun onAttachedToWindow() {
+ delegate.onAttachedToWindow()
+ }
+
+ fun onDetachedFromWindow() {
+ delegate.onDetachedFromWindow()
+ }
+
@CallSuper
open fun onRecycled() {
delegate.onRecycle()
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/BaseReaderAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/BaseReaderAdapter.kt
index 0529c8ebe..33456c7d3 100644
--- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/BaseReaderAdapter.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/BaseReaderAdapter.kt
@@ -7,14 +7,14 @@ import androidx.recyclerview.widget.RecyclerView
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
-import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.reader.domain.PageLoader
+import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
import org.koitharu.kotatsu.utils.ext.resetTransformations
@Suppress("LeakingThis")
abstract class BaseReaderAdapter>(
private val loader: PageLoader,
- private val settings: AppSettings,
+ private val readerSettings: ReaderSettings,
private val exceptionResolver: ExceptionResolver,
) : RecyclerView.Adapter() {
@@ -35,6 +35,16 @@ abstract class BaseReaderAdapter>(
super.onViewRecycled(holder)
}
+ override fun onViewAttachedToWindow(holder: H) {
+ super.onViewAttachedToWindow(holder)
+ holder.onAttachedToWindow()
+ }
+
+ override fun onViewDetachedFromWindow(holder: H) {
+ holder.onDetachedFromWindow()
+ super.onViewDetachedFromWindow(holder)
+ }
+
open fun getItem(position: Int): ReaderPage = differ.currentList[position]
open fun getItemOrNull(position: Int) = differ.currentList.getOrNull(position)
@@ -46,7 +56,7 @@ abstract class BaseReaderAdapter>(
final override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int,
- ): H = onCreateViewHolder(parent, loader, settings, exceptionResolver)
+ ): H = onCreateViewHolder(parent, loader, readerSettings, exceptionResolver)
suspend fun setItems(items: List) = suspendCoroutine { cont ->
differ.submitList(items) {
@@ -57,7 +67,7 @@ abstract class BaseReaderAdapter>(
protected abstract fun onCreateViewHolder(
parent: ViewGroup,
loader: PageLoader,
- settings: AppSettings,
+ settings: ReaderSettings,
exceptionResolver: ExceptionResolver,
): H
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt
index 5630cb1ba..ca83488bd 100644
--- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt
@@ -2,26 +2,26 @@ package org.koitharu.kotatsu.reader.ui.pager
import android.net.Uri
import androidx.core.net.toUri
+import androidx.lifecycle.Observer
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
+import java.io.File
+import java.io.IOException
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
-import org.koitharu.kotatsu.core.model.ZoomMode
-import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.reader.domain.PageLoader
-import java.io.File
-import java.io.IOException
+import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
class PageHolderDelegate(
private val loader: PageLoader,
- private val settings: AppSettings,
+ private val readerSettings: ReaderSettings,
private val callback: Callback,
- private val exceptionResolver: ExceptionResolver
-) : SubsamplingScaleImageView.DefaultOnImageEventListener() {
+ private val exceptionResolver: ExceptionResolver,
+) : SubsamplingScaleImageView.DefaultOnImageEventListener(), Observer {
private val scope = loader.loaderScope + Dispatchers.Main.immediate
private var state = State.EMPTY
@@ -49,6 +49,14 @@ class PageHolderDelegate(
}
}
+ fun onAttachedToWindow() {
+ readerSettings.observeForever(this)
+ }
+
+ fun onDetachedFromWindow() {
+ readerSettings.removeObserver(this)
+ }
+
fun onRecycle() {
state = State.EMPTY
file = null
@@ -59,7 +67,7 @@ class PageHolderDelegate(
override fun onReady() {
state = State.SHOWING
error = null
- callback.onImageShowing(settings.zoomMode)
+ callback.onImageShowing(readerSettings)
}
override fun onImageLoaded() {
@@ -79,6 +87,12 @@ class PageHolderDelegate(
}
}
+ override fun onChanged(t: ReaderSettings?) {
+ if (state == State.SHOWN) {
+ callback.onImageShowing(readerSettings)
+ }
+ }
+
private fun tryConvert(file: File, e: Exception) {
val prevJob = job
job = scope.launch {
@@ -134,10 +148,10 @@ class PageHolderDelegate(
fun onImageReady(uri: Uri)
- fun onImageShowing(zoom: ZoomMode)
+ fun onImageShowing(settings: ReaderSettings)
fun onImageShown()
fun onProgressChanged(progress: Int)
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPageHolder.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPageHolder.kt
index 33920e631..cdc5b53a9 100644
--- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPageHolder.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPageHolder.kt
@@ -6,16 +6,16 @@ import android.widget.FrameLayout
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.model.ZoomMode
-import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.ItemPageBinding
import org.koitharu.kotatsu.reader.domain.PageLoader
+import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
import org.koitharu.kotatsu.reader.ui.pager.standard.PageHolder
class ReversedPageHolder(
binding: ItemPageBinding,
loader: PageLoader,
- settings: AppSettings,
- exceptionResolver: ExceptionResolver
+ settings: ReaderSettings,
+ exceptionResolver: ExceptionResolver,
) : PageHolder(binding, loader, settings, exceptionResolver) {
init {
@@ -23,13 +23,14 @@ class ReversedPageHolder(
.gravity = Gravity.START or Gravity.BOTTOM
}
- override fun onImageShowing(zoom: ZoomMode) {
+ override fun onImageShowing(settings: ReaderSettings) {
with(binding.ssiv) {
maxScale = 2f * maxOf(
width / sWidth.toFloat(),
- height / sHeight.toFloat()
+ height / sHeight.toFloat(),
)
- when (zoom) {
+ binding.ssiv.colorFilter = settings.colorFilter?.toColorFilter()
+ when (settings.zoomMode) {
ZoomMode.FIT_CENTER -> {
setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE)
resetScaleAndCenter()
@@ -39,7 +40,7 @@ class ReversedPageHolder(
minScale = height / sHeight.toFloat()
setScaleAndCenter(
minScale,
- PointF(sWidth.toFloat(), sHeight / 2f)
+ PointF(sWidth.toFloat(), sHeight / 2f),
)
}
ZoomMode.FIT_WIDTH -> {
@@ -47,17 +48,17 @@ class ReversedPageHolder(
minScale = width / sWidth.toFloat()
setScaleAndCenter(
minScale,
- PointF(sWidth / 2f, 0f)
+ PointF(sWidth / 2f, 0f),
)
}
ZoomMode.KEEP_START -> {
setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE)
setScaleAndCenter(
maxScale,
- PointF(sWidth.toFloat(), 0f)
+ PointF(sWidth.toFloat(), 0f),
)
}
}
}
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPagesAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPagesAdapter.kt
index aebb58b18..46c1f1690 100644
--- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPagesAdapter.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPagesAdapter.kt
@@ -3,26 +3,26 @@ package org.koitharu.kotatsu.reader.ui.pager.reversed
import android.view.LayoutInflater
import android.view.ViewGroup
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
-import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.ItemPageBinding
import org.koitharu.kotatsu.reader.domain.PageLoader
+import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
class ReversedPagesAdapter(
loader: PageLoader,
- settings: AppSettings,
- exceptionResolver: ExceptionResolver
+ settings: ReaderSettings,
+ exceptionResolver: ExceptionResolver,
) : BaseReaderAdapter(loader, settings, exceptionResolver) {
override fun onCreateViewHolder(
parent: ViewGroup,
loader: PageLoader,
- settings: AppSettings,
- exceptionResolver: ExceptionResolver
+ settings: ReaderSettings,
+ exceptionResolver: ExceptionResolver,
) = ReversedPageHolder(
binding = ItemPageBinding.inflate(LayoutInflater.from(parent.context), parent, false),
loader = loader,
settings = settings,
- exceptionResolver = exceptionResolver
+ exceptionResolver = exceptionResolver,
)
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt
index 30a8b7331..9a1c297f2 100644
--- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt
@@ -7,10 +7,8 @@ import android.view.View
import android.view.ViewGroup
import androidx.core.view.children
import dagger.hilt.android.AndroidEntryPoint
-import javax.inject.Inject
import kotlin.math.absoluteValue
import kotlinx.coroutines.async
-import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.FragmentReaderStandardBinding
import org.koitharu.kotatsu.reader.ui.ReaderState
import org.koitharu.kotatsu.reader.ui.pager.BaseReader
@@ -25,9 +23,6 @@ import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
@AndroidEntryPoint
class ReversedReaderFragment : BaseReader() {
- @Inject
- lateinit var settings: AppSettings
-
private var pagerAdapter: ReversedPagesAdapter? = null
override fun onInflateView(
@@ -38,7 +33,7 @@ class ReversedReaderFragment : BaseReader() {
@SuppressLint("NotifyDataSetChanged")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- pagerAdapter = ReversedPagesAdapter(viewModel.pageLoader, settings, exceptionResolver)
+ pagerAdapter = ReversedPagesAdapter(viewModel.pageLoader, viewModel.readerSettings, exceptionResolver)
with(binding.pager) {
adapter = pagerAdapter
offscreenPageLimit = 2
@@ -54,9 +49,6 @@ class ReversedReaderFragment : BaseReader() {
}
}
}
- viewModel.onZoomChanged.observe(viewLifecycleOwner) {
- pagerAdapter?.notifyDataSetChanged()
- }
}
override fun onDestroyView() {
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt
index 397ce0b4e..fba2d45cf 100644
--- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt
@@ -12,9 +12,9 @@ import kotlinx.coroutines.asExecutor
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.model.ZoomMode
-import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.ItemPageBinding
import org.koitharu.kotatsu.reader.domain.PageLoader
+import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
import org.koitharu.kotatsu.reader.ui.pager.BasePageHolder
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
import org.koitharu.kotatsu.utils.ext.*
@@ -22,7 +22,7 @@ import org.koitharu.kotatsu.utils.ext.*
open class PageHolder(
binding: ItemPageBinding,
loader: PageLoader,
- settings: AppSettings,
+ settings: ReaderSettings,
exceptionResolver: ExceptionResolver,
) : BasePageHolder(binding, loader, settings, exceptionResolver),
View.OnClickListener {
@@ -66,12 +66,13 @@ open class PageHolder(
binding.ssiv.setImage(ImageSource.uri(uri))
}
- override fun onImageShowing(zoom: ZoomMode) {
+ override fun onImageShowing(settings: ReaderSettings) {
binding.ssiv.maxScale = 2f * maxOf(
binding.ssiv.width / binding.ssiv.sWidth.toFloat(),
binding.ssiv.height / binding.ssiv.sHeight.toFloat(),
)
- when (zoom) {
+ binding.ssiv.colorFilter = settings.colorFilter?.toColorFilter()
+ when (settings.zoomMode) {
ZoomMode.FIT_CENTER -> {
binding.ssiv.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE)
binding.ssiv.resetScaleAndCenter()
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt
index bb3a583c8..a7d526d95 100644
--- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt
@@ -7,10 +7,8 @@ import android.view.View
import android.view.ViewGroup
import androidx.core.view.children
import dagger.hilt.android.AndroidEntryPoint
-import javax.inject.Inject
import kotlin.math.absoluteValue
import kotlinx.coroutines.async
-import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.FragmentReaderStandardBinding
import org.koitharu.kotatsu.reader.ui.ReaderState
import org.koitharu.kotatsu.reader.ui.pager.BaseReader
@@ -24,9 +22,6 @@ import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
@AndroidEntryPoint
class PagerReaderFragment : BaseReader() {
- @Inject
- lateinit var settings: AppSettings
-
private var pagesAdapter: PagesAdapter? = null
override fun onInflateView(
@@ -37,7 +32,7 @@ class PagerReaderFragment : BaseReader() {
@SuppressLint("NotifyDataSetChanged")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- pagesAdapter = PagesAdapter(viewModel.pageLoader, settings, exceptionResolver)
+ pagesAdapter = PagesAdapter(viewModel.pageLoader, viewModel.readerSettings, exceptionResolver)
with(binding.pager) {
adapter = pagesAdapter
offscreenPageLimit = 2
@@ -53,9 +48,6 @@ class PagerReaderFragment : BaseReader() {
}
}
}
- viewModel.onZoomChanged.observe(viewLifecycleOwner) {
- pagesAdapter?.notifyDataSetChanged()
- }
}
override fun onDestroyView() {
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagesAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagesAdapter.kt
index 553139c76..57badce92 100644
--- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagesAdapter.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagesAdapter.kt
@@ -3,26 +3,26 @@ package org.koitharu.kotatsu.reader.ui.pager.standard
import android.view.LayoutInflater
import android.view.ViewGroup
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
-import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.ItemPageBinding
import org.koitharu.kotatsu.reader.domain.PageLoader
+import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
class PagesAdapter(
loader: PageLoader,
- settings: AppSettings,
- exceptionResolver: ExceptionResolver
+ settings: ReaderSettings,
+ exceptionResolver: ExceptionResolver,
) : BaseReaderAdapter(loader, settings, exceptionResolver) {
override fun onCreateViewHolder(
parent: ViewGroup,
loader: PageLoader,
- settings: AppSettings,
- exceptionResolver: ExceptionResolver
+ settings: ReaderSettings,
+ exceptionResolver: ExceptionResolver,
) = PageHolder(
binding = ItemPageBinding.inflate(LayoutInflater.from(parent.context), parent, false),
loader = loader,
settings = settings,
- exceptionResolver = exceptionResolver
+ exceptionResolver = exceptionResolver,
)
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonAdapter.kt
index a089d4d17..ea76b62f8 100644
--- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonAdapter.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonAdapter.kt
@@ -6,27 +6,28 @@ import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.ItemPageWebtoonBinding
import org.koitharu.kotatsu.reader.domain.PageLoader
+import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
class WebtoonAdapter(
loader: PageLoader,
- settings: AppSettings,
- exceptionResolver: ExceptionResolver
+ settings: ReaderSettings,
+ exceptionResolver: ExceptionResolver,
) : BaseReaderAdapter(loader, settings, exceptionResolver) {
override fun onCreateViewHolder(
parent: ViewGroup,
loader: PageLoader,
- settings: AppSettings,
- exceptionResolver: ExceptionResolver
+ settings: ReaderSettings,
+ exceptionResolver: ExceptionResolver,
) = WebtoonHolder(
binding = ItemPageWebtoonBinding.inflate(
LayoutInflater.from(parent.context),
parent,
- false
+ false,
),
loader = loader,
settings = settings,
- exceptionResolver = exceptionResolver
+ exceptionResolver = exceptionResolver,
)
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt
index 4d9fc1ed8..89fb75aa6 100644
--- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt
@@ -7,10 +7,9 @@ import com.davemorrissey.labs.subscaleview.ImageSource
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
-import org.koitharu.kotatsu.core.model.ZoomMode
-import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.ItemPageWebtoonBinding
import org.koitharu.kotatsu.reader.domain.PageLoader
+import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
import org.koitharu.kotatsu.reader.ui.pager.BasePageHolder
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
import org.koitharu.kotatsu.utils.GoneOnInvisibleListener
@@ -19,7 +18,7 @@ import org.koitharu.kotatsu.utils.ext.*
class WebtoonHolder(
binding: ItemPageWebtoonBinding,
loader: PageLoader,
- settings: AppSettings,
+ settings: ReaderSettings,
exceptionResolver: ExceptionResolver,
) : BasePageHolder(binding, loader, settings, exceptionResolver),
View.OnClickListener {
@@ -60,7 +59,8 @@ class WebtoonHolder(
binding.ssiv.setImage(ImageSource.uri(uri))
}
- override fun onImageShowing(zoom: ZoomMode) {
+ override fun onImageShowing(settings: ReaderSettings) {
+ binding.ssiv.colorFilter = settings.colorFilter?.toColorFilter()
with(binding.ssiv) {
setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CUSTOM)
minScale = width / sWidth.toFloat()
@@ -70,7 +70,7 @@ class WebtoonHolder(
scrollToRestore != 0 -> scrollToRestore
itemView.top < 0 -> getScrollRange()
else -> 0
- }
+ },
)
scrollToRestore = 0
}
@@ -89,7 +89,7 @@ class WebtoonHolder(
override fun onError(e: Throwable) {
bindingInfo.textViewError.text = e.getDisplayMessage(context.resources)
bindingInfo.buttonRetry.setText(
- ExceptionResolver.getResolveStringId(e).ifZero { R.string.try_again }
+ ExceptionResolver.getResolveStringId(e).ifZero { R.string.try_again },
)
bindingInfo.layoutError.isVisible = true
bindingInfo.progressBar.hideCompat()
@@ -104,4 +104,4 @@ class WebtoonHolder(
scrollToRestore = scroll
}
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt
index cfdf3e9c5..e91f1467c 100644
--- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt
@@ -6,9 +6,7 @@ import android.view.View
import android.view.ViewGroup
import android.view.animation.AccelerateDecelerateInterpolator
import dagger.hilt.android.AndroidEntryPoint
-import javax.inject.Inject
import kotlinx.coroutines.async
-import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.FragmentReaderWebtoonBinding
import org.koitharu.kotatsu.reader.ui.ReaderState
import org.koitharu.kotatsu.reader.ui.pager.BaseReader
@@ -21,9 +19,6 @@ import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
@AndroidEntryPoint
class WebtoonReaderFragment : BaseReader() {
- @Inject
- lateinit var settings: AppSettings
-
private val scrollInterpolator = AccelerateDecelerateInterpolator()
private var webtoonAdapter: WebtoonAdapter? = null
@@ -34,7 +29,7 @@ class WebtoonReaderFragment : BaseReader() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- webtoonAdapter = WebtoonAdapter(viewModel.pageLoader, settings, exceptionResolver)
+ webtoonAdapter = WebtoonAdapter(viewModel.pageLoader, viewModel.readerSettings, exceptionResolver)
with(binding.recyclerView) {
setHasFixedSize(true)
adapter = webtoonAdapter
diff --git a/app/src/main/res/layout/activity_color_filter.xml b/app/src/main/res/layout/activity_color_filter.xml
index 782673328..bacb8124d 100644
--- a/app/src/main/res/layout/activity_color_filter.xml
+++ b/app/src/main/res/layout/activity_color_filter.xml
@@ -12,7 +12,7 @@
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
tools:navigationIcon="@drawable/abc_ic_clear_material"
- tools:title="@string/color_filter">
+ tools:title="@string/color_correction">
-
+ app:layout_constraintTop_toBottomOf="@id/textView_brightness" />
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/sheet_reader_config.xml b/app/src/main/res/layout/sheet_reader_config.xml
index f5285c9fc..c31c5f5c5 100644
--- a/app/src/main/res/layout/sheet_reader_config.xml
+++ b/app/src/main/res/layout/sheet_reader_config.xml
@@ -155,7 +155,7 @@
android:drawablePadding="?android:listPreferredItemPaddingStart"
android:paddingStart="?android:listPreferredItemPaddingStart"
android:paddingEnd="?android:listPreferredItemPaddingEnd"
- android:text="@string/color_filter"
+ android:text="@string/color_correction"
android:textAppearance="?attr/textAppearanceButton"
app:drawableStartCompat="@drawable/ic_appearance" />
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 940613e5b..36cd8f13b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -381,5 +381,11 @@
Make recent manga available by long pressing on application icon
Tap on the right edge or pressing the right key always switches to the next page
Ergonomic reader control
- Color filter
+ Color correction
+ Brightness
+ Contrast
+ Reset
+ The chosen color settings will be remembered for this manga
+ You have unsaved changes, do you want to save or discard them?
+ Discard