Don't include "app state" preferences in backups
This commit is contained in:
parent
1aa5222c99
commit
ce7bf396eb
9 changed files with 100 additions and 28 deletions
|
@ -22,7 +22,7 @@ android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "eu.kanade.tachiyomi"
|
applicationId = "eu.kanade.tachiyomi"
|
||||||
|
|
||||||
versionCode = 107
|
versionCode = 108
|
||||||
versionName = "0.14.7"
|
versionName = "0.14.7"
|
||||||
|
|
||||||
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
||||||
|
|
|
@ -5,6 +5,7 @@ import androidx.annotation.StringRes
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.util.system.isPreviewBuildType
|
import eu.kanade.tachiyomi.util.system.isPreviewBuildType
|
||||||
import eu.kanade.tachiyomi.util.system.isReleaseBuildType
|
import eu.kanade.tachiyomi.util.system.isReleaseBuildType
|
||||||
|
import tachiyomi.core.preference.Preference
|
||||||
import tachiyomi.core.preference.PreferenceStore
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
|
|
||||||
class BasePreferences(
|
class BasePreferences(
|
||||||
|
@ -12,9 +13,12 @@ class BasePreferences(
|
||||||
private val preferenceStore: PreferenceStore,
|
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)
|
fun extensionInstaller() = ExtensionInstallerPreference(context, preferenceStore)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package eu.kanade.domain.source.service
|
||||||
|
|
||||||
import eu.kanade.domain.source.interactor.SetMigrateSorting
|
import eu.kanade.domain.source.interactor.SetMigrateSorting
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
|
import tachiyomi.core.preference.Preference
|
||||||
import tachiyomi.core.preference.PreferenceStore
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
import tachiyomi.core.preference.getEnum
|
import tachiyomi.core.preference.getEnum
|
||||||
import tachiyomi.domain.library.model.LibraryDisplayMode
|
import tachiyomi.domain.library.model.LibraryDisplayMode
|
||||||
|
@ -18,7 +19,10 @@ class SourcePreferences(
|
||||||
|
|
||||||
fun pinnedSources() = preferenceStore.getStringSet("pinned_catalogues", emptySet())
|
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)
|
fun showNsfwSource() = preferenceStore.getBoolean("show_nsfw_source", true)
|
||||||
|
|
||||||
|
@ -28,7 +32,7 @@ class SourcePreferences(
|
||||||
|
|
||||||
fun extensionUpdatesCount() = preferenceStore.getInt("ext_updates_count", 0)
|
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)
|
fun hideInLibraryItems() = preferenceStore.getBoolean("browse_hide_in_library_items", false)
|
||||||
}
|
}
|
||||||
|
|
|
@ -375,17 +375,28 @@ object Migrations {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (oldVersion < 107) {
|
if (oldVersion < 107) {
|
||||||
preferenceStore.getAll()
|
replacePreferences(
|
||||||
.filter { it.key.startsWith("pref_mangasync_") || it.key.startsWith("track_token_") }
|
preferenceStore = preferenceStore,
|
||||||
.forEach { (key, value) ->
|
filterPredicate = { it.key.startsWith("pref_mangasync_") || it.key.startsWith("track_token_") },
|
||||||
if (value is String) {
|
newKey = { Preference.privateKey(it) },
|
||||||
preferenceStore
|
)
|
||||||
.getString(Preference.privateKey(key))
|
|
||||||
.set(value)
|
|
||||||
|
|
||||||
preferenceStore.getString(key).delete()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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
|
return true
|
||||||
}
|
}
|
||||||
|
@ -393,3 +404,41 @@ object Migrations {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
private fun replacePreferences(
|
||||||
|
preferenceStore: PreferenceStore,
|
||||||
|
filterPredicate: (Map.Entry<String, Any?>) -> 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<String>)?.let {
|
||||||
|
preferenceStore.getStringSet(newKey(key)).set(value)
|
||||||
|
preferenceStore.getStringSet(key).delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -250,7 +250,9 @@ class BackupCreator(
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
private fun Map<String, *>.toBackupPreferences(): List<BackupPreference> {
|
private fun Map<String, *>.toBackupPreferences(): List<BackupPreference> {
|
||||||
return this.filterKeys { !Preference.isPrivate(it) }
|
return this.filterKeys {
|
||||||
|
!Preference.isPrivate(it) && !Preference.isAppState(it)
|
||||||
|
}
|
||||||
.mapNotNull { (key, value) ->
|
.mapNotNull { (key, value) ->
|
||||||
when (value) {
|
when (value) {
|
||||||
is Int -> BackupPreference(key, IntPreferenceValue(value))
|
is Int -> BackupPreference(key, IntPreferenceValue(value))
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package eu.kanade.tachiyomi.core.security
|
package eu.kanade.tachiyomi.core.security
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.core.R
|
import eu.kanade.tachiyomi.core.R
|
||||||
|
import tachiyomi.core.preference.Preference
|
||||||
import tachiyomi.core.preference.PreferenceStore
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
import tachiyomi.core.preference.getEnum
|
import tachiyomi.core.preference.getEnum
|
||||||
|
|
||||||
|
@ -20,7 +21,10 @@ class SecurityPreferences(
|
||||||
* 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() = preferenceStore.getLong("last_app_closed", 0)
|
fun lastAppClosed() = preferenceStore.getLong(
|
||||||
|
Preference.appStateKey("last_app_closed"),
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
|
||||||
enum class SecureScreenMode(val titleResId: Int) {
|
enum class SecureScreenMode(val titleResId: Int) {
|
||||||
ALWAYS(R.string.lock_always),
|
ALWAYS(R.string.lock_always),
|
||||||
|
|
|
@ -22,21 +22,29 @@ interface Preference<T> {
|
||||||
|
|
||||||
fun stateIn(scope: CoroutineScope): StateFlow<T>
|
fun stateIn(scope: CoroutineScope): StateFlow<T>
|
||||||
|
|
||||||
val isPrivate: Boolean
|
|
||||||
get() = key().startsWith(PRIVATE_PREFIX)
|
|
||||||
|
|
||||||
companion object {
|
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 {
|
fun isPrivate(key: String): Boolean {
|
||||||
return key.startsWith(PRIVATE_PREFIX)
|
return key.startsWith(PRIVATE_PREFIX)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun privateKey(key: String): String {
|
fun privateKey(key: String): String {
|
||||||
return "${PRIVATE_PREFIX}$key"
|
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_"
|
private const val PRIVATE_PREFIX = "__PRIVATE_"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package tachiyomi.domain.backup.service
|
package tachiyomi.domain.backup.service
|
||||||
|
|
||||||
|
import tachiyomi.core.preference.Preference
|
||||||
import tachiyomi.core.preference.PreferenceStore
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
import tachiyomi.core.provider.FolderProvider
|
import tachiyomi.core.provider.FolderProvider
|
||||||
|
|
||||||
|
@ -14,6 +15,5 @@ class BackupPreferences(
|
||||||
|
|
||||||
fun backupInterval() = preferenceStore.getInt("backup_interval", 12)
|
fun backupInterval() = preferenceStore.getInt("backup_interval", 12)
|
||||||
|
|
||||||
// TODO: move this and other "app state" preferences elsewhere and exclude from backups
|
fun lastAutoBackupTimestamp() = preferenceStore.getLong(Preference.appStateKey("last_auto_backup_timestamp"), 0L)
|
||||||
fun lastAutoBackupTimestamp() = preferenceStore.getLong("__APP_STATE_last_auto_backup_timestamp", 0L)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package tachiyomi.domain.library.service
|
package tachiyomi.domain.library.service
|
||||||
|
|
||||||
|
import tachiyomi.core.preference.Preference
|
||||||
import tachiyomi.core.preference.PreferenceStore
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
import tachiyomi.core.preference.TriState
|
import tachiyomi.core.preference.TriState
|
||||||
import tachiyomi.core.preference.getEnum
|
import tachiyomi.core.preference.getEnum
|
||||||
|
@ -29,7 +30,7 @@ class LibraryPreferences(
|
||||||
|
|
||||||
fun landscapeColumns() = preferenceStore.getInt("pref_library_columns_landscape_key", 0)
|
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 autoUpdateInterval() = preferenceStore.getInt("pref_library_update_interval_key", 0)
|
||||||
|
|
||||||
fun autoUpdateDeviceRestrictions() = preferenceStore.getStringSet(
|
fun autoUpdateDeviceRestrictions() = preferenceStore.getStringSet(
|
||||||
|
@ -120,7 +121,7 @@ class LibraryPreferences(
|
||||||
fun languageBadge() = preferenceStore.getBoolean("display_language_badge", false)
|
fun languageBadge() = preferenceStore.getBoolean("display_language_badge", false)
|
||||||
|
|
||||||
fun newShowUpdatesCount() = preferenceStore.getBoolean("library_show_updates_count", true)
|
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
|
// endregion
|
||||||
|
|
||||||
|
@ -128,7 +129,7 @@ class LibraryPreferences(
|
||||||
|
|
||||||
fun defaultCategory() = preferenceStore.getInt("default_category", -1)
|
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)
|
fun categoryTabs() = preferenceStore.getBoolean("display_category_tabs", true)
|
||||||
|
|
||||||
|
|
Reference in a new issue