Browse Source

Add source preferences to backups

Closes #1857

Co-authored-by: jmir1 <[email protected]>
arkon 1 year ago
parent
commit
0f42b9f154

+ 1 - 0
app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt

@@ -148,6 +148,7 @@ object SettingsBackupScreen : SearchableSettings {
                 BackupConst.BACKUP_TRACK to R.string.track,
                 BackupConst.BACKUP_HISTORY to R.string.history,
                 BackupConst.BACKUP_APP_PREFS to R.string.app_settings,
+                BackupConst.BACKUP_SOURCE_PREFS to R.string.source_settings,
             )
         }
         val flags = remember { choices.keys.toMutableStateList() }

+ 4 - 1
app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt

@@ -17,5 +17,8 @@ internal object BackupConst {
     const val BACKUP_APP_PREFS = 0x10
     const val BACKUP_APP_PREFS_MASK = 0x10
 
-    const val BACKUP_ALL = 0x1F
+    const val BACKUP_SOURCE_PREFS = 0x20
+    const val BACKUP_SOURCE_PREFS_MASK = 0x20
+
+    const val BACKUP_ALL = 0x3F
 }

+ 26 - 3
app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt

@@ -12,12 +12,15 @@ import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY
 import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY_MASK
 import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CHAPTER
 import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CHAPTER_MASK
+import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_SOURCE_PREFS
+import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_SOURCE_PREFS_MASK
 import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_HISTORY
 import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_HISTORY_MASK
 import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_TRACK
 import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_TRACK_MASK
 import eu.kanade.tachiyomi.data.backup.models.Backup
 import eu.kanade.tachiyomi.data.backup.models.BackupCategory
+import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences
 import eu.kanade.tachiyomi.data.backup.models.BackupHistory
 import eu.kanade.tachiyomi.data.backup.models.BackupManga
 import eu.kanade.tachiyomi.data.backup.models.BackupPreference
@@ -32,7 +35,10 @@ import eu.kanade.tachiyomi.data.backup.models.StringSetPreferenceValue
 import eu.kanade.tachiyomi.data.backup.models.backupCategoryMapper
 import eu.kanade.tachiyomi.data.backup.models.backupChapterMapper
 import eu.kanade.tachiyomi.data.backup.models.backupTrackMapper
+import eu.kanade.tachiyomi.source.ConfigurableSource
 import eu.kanade.tachiyomi.source.model.copyFrom
+import eu.kanade.tachiyomi.source.preferenceKey
+import eu.kanade.tachiyomi.source.sourcePreferences
 import eu.kanade.tachiyomi.util.system.hasPermission
 import kotlinx.serialization.protobuf.ProtoBuf
 import logcat.LogPriority
@@ -94,6 +100,7 @@ class BackupManager(
             emptyList(),
             prepExtensionInfoForSync(databaseManga),
             backupAppPreferences(flags),
+            backupSourcePreferences(flags),
         )
 
         var file: UniFile? = null
@@ -232,12 +239,28 @@ class BackupManager(
         return mangaObject
     }
 
-    @Suppress("UNCHECKED_CAST")
     private fun backupAppPreferences(flags: Int): List<BackupPreference> {
         if (flags and BACKUP_APP_PREFS_MASK != BACKUP_APP_PREFS) return emptyList()
 
-        return preferenceStore.getAll()
-            .filterKeys { !Preference.isPrivate(it) }
+        return preferenceStore.getAll().toBackupPreferences()
+    }
+
+    private fun backupSourcePreferences(flags: Int): List<BackupSourcePreferences> {
+        if (flags and BACKUP_SOURCE_PREFS_MASK != BACKUP_SOURCE_PREFS) return emptyList()
+
+        return sourceManager.getOnlineSources()
+            .filterIsInstance<ConfigurableSource>()
+            .map {
+                BackupSourcePreferences(
+                    it.preferenceKey(),
+                    it.sourcePreferences().all.toBackupPreferences()
+                )
+            }
+    }
+
+    @Suppress("UNCHECKED_CAST")
+    private fun Map<String, *>.toBackupPreferences(): List<BackupPreference> {
+        return this.filterKeys { !Preference.isPrivate(it) }
             .mapNotNull { (key, value) ->
                 when (value) {
                     is Int -> BackupPreference(key, IntPreferenceValue(value))

+ 19 - 9
app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt

@@ -9,16 +9,19 @@ import eu.kanade.tachiyomi.data.backup.models.BackupHistory
 import eu.kanade.tachiyomi.data.backup.models.BackupManga
 import eu.kanade.tachiyomi.data.backup.models.BackupPreference
 import eu.kanade.tachiyomi.data.backup.models.BackupSource
+import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences
 import eu.kanade.tachiyomi.data.backup.models.BooleanPreferenceValue
 import eu.kanade.tachiyomi.data.backup.models.FloatPreferenceValue
 import eu.kanade.tachiyomi.data.backup.models.IntPreferenceValue
 import eu.kanade.tachiyomi.data.backup.models.LongPreferenceValue
 import eu.kanade.tachiyomi.data.backup.models.StringPreferenceValue
 import eu.kanade.tachiyomi.data.backup.models.StringSetPreferenceValue
+import eu.kanade.tachiyomi.source.sourcePreferences
 import eu.kanade.tachiyomi.util.BackupUtil
 import eu.kanade.tachiyomi.util.system.createFileInCacheDir
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.isActive
+import tachiyomi.core.preference.AndroidPreferenceStore
 import tachiyomi.core.preference.PreferenceStore
 import tachiyomi.domain.chapter.model.Chapter
 import tachiyomi.domain.manga.interactor.FetchInterval
@@ -114,6 +117,7 @@ class BackupRestorer(
 
         return coroutineScope {
             restoreAppPreferences(backup.backupPreferences)
+            restoreSourcePreferences(backup.backupSourcePreferences)
 
             // Restore individual manga
             backup.backupManga.forEach {
@@ -211,9 +215,22 @@ class BackupRestorer(
     }
 
     private fun restoreAppPreferences(preferences: List<BackupPreference>) {
-        val prefs = preferenceStore.getAll()
+        restorePreferences(preferences, preferenceStore)
+    }
+
+    private fun restoreSourcePreferences(preferences: List<BackupSourcePreferences>) {
+        preferences.forEach {
+            val sourcePrefs = AndroidPreferenceStore(context, sourcePreferences(it.sourceKey))
+            restorePreferences(it.prefs, sourcePrefs)
+        }
+    }
 
-        preferences.forEach { (key, value) ->
+    private fun restorePreferences(
+        toRestore: List<BackupPreference>,
+        preferenceStore: PreferenceStore,
+    ) {
+        val prefs = preferenceStore.getAll()
+        toRestore.forEach { (key, value) ->
             when (value) {
                 is IntPreferenceValue -> {
                     if (prefs[key] is Int?) {
@@ -249,13 +266,6 @@ class BackupRestorer(
         }
     }
 
-    /**
-     * Called to update dialog in [BackupConst]
-     *
-     * @param progress restore progress
-     * @param amount total restoreAmount of manga
-     * @param title title of restored manga
-     */
     private fun showRestoreProgress(progress: Int, amount: Int, title: String, contentTitle: String) {
         notifier.showRestoreProgress(title, contentTitle, progress, amount)
     }

+ 1 - 0
app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt

@@ -14,6 +14,7 @@ data class Backup(
     @ProtoNumber(100) var backupBrokenSources: List<BrokenBackupSource> = emptyList(),
     @ProtoNumber(101) var backupSources: List<BackupSource> = emptyList(),
     @ProtoNumber(104) var backupPreferences: List<BackupPreference> = emptyList(),
+    @ProtoNumber(105) var backupSourcePreferences: List<BackupSourcePreferences> = emptyList(),
 ) {
 
     companion object {

+ 6 - 0
app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupPreference.kt

@@ -9,6 +9,12 @@ data class BackupPreference(
     @ProtoNumber(2) val value: PreferenceValue,
 )
 
+@Serializable
+data class BackupSourcePreferences(
+    @ProtoNumber(1) val sourceKey: String,
+    @ProtoNumber(2) val prefs: List<BackupPreference>,
+)
+
 @Serializable
 sealed class PreferenceValue
 

+ 1 - 2
core/src/main/java/tachiyomi/core/preference/AndroidPreferenceStore.kt

@@ -15,10 +15,9 @@ import tachiyomi.core.preference.AndroidPreference.StringSetPrimitive
 
 class AndroidPreferenceStore(
     context: Context,
+    private val sharedPreferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context),
 ) : PreferenceStore {
 
-    private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
-
     private val keyFlow = sharedPreferences.keyFlow
 
     override fun getString(key: String, defaultValue: String): Preference<String> {

+ 1 - 0
i18n/src/main/res/values/strings.xml

@@ -494,6 +494,7 @@
     <string name="backup_in_progress">Backup is already in progress</string>
     <string name="backup_choice">What do you want to backup?</string>
     <string name="app_settings">App settings</string>
+    <string name="source_settings">Source settings</string>
     <string name="creating_backup">Creating backup</string>
     <string name="creating_backup_error">Backup failed</string>
     <string name="missing_storage_permission">Storage permissions not granted</string>

+ 4 - 1
source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt

@@ -19,8 +19,11 @@ interface ConfigurableSource : Source {
     fun setupPreferenceScreen(screen: PreferenceScreen)
 }
 
-private fun ConfigurableSource.preferenceKey(): String = "source_$id"
+fun ConfigurableSource.preferenceKey(): String = "source_$id"
 
 // TODO: use getSourcePreferences once all extensions are on ext-lib 1.5
 fun ConfigurableSource.sourcePreferences(): SharedPreferences =
     Injekt.get<Application>().getSharedPreferences(preferenceKey(), Context.MODE_PRIVATE)
+
+fun sourcePreferences(key: String): SharedPreferences =
+    Injekt.get<Application>().getSharedPreferences(key, Context.MODE_PRIVATE)