Просмотр исходного кода

Foundations for partial restores

Related to #3136
arkon 1 год назад
Родитель
Сommit
83a67feb48

+ 21 - 2
app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt

@@ -40,6 +40,7 @@ import eu.kanade.presentation.util.relativeTimeSpanString
 import eu.kanade.tachiyomi.data.backup.BackupFileValidator
 import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob
 import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreJob
+import eu.kanade.tachiyomi.data.backup.restore.RestoreOptions
 import eu.kanade.tachiyomi.data.cache.ChapterCache
 import eu.kanade.tachiyomi.util.storage.DiskUtil
 import eu.kanade.tachiyomi.util.system.DeviceUtil
@@ -249,7 +250,16 @@ object SettingsDataScreen : SearchableSettings {
                         confirmButton = {
                             TextButton(
                                 onClick = {
-                                    BackupRestoreJob.start(context, err.uri)
+                                    BackupRestoreJob.start(
+                                        context = context,
+                                        uri = err.uri,
+                                        // TODO: allow user-selectable restore options
+                                        options = RestoreOptions(
+                                            appSettings = true,
+                                            sourceSettings = true,
+                                            library = true,
+                                        ),
+                                    )
                                     onDismissRequest()
                                 },
                             ) {
@@ -283,7 +293,16 @@ object SettingsDataScreen : SearchableSettings {
             }
 
             if (results.missingSources.isEmpty() && results.missingTrackers.isEmpty()) {
-                BackupRestoreJob.start(context, it)
+                BackupRestoreJob.start(
+                    context = context,
+                    uri = it,
+                    // TODO: allow user-selectable restore options
+                    options = RestoreOptions(
+                        appSettings = true,
+                        sourceSettings = true,
+                        library = true,
+                    ),
+                )
                 return@rememberLauncherForActivityResult
             }
 

+ 16 - 3
app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestoreJob.kt

@@ -30,13 +30,19 @@ class BackupRestoreJob(private val context: Context, workerParams: WorkerParamet
 
     override suspend fun doWork(): Result {
         val uri = inputData.getString(LOCATION_URI_KEY)?.toUri()
-            ?: return Result.failure()
+        val options = inputData.getBooleanArray(OPTIONS_KEY)
+            ?.let { RestoreOptions.fromBooleanArray(it) }
+
+        if (uri == null || options == null) {
+            return Result.failure()
+        }
+
         val isSync = inputData.getBoolean(SYNC_KEY, false)
 
         setForegroundSafely()
 
         return try {
-            BackupRestorer(context, notifier, isSync).restore(uri)
+            BackupRestorer(context, notifier, isSync).restore(uri, options)
             Result.success()
         } catch (e: Exception) {
             if (e is CancellationException) {
@@ -69,10 +75,16 @@ class BackupRestoreJob(private val context: Context, workerParams: WorkerParamet
             return context.workManager.isRunning(TAG)
         }
 
-        fun start(context: Context, uri: Uri, sync: Boolean = false) {
+        fun start(
+            context: Context,
+            uri: Uri,
+            options: RestoreOptions,
+            sync: Boolean = false,
+        ) {
             val inputData = workDataOf(
                 LOCATION_URI_KEY to uri.toString(),
                 SYNC_KEY to sync,
+                OPTIONS_KEY to options.toBooleanArray(),
             )
             val request = OneTimeWorkRequestBuilder<BackupRestoreJob>()
                 .addTag(TAG)
@@ -91,3 +103,4 @@ private const val TAG = "BackupRestore"
 
 private const val LOCATION_URI_KEY = "location_uri" // String
 private const val SYNC_KEY = "sync" // Boolean
+private const val OPTIONS_KEY = "options" // BooleanArray

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

@@ -39,10 +39,10 @@ class BackupRestorer(
      */
     private var sourceMapping: Map<Long, String> = emptyMap()
 
-    suspend fun restore(uri: Uri) {
+    suspend fun restore(uri: Uri, options: RestoreOptions) {
         val startTime = System.currentTimeMillis()
 
-        restoreFromFile(uri)
+        restoreFromFile(uri, options)
 
         val time = System.currentTimeMillis() - startTime
 
@@ -57,20 +57,36 @@ class BackupRestorer(
         )
     }
 
-    private suspend fun restoreFromFile(uri: Uri) {
+    private suspend fun restoreFromFile(uri: Uri, options: RestoreOptions) {
         val backup = BackupUtil.decodeBackup(context, uri)
 
-        restoreAmount = backup.backupManga.size + 3 // +3 for categories, app prefs, source prefs
-
         // Store source mapping for error messages
         val backupMaps = backup.backupSources + backup.backupBrokenSources.map { it.toBackupSource() }
         sourceMapping = backupMaps.associate { it.sourceId to it.name }
 
+        if (options.library) {
+            restoreAmount += backup.backupManga.size + 1 // +1 for categories
+        }
+        if (options.appSettings) {
+            restoreAmount += 1
+        }
+        if (options.sourceSettings) {
+            restoreAmount += 1
+        }
+
         coroutineScope {
-            restoreCategories(backup.backupCategories)
-            restoreAppPreferences(backup.backupPreferences)
-            restoreSourcePreferences(backup.backupSourcePreferences)
-            restoreManga(backup.backupManga, backup.backupCategories)
+            if (options.library) {
+                restoreCategories(backup.backupCategories)
+            }
+            if (options.appSettings) {
+                restoreAppPreferences(backup.backupPreferences)
+            }
+            if (options.sourceSettings) {
+                restoreSourcePreferences(backup.backupSourcePreferences)
+            }
+            if (options.library) {
+                restoreManga(backup.backupManga, backup.backupCategories)
+            }
 
             // TODO: optionally trigger online library + tracker update
         }
@@ -154,3 +170,19 @@ class BackupRestorer(
         return File("")
     }
 }
+
+data class RestoreOptions(
+    val appSettings: Boolean,
+    val sourceSettings: Boolean,
+    val library: Boolean,
+) {
+    fun toBooleanArray() = booleanArrayOf(appSettings, sourceSettings, library)
+
+    companion object {
+        fun fromBooleanArray(booleanArray: BooleanArray) = RestoreOptions(
+            appSettings = booleanArray[0],
+            sourceSettings = booleanArray[1],
+            library = booleanArray[2],
+        )
+    }
+}