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
implementation(libs.preferencektx)
implementation(libs.flowpreferences)
// Model View Presenter
implementation(libs.bundles.nucleus)

View File

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

View File

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

View File

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

View File

@ -16,7 +16,7 @@ class GetExtensionSources(
val isMultiLangSingleSource =
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
extension.sources

View File

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

View File

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

View File

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

View File

@ -15,8 +15,8 @@ class GetLanguagesWithSources(
fun subscribe(): Flow<Map<String, List<Source>>> {
return combine(
preferences.enabledLanguages().asFlow(),
preferences.disabledSources().asFlow(),
preferences.enabledLanguages().changes(),
preferences.disabledSources().changes(),
repository.getOnlineSources(),
) { enabledLanguage, disabledSource, onlineSources ->
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> {
return preferences.useNewSourceNavigation().asFlow()
return preferences.useNewSourceNavigation().changes()
.map {
mode == SourcesController.Mode.CATALOGUE && !it
}

View File

@ -9,6 +9,6 @@ class GetSourceCategories(
) {
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) {
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>>> {
return combine(
preferences.migrationSortingDirection().asFlow(),
preferences.migrationSortingMode().asFlow(),
preferences.migrationSortingDirection().changes(),
preferences.migrationSortingMode().changes(),
repository.getSourcesWithFavoriteCount(),
) { direction, mode, list ->
list.sortedWith(sortFn(direction, mode))

View File

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

View File

@ -1,6 +1,7 @@
package eu.kanade.domain.source.interactor
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.util.preference.minusAssign
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()) {
if (enable) {
preferences.disabledSources() -= sourceId.toString()
} else {
preferences.disabledSources() += sourceId.toString()
preferences.disabledSources().getAndSet { disabled ->
if (enable) disabled.minus("$sourceId") else disabled.plus("$sourceId")
}
}
}

View File

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

View File

@ -1,20 +1,20 @@
package eu.kanade.domain.source.interactor
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.util.preference.minusAssign
import eu.kanade.tachiyomi.util.preference.plusAssign
class ToggleSources(
private val preferences: PreferencesHelper,
) {
fun await(isEnable: Boolean, sources: List<Source>) {
val newDisabledSources = if (isEnable) {
preferences.disabledSources().get() - sources.map { it.id.toString() }
} else {
preferences.disabledSources().get() + sources.map { it.id.toString() }
preferences.disabledSources().getAndSet { disabledSources ->
if (isEnable) {
disabledSources - sources.map { it.id.toString() }.toSet()
} else {
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.glance.UpdatesGridGlanceWidget
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.network.NetworkPreferences
import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate
import eu.kanade.tachiyomi.util.preference.asHotFlow
import eu.kanade.tachiyomi.util.system.WebViewUtil
@ -88,6 +89,7 @@ import kotlin.time.Duration.Companion.days
class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
private val preferences: PreferencesHelper by injectLazy()
private val networkPreferences: NetworkPreferences by injectLazy()
private val disableIncognitoReceiver = DisableIncognitoReceiver()
@ -111,8 +113,10 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
}
Injekt.importModule(AppModule(this))
Injekt.importModule(PreferenceModule(this))
Injekt.importModule(DomainModule())
// SY -->
Injekt.importModule(SYPreferenceModule(this))
Injekt.importModule(SYDomainModule())
// SY <--
@ -124,7 +128,7 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
// Show notification to disable Incognito Mode when it's enabled
preferences.incognitoMode().asFlow()
preferences.incognitoMode().changes()
.onEach { enabled ->
val notificationManager = NotificationManagerCompat.from(this)
if (enabled) {
@ -175,7 +179,7 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
}
.launchIn(ProcessLifecycleOwner.get().lifecycleScope)
/*if (!LogcatLogger.isInstalled && preferences.verboseLogging()) {
/*if (!LogcatLogger.isInstalled && networkPreferences.verboseLogging().get()) {
LogcatLogger.install(AndroidLogcatLogger(LogPriority.VERBOSE))
}*/
}
@ -206,7 +210,7 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
diskCache(diskCacheInit)
crossfade((300 * this@App.animatorDurationScale).toInt())
allowRgb565(getSystemService<ActivityManager>()!!.isLowRamDevice)
if (preferences.verboseLogging()) logger(DebugLogger())
if (networkPreferences.verboseLogging().get()) logger(DebugLogger())
}.build()
}

View File

@ -16,6 +16,8 @@ import eu.kanade.data.dateAdapter
import eu.kanade.data.listOfLongsAdapter
import eu.kanade.data.listOfStringsAdapter
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.CoverCache
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.extension.ExtensionManager
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.network.NetworkPreferences
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.util.system.isDevFlavor
import exh.eh.EHentaiUpdateHelper
import exh.pref.SourcePreferences
import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory
import kotlinx.serialization.json.Json
import uy.kohesive.injekt.api.InjektModule
@ -98,8 +103,6 @@ class AppModule(val app: Application) : InjektModule {
}
}
addSingletonFactory { PreferencesHelper(app) }
addSingletonFactory { ChapterCache(app) }
addSingletonFactory { CoverCache(app) }
@ -128,8 +131,6 @@ class AppModule(val app: Application) : InjektModule {
// Asynchronously init expensive components for a faster cold start
ContextCompat.getMainExecutor(app).execute {
get<PreferencesHelper>()
get<NetworkHelper>()
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
import android.content.Context
import android.os.Build
import androidx.core.content.edit
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.updater.AppUpdateJob
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
import eu.kanade.tachiyomi.network.NetworkPreferences
import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
import eu.kanade.tachiyomi.util.preference.minusAssign
@ -33,9 +35,11 @@ object Migrations {
* @param preferences Preferences of the application.
* @return true if a migration is performed, false otherwise.
*/
fun upgrade(preferences: PreferencesHelper): Boolean {
val context = preferences.context
fun upgrade(
context: Context,
preferences: PreferencesHelper,
networkPreferences: NetworkPreferences,
): Boolean {
val oldVersion = preferences.lastVersionCode().get()
if (oldVersion < BuildConfig.VERSION_CODE) {
preferences.lastVersionCode().set(BuildConfig.VERSION_CODE)
@ -145,7 +149,7 @@ object Migrations {
val wasDohEnabled = prefs.getBoolean("enable_doh", false)
if (wasDohEnabled) {
prefs.edit {
putInt(PreferenceKeys.dohProvider, PREF_DOH_CLOUDFLARE)
putInt(networkPreferences.dohProvider().key(), PREF_DOH_CLOUDFLARE)
remove("enable_doh")
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -58,10 +58,6 @@ object PreferenceKeys {
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 defaultChapterFilterByDownloaded = "default_chapter_filter_by_downloaded"
@ -74,8 +70,6 @@ object PreferenceKeys {
const val defaultChapterDisplayByNameOrNumber = "default_chapter_display_by_name_or_number"
const val verboseLogging = "verbose_logging"
const val autoClearChapterCache = "auto_clear_chapter_cache"
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.os.Build
import android.os.Environment
import androidx.core.content.edit
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.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.track.TrackService
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.util.system.DeviceUtil
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.widget.ExtendedNavigationView
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.PreferenceValues as Values
class PreferencesHelper(val context: Context) {
private val prefs = PreferenceManager.getDefaultSharedPreferences(context)
val flowPrefs = FlowSharedPreferences(prefs)
class PreferencesHelper(
val context: Context,
private val preferenceStore: PreferenceStore,
) {
private val defaultDownloadsDir = File(
Environment.getExternalStorageDirectory().absolutePath + File.separator +
@ -49,484 +47,474 @@ class PreferencesHelper(val context: Context) {
"backup",
).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.
* 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",
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",
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 -->
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 <--
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) {
prefs.edit {
putString(Keys.trackUsername(sync.id), username)
putString(Keys.trackPassword(sync.id), password)
}
trackUsername(sync).set(username)
trackPassword(sync).set(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)
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 libraryUpdateLastTimestamp() = flowPrefs.getLong("library_update_last_timestamp", 0L)
fun libraryUpdateInterval() = this.preferenceStore.getInt("pref_library_update_interval_key", 24)
fun libraryUpdateLastTimestamp() = this.preferenceStore.getLong("library_update_last_timestamp", 0L)
fun libraryUpdateDeviceRestriction() = flowPrefs.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 libraryUpdateDeviceRestriction() = this.preferenceStore.getStringSet("library_update_restriction", setOf(DEVICE_ONLY_ON_WIFI))
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 unreadUpdatesCount() = flowPrefs.getInt("library_unread_updates_count", 0)
fun showUpdatesNavBadge() = this.preferenceStore.getBoolean("library_update_show_tab_badge", false)
fun unreadUpdatesCount() = this.preferenceStore.getInt("library_unread_updates_count", 0)
fun libraryUpdateCategories() = flowPrefs.getStringSet("library_update_categories", emptySet())
fun libraryUpdateCategoriesExclude() = flowPrefs.getStringSet("library_update_categories_exclude", emptySet())
fun libraryUpdateCategories() = this.preferenceStore.getStringSet("library_update_categories", 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 migrationSortingDirection() = flowPrefs.getEnum(Keys.migrationSortingDirection, SetMigrateSorting.Direction.ASCENDING)
fun librarySortingMode() = this.preferenceStore.getObject(Keys.librarySortingMode, LibrarySort.default, LibrarySort.Serializer::serialize, LibrarySort.Serializer::deserialize)
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 lastExtCheck() = flowPrefs.getLong("last_ext_check", 0)
fun extensionUpdatesCount() = this.preferenceStore.getInt("ext_updates_count", 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 downloadNewChapterCategoriesExclude() = flowPrefs.getStringSet("download_new_categories_exclude", emptySet())
fun downloadNewChapters() = this.preferenceStore.getBoolean("download_new", false)
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() = flowPrefs.getEnum(
fun extensionInstaller() = this.preferenceStore.getEnum(
"extension_installer",
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() = flowPrefs.getBoolean("duplicate_pinned_sources", false)
fun duplicatePinnedSources() = this.preferenceStore.getBoolean("duplicate_pinned_sources", false)
fun setChapterSettingsDefault(manga: Manga) {
prefs.edit {
putInt(Keys.defaultChapterFilterByRead, manga.readFilter)
putInt(Keys.defaultChapterFilterByDownloaded, manga.downloadedFilter)
putInt(Keys.defaultChapterFilterByBookmarked, manga.bookmarkedFilter)
putInt(Keys.defaultChapterSortBySourceOrNumber, manga.sorting)
putInt(Keys.defaultChapterDisplayByNameOrNumber, manga.displayMode)
putInt(Keys.defaultChapterSortByAscendingOrDescending, if (manga.sortDescending()) DomainManga.CHAPTER_SORT_DESC.toInt() else DomainManga.CHAPTER_SORT_ASC.toInt())
}
filterChapterByRead().set(manga.readFilter)
filterChapterByDownloaded().set(manga.downloadedFilter)
filterChapterByBookmarked().set(manga.bookmarkedFilter)
sortChapterBySourceOrNumber().set(manga.sorting)
displayChapterByNameOrNumber().set(manga.displayMode)
sortChapterByAscendingOrDescending().set(if (manga.sortDescending()) DomainManga.CHAPTER_SORT_DESC.toInt() else DomainManga.CHAPTER_SORT_ASC.toInt())
}
// 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
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 igneousVal() = flowPrefs.getString("eh_igneous", "")
fun ehSettingsProfile() = flowPrefs.getInt("eh_ehSettingsProfile", -1)
fun exhSettingsProfile() = flowPrefs.getInt("eh_exhSettingsProfile", -1)
fun exhSettingsKey() = flowPrefs.getString("eh_settingsKey", "")
fun exhSessionCookie() = flowPrefs.getString("eh_sessionCookie", "")
fun exhHathPerksCookies() = flowPrefs.getString("eh_hathPerksCookie", "")
fun passHashVal() = this.preferenceStore.getString("eh_ipb_pass_hash", "")
fun igneousVal() = this.preferenceStore.getString("eh_igneous", "")
fun ehSettingsProfile() = this.preferenceStore.getInt("eh_ehSettingsProfile", -1)
fun exhSettingsProfile() = this.preferenceStore.getInt("eh_exhSettingsProfile", -1)
fun exhSettingsKey() = this.preferenceStore.getString("eh_settingsKey", "")
fun exhSessionCookie() = this.preferenceStore.getString("eh_sessionCookie", "")
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() = flowPrefs.getString(
fun exhSettingsLanguages() = this.preferenceStore.getString(
"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",
)
fun exhEnabledCategories() = flowPrefs.getString(
fun exhEnabledCategories() = this.preferenceStore.getString(
"eh_enabled_categories",
"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() &&
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) {
preferences.setTrackCredentials(this, username, password)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -10,9 +10,9 @@ import android.widget.RadioButton
import android.widget.RadioGroup
import android.widget.Toast
import androidx.core.view.isVisible
import com.fredporciuncula.flow.preferences.Preference
import com.google.android.material.bottomsheet.BottomSheetBehavior
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.core.preference.Preference
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.MigrationBottomSheetBinding
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 }
.launchIn(presenterScope)
preferences.migrationSortingMode().asFlow()
preferences.migrationSortingMode().changes()
.onEach { state.sortingMode = it }
.launchIn(presenterScope)
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
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.PreferencesHelper
import kotlinx.coroutines.CoroutineScope
@ -76,7 +76,7 @@ abstract class ViewerConfig(preferences: PreferencesHelper, private val scope: C
valueAssignment: (T) -> Unit,
onChanged: (T) -> Unit = {},
) {
asFlow()
changes()
.onEach { valueAssignment(it) }
.distinctUntilChanged()
.onEach { onChanged(it) }

View File

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

View File

@ -63,7 +63,7 @@ class WebtoonConfig(
preferences.webtoonNavInverted()
.register({ tappingInverted = it }, { navigator.invertMode = it })
preferences.webtoonNavInverted().asFlow()
preferences.webtoonNavInverted().changes()
.drop(1)
.onEach { navigationModeChangedListener?.invoke() }
.launchIn(scope)
@ -83,7 +83,7 @@ class WebtoonConfig(
},
)
preferences.readerTheme().asFlow()
preferences.readerTheme().changes()
.drop(1)
.distinctUntilChanged()
.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.track.TrackManager
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_ADGUARD
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 exh.debug.SettingsDebugController
import exh.log.EHLogLevel
import exh.pref.SourcePreferences
import exh.source.BlacklistedSources
import exh.source.EH_SOURCE_ID
import exh.source.EXH_SOURCE_ID
@ -89,6 +91,8 @@ class SettingsAdvancedController(
private val network: NetworkHelper by injectLazy()
private val chapterCache: ChapterCache 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 getChapterByMangaId: GetChapterByMangaId by injectLazy()
private val pagePreviewCache: PagePreviewCache by injectLazy()
@ -110,7 +114,7 @@ class SettingsAdvancedController(
}
/*switchPreference {
key = Keys.verboseLogging
key = networkPreferences.verboseLogging().key()
titleRes = R.string.pref_verbose_logging
summaryRes = R.string.pref_verbose_logging_summary
defaultValue = isDevFlavor
@ -212,7 +216,7 @@ class SettingsAdvancedController(
onClick { clearWebViewData() }
}
intListPreference {
key = Keys.dohProvider
key = networkPreferences.dohProvider().key()
titleRes = R.string.pref_dns_over_https
entries = arrayOf(
context.getString(R.string.disabled),
@ -250,10 +254,11 @@ class SettingsAdvancedController(
true
}
}
val defaultUserAgent = networkPreferences.defaultUserAgent()
editTextPreference {
key = Keys.defaultUserAgent
key = defaultUserAgent.key()
titleRes = R.string.pref_user_agent_string
text = preferences.defaultUserAgent().get()
text = defaultUserAgent.get()
summary = network.defaultUserAgent
onChange {
@ -270,10 +275,10 @@ class SettingsAdvancedController(
key = "pref_reset_user_agent"
titleRes = R.string.pref_reset_user_agent_string
visibleIf(preferences.defaultUserAgent()) { it != preferences.defaultUserAgent().defaultValue }
visibleIf(defaultUserAgent) { it != defaultUserAgent.defaultValue() }
onClick {
preferences.defaultUserAgent().delete()
defaultUserAgent.delete()
activity?.toast(R.string.requires_app_restart)
}
}
@ -466,7 +471,7 @@ class SettingsAdvancedController(
}
switchPreference {
bindTo(preferences.delegateSources())
bindTo(sourcePreferences.delegateSources())
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())
}

View File

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

View File

@ -130,7 +130,7 @@ abstract class SettingsController : PreferenceController() {
(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) }
.launchIn(viewScope)
}

View File

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

View File

@ -12,12 +12,12 @@ import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.core.widget.doAfterTextChanged
import androidx.preference.PreferenceScreen
import com.fredporciuncula.flow.preferences.Preference
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import eu.kanade.domain.manga.interactor.DeleteFavoriteEntries
import eu.kanade.domain.manga.interactor.GetExhFavoriteMangaWithMetadata
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
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_ONLY_ON_WIFI
import eu.kanade.tachiyomi.databinding.DialogStubTextinputBinding
@ -75,7 +75,7 @@ class SettingsEhController : SettingsController() {
fun Preference<*>.reconfigure(): Boolean {
// Listen for change commit
asFlow()
changes()
.take(1) // Only listen for first commit
.onEach {
// Only listen for first change commit
@ -99,7 +99,7 @@ class SettingsEhController : SettingsController() {
summaryOff = context.getString(R.string.requires_login)
isPersistent = false
preferences.enableExhentai()
.asFlow()
.changes()
.onEach {
isChecked = it
}
@ -395,7 +395,7 @@ class SettingsEhController : SettingsController() {
)
entryValues = arrayOf("0", "1", "2", "3", "6", "12", "24", "48")
preferences.exhAutoUpdateFrequency().asFlow()
preferences.exhAutoUpdateFrequency().changes()
.onEach { newVal ->
summary = if (newVal == 0) {
context.getString(R.string.time_between_batches_summary_1, context.getString(R.string.app_name))
@ -445,7 +445,7 @@ class SettingsEhController : SettingsController() {
true
}
preferences.exhAutoUpdateRequirements().asFlow()
preferences.exhAutoUpdateRequirements().changes()
.onEach { updateSummary() }
.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) ->
val portrait = getColumnValue(portraitCols)
val landscape = getColumnValue(landscapeCols)
@ -117,7 +117,7 @@ class SettingsLibraryController : SettingsController() {
entryValues = arrayOf("-1") + allCategories.map { it.id.toString() }.toTypedArray()
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)
?: context.getString(R.string.default_category_summary)
onChange { newValue ->
@ -132,7 +132,7 @@ class SettingsLibraryController : SettingsController() {
bindTo(preferences.categorizedDisplaySettings())
titleRes = R.string.categorized_display_settings
preferences.categorizedDisplaySettings().asFlow()
preferences.categorizedDisplaySettings().changes()
.onEach {
if (it.not()) {
resetCategoryFlags.await()
@ -200,7 +200,7 @@ class SettingsLibraryController : SettingsController() {
summary = context.getString(R.string.restrictions, restrictionsText)
}
preferences.libraryUpdateDeviceRestriction().asFlow()
preferences.libraryUpdateDeviceRestriction().changes()
.onEach { updateSummary() }
.launchIn(viewScope)
}
@ -229,7 +229,7 @@ class SettingsLibraryController : SettingsController() {
summary = restrictionsText
}
preferences.libraryUpdateMangaRestriction().asFlow()
preferences.libraryUpdateMangaRestriction().changes()
.onEach { updateSummary() }
.launchIn(viewScope)
}
@ -272,10 +272,10 @@ class SettingsLibraryController : SettingsController() {
}
}
preferences.libraryUpdateCategories().asFlow()
preferences.libraryUpdateCategories().changes()
.onEach { updateSummary() }
.launchIn(viewScope)
preferences.libraryUpdateCategoriesExclude().asFlow()
preferences.libraryUpdateCategoriesExclude().changes()
.onEach { updateSummary() }
.launchIn(viewScope)
}

View File

@ -27,12 +27,12 @@ object ChapterSettingsHelper {
suspend fun applySettingDefaults(mangaId: Long) {
setMangaChapterFlags.awaitSetAllFlags(
mangaId = mangaId,
unreadFilter = preferences.filterChapterByRead().toLong(),
downloadedFilter = preferences.filterChapterByDownloaded().toLong(),
bookmarkedFilter = preferences.filterChapterByBookmarked().toLong(),
sortingMode = preferences.sortChapterBySourceOrNumber().toLong(),
sortingDirection = preferences.sortChapterByAscendingOrDescending().toLong(),
displayMode = preferences.displayChapterByNameOrNumber().toLong(),
unreadFilter = preferences.filterChapterByRead().get().toLong(),
downloadedFilter = preferences.filterChapterByDownloaded().get().toLong(),
bookmarkedFilter = preferences.filterChapterByBookmarked().get().toLong(),
sortingMode = preferences.sortChapterBySourceOrNumber().get().toLong(),
sortingDirection = preferences.sortChapterByAscendingOrDescending().get().toLong(),
displayMode = preferences.displayChapterByNameOrNumber().get().toLong(),
)
}
@ -45,12 +45,12 @@ object ChapterSettingsHelper {
.map { manga ->
setMangaChapterFlags.awaitSetAllFlags(
mangaId = manga.id,
unreadFilter = preferences.filterChapterByRead().toLong(),
downloadedFilter = preferences.filterChapterByDownloaded().toLong(),
bookmarkedFilter = preferences.filterChapterByBookmarked().toLong(),
sortingMode = preferences.sortChapterBySourceOrNumber().toLong(),
sortingDirection = preferences.sortChapterByAscendingOrDescending().toLong(),
displayMode = preferences.displayChapterByNameOrNumber().toLong(),
unreadFilter = preferences.filterChapterByRead().get().toLong(),
downloadedFilter = preferences.filterChapterByDownloaded().get().toLong(),
bookmarkedFilter = preferences.filterChapterByBookmarked().get().toLong(),
sortingMode = preferences.sortChapterBySourceOrNumber().get().toLong(),
sortingDirection = preferences.sortChapterByAscendingOrDescending().get().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>) {
key = preference.key
defaultValue = preference.defaultValue
inline fun <T> Preference.bindTo(preference: eu.kanade.tachiyomi.core.preference.Preference<T>) {
key = preference.key()
defaultValue = preference.defaultValue()
}
inline fun <T> ListPreference.bindTo(preference: com.fredporciuncula.flow.preferences.Preference<T>) {
key = preference.key
// ListPreferences persist values as strings, even when we're using our IntListPreference
defaultValue = preference.defaultValue.toString()
inline fun <T> ListPreference.bindTo(preference: eu.kanade.tachiyomi.core.preference.Preference<T>) {
key = preference.key()
defaultValue = preference.defaultValue().toString()
}
inline fun Preference.onClick(crossinline block: () -> Unit) {

View File

@ -1,7 +1,7 @@
package eu.kanade.tachiyomi.util.preference
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.onEach
@ -15,7 +15,7 @@ fun CompoundButton.bindToPreference(pref: Preference<Boolean>) {
fun <T> Preference<T>.asHotFlow(block: (T) -> Unit): Flow<T> {
block(get())
return asFlow()
return changes()
.onEach { block(it) }
}

View File

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

View File

@ -31,13 +31,15 @@ class TachiyomiSearchView @JvmOverloads constructor(
override fun onAttachedToWindow() {
super.onAttachedToWindow()
scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
Injekt.get<PreferencesHelper>().incognitoMode().asHotFlow {
imeOptions = if (it) {
imeOptions or EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING
} else {
imeOptions and EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING.inv()
Injekt.get<PreferencesHelper>().incognitoMode()
.asHotFlow {
imeOptions = if (it) {
imeOptions or EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING
} else {
imeOptions and EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING.inv()
}
}
}.launchIn(scope!!)
.launchIn(scope!!)
}
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.
*/
fun EditText.setIncognito(viewScope: CoroutineScope) {
Injekt.get<PreferencesHelper>().incognitoMode().asHotFlow {
imeOptions = if (it) {
imeOptions or EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING
} else {
imeOptions and EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING.inv()
Injekt.get<PreferencesHelper>().incognitoMode()
.asHotFlow {
imeOptions = if (it) {
imeOptions or EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING
} else {
imeOptions and EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING.inv()
}
}
}.launchIn(viewScope)
.launchIn(viewScope)
}
}
}

View File

@ -2,6 +2,7 @@
package exh
import android.content.Context
import androidx.core.content.edit
import androidx.preference.PreferenceManager
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.updater.AppUpdateJob
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
import eu.kanade.tachiyomi.network.NetworkPreferences
import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceManager
@ -87,8 +89,11 @@ object EXHMigrations {
* @param preferences Preferences of the application.
* @return true if a migration is performed, false otherwise.
*/
fun upgrade(preferences: PreferencesHelper): Boolean {
val context = preferences.context
fun upgrade(
context: Context,
preferences: PreferencesHelper,
networkPreferences: NetworkPreferences,
): Boolean {
val oldVersion = preferences.ehLastVersionCode().get()
try {
if (oldVersion < BuildConfig.VERSION_CODE) {
@ -211,7 +216,7 @@ object EXHMigrations {
val wasDohEnabled = prefs.getBoolean("enable_doh", false)
if (wasDohEnabled) {
prefs.edit {
putInt(PreferenceKeys.dohProvider, PREF_DOH_CLOUDFLARE)
putInt(networkPreferences.dohProvider().key(), PREF_DOH_CLOUDFLARE)
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.UpdateManga
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.network.NetworkPreferences
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.online.all.NHentai
import exh.EXHMigrations
@ -30,6 +31,7 @@ object DebugFunctions {
val app: Application by injectLazy()
val handler: DatabaseHandler by injectLazy()
val prefs: PreferencesHelper by injectLazy()
val networkPrefs: NetworkPreferences by injectLazy()
val sourceManager: SourceManager by injectLazy()
val updateManga: UpdateManga by injectLazy()
val getFavorites: GetFavorites by injectLazy()
@ -41,12 +43,12 @@ object DebugFunctions {
fun forceUpgradeMigration() {
prefs.ehLastVersionCode().set(1)
EXHMigrations.upgrade(prefs)
EXHMigrations.upgrade(app, prefs, networkPrefs)
}
fun forceSetupJobs() {
prefs.ehLastVersionCode().set(0)
EXHMigrations.upgrade(prefs)
EXHMigrations.upgrade(app, prefs, networkPrefs)
}
fun resetAgedFlagInEXHManga() {

View File

@ -1,7 +1,7 @@
package exh.debug
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 uy.kohesive.injekt.injectLazy
import java.util.Locale
@ -26,14 +26,14 @@ enum class DebugToggles(val default: Boolean) {
private val prefKey = "eh_debug_toggle_${name.lowercase(Locale.US)}"
var enabled: Boolean
get() = prefs.flowPrefs.getBoolean(prefKey, default).get()
get() = preferenceStore.getBoolean(prefKey, default).get()
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 {
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 {
val username = preferences.trackUsername(mdList)
val password = preferences.trackPassword(mdList)
if (username.isNullOrBlank() || password.isNullOrBlank()) {
val username = preferences.trackUsername(mdList).get()
val password = preferences.trackPassword(mdList).get()
if (username.isBlank() || password.isBlank()) {
xLogI("No username or password stored, can't login")
return false
}

View File

@ -1,6 +1,6 @@
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.source.Source
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
import android.content.Context
import androidx.preference.PreferenceManager
import eu.kanade.tachiyomi.i18n.BuildConfig
import eu.kanade.tachiyomi.network.interceptor.CloudflareInterceptor
import eu.kanade.tachiyomi.network.interceptor.Http103Interceptor
@ -9,14 +8,14 @@ import eu.kanade.tachiyomi.network.interceptor.UserAgentInterceptor
import okhttp3.Cache
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import uy.kohesive.injekt.injectLazy
import java.io.File
import java.util.concurrent.TimeUnit
/* SY --> */
open /* SY <-- */ class NetworkHelper(context: Context) {
// TODO: Abstract preferences similar to 1.x
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
private val preferences: NetworkPreferences by injectLazy()
private val cacheDir = File(context.cacheDir, "network_cache")
private val cacheSize = 5L * 1024 * 1024 // 5 MiB
@ -46,7 +45,7 @@ open /* SY <-- */ class NetworkHelper(context: Context) {
builder.addNetworkInterceptor(httpLoggingInterceptor)
}
when (preferences.getInt("doh_provider", -1)) {
when (preferences.dohProvider().get()) {
PREF_DOH_CLOUDFLARE -> builder.dohCloudflare()
PREF_DOH_GOOGLE -> builder.dohGoogle()
PREF_DOH_ADGUARD -> builder.dohAdGuard()
@ -74,6 +73,6 @@ open /* SY <-- */ class NetworkHelper(context: Context) {
}
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"
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-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.SManga
import exh.log.maybeInjectEHLogger
import exh.pref.SourcePreferences
import exh.source.DelegatedHttpSource
import okhttp3.Headers
import okhttp3.OkHttpClient
@ -409,7 +410,7 @@ abstract class HttpSource : CatalogueSource {
// EXH -->
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
} else {
null

View File

@ -2,12 +2,12 @@ package exh.metadata.metadata
import android.content.Context
import androidx.core.net.toUri
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.source.R
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.model.copy
import exh.metadata.MetadataUtil
import exh.metadata.metadata.base.RaisedSearchMetadata
import exh.pref.SourcePreferences
import kotlinx.serialization.Serializable
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -53,7 +53,7 @@ class EHentaiSearchMetadata : RaisedSearchMetadata() {
// No title bug?
val title = altTitle
?.takeIf { Injekt.get<NetworkHelper>().preferences.getBoolean("use_jp_title", false) } // todo
?.takeIf { Injekt.get<SourcePreferences>().useJapaneseTitle().get() } // todo
?: title
// 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.SManga
import eu.kanade.tachiyomi.source.online.HttpSource
import exh.pref.SourcePreferences
import okhttp3.Response
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@Suppress("OverridingDeprecatedMember", "DEPRECATION")
class EnhancedHttpSource(
val originalSource: HttpSource,
val enhancedSource: HttpSource,
val delegateSources:() -> Boolean
val enhancedSource: HttpSource
) : HttpSource() {
/**
@ -247,7 +249,7 @@ class EnhancedHttpSource(
override fun getFilterList() = source().getFilterList()
fun source(): HttpSource {
return if (delegateSources()) {
return if (Injekt.get<SourcePreferences>().delegateSources().get()) {
enhancedSource
} else {
originalSource