From ce7bf396ebc0b85d0e857c55b27cb5eab2ad9d5b Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 29 Oct 2023 12:24:02 -0400 Subject: [PATCH] Don't include "app state" preferences in backups --- app/build.gradle.kts | 2 +- .../eu/kanade/domain/base/BasePreferences.kt | 8 ++- .../source/service/SourcePreferences.kt | 8 ++- .../java/eu/kanade/tachiyomi/Migrations.kt | 71 ++++++++++++++++--- .../tachiyomi/data/backup/BackupCreator.kt | 4 +- .../core/security/SecurityPreferences.kt | 6 +- .../tachiyomi/core/preference/Preference.kt | 18 +++-- .../backup/service/BackupPreferences.kt | 4 +- .../library/service/LibraryPreferences.kt | 7 +- 9 files changed, 100 insertions(+), 28 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2e59bec8f6..3d120e8aa8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,7 +22,7 @@ android { defaultConfig { applicationId = "eu.kanade.tachiyomi" - versionCode = 107 + versionCode = 108 versionName = "0.14.7" buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"") diff --git a/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt b/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt index 34ef79b483..0acef84a9a 100644 --- a/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt +++ b/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt @@ -5,6 +5,7 @@ import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.util.system.isPreviewBuildType import eu.kanade.tachiyomi.util.system.isReleaseBuildType +import tachiyomi.core.preference.Preference import tachiyomi.core.preference.PreferenceStore class BasePreferences( @@ -12,9 +13,12 @@ class BasePreferences( private val preferenceStore: PreferenceStore, ) { - fun downloadedOnly() = preferenceStore.getBoolean("pref_downloaded_only", false) + fun downloadedOnly() = preferenceStore.getBoolean( + Preference.appStateKey("pref_downloaded_only"), + false, + ) - fun incognitoMode() = preferenceStore.getBoolean("incognito_mode", false) + fun incognitoMode() = preferenceStore.getBoolean(Preference.appStateKey("incognito_mode"), false) fun extensionInstaller() = ExtensionInstallerPreference(context, preferenceStore) diff --git a/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt b/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt index 582dd61d7b..67f5c3190a 100644 --- a/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt +++ b/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt @@ -2,6 +2,7 @@ package eu.kanade.domain.source.service import eu.kanade.domain.source.interactor.SetMigrateSorting import eu.kanade.tachiyomi.util.system.LocaleHelper +import tachiyomi.core.preference.Preference import tachiyomi.core.preference.PreferenceStore import tachiyomi.core.preference.getEnum import tachiyomi.domain.library.model.LibraryDisplayMode @@ -18,7 +19,10 @@ class SourcePreferences( fun pinnedSources() = preferenceStore.getStringSet("pinned_catalogues", emptySet()) - fun lastUsedSource() = preferenceStore.getLong("last_catalogue_source", -1) + fun lastUsedSource() = preferenceStore.getLong( + Preference.appStateKey("last_catalogue_source"), + -1, + ) fun showNsfwSource() = preferenceStore.getBoolean("show_nsfw_source", true) @@ -28,7 +32,7 @@ class SourcePreferences( fun extensionUpdatesCount() = preferenceStore.getInt("ext_updates_count", 0) - fun trustedSignatures() = preferenceStore.getStringSet("trusted_signatures", emptySet()) + fun trustedSignatures() = preferenceStore.getStringSet(Preference.appStateKey("trusted_signatures"), emptySet()) fun hideInLibraryItems() = preferenceStore.getBoolean("browse_hide_in_library_items", false) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt index bbdcaa6eae..b1cbe9d276 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt @@ -375,17 +375,28 @@ object Migrations { } } if (oldVersion < 107) { - preferenceStore.getAll() - .filter { it.key.startsWith("pref_mangasync_") || it.key.startsWith("track_token_") } - .forEach { (key, value) -> - if (value is String) { - preferenceStore - .getString(Preference.privateKey(key)) - .set(value) - - preferenceStore.getString(key).delete() - } - } + replacePreferences( + preferenceStore = preferenceStore, + filterPredicate = { it.key.startsWith("pref_mangasync_") || it.key.startsWith("track_token_") }, + newKey = { Preference.privateKey(it) }, + ) + } + if (oldVersion < 108) { + val prefsToReplace = listOf( + "pref_download_only", + "incognito_mode", + "last_catalogue_source", + "trusted_signatures", + "last_app_closed", + "library_update_last_timestamp", + "library_unseen_updates_count", + "last_used_category", + ) + replacePreferences( + preferenceStore = preferenceStore, + filterPredicate = { it.key in prefsToReplace }, + newKey = { Preference.appStateKey(it) }, + ) } return true } @@ -393,3 +404,41 @@ object Migrations { return false } } + +@Suppress("UNCHECKED_CAST") +private fun replacePreferences( + preferenceStore: PreferenceStore, + filterPredicate: (Map.Entry) -> Boolean, + newKey: (String) -> String, +) { + preferenceStore.getAll() + .filter(filterPredicate) + .forEach { (key, value) -> + when (value) { + is Int -> { + preferenceStore.getInt(newKey(key)).set(value) + preferenceStore.getInt(key).delete() + } + is Long -> { + preferenceStore.getLong(newKey(key)).set(value) + preferenceStore.getLong(key).delete() + } + is Float -> { + preferenceStore.getFloat(newKey(key)).set(value) + preferenceStore.getFloat(key).delete() + } + is String -> { + preferenceStore.getString(newKey(key)).set(value) + preferenceStore.getString(key).delete() + } + is Boolean -> { + preferenceStore.getBoolean(newKey(key)).set(value) + preferenceStore.getBoolean(key).delete() + } + is Set<*> -> (value as? Set)?.let { + preferenceStore.getStringSet(newKey(key)).set(value) + preferenceStore.getStringSet(key).delete() + } + } + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt index ef8704b02a..37c9e73f0f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt @@ -250,7 +250,9 @@ class BackupCreator( @Suppress("UNCHECKED_CAST") private fun Map.toBackupPreferences(): List { - return this.filterKeys { !Preference.isPrivate(it) } + return this.filterKeys { + !Preference.isPrivate(it) && !Preference.isAppState(it) + } .mapNotNull { (key, value) -> when (value) { is Int -> BackupPreference(key, IntPreferenceValue(value)) diff --git a/core/src/main/java/eu/kanade/tachiyomi/core/security/SecurityPreferences.kt b/core/src/main/java/eu/kanade/tachiyomi/core/security/SecurityPreferences.kt index 371bd776b7..f27b1a44c4 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/core/security/SecurityPreferences.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/core/security/SecurityPreferences.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.core.security import eu.kanade.tachiyomi.core.R +import tachiyomi.core.preference.Preference import tachiyomi.core.preference.PreferenceStore import tachiyomi.core.preference.getEnum @@ -20,7 +21,10 @@ class SecurityPreferences( * For app lock. Will be set when there is a pending timed lock. * Otherwise this pref should be deleted. */ - fun lastAppClosed() = preferenceStore.getLong("last_app_closed", 0) + fun lastAppClosed() = preferenceStore.getLong( + Preference.appStateKey("last_app_closed"), + 0, + ) enum class SecureScreenMode(val titleResId: Int) { ALWAYS(R.string.lock_always), diff --git a/core/src/main/java/tachiyomi/core/preference/Preference.kt b/core/src/main/java/tachiyomi/core/preference/Preference.kt index e10f6e7fe2..bd95798ef5 100644 --- a/core/src/main/java/tachiyomi/core/preference/Preference.kt +++ b/core/src/main/java/tachiyomi/core/preference/Preference.kt @@ -22,21 +22,29 @@ interface Preference { fun stateIn(scope: CoroutineScope): StateFlow - val isPrivate: Boolean - get() = key().startsWith(PRIVATE_PREFIX) - companion object { /** - * A preference that should not be exposed in places like backups. + * A preference that should not be exposed in places like backups without user consent. */ fun isPrivate(key: String): Boolean { return key.startsWith(PRIVATE_PREFIX) } - fun privateKey(key: String): String { return "${PRIVATE_PREFIX}$key" } + /** + * A preference used for internal app state that isn't really a user preference + * and therefore should not be inplaces like backips. + */ + fun isAppState(key: String): Boolean { + return key.startsWith(APP_STATE_PREFIX) + } + fun appStateKey(key: String): String { + return "${APP_STATE_PREFIX}$key" + } + + private const val APP_STATE_PREFIX = "__APP_STATE_" private const val PRIVATE_PREFIX = "__PRIVATE_" } } diff --git a/domain/src/main/java/tachiyomi/domain/backup/service/BackupPreferences.kt b/domain/src/main/java/tachiyomi/domain/backup/service/BackupPreferences.kt index e0f96dffab..e923b2daaf 100644 --- a/domain/src/main/java/tachiyomi/domain/backup/service/BackupPreferences.kt +++ b/domain/src/main/java/tachiyomi/domain/backup/service/BackupPreferences.kt @@ -1,5 +1,6 @@ package tachiyomi.domain.backup.service +import tachiyomi.core.preference.Preference import tachiyomi.core.preference.PreferenceStore import tachiyomi.core.provider.FolderProvider @@ -14,6 +15,5 @@ class BackupPreferences( fun backupInterval() = preferenceStore.getInt("backup_interval", 12) - // TODO: move this and other "app state" preferences elsewhere and exclude from backups - fun lastAutoBackupTimestamp() = preferenceStore.getLong("__APP_STATE_last_auto_backup_timestamp", 0L) + fun lastAutoBackupTimestamp() = preferenceStore.getLong(Preference.appStateKey("last_auto_backup_timestamp"), 0L) } diff --git a/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt b/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt index 8edfa7a275..1a51fa6593 100644 --- a/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt +++ b/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt @@ -1,5 +1,6 @@ package tachiyomi.domain.library.service +import tachiyomi.core.preference.Preference import tachiyomi.core.preference.PreferenceStore import tachiyomi.core.preference.TriState import tachiyomi.core.preference.getEnum @@ -29,7 +30,7 @@ class LibraryPreferences( fun landscapeColumns() = preferenceStore.getInt("pref_library_columns_landscape_key", 0) - fun lastUpdatedTimestamp() = preferenceStore.getLong("library_update_last_timestamp", 0L) + fun lastUpdatedTimestamp() = preferenceStore.getLong(Preference.appStateKey("library_update_last_timestamp"), 0L) fun autoUpdateInterval() = preferenceStore.getInt("pref_library_update_interval_key", 0) fun autoUpdateDeviceRestrictions() = preferenceStore.getStringSet( @@ -120,7 +121,7 @@ class LibraryPreferences( fun languageBadge() = preferenceStore.getBoolean("display_language_badge", false) fun newShowUpdatesCount() = preferenceStore.getBoolean("library_show_updates_count", true) - fun newUpdatesCount() = preferenceStore.getInt("library_unseen_updates_count", 0) + fun newUpdatesCount() = preferenceStore.getInt(Preference.appStateKey("library_unseen_updates_count"), 0) // endregion @@ -128,7 +129,7 @@ class LibraryPreferences( fun defaultCategory() = preferenceStore.getInt("default_category", -1) - fun lastUsedCategory() = preferenceStore.getInt("last_used_category", 0) + fun lastUsedCategory() = preferenceStore.getInt(Preference.appStateKey("last_used_category"), 0) fun categoryTabs() = preferenceStore.getBoolean("display_category_tabs", true)