From ccec5c3efeea699124d4bb7448d6fe9718cb883f Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 28 Dec 2023 17:38:37 -0500 Subject: [PATCH] Add ability to create manual backups with private preferences too --- .../screen/data/CreateBackupScreen.kt | 10 +-- .../data/backup/create/BackupCreateJob.kt | 9 +-- .../data/backup/create/BackupCreator.kt | 4 +- .../data/backup/create/BackupOptions.kt | 61 ++++++------------- .../creators/PreferenceBackupCreator.kt | 20 ++++-- .../data/backup/restore/BackupRestoreJob.kt | 7 ++- .../data/backup/restore/RestoreOptions.kt | 12 +--- .../util/lang/BooleanArrayExtensions.kt | 18 ++++++ .../commonMain/resources/MR/base/strings.xml | 1 + 9 files changed, 65 insertions(+), 77 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/util/lang/BooleanArrayExtensions.kt diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt index 27aa0598fd..cf673b28d6 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt @@ -154,14 +154,6 @@ private class CreateBackupScreenModel : StateScreenModel() .addTag(TAG_MANUAL) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt index 6b3cfa5a4c..8bd718206c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt @@ -131,13 +131,13 @@ class BackupCreator( private fun backupAppPreferences(options: BackupOptions): List { if (!options.appSettings) return emptyList() - return preferenceBackupCreator.backupAppPreferences() + return preferenceBackupCreator.backupAppPreferences(includePrivatePreferences = options.privateSettings) } private fun backupSourcePreferences(options: BackupOptions): List { if (!options.sourceSettings) return emptyList() - return preferenceBackupCreator.backupSourcePreferences() + return preferenceBackupCreator.backupSourcePreferences(includePrivatePreferences = options.privateSettings) } companion object { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt index c7c59c97b6..13e1cf4803 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt @@ -12,75 +12,52 @@ data class BackupOptions( val history: Boolean = true, val appSettings: Boolean = true, val sourceSettings: Boolean = true, + val privateSettings: Boolean = false, ) { - fun toBooleanArray() = booleanArrayOf( - libraryEntries, - categories, - chapters, - tracking, - history, - appSettings, - sourceSettings, - ) companion object { - val AutomaticDefaults = BackupOptions( - libraryEntries = true, - categories = true, - chapters = true, - tracking = true, - history = true, - appSettings = true, - sourceSettings = true, - ) - - fun fromBooleanArray(booleanArray: BooleanArray) = BackupOptions( - libraryEntries = booleanArray[0], - categories = booleanArray[1], - chapters = booleanArray[2], - tracking = booleanArray[3], - history = booleanArray[4], - appSettings = booleanArray[5], - sourceSettings = booleanArray[6], - ) - - val entries = persistentListOf( - BackupOptionEntry( + val entries = persistentListOf( + Entry( label = MR.strings.categories, getter = BackupOptions::categories, setter = { options, enabled -> options.copy(categories = enabled) }, ), - BackupOptionEntry( + Entry( label = MR.strings.chapters, getter = BackupOptions::chapters, setter = { options, enabled -> options.copy(chapters = enabled) }, ), - BackupOptionEntry( + Entry( label = MR.strings.track, getter = BackupOptions::tracking, setter = { options, enabled -> options.copy(tracking = enabled) }, ), - BackupOptionEntry( + Entry( label = MR.strings.history, getter = BackupOptions::history, setter = { options, enabled -> options.copy(history = enabled) }, ), - BackupOptionEntry( + Entry( label = MR.strings.app_settings, getter = BackupOptions::appSettings, setter = { options, enabled -> options.copy(appSettings = enabled) }, ), - BackupOptionEntry( + Entry( label = MR.strings.source_settings, getter = BackupOptions::sourceSettings, setter = { options, enabled -> options.copy(sourceSettings = enabled) }, ), + Entry( + label = MR.strings.private_settings, + getter = BackupOptions::privateSettings, + setter = { options, enabled -> options.copy(privateSettings = enabled) }, + ), ) } -} -data class BackupOptionEntry( - val label: StringResource, - val getter: (BackupOptions) -> Boolean, - val setter: (BackupOptions, Boolean) -> BackupOptions, -) + data class Entry( + val label: StringResource, + val getter: (BackupOptions) -> Boolean, + val setter: (BackupOptions, Boolean) -> BackupOptions, + ) +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/PreferenceBackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/PreferenceBackupCreator.kt index 304f909ad5..cc1a7157f6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/PreferenceBackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/PreferenceBackupCreator.kt @@ -22,26 +22,27 @@ class PreferenceBackupCreator( private val preferenceStore: PreferenceStore = Injekt.get(), ) { - fun backupAppPreferences(): List { + fun backupAppPreferences(includePrivatePreferences: Boolean): List { return preferenceStore.getAll().toBackupPreferences() + .withPrivatePreferences(includePrivatePreferences) } - fun backupSourcePreferences(): List { + fun backupSourcePreferences(includePrivatePreferences: Boolean): List { return sourceManager.getCatalogueSources() .filterIsInstance() .map { BackupSourcePreferences( it.preferenceKey(), - it.sourcePreferences().all.toBackupPreferences(), + it.sourcePreferences().all.toBackupPreferences() + .withPrivatePreferences(includePrivatePreferences), ) } } @Suppress("UNCHECKED_CAST") private fun Map.toBackupPreferences(): List { - return this.filterKeys { - !Preference.isAppState(it) && !Preference.isPrivate(it) - } + return this + .filterKeys { !Preference.isAppState(it) } .mapNotNull { (key, value) -> when (value) { is Int -> BackupPreference(key, IntPreferenceValue(value)) @@ -56,4 +57,11 @@ class PreferenceBackupCreator( } } } + + private fun List.withPrivatePreferences(include: Boolean) = + if (include) { + this + } else { + this.filter { !Preference.isPrivate(it.key) } + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestoreJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestoreJob.kt index f1b3a28c90..470efcd83e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestoreJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestoreJob.kt @@ -13,6 +13,8 @@ import androidx.work.WorkerParameters import androidx.work.workDataOf import eu.kanade.tachiyomi.data.backup.BackupNotifier import eu.kanade.tachiyomi.data.notification.Notifications +import eu.kanade.tachiyomi.util.lang.asBooleanArray +import eu.kanade.tachiyomi.util.lang.asDataClass import eu.kanade.tachiyomi.util.system.cancelNotification import eu.kanade.tachiyomi.util.system.isRunning import eu.kanade.tachiyomi.util.system.setForegroundSafely @@ -30,8 +32,7 @@ class BackupRestoreJob(private val context: Context, workerParams: WorkerParamet override suspend fun doWork(): Result { val uri = inputData.getString(LOCATION_URI_KEY)?.toUri() - val options = inputData.getBooleanArray(OPTIONS_KEY) - ?.let { RestoreOptions.fromBooleanArray(it) } + val options: RestoreOptions? = inputData.getBooleanArray(OPTIONS_KEY)?.asDataClass() if (uri == null || options == null) { return Result.failure() @@ -84,7 +85,7 @@ class BackupRestoreJob(private val context: Context, workerParams: WorkerParamet val inputData = workDataOf( LOCATION_URI_KEY to uri.toString(), SYNC_KEY to sync, - OPTIONS_KEY to options.toBooleanArray(), + OPTIONS_KEY to options.asBooleanArray(), ) val request = OneTimeWorkRequestBuilder() .addTag(TAG) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt index d9e124a813..bd5bface9c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt @@ -4,14 +4,4 @@ data class RestoreOptions( val appSettings: Boolean = true, val sourceSettings: Boolean = true, val library: Boolean = true, -) { - fun toBooleanArray() = booleanArrayOf(appSettings, sourceSettings, library) - - companion object { - fun fromBooleanArray(booleanArray: BooleanArray) = RestoreOptions( - appSettings = booleanArray[0], - sourceSettings = booleanArray[1], - library = booleanArray[2], - ) - } -} +) diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/lang/BooleanArrayExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/lang/BooleanArrayExtensions.kt new file mode 100644 index 0000000000..f7b5778893 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/util/lang/BooleanArrayExtensions.kt @@ -0,0 +1,18 @@ +package eu.kanade.tachiyomi.util.lang + +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.declaredMemberProperties +import kotlin.reflect.full.primaryConstructor + +fun T.asBooleanArray(): BooleanArray { + return this::class.declaredMemberProperties + .filterIsInstance>() + .map { it.get(this) } + .toBooleanArray() +} + +inline fun BooleanArray.asDataClass(): T { + val properties = T::class.declaredMemberProperties.filterIsInstance>() + require(properties.size == this.size) { "Boolean array size does not match data class property count" } + return T::class.primaryConstructor!!.call(*this.toTypedArray()) +} diff --git a/i18n/src/commonMain/resources/MR/base/strings.xml b/i18n/src/commonMain/resources/MR/base/strings.xml index 640b514344..8e77eaea9c 100644 --- a/i18n/src/commonMain/resources/MR/base/strings.xml +++ b/i18n/src/commonMain/resources/MR/base/strings.xml @@ -504,6 +504,7 @@ What do you want to backup? App settings Source settings + Include sensitive settings (e.g., tracker login tokens) Creating backup Backup failed Storage permissions not granted