Use 1.x preference abstraction (#8020)

* Use 1.x preference abstraction

- Uses SharedPreferences compared to 1.x impl which uses DataStore but it breaks all settings screens currently
- Move PreferencesHelper to new PreferenceStore
  - PreferencesHelper should be split into smaller preference stores and be in core or domain
- Remove flow preferences as new PreferenceStore handles changes for us

Co-authored-by: inorichi <3521738+inorichi@users.noreply.github.com>

* Fix PreferenceMutableState not updating

* Fix changes not emitting on first subscription

Co-authored-by: inorichi <3521738+inorichi@users.noreply.github.com>
(cherry picked from commit 0086743a5311c22fb8c07f596ab5de384862a68a)

# Conflicts:
#	app/src/main/java/eu/kanade/domain/source/interactor/GetEnabledSources.kt
#	app/src/main/java/eu/kanade/tachiyomi/App.kt
#	app/src/main/java/eu/kanade/tachiyomi/AppModule.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt
#	core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt
This commit is contained in:
Andreas 2022-09-17 17:48:24 +02:00 committed by Jobobby04
parent 432c6fc8a9
commit 41c9c20e26
84 changed files with 879 additions and 483 deletions

View File

@ -209,7 +209,6 @@ dependencies {
// Preferences // Preferences
implementation(libs.preferencektx) implementation(libs.preferencektx)
implementation(libs.flowpreferences)
// Model View Presenter // Model View Presenter
implementation(libs.bundles.nucleus) implementation(libs.bundles.nucleus)

View File

@ -2,9 +2,8 @@ package eu.kanade.core.prefs
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import com.fredporciuncula.flow.preferences.Preference import eu.kanade.tachiyomi.core.preference.Preference
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
@ -16,8 +15,7 @@ class PreferenceMutableState<T>(
private val state = mutableStateOf(preference.get()) private val state = mutableStateOf(preference.get())
init { init {
preference.asFlow() preference.changes()
.distinctUntilChanged()
.onEach { state.value = it } .onEach { state.value = it }
.launchIn(scope) .launchIn(scope)
} }

View File

@ -56,7 +56,7 @@ class SetReadStatus(
return@withContext Result.InternalError(e) return@withContext Result.InternalError(e)
} }
if (read && preferences.removeAfterMarkedAsRead()) { if (read && preferences.removeAfterMarkedAsRead().get()) {
manga.forEach { manga.forEach {
deleteDownload.awaitAll( deleteDownload.awaitAll(
manga = it, manga = it,

View File

@ -12,7 +12,7 @@ class GetExtensionLanguages(
) { ) {
fun subscribe(): Flow<List<String>> { fun subscribe(): Flow<List<String>> {
return combine( return combine(
preferences.enabledLanguages().asFlow(), preferences.enabledLanguages().changes(),
extensionManager.getAvailableExtensionsFlow(), extensionManager.getAvailableExtensionsFlow(),
) { enabledLanguage, availableExtensions -> ) { enabledLanguage, availableExtensions ->
availableExtensions availableExtensions

View File

@ -16,7 +16,7 @@ class GetExtensionSources(
val isMultiLangSingleSource = val isMultiLangSingleSource =
isMultiSource && extension.sources.map { it.name }.distinct().size == 1 isMultiSource && extension.sources.map { it.name }.distinct().size == 1
return preferences.disabledSources().asFlow().map { disabledSources -> return preferences.disabledSources().changes().map { disabledSources ->
fun Source.isEnabled() = id.toString() !in disabledSources fun Source.isEnabled() = id.toString() !in disabledSources
extension.sources extension.sources

View File

@ -16,7 +16,7 @@ class GetExtensionsByType(
val showNsfwSources = preferences.showNsfwSource().get() val showNsfwSources = preferences.showNsfwSource().get()
return combine( return combine(
preferences.enabledLanguages().asFlow(), preferences.enabledLanguages().changes(),
extensionManager.getInstalledExtensionsFlow(), extensionManager.getInstalledExtensionsFlow(),
extensionManager.getUntrustedExtensionsFlow(), extensionManager.getUntrustedExtensionsFlow(),
extensionManager.getAvailableExtensionsFlow(), extensionManager.getAvailableExtensionsFlow(),

View File

@ -7,7 +7,7 @@ import kotlinx.coroutines.flow.map
class GetSortTag(private val preferences: PreferencesHelper) { class GetSortTag(private val preferences: PreferencesHelper) {
fun subscribe(): Flow<List<String>> { fun subscribe(): Flow<List<String>> {
return preferences.sortTagsForLibrary().asFlow() return preferences.sortTagsForLibrary().changes()
.map(::mapSortTags) .map(::mapSortTags)
} }

View File

@ -18,17 +18,17 @@ class GetEnabledSources(
fun subscribe(): Flow<List<Source>> { fun subscribe(): Flow<List<Source>> {
return combine( return combine(
preferences.pinnedSources().asFlow(), preferences.pinnedSources().changes(),
combine( combine(
preferences.enabledLanguages().asFlow(), preferences.enabledLanguages().changes(),
preferences.disabledSources().asFlow(), preferences.disabledSources().changes(),
preferences.lastUsedSource().asFlow(), preferences.lastUsedSource().changes(),
) { a, b, c -> Triple(a, b, c) }, ) { a, b, c -> Triple(a, b, c) },
// SY --> // SY -->
combine( combine(
preferences.dataSaverExcludedSources().asFlow(), preferences.dataSaverExcludedSources().changes(),
preferences.sourcesTabSourcesInCategories().asFlow(), preferences.sourcesTabSourcesInCategories().changes(),
preferences.sourcesTabCategoriesFilter().asFlow(), preferences.sourcesTabCategoriesFilter().changes(),
) { a, b, c -> Triple(a, b, c) }, ) { a, b, c -> Triple(a, b, c) },
// SY <-- // SY <--
repository.getSources(), repository.getSources(),

View File

@ -15,8 +15,8 @@ class GetLanguagesWithSources(
fun subscribe(): Flow<Map<String, List<Source>>> { fun subscribe(): Flow<Map<String, List<Source>>> {
return combine( return combine(
preferences.enabledLanguages().asFlow(), preferences.enabledLanguages().changes(),
preferences.disabledSources().asFlow(), preferences.disabledSources().changes(),
repository.getOnlineSources(), repository.getOnlineSources(),
) { enabledLanguage, disabledSource, onlineSources -> ) { enabledLanguage, disabledSource, onlineSources ->
val sortedSources = onlineSources.filterNot { it.id in BlacklistedSources.HIDDEN_SOURCES }.sortedWith( val sortedSources = onlineSources.filterNot { it.id in BlacklistedSources.HIDDEN_SOURCES }.sortedWith(

View File

@ -10,7 +10,7 @@ class GetShowLatest(
) { ) {
fun subscribe(mode: SourcesController.Mode): Flow<Boolean> { fun subscribe(mode: SourcesController.Mode): Flow<Boolean> {
return preferences.useNewSourceNavigation().asFlow() return preferences.useNewSourceNavigation().changes()
.map { .map {
mode == SourcesController.Mode.CATALOGUE && !it mode == SourcesController.Mode.CATALOGUE && !it
} }

View File

@ -9,6 +9,6 @@ class GetSourceCategories(
) { ) {
fun subscribe(): Flow<List<String>> { fun subscribe(): Flow<List<String>> {
return preferences.sourcesTabCategories().asFlow().map { it.sortedWith(String.CASE_INSENSITIVE_ORDER) } return preferences.sourcesTabCategories().changes().map { it.sortedWith(String.CASE_INSENSITIVE_ORDER) }
} }
} }

View File

@ -7,6 +7,6 @@ import kotlinx.coroutines.flow.map
class GetSourceRepos(private val preferences: PreferencesHelper) { class GetSourceRepos(private val preferences: PreferencesHelper) {
fun subscribe(): Flow<List<String>> { fun subscribe(): Flow<List<String>> {
return preferences.extensionRepos().asFlow().map { it.sortedWith(String.CASE_INSENSITIVE_ORDER) } return preferences.extensionRepos().changes().map { it.sortedWith(String.CASE_INSENSITIVE_ORDER) }
} }
} }

View File

@ -16,8 +16,8 @@ class GetSourcesWithFavoriteCount(
fun subscribe(): Flow<List<Pair<Source, Long>>> { fun subscribe(): Flow<List<Pair<Source, Long>>> {
return combine( return combine(
preferences.migrationSortingDirection().asFlow(), preferences.migrationSortingDirection().changes(),
preferences.migrationSortingMode().asFlow(), preferences.migrationSortingMode().changes(),
repository.getSourcesWithFavoriteCount(), repository.getSourcesWithFavoriteCount(),
) { direction, mode, list -> ) { direction, mode, list ->
list.sortedWith(sortFn(direction, mode)) list.sortedWith(sortFn(direction, mode))

View File

@ -1,5 +1,6 @@
package eu.kanade.domain.source.interactor package eu.kanade.domain.source.interactor
import eu.kanade.tachiyomi.core.preference.getAndSet
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.util.preference.minusAssign import eu.kanade.tachiyomi.util.preference.minusAssign
import eu.kanade.tachiyomi.util.preference.plusAssign import eu.kanade.tachiyomi.util.preference.plusAssign
@ -9,11 +10,9 @@ class ToggleLanguage(
) { ) {
fun await(language: String) { fun await(language: String) {
val enabled = language in preferences.enabledLanguages().get() val isEnabled = language in preferences.enabledLanguages().get()
if (enabled) { preferences.enabledLanguages().getAndSet { enabled ->
preferences.enabledLanguages() -= language if (isEnabled) enabled.minus(language) else enabled.plus(language)
} else {
preferences.enabledLanguages() += language
} }
} }
} }

View File

@ -1,6 +1,7 @@
package eu.kanade.domain.source.interactor package eu.kanade.domain.source.interactor
import eu.kanade.domain.source.model.Source import eu.kanade.domain.source.model.Source
import eu.kanade.tachiyomi.core.preference.getAndSet
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.util.preference.minusAssign import eu.kanade.tachiyomi.util.preference.minusAssign
import eu.kanade.tachiyomi.util.preference.plusAssign import eu.kanade.tachiyomi.util.preference.plusAssign
@ -14,10 +15,8 @@ class ToggleSource(
} }
fun await(sourceId: Long, enable: Boolean = sourceId.toString() in preferences.disabledSources().get()) { fun await(sourceId: Long, enable: Boolean = sourceId.toString() in preferences.disabledSources().get()) {
if (enable) { preferences.disabledSources().getAndSet { disabled ->
preferences.disabledSources() -= sourceId.toString() if (enable) disabled.minus("$sourceId") else disabled.plus("$sourceId")
} else {
preferences.disabledSources() += sourceId.toString()
} }
} }
} }

View File

@ -1,6 +1,7 @@
package eu.kanade.domain.source.interactor package eu.kanade.domain.source.interactor
import eu.kanade.domain.source.model.Source import eu.kanade.domain.source.model.Source
import eu.kanade.tachiyomi.core.preference.getAndSet
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.util.preference.minusAssign import eu.kanade.tachiyomi.util.preference.minusAssign
import eu.kanade.tachiyomi.util.preference.plusAssign import eu.kanade.tachiyomi.util.preference.plusAssign
@ -11,10 +12,8 @@ class ToggleSourcePin(
fun await(source: Source) { fun await(source: Source) {
val isPinned = source.id.toString() in preferences.pinnedSources().get() val isPinned = source.id.toString() in preferences.pinnedSources().get()
if (isPinned) { preferences.pinnedSources().getAndSet { pinned ->
preferences.pinnedSources() -= source.id.toString() if (isPinned) pinned.minus("${source.id}") else pinned.plus("${source.id}")
} else {
preferences.pinnedSources() += source.id.toString()
} }
} }
} }

View File

@ -1,20 +1,20 @@
package eu.kanade.domain.source.interactor package eu.kanade.domain.source.interactor
import eu.kanade.domain.source.model.Source import eu.kanade.domain.source.model.Source
import eu.kanade.tachiyomi.core.preference.getAndSet
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.util.preference.minusAssign
import eu.kanade.tachiyomi.util.preference.plusAssign
class ToggleSources( class ToggleSources(
private val preferences: PreferencesHelper, private val preferences: PreferencesHelper,
) { ) {
fun await(isEnable: Boolean, sources: List<Source>) { fun await(isEnable: Boolean, sources: List<Source>) {
val newDisabledSources = if (isEnable) { preferences.disabledSources().getAndSet { disabledSources ->
preferences.disabledSources().get() - sources.map { it.id.toString() } if (isEnable) {
disabledSources - sources.map { it.id.toString() }.toSet()
} else { } else {
preferences.disabledSources().get() + sources.map { it.id.toString() } disabledSources + sources.map { it.id.toString() }
}
} }
preferences.disabledSources().set(newDisabledSources)
} }
} }

View File

@ -54,6 +54,7 @@ import eu.kanade.tachiyomi.data.preference.PreferenceValues
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.glance.UpdatesGridGlanceWidget import eu.kanade.tachiyomi.glance.UpdatesGridGlanceWidget
import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.network.NetworkPreferences
import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate
import eu.kanade.tachiyomi.util.preference.asHotFlow import eu.kanade.tachiyomi.util.preference.asHotFlow
import eu.kanade.tachiyomi.util.system.WebViewUtil import eu.kanade.tachiyomi.util.system.WebViewUtil
@ -88,6 +89,7 @@ import kotlin.time.Duration.Companion.days
class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory { class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
private val preferences: PreferencesHelper by injectLazy() private val preferences: PreferencesHelper by injectLazy()
private val networkPreferences: NetworkPreferences by injectLazy()
private val disableIncognitoReceiver = DisableIncognitoReceiver() private val disableIncognitoReceiver = DisableIncognitoReceiver()
@ -111,8 +113,10 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
} }
Injekt.importModule(AppModule(this)) Injekt.importModule(AppModule(this))
Injekt.importModule(PreferenceModule(this))
Injekt.importModule(DomainModule()) Injekt.importModule(DomainModule())
// SY --> // SY -->
Injekt.importModule(SYPreferenceModule(this))
Injekt.importModule(SYDomainModule()) Injekt.importModule(SYDomainModule())
// SY <-- // SY <--
@ -124,7 +128,7 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
ProcessLifecycleOwner.get().lifecycle.addObserver(this) ProcessLifecycleOwner.get().lifecycle.addObserver(this)
// Show notification to disable Incognito Mode when it's enabled // Show notification to disable Incognito Mode when it's enabled
preferences.incognitoMode().asFlow() preferences.incognitoMode().changes()
.onEach { enabled -> .onEach { enabled ->
val notificationManager = NotificationManagerCompat.from(this) val notificationManager = NotificationManagerCompat.from(this)
if (enabled) { if (enabled) {
@ -175,7 +179,7 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
} }
.launchIn(ProcessLifecycleOwner.get().lifecycleScope) .launchIn(ProcessLifecycleOwner.get().lifecycleScope)
/*if (!LogcatLogger.isInstalled && preferences.verboseLogging()) { /*if (!LogcatLogger.isInstalled && networkPreferences.verboseLogging().get()) {
LogcatLogger.install(AndroidLogcatLogger(LogPriority.VERBOSE)) LogcatLogger.install(AndroidLogcatLogger(LogPriority.VERBOSE))
}*/ }*/
} }
@ -206,7 +210,7 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
diskCache(diskCacheInit) diskCache(diskCacheInit)
crossfade((300 * this@App.animatorDurationScale).toInt()) crossfade((300 * this@App.animatorDurationScale).toInt())
allowRgb565(getSystemService<ActivityManager>()!!.isLowRamDevice) allowRgb565(getSystemService<ActivityManager>()!!.isLowRamDevice)
if (preferences.verboseLogging()) logger(DebugLogger()) if (networkPreferences.verboseLogging().get()) logger(DebugLogger())
}.build() }.build()
} }

View File

@ -16,6 +16,8 @@ import eu.kanade.data.dateAdapter
import eu.kanade.data.listOfLongsAdapter import eu.kanade.data.listOfLongsAdapter
import eu.kanade.data.listOfStringsAdapter import eu.kanade.data.listOfStringsAdapter
import eu.kanade.data.listOfStringsAndAdapter import eu.kanade.data.listOfStringsAndAdapter
import eu.kanade.tachiyomi.core.preference.AndroidPreferenceStore
import eu.kanade.tachiyomi.core.preference.PreferenceStore
import eu.kanade.tachiyomi.data.cache.ChapterCache import eu.kanade.tachiyomi.data.cache.ChapterCache
import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.cache.PagePreviewCache import eu.kanade.tachiyomi.data.cache.PagePreviewCache
@ -27,8 +29,11 @@ import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.data.track.job.DelayedTrackingStore import eu.kanade.tachiyomi.data.track.job.DelayedTrackingStore
import eu.kanade.tachiyomi.extension.ExtensionManager import eu.kanade.tachiyomi.extension.ExtensionManager
import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.network.NetworkPreferences
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.util.system.isDevFlavor
import exh.eh.EHentaiUpdateHelper import exh.eh.EHentaiUpdateHelper
import exh.pref.SourcePreferences
import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import uy.kohesive.injekt.api.InjektModule import uy.kohesive.injekt.api.InjektModule
@ -98,8 +103,6 @@ class AppModule(val app: Application) : InjektModule {
} }
} }
addSingletonFactory { PreferencesHelper(app) }
addSingletonFactory { ChapterCache(app) } addSingletonFactory { ChapterCache(app) }
addSingletonFactory { CoverCache(app) } addSingletonFactory { CoverCache(app) }
@ -128,8 +131,6 @@ class AppModule(val app: Application) : InjektModule {
// Asynchronously init expensive components for a faster cold start // Asynchronously init expensive components for a faster cold start
ContextCompat.getMainExecutor(app).execute { ContextCompat.getMainExecutor(app).execute {
get<PreferencesHelper>()
get<NetworkHelper>() get<NetworkHelper>()
get<SourceManager>() get<SourceManager>()
@ -144,3 +145,36 @@ class AppModule(val app: Application) : InjektModule {
} }
} }
} }
class PreferenceModule(val application: Application) : InjektModule {
override fun InjektRegistrar.registerInjectables() {
addSingletonFactory<PreferenceStore> {
AndroidPreferenceStore(application)
}
addSingletonFactory {
NetworkPreferences(
preferenceStore = get(),
verboseLogging = isDevFlavor,
)
}
addSingletonFactory {
PreferencesHelper(
context = application,
preferenceStore = get(),
)
}
}
}
// SY -->
class SYPreferenceModule(val application: Application) : InjektModule {
override fun InjektRegistrar.registerInjectables() {
addSingletonFactory {
SourcePreferences(
preferenceStore = get(),
)
}
}
}
// SY <--

View File

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi package eu.kanade.tachiyomi
import android.content.Context
import android.os.Build import android.os.Build
import androidx.core.content.edit import androidx.core.content.edit
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
@ -12,6 +13,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.data.updater.AppUpdateJob import eu.kanade.tachiyomi.data.updater.AppUpdateJob
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
import eu.kanade.tachiyomi.network.NetworkPreferences
import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
import eu.kanade.tachiyomi.util.preference.minusAssign import eu.kanade.tachiyomi.util.preference.minusAssign
@ -33,9 +35,11 @@ object Migrations {
* @param preferences Preferences of the application. * @param preferences Preferences of the application.
* @return true if a migration is performed, false otherwise. * @return true if a migration is performed, false otherwise.
*/ */
fun upgrade(preferences: PreferencesHelper): Boolean { fun upgrade(
val context = preferences.context context: Context,
preferences: PreferencesHelper,
networkPreferences: NetworkPreferences,
): Boolean {
val oldVersion = preferences.lastVersionCode().get() val oldVersion = preferences.lastVersionCode().get()
if (oldVersion < BuildConfig.VERSION_CODE) { if (oldVersion < BuildConfig.VERSION_CODE) {
preferences.lastVersionCode().set(BuildConfig.VERSION_CODE) preferences.lastVersionCode().set(BuildConfig.VERSION_CODE)
@ -145,7 +149,7 @@ object Migrations {
val wasDohEnabled = prefs.getBoolean("enable_doh", false) val wasDohEnabled = prefs.getBoolean("enable_doh", false)
if (wasDohEnabled) { if (wasDohEnabled) {
prefs.edit { prefs.edit {
putInt(PreferenceKeys.dohProvider, PREF_DOH_CLOUDFLARE) putInt(networkPreferences.dohProvider().key(), PREF_DOH_CLOUDFLARE)
remove("enable_doh") remove("enable_doh")
} }
} }

View File

@ -84,7 +84,7 @@ class BackupNotifier(private val context: Context) {
val builder = with(progressNotificationBuilder) { val builder = with(progressNotificationBuilder) {
setContentTitle(context.getString(R.string.restoring_backup)) setContentTitle(context.getString(R.string.restoring_backup))
if (!preferences.hideNotificationContent()) { if (!preferences.hideNotificationContent().get()) {
setContentText(content) setContentText(content)
} }

View File

@ -57,7 +57,7 @@ class ChapterCache(private val context: Context) {
private var diskCache = setupDiskCache(prefs.cacheSize().get().toLong()) private var diskCache = setupDiskCache(prefs.cacheSize().get().toLong())
init { init {
prefs.cacheSize().asFlow() prefs.cacheSize().changes()
.onEach { .onEach {
// Save old cache for destruction later // Save old cache for destruction later
val oldCache = diskCache val oldCache = diskCache

View File

@ -47,7 +47,7 @@ class DownloadCache(
private var rootDir = RootDirectory(getDirectoryFromPreference()) private var rootDir = RootDirectory(getDirectoryFromPreference())
init { init {
preferences.downloadsDirectory().asFlow() preferences.downloadsDirectory().changes()
.onEach { .onEach {
lastRenew = 0L // invalidate cache lastRenew = 0L // invalidate cache
rootDir = RootDirectory(getDirectoryFromPreference()) rootDir = RootDirectory(getDirectoryFromPreference())

View File

@ -468,7 +468,7 @@ class DownloadManager(
return if (categoriesForManga.intersect(categoriesToExclude).isNotEmpty()) { return if (categoriesForManga.intersect(categoriesToExclude).isNotEmpty()) {
chapters.filterNot { it.read } chapters.filterNot { it.read }
} else if (!preferences.removeBookmarkedChapters()) { } else if (!preferences.removeBookmarkedChapters().get()) {
chapters.filterNot { it.bookmark } chapters.filterNot { it.bookmark }
} else { } else {
chapters chapters

View File

@ -104,7 +104,7 @@ internal class DownloadNotifier(private val context: Context) {
download.pages!!.size, download.pages!!.size,
) )
if (preferences.hideNotificationContent()) { if (preferences.hideNotificationContent().get()) {
setContentTitle(downloadingProgressText) setContentTitle(downloadingProgressText)
setContentText(null) setContentText(null)
} else { } else {

View File

@ -39,7 +39,7 @@ class DownloadProvider(private val context: Context) {
} }
init { init {
preferences.downloadsDirectory().asFlow() preferences.downloadsDirectory().changes()
.onEach { downloadsDir = UniFile.fromUri(context, it.toUri()) } .onEach { downloadsDir = UniFile.fromUri(context, it.toUri()) }
.launchIn(scope) .launchIn(scope)
} }

View File

@ -164,7 +164,7 @@ class DownloadService : Service() {
*/ */
private fun onNetworkStateChanged() { private fun onNetworkStateChanged() {
if (isOnline()) { if (isOnline()) {
if (preferences.downloadOnlyOverWifi() && !isConnectedToWifi()) { if (preferences.downloadOnlyOverWifi().get() && !isConnectedToWifi()) {
stopDownloads(R.string.download_notifier_text_only_wifi) stopDownloads(R.string.download_notifier_text_only_wifi)
} else { } else {
val started = downloadManager.startDownloads() val started = downloadManager.startDownloads()

View File

@ -72,7 +72,7 @@ class LibraryUpdateNotifier(private val context: Context) {
* @param total the total progress. * @param total the total progress.
*/ */
fun showProgressNotification(manga: List</* SY --> */SManga/* SY <-- */>, current: Int, total: Int) { fun showProgressNotification(manga: List</* SY --> */SManga/* SY <-- */>, current: Int, total: Int) {
if (preferences.hideNotificationContent()) { if (preferences.hideNotificationContent().get()) {
progressNotificationBuilder progressNotificationBuilder
.setContentTitle(context.getString(R.string.notification_check_updates)) .setContentTitle(context.getString(R.string.notification_check_updates))
.setContentText("($current/$total)") .setContentText("($current/$total)")
@ -168,12 +168,12 @@ class LibraryUpdateNotifier(private val context: Context) {
Notifications.ID_NEW_CHAPTERS, Notifications.ID_NEW_CHAPTERS,
context.notification(Notifications.CHANNEL_NEW_CHAPTERS) { context.notification(Notifications.CHANNEL_NEW_CHAPTERS) {
setContentTitle(context.getString(R.string.notification_new_chapters)) setContentTitle(context.getString(R.string.notification_new_chapters))
if (updates.size == 1 && !preferences.hideNotificationContent()) { if (updates.size == 1 && !preferences.hideNotificationContent().get()) {
setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN)) setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN))
} else { } else {
setContentText(context.resources.getQuantityString(R.plurals.notification_new_chapters_summary, updates.size, updates.size)) setContentText(context.resources.getQuantityString(R.plurals.notification_new_chapters_summary, updates.size, updates.size))
if (!preferences.hideNotificationContent()) { if (!preferences.hideNotificationContent().get()) {
setStyle( setStyle(
NotificationCompat.BigTextStyle().bigText( NotificationCompat.BigTextStyle().bigText(
updates.joinToString("\n") { updates.joinToString("\n") {
@ -198,7 +198,7 @@ class LibraryUpdateNotifier(private val context: Context) {
) )
// Per-manga notification // Per-manga notification
if (!preferences.hideNotificationContent()) { if (!preferences.hideNotificationContent().get()) {
launchUI { launchUI {
updates.forEach { (manga, chapters) -> updates.forEach { (manga, chapters) ->
notify(manga.id.hashCode(), createNewChaptersNotification(manga, chapters)) notify(manga.id.hashCode(), createNewChaptersNotification(manga, chapters))

View File

@ -467,7 +467,7 @@ class LibraryUpdateService(
failedUpdates.add(mangaWithNotif to errorMessage) failedUpdates.add(mangaWithNotif to errorMessage)
} }
if (preferences.autoUpdateTrackers()) { if (preferences.autoUpdateTrackers().get()) {
updateTrackings(mangaWithNotif, loggedServices) updateTrackings(mangaWithNotif, loggedServices)
} }
} }
@ -533,7 +533,7 @@ class LibraryUpdateService(
val source = sourceManager.getOrStub(manga.source) val source = sourceManager.getOrStub(manga.source)
// Update manga metadata if needed // Update manga metadata if needed
if (preferences.autoUpdateMetadata()) { if (preferences.autoUpdateMetadata().get()) {
val networkManga = source.getMangaDetails(manga.toSManga()) val networkManga = source.getMangaDetails(manga.toSManga())
updateManga.awaitUpdateFromSource(manga, networkManga, manualFetch = false, coverCache) updateManga.awaitUpdateFromSource(manga, networkManga, manualFetch = false, coverCache)
} }

View File

@ -248,7 +248,7 @@ class NotificationReceiver : BroadcastReceiver() {
val toUpdate = chapterUrls.mapNotNull { getChapter.await(it, mangaId) } val toUpdate = chapterUrls.mapNotNull { getChapter.await(it, mangaId) }
.map { .map {
val chapter = it.copy(read = true) val chapter = it.copy(read = true)
if (preferences.removeAfterMarkedAsRead()) { if (preferences.removeAfterMarkedAsRead().get()) {
val manga = getManga.await(mangaId) val manga = getManga.await(mangaId)
if (manga != null) { if (manga != null) {
val source = sourceManager.get(manga.source) val source = sourceManager.get(manga.source)

View File

@ -58,10 +58,6 @@ object PreferenceKeys {
const val searchPinnedSourcesOnly = "search_pinned_sources_only" const val searchPinnedSourcesOnly = "search_pinned_sources_only"
const val dohProvider = "doh_provider"
const val defaultUserAgent = "default_user_agent"
const val defaultChapterFilterByRead = "default_chapter_filter_by_read" const val defaultChapterFilterByRead = "default_chapter_filter_by_read"
const val defaultChapterFilterByDownloaded = "default_chapter_filter_by_downloaded" const val defaultChapterFilterByDownloaded = "default_chapter_filter_by_downloaded"
@ -74,8 +70,6 @@ object PreferenceKeys {
const val defaultChapterDisplayByNameOrNumber = "default_chapter_display_by_name_or_number" const val defaultChapterDisplayByNameOrNumber = "default_chapter_display_by_name_or_number"
const val verboseLogging = "verbose_logging"
const val autoClearChapterCache = "auto_clear_chapter_cache" const val autoClearChapterCache = "auto_clear_chapter_cache"
fun trackUsername(syncId: Long) = "pref_mangasync_username_$syncId" fun trackUsername(syncId: Long) = "pref_mangasync_username_$syncId"

View File

@ -3,12 +3,11 @@ package eu.kanade.tachiyomi.data.preference
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
import android.os.Environment import android.os.Environment
import androidx.core.content.edit
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.preference.PreferenceManager
import com.fredporciuncula.flow.preferences.FlowSharedPreferences
import eu.kanade.domain.source.interactor.SetMigrateSorting import eu.kanade.domain.source.interactor.SetMigrateSorting
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.core.preference.PreferenceStore
import eu.kanade.tachiyomi.core.preference.getEnum
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.data.track.TrackService
import eu.kanade.tachiyomi.data.track.anilist.Anilist import eu.kanade.tachiyomi.data.track.anilist.Anilist
@ -21,7 +20,6 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerConfig import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerConfig
import eu.kanade.tachiyomi.util.system.DeviceUtil import eu.kanade.tachiyomi.util.system.DeviceUtil
import eu.kanade.tachiyomi.util.system.LocaleHelper import eu.kanade.tachiyomi.util.system.LocaleHelper
import eu.kanade.tachiyomi.util.system.isDevFlavor
import eu.kanade.tachiyomi.util.system.isDynamicColorAvailable import eu.kanade.tachiyomi.util.system.isDynamicColorAvailable
import eu.kanade.tachiyomi.widget.ExtendedNavigationView import eu.kanade.tachiyomi.widget.ExtendedNavigationView
import java.io.File import java.io.File
@ -32,10 +30,10 @@ import eu.kanade.domain.manga.model.Manga as DomainManga
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values
class PreferencesHelper(val context: Context) { class PreferencesHelper(
val context: Context,
private val prefs = PreferenceManager.getDefaultSharedPreferences(context) private val preferenceStore: PreferenceStore,
val flowPrefs = FlowSharedPreferences(prefs) ) {
private val defaultDownloadsDir = File( private val defaultDownloadsDir = File(
Environment.getExternalStorageDirectory().absolutePath + File.separator + Environment.getExternalStorageDirectory().absolutePath + File.separator +
@ -49,484 +47,474 @@ class PreferencesHelper(val context: Context) {
"backup", "backup",
).toUri() ).toUri()
fun confirmExit() = prefs.getBoolean(Keys.confirmExit, false) fun confirmExit() = this.preferenceStore.getBoolean(Keys.confirmExit, false)
fun sideNavIconAlignment() = flowPrefs.getInt("pref_side_nav_icon_alignment", 0) fun sideNavIconAlignment() = this.preferenceStore.getInt("pref_side_nav_icon_alignment", 0)
fun useAuthenticator() = flowPrefs.getBoolean("use_biometric_lock", false) fun useAuthenticator() = this.preferenceStore.getBoolean("use_biometric_lock", false)
fun lockAppAfter() = flowPrefs.getInt("lock_app_after", 0) fun lockAppAfter() = this.preferenceStore.getInt("lock_app_after", 0)
/** /**
* For app lock. Will be set when there is a pending timed lock. * For app lock. Will be set when there is a pending timed lock.
* Otherwise this pref should be deleted. * Otherwise this pref should be deleted.
*/ */
fun lastAppClosed() = flowPrefs.getLong("last_app_closed", 0) fun lastAppClosed() = this.preferenceStore.getLong("last_app_closed", 0)
fun secureScreen() = flowPrefs.getEnum("secure_screen_v2", Values.SecureScreenMode.INCOGNITO) fun secureScreen() = this.preferenceStore.getEnum("secure_screen_v2", Values.SecureScreenMode.INCOGNITO)
fun hideNotificationContent() = prefs.getBoolean(Keys.hideNotificationContent, false) fun hideNotificationContent() = this.preferenceStore.getBoolean(Keys.hideNotificationContent, false)
fun autoUpdateMetadata() = prefs.getBoolean(Keys.autoUpdateMetadata, false) fun autoUpdateMetadata() = this.preferenceStore.getBoolean(Keys.autoUpdateMetadata, false)
fun autoUpdateTrackers() = prefs.getBoolean(Keys.autoUpdateTrackers, false) fun autoUpdateTrackers() = this.preferenceStore.getBoolean(Keys.autoUpdateTrackers, false)
fun themeMode() = flowPrefs.getEnum( fun themeMode() = this.preferenceStore.getEnum(
"pref_theme_mode_key", "pref_theme_mode_key",
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { Values.ThemeMode.system } else { Values.ThemeMode.light }, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { Values.ThemeMode.system } else { Values.ThemeMode.light },
) )
fun appTheme() = flowPrefs.getEnum( fun appTheme() = this.preferenceStore.getEnum(
"pref_app_theme", "pref_app_theme",
if (DeviceUtil.isDynamicColorAvailable) { Values.AppTheme.MONET } else { Values.AppTheme.DEFAULT }, if (DeviceUtil.isDynamicColorAvailable) { Values.AppTheme.MONET } else { Values.AppTheme.DEFAULT },
) )
fun themeDarkAmoled() = flowPrefs.getBoolean("pref_theme_dark_amoled_key", false) fun themeDarkAmoled() = this.preferenceStore.getBoolean("pref_theme_dark_amoled_key", false)
// SY --> // SY -->
fun pageTransitionsPager() = flowPrefs.getBoolean("pref_enable_transitions_pager_key", true) fun pageTransitionsPager() = this.preferenceStore.getBoolean("pref_enable_transitions_pager_key", true)
fun pageTransitionsWebtoon() = flowPrefs.getBoolean("pref_enable_transitions_webtoon_key", true) fun pageTransitionsWebtoon() = this.preferenceStore.getBoolean("pref_enable_transitions_webtoon_key", true)
// SY <-- // SY <--
fun doubleTapAnimSpeed() = flowPrefs.getInt("pref_double_tap_anim_speed", 500) fun doubleTapAnimSpeed() = this.preferenceStore.getInt("pref_double_tap_anim_speed", 500)
fun showPageNumber() = flowPrefs.getBoolean("pref_show_page_number_key", true) fun showPageNumber() = this.preferenceStore.getBoolean("pref_show_page_number_key", true)
fun dualPageSplitPaged() = flowPrefs.getBoolean("pref_dual_page_split", false) fun dualPageSplitPaged() = this.preferenceStore.getBoolean("pref_dual_page_split", false)
fun dualPageInvertPaged() = flowPrefs.getBoolean("pref_dual_page_invert", false) fun dualPageInvertPaged() = this.preferenceStore.getBoolean("pref_dual_page_invert", false)
fun dualPageSplitWebtoon() = flowPrefs.getBoolean("pref_dual_page_split_webtoon", false) fun dualPageSplitWebtoon() = this.preferenceStore.getBoolean("pref_dual_page_split_webtoon", false)
fun dualPageInvertWebtoon() = flowPrefs.getBoolean("pref_dual_page_invert_webtoon", false) fun dualPageInvertWebtoon() = this.preferenceStore.getBoolean("pref_dual_page_invert_webtoon", false)
fun longStripSplitWebtoon() = flowPrefs.getBoolean("pref_long_strip_split_webtoon", true) fun longStripSplitWebtoon() = this.preferenceStore.getBoolean("pref_long_strip_split_webtoon", true)
fun showReadingMode() = prefs.getBoolean(Keys.showReadingMode, true) fun showReadingMode() = this.preferenceStore.getBoolean(Keys.showReadingMode, true)
fun trueColor() = flowPrefs.getBoolean("pref_true_color_key", false) fun trueColor() = this.preferenceStore.getBoolean("pref_true_color_key", false)
fun fullscreen() = flowPrefs.getBoolean("fullscreen", true) fun fullscreen() = this.preferenceStore.getBoolean("fullscreen", true)
fun cutoutShort() = flowPrefs.getBoolean("cutout_short", true) fun cutoutShort() = this.preferenceStore.getBoolean("cutout_short", true)
fun keepScreenOn() = flowPrefs.getBoolean("pref_keep_screen_on_key", true) fun keepScreenOn() = this.preferenceStore.getBoolean("pref_keep_screen_on_key", true)
fun customBrightness() = flowPrefs.getBoolean("pref_custom_brightness_key", false) fun customBrightness() = this.preferenceStore.getBoolean("pref_custom_brightness_key", false)
fun customBrightnessValue() = flowPrefs.getInt("custom_brightness_value", 0) fun customBrightnessValue() = this.preferenceStore.getInt("custom_brightness_value", 0)
fun colorFilter() = flowPrefs.getBoolean("pref_color_filter_key", false) fun colorFilter() = this.preferenceStore.getBoolean("pref_color_filter_key", false)
fun colorFilterValue() = flowPrefs.getInt("color_filter_value", 0) fun colorFilterValue() = this.preferenceStore.getInt("color_filter_value", 0)
fun colorFilterMode() = flowPrefs.getInt("color_filter_mode", 0) fun colorFilterMode() = this.preferenceStore.getInt("color_filter_mode", 0)
fun grayscale() = flowPrefs.getBoolean("pref_grayscale", false) fun grayscale() = this.preferenceStore.getBoolean("pref_grayscale", false)
fun invertedColors() = flowPrefs.getBoolean("pref_inverted_colors", false) fun invertedColors() = this.preferenceStore.getBoolean("pref_inverted_colors", false)
fun defaultReadingMode() = prefs.getInt(Keys.defaultReadingMode, ReadingModeType.RIGHT_TO_LEFT.flagValue) fun defaultReadingMode() = this.preferenceStore.getInt(Keys.defaultReadingMode, ReadingModeType.RIGHT_TO_LEFT.flagValue)
fun defaultOrientationType() = prefs.getInt(Keys.defaultOrientationType, OrientationType.FREE.flagValue) fun defaultOrientationType() = this.preferenceStore.getInt(Keys.defaultOrientationType, OrientationType.FREE.flagValue)
fun imageScaleType() = flowPrefs.getInt("pref_image_scale_type_key", 1) fun imageScaleType() = this.preferenceStore.getInt("pref_image_scale_type_key", 1)
fun zoomStart() = flowPrefs.getInt("pref_zoom_start_key", 1) fun zoomStart() = this.preferenceStore.getInt("pref_zoom_start_key", 1)
fun readerTheme() = flowPrefs.getInt("pref_reader_theme_key", 3) fun readerTheme() = this.preferenceStore.getInt("pref_reader_theme_key", 3)
fun alwaysShowChapterTransition() = flowPrefs.getBoolean("always_show_chapter_transition", true) fun alwaysShowChapterTransition() = this.preferenceStore.getBoolean("always_show_chapter_transition", true)
fun cropBorders() = flowPrefs.getBoolean("crop_borders", false) fun cropBorders() = this.preferenceStore.getBoolean("crop_borders", false)
fun navigateToPan() = flowPrefs.getBoolean("navigate_pan", true) fun navigateToPan() = this.preferenceStore.getBoolean("navigate_pan", true)
fun landscapeZoom() = flowPrefs.getBoolean("landscape_zoom", true) fun landscapeZoom() = this.preferenceStore.getBoolean("landscape_zoom", true)
fun cropBordersWebtoon() = flowPrefs.getBoolean("crop_borders_webtoon", false) fun cropBordersWebtoon() = this.preferenceStore.getBoolean("crop_borders_webtoon", false)
fun webtoonSidePadding() = flowPrefs.getInt("webtoon_side_padding", 0) fun webtoonSidePadding() = this.preferenceStore.getInt("webtoon_side_padding", 0)
fun readWithTapping() = flowPrefs.getBoolean("reader_tap", true) fun readWithTapping() = this.preferenceStore.getBoolean("reader_tap", true)
fun pagerNavInverted() = flowPrefs.getEnum("reader_tapping_inverted", Values.TappingInvertMode.NONE) fun pagerNavInverted() = this.preferenceStore.getEnum("reader_tapping_inverted", Values.TappingInvertMode.NONE)
fun webtoonNavInverted() = flowPrefs.getEnum("reader_tapping_inverted_webtoon", Values.TappingInvertMode.NONE) fun webtoonNavInverted() = this.preferenceStore.getEnum("reader_tapping_inverted_webtoon", Values.TappingInvertMode.NONE)
fun readWithLongTap() = flowPrefs.getBoolean("reader_long_tap", true) fun readWithLongTap() = this.preferenceStore.getBoolean("reader_long_tap", true)
fun readWithVolumeKeys() = flowPrefs.getBoolean("reader_volume_keys", false) fun readWithVolumeKeys() = this.preferenceStore.getBoolean("reader_volume_keys", false)
fun readWithVolumeKeysInverted() = flowPrefs.getBoolean("reader_volume_keys_inverted", false) fun readWithVolumeKeysInverted() = this.preferenceStore.getBoolean("reader_volume_keys_inverted", false)
fun navigationModePager() = flowPrefs.getInt("reader_navigation_mode_pager", 0) fun navigationModePager() = this.preferenceStore.getInt("reader_navigation_mode_pager", 0)
fun navigationModeWebtoon() = flowPrefs.getInt("reader_navigation_mode_webtoon", 0) fun navigationModeWebtoon() = this.preferenceStore.getInt("reader_navigation_mode_webtoon", 0)
fun showNavigationOverlayNewUser() = flowPrefs.getBoolean("reader_navigation_overlay_new_user", true) fun showNavigationOverlayNewUser() = this.preferenceStore.getBoolean("reader_navigation_overlay_new_user", true)
fun showNavigationOverlayOnStart() = flowPrefs.getBoolean("reader_navigation_overlay_on_start", false) fun showNavigationOverlayOnStart() = this.preferenceStore.getBoolean("reader_navigation_overlay_on_start", false)
fun readerHideThreshold() = flowPrefs.getEnum("reader_hide_threshold", Values.ReaderHideThreshold.LOW) fun readerHideThreshold() = this.preferenceStore.getEnum("reader_hide_threshold", Values.ReaderHideThreshold.LOW)
fun portraitColumns() = flowPrefs.getInt("pref_library_columns_portrait_key", 0) fun portraitColumns() = this.preferenceStore.getInt("pref_library_columns_portrait_key", 0)
fun landscapeColumns() = flowPrefs.getInt("pref_library_columns_landscape_key", 0) fun landscapeColumns() = this.preferenceStore.getInt("pref_library_columns_landscape_key", 0)
fun autoUpdateTrack() = prefs.getBoolean(Keys.autoUpdateTrack, true) fun autoUpdateTrack() = this.preferenceStore.getBoolean(Keys.autoUpdateTrack, true)
fun lastUsedSource() = flowPrefs.getLong("last_catalogue_source", -1) fun lastUsedSource() = this.preferenceStore.getLong("last_catalogue_source", -1)
fun lastUsedCategory() = flowPrefs.getInt("last_used_category", 0) fun lastUsedCategory() = this.preferenceStore.getInt("last_used_category", 0)
fun lastVersionCode() = flowPrefs.getInt("last_version_code", 0) fun lastVersionCode() = this.preferenceStore.getInt("last_version_code", 0)
fun sourceDisplayMode() = flowPrefs.getObject("pref_display_mode_catalogue", LibraryDisplayMode.Serializer, LibraryDisplayMode.default) fun sourceDisplayMode() = this.preferenceStore.getObject("pref_display_mode_catalogue", LibraryDisplayMode.default, LibraryDisplayMode.Serializer::serialize, LibraryDisplayMode.Serializer::deserialize)
fun enabledLanguages() = flowPrefs.getStringSet("source_languages", LocaleHelper.getDefaultEnabledLanguages()) fun enabledLanguages() = this.preferenceStore.getStringSet("source_languages", LocaleHelper.getDefaultEnabledLanguages())
fun trackUsername(sync: TrackService) = prefs.getString(Keys.trackUsername(sync.id), "") fun trackUsername(sync: TrackService) = this.preferenceStore.getString(Keys.trackUsername(sync.id), "")
fun trackPassword(sync: TrackService) = prefs.getString(Keys.trackPassword(sync.id), "") fun trackPassword(sync: TrackService) = this.preferenceStore.getString(Keys.trackPassword(sync.id), "")
fun setTrackCredentials(sync: TrackService, username: String, password: String) { fun setTrackCredentials(sync: TrackService, username: String, password: String) {
prefs.edit { trackUsername(sync).set(username)
putString(Keys.trackUsername(sync.id), username) trackPassword(sync).set(password)
putString(Keys.trackPassword(sync.id), password)
}
} }
fun trackToken(sync: TrackService) = flowPrefs.getString(Keys.trackToken(sync.id), "") fun trackToken(sync: TrackService) = this.preferenceStore.getString(Keys.trackToken(sync.id), "")
fun anilistScoreType() = flowPrefs.getString("anilist_score_type", Anilist.POINT_10) fun anilistScoreType() = this.preferenceStore.getString("anilist_score_type", Anilist.POINT_10)
fun backupsDirectory() = flowPrefs.getString("backup_directory", defaultBackupDir.toString()) fun backupsDirectory() = this.preferenceStore.getString("backup_directory", defaultBackupDir.toString())
fun relativeTime() = flowPrefs.getInt("relative_time", 7) fun relativeTime() = this.preferenceStore.getInt("relative_time", 7)
fun dateFormat(format: String = flowPrefs.getString(Keys.dateFormat, "").get()): DateFormat = when (format) { fun dateFormat(format: String = this.preferenceStore.getString(Keys.dateFormat, "").get()): DateFormat = when (format) {
"" -> DateFormat.getDateInstance(DateFormat.SHORT) "" -> DateFormat.getDateInstance(DateFormat.SHORT)
else -> SimpleDateFormat(format, Locale.getDefault()) else -> SimpleDateFormat(format, Locale.getDefault())
} }
fun downloadsDirectory() = flowPrefs.getString("download_directory", defaultDownloadsDir.toString()) fun downloadsDirectory() = this.preferenceStore.getString("download_directory", defaultDownloadsDir.toString())
fun downloadOnlyOverWifi() = prefs.getBoolean(Keys.downloadOnlyOverWifi, true) fun downloadOnlyOverWifi() = this.preferenceStore.getBoolean(Keys.downloadOnlyOverWifi, true)
fun saveChaptersAsCBZ() = flowPrefs.getBoolean("save_chapter_as_cbz", true) fun saveChaptersAsCBZ() = this.preferenceStore.getBoolean("save_chapter_as_cbz", true)
fun splitTallImages() = flowPrefs.getBoolean("split_tall_images", false) fun splitTallImages() = this.preferenceStore.getBoolean("split_tall_images", false)
fun folderPerManga() = prefs.getBoolean(Keys.folderPerManga, false) fun folderPerManga() = this.preferenceStore.getBoolean(Keys.folderPerManga, false)
fun numberOfBackups() = flowPrefs.getInt("backup_slots", 2) fun numberOfBackups() = this.preferenceStore.getInt("backup_slots", 2)
fun backupInterval() = flowPrefs.getInt("backup_interval", 12) fun backupInterval() = this.preferenceStore.getInt("backup_interval", 12)
fun removeAfterReadSlots() = prefs.getInt(Keys.removeAfterReadSlots, -1) fun removeAfterReadSlots() = this.preferenceStore.getInt(Keys.removeAfterReadSlots, -1)
fun removeAfterMarkedAsRead() = prefs.getBoolean(Keys.removeAfterMarkedAsRead, false) fun removeAfterMarkedAsRead() = this.preferenceStore.getBoolean(Keys.removeAfterMarkedAsRead, false)
fun removeBookmarkedChapters() = prefs.getBoolean(Keys.removeBookmarkedChapters, false) fun removeBookmarkedChapters() = this.preferenceStore.getBoolean(Keys.removeBookmarkedChapters, false)
fun removeExcludeCategories() = flowPrefs.getStringSet("remove_exclude_categories", emptySet()) fun removeExcludeCategories() = this.preferenceStore.getStringSet("remove_exclude_categories", emptySet())
fun libraryUpdateInterval() = flowPrefs.getInt("pref_library_update_interval_key", 24) fun libraryUpdateInterval() = this.preferenceStore.getInt("pref_library_update_interval_key", 24)
fun libraryUpdateLastTimestamp() = flowPrefs.getLong("library_update_last_timestamp", 0L) fun libraryUpdateLastTimestamp() = this.preferenceStore.getLong("library_update_last_timestamp", 0L)
fun libraryUpdateDeviceRestriction() = flowPrefs.getStringSet("library_update_restriction", setOf(DEVICE_ONLY_ON_WIFI)) fun libraryUpdateDeviceRestriction() = this.preferenceStore.getStringSet("library_update_restriction", setOf(DEVICE_ONLY_ON_WIFI))
fun libraryUpdateMangaRestriction() = flowPrefs.getStringSet("library_update_manga_restriction", setOf(MANGA_HAS_UNREAD, MANGA_NON_COMPLETED, MANGA_NON_READ)) fun libraryUpdateMangaRestriction() = this.preferenceStore.getStringSet("library_update_manga_restriction", setOf(MANGA_HAS_UNREAD, MANGA_NON_COMPLETED, MANGA_NON_READ))
fun showUpdatesNavBadge() = flowPrefs.getBoolean("library_update_show_tab_badge", false) fun showUpdatesNavBadge() = this.preferenceStore.getBoolean("library_update_show_tab_badge", false)
fun unreadUpdatesCount() = flowPrefs.getInt("library_unread_updates_count", 0) fun unreadUpdatesCount() = this.preferenceStore.getInt("library_unread_updates_count", 0)
fun libraryUpdateCategories() = flowPrefs.getStringSet("library_update_categories", emptySet()) fun libraryUpdateCategories() = this.preferenceStore.getStringSet("library_update_categories", emptySet())
fun libraryUpdateCategoriesExclude() = flowPrefs.getStringSet("library_update_categories_exclude", emptySet()) fun libraryUpdateCategoriesExclude() = this.preferenceStore.getStringSet("library_update_categories_exclude", emptySet())
fun libraryDisplayMode() = flowPrefs.getObject("pref_display_mode_library", LibraryDisplayMode.Serializer, LibraryDisplayMode.default) fun libraryDisplayMode() = this.preferenceStore.getObject("pref_display_mode_library", LibraryDisplayMode.default, LibraryDisplayMode.Serializer::serialize, LibraryDisplayMode.Serializer::deserialize)
fun downloadBadge() = flowPrefs.getBoolean("display_download_badge", false) fun downloadBadge() = this.preferenceStore.getBoolean("display_download_badge", false)
fun localBadge() = flowPrefs.getBoolean("display_local_badge", true) fun localBadge() = this.preferenceStore.getBoolean("display_local_badge", true)
fun downloadedOnly() = flowPrefs.getBoolean("pref_downloaded_only", false) fun downloadedOnly() = this.preferenceStore.getBoolean("pref_downloaded_only", false)
fun unreadBadge() = flowPrefs.getBoolean("display_unread_badge", true) fun unreadBadge() = this.preferenceStore.getBoolean("display_unread_badge", true)
fun languageBadge() = flowPrefs.getBoolean("display_language_badge", false) fun languageBadge() = this.preferenceStore.getBoolean("display_language_badge", false)
fun categoryTabs() = flowPrefs.getBoolean("display_category_tabs", true) fun categoryTabs() = this.preferenceStore.getBoolean("display_category_tabs", true)
fun categoryNumberOfItems() = flowPrefs.getBoolean("display_number_of_items", false) fun categoryNumberOfItems() = this.preferenceStore.getBoolean("display_number_of_items", false)
fun filterDownloaded() = flowPrefs.getInt(Keys.filterDownloaded, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value) fun filterDownloaded() = this.preferenceStore.getInt(Keys.filterDownloaded, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
fun filterUnread() = flowPrefs.getInt(Keys.filterUnread, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value) fun filterUnread() = this.preferenceStore.getInt(Keys.filterUnread, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
fun filterStarted() = flowPrefs.getInt(Keys.filterStarted, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value) fun filterStarted() = this.preferenceStore.getInt(Keys.filterStarted, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
fun filterCompleted() = flowPrefs.getInt(Keys.filterCompleted, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value) fun filterCompleted() = this.preferenceStore.getInt(Keys.filterCompleted, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
fun filterTracking(name: Long) = flowPrefs.getInt("${Keys.filterTracked}_$name", ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value) fun filterTracking(name: Long) = this.preferenceStore.getInt("${Keys.filterTracked}_$name", ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
fun filterLewd() = flowPrefs.getInt(Keys.filterLewd, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value) fun filterLewd() = this.preferenceStore.getInt(Keys.filterLewd, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
fun librarySortingMode() = flowPrefs.getObject(Keys.librarySortingMode, LibrarySort.Serializer, LibrarySort.default) fun filterTracking(name: Int) = this.preferenceStore.getInt("${Keys.filterTracked}_$name", ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
fun migrationSortingMode() = flowPrefs.getEnum(Keys.migrationSortingMode, SetMigrateSorting.Mode.ALPHABETICAL) fun librarySortingMode() = this.preferenceStore.getObject(Keys.librarySortingMode, LibrarySort.default, LibrarySort.Serializer::serialize, LibrarySort.Serializer::deserialize)
fun migrationSortingDirection() = flowPrefs.getEnum(Keys.migrationSortingDirection, SetMigrateSorting.Direction.ASCENDING)
fun automaticExtUpdates() = flowPrefs.getBoolean("automatic_ext_updates", true) fun migrationSortingMode() = this.preferenceStore.getEnum(Keys.migrationSortingMode, SetMigrateSorting.Mode.ALPHABETICAL)
fun migrationSortingDirection() = this.preferenceStore.getEnum(Keys.migrationSortingDirection, SetMigrateSorting.Direction.ASCENDING)
fun showNsfwSource() = flowPrefs.getBoolean("show_nsfw_source", true) fun automaticExtUpdates() = this.preferenceStore.getBoolean("automatic_ext_updates", true)
fun extensionUpdatesCount() = flowPrefs.getInt("ext_updates_count", 0) fun showNsfwSource() = this.preferenceStore.getBoolean("show_nsfw_source", true)
fun lastAppCheck() = flowPrefs.getLong("last_app_check", 0) fun extensionUpdatesCount() = this.preferenceStore.getInt("ext_updates_count", 0)
fun lastExtCheck() = flowPrefs.getLong("last_ext_check", 0)
fun searchPinnedSourcesOnly() = prefs.getBoolean(Keys.searchPinnedSourcesOnly, false) fun lastAppCheck() = this.preferenceStore.getLong("last_app_check", 0)
fun lastExtCheck() = this.preferenceStore.getLong("last_ext_check", 0)
fun disabledSources() = flowPrefs.getStringSet("hidden_catalogues", emptySet()) fun searchPinnedSourcesOnly() = this.preferenceStore.getBoolean(Keys.searchPinnedSourcesOnly, false)
fun pinnedSources() = flowPrefs.getStringSet("pinned_catalogues", emptySet()) fun disabledSources() = this.preferenceStore.getStringSet("hidden_catalogues", emptySet())
fun downloadNewChapters() = flowPrefs.getBoolean("download_new", false) fun pinnedSources() = this.preferenceStore.getStringSet("pinned_catalogues", emptySet())
fun downloadNewChapterCategories() = flowPrefs.getStringSet("download_new_categories", emptySet()) fun downloadNewChapters() = this.preferenceStore.getBoolean("download_new", false)
fun downloadNewChapterCategoriesExclude() = flowPrefs.getStringSet("download_new_categories_exclude", emptySet())
fun autoDownloadWhileReading() = flowPrefs.getInt("auto_download_while_reading", 0) fun downloadNewChapterCategories() = this.preferenceStore.getStringSet("download_new_categories", emptySet())
fun downloadNewChapterCategoriesExclude() = this.preferenceStore.getStringSet("download_new_categories_exclude", emptySet())
fun defaultCategory() = prefs.getInt(Keys.defaultCategory, -1) fun autoDownloadWhileReading() = this.preferenceStore.getInt("auto_download_while_reading", 0)
fun categorizedDisplaySettings() = flowPrefs.getBoolean("categorized_display", false) fun defaultCategory() = this.preferenceStore.getInt(Keys.defaultCategory, -1)
fun skipRead() = prefs.getBoolean(Keys.skipRead, false) fun categorizedDisplaySettings() = this.preferenceStore.getBoolean("categorized_display", false)
fun skipFiltered() = prefs.getBoolean(Keys.skipFiltered, true) fun skipRead() = this.preferenceStore.getBoolean(Keys.skipRead, false)
fun migrateFlags() = flowPrefs.getInt("migrate_flags", Int.MAX_VALUE) fun skipFiltered() = this.preferenceStore.getBoolean(Keys.skipFiltered, true)
fun trustedSignatures() = flowPrefs.getStringSet("trusted_signatures", emptySet()) fun migrateFlags() = this.preferenceStore.getInt("migrate_flags", Int.MAX_VALUE)
fun dohProvider() = prefs.getInt(Keys.dohProvider, -1) fun trustedSignatures() = this.preferenceStore.getStringSet("trusted_signatures", emptySet())
fun defaultUserAgent() = flowPrefs.getString(Keys.defaultUserAgent, "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0") fun filterChapterByRead() = this.preferenceStore.getInt(Keys.defaultChapterFilterByRead, DomainManga.SHOW_ALL.toInt())
fun filterChapterByRead() = prefs.getInt(Keys.defaultChapterFilterByRead, DomainManga.SHOW_ALL.toInt()) fun filterChapterByDownloaded() = this.preferenceStore.getInt(Keys.defaultChapterFilterByDownloaded, DomainManga.SHOW_ALL.toInt())
fun filterChapterByDownloaded() = prefs.getInt(Keys.defaultChapterFilterByDownloaded, DomainManga.SHOW_ALL.toInt()) fun filterChapterByBookmarked() = this.preferenceStore.getInt(Keys.defaultChapterFilterByBookmarked, DomainManga.SHOW_ALL.toInt())
fun filterChapterByBookmarked() = prefs.getInt(Keys.defaultChapterFilterByBookmarked, DomainManga.SHOW_ALL.toInt()) fun sortChapterBySourceOrNumber() = this.preferenceStore.getInt(Keys.defaultChapterSortBySourceOrNumber, DomainManga.CHAPTER_SORTING_SOURCE.toInt())
fun sortChapterBySourceOrNumber() = prefs.getInt(Keys.defaultChapterSortBySourceOrNumber, DomainManga.CHAPTER_SORTING_SOURCE.toInt()) fun displayChapterByNameOrNumber() = this.preferenceStore.getInt(Keys.defaultChapterDisplayByNameOrNumber, DomainManga.CHAPTER_DISPLAY_NAME.toInt())
fun displayChapterByNameOrNumber() = prefs.getInt(Keys.defaultChapterDisplayByNameOrNumber, DomainManga.CHAPTER_DISPLAY_NAME.toInt()) fun sortChapterByAscendingOrDescending() = this.preferenceStore.getInt(Keys.defaultChapterSortByAscendingOrDescending, DomainManga.CHAPTER_SORT_DESC.toInt())
fun sortChapterByAscendingOrDescending() = prefs.getInt(Keys.defaultChapterSortByAscendingOrDescending, DomainManga.CHAPTER_SORT_DESC.toInt()) fun incognitoMode() = this.preferenceStore.getBoolean("incognito_mode", false)
fun incognitoMode() = flowPrefs.getBoolean("incognito_mode", false) fun tabletUiMode() = this.preferenceStore.getEnum("tablet_ui_mode", Values.TabletUiMode.AUTOMATIC)
fun tabletUiMode() = flowPrefs.getEnum("tablet_ui_mode", Values.TabletUiMode.AUTOMATIC) fun extensionInstaller() = this.preferenceStore.getEnum(
fun extensionInstaller() = flowPrefs.getEnum(
"extension_installer", "extension_installer",
if (DeviceUtil.isMiui) Values.ExtensionInstaller.LEGACY else Values.ExtensionInstaller.PACKAGEINSTALLER, if (DeviceUtil.isMiui) Values.ExtensionInstaller.LEGACY else Values.ExtensionInstaller.PACKAGEINSTALLER,
) )
fun verboseLogging() = prefs.getBoolean(Keys.verboseLogging, isDevFlavor) fun autoClearChapterCache() = this.preferenceStore.getBoolean(Keys.autoClearChapterCache, false)
fun autoClearChapterCache() = prefs.getBoolean(Keys.autoClearChapterCache, false) fun duplicatePinnedSources() = this.preferenceStore.getBoolean("duplicate_pinned_sources", false)
fun duplicatePinnedSources() = flowPrefs.getBoolean("duplicate_pinned_sources", false)
fun setChapterSettingsDefault(manga: Manga) { fun setChapterSettingsDefault(manga: Manga) {
prefs.edit { filterChapterByRead().set(manga.readFilter)
putInt(Keys.defaultChapterFilterByRead, manga.readFilter) filterChapterByDownloaded().set(manga.downloadedFilter)
putInt(Keys.defaultChapterFilterByDownloaded, manga.downloadedFilter) filterChapterByBookmarked().set(manga.bookmarkedFilter)
putInt(Keys.defaultChapterFilterByBookmarked, manga.bookmarkedFilter) sortChapterBySourceOrNumber().set(manga.sorting)
putInt(Keys.defaultChapterSortBySourceOrNumber, manga.sorting) displayChapterByNameOrNumber().set(manga.displayMode)
putInt(Keys.defaultChapterDisplayByNameOrNumber, manga.displayMode) sortChapterByAscendingOrDescending().set(if (manga.sortDescending()) DomainManga.CHAPTER_SORT_DESC.toInt() else DomainManga.CHAPTER_SORT_ASC.toInt())
putInt(Keys.defaultChapterSortByAscendingOrDescending, if (manga.sortDescending()) DomainManga.CHAPTER_SORT_DESC.toInt() else DomainManga.CHAPTER_SORT_ASC.toInt())
}
} }
// SY --> // SY -->
fun defaultMangaOrder() = flowPrefs.getString("default_manga_order", "") fun defaultMangaOrder() = this.preferenceStore.getString("default_manga_order", "")
fun migrationSources() = flowPrefs.getString("migrate_sources", "") fun migrationSources() = this.preferenceStore.getString("migrate_sources", "")
fun smartMigration() = flowPrefs.getBoolean("smart_migrate", false) fun smartMigration() = this.preferenceStore.getBoolean("smart_migrate", false)
fun useSourceWithMost() = flowPrefs.getBoolean("use_source_with_most", false) fun useSourceWithMost() = this.preferenceStore.getBoolean("use_source_with_most", false)
fun skipPreMigration() = flowPrefs.getBoolean("skip_pre_migration", false) fun skipPreMigration() = this.preferenceStore.getBoolean("skip_pre_migration", false)
fun hideNotFoundMigration() = flowPrefs.getBoolean("hide_not_found_migration", false) fun hideNotFoundMigration() = this.preferenceStore.getBoolean("hide_not_found_migration", false)
fun isHentaiEnabled() = flowPrefs.getBoolean("eh_is_hentai_enabled", true) fun isHentaiEnabled() = this.preferenceStore.getBoolean("eh_is_hentai_enabled", true)
fun enableExhentai() = flowPrefs.getBoolean("enable_exhentai", false) fun enableExhentai() = this.preferenceStore.getBoolean("enable_exhentai", false)
fun imageQuality() = flowPrefs.getString("ehentai_quality", "auto") fun imageQuality() = this.preferenceStore.getString("ehentai_quality", "auto")
fun useHentaiAtHome() = flowPrefs.getInt("eh_enable_hah", 0) fun useHentaiAtHome() = this.preferenceStore.getInt("eh_enable_hah", 0)
fun useJapaneseTitle() = flowPrefs.getBoolean("use_jp_title", false) fun useJapaneseTitle() = this.preferenceStore.getBoolean("use_jp_title", false)
fun exhUseOriginalImages() = flowPrefs.getBoolean("eh_useOrigImages", false) fun exhUseOriginalImages() = this.preferenceStore.getBoolean("eh_useOrigImages", false)
fun ehTagFilterValue() = flowPrefs.getInt("eh_tag_filtering_value", 0) fun ehTagFilterValue() = this.preferenceStore.getInt("eh_tag_filtering_value", 0)
fun ehTagWatchingValue() = flowPrefs.getInt("eh_tag_watching_value", 0) fun ehTagWatchingValue() = this.preferenceStore.getInt("eh_tag_watching_value", 0)
// EH Cookies // EH Cookies
fun memberIdVal() = flowPrefs.getString("eh_ipb_member_id", "") fun memberIdVal() = this.preferenceStore.getString("eh_ipb_member_id", "")
fun passHashVal() = flowPrefs.getString("eh_ipb_pass_hash", "") fun passHashVal() = this.preferenceStore.getString("eh_ipb_pass_hash", "")
fun igneousVal() = flowPrefs.getString("eh_igneous", "") fun igneousVal() = this.preferenceStore.getString("eh_igneous", "")
fun ehSettingsProfile() = flowPrefs.getInt("eh_ehSettingsProfile", -1) fun ehSettingsProfile() = this.preferenceStore.getInt("eh_ehSettingsProfile", -1)
fun exhSettingsProfile() = flowPrefs.getInt("eh_exhSettingsProfile", -1) fun exhSettingsProfile() = this.preferenceStore.getInt("eh_exhSettingsProfile", -1)
fun exhSettingsKey() = flowPrefs.getString("eh_settingsKey", "") fun exhSettingsKey() = this.preferenceStore.getString("eh_settingsKey", "")
fun exhSessionCookie() = flowPrefs.getString("eh_sessionCookie", "") fun exhSessionCookie() = this.preferenceStore.getString("eh_sessionCookie", "")
fun exhHathPerksCookies() = flowPrefs.getString("eh_hathPerksCookie", "") fun exhHathPerksCookies() = this.preferenceStore.getString("eh_hathPerksCookie", "")
fun exhShowSyncIntro() = flowPrefs.getBoolean("eh_show_sync_intro", true) fun exhShowSyncIntro() = this.preferenceStore.getBoolean("eh_show_sync_intro", true)
fun exhReadOnlySync() = flowPrefs.getBoolean("eh_sync_read_only", false) fun exhReadOnlySync() = this.preferenceStore.getBoolean("eh_sync_read_only", false)
fun exhLenientSync() = flowPrefs.getBoolean("eh_lenient_sync", false) fun exhLenientSync() = this.preferenceStore.getBoolean("eh_lenient_sync", false)
fun exhShowSettingsUploadWarning() = flowPrefs.getBoolean("eh_showSettingsUploadWarning2", true) fun exhShowSettingsUploadWarning() = this.preferenceStore.getBoolean("eh_showSettingsUploadWarning2", true)
fun expandFilters() = flowPrefs.getBoolean("eh_expand_filters", false) fun expandFilters() = this.preferenceStore.getBoolean("eh_expand_filters", false)
fun readerThreads() = flowPrefs.getInt("eh_reader_threads", 2) fun readerThreads() = this.preferenceStore.getInt("eh_reader_threads", 2)
fun readerInstantRetry() = flowPrefs.getBoolean("eh_reader_instant_retry", true) fun readerInstantRetry() = this.preferenceStore.getBoolean("eh_reader_instant_retry", true)
fun autoscrollInterval() = flowPrefs.getFloat("eh_util_autoscroll_interval", 3f) fun autoscrollInterval() = this.preferenceStore.getFloat("eh_util_autoscroll_interval", 3f)
fun cacheSize() = flowPrefs.getString("eh_cache_size", "75") fun cacheSize() = this.preferenceStore.getString("eh_cache_size", "75")
fun preserveReadingPosition() = flowPrefs.getBoolean("eh_preserve_reading_position", false) fun preserveReadingPosition() = this.preferenceStore.getBoolean("eh_preserve_reading_position", false)
fun autoSolveCaptcha() = flowPrefs.getBoolean("eh_autosolve_captchas", false) fun autoSolveCaptcha() = this.preferenceStore.getBoolean("eh_autosolve_captchas", false)
fun delegateSources() = flowPrefs.getBoolean("eh_delegate_sources", true) fun ehLastVersionCode() = this.preferenceStore.getInt("eh_last_version_code", 0)
fun ehLastVersionCode() = flowPrefs.getInt("eh_last_version_code", 0) fun logLevel() = this.preferenceStore.getInt(Keys.eh_logLevel, 0)
fun logLevel() = flowPrefs.getInt(Keys.eh_logLevel, 0) fun enableSourceBlacklist() = this.preferenceStore.getBoolean("eh_enable_source_blacklist", true)
fun enableSourceBlacklist() = flowPrefs.getBoolean("eh_enable_source_blacklist", true) fun exhAutoUpdateFrequency() = this.preferenceStore.getInt("eh_auto_update_frequency", 1)
fun exhAutoUpdateFrequency() = flowPrefs.getInt("eh_auto_update_frequency", 1) fun exhAutoUpdateRequirements() = this.preferenceStore.getStringSet("eh_auto_update_restrictions", emptySet())
fun exhAutoUpdateRequirements() = flowPrefs.getStringSet("eh_auto_update_restrictions", emptySet()) fun exhAutoUpdateStats() = this.preferenceStore.getString("eh_auto_update_stats", "")
fun exhAutoUpdateStats() = flowPrefs.getString("eh_auto_update_stats", "") fun aggressivePageLoading() = this.preferenceStore.getBoolean("eh_aggressive_page_loading", false)
fun aggressivePageLoading() = flowPrefs.getBoolean("eh_aggressive_page_loading", false) fun preloadSize() = this.preferenceStore.getInt("eh_preload_size", 10)
fun preloadSize() = flowPrefs.getInt("eh_preload_size", 10) fun useAutoWebtoon() = this.preferenceStore.getBoolean("eh_use_auto_webtoon", true)
fun useAutoWebtoon() = flowPrefs.getBoolean("eh_use_auto_webtoon", true) fun exhWatchedListDefaultState() = this.preferenceStore.getBoolean("eh_watched_list_default_state", false)
fun exhWatchedListDefaultState() = flowPrefs.getBoolean("eh_watched_list_default_state", false) fun exhSettingsLanguages() = this.preferenceStore.getString(
fun exhSettingsLanguages() = flowPrefs.getString(
"eh_settings_languages", "eh_settings_languages",
"false*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false", "false*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false",
) )
fun exhEnabledCategories() = flowPrefs.getString( fun exhEnabledCategories() = this.preferenceStore.getString(
"eh_enabled_categories", "eh_enabled_categories",
"false,false,false,false,false,false,false,false,false,false", "false,false,false,false,false,false,false,false,false,false",
) )
fun feedTabInFront() = flowPrefs.getBoolean("latest_tab_position", false) fun feedTabInFront() = this.preferenceStore.getBoolean("latest_tab_position", false)
fun sourcesTabCategories() = flowPrefs.getStringSet("sources_tab_categories", mutableSetOf()) fun sourcesTabCategories() = this.preferenceStore.getStringSet("sources_tab_categories", mutableSetOf())
fun sourcesTabCategoriesFilter() = flowPrefs.getBoolean("sources_tab_categories_filter", false) fun sourcesTabCategoriesFilter() = this.preferenceStore.getBoolean("sources_tab_categories_filter", false)
fun sourcesTabSourcesInCategories() = flowPrefs.getStringSet("sources_tab_source_categories", mutableSetOf()) fun sourcesTabSourcesInCategories() = this.preferenceStore.getStringSet("sources_tab_source_categories", mutableSetOf())
fun sourceSorting() = flowPrefs.getInt("sources_sort", 0) fun sourceSorting() = this.preferenceStore.getInt("sources_sort", 0)
fun recommendsInOverflow() = flowPrefs.getBoolean("recommends_in_overflow", false) fun recommendsInOverflow() = this.preferenceStore.getBoolean("recommends_in_overflow", false)
fun mergeInOverflow() = flowPrefs.getBoolean("merge_in_overflow", false) fun mergeInOverflow() = this.preferenceStore.getBoolean("merge_in_overflow", false)
fun enhancedEHentaiView() = flowPrefs.getBoolean("enhanced_e_hentai_view", true) fun enhancedEHentaiView() = this.preferenceStore.getBoolean("enhanced_e_hentai_view", true)
fun webtoonEnableZoomOut() = flowPrefs.getBoolean("webtoon_enable_zoom_out", false) fun webtoonEnableZoomOut() = this.preferenceStore.getBoolean("webtoon_enable_zoom_out", false)
fun startReadingButton() = flowPrefs.getBoolean("start_reading_button", true) fun startReadingButton() = this.preferenceStore.getBoolean("start_reading_button", true)
fun groupLibraryBy() = flowPrefs.getInt("group_library_by", LibraryGroup.BY_DEFAULT) fun groupLibraryBy() = this.preferenceStore.getInt("group_library_by", LibraryGroup.BY_DEFAULT)
fun continuousVerticalTappingByPage() = flowPrefs.getBoolean("continuous_vertical_tapping_by_page", false) fun continuousVerticalTappingByPage() = this.preferenceStore.getBoolean("continuous_vertical_tapping_by_page", false)
fun groupLibraryUpdateType() = flowPrefs.getEnum("group_library_update_type", Values.GroupLibraryMode.GLOBAL) fun groupLibraryUpdateType() = this.preferenceStore.getEnum("group_library_update_type", Values.GroupLibraryMode.GLOBAL)
fun useNewSourceNavigation() = flowPrefs.getBoolean("use_new_source_navigation", true) fun useNewSourceNavigation() = this.preferenceStore.getBoolean("use_new_source_navigation", true)
fun preferredMangaDexId() = flowPrefs.getString("preferred_mangaDex_id", "0") fun preferredMangaDexId() = this.preferenceStore.getString("preferred_mangaDex_id", "0")
fun mangadexSyncToLibraryIndexes() = flowPrefs.getStringSet("pref_mangadex_sync_to_library_indexes", emptySet()) fun mangadexSyncToLibraryIndexes() = this.preferenceStore.getStringSet("pref_mangadex_sync_to_library_indexes", emptySet())
fun dataSaver() = flowPrefs.getBoolean("data_saver", false) fun dataSaver() = this.preferenceStore.getBoolean("data_saver", false)
fun dataSaverIgnoreJpeg() = flowPrefs.getBoolean("ignore_jpeg", false) fun dataSaverIgnoreJpeg() = this.preferenceStore.getBoolean("ignore_jpeg", false)
fun dataSaverIgnoreGif() = flowPrefs.getBoolean("ignore_gif", true) fun dataSaverIgnoreGif() = this.preferenceStore.getBoolean("ignore_gif", true)
fun dataSaverImageQuality() = flowPrefs.getInt("data_saver_image_quality", 80) fun dataSaverImageQuality() = this.preferenceStore.getInt("data_saver_image_quality", 80)
fun dataSaverImageFormatJpeg() = flowPrefs.getBoolean("data_saver_image_format_jpeg", false) fun dataSaverImageFormatJpeg() = this.preferenceStore.getBoolean("data_saver_image_format_jpeg", false)
fun dataSaverServer() = flowPrefs.getString("data_saver_server", "") fun dataSaverServer() = this.preferenceStore.getString("data_saver_server", "")
fun dataSaverColorBW() = flowPrefs.getBoolean("data_saver_color_bw", false) fun dataSaverColorBW() = this.preferenceStore.getBoolean("data_saver_color_bw", false)
fun dataSaverExcludedSources() = flowPrefs.getStringSet("data_saver_excluded", emptySet()) fun dataSaverExcludedSources() = this.preferenceStore.getStringSet("data_saver_excluded", emptySet())
fun dataSaverDownloader() = flowPrefs.getBoolean("data_saver_downloader", true) fun dataSaverDownloader() = this.preferenceStore.getBoolean("data_saver_downloader", true)
fun allowLocalSourceHiddenFolders() = flowPrefs.getBoolean("allow_local_source_hidden_folders", false) fun allowLocalSourceHiddenFolders() = this.preferenceStore.getBoolean("allow_local_source_hidden_folders", false)
fun authenticatorTimeRanges() = flowPrefs.getStringSet("biometric_time_ranges", mutableSetOf()) fun authenticatorTimeRanges() = this.preferenceStore.getStringSet("biometric_time_ranges", mutableSetOf())
fun authenticatorDays() = flowPrefs.getInt("biometric_days", 0x7F) fun authenticatorDays() = this.preferenceStore.getInt("biometric_days", 0x7F)
fun sortTagsForLibrary() = flowPrefs.getStringSet("sort_tags_for_library", mutableSetOf()) fun sortTagsForLibrary() = this.preferenceStore.getStringSet("sort_tags_for_library", mutableSetOf())
fun extensionRepos() = flowPrefs.getStringSet("extension_repos", emptySet()) fun extensionRepos() = this.preferenceStore.getStringSet("extension_repos", emptySet())
fun cropBordersContinuousVertical() = flowPrefs.getBoolean("crop_borders_continues_vertical", false) fun cropBordersContinuousVertical() = this.preferenceStore.getBoolean("crop_borders_continues_vertical", false)
fun forceHorizontalSeekbar() = flowPrefs.getBoolean("pref_force_horz_seekbar", false) fun forceHorizontalSeekbar() = this.preferenceStore.getBoolean("pref_force_horz_seekbar", false)
fun landscapeVerticalSeekbar() = flowPrefs.getBoolean("pref_show_vert_seekbar_landscape", false) fun landscapeVerticalSeekbar() = this.preferenceStore.getBoolean("pref_show_vert_seekbar_landscape", false)
fun leftVerticalSeekbar() = flowPrefs.getBoolean("pref_left_handed_vertical_seekbar", false) fun leftVerticalSeekbar() = this.preferenceStore.getBoolean("pref_left_handed_vertical_seekbar", false)
fun readerBottomButtons() = flowPrefs.getStringSet("reader_bottom_buttons", ReaderBottomButton.BUTTONS_DEFAULTS) fun readerBottomButtons() = this.preferenceStore.getStringSet("reader_bottom_buttons", ReaderBottomButton.BUTTONS_DEFAULTS)
fun bottomBarLabels() = flowPrefs.getBoolean("pref_show_bottom_bar_labels", true) fun bottomBarLabels() = this.preferenceStore.getBoolean("pref_show_bottom_bar_labels", true)
fun showNavUpdates() = flowPrefs.getBoolean("pref_show_updates_button", true) fun showNavUpdates() = this.preferenceStore.getBoolean("pref_show_updates_button", true)
fun showNavHistory() = flowPrefs.getBoolean("pref_show_history_button", true) fun showNavHistory() = this.preferenceStore.getBoolean("pref_show_history_button", true)
fun pageLayout() = flowPrefs.getInt("page_layout", PagerConfig.PageLayout.AUTOMATIC) fun pageLayout() = this.preferenceStore.getInt("page_layout", PagerConfig.PageLayout.AUTOMATIC)
fun centerMarginType() = flowPrefs.getInt("center_margin_type", PagerConfig.CenterMarginType.NONE) fun centerMarginType() = this.preferenceStore.getInt("center_margin_type", PagerConfig.CenterMarginType.NONE)
fun invertDoublePages() = flowPrefs.getBoolean("invert_double_pages", false) fun invertDoublePages() = this.preferenceStore.getBoolean("invert_double_pages", false)
} }

View File

@ -69,9 +69,9 @@ abstract class TrackService(val id: Long) {
get() = getUsername().isNotEmpty() && get() = getUsername().isNotEmpty() &&
getPassword().isNotEmpty() getPassword().isNotEmpty()
fun getUsername() = preferences.trackUsername(this)!! fun getUsername() = preferences.trackUsername(this).get()
fun getPassword() = preferences.trackPassword(this)!! fun getPassword() = preferences.trackPassword(this).get()
fun saveCredentials(username: String, password: String) { fun saveCredentials(username: String, password: String) {
preferences.setTrackCredentials(this, username, password) preferences.setTrackCredentials(this, username, password)

View File

@ -99,6 +99,6 @@ class MangaUpdates(private val context: Context, id: Long) : TrackService(id) {
} }
fun restoreSession(): String? { fun restoreSession(): String? {
return preferences.trackPassword(this) return preferences.trackPassword(this).get()
} }
} }

View File

@ -233,7 +233,7 @@ class ExtensionManager(
.map(AvailableSources::lang) .map(AvailableSources::lang)
val deviceLanguage = Locale.getDefault().language val deviceLanguage = Locale.getDefault().language
val defaultLanguages = preferences.enabledLanguages().defaultValue val defaultLanguages = preferences.enabledLanguages().defaultValue()
val languagesToEnable = availableLanguages.filter { val languagesToEnable = availableLanguages.filter {
it != deviceLanguage && it.startsWith(deviceLanguage) it != deviceLanguage && it.startsWith(deviceLanguage)
} }

View File

@ -79,7 +79,7 @@ class SourceManager(
scope.launch { scope.launch {
extensionManager.getInstalledExtensionsFlow() extensionManager.getInstalledExtensionsFlow()
// SY --> // SY -->
.combine(preferences.enableExhentai().asFlow()) { extensions, enableExhentai -> .combine(preferences.enableExhentai().changes()) { extensions, enableExhentai ->
extensions to enableExhentai extensions to enableExhentai
} }
// SY <-- // SY <--
@ -133,7 +133,6 @@ class SourceManager(
val enhancedSource = EnhancedHttpSource( val enhancedSource = EnhancedHttpSource(
this, this,
delegate.newSourceClass.constructors.find { it.parameters.size == 2 }!!.call(this, context), delegate.newSourceClass.constructors.find { it.parameters.size == 2 }!!.call(this, context),
::delegateSources,
) )
currentDelegatedSources[enhancedSource.originalSource.id] = DelegatedSource( currentDelegatedSources[enhancedSource.originalSource.id] = DelegatedSource(
@ -157,8 +156,6 @@ class SourceManager(
// EXH <-- // EXH <--
} }
private fun delegateSources() = preferences.delegateSources().get()
fun get(sourceKey: Long): Source? { fun get(sourceKey: Long): Source? {
return sourcesMap[sourceKey] return sourcesMap[sourceKey]
} }

View File

@ -105,8 +105,8 @@ class SecureActivityDelegateImpl : SecureActivityDelegate, DefaultLifecycleObser
} }
private fun setSecureScreen() { private fun setSecureScreen() {
val secureScreenFlow = preferences.secureScreen().asFlow() val secureScreenFlow = preferences.secureScreen().changes()
val incognitoModeFlow = preferences.incognitoMode().asFlow() val incognitoModeFlow = preferences.incognitoMode().changes()
combine(secureScreenFlow, incognitoModeFlow) { secureScreen, incognitoMode -> combine(secureScreenFlow, incognitoModeFlow) { secureScreen, incognitoMode ->
secureScreen == PreferenceValues.SecureScreenMode.ALWAYS || secureScreen == PreferenceValues.SecureScreenMode.ALWAYS ||
secureScreen == PreferenceValues.SecureScreenMode.INCOGNITO && incognitoMode secureScreen == PreferenceValues.SecureScreenMode.INCOGNITO && incognitoMode

View File

@ -1,8 +1,8 @@
package eu.kanade.tachiyomi.ui.base.presenter package eu.kanade.tachiyomi.ui.base.presenter
import android.os.Bundle import android.os.Bundle
import com.fredporciuncula.flow.preferences.Preference
import eu.kanade.core.prefs.PreferenceMutableState import eu.kanade.core.prefs.PreferenceMutableState
import eu.kanade.tachiyomi.core.preference.Preference
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel

View File

@ -123,7 +123,7 @@ class ExtensionsPresenter(
presenterScope.launchIO { findAvailableExtensions() } presenterScope.launchIO { findAvailableExtensions() }
preferences.extensionUpdatesCount().asFlow() preferences.extensionUpdatesCount().changes()
.onEach { state.updates = it } .onEach { state.updates = it }
.launchIn(presenterScope) .launchIn(presenterScope)
} }

View File

@ -10,9 +10,9 @@ import android.widget.RadioButton
import android.widget.RadioGroup import android.widget.RadioGroup
import android.widget.Toast import android.widget.Toast
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.fredporciuncula.flow.preferences.Preference
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.core.preference.Preference
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.MigrationBottomSheetBinding import eu.kanade.tachiyomi.databinding.MigrationBottomSheetBinding
import eu.kanade.tachiyomi.ui.browse.migration.MigrationFlags import eu.kanade.tachiyomi.ui.browse.migration.MigrationFlags

View File

@ -42,11 +42,11 @@ class MigrationSourcesPresenter(
} }
} }
preferences.migrationSortingDirection().asFlow() preferences.migrationSortingDirection().changes()
.onEach { state.sortingDirection = it } .onEach { state.sortingDirection = it }
.launchIn(presenterScope) .launchIn(presenterScope)
preferences.migrationSortingMode().asFlow() preferences.migrationSortingMode().changes()
.onEach { state.sortingMode = it } .onEach { state.sortingMode = it }
.launchIn(presenterScope) .launchIn(presenterScope)
} }

View File

@ -147,7 +147,7 @@ open class BrowseSourcePresenter(
val isLandscape = LocalConfiguration.current.orientation == Configuration.ORIENTATION_LANDSCAPE val isLandscape = LocalConfiguration.current.orientation == Configuration.ORIENTATION_LANDSCAPE
return produceState<GridCells>(initialValue = GridCells.Adaptive(128.dp), isLandscape) { return produceState<GridCells>(initialValue = GridCells.Adaptive(128.dp), isLandscape) {
(if (isLandscape) preferences.landscapeColumns() else preferences.portraitColumns()) (if (isLandscape) preferences.landscapeColumns() else preferences.portraitColumns())
.asFlow() .changes()
.collectLatest { columns -> .collectLatest { columns ->
value = if (columns == 0) GridCells.Adaptive(128.dp) else GridCells.Fixed(columns) value = if (columns == 0) GridCells.Adaptive(128.dp) else GridCells.Fixed(columns)
} }
@ -342,7 +342,7 @@ open class BrowseSourcePresenter(
fun addFavorite(manga: DomainManga) { fun addFavorite(manga: DomainManga) {
presenterScope.launch { presenterScope.launch {
val categories = getCategories() val categories = getCategories()
val defaultCategoryId = preferences.defaultCategory() val defaultCategoryId = preferences.defaultCategory().get()
val defaultCategory = categories.find { it.id == defaultCategoryId.toLong() } val defaultCategory = categories.find { it.id == defaultCategoryId.toLong() }
when { when {

View File

@ -180,7 +180,7 @@ open class GlobalSearchController(
* @param searchResult result of search. * @param searchResult result of search.
*/ */
fun setItems(searchResult: List<GlobalSearchItem>) { fun setItems(searchResult: List<GlobalSearchItem>) {
if (searchResult.isEmpty() && preferences.searchPinnedSourcesOnly()) { if (searchResult.isEmpty() && preferences.searchPinnedSourcesOnly().get()) {
binding.emptyView.show(R.string.no_pinned_sources) binding.emptyView.show(R.string.no_pinned_sources)
} else { } else {
binding.emptyView.hide() binding.emptyView.hide()

View File

@ -125,7 +125,7 @@ open class GlobalSearchPresenter(
return filteredSources return filteredSources
} }
val onlyPinnedSources = preferences.searchPinnedSourcesOnly() val onlyPinnedSources = preferences.searchPinnedSourcesOnly().get()
val pinnedSourceIds = preferences.pinnedSources().get() val pinnedSourceIds = preferences.pinnedSources().get()
return enabledSources return enabledSources

View File

@ -30,7 +30,7 @@ class BiometricTimesPresenter(
super.onCreate(savedState) super.onCreate(savedState)
presenterScope.launchIO { presenterScope.launchIO {
// todo usecase // todo usecase
preferences.authenticatorTimeRanges().asFlow() preferences.authenticatorTimeRanges().changes()
.collectLatest { .collectLatest {
val context = view?.activity ?: Injekt.get<Application>() val context = view?.activity ?: Injekt.get<Application>()
state.isLoading = false state.isLoading = false

View File

@ -200,9 +200,9 @@ class LibraryPresenter(
// SY --> // SY -->
combine( combine(
preferences.isHentaiEnabled().asFlow(), preferences.isHentaiEnabled().changes(),
preferences.disabledSources().asFlow(), preferences.disabledSources().changes(),
preferences.enableExhentai().asFlow(), preferences.enableExhentai().changes(),
) { isHentaiEnabled, disabledSources, enableExhentai -> ) { isHentaiEnabled, disabledSources, enableExhentai ->
state.showSyncExh = isHentaiEnabled && (EH_SOURCE_ID.toString() !in disabledSources || enableExhentai) state.showSyncExh = isHentaiEnabled && (EH_SOURCE_ID.toString() !in disabledSources || enableExhentai)
}.flowOn(Dispatchers.IO).launchIn(presenterScope) }.flowOn(Dispatchers.IO).launchIn(presenterScope)

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.ui.library.setting package eu.kanade.tachiyomi.ui.library.setting
import eu.kanade.domain.category.model.Category import eu.kanade.domain.category.model.Category
import com.fredporciuncula.flow.preferences.Serializer as PreferencesSerializer
sealed class LibraryDisplayMode( sealed class LibraryDisplayMode(
override val flag: Long, override val flag: Long,
@ -14,12 +13,12 @@ sealed class LibraryDisplayMode(
object List : LibraryDisplayMode(0b00000010) object List : LibraryDisplayMode(0b00000010)
object CoverOnlyGrid : LibraryDisplayMode(0b00000011) object CoverOnlyGrid : LibraryDisplayMode(0b00000011)
object Serializer : PreferencesSerializer<LibraryDisplayMode> { object Serializer {
override fun deserialize(serialized: String): LibraryDisplayMode { fun deserialize(serialized: String): LibraryDisplayMode {
return LibraryDisplayMode.deserialize(serialized) return LibraryDisplayMode.deserialize(serialized)
} }
override fun serialize(value: LibraryDisplayMode): String { fun serialize(value: LibraryDisplayMode): String {
return value.serialize() return value.serialize()
} }
} }

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.ui.library.setting package eu.kanade.tachiyomi.ui.library.setting
import eu.kanade.domain.category.model.Category import eu.kanade.domain.category.model.Category
import com.fredporciuncula.flow.preferences.Serializer as PreferencesSerializer
data class LibrarySort( data class LibrarySort(
val type: Type, val type: Type,
@ -61,12 +60,12 @@ data class LibrarySort(
} }
} }
object Serializer : PreferencesSerializer<LibrarySort> { object Serializer {
override fun deserialize(serialized: String): LibrarySort { fun deserialize(serialized: String): LibrarySort {
return LibrarySort.deserialize(serialized) return LibrarySort.deserialize(serialized)
} }
override fun serialize(value: LibrarySort): String { fun serialize(value: LibrarySort): String {
return value.serialize() return value.serialize()
} }
} }

View File

@ -79,6 +79,8 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import logcat.LogPriority import logcat.LogPriority
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.util.LinkedList import java.util.LinkedList
@ -132,7 +134,15 @@ class MainActivity : BaseActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val didMigration = if (savedInstanceState == null) EXHMigrations.upgrade(preferences) else false val didMigration = if (savedInstanceState == null) {
EXHMigrations.upgrade(
context = applicationContext,
preferences = preferences,
networkPreferences = Injekt.get(),
)
} else {
false
}
binding = MainActivityBinding.inflate(layoutInflater) binding = MainActivityBinding.inflate(layoutInflater)
@ -288,7 +298,7 @@ class MainActivity : BaseActivity() {
} }
// SY --> // SY -->
merge(preferences.showUpdatesNavBadge().asFlow(), preferences.unreadUpdatesCount().asFlow()) merge(preferences.showUpdatesNavBadge().changes(), preferences.unreadUpdatesCount().changes())
.onEach { setUnreadUpdatesBadge() } .onEach { setUnreadUpdatesBadge() }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
@ -301,7 +311,7 @@ class MainActivity : BaseActivity() {
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
binding.incognitoMode.isVisible = preferences.incognitoMode().get() binding.incognitoMode.isVisible = preferences.incognitoMode().get()
preferences.incognitoMode().asFlow() preferences.incognitoMode().changes()
.drop(1) .drop(1)
.onEach { .onEach {
binding.incognitoMode.isVisible = it binding.incognitoMode.isVisible = it
@ -544,7 +554,7 @@ class MainActivity : BaseActivity() {
lifecycleScope.launchUI { resetExitConfirmation() } lifecycleScope.launchUI { resetExitConfirmation() }
} else if (backstackSize == 1 || !router.handleBack()) { } else if (backstackSize == 1 || !router.handleBack()) {
// Regular back (i.e. closing the app) // Regular back (i.e. closing the app)
if (preferences.autoClearChapterCache()) { if (preferences.autoClearChapterCache().get()) {
chapterCache.clear() chapterCache.clear()
} }
super.onBackPressed() super.onBackPressed()
@ -588,7 +598,7 @@ class MainActivity : BaseActivity() {
private fun shouldHandleExitConfirmation(): Boolean { private fun shouldHandleExitConfirmation(): Boolean {
return router.backstackSize == 1 && return router.backstackSize == 1 &&
router.getControllerWithTag("$startScreenId") != null && router.getControllerWithTag("$startScreenId") != null &&
preferences.confirmExit() && preferences.confirmExit().get() &&
!isConfirmingExit !isConfirmingExit
} }

View File

@ -686,7 +686,7 @@ class MangaPresenter(
// Now check if user previously set categories, when available // Now check if user previously set categories, when available
val categories = getCategories() val categories = getCategories()
val defaultCategoryId = preferences.defaultCategory().toLong() val defaultCategoryId = preferences.defaultCategory().get().toLong()
val defaultCategory = categories.find { it.id == defaultCategoryId } val defaultCategory = categories.find { it.id == defaultCategoryId }
when { when {
// Default category set // Default category set

View File

@ -246,7 +246,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
initializeMenu() initializeMenu()
// Finish when incognito mode is disabled // Finish when incognito mode is disabled
preferences.incognitoMode().asFlow() preferences.incognitoMode().changes()
.drop(1) .drop(1)
.onEach { if (!it) finish() } .onEach { if (!it) finish() }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
@ -561,7 +561,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
presenter.setMangaReadingMode(newReadingMode.flagValue) presenter.setMangaReadingMode(newReadingMode.flagValue)
menuToggleToast?.cancel() menuToggleToast?.cancel()
if (!preferences.showReadingMode()) { if (!preferences.showReadingMode().get()) {
menuToggleToast = toast(newReadingMode.stringRes) menuToggleToast = toast(newReadingMode.stringRes)
} }
@ -604,7 +604,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
updateCropBordersShortcut() updateCropBordersShortcut()
listOf(preferences.cropBorders(), preferences.cropBordersWebtoon() /* SY --> */, preferences.cropBordersContinuousVertical()/* SY <-- */) listOf(preferences.cropBorders(), preferences.cropBordersWebtoon() /* SY --> */, preferences.cropBordersContinuousVertical()/* SY <-- */)
.forEach { pref -> .forEach { pref ->
pref.asFlow() pref.changes()
.onEach { updateCropBordersShortcut() } .onEach { updateCropBordersShortcut() }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
} }
@ -617,7 +617,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
popupMenu( popupMenu(
items = OrientationType.values().map { it.flagValue to it.stringRes }, items = OrientationType.values().map { it.flagValue to it.stringRes },
selectedItemId = presenter.manga?.orientationType selectedItemId = presenter.manga?.orientationType
?: preferences.defaultOrientationType(), ?: preferences.defaultOrientationType().get(),
) { ) {
val newOrientation = OrientationType.fromPreference(itemId) val newOrientation = OrientationType.fromPreference(itemId)
@ -1079,7 +1079,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
if (preferences.useAutoWebtoon().get() && manga.readingModeType == ReadingModeType.DEFAULT.flagValue && defaultReaderType != null && defaultReaderType == ReadingModeType.WEBTOON.prefValue) { if (preferences.useAutoWebtoon().get() && manga.readingModeType == ReadingModeType.DEFAULT.flagValue && defaultReaderType != null && defaultReaderType == ReadingModeType.WEBTOON.prefValue) {
readingModeToast?.cancel() readingModeToast?.cancel()
readingModeToast = toast(resources.getString(R.string.eh_auto_webtoon_snack)) readingModeToast = toast(resources.getString(R.string.eh_auto_webtoon_snack))
} else if (preferences.showReadingMode()) { } else if (preferences.showReadingMode().get()) {
// SY <-- // SY <--
showReadingModeToast(presenter.getMangaReadingMode()) showReadingModeToast(presenter.getMangaReadingMode())
} }
@ -1510,7 +1510,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
* Initializes the reader subscriptions. * Initializes the reader subscriptions.
*/ */
init { init {
preferences.readerTheme().asFlow() preferences.readerTheme().changes()
.onEach { .onEach {
binding.readerContainer.setBackgroundResource( binding.readerContainer.setBackgroundResource(
when (preferences.readerTheme().get()) { when (preferences.readerTheme().get()) {
@ -1523,41 +1523,41 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
} }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
preferences.showPageNumber().asFlow() preferences.showPageNumber().changes()
.onEach { setPageNumberVisibility(it) } .onEach { setPageNumberVisibility(it) }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
preferences.trueColor().asFlow() preferences.trueColor().changes()
.onEach { setTrueColor(it) } .onEach { setTrueColor(it) }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
preferences.cutoutShort().asFlow() preferences.cutoutShort().changes()
.onEach { setCutoutShort(it) } .onEach { setCutoutShort(it) }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
} }
preferences.keepScreenOn().asFlow() preferences.keepScreenOn().changes()
.onEach { setKeepScreenOn(it) } .onEach { setKeepScreenOn(it) }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
preferences.customBrightness().asFlow() preferences.customBrightness().changes()
.onEach { setCustomBrightness(it) } .onEach { setCustomBrightness(it) }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
preferences.colorFilter().asFlow() preferences.colorFilter().changes()
.onEach { setColorFilter(it) } .onEach { setColorFilter(it) }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
preferences.colorFilterMode().asFlow() preferences.colorFilterMode().changes()
.onEach { setColorFilter(preferences.colorFilter().get()) } .onEach { setColorFilter(preferences.colorFilter().get()) }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
merge(preferences.grayscale().asFlow(), preferences.invertedColors().asFlow()) merge(preferences.grayscale().changes(), preferences.invertedColors().changes())
.onEach { setLayerPaint(preferences.grayscale().get(), preferences.invertedColors().get()) } .onEach { setLayerPaint(preferences.grayscale().get(), preferences.invertedColors().get()) }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
preferences.fullscreen().asFlow() preferences.fullscreen().changes()
.onEach { .onEach {
WindowCompat.setDecorFitsSystemWindows(window, !it) WindowCompat.setDecorFitsSystemWindows(window, !it)
updateViewerInset(it) updateViewerInset(it)
@ -1565,12 +1565,12 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
// SY --> // SY -->
preferences.pageLayout().asFlow() preferences.pageLayout().changes()
.drop(1) .drop(1)
.onEach { updateBottomButtons() } .onEach { updateBottomButtons() }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
preferences.dualPageSplitPaged().asFlow() preferences.dualPageSplitPaged().changes()
.drop(1) .drop(1)
.onEach { .onEach {
if (viewer !is PagerViewer) return@onEach if (viewer !is PagerViewer) return@onEach
@ -1644,7 +1644,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
*/ */
private fun setCustomBrightness(enabled: Boolean) { private fun setCustomBrightness(enabled: Boolean) {
if (enabled) { if (enabled) {
preferences.customBrightnessValue().asFlow() preferences.customBrightnessValue().changes()
.sample(100) .sample(100)
.onEach { setCustomBrightnessValue(it) } .onEach { setCustomBrightnessValue(it) }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
@ -1658,7 +1658,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
*/ */
private fun setColorFilter(enabled: Boolean) { private fun setColorFilter(enabled: Boolean) {
if (enabled) { if (enabled) {
preferences.colorFilterValue().asFlow() preferences.colorFilterValue().changes()
.sample(100) .sample(100)
.onEach { setColorFilterValue(it) } .onEach { setColorFilterValue(it) }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)

View File

@ -183,11 +183,11 @@ class ReaderPresenter(
?: error("Requested chapter of id $chapterId not found in chapter list") ?: error("Requested chapter of id $chapterId not found in chapter list")
val chaptersForReader = when { val chaptersForReader = when {
(preferences.skipRead() || preferences.skipFiltered()) -> { (preferences.skipRead().get() || preferences.skipFiltered().get()) -> {
val filteredChapters = chapters.filterNot { val filteredChapters = chapters.filterNot {
when { when {
preferences.skipRead() && it.read -> true preferences.skipRead().get() && it.read -> true
preferences.skipFiltered() -> { preferences.skipFiltered().get() -> {
(manga.readFilter == DomainManga.CHAPTER_SHOW_READ.toInt() && !it.read) || (manga.readFilter == DomainManga.CHAPTER_SHOW_READ.toInt() && !it.read) ||
(manga.readFilter == DomainManga.CHAPTER_SHOW_UNREAD.toInt() && it.read) || (manga.readFilter == DomainManga.CHAPTER_SHOW_UNREAD.toInt() && it.read) ||
(manga.downloadedFilter == DomainManga.CHAPTER_SHOW_DOWNLOADED.toInt() && !downloadManager.isChapterDownloaded(it.name, it.scanlator, manga.title, manga.source)) || (manga.downloadedFilter == DomainManga.CHAPTER_SHOW_DOWNLOADED.toInt() && !downloadManager.isChapterDownloaded(it.name, it.scanlator, manga.title, manga.source)) ||
@ -603,7 +603,7 @@ class ReaderPresenter(
private fun deleteChapterIfNeeded(currentChapter: ReaderChapter) { private fun deleteChapterIfNeeded(currentChapter: ReaderChapter) {
// Determine which chapter should be deleted and enqueue // Determine which chapter should be deleted and enqueue
val currentChapterPosition = chapterList.indexOf(currentChapter) val currentChapterPosition = chapterList.indexOf(currentChapter)
val removeAfterReadSlots = preferences.removeAfterReadSlots() val removeAfterReadSlots = preferences.removeAfterReadSlots().get()
val chapterToDelete = chapterList.getOrNull(currentChapterPosition - removeAfterReadSlots) val chapterToDelete = chapterList.getOrNull(currentChapterPosition - removeAfterReadSlots)
if (removeAfterReadSlots != 0 && chapterDownload != null) { if (removeAfterReadSlots != 0 && chapterDownload != null) {
@ -735,7 +735,7 @@ class ReaderPresenter(
* Returns the viewer position used by this manga or the default one. * Returns the viewer position used by this manga or the default one.
*/ */
fun getMangaReadingMode(resolveDefault: Boolean = true): Int { fun getMangaReadingMode(resolveDefault: Boolean = true): Int {
val default = preferences.defaultReadingMode() val default = preferences.defaultReadingMode().get()
val manga = manga ?: return default val manga = manga ?: return default
val readingMode = ReadingModeType.fromPreference(manga.readingModeType) val readingMode = ReadingModeType.fromPreference(manga.readingModeType)
// SY --> // SY -->
@ -779,7 +779,7 @@ class ReaderPresenter(
* Returns the orientation type used by this manga or the default one. * Returns the orientation type used by this manga or the default one.
*/ */
fun getMangaOrientationType(resolveDefault: Boolean = true): Int { fun getMangaOrientationType(resolveDefault: Boolean = true): Int {
val default = preferences.defaultOrientationType() val default = preferences.defaultOrientationType().get()
val orientation = OrientationType.fromPreference(manga?.orientationType) val orientation = OrientationType.fromPreference(manga?.orientationType)
return when { return when {
resolveDefault && orientation == OrientationType.DEFAULT -> default resolveDefault && orientation == OrientationType.DEFAULT -> default
@ -837,7 +837,7 @@ class ReaderPresenter(
val filename = generateFilename(manga, page) val filename = generateFilename(manga, page)
// Pictures directory. // Pictures directory.
val relativePath = if (preferences.folderPerManga()) DiskUtil.buildValidFilename(manga.title) else "" val relativePath = if (preferences.folderPerManga().get()) DiskUtil.buildValidFilename(manga.title) else ""
// Copy file in background. // Copy file in background.
try { try {
@ -871,7 +871,7 @@ class ReaderPresenter(
notifier.onClear() notifier.onClear()
// Pictures directory. // Pictures directory.
val relativePath = if (preferences.folderPerManga()) DiskUtil.buildValidFilename(manga.title) else "" val relativePath = if (preferences.folderPerManga().get()) DiskUtil.buildValidFilename(manga.title) else ""
// Copy file in background. // Copy file in background.
try { try {
@ -1039,7 +1039,7 @@ class ReaderPresenter(
* will run in a background thread and errors are ignored. * will run in a background thread and errors are ignored.
*/ */
private fun updateTrackChapterRead(readerChapter: ReaderChapter) { private fun updateTrackChapterRead(readerChapter: ReaderChapter) {
if (!preferences.autoUpdateTrack()) return if (!preferences.autoUpdateTrack().get()) return
val manga = manga ?: return val manga = manga ?: return
val chapterRead = readerChapter.chapter.chapter_number.toDouble() val chapterRead = readerChapter.chapter.chapter_number.toDouble()

View File

@ -32,15 +32,15 @@ class ReaderColorFilterSettings @JvmOverloads constructor(context: Context, attr
init { init {
addView(binding.root) addView(binding.root)
preferences.colorFilter().asFlow() preferences.colorFilter().changes()
.onEach { setColorFilter(it) } .onEach { setColorFilter(it) }
.launchIn((context as ReaderActivity).lifecycleScope) .launchIn((context as ReaderActivity).lifecycleScope)
preferences.colorFilterMode().asFlow() preferences.colorFilterMode().changes()
.onEach { setColorFilter(preferences.colorFilter().get()) } .onEach { setColorFilter(preferences.colorFilter().get()) }
.launchIn(context.lifecycleScope) .launchIn(context.lifecycleScope)
preferences.customBrightness().asFlow() preferences.customBrightness().changes()
.onEach { setCustomBrightness(it) } .onEach { setCustomBrightness(it) }
.launchIn(context.lifecycleScope) .launchIn(context.lifecycleScope)
@ -139,7 +139,7 @@ class ReaderColorFilterSettings @JvmOverloads constructor(context: Context, attr
*/ */
private fun setCustomBrightness(enabled: Boolean) { private fun setCustomBrightness(enabled: Boolean) {
if (enabled) { if (enabled) {
preferences.customBrightnessValue().asFlow() preferences.customBrightnessValue().changes()
.sample(100) .sample(100)
.onEach { setCustomBrightnessValue(it) } .onEach { setCustomBrightnessValue(it) }
.launchIn((context as ReaderActivity).lifecycleScope) .launchIn((context as ReaderActivity).lifecycleScope)
@ -167,7 +167,7 @@ class ReaderColorFilterSettings @JvmOverloads constructor(context: Context, attr
*/ */
private fun setColorFilter(enabled: Boolean) { private fun setColorFilter(enabled: Boolean) {
if (enabled) { if (enabled) {
preferences.colorFilterValue().asFlow() preferences.colorFilterValue().changes()
.sample(100) .sample(100)
.onEach { setColorFilterValue(it) } .onEach { setColorFilterValue(it) }
.launchIn((context as ReaderActivity).lifecycleScope) .launchIn((context as ReaderActivity).lifecycleScope)

View File

@ -1,6 +1,6 @@
package eu.kanade.tachiyomi.ui.reader.viewer package eu.kanade.tachiyomi.ui.reader.viewer
import com.fredporciuncula.flow.preferences.Preference import eu.kanade.tachiyomi.core.preference.Preference
import eu.kanade.tachiyomi.data.preference.PreferenceValues.TappingInvertMode import eu.kanade.tachiyomi.data.preference.PreferenceValues.TappingInvertMode
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -76,7 +76,7 @@ abstract class ViewerConfig(preferences: PreferencesHelper, private val scope: C
valueAssignment: (T) -> Unit, valueAssignment: (T) -> Unit,
onChanged: (T) -> Unit = {}, onChanged: (T) -> Unit = {},
) { ) {
asFlow() changes()
.onEach { valueAssignment(it) } .onEach { valueAssignment(it) }
.distinctUntilChanged() .distinctUntilChanged()
.onEach { onChanged(it) } .onEach { onChanged(it) }

View File

@ -106,7 +106,7 @@ class PagerConfig(
preferences.pagerNavInverted() preferences.pagerNavInverted()
.register({ tappingInverted = it }, { navigator.invertMode = it }) .register({ tappingInverted = it }, { navigator.invertMode = it })
preferences.pagerNavInverted().asFlow() preferences.pagerNavInverted().changes()
.drop(1) .drop(1)
.onEach { navigationModeChangedListener?.invoke() } .onEach { navigationModeChangedListener?.invoke() }
.launchIn(scope) .launchIn(scope)

View File

@ -63,7 +63,7 @@ class WebtoonConfig(
preferences.webtoonNavInverted() preferences.webtoonNavInverted()
.register({ tappingInverted = it }, { navigator.invertMode = it }) .register({ tappingInverted = it }, { navigator.invertMode = it })
preferences.webtoonNavInverted().asFlow() preferences.webtoonNavInverted().changes()
.drop(1) .drop(1)
.onEach { navigationModeChangedListener?.invoke() } .onEach { navigationModeChangedListener?.invoke() }
.launchIn(scope) .launchIn(scope)
@ -83,7 +83,7 @@ class WebtoonConfig(
}, },
) )
preferences.readerTheme().asFlow() preferences.readerTheme().changes()
.drop(1) .drop(1)
.distinctUntilChanged() .distinctUntilChanged()
.onEach { themeChangedListener?.invoke() } .onEach { themeChangedListener?.invoke() }

View File

@ -27,6 +27,7 @@ import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Target
import eu.kanade.tachiyomi.data.preference.PreferenceValues import eu.kanade.tachiyomi.data.preference.PreferenceValues
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.network.NetworkPreferences
import eu.kanade.tachiyomi.network.PREF_DOH_360 import eu.kanade.tachiyomi.network.PREF_DOH_360
import eu.kanade.tachiyomi.network.PREF_DOH_ADGUARD import eu.kanade.tachiyomi.network.PREF_DOH_ADGUARD
import eu.kanade.tachiyomi.network.PREF_DOH_ALIDNS import eu.kanade.tachiyomi.network.PREF_DOH_ALIDNS
@ -70,6 +71,7 @@ import eu.kanade.tachiyomi.util.system.setDefaultSettings
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import exh.debug.SettingsDebugController import exh.debug.SettingsDebugController
import exh.log.EHLogLevel import exh.log.EHLogLevel
import exh.pref.SourcePreferences
import exh.source.BlacklistedSources import exh.source.BlacklistedSources
import exh.source.EH_SOURCE_ID import exh.source.EH_SOURCE_ID
import exh.source.EXH_SOURCE_ID import exh.source.EXH_SOURCE_ID
@ -89,6 +91,8 @@ class SettingsAdvancedController(
private val network: NetworkHelper by injectLazy() private val network: NetworkHelper by injectLazy()
private val chapterCache: ChapterCache by injectLazy() private val chapterCache: ChapterCache by injectLazy()
private val trackManager: TrackManager by injectLazy() private val trackManager: TrackManager by injectLazy()
private val networkPreferences: NetworkPreferences by injectLazy()
private val sourcePreferences: SourcePreferences by injectLazy()
private val getAllManga: GetAllManga by injectLazy() private val getAllManga: GetAllManga by injectLazy()
private val getChapterByMangaId: GetChapterByMangaId by injectLazy() private val getChapterByMangaId: GetChapterByMangaId by injectLazy()
private val pagePreviewCache: PagePreviewCache by injectLazy() private val pagePreviewCache: PagePreviewCache by injectLazy()
@ -110,7 +114,7 @@ class SettingsAdvancedController(
} }
/*switchPreference { /*switchPreference {
key = Keys.verboseLogging key = networkPreferences.verboseLogging().key()
titleRes = R.string.pref_verbose_logging titleRes = R.string.pref_verbose_logging
summaryRes = R.string.pref_verbose_logging_summary summaryRes = R.string.pref_verbose_logging_summary
defaultValue = isDevFlavor defaultValue = isDevFlavor
@ -212,7 +216,7 @@ class SettingsAdvancedController(
onClick { clearWebViewData() } onClick { clearWebViewData() }
} }
intListPreference { intListPreference {
key = Keys.dohProvider key = networkPreferences.dohProvider().key()
titleRes = R.string.pref_dns_over_https titleRes = R.string.pref_dns_over_https
entries = arrayOf( entries = arrayOf(
context.getString(R.string.disabled), context.getString(R.string.disabled),
@ -250,10 +254,11 @@ class SettingsAdvancedController(
true true
} }
} }
val defaultUserAgent = networkPreferences.defaultUserAgent()
editTextPreference { editTextPreference {
key = Keys.defaultUserAgent key = defaultUserAgent.key()
titleRes = R.string.pref_user_agent_string titleRes = R.string.pref_user_agent_string
text = preferences.defaultUserAgent().get() text = defaultUserAgent.get()
summary = network.defaultUserAgent summary = network.defaultUserAgent
onChange { onChange {
@ -270,10 +275,10 @@ class SettingsAdvancedController(
key = "pref_reset_user_agent" key = "pref_reset_user_agent"
titleRes = R.string.pref_reset_user_agent_string titleRes = R.string.pref_reset_user_agent_string
visibleIf(preferences.defaultUserAgent()) { it != preferences.defaultUserAgent().defaultValue } visibleIf(defaultUserAgent) { it != defaultUserAgent.defaultValue() }
onClick { onClick {
preferences.defaultUserAgent().delete() defaultUserAgent.delete()
activity?.toast(R.string.requires_app_restart) activity?.toast(R.string.requires_app_restart)
} }
} }
@ -466,7 +471,7 @@ class SettingsAdvancedController(
} }
switchPreference { switchPreference {
bindTo(preferences.delegateSources()) bindTo(sourcePreferences.delegateSources())
titleRes = R.string.toggle_delegated_sources titleRes = R.string.toggle_delegated_sources
summary = context.getString(R.string.toggle_delegated_sources_summary, context.getString(R.string.app_name), DELEGATED_SOURCES.values.map { it.sourceName }.distinct().joinToString()) summary = context.getString(R.string.toggle_delegated_sources_summary, context.getString(R.string.app_name), DELEGATED_SOURCES.values.map { it.sourceName }.distinct().joinToString())
} }

View File

@ -136,7 +136,7 @@ class SettingsBackupController : SettingsController() {
} }
} }
preferences.backupsDirectory().asFlow() preferences.backupsDirectory().changes()
.onEach { path -> .onEach { path ->
val dir = UniFile.fromUri(context, path.toUri()) val dir = UniFile.fromUri(context, path.toUri())
summary = dir.filePath + "/automatic" summary = dir.filePath + "/automatic"

View File

@ -130,7 +130,7 @@ abstract class SettingsController : PreferenceController() {
(activity as? AppCompatActivity)?.supportActionBar?.title = getTitle() (activity as? AppCompatActivity)?.supportActionBar?.title = getTitle()
} }
inline fun <T> Preference.visibleIf(preference: com.fredporciuncula.flow.preferences.Preference<T>, crossinline block: (T) -> Boolean) { inline fun <T> Preference.visibleIf(preference: eu.kanade.tachiyomi.core.preference.Preference<T>, crossinline block: (T) -> Boolean) {
preference.asHotFlow { isVisible = block(it) } preference.asHotFlow { isVisible = block(it) }
.launchIn(viewScope) .launchIn(viewScope)
} }

View File

@ -58,7 +58,7 @@ class SettingsDownloadController : SettingsController() {
ctrl.showDialog(router) ctrl.showDialog(router)
} }
preferences.downloadsDirectory().asFlow() preferences.downloadsDirectory().changes()
.onEach { path -> .onEach { path ->
val dir = UniFile.fromUri(context, path.toUri()) val dir = UniFile.fromUri(context, path.toUri())
summary = dir.filePath ?: path summary = dir.filePath ?: path
@ -114,7 +114,7 @@ class SettingsDownloadController : SettingsController() {
entries = categories.map { it.visualName(context) }.toTypedArray() entries = categories.map { it.visualName(context) }.toTypedArray()
entryValues = categories.map { it.id.toString() }.toTypedArray() entryValues = categories.map { it.id.toString() }.toTypedArray()
preferences.removeExcludeCategories().asFlow() preferences.removeExcludeCategories().changes()
.onEach { mutable -> .onEach { mutable ->
val selected = mutable val selected = mutable
.mapNotNull { id -> categories.find { it.id == id.toLong() } } .mapNotNull { id -> categories.find { it.id == id.toLong() } }
@ -171,10 +171,10 @@ class SettingsDownloadController : SettingsController() {
} }
} }
preferences.downloadNewChapterCategories().asFlow() preferences.downloadNewChapterCategories().changes()
.onEach { updateSummary() } .onEach { updateSummary() }
.launchIn(viewScope) .launchIn(viewScope)
preferences.downloadNewChapterCategoriesExclude().asFlow() preferences.downloadNewChapterCategoriesExclude().changes()
.onEach { updateSummary() } .onEach { updateSummary() }
.launchIn(viewScope) .launchIn(viewScope)
} }

View File

@ -12,12 +12,12 @@ import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.core.widget.doAfterTextChanged import androidx.core.widget.doAfterTextChanged
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import com.fredporciuncula.flow.preferences.Preference
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import eu.kanade.domain.manga.interactor.DeleteFavoriteEntries import eu.kanade.domain.manga.interactor.DeleteFavoriteEntries
import eu.kanade.domain.manga.interactor.GetExhFavoriteMangaWithMetadata import eu.kanade.domain.manga.interactor.GetExhFavoriteMangaWithMetadata
import eu.kanade.domain.manga.interactor.GetFlatMetadataById import eu.kanade.domain.manga.interactor.GetFlatMetadataById
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.core.preference.Preference
import eu.kanade.tachiyomi.data.preference.DEVICE_CHARGING import eu.kanade.tachiyomi.data.preference.DEVICE_CHARGING
import eu.kanade.tachiyomi.data.preference.DEVICE_ONLY_ON_WIFI import eu.kanade.tachiyomi.data.preference.DEVICE_ONLY_ON_WIFI
import eu.kanade.tachiyomi.databinding.DialogStubTextinputBinding import eu.kanade.tachiyomi.databinding.DialogStubTextinputBinding
@ -75,7 +75,7 @@ class SettingsEhController : SettingsController() {
fun Preference<*>.reconfigure(): Boolean { fun Preference<*>.reconfigure(): Boolean {
// Listen for change commit // Listen for change commit
asFlow() changes()
.take(1) // Only listen for first commit .take(1) // Only listen for first commit
.onEach { .onEach {
// Only listen for first change commit // Only listen for first change commit
@ -99,7 +99,7 @@ class SettingsEhController : SettingsController() {
summaryOff = context.getString(R.string.requires_login) summaryOff = context.getString(R.string.requires_login)
isPersistent = false isPersistent = false
preferences.enableExhentai() preferences.enableExhentai()
.asFlow() .changes()
.onEach { .onEach {
isChecked = it isChecked = it
} }
@ -395,7 +395,7 @@ class SettingsEhController : SettingsController() {
) )
entryValues = arrayOf("0", "1", "2", "3", "6", "12", "24", "48") entryValues = arrayOf("0", "1", "2", "3", "6", "12", "24", "48")
preferences.exhAutoUpdateFrequency().asFlow() preferences.exhAutoUpdateFrequency().changes()
.onEach { newVal -> .onEach { newVal ->
summary = if (newVal == 0) { summary = if (newVal == 0) {
context.getString(R.string.time_between_batches_summary_1, context.getString(R.string.app_name)) context.getString(R.string.time_between_batches_summary_1, context.getString(R.string.app_name))
@ -445,7 +445,7 @@ class SettingsEhController : SettingsController() {
true true
} }
preferences.exhAutoUpdateRequirements().asFlow() preferences.exhAutoUpdateRequirements().changes()
.onEach { updateSummary() } .onEach { updateSummary() }
.launchIn(viewScope) .launchIn(viewScope)
} }

View File

@ -82,7 +82,7 @@ class SettingsLibraryController : SettingsController() {
} }
} }
combine(preferences.portraitColumns().asFlow(), preferences.landscapeColumns().asFlow()) { portraitCols, landscapeCols -> Pair(portraitCols, landscapeCols) } combine(preferences.portraitColumns().changes(), preferences.landscapeColumns().changes()) { portraitCols, landscapeCols -> Pair(portraitCols, landscapeCols) }
.onEach { (portraitCols, landscapeCols) -> .onEach { (portraitCols, landscapeCols) ->
val portrait = getColumnValue(portraitCols) val portrait = getColumnValue(portraitCols)
val landscape = getColumnValue(landscapeCols) val landscape = getColumnValue(landscapeCols)
@ -117,7 +117,7 @@ class SettingsLibraryController : SettingsController() {
entryValues = arrayOf("-1") + allCategories.map { it.id.toString() }.toTypedArray() entryValues = arrayOf("-1") + allCategories.map { it.id.toString() }.toTypedArray()
defaultValue = "-1" defaultValue = "-1"
val selectedCategory = allCategories.find { it.id == preferences.defaultCategory().toLong() } val selectedCategory = allCategories.find { it.id == preferences.defaultCategory().get().toLong() }
summary = selectedCategory?.visualName(context) summary = selectedCategory?.visualName(context)
?: context.getString(R.string.default_category_summary) ?: context.getString(R.string.default_category_summary)
onChange { newValue -> onChange { newValue ->
@ -132,7 +132,7 @@ class SettingsLibraryController : SettingsController() {
bindTo(preferences.categorizedDisplaySettings()) bindTo(preferences.categorizedDisplaySettings())
titleRes = R.string.categorized_display_settings titleRes = R.string.categorized_display_settings
preferences.categorizedDisplaySettings().asFlow() preferences.categorizedDisplaySettings().changes()
.onEach { .onEach {
if (it.not()) { if (it.not()) {
resetCategoryFlags.await() resetCategoryFlags.await()
@ -200,7 +200,7 @@ class SettingsLibraryController : SettingsController() {
summary = context.getString(R.string.restrictions, restrictionsText) summary = context.getString(R.string.restrictions, restrictionsText)
} }
preferences.libraryUpdateDeviceRestriction().asFlow() preferences.libraryUpdateDeviceRestriction().changes()
.onEach { updateSummary() } .onEach { updateSummary() }
.launchIn(viewScope) .launchIn(viewScope)
} }
@ -229,7 +229,7 @@ class SettingsLibraryController : SettingsController() {
summary = restrictionsText summary = restrictionsText
} }
preferences.libraryUpdateMangaRestriction().asFlow() preferences.libraryUpdateMangaRestriction().changes()
.onEach { updateSummary() } .onEach { updateSummary() }
.launchIn(viewScope) .launchIn(viewScope)
} }
@ -272,10 +272,10 @@ class SettingsLibraryController : SettingsController() {
} }
} }
preferences.libraryUpdateCategories().asFlow() preferences.libraryUpdateCategories().changes()
.onEach { updateSummary() } .onEach { updateSummary() }
.launchIn(viewScope) .launchIn(viewScope)
preferences.libraryUpdateCategoriesExclude().asFlow() preferences.libraryUpdateCategoriesExclude().changes()
.onEach { updateSummary() } .onEach { updateSummary() }
.launchIn(viewScope) .launchIn(viewScope)
} }

View File

@ -27,12 +27,12 @@ object ChapterSettingsHelper {
suspend fun applySettingDefaults(mangaId: Long) { suspend fun applySettingDefaults(mangaId: Long) {
setMangaChapterFlags.awaitSetAllFlags( setMangaChapterFlags.awaitSetAllFlags(
mangaId = mangaId, mangaId = mangaId,
unreadFilter = preferences.filterChapterByRead().toLong(), unreadFilter = preferences.filterChapterByRead().get().toLong(),
downloadedFilter = preferences.filterChapterByDownloaded().toLong(), downloadedFilter = preferences.filterChapterByDownloaded().get().toLong(),
bookmarkedFilter = preferences.filterChapterByBookmarked().toLong(), bookmarkedFilter = preferences.filterChapterByBookmarked().get().toLong(),
sortingMode = preferences.sortChapterBySourceOrNumber().toLong(), sortingMode = preferences.sortChapterBySourceOrNumber().get().toLong(),
sortingDirection = preferences.sortChapterByAscendingOrDescending().toLong(), sortingDirection = preferences.sortChapterByAscendingOrDescending().get().toLong(),
displayMode = preferences.displayChapterByNameOrNumber().toLong(), displayMode = preferences.displayChapterByNameOrNumber().get().toLong(),
) )
} }
@ -45,12 +45,12 @@ object ChapterSettingsHelper {
.map { manga -> .map { manga ->
setMangaChapterFlags.awaitSetAllFlags( setMangaChapterFlags.awaitSetAllFlags(
mangaId = manga.id, mangaId = manga.id,
unreadFilter = preferences.filterChapterByRead().toLong(), unreadFilter = preferences.filterChapterByRead().get().toLong(),
downloadedFilter = preferences.filterChapterByDownloaded().toLong(), downloadedFilter = preferences.filterChapterByDownloaded().get().toLong(),
bookmarkedFilter = preferences.filterChapterByBookmarked().toLong(), bookmarkedFilter = preferences.filterChapterByBookmarked().get().toLong(),
sortingMode = preferences.sortChapterBySourceOrNumber().toLong(), sortingMode = preferences.sortChapterBySourceOrNumber().get().toLong(),
sortingDirection = preferences.sortChapterByAscendingOrDescending().toLong(), sortingDirection = preferences.sortChapterByAscendingOrDescending().get().toLong(),
displayMode = preferences.displayChapterByNameOrNumber().toLong(), displayMode = preferences.displayChapterByNameOrNumber().get().toLong(),
) )
} }
} }

View File

@ -106,15 +106,14 @@ inline fun <P : Preference> PreferenceGroup.addThenInit(p: P, block: P.() -> Uni
} }
} }
inline fun <T> Preference.bindTo(preference: com.fredporciuncula.flow.preferences.Preference<T>) { inline fun <T> Preference.bindTo(preference: eu.kanade.tachiyomi.core.preference.Preference<T>) {
key = preference.key key = preference.key()
defaultValue = preference.defaultValue defaultValue = preference.defaultValue()
} }
inline fun <T> ListPreference.bindTo(preference: com.fredporciuncula.flow.preferences.Preference<T>) { inline fun <T> ListPreference.bindTo(preference: eu.kanade.tachiyomi.core.preference.Preference<T>) {
key = preference.key key = preference.key()
// ListPreferences persist values as strings, even when we're using our IntListPreference defaultValue = preference.defaultValue().toString()
defaultValue = preference.defaultValue.toString()
} }
inline fun Preference.onClick(crossinline block: () -> Unit) { inline fun Preference.onClick(crossinline block: () -> Unit) {

View File

@ -1,7 +1,7 @@
package eu.kanade.tachiyomi.util.preference package eu.kanade.tachiyomi.util.preference
import android.widget.CompoundButton import android.widget.CompoundButton
import com.fredporciuncula.flow.preferences.Preference import eu.kanade.tachiyomi.core.preference.Preference
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
@ -15,7 +15,7 @@ fun CompoundButton.bindToPreference(pref: Preference<Boolean>) {
fun <T> Preference<T>.asHotFlow(block: (T) -> Unit): Flow<T> { fun <T> Preference<T>.asHotFlow(block: (T) -> Unit): Flow<T> {
block(get()) block(get())
return asFlow() return changes()
.onEach { block(it) } .onEach { block(it) }
} }

View File

@ -14,8 +14,8 @@ import androidx.appcompat.widget.PopupMenu
import androidx.core.content.withStyledAttributes import androidx.core.content.withStyledAttributes
import androidx.core.view.forEach import androidx.core.view.forEach
import androidx.core.view.get import androidx.core.view.get
import com.fredporciuncula.flow.preferences.Preference
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.core.preference.Preference
import eu.kanade.tachiyomi.databinding.PrefSpinnerBinding import eu.kanade.tachiyomi.databinding.PrefSpinnerBinding
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor

View File

@ -31,13 +31,15 @@ class TachiyomiSearchView @JvmOverloads constructor(
override fun onAttachedToWindow() { override fun onAttachedToWindow() {
super.onAttachedToWindow() super.onAttachedToWindow()
scope = CoroutineScope(SupervisorJob() + Dispatchers.Main) scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
Injekt.get<PreferencesHelper>().incognitoMode().asHotFlow { Injekt.get<PreferencesHelper>().incognitoMode()
.asHotFlow {
imeOptions = if (it) { imeOptions = if (it) {
imeOptions or EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING imeOptions or EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING
} else { } else {
imeOptions and EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING.inv() imeOptions and EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING.inv()
} }
}.launchIn(scope!!) }
.launchIn(scope!!)
} }
override fun setOnQueryTextListener(listener: OnQueryTextListener?) { override fun setOnQueryTextListener(listener: OnQueryTextListener?) {

View File

@ -49,13 +49,15 @@ class TachiyomiTextInputEditText @JvmOverloads constructor(
* if [PreferencesHelper.incognitoMode] is true. Some IMEs may not respect this flag. * if [PreferencesHelper.incognitoMode] is true. Some IMEs may not respect this flag.
*/ */
fun EditText.setIncognito(viewScope: CoroutineScope) { fun EditText.setIncognito(viewScope: CoroutineScope) {
Injekt.get<PreferencesHelper>().incognitoMode().asHotFlow { Injekt.get<PreferencesHelper>().incognitoMode()
.asHotFlow {
imeOptions = if (it) { imeOptions = if (it) {
imeOptions or EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING imeOptions or EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING
} else { } else {
imeOptions and EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING.inv() imeOptions and EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING.inv()
} }
}.launchIn(viewScope) }
.launchIn(viewScope)
} }
} }
} }

View File

@ -2,6 +2,7 @@
package exh package exh
import android.content.Context
import androidx.core.content.edit import androidx.core.content.edit
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import eu.kanade.data.DatabaseHandler import eu.kanade.data.DatabaseHandler
@ -28,6 +29,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.data.updater.AppUpdateJob import eu.kanade.tachiyomi.data.updater.AppUpdateJob
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
import eu.kanade.tachiyomi.network.NetworkPreferences
import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
@ -87,8 +89,11 @@ object EXHMigrations {
* @param preferences Preferences of the application. * @param preferences Preferences of the application.
* @return true if a migration is performed, false otherwise. * @return true if a migration is performed, false otherwise.
*/ */
fun upgrade(preferences: PreferencesHelper): Boolean { fun upgrade(
val context = preferences.context context: Context,
preferences: PreferencesHelper,
networkPreferences: NetworkPreferences,
): Boolean {
val oldVersion = preferences.ehLastVersionCode().get() val oldVersion = preferences.ehLastVersionCode().get()
try { try {
if (oldVersion < BuildConfig.VERSION_CODE) { if (oldVersion < BuildConfig.VERSION_CODE) {
@ -211,7 +216,7 @@ object EXHMigrations {
val wasDohEnabled = prefs.getBoolean("enable_doh", false) val wasDohEnabled = prefs.getBoolean("enable_doh", false)
if (wasDohEnabled) { if (wasDohEnabled) {
prefs.edit { prefs.edit {
putInt(PreferenceKeys.dohProvider, PREF_DOH_CLOUDFLARE) putInt(networkPreferences.dohProvider().key(), PREF_DOH_CLOUDFLARE)
remove("enable_doh") remove("enable_doh")
} }
} }

View File

@ -11,6 +11,7 @@ import eu.kanade.domain.manga.interactor.GetSearchMetadata
import eu.kanade.domain.manga.interactor.InsertFlatMetadata import eu.kanade.domain.manga.interactor.InsertFlatMetadata
import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.network.NetworkPreferences
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.online.all.NHentai import eu.kanade.tachiyomi.source.online.all.NHentai
import exh.EXHMigrations import exh.EXHMigrations
@ -30,6 +31,7 @@ object DebugFunctions {
val app: Application by injectLazy() val app: Application by injectLazy()
val handler: DatabaseHandler by injectLazy() val handler: DatabaseHandler by injectLazy()
val prefs: PreferencesHelper by injectLazy() val prefs: PreferencesHelper by injectLazy()
val networkPrefs: NetworkPreferences by injectLazy()
val sourceManager: SourceManager by injectLazy() val sourceManager: SourceManager by injectLazy()
val updateManga: UpdateManga by injectLazy() val updateManga: UpdateManga by injectLazy()
val getFavorites: GetFavorites by injectLazy() val getFavorites: GetFavorites by injectLazy()
@ -41,12 +43,12 @@ object DebugFunctions {
fun forceUpgradeMigration() { fun forceUpgradeMigration() {
prefs.ehLastVersionCode().set(1) prefs.ehLastVersionCode().set(1)
EXHMigrations.upgrade(prefs) EXHMigrations.upgrade(app, prefs, networkPrefs)
} }
fun forceSetupJobs() { fun forceSetupJobs() {
prefs.ehLastVersionCode().set(0) prefs.ehLastVersionCode().set(0)
EXHMigrations.upgrade(prefs) EXHMigrations.upgrade(app, prefs, networkPrefs)
} }
fun resetAgedFlagInEXHManga() { fun resetAgedFlagInEXHManga() {

View File

@ -1,7 +1,7 @@
package exh.debug package exh.debug
import eu.kanade.core.prefs.PreferenceMutableState import eu.kanade.core.prefs.PreferenceMutableState
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.core.preference.PreferenceStore
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.util.Locale import java.util.Locale
@ -26,14 +26,14 @@ enum class DebugToggles(val default: Boolean) {
private val prefKey = "eh_debug_toggle_${name.lowercase(Locale.US)}" private val prefKey = "eh_debug_toggle_${name.lowercase(Locale.US)}"
var enabled: Boolean var enabled: Boolean
get() = prefs.flowPrefs.getBoolean(prefKey, default).get() get() = preferenceStore.getBoolean(prefKey, default).get()
set(value) { set(value) {
prefs.flowPrefs.getBoolean(prefKey).set(value) preferenceStore.getBoolean(prefKey).set(value)
} }
fun asPref(scope: CoroutineScope) = PreferenceMutableState(prefs.flowPrefs.getBoolean(prefKey, default), scope) fun asPref(scope: CoroutineScope) = PreferenceMutableState(preferenceStore.getBoolean(prefKey, default), scope)
companion object { companion object {
private val prefs: PreferencesHelper by injectLazy() private val preferenceStore: PreferenceStore by injectLazy()
} }
} }

View File

@ -66,9 +66,9 @@ class MangaDexLoginHelper(authServiceLazy: Lazy<MangaDexAuthService>, val prefer
} }
suspend fun login(): Boolean { suspend fun login(): Boolean {
val username = preferences.trackUsername(mdList) val username = preferences.trackUsername(mdList).get()
val password = preferences.trackPassword(mdList) val password = preferences.trackPassword(mdList).get()
if (username.isNullOrBlank() || password.isNullOrBlank()) { if (username.isBlank() || password.isBlank()) {
xLogI("No username or password stored, can't login") xLogI("No username or password stored, can't login")
return false return false
} }

View File

@ -1,6 +1,6 @@
package exh.util package exh.util
import com.fredporciuncula.flow.preferences.Preference import eu.kanade.tachiyomi.core.preference.Preference
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page

View File

@ -0,0 +1,176 @@
package eu.kanade.tachiyomi.core.preference
import android.content.SharedPreferences
import android.content.SharedPreferences.Editor
import androidx.core.content.edit
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
sealed class AndroidPreference<T>(
private val preferences: SharedPreferences,
private val keyFlow: Flow<String?>,
private val key: String,
private val defaultValue: T,
) : Preference<T> {
abstract fun read(preferences: SharedPreferences, key: String, defaultValue: T): T
abstract fun write(key: String, value: T): Editor.() -> Unit
override fun key(): String {
return key
}
override fun get(): T {
return read(preferences, key, defaultValue)
}
override fun set(value: T) {
preferences.edit(action = write(key, value))
}
override fun isSet(): Boolean {
return preferences.contains(key)
}
override fun delete() {
preferences.edit {
remove(key)
}
}
override fun defaultValue(): T {
return defaultValue
}
override fun changes(): Flow<T> {
return keyFlow
.filter { it == key || it == null }
.onStart { emit("ignition") }
.map { get() }
.conflate()
}
override fun stateIn(scope: CoroutineScope): StateFlow<T> {
return changes().stateIn(scope, SharingStarted.Eagerly, get())
}
class StringPrimitive(
preferences: SharedPreferences,
keyFlow: Flow<String?>,
key: String,
defaultValue: String
) : AndroidPreference<String>(preferences, keyFlow, key, defaultValue) {
override fun read(preferences: SharedPreferences, key: String, defaultValue: String): String {
return preferences.getString(key, defaultValue) ?: defaultValue
}
override fun write(key: String, value: String): Editor.() -> Unit = {
putString(key, value)
}
}
class LongPrimitive(
preferences: SharedPreferences,
keyFlow: Flow<String?>,
key: String,
defaultValue: Long
) : AndroidPreference<Long>(preferences, keyFlow, key, defaultValue) {
override fun read(preferences: SharedPreferences, key: String, defaultValue: Long): Long {
return preferences.getLong(key, defaultValue)
}
override fun write(key: String, value: Long): Editor.() -> Unit = {
putLong(key, value)
}
}
class IntPrimitive(
preferences: SharedPreferences,
keyFlow: Flow<String?>,
key: String,
defaultValue: Int
) : AndroidPreference<Int>(preferences, keyFlow, key, defaultValue) {
override fun read(preferences: SharedPreferences, key: String, defaultValue: Int): Int {
return preferences.getInt(key, defaultValue)
}
override fun write(key: String, value: Int): Editor.() -> Unit = {
putInt(key, value)
}
}
class FloatPrimitive(
preferences: SharedPreferences,
keyFlow: Flow<String?>,
key: String,
defaultValue: Float
) : AndroidPreference<Float>(preferences, keyFlow, key, defaultValue) {
override fun read(preferences: SharedPreferences, key: String, defaultValue: Float): Float {
return preferences.getFloat(key, defaultValue)
}
override fun write(key: String, value: Float): Editor.() -> Unit = {
putFloat(key, value)
}
}
class BooleanPrimitive(
preferences: SharedPreferences,
keyFlow: Flow<String?>,
key: String,
defaultValue: Boolean
) : AndroidPreference<Boolean>(preferences, keyFlow, key, defaultValue) {
override fun read(preferences: SharedPreferences, key: String, defaultValue: Boolean): Boolean {
return preferences.getBoolean(key, defaultValue)
}
override fun write(key: String, value: Boolean): Editor.() -> Unit = {
putBoolean(key, value)
}
}
class StringSetPrimitive(
preferences: SharedPreferences,
keyFlow: Flow<String?>,
key: String,
defaultValue: Set<String>
) : AndroidPreference<Set<String>>(preferences, keyFlow, key, defaultValue) {
override fun read(preferences: SharedPreferences, key: String, defaultValue: Set<String>): Set<String> {
return preferences.getStringSet(key, defaultValue) ?: defaultValue
}
override fun write(key: String, value: Set<String>): Editor.() -> Unit = {
putStringSet(key, value)
}
}
class Object<T>(
preferences: SharedPreferences,
keyFlow: Flow<String?>,
key: String,
defaultValue: T,
val serializer: (T) -> String,
val deserializer: (String) -> T
) : AndroidPreference<T>(preferences, keyFlow, key, defaultValue) {
override fun read(preferences: SharedPreferences, key: String, defaultValue: T): T {
return try {
preferences.getString(key, null)?.let(deserializer) ?: defaultValue
} catch (e: Exception) {
defaultValue
}
}
override fun write(key: String, value: T): Editor.() -> Unit = {
putString(key, serializer(value))
}
}
}

View File

@ -0,0 +1,72 @@
package eu.kanade.tachiyomi.core.preference
import android.content.Context
import android.content.SharedPreferences
import androidx.preference.PreferenceManager
import eu.kanade.tachiyomi.core.preference.AndroidPreference.BooleanPrimitive
import eu.kanade.tachiyomi.core.preference.AndroidPreference.FloatPrimitive
import eu.kanade.tachiyomi.core.preference.AndroidPreference.IntPrimitive
import eu.kanade.tachiyomi.core.preference.AndroidPreference.LongPrimitive
import eu.kanade.tachiyomi.core.preference.AndroidPreference.Object
import eu.kanade.tachiyomi.core.preference.AndroidPreference.StringPrimitive
import eu.kanade.tachiyomi.core.preference.AndroidPreference.StringSetPrimitive
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow
class AndroidPreferenceStore(
context: Context
) : PreferenceStore {
private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
private val keyFlow = sharedPreferences.keyFlow
override fun getString(key: String, defaultValue: String): Preference<String> {
return StringPrimitive(sharedPreferences, keyFlow, key, defaultValue)
}
override fun getLong(key: String, defaultValue: Long): Preference<Long> {
return LongPrimitive(sharedPreferences, keyFlow,key, defaultValue)
}
override fun getInt(key: String, defaultValue: Int): Preference<Int> {
return IntPrimitive(sharedPreferences, keyFlow,key, defaultValue)
}
override fun getFloat(key: String, defaultValue: Float): Preference<Float> {
return FloatPrimitive(sharedPreferences, keyFlow,key, defaultValue)
}
override fun getBoolean(key: String, defaultValue: Boolean): Preference<Boolean> {
return BooleanPrimitive(sharedPreferences, keyFlow, key, defaultValue)
}
override fun getStringSet(key: String, defaultValue: Set<String>): Preference<Set<String>> {
return StringSetPrimitive(sharedPreferences, keyFlow, key, defaultValue)
}
override fun <T> getObject(
key: String,
defaultValue: T,
serializer: (T) -> String,
deserializer: (String) -> T,
): Preference<T> {
return Object(
preferences = sharedPreferences,
keyFlow = keyFlow,
key = key,
defaultValue = defaultValue,
serializer = serializer,
deserializer = deserializer
)
}
}
private val SharedPreferences.keyFlow
get() = callbackFlow {
val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key: String? -> trySend(key) }
registerOnSharedPreferenceChangeListener(listener)
awaitClose {
unregisterOnSharedPreferenceChangeListener(listener)
}
}

View File

@ -0,0 +1,27 @@
package eu.kanade.tachiyomi.core.preference
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
interface Preference<T> {
fun key(): String
fun get(): T
fun set(value: T)
fun isSet(): Boolean
fun delete()
fun defaultValue(): T
fun changes(): Flow<T>
fun stateIn(scope: CoroutineScope): StateFlow<T>
}
inline fun <reified T, R : T> Preference<T>.getAndSet(crossinline block: (T) -> R) = set(block(get()))

View File

@ -0,0 +1,42 @@
package eu.kanade.tachiyomi.core.preference
interface PreferenceStore {
fun getString(key: String, defaultValue: String = ""): Preference<String>
fun getLong(key: String, defaultValue: Long = 0): Preference<Long>
fun getInt(key: String, defaultValue: Int = 0): Preference<Int>
fun getFloat(key: String, defaultValue: Float = 0f): Preference<Float>
fun getBoolean(key: String, defaultValue: Boolean = false): Preference<Boolean>
fun getStringSet(key: String, defaultValue: Set<String> = emptySet()): Preference<Set<String>>
fun <T> getObject(
key: String,
defaultValue: T,
serializer: (T) -> String,
deserializer: (String) -> T
): Preference<T>
}
inline fun <reified T : Enum<T>> PreferenceStore.getEnum(
key: String,
defaultValue: T
) : Preference<T> {
return getObject(
key = key,
defaultValue = defaultValue,
serializer = { it.name },
deserializer = {
try {
enumValueOf(it)
} catch (e: IllegalArgumentException) {
defaultValue
}
}
)
}

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.network package eu.kanade.tachiyomi.network
import android.content.Context import android.content.Context
import androidx.preference.PreferenceManager
import eu.kanade.tachiyomi.i18n.BuildConfig import eu.kanade.tachiyomi.i18n.BuildConfig
import eu.kanade.tachiyomi.network.interceptor.CloudflareInterceptor import eu.kanade.tachiyomi.network.interceptor.CloudflareInterceptor
import eu.kanade.tachiyomi.network.interceptor.Http103Interceptor import eu.kanade.tachiyomi.network.interceptor.Http103Interceptor
@ -9,14 +8,14 @@ import eu.kanade.tachiyomi.network.interceptor.UserAgentInterceptor
import okhttp3.Cache import okhttp3.Cache
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor import okhttp3.logging.HttpLoggingInterceptor
import uy.kohesive.injekt.injectLazy
import java.io.File import java.io.File
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
/* SY --> */ /* SY --> */
open /* SY <-- */ class NetworkHelper(context: Context) { open /* SY <-- */ class NetworkHelper(context: Context) {
// TODO: Abstract preferences similar to 1.x private val preferences: NetworkPreferences by injectLazy()
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
private val cacheDir = File(context.cacheDir, "network_cache") private val cacheDir = File(context.cacheDir, "network_cache")
private val cacheSize = 5L * 1024 * 1024 // 5 MiB private val cacheSize = 5L * 1024 * 1024 // 5 MiB
@ -46,7 +45,7 @@ open /* SY <-- */ class NetworkHelper(context: Context) {
builder.addNetworkInterceptor(httpLoggingInterceptor) builder.addNetworkInterceptor(httpLoggingInterceptor)
} }
when (preferences.getInt("doh_provider", -1)) { when (preferences.dohProvider().get()) {
PREF_DOH_CLOUDFLARE -> builder.dohCloudflare() PREF_DOH_CLOUDFLARE -> builder.dohCloudflare()
PREF_DOH_GOOGLE -> builder.dohGoogle() PREF_DOH_GOOGLE -> builder.dohGoogle()
PREF_DOH_ADGUARD -> builder.dohAdGuard() PREF_DOH_ADGUARD -> builder.dohAdGuard()
@ -74,6 +73,6 @@ open /* SY <-- */ class NetworkHelper(context: Context) {
} }
val defaultUserAgent by lazy { val defaultUserAgent by lazy {
preferences.getString("default_user_agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0")!! preferences.defaultUserAgent().get()
} }
} }

View File

@ -0,0 +1,23 @@
package eu.kanade.tachiyomi.network
import eu.kanade.tachiyomi.core.preference.Preference
import eu.kanade.tachiyomi.core.preference.PreferenceStore
class NetworkPreferences(
private val preferenceStore: PreferenceStore,
private val verboseLogging: Boolean = false
) {
fun verboseLogging(): Preference<Boolean> {
return preferenceStore.getBoolean("verbose_logging", verboseLogging)
}
fun dohProvider(): Preference<Int> {
return preferenceStore.getInt("doh_provider", -1)
}
fun defaultUserAgent(): Preference<String> {
return preferenceStore.getString("default_user_agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0")
}
}

View File

@ -0,0 +1,17 @@
package exh.pref
import eu.kanade.tachiyomi.core.preference.Preference
import eu.kanade.tachiyomi.core.preference.PreferenceStore
class SourcePreferences(
private val preferenceStore: PreferenceStore,
) {
fun delegateSources(): Preference<Boolean> {
return preferenceStore.getBoolean("eh_delegate_sources", true)
}
fun useJapaneseTitle(): Preference<Boolean> {
return preferenceStore.getBoolean("use_jp_title", false)
}
}

View File

@ -37,7 +37,6 @@ sqlitektx = "androidx.sqlite:sqlite-ktx:2.3.0-alpha05"
sqlite-android = "com.github.requery:sqlite-android:3.36.0" sqlite-android = "com.github.requery:sqlite-android:3.36.0"
preferencektx = "androidx.preference:preference-ktx:1.2.0" preferencektx = "androidx.preference:preference-ktx:1.2.0"
flowpreferences = "com.fredporciuncula:flow-preferences:1.8.0"
nucleus-core = { module = "info.android15.nucleus:nucleus", version.ref = "nucleus_version" } nucleus-core = { module = "info.android15.nucleus:nucleus", version.ref = "nucleus_version" }
nucleus-supportv7 = { module = "info.android15.nucleus:nucleus-support-v7", version.ref = "nucleus_version" } nucleus-supportv7 = { module = "info.android15.nucleus:nucleus-support-v7", version.ref = "nucleus_version" }

View File

@ -14,6 +14,7 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import exh.log.maybeInjectEHLogger import exh.log.maybeInjectEHLogger
import exh.pref.SourcePreferences
import exh.source.DelegatedHttpSource import exh.source.DelegatedHttpSource
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -409,7 +410,7 @@ abstract class HttpSource : CatalogueSource {
// EXH --> // EXH -->
private var delegate: DelegatedHttpSource? = null private var delegate: DelegatedHttpSource? = null
get() = if (Injekt.get<NetworkHelper>().preferences.getBoolean("eh_delegate_sources", true)) { // todo get() = if (Injekt.get<SourcePreferences>().delegateSources().get()) {
field field
} else { } else {
null null

View File

@ -2,12 +2,12 @@ package exh.metadata.metadata
import android.content.Context import android.content.Context
import androidx.core.net.toUri import androidx.core.net.toUri
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.source.R import eu.kanade.tachiyomi.source.R
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.model.copy import eu.kanade.tachiyomi.source.model.copy
import exh.metadata.MetadataUtil import exh.metadata.MetadataUtil
import exh.metadata.metadata.base.RaisedSearchMetadata import exh.metadata.metadata.base.RaisedSearchMetadata
import exh.pref.SourcePreferences
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -53,7 +53,7 @@ class EHentaiSearchMetadata : RaisedSearchMetadata() {
// No title bug? // No title bug?
val title = altTitle val title = altTitle
?.takeIf { Injekt.get<NetworkHelper>().preferences.getBoolean("use_jp_title", false) } // todo ?.takeIf { Injekt.get<SourcePreferences>().useJapaneseTitle().get() } // todo
?: title ?: title
// Set artist (if we can find one) // Set artist (if we can find one)

View File

@ -6,13 +6,15 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import exh.pref.SourcePreferences
import okhttp3.Response import okhttp3.Response
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@Suppress("OverridingDeprecatedMember", "DEPRECATION") @Suppress("OverridingDeprecatedMember", "DEPRECATION")
class EnhancedHttpSource( class EnhancedHttpSource(
val originalSource: HttpSource, val originalSource: HttpSource,
val enhancedSource: HttpSource, val enhancedSource: HttpSource
val delegateSources:() -> Boolean
) : HttpSource() { ) : HttpSource() {
/** /**
@ -247,7 +249,7 @@ class EnhancedHttpSource(
override fun getFilterList() = source().getFilterList() override fun getFilterList() = source().getFilterList()
fun source(): HttpSource { fun source(): HttpSource {
return if (delegateSources()) { return if (Injekt.get<SourcePreferences>().delegateSources().get()) {
enhancedSource enhancedSource
} else { } else {
originalSource originalSource