mirror of
https://github.com/mihonapp/mihon.git
synced 2024-11-21 20:47:03 -05:00
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>
This commit is contained in:
parent
bc8c45832e
commit
0086743a53
64 changed files with 698 additions and 340 deletions
|
@ -226,7 +226,6 @@ dependencies {
|
||||||
|
|
||||||
// Preferences
|
// Preferences
|
||||||
implementation(libs.preferencektx)
|
implementation(libs.preferencektx)
|
||||||
implementation(libs.flowpreferences)
|
|
||||||
|
|
||||||
// Model View Presenter
|
// Model View Presenter
|
||||||
implementation(libs.bundles.nucleus)
|
implementation(libs.bundles.nucleus)
|
||||||
|
|
|
@ -2,9 +2,8 @@ package eu.kanade.core.prefs
|
||||||
|
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import com.fredporciuncula.flow.preferences.Preference
|
import eu.kanade.tachiyomi.core.preference.Preference
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|
||||||
|
@ -16,8 +15,7 @@ class PreferenceMutableState<T>(
|
||||||
private val state = mutableStateOf(preference.get())
|
private val state = mutableStateOf(preference.get())
|
||||||
|
|
||||||
init {
|
init {
|
||||||
preference.asFlow()
|
preference.changes()
|
||||||
.distinctUntilChanged()
|
|
||||||
.onEach { state.value = it }
|
.onEach { state.value = it }
|
||||||
.launchIn(scope)
|
.launchIn(scope)
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ class SetReadStatus(
|
||||||
return@withContext Result.InternalError(e)
|
return@withContext Result.InternalError(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read && preferences.removeAfterMarkedAsRead()) {
|
if (read && preferences.removeAfterMarkedAsRead().get()) {
|
||||||
manga.forEach {
|
manga.forEach {
|
||||||
deleteDownload.awaitAll(
|
deleteDownload.awaitAll(
|
||||||
manga = it,
|
manga = it,
|
||||||
|
|
|
@ -12,7 +12,7 @@ class GetExtensionLanguages(
|
||||||
) {
|
) {
|
||||||
fun subscribe(): Flow<List<String>> {
|
fun subscribe(): Flow<List<String>> {
|
||||||
return combine(
|
return combine(
|
||||||
preferences.enabledLanguages().asFlow(),
|
preferences.enabledLanguages().changes(),
|
||||||
extensionManager.getAvailableExtensionsFlow(),
|
extensionManager.getAvailableExtensionsFlow(),
|
||||||
) { enabledLanguage, availableExtensions ->
|
) { enabledLanguage, availableExtensions ->
|
||||||
availableExtensions
|
availableExtensions
|
||||||
|
|
|
@ -16,7 +16,7 @@ class GetExtensionSources(
|
||||||
val isMultiLangSingleSource =
|
val isMultiLangSingleSource =
|
||||||
isMultiSource && extension.sources.map { it.name }.distinct().size == 1
|
isMultiSource && extension.sources.map { it.name }.distinct().size == 1
|
||||||
|
|
||||||
return preferences.disabledSources().asFlow().map { disabledSources ->
|
return preferences.disabledSources().changes().map { disabledSources ->
|
||||||
fun Source.isEnabled() = id.toString() !in disabledSources
|
fun Source.isEnabled() = id.toString() !in disabledSources
|
||||||
|
|
||||||
extension.sources
|
extension.sources
|
||||||
|
|
|
@ -16,7 +16,7 @@ class GetExtensionsByType(
|
||||||
val showNsfwSources = preferences.showNsfwSource().get()
|
val showNsfwSources = preferences.showNsfwSource().get()
|
||||||
|
|
||||||
return combine(
|
return combine(
|
||||||
preferences.enabledLanguages().asFlow(),
|
preferences.enabledLanguages().changes(),
|
||||||
extensionManager.getInstalledExtensionsFlow(),
|
extensionManager.getInstalledExtensionsFlow(),
|
||||||
extensionManager.getUntrustedExtensionsFlow(),
|
extensionManager.getUntrustedExtensionsFlow(),
|
||||||
extensionManager.getAvailableExtensionsFlow(),
|
extensionManager.getAvailableExtensionsFlow(),
|
||||||
|
|
|
@ -17,10 +17,10 @@ class GetEnabledSources(
|
||||||
|
|
||||||
fun subscribe(): Flow<List<Source>> {
|
fun subscribe(): Flow<List<Source>> {
|
||||||
return combine(
|
return combine(
|
||||||
preferences.pinnedSources().asFlow(),
|
preferences.pinnedSources().changes(),
|
||||||
preferences.enabledLanguages().asFlow(),
|
preferences.enabledLanguages().changes(),
|
||||||
preferences.disabledSources().asFlow(),
|
preferences.disabledSources().changes(),
|
||||||
preferences.lastUsedSource().asFlow(),
|
preferences.lastUsedSource().changes(),
|
||||||
repository.getSources(),
|
repository.getSources(),
|
||||||
) { pinnedSourceIds, enabledLanguages, disabledSources, lastUsedSource, sources ->
|
) { pinnedSourceIds, enabledLanguages, disabledSources, lastUsedSource, sources ->
|
||||||
val duplicatePins = preferences.duplicatePinnedSources().get()
|
val duplicatePins = preferences.duplicatePinnedSources().get()
|
||||||
|
|
|
@ -14,8 +14,8 @@ class GetLanguagesWithSources(
|
||||||
|
|
||||||
fun subscribe(): Flow<Map<String, List<Source>>> {
|
fun subscribe(): Flow<Map<String, List<Source>>> {
|
||||||
return combine(
|
return combine(
|
||||||
preferences.enabledLanguages().asFlow(),
|
preferences.enabledLanguages().changes(),
|
||||||
preferences.disabledSources().asFlow(),
|
preferences.disabledSources().changes(),
|
||||||
repository.getOnlineSources(),
|
repository.getOnlineSources(),
|
||||||
) { enabledLanguage, disabledSource, onlineSources ->
|
) { enabledLanguage, disabledSource, onlineSources ->
|
||||||
val sortedSources = onlineSources.sortedWith(
|
val sortedSources = onlineSources.sortedWith(
|
||||||
|
|
|
@ -16,8 +16,8 @@ class GetSourcesWithFavoriteCount(
|
||||||
|
|
||||||
fun subscribe(): Flow<List<Pair<Source, Long>>> {
|
fun subscribe(): Flow<List<Pair<Source, Long>>> {
|
||||||
return combine(
|
return combine(
|
||||||
preferences.migrationSortingDirection().asFlow(),
|
preferences.migrationSortingDirection().changes(),
|
||||||
preferences.migrationSortingMode().asFlow(),
|
preferences.migrationSortingMode().changes(),
|
||||||
repository.getSourcesWithFavoriteCount(),
|
repository.getSourcesWithFavoriteCount(),
|
||||||
) { direction, mode, list ->
|
) { direction, mode, list ->
|
||||||
list.sortedWith(sortFn(direction, mode))
|
list.sortedWith(sortFn(direction, mode))
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package eu.kanade.domain.source.interactor
|
package eu.kanade.domain.source.interactor
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.core.preference.getAndSet
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.util.preference.minusAssign
|
import eu.kanade.tachiyomi.util.preference.minusAssign
|
||||||
import eu.kanade.tachiyomi.util.preference.plusAssign
|
import eu.kanade.tachiyomi.util.preference.plusAssign
|
||||||
|
@ -9,11 +10,9 @@ class ToggleLanguage(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun await(language: String) {
|
fun await(language: String) {
|
||||||
val enabled = language in preferences.enabledLanguages().get()
|
val isEnabled = language in preferences.enabledLanguages().get()
|
||||||
if (enabled) {
|
preferences.enabledLanguages().getAndSet { enabled ->
|
||||||
preferences.enabledLanguages() -= language
|
if (isEnabled) enabled.minus(language) else enabled.plus(language)
|
||||||
} else {
|
|
||||||
preferences.enabledLanguages() += language
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package eu.kanade.domain.source.interactor
|
package eu.kanade.domain.source.interactor
|
||||||
|
|
||||||
import eu.kanade.domain.source.model.Source
|
import eu.kanade.domain.source.model.Source
|
||||||
|
import eu.kanade.tachiyomi.core.preference.getAndSet
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.util.preference.minusAssign
|
import eu.kanade.tachiyomi.util.preference.minusAssign
|
||||||
import eu.kanade.tachiyomi.util.preference.plusAssign
|
import eu.kanade.tachiyomi.util.preference.plusAssign
|
||||||
|
@ -14,10 +15,8 @@ class ToggleSource(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun await(sourceId: Long, enable: Boolean = sourceId.toString() in preferences.disabledSources().get()) {
|
fun await(sourceId: Long, enable: Boolean = sourceId.toString() in preferences.disabledSources().get()) {
|
||||||
if (enable) {
|
preferences.disabledSources().getAndSet { disabled ->
|
||||||
preferences.disabledSources() -= sourceId.toString()
|
if (enable) disabled.minus("$sourceId") else disabled.plus("$sourceId")
|
||||||
} else {
|
|
||||||
preferences.disabledSources() += sourceId.toString()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package eu.kanade.domain.source.interactor
|
package eu.kanade.domain.source.interactor
|
||||||
|
|
||||||
import eu.kanade.domain.source.model.Source
|
import eu.kanade.domain.source.model.Source
|
||||||
|
import eu.kanade.tachiyomi.core.preference.getAndSet
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.util.preference.minusAssign
|
import eu.kanade.tachiyomi.util.preference.minusAssign
|
||||||
import eu.kanade.tachiyomi.util.preference.plusAssign
|
import eu.kanade.tachiyomi.util.preference.plusAssign
|
||||||
|
@ -11,10 +12,8 @@ class ToggleSourcePin(
|
||||||
|
|
||||||
fun await(source: Source) {
|
fun await(source: Source) {
|
||||||
val isPinned = source.id.toString() in preferences.pinnedSources().get()
|
val isPinned = source.id.toString() in preferences.pinnedSources().get()
|
||||||
if (isPinned) {
|
preferences.pinnedSources().getAndSet { pinned ->
|
||||||
preferences.pinnedSources() -= source.id.toString()
|
if (isPinned) pinned.minus("${source.id}") else pinned.plus("${source.id}")
|
||||||
} else {
|
|
||||||
preferences.pinnedSources() += source.id.toString()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ import eu.kanade.tachiyomi.data.preference.PreferenceValues
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.glance.UpdatesGridGlanceWidget
|
import eu.kanade.tachiyomi.glance.UpdatesGridGlanceWidget
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
|
import eu.kanade.tachiyomi.network.NetworkPreferences
|
||||||
import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate
|
import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate
|
||||||
import eu.kanade.tachiyomi.util.preference.asHotFlow
|
import eu.kanade.tachiyomi.util.preference.asHotFlow
|
||||||
import eu.kanade.tachiyomi.util.system.WebViewUtil
|
import eu.kanade.tachiyomi.util.system.WebViewUtil
|
||||||
|
@ -63,6 +64,7 @@ import java.security.Security
|
||||||
class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
||||||
|
|
||||||
private val preferences: PreferencesHelper by injectLazy()
|
private val preferences: PreferencesHelper by injectLazy()
|
||||||
|
private val networkPreferences: NetworkPreferences by injectLazy()
|
||||||
|
|
||||||
private val disableIncognitoReceiver = DisableIncognitoReceiver()
|
private val disableIncognitoReceiver = DisableIncognitoReceiver()
|
||||||
|
|
||||||
|
@ -82,6 +84,7 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
Injekt.importModule(AppModule(this))
|
Injekt.importModule(AppModule(this))
|
||||||
|
Injekt.importModule(PreferenceModule(this))
|
||||||
Injekt.importModule(DomainModule())
|
Injekt.importModule(DomainModule())
|
||||||
|
|
||||||
setupAcra()
|
setupAcra()
|
||||||
|
@ -90,7 +93,7 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
||||||
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
|
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
|
||||||
|
|
||||||
// Show notification to disable Incognito Mode when it's enabled
|
// Show notification to disable Incognito Mode when it's enabled
|
||||||
preferences.incognitoMode().asFlow()
|
preferences.incognitoMode().changes()
|
||||||
.onEach { enabled ->
|
.onEach { enabled ->
|
||||||
val notificationManager = NotificationManagerCompat.from(this)
|
val notificationManager = NotificationManagerCompat.from(this)
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
|
@ -141,7 +144,7 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
||||||
}
|
}
|
||||||
.launchIn(ProcessLifecycleOwner.get().lifecycleScope)
|
.launchIn(ProcessLifecycleOwner.get().lifecycleScope)
|
||||||
|
|
||||||
if (!LogcatLogger.isInstalled && preferences.verboseLogging()) {
|
if (!LogcatLogger.isInstalled && networkPreferences.verboseLogging().get()) {
|
||||||
LogcatLogger.install(AndroidLogcatLogger(LogPriority.VERBOSE))
|
LogcatLogger.install(AndroidLogcatLogger(LogPriority.VERBOSE))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,7 +171,7 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
||||||
diskCache(diskCacheInit)
|
diskCache(diskCacheInit)
|
||||||
crossfade((300 * this@App.animatorDurationScale).toInt())
|
crossfade((300 * this@App.animatorDurationScale).toInt())
|
||||||
allowRgb565(getSystemService<ActivityManager>()!!.isLowRamDevice)
|
allowRgb565(getSystemService<ActivityManager>()!!.isLowRamDevice)
|
||||||
if (preferences.verboseLogging()) logger(DebugLogger())
|
if (networkPreferences.verboseLogging().get()) logger(DebugLogger())
|
||||||
}.build()
|
}.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@ import eu.kanade.data.AndroidDatabaseHandler
|
||||||
import eu.kanade.data.DatabaseHandler
|
import eu.kanade.data.DatabaseHandler
|
||||||
import eu.kanade.data.dateAdapter
|
import eu.kanade.data.dateAdapter
|
||||||
import eu.kanade.data.listOfStringsAdapter
|
import eu.kanade.data.listOfStringsAdapter
|
||||||
|
import eu.kanade.tachiyomi.core.preference.AndroidPreferenceStore
|
||||||
|
import eu.kanade.tachiyomi.core.preference.PreferenceStore
|
||||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
|
@ -22,7 +24,9 @@ import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.data.track.job.DelayedTrackingStore
|
import eu.kanade.tachiyomi.data.track.job.DelayedTrackingStore
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
|
import eu.kanade.tachiyomi.network.NetworkPreferences
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
|
import eu.kanade.tachiyomi.util.system.isDevFlavor
|
||||||
import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory
|
import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import uy.kohesive.injekt.api.InjektModule
|
import uy.kohesive.injekt.api.InjektModule
|
||||||
|
@ -84,8 +88,6 @@ class AppModule(val app: Application) : InjektModule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addSingletonFactory { PreferencesHelper(app) }
|
|
||||||
|
|
||||||
addSingletonFactory { ChapterCache(app) }
|
addSingletonFactory { ChapterCache(app) }
|
||||||
|
|
||||||
addSingletonFactory { CoverCache(app) }
|
addSingletonFactory { CoverCache(app) }
|
||||||
|
@ -106,8 +108,6 @@ class AppModule(val app: Application) : InjektModule {
|
||||||
|
|
||||||
// Asynchronously init expensive components for a faster cold start
|
// Asynchronously init expensive components for a faster cold start
|
||||||
ContextCompat.getMainExecutor(app).execute {
|
ContextCompat.getMainExecutor(app).execute {
|
||||||
get<PreferencesHelper>()
|
|
||||||
|
|
||||||
get<NetworkHelper>()
|
get<NetworkHelper>()
|
||||||
|
|
||||||
get<SourceManager>()
|
get<SourceManager>()
|
||||||
|
@ -118,3 +118,23 @@ 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(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package eu.kanade.tachiyomi
|
package eu.kanade.tachiyomi
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
@ -12,6 +13,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.data.updater.AppUpdateJob
|
import eu.kanade.tachiyomi.data.updater.AppUpdateJob
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
|
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
|
||||||
|
import eu.kanade.tachiyomi.network.NetworkPreferences
|
||||||
import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
|
import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||||
import eu.kanade.tachiyomi.util.preference.minusAssign
|
import eu.kanade.tachiyomi.util.preference.minusAssign
|
||||||
|
@ -31,9 +33,11 @@ object Migrations {
|
||||||
* @param preferences Preferences of the application.
|
* @param preferences Preferences of the application.
|
||||||
* @return true if a migration is performed, false otherwise.
|
* @return true if a migration is performed, false otherwise.
|
||||||
*/
|
*/
|
||||||
fun upgrade(preferences: PreferencesHelper): Boolean {
|
fun upgrade(
|
||||||
val context = preferences.context
|
context: Context,
|
||||||
|
preferences: PreferencesHelper,
|
||||||
|
networkPreferences: NetworkPreferences,
|
||||||
|
): Boolean {
|
||||||
val oldVersion = preferences.lastVersionCode().get()
|
val oldVersion = preferences.lastVersionCode().get()
|
||||||
if (oldVersion < BuildConfig.VERSION_CODE) {
|
if (oldVersion < BuildConfig.VERSION_CODE) {
|
||||||
preferences.lastVersionCode().set(BuildConfig.VERSION_CODE)
|
preferences.lastVersionCode().set(BuildConfig.VERSION_CODE)
|
||||||
|
@ -143,7 +147,7 @@ object Migrations {
|
||||||
val wasDohEnabled = prefs.getBoolean("enable_doh", false)
|
val wasDohEnabled = prefs.getBoolean("enable_doh", false)
|
||||||
if (wasDohEnabled) {
|
if (wasDohEnabled) {
|
||||||
prefs.edit {
|
prefs.edit {
|
||||||
putInt(PreferenceKeys.dohProvider, PREF_DOH_CLOUDFLARE)
|
putInt(networkPreferences.dohProvider().key(), PREF_DOH_CLOUDFLARE)
|
||||||
remove("enable_doh")
|
remove("enable_doh")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ class BackupNotifier(private val context: Context) {
|
||||||
val builder = with(progressNotificationBuilder) {
|
val builder = with(progressNotificationBuilder) {
|
||||||
setContentTitle(context.getString(R.string.restoring_backup))
|
setContentTitle(context.getString(R.string.restoring_backup))
|
||||||
|
|
||||||
if (!preferences.hideNotificationContent()) {
|
if (!preferences.hideNotificationContent().get()) {
|
||||||
setContentText(content)
|
setContentText(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ class DownloadCache(
|
||||||
private var rootDir = RootDirectory(getDirectoryFromPreference())
|
private var rootDir = RootDirectory(getDirectoryFromPreference())
|
||||||
|
|
||||||
init {
|
init {
|
||||||
preferences.downloadsDirectory().asFlow()
|
preferences.downloadsDirectory().changes()
|
||||||
.onEach {
|
.onEach {
|
||||||
lastRenew = 0L // invalidate cache
|
lastRenew = 0L // invalidate cache
|
||||||
rootDir = RootDirectory(getDirectoryFromPreference())
|
rootDir = RootDirectory(getDirectoryFromPreference())
|
||||||
|
|
|
@ -414,7 +414,7 @@ class DownloadManager(
|
||||||
|
|
||||||
return if (categoriesForManga.intersect(categoriesToExclude).isNotEmpty()) {
|
return if (categoriesForManga.intersect(categoriesToExclude).isNotEmpty()) {
|
||||||
chapters.filterNot { it.read }
|
chapters.filterNot { it.read }
|
||||||
} else if (!preferences.removeBookmarkedChapters()) {
|
} else if (!preferences.removeBookmarkedChapters().get()) {
|
||||||
chapters.filterNot { it.bookmark }
|
chapters.filterNot { it.bookmark }
|
||||||
} else {
|
} else {
|
||||||
chapters
|
chapters
|
||||||
|
|
|
@ -104,7 +104,7 @@ internal class DownloadNotifier(private val context: Context) {
|
||||||
download.pages!!.size,
|
download.pages!!.size,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (preferences.hideNotificationContent()) {
|
if (preferences.hideNotificationContent().get()) {
|
||||||
setContentTitle(downloadingProgressText)
|
setContentTitle(downloadingProgressText)
|
||||||
setContentText(null)
|
setContentText(null)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -39,7 +39,7 @@ class DownloadProvider(private val context: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
preferences.downloadsDirectory().asFlow()
|
preferences.downloadsDirectory().changes()
|
||||||
.onEach { downloadsDir = UniFile.fromUri(context, it.toUri()) }
|
.onEach { downloadsDir = UniFile.fromUri(context, it.toUri()) }
|
||||||
.launchIn(scope)
|
.launchIn(scope)
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,7 +164,7 @@ class DownloadService : Service() {
|
||||||
*/
|
*/
|
||||||
private fun onNetworkStateChanged() {
|
private fun onNetworkStateChanged() {
|
||||||
if (isOnline()) {
|
if (isOnline()) {
|
||||||
if (preferences.downloadOnlyOverWifi() && !isConnectedToWifi()) {
|
if (preferences.downloadOnlyOverWifi().get() && !isConnectedToWifi()) {
|
||||||
stopDownloads(R.string.download_notifier_text_only_wifi)
|
stopDownloads(R.string.download_notifier_text_only_wifi)
|
||||||
} else {
|
} else {
|
||||||
val started = downloadManager.startDownloads()
|
val started = downloadManager.startDownloads()
|
||||||
|
|
|
@ -71,7 +71,7 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||||
* @param total the total progress.
|
* @param total the total progress.
|
||||||
*/
|
*/
|
||||||
fun showProgressNotification(manga: List<Manga>, current: Int, total: Int) {
|
fun showProgressNotification(manga: List<Manga>, current: Int, total: Int) {
|
||||||
if (preferences.hideNotificationContent()) {
|
if (preferences.hideNotificationContent().get()) {
|
||||||
progressNotificationBuilder
|
progressNotificationBuilder
|
||||||
.setContentTitle(context.getString(R.string.notification_check_updates))
|
.setContentTitle(context.getString(R.string.notification_check_updates))
|
||||||
.setContentText("($current/$total)")
|
.setContentText("($current/$total)")
|
||||||
|
@ -167,12 +167,12 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||||
Notifications.ID_NEW_CHAPTERS,
|
Notifications.ID_NEW_CHAPTERS,
|
||||||
context.notification(Notifications.CHANNEL_NEW_CHAPTERS) {
|
context.notification(Notifications.CHANNEL_NEW_CHAPTERS) {
|
||||||
setContentTitle(context.getString(R.string.notification_new_chapters))
|
setContentTitle(context.getString(R.string.notification_new_chapters))
|
||||||
if (updates.size == 1 && !preferences.hideNotificationContent()) {
|
if (updates.size == 1 && !preferences.hideNotificationContent().get()) {
|
||||||
setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN))
|
setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN))
|
||||||
} else {
|
} else {
|
||||||
setContentText(context.resources.getQuantityString(R.plurals.notification_new_chapters_summary, updates.size, updates.size))
|
setContentText(context.resources.getQuantityString(R.plurals.notification_new_chapters_summary, updates.size, updates.size))
|
||||||
|
|
||||||
if (!preferences.hideNotificationContent()) {
|
if (!preferences.hideNotificationContent().get()) {
|
||||||
setStyle(
|
setStyle(
|
||||||
NotificationCompat.BigTextStyle().bigText(
|
NotificationCompat.BigTextStyle().bigText(
|
||||||
updates.joinToString("\n") {
|
updates.joinToString("\n") {
|
||||||
|
@ -197,7 +197,7 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||||
)
|
)
|
||||||
|
|
||||||
// Per-manga notification
|
// Per-manga notification
|
||||||
if (!preferences.hideNotificationContent()) {
|
if (!preferences.hideNotificationContent().get()) {
|
||||||
launchUI {
|
launchUI {
|
||||||
updates.forEach { (manga, chapters) ->
|
updates.forEach { (manga, chapters) ->
|
||||||
notify(manga.id.hashCode(), createNewChaptersNotification(manga, chapters))
|
notify(manga.id.hashCode(), createNewChaptersNotification(manga, chapters))
|
||||||
|
|
|
@ -380,7 +380,7 @@ class LibraryUpdateService(
|
||||||
failedUpdates.add(mangaWithNotif to errorMessage)
|
failedUpdates.add(mangaWithNotif to errorMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (preferences.autoUpdateTrackers()) {
|
if (preferences.autoUpdateTrackers().get()) {
|
||||||
updateTrackings(mangaWithNotif, loggedServices)
|
updateTrackings(mangaWithNotif, loggedServices)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -430,7 +430,7 @@ class LibraryUpdateService(
|
||||||
val source = sourceManager.getOrStub(manga.source)
|
val source = sourceManager.getOrStub(manga.source)
|
||||||
|
|
||||||
// Update manga metadata if needed
|
// Update manga metadata if needed
|
||||||
if (preferences.autoUpdateMetadata()) {
|
if (preferences.autoUpdateMetadata().get()) {
|
||||||
val networkManga = source.getMangaDetails(manga.toSManga())
|
val networkManga = source.getMangaDetails(manga.toSManga())
|
||||||
updateManga.awaitUpdateFromSource(manga, networkManga, manualFetch = false, coverCache)
|
updateManga.awaitUpdateFromSource(manga, networkManga, manualFetch = false, coverCache)
|
||||||
}
|
}
|
||||||
|
|
|
@ -248,7 +248,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||||
val toUpdate = chapterUrls.mapNotNull { getChapter.await(it, mangaId) }
|
val toUpdate = chapterUrls.mapNotNull { getChapter.await(it, mangaId) }
|
||||||
.map {
|
.map {
|
||||||
val chapter = it.copy(read = true)
|
val chapter = it.copy(read = true)
|
||||||
if (preferences.removeAfterMarkedAsRead()) {
|
if (preferences.removeAfterMarkedAsRead().get()) {
|
||||||
val manga = getManga.await(mangaId)
|
val manga = getManga.await(mangaId)
|
||||||
if (manga != null) {
|
if (manga != null) {
|
||||||
val source = sourceManager.get(manga.source)
|
val source = sourceManager.get(manga.source)
|
||||||
|
|
|
@ -56,10 +56,6 @@ object PreferenceKeys {
|
||||||
|
|
||||||
const val searchPinnedSourcesOnly = "search_pinned_sources_only"
|
const val searchPinnedSourcesOnly = "search_pinned_sources_only"
|
||||||
|
|
||||||
const val dohProvider = "doh_provider"
|
|
||||||
|
|
||||||
const val defaultUserAgent = "default_user_agent"
|
|
||||||
|
|
||||||
const val defaultChapterFilterByRead = "default_chapter_filter_by_read"
|
const val defaultChapterFilterByRead = "default_chapter_filter_by_read"
|
||||||
|
|
||||||
const val defaultChapterFilterByDownloaded = "default_chapter_filter_by_downloaded"
|
const val defaultChapterFilterByDownloaded = "default_chapter_filter_by_downloaded"
|
||||||
|
@ -72,8 +68,6 @@ object PreferenceKeys {
|
||||||
|
|
||||||
const val defaultChapterDisplayByNameOrNumber = "default_chapter_display_by_name_or_number"
|
const val defaultChapterDisplayByNameOrNumber = "default_chapter_display_by_name_or_number"
|
||||||
|
|
||||||
const val verboseLogging = "verbose_logging"
|
|
||||||
|
|
||||||
const val autoClearChapterCache = "auto_clear_chapter_cache"
|
const val autoClearChapterCache = "auto_clear_chapter_cache"
|
||||||
|
|
||||||
fun trackUsername(syncId: Long) = "pref_mangasync_username_$syncId"
|
fun trackUsername(syncId: Long) = "pref_mangasync_username_$syncId"
|
||||||
|
|
|
@ -3,12 +3,11 @@ package eu.kanade.tachiyomi.data.preference
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import androidx.core.content.edit
|
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import com.fredporciuncula.flow.preferences.FlowSharedPreferences
|
|
||||||
import eu.kanade.domain.source.interactor.SetMigrateSorting
|
import eu.kanade.domain.source.interactor.SetMigrateSorting
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.core.preference.PreferenceStore
|
||||||
|
import eu.kanade.tachiyomi.core.preference.getEnum
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.track.TrackService
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
import eu.kanade.tachiyomi.data.track.anilist.Anilist
|
import eu.kanade.tachiyomi.data.track.anilist.Anilist
|
||||||
|
@ -18,7 +17,6 @@ import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import eu.kanade.tachiyomi.util.system.isDevFlavor
|
|
||||||
import eu.kanade.tachiyomi.util.system.isDynamicColorAvailable
|
import eu.kanade.tachiyomi.util.system.isDynamicColorAvailable
|
||||||
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
@ -29,10 +27,10 @@ import eu.kanade.domain.manga.model.Manga as DomainManga
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values
|
import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values
|
||||||
|
|
||||||
class PreferencesHelper(val context: Context) {
|
class PreferencesHelper(
|
||||||
|
val context: Context,
|
||||||
private val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
private val preferenceStore: PreferenceStore,
|
||||||
private val flowPrefs = FlowSharedPreferences(prefs)
|
) {
|
||||||
|
|
||||||
private val defaultDownloadsDir = File(
|
private val defaultDownloadsDir = File(
|
||||||
Environment.getExternalStorageDirectory().absolutePath + File.separator +
|
Environment.getExternalStorageDirectory().absolutePath + File.separator +
|
||||||
|
@ -46,300 +44,290 @@ class PreferencesHelper(val context: Context) {
|
||||||
"backup",
|
"backup",
|
||||||
).toUri()
|
).toUri()
|
||||||
|
|
||||||
fun confirmExit() = prefs.getBoolean(Keys.confirmExit, false)
|
fun confirmExit() = this.preferenceStore.getBoolean(Keys.confirmExit, false)
|
||||||
|
|
||||||
fun sideNavIconAlignment() = flowPrefs.getInt("pref_side_nav_icon_alignment", 0)
|
fun sideNavIconAlignment() = this.preferenceStore.getInt("pref_side_nav_icon_alignment", 0)
|
||||||
|
|
||||||
fun useAuthenticator() = flowPrefs.getBoolean("use_biometric_lock", false)
|
fun useAuthenticator() = this.preferenceStore.getBoolean("use_biometric_lock", false)
|
||||||
|
|
||||||
fun lockAppAfter() = flowPrefs.getInt("lock_app_after", 0)
|
fun lockAppAfter() = this.preferenceStore.getInt("lock_app_after", 0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For app lock. Will be set when there is a pending timed lock.
|
* For app lock. Will be set when there is a pending timed lock.
|
||||||
* Otherwise this pref should be deleted.
|
* Otherwise this pref should be deleted.
|
||||||
*/
|
*/
|
||||||
fun lastAppClosed() = flowPrefs.getLong("last_app_closed", 0)
|
fun lastAppClosed() = this.preferenceStore.getLong("last_app_closed", 0)
|
||||||
|
|
||||||
fun secureScreen() = flowPrefs.getEnum("secure_screen_v2", Values.SecureScreenMode.INCOGNITO)
|
fun secureScreen() = this.preferenceStore.getEnum("secure_screen_v2", Values.SecureScreenMode.INCOGNITO)
|
||||||
|
|
||||||
fun hideNotificationContent() = prefs.getBoolean(Keys.hideNotificationContent, false)
|
fun hideNotificationContent() = this.preferenceStore.getBoolean(Keys.hideNotificationContent, false)
|
||||||
|
|
||||||
fun autoUpdateMetadata() = prefs.getBoolean(Keys.autoUpdateMetadata, false)
|
fun autoUpdateMetadata() = this.preferenceStore.getBoolean(Keys.autoUpdateMetadata, false)
|
||||||
|
|
||||||
fun autoUpdateTrackers() = prefs.getBoolean(Keys.autoUpdateTrackers, false)
|
fun autoUpdateTrackers() = this.preferenceStore.getBoolean(Keys.autoUpdateTrackers, false)
|
||||||
|
|
||||||
fun themeMode() = flowPrefs.getEnum(
|
fun themeMode() = this.preferenceStore.getEnum(
|
||||||
"pref_theme_mode_key",
|
"pref_theme_mode_key",
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { Values.ThemeMode.system } else { Values.ThemeMode.light },
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { Values.ThemeMode.system } else { Values.ThemeMode.light },
|
||||||
)
|
)
|
||||||
|
|
||||||
fun appTheme() = flowPrefs.getEnum(
|
fun appTheme() = this.preferenceStore.getEnum(
|
||||||
"pref_app_theme",
|
"pref_app_theme",
|
||||||
if (DeviceUtil.isDynamicColorAvailable) { Values.AppTheme.MONET } else { Values.AppTheme.DEFAULT },
|
if (DeviceUtil.isDynamicColorAvailable) { Values.AppTheme.MONET } else { Values.AppTheme.DEFAULT },
|
||||||
)
|
)
|
||||||
|
|
||||||
fun themeDarkAmoled() = flowPrefs.getBoolean("pref_theme_dark_amoled_key", false)
|
fun themeDarkAmoled() = this.preferenceStore.getBoolean("pref_theme_dark_amoled_key", false)
|
||||||
|
|
||||||
fun pageTransitions() = flowPrefs.getBoolean("pref_enable_transitions_key", true)
|
fun pageTransitions() = this.preferenceStore.getBoolean("pref_enable_transitions_key", true)
|
||||||
|
|
||||||
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", 1)
|
fun readerTheme() = this.preferenceStore.getInt("pref_reader_theme_key", 1)
|
||||||
|
|
||||||
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 pagerNavInverted() = flowPrefs.getEnum("reader_tapping_inverted", Values.TappingInvertMode.NONE)
|
fun pagerNavInverted() = this.preferenceStore.getEnum("reader_tapping_inverted", Values.TappingInvertMode.NONE)
|
||||||
|
|
||||||
fun webtoonNavInverted() = flowPrefs.getEnum("reader_tapping_inverted_webtoon", Values.TappingInvertMode.NONE)
|
fun webtoonNavInverted() = this.preferenceStore.getEnum("reader_tapping_inverted_webtoon", Values.TappingInvertMode.NONE)
|
||||||
|
|
||||||
fun readWithLongTap() = flowPrefs.getBoolean("reader_long_tap", true)
|
fun readWithLongTap() = this.preferenceStore.getBoolean("reader_long_tap", true)
|
||||||
|
|
||||||
fun readWithVolumeKeys() = flowPrefs.getBoolean("reader_volume_keys", false)
|
fun readWithVolumeKeys() = this.preferenceStore.getBoolean("reader_volume_keys", false)
|
||||||
|
|
||||||
fun readWithVolumeKeysInverted() = flowPrefs.getBoolean("reader_volume_keys_inverted", false)
|
fun readWithVolumeKeysInverted() = this.preferenceStore.getBoolean("reader_volume_keys_inverted", false)
|
||||||
|
|
||||||
fun navigationModePager() = flowPrefs.getInt("reader_navigation_mode_pager", 0)
|
fun navigationModePager() = this.preferenceStore.getInt("reader_navigation_mode_pager", 0)
|
||||||
|
|
||||||
fun navigationModeWebtoon() = flowPrefs.getInt("reader_navigation_mode_webtoon", 0)
|
fun navigationModeWebtoon() = this.preferenceStore.getInt("reader_navigation_mode_webtoon", 0)
|
||||||
|
|
||||||
fun showNavigationOverlayNewUser() = flowPrefs.getBoolean("reader_navigation_overlay_new_user", true)
|
fun showNavigationOverlayNewUser() = this.preferenceStore.getBoolean("reader_navigation_overlay_new_user", true)
|
||||||
|
|
||||||
fun showNavigationOverlayOnStart() = flowPrefs.getBoolean("reader_navigation_overlay_on_start", false)
|
fun showNavigationOverlayOnStart() = this.preferenceStore.getBoolean("reader_navigation_overlay_on_start", false)
|
||||||
|
|
||||||
fun readerHideThreshold() = flowPrefs.getEnum("reader_hide_threshold", Values.ReaderHideThreshold.LOW)
|
fun readerHideThreshold() = this.preferenceStore.getEnum("reader_hide_threshold", Values.ReaderHideThreshold.LOW)
|
||||||
|
|
||||||
fun portraitColumns() = flowPrefs.getInt("pref_library_columns_portrait_key", 0)
|
fun portraitColumns() = this.preferenceStore.getInt("pref_library_columns_portrait_key", 0)
|
||||||
|
|
||||||
fun landscapeColumns() = flowPrefs.getInt("pref_library_columns_landscape_key", 0)
|
fun landscapeColumns() = this.preferenceStore.getInt("pref_library_columns_landscape_key", 0)
|
||||||
|
|
||||||
fun autoUpdateTrack() = prefs.getBoolean(Keys.autoUpdateTrack, true)
|
fun autoUpdateTrack() = this.preferenceStore.getBoolean(Keys.autoUpdateTrack, true)
|
||||||
|
|
||||||
fun lastUsedSource() = flowPrefs.getLong("last_catalogue_source", -1)
|
fun lastUsedSource() = this.preferenceStore.getLong("last_catalogue_source", -1)
|
||||||
|
|
||||||
fun lastUsedCategory() = flowPrefs.getInt("last_used_category", 0)
|
fun lastUsedCategory() = this.preferenceStore.getInt("last_used_category", 0)
|
||||||
|
|
||||||
fun lastVersionCode() = flowPrefs.getInt("last_version_code", 0)
|
fun lastVersionCode() = this.preferenceStore.getInt("last_version_code", 0)
|
||||||
|
|
||||||
fun sourceDisplayMode() = flowPrefs.getObject("pref_display_mode_catalogue", LibraryDisplayMode.Serializer, LibraryDisplayMode.default)
|
fun sourceDisplayMode() = this.preferenceStore.getObject("pref_display_mode_catalogue", LibraryDisplayMode.default, LibraryDisplayMode.Serializer::serialize, LibraryDisplayMode.Serializer::deserialize)
|
||||||
|
|
||||||
fun enabledLanguages() = flowPrefs.getStringSet("source_languages", LocaleHelper.getDefaultEnabledLanguages())
|
fun enabledLanguages() = this.preferenceStore.getStringSet("source_languages", LocaleHelper.getDefaultEnabledLanguages())
|
||||||
|
|
||||||
fun trackUsername(sync: TrackService) = prefs.getString(Keys.trackUsername(sync.id), "")
|
fun trackUsername(sync: TrackService) = this.preferenceStore.getString(Keys.trackUsername(sync.id), "")
|
||||||
|
|
||||||
fun trackPassword(sync: TrackService) = prefs.getString(Keys.trackPassword(sync.id), "")
|
fun trackPassword(sync: TrackService) = this.preferenceStore.getString(Keys.trackPassword(sync.id), "")
|
||||||
|
|
||||||
fun setTrackCredentials(sync: TrackService, username: String, password: String) {
|
fun setTrackCredentials(sync: TrackService, username: String, password: String) {
|
||||||
prefs.edit {
|
trackUsername(sync).set(username)
|
||||||
putString(Keys.trackUsername(sync.id), username)
|
trackPassword(sync).set(password)
|
||||||
putString(Keys.trackPassword(sync.id), password)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun trackToken(sync: TrackService) = flowPrefs.getString(Keys.trackToken(sync.id), "")
|
fun trackToken(sync: TrackService) = this.preferenceStore.getString(Keys.trackToken(sync.id), "")
|
||||||
|
|
||||||
fun anilistScoreType() = flowPrefs.getString("anilist_score_type", Anilist.POINT_10)
|
fun anilistScoreType() = this.preferenceStore.getString("anilist_score_type", Anilist.POINT_10)
|
||||||
|
|
||||||
fun backupsDirectory() = flowPrefs.getString("backup_directory", defaultBackupDir.toString())
|
fun backupsDirectory() = this.preferenceStore.getString("backup_directory", defaultBackupDir.toString())
|
||||||
|
|
||||||
fun relativeTime() = flowPrefs.getInt("relative_time", 7)
|
fun relativeTime() = this.preferenceStore.getInt("relative_time", 7)
|
||||||
|
|
||||||
fun dateFormat(format: String = flowPrefs.getString(Keys.dateFormat, "").get()): DateFormat = when (format) {
|
fun dateFormat(format: String = this.preferenceStore.getString(Keys.dateFormat, "").get()): DateFormat = when (format) {
|
||||||
"" -> DateFormat.getDateInstance(DateFormat.SHORT)
|
"" -> DateFormat.getDateInstance(DateFormat.SHORT)
|
||||||
else -> SimpleDateFormat(format, Locale.getDefault())
|
else -> SimpleDateFormat(format, Locale.getDefault())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun downloadsDirectory() = flowPrefs.getString("download_directory", defaultDownloadsDir.toString())
|
fun downloadsDirectory() = this.preferenceStore.getString("download_directory", defaultDownloadsDir.toString())
|
||||||
|
|
||||||
fun downloadOnlyOverWifi() = prefs.getBoolean(Keys.downloadOnlyOverWifi, true)
|
fun downloadOnlyOverWifi() = this.preferenceStore.getBoolean(Keys.downloadOnlyOverWifi, true)
|
||||||
|
|
||||||
fun saveChaptersAsCBZ() = flowPrefs.getBoolean("save_chapter_as_cbz", true)
|
fun saveChaptersAsCBZ() = this.preferenceStore.getBoolean("save_chapter_as_cbz", true)
|
||||||
|
|
||||||
fun splitTallImages() = flowPrefs.getBoolean("split_tall_images", false)
|
fun splitTallImages() = this.preferenceStore.getBoolean("split_tall_images", false)
|
||||||
|
|
||||||
fun folderPerManga() = prefs.getBoolean(Keys.folderPerManga, false)
|
fun folderPerManga() = this.preferenceStore.getBoolean(Keys.folderPerManga, false)
|
||||||
|
|
||||||
fun numberOfBackups() = flowPrefs.getInt("backup_slots", 2)
|
fun numberOfBackups() = this.preferenceStore.getInt("backup_slots", 2)
|
||||||
|
|
||||||
fun backupInterval() = flowPrefs.getInt("backup_interval", 12)
|
fun backupInterval() = this.preferenceStore.getInt("backup_interval", 12)
|
||||||
|
|
||||||
fun removeAfterReadSlots() = prefs.getInt(Keys.removeAfterReadSlots, -1)
|
fun removeAfterReadSlots() = this.preferenceStore.getInt(Keys.removeAfterReadSlots, -1)
|
||||||
|
|
||||||
fun removeAfterMarkedAsRead() = prefs.getBoolean(Keys.removeAfterMarkedAsRead, false)
|
fun removeAfterMarkedAsRead() = this.preferenceStore.getBoolean(Keys.removeAfterMarkedAsRead, false)
|
||||||
|
|
||||||
fun removeBookmarkedChapters() = prefs.getBoolean(Keys.removeBookmarkedChapters, false)
|
fun removeBookmarkedChapters() = this.preferenceStore.getBoolean(Keys.removeBookmarkedChapters, false)
|
||||||
|
|
||||||
fun removeExcludeCategories() = flowPrefs.getStringSet("remove_exclude_categories", emptySet())
|
fun removeExcludeCategories() = this.preferenceStore.getStringSet("remove_exclude_categories", emptySet())
|
||||||
|
|
||||||
fun libraryUpdateInterval() = flowPrefs.getInt("pref_library_update_interval_key", 24)
|
fun libraryUpdateInterval() = this.preferenceStore.getInt("pref_library_update_interval_key", 24)
|
||||||
fun libraryUpdateLastTimestamp() = flowPrefs.getLong("library_update_last_timestamp", 0L)
|
fun libraryUpdateLastTimestamp() = this.preferenceStore.getLong("library_update_last_timestamp", 0L)
|
||||||
|
|
||||||
fun libraryUpdateDeviceRestriction() = flowPrefs.getStringSet("library_update_restriction", setOf(DEVICE_ONLY_ON_WIFI))
|
fun libraryUpdateDeviceRestriction() = this.preferenceStore.getStringSet("library_update_restriction", setOf(DEVICE_ONLY_ON_WIFI))
|
||||||
fun libraryUpdateMangaRestriction() = flowPrefs.getStringSet("library_update_manga_restriction", setOf(MANGA_HAS_UNREAD, MANGA_NON_COMPLETED, MANGA_NON_READ))
|
fun libraryUpdateMangaRestriction() = this.preferenceStore.getStringSet("library_update_manga_restriction", setOf(MANGA_HAS_UNREAD, MANGA_NON_COMPLETED, MANGA_NON_READ))
|
||||||
|
|
||||||
fun showUpdatesNavBadge() = flowPrefs.getBoolean("library_update_show_tab_badge", false)
|
fun showUpdatesNavBadge() = this.preferenceStore.getBoolean("library_update_show_tab_badge", false)
|
||||||
fun unreadUpdatesCount() = flowPrefs.getInt("library_unread_updates_count", 0)
|
fun unreadUpdatesCount() = this.preferenceStore.getInt("library_unread_updates_count", 0)
|
||||||
|
|
||||||
fun libraryUpdateCategories() = flowPrefs.getStringSet("library_update_categories", emptySet())
|
fun libraryUpdateCategories() = this.preferenceStore.getStringSet("library_update_categories", emptySet())
|
||||||
fun libraryUpdateCategoriesExclude() = flowPrefs.getStringSet("library_update_categories_exclude", emptySet())
|
fun libraryUpdateCategoriesExclude() = this.preferenceStore.getStringSet("library_update_categories_exclude", emptySet())
|
||||||
|
|
||||||
fun libraryDisplayMode() = flowPrefs.getObject("pref_display_mode_library", LibraryDisplayMode.Serializer, LibraryDisplayMode.default)
|
fun libraryDisplayMode() = this.preferenceStore.getObject("pref_display_mode_library", LibraryDisplayMode.default, LibraryDisplayMode.Serializer::serialize, LibraryDisplayMode.Serializer::deserialize)
|
||||||
|
|
||||||
fun downloadBadge() = flowPrefs.getBoolean("display_download_badge", false)
|
fun downloadBadge() = this.preferenceStore.getBoolean("display_download_badge", false)
|
||||||
|
|
||||||
fun localBadge() = flowPrefs.getBoolean("display_local_badge", true)
|
fun localBadge() = this.preferenceStore.getBoolean("display_local_badge", true)
|
||||||
|
|
||||||
fun downloadedOnly() = flowPrefs.getBoolean("pref_downloaded_only", false)
|
fun downloadedOnly() = this.preferenceStore.getBoolean("pref_downloaded_only", false)
|
||||||
|
|
||||||
fun unreadBadge() = flowPrefs.getBoolean("display_unread_badge", true)
|
fun unreadBadge() = this.preferenceStore.getBoolean("display_unread_badge", true)
|
||||||
|
|
||||||
fun languageBadge() = flowPrefs.getBoolean("display_language_badge", false)
|
fun languageBadge() = this.preferenceStore.getBoolean("display_language_badge", false)
|
||||||
|
|
||||||
fun categoryTabs() = flowPrefs.getBoolean("display_category_tabs", true)
|
fun categoryTabs() = this.preferenceStore.getBoolean("display_category_tabs", true)
|
||||||
|
|
||||||
fun categoryNumberOfItems() = flowPrefs.getBoolean("display_number_of_items", false)
|
fun categoryNumberOfItems() = this.preferenceStore.getBoolean("display_number_of_items", false)
|
||||||
|
|
||||||
fun filterDownloaded() = flowPrefs.getInt(Keys.filterDownloaded, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
|
fun filterDownloaded() = this.preferenceStore.getInt(Keys.filterDownloaded, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
|
||||||
|
|
||||||
fun filterUnread() = flowPrefs.getInt(Keys.filterUnread, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
|
fun filterUnread() = this.preferenceStore.getInt(Keys.filterUnread, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
|
||||||
|
|
||||||
fun filterStarted() = flowPrefs.getInt(Keys.filterStarted, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
|
fun filterStarted() = this.preferenceStore.getInt(Keys.filterStarted, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
|
||||||
|
|
||||||
fun filterCompleted() = flowPrefs.getInt(Keys.filterCompleted, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
|
fun filterCompleted() = this.preferenceStore.getInt(Keys.filterCompleted, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
|
||||||
|
|
||||||
fun filterTracking(name: Int) = flowPrefs.getInt("${Keys.filterTracked}_$name", ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
|
fun filterTracking(name: Int) = this.preferenceStore.getInt("${Keys.filterTracked}_$name", ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
|
||||||
|
|
||||||
fun librarySortingMode() = flowPrefs.getObject(Keys.librarySortingMode, LibrarySort.Serializer, LibrarySort.default)
|
fun librarySortingMode() = this.preferenceStore.getObject(Keys.librarySortingMode, LibrarySort.default, LibrarySort.Serializer::serialize, LibrarySort.Serializer::deserialize)
|
||||||
|
|
||||||
fun migrationSortingMode() = flowPrefs.getEnum(Keys.migrationSortingMode, SetMigrateSorting.Mode.ALPHABETICAL)
|
fun migrationSortingMode() = this.preferenceStore.getEnum(Keys.migrationSortingMode, SetMigrateSorting.Mode.ALPHABETICAL)
|
||||||
fun migrationSortingDirection() = flowPrefs.getEnum(Keys.migrationSortingDirection, SetMigrateSorting.Direction.ASCENDING)
|
fun migrationSortingDirection() = this.preferenceStore.getEnum(Keys.migrationSortingDirection, SetMigrateSorting.Direction.ASCENDING)
|
||||||
|
|
||||||
fun automaticExtUpdates() = flowPrefs.getBoolean("automatic_ext_updates", true)
|
fun automaticExtUpdates() = this.preferenceStore.getBoolean("automatic_ext_updates", true)
|
||||||
|
|
||||||
fun showNsfwSource() = flowPrefs.getBoolean("show_nsfw_source", true)
|
fun showNsfwSource() = this.preferenceStore.getBoolean("show_nsfw_source", true)
|
||||||
|
|
||||||
fun extensionUpdatesCount() = flowPrefs.getInt("ext_updates_count", 0)
|
fun extensionUpdatesCount() = this.preferenceStore.getInt("ext_updates_count", 0)
|
||||||
|
|
||||||
fun lastAppCheck() = flowPrefs.getLong("last_app_check", 0)
|
fun lastAppCheck() = this.preferenceStore.getLong("last_app_check", 0)
|
||||||
fun lastExtCheck() = flowPrefs.getLong("last_ext_check", 0)
|
fun lastExtCheck() = this.preferenceStore.getLong("last_ext_check", 0)
|
||||||
|
|
||||||
fun searchPinnedSourcesOnly() = prefs.getBoolean(Keys.searchPinnedSourcesOnly, false)
|
fun searchPinnedSourcesOnly() = this.preferenceStore.getBoolean(Keys.searchPinnedSourcesOnly, false)
|
||||||
|
|
||||||
fun disabledSources() = flowPrefs.getStringSet("hidden_catalogues", emptySet())
|
fun disabledSources() = this.preferenceStore.getStringSet("hidden_catalogues", emptySet())
|
||||||
|
|
||||||
fun pinnedSources() = flowPrefs.getStringSet("pinned_catalogues", emptySet())
|
fun pinnedSources() = this.preferenceStore.getStringSet("pinned_catalogues", emptySet())
|
||||||
|
|
||||||
fun downloadNewChapters() = flowPrefs.getBoolean("download_new", false)
|
fun downloadNewChapters() = this.preferenceStore.getBoolean("download_new", false)
|
||||||
|
|
||||||
fun downloadNewChapterCategories() = flowPrefs.getStringSet("download_new_categories", emptySet())
|
fun downloadNewChapterCategories() = this.preferenceStore.getStringSet("download_new_categories", emptySet())
|
||||||
fun downloadNewChapterCategoriesExclude() = flowPrefs.getStringSet("download_new_categories_exclude", emptySet())
|
fun downloadNewChapterCategoriesExclude() = this.preferenceStore.getStringSet("download_new_categories_exclude", emptySet())
|
||||||
|
|
||||||
fun autoDownloadWhileReading() = flowPrefs.getInt("auto_download_while_reading", 0)
|
fun autoDownloadWhileReading() = this.preferenceStore.getInt("auto_download_while_reading", 0)
|
||||||
|
|
||||||
fun defaultCategory() = prefs.getInt(Keys.defaultCategory, -1)
|
fun defaultCategory() = this.preferenceStore.getInt(Keys.defaultCategory, -1)
|
||||||
|
|
||||||
fun categorizedDisplaySettings() = flowPrefs.getBoolean("categorized_display", false)
|
fun categorizedDisplaySettings() = this.preferenceStore.getBoolean("categorized_display", false)
|
||||||
|
|
||||||
fun skipRead() = prefs.getBoolean(Keys.skipRead, false)
|
fun skipRead() = this.preferenceStore.getBoolean(Keys.skipRead, false)
|
||||||
|
|
||||||
fun skipFiltered() = prefs.getBoolean(Keys.skipFiltered, true)
|
fun skipFiltered() = this.preferenceStore.getBoolean(Keys.skipFiltered, true)
|
||||||
|
|
||||||
fun migrateFlags() = flowPrefs.getInt("migrate_flags", Int.MAX_VALUE)
|
fun migrateFlags() = this.preferenceStore.getInt("migrate_flags", Int.MAX_VALUE)
|
||||||
|
|
||||||
fun trustedSignatures() = flowPrefs.getStringSet("trusted_signatures", emptySet())
|
fun trustedSignatures() = this.preferenceStore.getStringSet("trusted_signatures", emptySet())
|
||||||
|
|
||||||
fun dohProvider() = prefs.getInt(Keys.dohProvider, -1)
|
fun filterChapterByRead() = this.preferenceStore.getInt(Keys.defaultChapterFilterByRead, DomainManga.SHOW_ALL.toInt())
|
||||||
|
|
||||||
fun defaultUserAgent() = flowPrefs.getString(Keys.defaultUserAgent, "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0")
|
fun filterChapterByDownloaded() = this.preferenceStore.getInt(Keys.defaultChapterFilterByDownloaded, DomainManga.SHOW_ALL.toInt())
|
||||||
|
|
||||||
fun filterChapterByRead() = prefs.getInt(Keys.defaultChapterFilterByRead, DomainManga.SHOW_ALL.toInt())
|
fun filterChapterByBookmarked() = this.preferenceStore.getInt(Keys.defaultChapterFilterByBookmarked, DomainManga.SHOW_ALL.toInt())
|
||||||
|
|
||||||
fun filterChapterByDownloaded() = prefs.getInt(Keys.defaultChapterFilterByDownloaded, DomainManga.SHOW_ALL.toInt())
|
fun sortChapterBySourceOrNumber() = this.preferenceStore.getInt(Keys.defaultChapterSortBySourceOrNumber, DomainManga.CHAPTER_SORTING_SOURCE.toInt())
|
||||||
|
|
||||||
fun filterChapterByBookmarked() = prefs.getInt(Keys.defaultChapterFilterByBookmarked, DomainManga.SHOW_ALL.toInt())
|
fun displayChapterByNameOrNumber() = this.preferenceStore.getInt(Keys.defaultChapterDisplayByNameOrNumber, DomainManga.CHAPTER_DISPLAY_NAME.toInt())
|
||||||
|
|
||||||
fun sortChapterBySourceOrNumber() = prefs.getInt(Keys.defaultChapterSortBySourceOrNumber, DomainManga.CHAPTER_SORTING_SOURCE.toInt())
|
fun sortChapterByAscendingOrDescending() = this.preferenceStore.getInt(Keys.defaultChapterSortByAscendingOrDescending, DomainManga.CHAPTER_SORT_DESC.toInt())
|
||||||
|
|
||||||
fun displayChapterByNameOrNumber() = prefs.getInt(Keys.defaultChapterDisplayByNameOrNumber, DomainManga.CHAPTER_DISPLAY_NAME.toInt())
|
fun incognitoMode() = this.preferenceStore.getBoolean("incognito_mode", false)
|
||||||
|
|
||||||
fun sortChapterByAscendingOrDescending() = prefs.getInt(Keys.defaultChapterSortByAscendingOrDescending, DomainManga.CHAPTER_SORT_DESC.toInt())
|
fun tabletUiMode() = this.preferenceStore.getEnum("tablet_ui_mode", Values.TabletUiMode.AUTOMATIC)
|
||||||
|
|
||||||
fun incognitoMode() = flowPrefs.getBoolean("incognito_mode", false)
|
fun extensionInstaller() = this.preferenceStore.getEnum(
|
||||||
|
|
||||||
fun tabletUiMode() = flowPrefs.getEnum("tablet_ui_mode", Values.TabletUiMode.AUTOMATIC)
|
|
||||||
|
|
||||||
fun extensionInstaller() = flowPrefs.getEnum(
|
|
||||||
"extension_installer",
|
"extension_installer",
|
||||||
if (DeviceUtil.isMiui) Values.ExtensionInstaller.LEGACY else Values.ExtensionInstaller.PACKAGEINSTALLER,
|
if (DeviceUtil.isMiui) Values.ExtensionInstaller.LEGACY else Values.ExtensionInstaller.PACKAGEINSTALLER,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun verboseLogging() = prefs.getBoolean(Keys.verboseLogging, isDevFlavor)
|
fun autoClearChapterCache() = this.preferenceStore.getBoolean(Keys.autoClearChapterCache, false)
|
||||||
|
|
||||||
fun autoClearChapterCache() = prefs.getBoolean(Keys.autoClearChapterCache, false)
|
fun duplicatePinnedSources() = this.preferenceStore.getBoolean("duplicate_pinned_sources", false)
|
||||||
|
|
||||||
fun duplicatePinnedSources() = flowPrefs.getBoolean("duplicate_pinned_sources", false)
|
|
||||||
|
|
||||||
fun setChapterSettingsDefault(manga: Manga) {
|
fun setChapterSettingsDefault(manga: Manga) {
|
||||||
prefs.edit {
|
filterChapterByRead().set(manga.readFilter)
|
||||||
putInt(Keys.defaultChapterFilterByRead, manga.readFilter)
|
filterChapterByDownloaded().set(manga.downloadedFilter)
|
||||||
putInt(Keys.defaultChapterFilterByDownloaded, manga.downloadedFilter)
|
filterChapterByBookmarked().set(manga.bookmarkedFilter)
|
||||||
putInt(Keys.defaultChapterFilterByBookmarked, manga.bookmarkedFilter)
|
sortChapterBySourceOrNumber().set(manga.sorting)
|
||||||
putInt(Keys.defaultChapterSortBySourceOrNumber, manga.sorting)
|
displayChapterByNameOrNumber().set(manga.displayMode)
|
||||||
putInt(Keys.defaultChapterDisplayByNameOrNumber, manga.displayMode)
|
sortChapterByAscendingOrDescending().set(if (manga.sortDescending()) DomainManga.CHAPTER_SORT_DESC.toInt() else DomainManga.CHAPTER_SORT_ASC.toInt())
|
||||||
putInt(Keys.defaultChapterSortByAscendingOrDescending, if (manga.sortDescending()) DomainManga.CHAPTER_SORT_DESC.toInt() else DomainManga.CHAPTER_SORT_ASC.toInt())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,9 +69,9 @@ abstract class TrackService(val id: Long) {
|
||||||
get() = getUsername().isNotEmpty() &&
|
get() = getUsername().isNotEmpty() &&
|
||||||
getPassword().isNotEmpty()
|
getPassword().isNotEmpty()
|
||||||
|
|
||||||
fun getUsername() = preferences.trackUsername(this)!!
|
fun getUsername() = preferences.trackUsername(this).get()
|
||||||
|
|
||||||
fun getPassword() = preferences.trackPassword(this)!!
|
fun getPassword() = preferences.trackPassword(this).get()
|
||||||
|
|
||||||
fun saveCredentials(username: String, password: String) {
|
fun saveCredentials(username: String, password: String) {
|
||||||
preferences.setTrackCredentials(this, username, password)
|
preferences.setTrackCredentials(this, username, password)
|
||||||
|
|
|
@ -99,6 +99,6 @@ class MangaUpdates(private val context: Context, id: Long) : TrackService(id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun restoreSession(): String? {
|
fun restoreSession(): String? {
|
||||||
return preferences.trackPassword(this)
|
return preferences.trackPassword(this).get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,7 +193,7 @@ class ExtensionManager(
|
||||||
.map(AvailableSources::lang)
|
.map(AvailableSources::lang)
|
||||||
|
|
||||||
val deviceLanguage = Locale.getDefault().language
|
val deviceLanguage = Locale.getDefault().language
|
||||||
val defaultLanguages = preferences.enabledLanguages().defaultValue
|
val defaultLanguages = preferences.enabledLanguages().defaultValue()
|
||||||
val languagesToEnable = availableLanguages.filter {
|
val languagesToEnable = availableLanguages.filter {
|
||||||
it != deviceLanguage && it.startsWith(deviceLanguage)
|
it != deviceLanguage && it.startsWith(deviceLanguage)
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,8 +82,8 @@ class SecureActivityDelegateImpl : SecureActivityDelegate, DefaultLifecycleObser
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setSecureScreen() {
|
private fun setSecureScreen() {
|
||||||
val secureScreenFlow = preferences.secureScreen().asFlow()
|
val secureScreenFlow = preferences.secureScreen().changes()
|
||||||
val incognitoModeFlow = preferences.incognitoMode().asFlow()
|
val incognitoModeFlow = preferences.incognitoMode().changes()
|
||||||
combine(secureScreenFlow, incognitoModeFlow) { secureScreen, incognitoMode ->
|
combine(secureScreenFlow, incognitoModeFlow) { secureScreen, incognitoMode ->
|
||||||
secureScreen == PreferenceValues.SecureScreenMode.ALWAYS ||
|
secureScreen == PreferenceValues.SecureScreenMode.ALWAYS ||
|
||||||
secureScreen == PreferenceValues.SecureScreenMode.INCOGNITO && incognitoMode
|
secureScreen == PreferenceValues.SecureScreenMode.INCOGNITO && incognitoMode
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package eu.kanade.tachiyomi.ui.base.presenter
|
package eu.kanade.tachiyomi.ui.base.presenter
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.fredporciuncula.flow.preferences.Preference
|
|
||||||
import eu.kanade.core.prefs.PreferenceMutableState
|
import eu.kanade.core.prefs.PreferenceMutableState
|
||||||
|
import eu.kanade.tachiyomi.core.preference.Preference
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.MainScope
|
import kotlinx.coroutines.MainScope
|
||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
|
|
|
@ -123,7 +123,7 @@ class ExtensionsPresenter(
|
||||||
|
|
||||||
presenterScope.launchIO { findAvailableExtensions() }
|
presenterScope.launchIO { findAvailableExtensions() }
|
||||||
|
|
||||||
preferences.extensionUpdatesCount().asFlow()
|
preferences.extensionUpdatesCount().changes()
|
||||||
.onEach { state.updates = it }
|
.onEach { state.updates = it }
|
||||||
.launchIn(presenterScope)
|
.launchIn(presenterScope)
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,11 +42,11 @@ class MigrationSourcesPresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences.migrationSortingDirection().asFlow()
|
preferences.migrationSortingDirection().changes()
|
||||||
.onEach { state.sortingDirection = it }
|
.onEach { state.sortingDirection = it }
|
||||||
.launchIn(presenterScope)
|
.launchIn(presenterScope)
|
||||||
|
|
||||||
preferences.migrationSortingMode().asFlow()
|
preferences.migrationSortingMode().changes()
|
||||||
.onEach { state.sortingMode = it }
|
.onEach { state.sortingMode = it }
|
||||||
.launchIn(presenterScope)
|
.launchIn(presenterScope)
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,7 +111,7 @@ open class BrowseSourcePresenter(
|
||||||
val isLandscape = LocalConfiguration.current.orientation == Configuration.ORIENTATION_LANDSCAPE
|
val isLandscape = LocalConfiguration.current.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||||
return produceState<GridCells>(initialValue = GridCells.Adaptive(128.dp), isLandscape) {
|
return produceState<GridCells>(initialValue = GridCells.Adaptive(128.dp), isLandscape) {
|
||||||
(if (isLandscape) preferences.landscapeColumns() else preferences.portraitColumns())
|
(if (isLandscape) preferences.landscapeColumns() else preferences.portraitColumns())
|
||||||
.asFlow()
|
.changes()
|
||||||
.collectLatest { columns ->
|
.collectLatest { columns ->
|
||||||
value = if (columns == 0) GridCells.Adaptive(128.dp) else GridCells.Fixed(columns)
|
value = if (columns == 0) GridCells.Adaptive(128.dp) else GridCells.Fixed(columns)
|
||||||
}
|
}
|
||||||
|
@ -257,7 +257,7 @@ open class BrowseSourcePresenter(
|
||||||
fun addFavorite(manga: DomainManga) {
|
fun addFavorite(manga: DomainManga) {
|
||||||
presenterScope.launch {
|
presenterScope.launch {
|
||||||
val categories = getCategories()
|
val categories = getCategories()
|
||||||
val defaultCategoryId = preferences.defaultCategory()
|
val defaultCategoryId = preferences.defaultCategory().get()
|
||||||
val defaultCategory = categories.find { it.id == defaultCategoryId.toLong() }
|
val defaultCategory = categories.find { it.id == defaultCategoryId.toLong() }
|
||||||
|
|
||||||
when {
|
when {
|
||||||
|
|
|
@ -174,7 +174,7 @@ open class GlobalSearchController(
|
||||||
* @param searchResult result of search.
|
* @param searchResult result of search.
|
||||||
*/
|
*/
|
||||||
fun setItems(searchResult: List<GlobalSearchItem>) {
|
fun setItems(searchResult: List<GlobalSearchItem>) {
|
||||||
if (searchResult.isEmpty() && preferences.searchPinnedSourcesOnly()) {
|
if (searchResult.isEmpty() && preferences.searchPinnedSourcesOnly().get()) {
|
||||||
binding.emptyView.show(R.string.no_pinned_sources)
|
binding.emptyView.show(R.string.no_pinned_sources)
|
||||||
} else {
|
} else {
|
||||||
binding.emptyView.hide()
|
binding.emptyView.hide()
|
||||||
|
|
|
@ -123,7 +123,7 @@ open class GlobalSearchPresenter(
|
||||||
return filteredSources
|
return filteredSources
|
||||||
}
|
}
|
||||||
|
|
||||||
val onlyPinnedSources = preferences.searchPinnedSourcesOnly()
|
val onlyPinnedSources = preferences.searchPinnedSourcesOnly().get()
|
||||||
val pinnedSourceIds = preferences.pinnedSources().get()
|
val pinnedSourceIds = preferences.pinnedSources().get()
|
||||||
|
|
||||||
return enabledSources
|
return enabledSources
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package eu.kanade.tachiyomi.ui.library.setting
|
package eu.kanade.tachiyomi.ui.library.setting
|
||||||
|
|
||||||
import eu.kanade.domain.category.model.Category
|
import eu.kanade.domain.category.model.Category
|
||||||
import com.fredporciuncula.flow.preferences.Serializer as PreferencesSerializer
|
|
||||||
|
|
||||||
sealed class LibraryDisplayMode(
|
sealed class LibraryDisplayMode(
|
||||||
override val flag: Long,
|
override val flag: Long,
|
||||||
|
@ -14,12 +13,12 @@ sealed class LibraryDisplayMode(
|
||||||
object List : LibraryDisplayMode(0b00000010)
|
object List : LibraryDisplayMode(0b00000010)
|
||||||
object CoverOnlyGrid : LibraryDisplayMode(0b00000011)
|
object CoverOnlyGrid : LibraryDisplayMode(0b00000011)
|
||||||
|
|
||||||
object Serializer : PreferencesSerializer<LibraryDisplayMode> {
|
object Serializer {
|
||||||
override fun deserialize(serialized: String): LibraryDisplayMode {
|
fun deserialize(serialized: String): LibraryDisplayMode {
|
||||||
return LibraryDisplayMode.deserialize(serialized)
|
return LibraryDisplayMode.deserialize(serialized)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun serialize(value: LibraryDisplayMode): String {
|
fun serialize(value: LibraryDisplayMode): String {
|
||||||
return value.serialize()
|
return value.serialize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package eu.kanade.tachiyomi.ui.library.setting
|
package eu.kanade.tachiyomi.ui.library.setting
|
||||||
|
|
||||||
import eu.kanade.domain.category.model.Category
|
import eu.kanade.domain.category.model.Category
|
||||||
import com.fredporciuncula.flow.preferences.Serializer as PreferencesSerializer
|
|
||||||
|
|
||||||
data class LibrarySort(
|
data class LibrarySort(
|
||||||
val type: Type,
|
val type: Type,
|
||||||
|
@ -57,12 +56,12 @@ data class LibrarySort(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object Serializer : PreferencesSerializer<LibrarySort> {
|
object Serializer {
|
||||||
override fun deserialize(serialized: String): LibrarySort {
|
fun deserialize(serialized: String): LibrarySort {
|
||||||
return LibrarySort.deserialize(serialized)
|
return LibrarySort.deserialize(serialized)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun serialize(value: LibrarySort): String {
|
fun serialize(value: LibrarySort): String {
|
||||||
return value.serialize()
|
return value.serialize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,8 @@ import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.merge
|
import kotlinx.coroutines.flow.merge
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
class MainActivity : BaseActivity() {
|
class MainActivity : BaseActivity() {
|
||||||
|
@ -105,7 +107,15 @@ class MainActivity : BaseActivity() {
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
val didMigration = if (savedInstanceState == null) Migrations.upgrade(preferences) else false
|
val didMigration = if (savedInstanceState == null) {
|
||||||
|
Migrations.upgrade(
|
||||||
|
context = applicationContext,
|
||||||
|
preferences = preferences,
|
||||||
|
networkPreferences = Injekt.get(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
binding = MainActivityBinding.inflate(layoutInflater)
|
binding = MainActivityBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
@ -240,7 +250,7 @@ class MainActivity : BaseActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
merge(preferences.showUpdatesNavBadge().asFlow(), preferences.unreadUpdatesCount().asFlow())
|
merge(preferences.showUpdatesNavBadge().changes(), preferences.unreadUpdatesCount().changes())
|
||||||
.onEach { setUnreadUpdatesBadge() }
|
.onEach { setUnreadUpdatesBadge() }
|
||||||
.launchIn(lifecycleScope)
|
.launchIn(lifecycleScope)
|
||||||
|
|
||||||
|
@ -253,7 +263,7 @@ class MainActivity : BaseActivity() {
|
||||||
.launchIn(lifecycleScope)
|
.launchIn(lifecycleScope)
|
||||||
|
|
||||||
binding.incognitoMode.isVisible = preferences.incognitoMode().get()
|
binding.incognitoMode.isVisible = preferences.incognitoMode().get()
|
||||||
preferences.incognitoMode().asFlow()
|
preferences.incognitoMode().changes()
|
||||||
.drop(1)
|
.drop(1)
|
||||||
.onEach {
|
.onEach {
|
||||||
binding.incognitoMode.isVisible = it
|
binding.incognitoMode.isVisible = it
|
||||||
|
@ -490,7 +500,7 @@ class MainActivity : BaseActivity() {
|
||||||
lifecycleScope.launchUI { resetExitConfirmation() }
|
lifecycleScope.launchUI { resetExitConfirmation() }
|
||||||
} else if (backstackSize == 1 || !router.handleBack()) {
|
} else if (backstackSize == 1 || !router.handleBack()) {
|
||||||
// Regular back (i.e. closing the app)
|
// Regular back (i.e. closing the app)
|
||||||
if (preferences.autoClearChapterCache()) {
|
if (preferences.autoClearChapterCache().get()) {
|
||||||
chapterCache.clear()
|
chapterCache.clear()
|
||||||
}
|
}
|
||||||
super.onBackPressed()
|
super.onBackPressed()
|
||||||
|
@ -534,7 +544,7 @@ class MainActivity : BaseActivity() {
|
||||||
private fun shouldHandleExitConfirmation(): Boolean {
|
private fun shouldHandleExitConfirmation(): Boolean {
|
||||||
return router.backstackSize == 1 &&
|
return router.backstackSize == 1 &&
|
||||||
router.getControllerWithTag("$startScreenId") != null &&
|
router.getControllerWithTag("$startScreenId") != null &&
|
||||||
preferences.confirmExit() &&
|
preferences.confirmExit().get() &&
|
||||||
!isConfirmingExit
|
!isConfirmingExit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -283,7 +283,7 @@ class MangaPresenter(
|
||||||
|
|
||||||
// Now check if user previously set categories, when available
|
// Now check if user previously set categories, when available
|
||||||
val categories = getCategories()
|
val categories = getCategories()
|
||||||
val defaultCategoryId = preferences.defaultCategory().toLong()
|
val defaultCategoryId = preferences.defaultCategory().get().toLong()
|
||||||
val defaultCategory = categories.find { it.id == defaultCategoryId }
|
val defaultCategory = categories.find { it.id == defaultCategoryId }
|
||||||
when {
|
when {
|
||||||
// Default category set
|
// Default category set
|
||||||
|
|
|
@ -194,7 +194,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
|
||||||
initializeMenu()
|
initializeMenu()
|
||||||
|
|
||||||
// Finish when incognito mode is disabled
|
// Finish when incognito mode is disabled
|
||||||
preferences.incognitoMode().asFlow()
|
preferences.incognitoMode().changes()
|
||||||
.drop(1)
|
.drop(1)
|
||||||
.onEach { if (!it) finish() }
|
.onEach { if (!it) finish() }
|
||||||
.launchIn(lifecycleScope)
|
.launchIn(lifecycleScope)
|
||||||
|
@ -446,7 +446,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
|
||||||
presenter.setMangaReadingMode(newReadingMode.flagValue)
|
presenter.setMangaReadingMode(newReadingMode.flagValue)
|
||||||
|
|
||||||
menuToggleToast?.cancel()
|
menuToggleToast?.cancel()
|
||||||
if (!preferences.showReadingMode()) {
|
if (!preferences.showReadingMode().get()) {
|
||||||
menuToggleToast = toast(newReadingMode.stringRes)
|
menuToggleToast = toast(newReadingMode.stringRes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,7 +480,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
|
||||||
updateCropBordersShortcut()
|
updateCropBordersShortcut()
|
||||||
listOf(preferences.cropBorders(), preferences.cropBordersWebtoon())
|
listOf(preferences.cropBorders(), preferences.cropBordersWebtoon())
|
||||||
.forEach { pref ->
|
.forEach { pref ->
|
||||||
pref.asFlow()
|
pref.changes()
|
||||||
.onEach { updateCropBordersShortcut() }
|
.onEach { updateCropBordersShortcut() }
|
||||||
.launchIn(lifecycleScope)
|
.launchIn(lifecycleScope)
|
||||||
}
|
}
|
||||||
|
@ -493,7 +493,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
|
||||||
popupMenu(
|
popupMenu(
|
||||||
items = OrientationType.values().map { it.flagValue to it.stringRes },
|
items = OrientationType.values().map { it.flagValue to it.stringRes },
|
||||||
selectedItemId = presenter.manga?.orientationType
|
selectedItemId = presenter.manga?.orientationType
|
||||||
?: preferences.defaultOrientationType(),
|
?: preferences.defaultOrientationType().get(),
|
||||||
) {
|
) {
|
||||||
val newOrientation = OrientationType.fromPreference(itemId)
|
val newOrientation = OrientationType.fromPreference(itemId)
|
||||||
|
|
||||||
|
@ -635,7 +635,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
|
||||||
updateViewerInset(preferences.fullscreen().get())
|
updateViewerInset(preferences.fullscreen().get())
|
||||||
binding.viewerContainer.addView(newViewer.getView())
|
binding.viewerContainer.addView(newViewer.getView())
|
||||||
|
|
||||||
if (preferences.showReadingMode()) {
|
if (preferences.showReadingMode().get()) {
|
||||||
showReadingModeToast(presenter.getMangaReadingMode())
|
showReadingModeToast(presenter.getMangaReadingMode())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -949,7 +949,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
|
||||||
* Initializes the reader subscriptions.
|
* Initializes the reader subscriptions.
|
||||||
*/
|
*/
|
||||||
init {
|
init {
|
||||||
preferences.readerTheme().asFlow()
|
preferences.readerTheme().changes()
|
||||||
.onEach {
|
.onEach {
|
||||||
binding.readerContainer.setBackgroundResource(
|
binding.readerContainer.setBackgroundResource(
|
||||||
when (preferences.readerTheme().get()) {
|
when (preferences.readerTheme().get()) {
|
||||||
|
@ -962,41 +962,41 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
|
||||||
}
|
}
|
||||||
.launchIn(lifecycleScope)
|
.launchIn(lifecycleScope)
|
||||||
|
|
||||||
preferences.showPageNumber().asFlow()
|
preferences.showPageNumber().changes()
|
||||||
.onEach { setPageNumberVisibility(it) }
|
.onEach { setPageNumberVisibility(it) }
|
||||||
.launchIn(lifecycleScope)
|
.launchIn(lifecycleScope)
|
||||||
|
|
||||||
preferences.trueColor().asFlow()
|
preferences.trueColor().changes()
|
||||||
.onEach { setTrueColor(it) }
|
.onEach { setTrueColor(it) }
|
||||||
.launchIn(lifecycleScope)
|
.launchIn(lifecycleScope)
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
preferences.cutoutShort().asFlow()
|
preferences.cutoutShort().changes()
|
||||||
.onEach { setCutoutShort(it) }
|
.onEach { setCutoutShort(it) }
|
||||||
.launchIn(lifecycleScope)
|
.launchIn(lifecycleScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences.keepScreenOn().asFlow()
|
preferences.keepScreenOn().changes()
|
||||||
.onEach { setKeepScreenOn(it) }
|
.onEach { setKeepScreenOn(it) }
|
||||||
.launchIn(lifecycleScope)
|
.launchIn(lifecycleScope)
|
||||||
|
|
||||||
preferences.customBrightness().asFlow()
|
preferences.customBrightness().changes()
|
||||||
.onEach { setCustomBrightness(it) }
|
.onEach { setCustomBrightness(it) }
|
||||||
.launchIn(lifecycleScope)
|
.launchIn(lifecycleScope)
|
||||||
|
|
||||||
preferences.colorFilter().asFlow()
|
preferences.colorFilter().changes()
|
||||||
.onEach { setColorFilter(it) }
|
.onEach { setColorFilter(it) }
|
||||||
.launchIn(lifecycleScope)
|
.launchIn(lifecycleScope)
|
||||||
|
|
||||||
preferences.colorFilterMode().asFlow()
|
preferences.colorFilterMode().changes()
|
||||||
.onEach { setColorFilter(preferences.colorFilter().get()) }
|
.onEach { setColorFilter(preferences.colorFilter().get()) }
|
||||||
.launchIn(lifecycleScope)
|
.launchIn(lifecycleScope)
|
||||||
|
|
||||||
merge(preferences.grayscale().asFlow(), preferences.invertedColors().asFlow())
|
merge(preferences.grayscale().changes(), preferences.invertedColors().changes())
|
||||||
.onEach { setLayerPaint(preferences.grayscale().get(), preferences.invertedColors().get()) }
|
.onEach { setLayerPaint(preferences.grayscale().get(), preferences.invertedColors().get()) }
|
||||||
.launchIn(lifecycleScope)
|
.launchIn(lifecycleScope)
|
||||||
|
|
||||||
preferences.fullscreen().asFlow()
|
preferences.fullscreen().changes()
|
||||||
.onEach {
|
.onEach {
|
||||||
WindowCompat.setDecorFitsSystemWindows(window, !it)
|
WindowCompat.setDecorFitsSystemWindows(window, !it)
|
||||||
updateViewerInset(it)
|
updateViewerInset(it)
|
||||||
|
@ -1060,7 +1060,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
|
||||||
*/
|
*/
|
||||||
private fun setCustomBrightness(enabled: Boolean) {
|
private fun setCustomBrightness(enabled: Boolean) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
preferences.customBrightnessValue().asFlow()
|
preferences.customBrightnessValue().changes()
|
||||||
.sample(100)
|
.sample(100)
|
||||||
.onEach { setCustomBrightnessValue(it) }
|
.onEach { setCustomBrightnessValue(it) }
|
||||||
.launchIn(lifecycleScope)
|
.launchIn(lifecycleScope)
|
||||||
|
@ -1074,7 +1074,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
|
||||||
*/
|
*/
|
||||||
private fun setColorFilter(enabled: Boolean) {
|
private fun setColorFilter(enabled: Boolean) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
preferences.colorFilterValue().asFlow()
|
preferences.colorFilterValue().changes()
|
||||||
.sample(100)
|
.sample(100)
|
||||||
.onEach { setColorFilterValue(it) }
|
.onEach { setColorFilterValue(it) }
|
||||||
.launchIn(lifecycleScope)
|
.launchIn(lifecycleScope)
|
||||||
|
|
|
@ -140,11 +140,11 @@ class ReaderPresenter(
|
||||||
?: error("Requested chapter of id $chapterId not found in chapter list")
|
?: error("Requested chapter of id $chapterId not found in chapter list")
|
||||||
|
|
||||||
val chaptersForReader = when {
|
val chaptersForReader = when {
|
||||||
(preferences.skipRead() || preferences.skipFiltered()) -> {
|
(preferences.skipRead().get() || preferences.skipFiltered().get()) -> {
|
||||||
val filteredChapters = chapters.filterNot {
|
val filteredChapters = chapters.filterNot {
|
||||||
when {
|
when {
|
||||||
preferences.skipRead() && it.read -> true
|
preferences.skipRead().get() && it.read -> true
|
||||||
preferences.skipFiltered() -> {
|
preferences.skipFiltered().get() -> {
|
||||||
(manga.readFilter == DomainManga.CHAPTER_SHOW_READ.toInt() && !it.read) ||
|
(manga.readFilter == DomainManga.CHAPTER_SHOW_READ.toInt() && !it.read) ||
|
||||||
(manga.readFilter == DomainManga.CHAPTER_SHOW_UNREAD.toInt() && it.read) ||
|
(manga.readFilter == DomainManga.CHAPTER_SHOW_UNREAD.toInt() && it.read) ||
|
||||||
(manga.downloadedFilter == DomainManga.CHAPTER_SHOW_DOWNLOADED.toInt() && !downloadManager.isChapterDownloaded(it.name, it.scanlator, manga.title, manga.source)) ||
|
(manga.downloadedFilter == DomainManga.CHAPTER_SHOW_DOWNLOADED.toInt() && !downloadManager.isChapterDownloaded(it.name, it.scanlator, manga.title, manga.source)) ||
|
||||||
|
@ -502,7 +502,7 @@ class ReaderPresenter(
|
||||||
private fun deleteChapterIfNeeded(currentChapter: ReaderChapter) {
|
private fun deleteChapterIfNeeded(currentChapter: ReaderChapter) {
|
||||||
// Determine which chapter should be deleted and enqueue
|
// Determine which chapter should be deleted and enqueue
|
||||||
val currentChapterPosition = chapterList.indexOf(currentChapter)
|
val currentChapterPosition = chapterList.indexOf(currentChapter)
|
||||||
val removeAfterReadSlots = preferences.removeAfterReadSlots()
|
val removeAfterReadSlots = preferences.removeAfterReadSlots().get()
|
||||||
val chapterToDelete = chapterList.getOrNull(currentChapterPosition - removeAfterReadSlots)
|
val chapterToDelete = chapterList.getOrNull(currentChapterPosition - removeAfterReadSlots)
|
||||||
|
|
||||||
if (removeAfterReadSlots != 0 && chapterDownload != null) {
|
if (removeAfterReadSlots != 0 && chapterDownload != null) {
|
||||||
|
@ -619,7 +619,7 @@ class ReaderPresenter(
|
||||||
* Returns the viewer position used by this manga or the default one.
|
* Returns the viewer position used by this manga or the default one.
|
||||||
*/
|
*/
|
||||||
fun getMangaReadingMode(resolveDefault: Boolean = true): Int {
|
fun getMangaReadingMode(resolveDefault: Boolean = true): Int {
|
||||||
val default = preferences.defaultReadingMode()
|
val default = preferences.defaultReadingMode().get()
|
||||||
val readingMode = ReadingModeType.fromPreference(manga?.readingModeType)
|
val readingMode = ReadingModeType.fromPreference(manga?.readingModeType)
|
||||||
return when {
|
return when {
|
||||||
resolveDefault && readingMode == ReadingModeType.DEFAULT -> default
|
resolveDefault && readingMode == ReadingModeType.DEFAULT -> default
|
||||||
|
@ -656,7 +656,7 @@ class ReaderPresenter(
|
||||||
* Returns the orientation type used by this manga or the default one.
|
* Returns the orientation type used by this manga or the default one.
|
||||||
*/
|
*/
|
||||||
fun getMangaOrientationType(resolveDefault: Boolean = true): Int {
|
fun getMangaOrientationType(resolveDefault: Boolean = true): Int {
|
||||||
val default = preferences.defaultOrientationType()
|
val default = preferences.defaultOrientationType().get()
|
||||||
val orientation = OrientationType.fromPreference(manga?.orientationType)
|
val orientation = OrientationType.fromPreference(manga?.orientationType)
|
||||||
return when {
|
return when {
|
||||||
resolveDefault && orientation == OrientationType.DEFAULT -> default
|
resolveDefault && orientation == OrientationType.DEFAULT -> default
|
||||||
|
@ -714,7 +714,7 @@ class ReaderPresenter(
|
||||||
val filename = generateFilename(manga, page)
|
val filename = generateFilename(manga, page)
|
||||||
|
|
||||||
// Pictures directory.
|
// Pictures directory.
|
||||||
val relativePath = if (preferences.folderPerManga()) DiskUtil.buildValidFilename(manga.title) else ""
|
val relativePath = if (preferences.folderPerManga().get()) DiskUtil.buildValidFilename(manga.title) else ""
|
||||||
|
|
||||||
// Copy file in background.
|
// Copy file in background.
|
||||||
try {
|
try {
|
||||||
|
@ -818,7 +818,7 @@ class ReaderPresenter(
|
||||||
* will run in a background thread and errors are ignored.
|
* will run in a background thread and errors are ignored.
|
||||||
*/
|
*/
|
||||||
private fun updateTrackChapterRead(readerChapter: ReaderChapter) {
|
private fun updateTrackChapterRead(readerChapter: ReaderChapter) {
|
||||||
if (!preferences.autoUpdateTrack()) return
|
if (!preferences.autoUpdateTrack().get()) return
|
||||||
val manga = manga ?: return
|
val manga = manga ?: return
|
||||||
|
|
||||||
val chapterRead = readerChapter.chapter.chapter_number.toDouble()
|
val chapterRead = readerChapter.chapter.chapter_number.toDouble()
|
||||||
|
|
|
@ -32,15 +32,15 @@ class ReaderColorFilterSettings @JvmOverloads constructor(context: Context, attr
|
||||||
init {
|
init {
|
||||||
addView(binding.root)
|
addView(binding.root)
|
||||||
|
|
||||||
preferences.colorFilter().asFlow()
|
preferences.colorFilter().changes()
|
||||||
.onEach { setColorFilter(it) }
|
.onEach { setColorFilter(it) }
|
||||||
.launchIn((context as ReaderActivity).lifecycleScope)
|
.launchIn((context as ReaderActivity).lifecycleScope)
|
||||||
|
|
||||||
preferences.colorFilterMode().asFlow()
|
preferences.colorFilterMode().changes()
|
||||||
.onEach { setColorFilter(preferences.colorFilter().get()) }
|
.onEach { setColorFilter(preferences.colorFilter().get()) }
|
||||||
.launchIn(context.lifecycleScope)
|
.launchIn(context.lifecycleScope)
|
||||||
|
|
||||||
preferences.customBrightness().asFlow()
|
preferences.customBrightness().changes()
|
||||||
.onEach { setCustomBrightness(it) }
|
.onEach { setCustomBrightness(it) }
|
||||||
.launchIn(context.lifecycleScope)
|
.launchIn(context.lifecycleScope)
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ class ReaderColorFilterSettings @JvmOverloads constructor(context: Context, attr
|
||||||
*/
|
*/
|
||||||
private fun setCustomBrightness(enabled: Boolean) {
|
private fun setCustomBrightness(enabled: Boolean) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
preferences.customBrightnessValue().asFlow()
|
preferences.customBrightnessValue().changes()
|
||||||
.sample(100)
|
.sample(100)
|
||||||
.onEach { setCustomBrightnessValue(it) }
|
.onEach { setCustomBrightnessValue(it) }
|
||||||
.launchIn((context as ReaderActivity).lifecycleScope)
|
.launchIn((context as ReaderActivity).lifecycleScope)
|
||||||
|
@ -167,7 +167,7 @@ class ReaderColorFilterSettings @JvmOverloads constructor(context: Context, attr
|
||||||
*/
|
*/
|
||||||
private fun setColorFilter(enabled: Boolean) {
|
private fun setColorFilter(enabled: Boolean) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
preferences.colorFilterValue().asFlow()
|
preferences.colorFilterValue().changes()
|
||||||
.sample(100)
|
.sample(100)
|
||||||
.onEach { setColorFilterValue(it) }
|
.onEach { setColorFilterValue(it) }
|
||||||
.launchIn((context as ReaderActivity).lifecycleScope)
|
.launchIn((context as ReaderActivity).lifecycleScope)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package eu.kanade.tachiyomi.ui.reader.viewer
|
package eu.kanade.tachiyomi.ui.reader.viewer
|
||||||
|
|
||||||
import com.fredporciuncula.flow.preferences.Preference
|
import eu.kanade.tachiyomi.core.preference.Preference
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues.TappingInvertMode
|
import eu.kanade.tachiyomi.data.preference.PreferenceValues.TappingInvertMode
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
@ -80,7 +80,7 @@ abstract class ViewerConfig(preferences: PreferencesHelper, private val scope: C
|
||||||
valueAssignment: (T) -> Unit,
|
valueAssignment: (T) -> Unit,
|
||||||
onChanged: (T) -> Unit = {},
|
onChanged: (T) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
asFlow()
|
changes()
|
||||||
.onEach { valueAssignment(it) }
|
.onEach { valueAssignment(it) }
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.onEach { onChanged(it) }
|
.onEach { onChanged(it) }
|
||||||
|
|
|
@ -78,7 +78,7 @@ class PagerConfig(
|
||||||
|
|
||||||
preferences.pagerNavInverted()
|
preferences.pagerNavInverted()
|
||||||
.register({ tappingInverted = it }, { navigator.invertMode = it })
|
.register({ tappingInverted = it }, { navigator.invertMode = it })
|
||||||
preferences.pagerNavInverted().asFlow()
|
preferences.pagerNavInverted().changes()
|
||||||
.drop(1)
|
.drop(1)
|
||||||
.onEach { navigationModeChangedListener?.invoke() }
|
.onEach { navigationModeChangedListener?.invoke() }
|
||||||
.launchIn(scope)
|
.launchIn(scope)
|
||||||
|
|
|
@ -51,7 +51,7 @@ class WebtoonConfig(
|
||||||
|
|
||||||
preferences.webtoonNavInverted()
|
preferences.webtoonNavInverted()
|
||||||
.register({ tappingInverted = it }, { navigator.invertMode = it })
|
.register({ tappingInverted = it }, { navigator.invertMode = it })
|
||||||
preferences.webtoonNavInverted().asFlow()
|
preferences.webtoonNavInverted().changes()
|
||||||
.drop(1)
|
.drop(1)
|
||||||
.onEach { navigationModeChangedListener?.invoke() }
|
.onEach { navigationModeChangedListener?.invoke() }
|
||||||
.launchIn(scope)
|
.launchIn(scope)
|
||||||
|
@ -71,7 +71,7 @@ class WebtoonConfig(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
preferences.readerTheme().asFlow()
|
preferences.readerTheme().changes()
|
||||||
.drop(1)
|
.drop(1)
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.onEach { themeChangedListener?.invoke() }
|
.onEach { themeChangedListener?.invoke() }
|
||||||
|
|
|
@ -17,6 +17,7 @@ import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Target
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues
|
import eu.kanade.tachiyomi.data.preference.PreferenceValues
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
|
import eu.kanade.tachiyomi.network.NetworkPreferences
|
||||||
import eu.kanade.tachiyomi.network.PREF_DOH_360
|
import eu.kanade.tachiyomi.network.PREF_DOH_360
|
||||||
import eu.kanade.tachiyomi.network.PREF_DOH_ADGUARD
|
import eu.kanade.tachiyomi.network.PREF_DOH_ADGUARD
|
||||||
import eu.kanade.tachiyomi.network.PREF_DOH_ALIDNS
|
import eu.kanade.tachiyomi.network.PREF_DOH_ALIDNS
|
||||||
|
@ -69,6 +70,7 @@ class SettingsAdvancedController(
|
||||||
private val network: NetworkHelper by injectLazy()
|
private val network: NetworkHelper by injectLazy()
|
||||||
private val chapterCache: ChapterCache by injectLazy()
|
private val chapterCache: ChapterCache by injectLazy()
|
||||||
private val trackManager: TrackManager by injectLazy()
|
private val trackManager: TrackManager by injectLazy()
|
||||||
|
private val networkPreferences: NetworkPreferences by injectLazy()
|
||||||
|
|
||||||
@SuppressLint("BatteryLife")
|
@SuppressLint("BatteryLife")
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply {
|
||||||
|
@ -96,7 +98,7 @@ class SettingsAdvancedController(
|
||||||
}
|
}
|
||||||
|
|
||||||
switchPreference {
|
switchPreference {
|
||||||
key = Keys.verboseLogging
|
key = networkPreferences.verboseLogging().key()
|
||||||
titleRes = R.string.pref_verbose_logging
|
titleRes = R.string.pref_verbose_logging
|
||||||
summaryRes = R.string.pref_verbose_logging_summary
|
summaryRes = R.string.pref_verbose_logging_summary
|
||||||
defaultValue = isDevFlavor
|
defaultValue = isDevFlavor
|
||||||
|
@ -189,7 +191,7 @@ class SettingsAdvancedController(
|
||||||
onClick { clearWebViewData() }
|
onClick { clearWebViewData() }
|
||||||
}
|
}
|
||||||
intListPreference {
|
intListPreference {
|
||||||
key = Keys.dohProvider
|
key = networkPreferences.dohProvider().key()
|
||||||
titleRes = R.string.pref_dns_over_https
|
titleRes = R.string.pref_dns_over_https
|
||||||
entries = arrayOf(
|
entries = arrayOf(
|
||||||
context.getString(R.string.disabled),
|
context.getString(R.string.disabled),
|
||||||
|
@ -227,10 +229,11 @@ class SettingsAdvancedController(
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val defaultUserAgent = networkPreferences.defaultUserAgent()
|
||||||
editTextPreference {
|
editTextPreference {
|
||||||
key = Keys.defaultUserAgent
|
key = defaultUserAgent.key()
|
||||||
titleRes = R.string.pref_user_agent_string
|
titleRes = R.string.pref_user_agent_string
|
||||||
text = preferences.defaultUserAgent().get()
|
text = defaultUserAgent.get()
|
||||||
summary = network.defaultUserAgent
|
summary = network.defaultUserAgent
|
||||||
|
|
||||||
onChange {
|
onChange {
|
||||||
|
@ -247,10 +250,10 @@ class SettingsAdvancedController(
|
||||||
key = "pref_reset_user_agent"
|
key = "pref_reset_user_agent"
|
||||||
titleRes = R.string.pref_reset_user_agent_string
|
titleRes = R.string.pref_reset_user_agent_string
|
||||||
|
|
||||||
visibleIf(preferences.defaultUserAgent()) { it != preferences.defaultUserAgent().defaultValue }
|
visibleIf(defaultUserAgent) { it != defaultUserAgent.defaultValue() }
|
||||||
|
|
||||||
onClick {
|
onClick {
|
||||||
preferences.defaultUserAgent().delete()
|
defaultUserAgent.delete()
|
||||||
activity?.toast(R.string.requires_app_restart)
|
activity?.toast(R.string.requires_app_restart)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,7 +136,7 @@ class SettingsBackupController : SettingsController() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences.backupsDirectory().asFlow()
|
preferences.backupsDirectory().changes()
|
||||||
.onEach { path ->
|
.onEach { path ->
|
||||||
val dir = UniFile.fromUri(context, path.toUri())
|
val dir = UniFile.fromUri(context, path.toUri())
|
||||||
summary = dir.filePath + "/automatic"
|
summary = dir.filePath + "/automatic"
|
||||||
|
|
|
@ -130,7 +130,7 @@ abstract class SettingsController : PreferenceController() {
|
||||||
(activity as? AppCompatActivity)?.supportActionBar?.title = getTitle()
|
(activity as? AppCompatActivity)?.supportActionBar?.title = getTitle()
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <T> Preference.visibleIf(preference: com.fredporciuncula.flow.preferences.Preference<T>, crossinline block: (T) -> Boolean) {
|
inline fun <T> Preference.visibleIf(preference: eu.kanade.tachiyomi.core.preference.Preference<T>, crossinline block: (T) -> Boolean) {
|
||||||
preference.asHotFlow { isVisible = block(it) }
|
preference.asHotFlow { isVisible = block(it) }
|
||||||
.launchIn(viewScope)
|
.launchIn(viewScope)
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ class SettingsDownloadController : SettingsController() {
|
||||||
ctrl.showDialog(router)
|
ctrl.showDialog(router)
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences.downloadsDirectory().asFlow()
|
preferences.downloadsDirectory().changes()
|
||||||
.onEach { path ->
|
.onEach { path ->
|
||||||
val dir = UniFile.fromUri(context, path.toUri())
|
val dir = UniFile.fromUri(context, path.toUri())
|
||||||
summary = dir.filePath ?: path
|
summary = dir.filePath ?: path
|
||||||
|
@ -114,7 +114,7 @@ class SettingsDownloadController : SettingsController() {
|
||||||
entries = categories.map { it.visualName(context) }.toTypedArray()
|
entries = categories.map { it.visualName(context) }.toTypedArray()
|
||||||
entryValues = categories.map { it.id.toString() }.toTypedArray()
|
entryValues = categories.map { it.id.toString() }.toTypedArray()
|
||||||
|
|
||||||
preferences.removeExcludeCategories().asFlow()
|
preferences.removeExcludeCategories().changes()
|
||||||
.onEach { mutable ->
|
.onEach { mutable ->
|
||||||
val selected = mutable
|
val selected = mutable
|
||||||
.mapNotNull { id -> categories.find { it.id == id.toLong() } }
|
.mapNotNull { id -> categories.find { it.id == id.toLong() } }
|
||||||
|
@ -171,10 +171,10 @@ class SettingsDownloadController : SettingsController() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences.downloadNewChapterCategories().asFlow()
|
preferences.downloadNewChapterCategories().changes()
|
||||||
.onEach { updateSummary() }
|
.onEach { updateSummary() }
|
||||||
.launchIn(viewScope)
|
.launchIn(viewScope)
|
||||||
preferences.downloadNewChapterCategoriesExclude().asFlow()
|
preferences.downloadNewChapterCategoriesExclude().changes()
|
||||||
.onEach { updateSummary() }
|
.onEach { updateSummary() }
|
||||||
.launchIn(viewScope)
|
.launchIn(viewScope)
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ class SettingsLibraryController : SettingsController() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
combine(preferences.portraitColumns().asFlow(), preferences.landscapeColumns().asFlow()) { portraitCols, landscapeCols -> Pair(portraitCols, landscapeCols) }
|
combine(preferences.portraitColumns().changes(), preferences.landscapeColumns().changes()) { portraitCols, landscapeCols -> Pair(portraitCols, landscapeCols) }
|
||||||
.onEach { (portraitCols, landscapeCols) ->
|
.onEach { (portraitCols, landscapeCols) ->
|
||||||
val portrait = getColumnValue(portraitCols)
|
val portrait = getColumnValue(portraitCols)
|
||||||
val landscape = getColumnValue(landscapeCols)
|
val landscape = getColumnValue(landscapeCols)
|
||||||
|
@ -114,7 +114,7 @@ class SettingsLibraryController : SettingsController() {
|
||||||
entryValues = arrayOf("-1") + allCategories.map { it.id.toString() }.toTypedArray()
|
entryValues = arrayOf("-1") + allCategories.map { it.id.toString() }.toTypedArray()
|
||||||
defaultValue = "-1"
|
defaultValue = "-1"
|
||||||
|
|
||||||
val selectedCategory = allCategories.find { it.id == preferences.defaultCategory().toLong() }
|
val selectedCategory = allCategories.find { it.id == preferences.defaultCategory().get().toLong() }
|
||||||
summary = selectedCategory?.visualName(context)
|
summary = selectedCategory?.visualName(context)
|
||||||
?: context.getString(R.string.default_category_summary)
|
?: context.getString(R.string.default_category_summary)
|
||||||
onChange { newValue ->
|
onChange { newValue ->
|
||||||
|
@ -129,7 +129,7 @@ class SettingsLibraryController : SettingsController() {
|
||||||
bindTo(preferences.categorizedDisplaySettings())
|
bindTo(preferences.categorizedDisplaySettings())
|
||||||
titleRes = R.string.categorized_display_settings
|
titleRes = R.string.categorized_display_settings
|
||||||
|
|
||||||
preferences.categorizedDisplaySettings().asFlow()
|
preferences.categorizedDisplaySettings().changes()
|
||||||
.onEach {
|
.onEach {
|
||||||
if (it.not()) {
|
if (it.not()) {
|
||||||
resetCategoryFlags.await()
|
resetCategoryFlags.await()
|
||||||
|
@ -197,7 +197,7 @@ class SettingsLibraryController : SettingsController() {
|
||||||
summary = context.getString(R.string.restrictions, restrictionsText)
|
summary = context.getString(R.string.restrictions, restrictionsText)
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences.libraryUpdateDeviceRestriction().asFlow()
|
preferences.libraryUpdateDeviceRestriction().changes()
|
||||||
.onEach { updateSummary() }
|
.onEach { updateSummary() }
|
||||||
.launchIn(viewScope)
|
.launchIn(viewScope)
|
||||||
}
|
}
|
||||||
|
@ -226,7 +226,7 @@ class SettingsLibraryController : SettingsController() {
|
||||||
summary = restrictionsText
|
summary = restrictionsText
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences.libraryUpdateMangaRestriction().asFlow()
|
preferences.libraryUpdateMangaRestriction().changes()
|
||||||
.onEach { updateSummary() }
|
.onEach { updateSummary() }
|
||||||
.launchIn(viewScope)
|
.launchIn(viewScope)
|
||||||
}
|
}
|
||||||
|
@ -269,10 +269,10 @@ class SettingsLibraryController : SettingsController() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences.libraryUpdateCategories().asFlow()
|
preferences.libraryUpdateCategories().changes()
|
||||||
.onEach { updateSummary() }
|
.onEach { updateSummary() }
|
||||||
.launchIn(viewScope)
|
.launchIn(viewScope)
|
||||||
preferences.libraryUpdateCategoriesExclude().asFlow()
|
preferences.libraryUpdateCategoriesExclude().changes()
|
||||||
.onEach { updateSummary() }
|
.onEach { updateSummary() }
|
||||||
.launchIn(viewScope)
|
.launchIn(viewScope)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,12 +27,12 @@ object ChapterSettingsHelper {
|
||||||
suspend fun applySettingDefaults(mangaId: Long) {
|
suspend fun applySettingDefaults(mangaId: Long) {
|
||||||
setMangaChapterFlags.awaitSetAllFlags(
|
setMangaChapterFlags.awaitSetAllFlags(
|
||||||
mangaId = mangaId,
|
mangaId = mangaId,
|
||||||
unreadFilter = preferences.filterChapterByRead().toLong(),
|
unreadFilter = preferences.filterChapterByRead().get().toLong(),
|
||||||
downloadedFilter = preferences.filterChapterByDownloaded().toLong(),
|
downloadedFilter = preferences.filterChapterByDownloaded().get().toLong(),
|
||||||
bookmarkedFilter = preferences.filterChapterByBookmarked().toLong(),
|
bookmarkedFilter = preferences.filterChapterByBookmarked().get().toLong(),
|
||||||
sortingMode = preferences.sortChapterBySourceOrNumber().toLong(),
|
sortingMode = preferences.sortChapterBySourceOrNumber().get().toLong(),
|
||||||
sortingDirection = preferences.sortChapterByAscendingOrDescending().toLong(),
|
sortingDirection = preferences.sortChapterByAscendingOrDescending().get().toLong(),
|
||||||
displayMode = preferences.displayChapterByNameOrNumber().toLong(),
|
displayMode = preferences.displayChapterByNameOrNumber().get().toLong(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,12 +45,12 @@ object ChapterSettingsHelper {
|
||||||
.map { manga ->
|
.map { manga ->
|
||||||
setMangaChapterFlags.awaitSetAllFlags(
|
setMangaChapterFlags.awaitSetAllFlags(
|
||||||
mangaId = manga.id,
|
mangaId = manga.id,
|
||||||
unreadFilter = preferences.filterChapterByRead().toLong(),
|
unreadFilter = preferences.filterChapterByRead().get().toLong(),
|
||||||
downloadedFilter = preferences.filterChapterByDownloaded().toLong(),
|
downloadedFilter = preferences.filterChapterByDownloaded().get().toLong(),
|
||||||
bookmarkedFilter = preferences.filterChapterByBookmarked().toLong(),
|
bookmarkedFilter = preferences.filterChapterByBookmarked().get().toLong(),
|
||||||
sortingMode = preferences.sortChapterBySourceOrNumber().toLong(),
|
sortingMode = preferences.sortChapterBySourceOrNumber().get().toLong(),
|
||||||
sortingDirection = preferences.sortChapterByAscendingOrDescending().toLong(),
|
sortingDirection = preferences.sortChapterByAscendingOrDescending().get().toLong(),
|
||||||
displayMode = preferences.displayChapterByNameOrNumber().toLong(),
|
displayMode = preferences.displayChapterByNameOrNumber().get().toLong(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,15 +106,14 @@ inline fun <P : Preference> PreferenceGroup.addThenInit(p: P, block: P.() -> Uni
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <T> Preference.bindTo(preference: com.fredporciuncula.flow.preferences.Preference<T>) {
|
inline fun <T> Preference.bindTo(preference: eu.kanade.tachiyomi.core.preference.Preference<T>) {
|
||||||
key = preference.key
|
key = preference.key()
|
||||||
defaultValue = preference.defaultValue
|
defaultValue = preference.defaultValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <T> ListPreference.bindTo(preference: com.fredporciuncula.flow.preferences.Preference<T>) {
|
inline fun <T> ListPreference.bindTo(preference: eu.kanade.tachiyomi.core.preference.Preference<T>) {
|
||||||
key = preference.key
|
key = preference.key()
|
||||||
// ListPreferences persist values as strings, even when we're using our IntListPreference
|
defaultValue = preference.defaultValue().toString()
|
||||||
defaultValue = preference.defaultValue.toString()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun Preference.onClick(crossinline block: () -> Unit) {
|
inline fun Preference.onClick(crossinline block: () -> Unit) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package eu.kanade.tachiyomi.util.preference
|
package eu.kanade.tachiyomi.util.preference
|
||||||
|
|
||||||
import android.widget.CompoundButton
|
import android.widget.CompoundButton
|
||||||
import com.fredporciuncula.flow.preferences.Preference
|
import eu.kanade.tachiyomi.core.preference.Preference
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ fun CompoundButton.bindToPreference(pref: Preference<Boolean>) {
|
||||||
|
|
||||||
fun <T> Preference<T>.asHotFlow(block: (T) -> Unit): Flow<T> {
|
fun <T> Preference<T>.asHotFlow(block: (T) -> Unit): Flow<T> {
|
||||||
block(get())
|
block(get())
|
||||||
return asFlow()
|
return changes()
|
||||||
.onEach { block(it) }
|
.onEach { block(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,8 @@ import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.core.content.withStyledAttributes
|
import androidx.core.content.withStyledAttributes
|
||||||
import androidx.core.view.forEach
|
import androidx.core.view.forEach
|
||||||
import androidx.core.view.get
|
import androidx.core.view.get
|
||||||
import com.fredporciuncula.flow.preferences.Preference
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.core.preference.Preference
|
||||||
import eu.kanade.tachiyomi.databinding.PrefSpinnerBinding
|
import eu.kanade.tachiyomi.databinding.PrefSpinnerBinding
|
||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
|
|
||||||
|
|
|
@ -31,13 +31,15 @@ class TachiyomiSearchView @JvmOverloads constructor(
|
||||||
override fun onAttachedToWindow() {
|
override fun onAttachedToWindow() {
|
||||||
super.onAttachedToWindow()
|
super.onAttachedToWindow()
|
||||||
scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
|
scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
|
||||||
Injekt.get<PreferencesHelper>().incognitoMode().asHotFlow {
|
Injekt.get<PreferencesHelper>().incognitoMode()
|
||||||
imeOptions = if (it) {
|
.asHotFlow {
|
||||||
imeOptions or EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING
|
imeOptions = if (it) {
|
||||||
} else {
|
imeOptions or EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING
|
||||||
imeOptions and EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING.inv()
|
} else {
|
||||||
|
imeOptions and EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING.inv()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.launchIn(scope!!)
|
.launchIn(scope!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setOnQueryTextListener(listener: OnQueryTextListener?) {
|
override fun setOnQueryTextListener(listener: OnQueryTextListener?) {
|
||||||
|
|
|
@ -49,13 +49,15 @@ class TachiyomiTextInputEditText @JvmOverloads constructor(
|
||||||
* if [PreferencesHelper.incognitoMode] is true. Some IMEs may not respect this flag.
|
* if [PreferencesHelper.incognitoMode] is true. Some IMEs may not respect this flag.
|
||||||
*/
|
*/
|
||||||
fun EditText.setIncognito(viewScope: CoroutineScope) {
|
fun EditText.setIncognito(viewScope: CoroutineScope) {
|
||||||
Injekt.get<PreferencesHelper>().incognitoMode().asHotFlow {
|
Injekt.get<PreferencesHelper>().incognitoMode()
|
||||||
imeOptions = if (it) {
|
.asHotFlow {
|
||||||
imeOptions or EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING
|
imeOptions = if (it) {
|
||||||
} else {
|
imeOptions or EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING
|
||||||
imeOptions and EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING.inv()
|
} else {
|
||||||
|
imeOptions and EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING.inv()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.launchIn(viewScope)
|
.launchIn(viewScope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,178 @@
|
||||||
|
package eu.kanade.tachiyomi.core.preference
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.content.SharedPreferences.Editor
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
|
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.onEach
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()))
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
|
@ -8,13 +8,13 @@ import eu.kanade.tachiyomi.network.interceptor.UserAgentInterceptor
|
||||||
import okhttp3.Cache
|
import okhttp3.Cache
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.logging.HttpLoggingInterceptor
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class NetworkHelper(context: Context) {
|
class NetworkHelper(context: Context) {
|
||||||
|
|
||||||
// TODO: Abstract preferences similar to 1.x
|
private val preferences: NetworkPreferences by injectLazy()
|
||||||
private val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
|
||||||
|
|
||||||
private val cacheDir = File(context.cacheDir, "network_cache")
|
private val cacheDir = File(context.cacheDir, "network_cache")
|
||||||
private val cacheSize = 5L * 1024 * 1024 // 5 MiB
|
private val cacheSize = 5L * 1024 * 1024 // 5 MiB
|
||||||
|
@ -36,14 +36,14 @@ class NetworkHelper(context: Context) {
|
||||||
.addInterceptor(userAgentInterceptor)
|
.addInterceptor(userAgentInterceptor)
|
||||||
.addNetworkInterceptor(http103Interceptor)
|
.addNetworkInterceptor(http103Interceptor)
|
||||||
|
|
||||||
if (preferences.getBoolean("verbose_logging", false)) {
|
if (preferences.verboseLogging().get()) {
|
||||||
val httpLoggingInterceptor = HttpLoggingInterceptor().apply {
|
val httpLoggingInterceptor = HttpLoggingInterceptor().apply {
|
||||||
level = HttpLoggingInterceptor.Level.HEADERS
|
level = HttpLoggingInterceptor.Level.HEADERS
|
||||||
}
|
}
|
||||||
builder.addNetworkInterceptor(httpLoggingInterceptor)
|
builder.addNetworkInterceptor(httpLoggingInterceptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
when (preferences.getInt("doh_provider", -1)) {
|
when (preferences.dohProvider().get()) {
|
||||||
PREF_DOH_CLOUDFLARE -> builder.dohCloudflare()
|
PREF_DOH_CLOUDFLARE -> builder.dohCloudflare()
|
||||||
PREF_DOH_GOOGLE -> builder.dohGoogle()
|
PREF_DOH_GOOGLE -> builder.dohGoogle()
|
||||||
PREF_DOH_ADGUARD -> builder.dohAdGuard()
|
PREF_DOH_ADGUARD -> builder.dohAdGuard()
|
||||||
|
@ -70,6 +70,6 @@ class NetworkHelper(context: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
val defaultUserAgent by lazy {
|
val defaultUserAgent by lazy {
|
||||||
preferences.getString("default_user_agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0")!!
|
preferences.defaultUserAgent().get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -37,7 +37,6 @@ sqlitektx = "androidx.sqlite:sqlite-ktx:2.3.0-alpha05"
|
||||||
sqlite-android = "com.github.requery:sqlite-android:3.36.0"
|
sqlite-android = "com.github.requery:sqlite-android:3.36.0"
|
||||||
|
|
||||||
preferencektx = "androidx.preference:preference-ktx:1.2.0"
|
preferencektx = "androidx.preference:preference-ktx:1.2.0"
|
||||||
flowpreferences = "com.fredporciuncula:flow-preferences:1.8.0"
|
|
||||||
|
|
||||||
nucleus-core = { module = "info.android15.nucleus:nucleus", version.ref = "nucleus_version" }
|
nucleus-core = { module = "info.android15.nucleus:nucleus", version.ref = "nucleus_version" }
|
||||||
nucleus-supportv7 = { module = "info.android15.nucleus:nucleus-support-v7", version.ref = "nucleus_version" }
|
nucleus-supportv7 = { module = "info.android15.nucleus:nucleus-support-v7", version.ref = "nucleus_version" }
|
||||||
|
|
Loading…
Reference in a new issue