Procházet zdrojové kódy

Start cleaning up backup/restore code

The abstraction was useful for handling 2 systems, but it's no longer needed. Cleaning it up will make migrating to domain models easier down the line.
arkon před 2 roky
rodič
revize
a2bb81b7db

+ 3 - 2
app/build.gradle.kts

@@ -291,14 +291,15 @@ tasks {
     // See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api(-markers)
     withType<KotlinCompile> {
         kotlinOptions.freeCompilerArgs += listOf(
-            "-opt-in=kotlinx.coroutines.InternalCoroutinesApi",
             "-opt-in=coil.annotation.ExperimentalCoilApi",
+            "-opt-in=com.google.accompanist.pager.ExperimentalPagerApi",
             "-opt-in=androidx.compose.material3.ExperimentalMaterial3Api",
             "-opt-in=androidx.compose.ui.ExperimentalComposeUiApi",
             "-opt-in=androidx.compose.foundation.ExperimentalFoundationApi",
             "-opt-in=androidx.compose.animation.graphics.ExperimentalAnimationGraphicsApi",
             "-opt-in=androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi",
-            "-opt-in=com.google.accompanist.pager.ExperimentalPagerApi",
+            "-opt-in=kotlinx.coroutines.InternalCoroutinesApi",
+            "-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
         )
     }
 

+ 0 - 10
app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestoreValidator.kt

@@ -1,10 +0,0 @@
-package eu.kanade.tachiyomi.data.backup
-
-import android.content.Context
-import android.net.Uri
-
-abstract class AbstractBackupRestoreValidator {
-    abstract fun validate(context: Context, uri: Uri): Results
-
-    data class Results(val missingSources: List<String>, val missingTrackers: List<String>)
-}

+ 1 - 2
app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt

@@ -13,7 +13,6 @@ import androidx.work.WorkManager
 import androidx.work.WorkerParameters
 import androidx.work.workDataOf
 import com.hippo.unifile.UniFile
-import eu.kanade.tachiyomi.data.backup.full.FullBackupManager
 import eu.kanade.tachiyomi.data.notification.Notifications
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.util.system.logcat
@@ -36,7 +35,7 @@ class BackupCreatorJob(private val context: Context, workerParams: WorkerParamet
 
         context.notificationManager.notify(Notifications.ID_BACKUP_PROGRESS, notifier.showBackupProgress().build())
         return try {
-            val location = FullBackupManager(context).createBackup(uri, flags, isAutoBackup)
+            val location = BackupManager(context).createBackup(uri, flags, isAutoBackup)
             if (!isAutoBackup) notifier.showBackupComplete(UniFile.fromUri(context, location.toUri()))
             Result.success()
         } catch (e: Exception) {

+ 10 - 9
app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestoreValidator.kt → app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt

@@ -1,10 +1,9 @@
-package eu.kanade.tachiyomi.data.backup.full
+package eu.kanade.tachiyomi.data.backup
 
 import android.content.Context
 import android.net.Uri
 import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.backup.AbstractBackupRestoreValidator
-import eu.kanade.tachiyomi.data.backup.full.models.BackupSerializer
+import eu.kanade.tachiyomi.data.backup.models.BackupSerializer
 import eu.kanade.tachiyomi.data.track.TrackManager
 import eu.kanade.tachiyomi.source.SourceManager
 import okio.buffer
@@ -13,10 +12,10 @@ import okio.source
 import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.api.get
 
-class FullBackupRestoreValidator : AbstractBackupRestoreValidator() {
-
-    private val sourceManager: SourceManager = Injekt.get()
-    private val trackManager: TrackManager = Injekt.get()
+class BackupFileValidator(
+    private val sourceManager: SourceManager = Injekt.get(),
+    private val trackManager: TrackManager = Injekt.get(),
+) {
 
     /**
      * Checks for critical backup file data.
@@ -24,8 +23,8 @@ class FullBackupRestoreValidator : AbstractBackupRestoreValidator() {
      * @throws Exception if manga cannot be found.
      * @return List of missing sources or missing trackers.
      */
-    override fun validate(context: Context, uri: Uri): Results {
-        val backupManager = FullBackupManager(context)
+    fun validate(context: Context, uri: Uri): Results {
+        val backupManager = BackupManager(context)
 
         val backup = try {
             val backupString =
@@ -63,4 +62,6 @@ class FullBackupRestoreValidator : AbstractBackupRestoreValidator() {
 
         return Results(missingSources, missingTrackers)
     }
+
+    data class Results(val missingSources: List<String>, val missingTrackers: List<String>)
 }

+ 28 - 29
app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt → app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt

@@ -1,4 +1,4 @@
-package eu.kanade.tachiyomi.data.backup.full
+package eu.kanade.tachiyomi.data.backup
 
 import android.content.Context
 import android.net.Uri
@@ -9,7 +9,6 @@ import eu.kanade.data.category.categoryMapper
 import eu.kanade.domain.category.model.Category
 import eu.kanade.domain.history.model.HistoryUpdate
 import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.backup.AbstractBackupManager
 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
@@ -18,16 +17,15 @@ 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.full.models.Backup
-import eu.kanade.tachiyomi.data.backup.full.models.BackupCategory
-import eu.kanade.tachiyomi.data.backup.full.models.BackupFull
-import eu.kanade.tachiyomi.data.backup.full.models.BackupHistory
-import eu.kanade.tachiyomi.data.backup.full.models.BackupManga
-import eu.kanade.tachiyomi.data.backup.full.models.BackupSerializer
-import eu.kanade.tachiyomi.data.backup.full.models.BackupSource
-import eu.kanade.tachiyomi.data.backup.full.models.backupCategoryMapper
-import eu.kanade.tachiyomi.data.backup.full.models.backupChapterMapper
-import eu.kanade.tachiyomi.data.backup.full.models.backupTrackMapper
+import eu.kanade.tachiyomi.data.backup.models.Backup
+import eu.kanade.tachiyomi.data.backup.models.BackupCategory
+import eu.kanade.tachiyomi.data.backup.models.BackupHistory
+import eu.kanade.tachiyomi.data.backup.models.BackupManga
+import eu.kanade.tachiyomi.data.backup.models.BackupSerializer
+import eu.kanade.tachiyomi.data.backup.models.BackupSource
+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.data.database.models.Chapter
 import eu.kanade.tachiyomi.data.database.models.Manga
 import eu.kanade.tachiyomi.data.database.models.Track
@@ -42,7 +40,7 @@ import java.util.Date
 import kotlin.math.max
 import eu.kanade.domain.manga.model.Manga as DomainManga
 
-class FullBackupManager(context: Context) : AbstractBackupManager(context) {
+class BackupManager(context: Context) : AbstractBackupManager(context) {
 
     val parser = ProtoBuf
 
@@ -52,6 +50,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
      * @param uri path of Uri
      * @param isAutoBackup backup called from scheduled backup job
      */
+    @Suppress("BlockingMethodInNonBlockingContext")
     override suspend fun createBackup(uri: Uri, flags: Int, isAutoBackup: Boolean): String {
         // Create root object
         var backup: Backup? = null
@@ -59,7 +58,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
         val databaseManga = getFavoriteManga()
 
         backup = Backup(
-            backupManga(databaseManga, flags),
+            backupMangas(databaseManga, flags),
             backupCategories(flags),
             emptyList(),
             backupExtensionInfo(databaseManga),
@@ -83,7 +82,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
                         .forEach { it.delete() }
 
                     // Create new file to place backup
-                    dir.createFile(BackupFull.getDefaultFilename())
+                    dir.createFile(Backup.getBackupFilename())
                 } else {
                     UniFile.fromUri(context, uri)
                 }
@@ -106,7 +105,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
             val fileUri = file.uri
 
             // Make sure it's a valid backup file
-            FullBackupRestoreValidator().validate(context, fileUri)
+            BackupFileValidator().validate(context, fileUri)
 
             return fileUri.toString()
         } catch (e: Exception) {
@@ -116,12 +115,6 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
         }
     }
 
-    private suspend fun backupManga(mangas: List<DomainManga>, flags: Int): List<BackupManga> {
-        return mangas.map {
-            backupMangaObject(it, flags)
-        }
-    }
-
     private fun backupExtensionInfo(mangas: List<DomainManga>): List<BackupSource> {
         return mangas
             .asSequence()
@@ -148,6 +141,12 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
         }
     }
 
+    private suspend fun backupMangas(mangas: List<DomainManga>, flags: Int): List<BackupManga> {
+        return mangas.map {
+            backupManga(it, flags)
+        }
+    }
+
     /**
      * Convert a manga to Json
      *
@@ -155,7 +154,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
      * @param options options for the backup
      * @return [BackupManga] containing manga in a serializable form
      */
-    private suspend fun backupMangaObject(manga: DomainManga, options: Int): BackupManga {
+    private suspend fun backupManga(manga: DomainManga, options: Int): BackupManga {
         // Entry for this manga
         val mangaObject = BackupManga.copyFrom(manga)
 
@@ -202,7 +201,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
         return mangaObject
     }
 
-    suspend fun restoreMangaNoFetch(manga: Manga, dbManga: Mangas) {
+    suspend fun restoreExistingManga(manga: Manga, dbManga: Mangas) {
         manga.id = dbManga._id
         manga.copyFrom(dbManga)
         updateManga(manga)
@@ -214,7 +213,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
      * @param manga manga that needs updating
      * @return Updated manga info.
      */
-    suspend fun restoreManga(manga: Manga): Manga {
+    suspend fun restoreNewManga(manga: Manga): Manga {
         return manga.also {
             it.initialized = it.description != null
             it.id = insertManga(it)
@@ -267,7 +266,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
      * @param manga the manga whose categories have to be restored.
      * @param categories the categories to restore.
      */
-    internal suspend fun restoreCategoriesForManga(manga: Manga, categories: List<Int>, backupCategories: List<BackupCategory>) {
+    internal suspend fun restoreCategories(manga: Manga, categories: List<Int>, backupCategories: List<BackupCategory>) {
         val dbCategories = handler.awaitList { categoriesQueries.getCategories() }
         val mangaCategoriesToUpdate = mutableListOf<Pair<Long, Long>>()
 
@@ -299,7 +298,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
      *
      * @param history list containing history to be restored
      */
-    internal suspend fun restoreHistoryForManga(history: List<BackupHistory>) {
+    internal suspend fun restoreHistory(history: List<BackupHistory>) {
         // List containing history to be updated
         val toUpdate = mutableListOf<HistoryUpdate>()
         for ((url, lastRead, readDuration) in history) {
@@ -349,7 +348,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
      * @param manga the manga whose sync have to be restored.
      * @param tracks the track list to restore.
      */
-    internal suspend fun restoreTrackForManga(manga: Manga, tracks: List<Track>) {
+    internal suspend fun restoreTracking(manga: Manga, tracks: List<Track>) {
         // Fix foreign keys with the current manga id
         tracks.map { it.manga_id = manga.id!! }
 
@@ -427,7 +426,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
         }
     }
 
-    internal suspend fun restoreChaptersForManga(manga: Manga, chapters: List<Chapter>) {
+    internal suspend fun restoreChapters(manga: Manga, chapters: List<Chapter>) {
         val dbChapters = handler.awaitList { chaptersQueries.getChaptersByMangaId(manga.id!!) }
 
         chapters.forEach { chapter ->

+ 7 - 8
app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt

@@ -8,7 +8,6 @@ import android.os.IBinder
 import android.os.PowerManager
 import androidx.core.content.ContextCompat
 import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.backup.full.FullBackupRestore
 import eu.kanade.tachiyomi.data.notification.Notifications
 import eu.kanade.tachiyomi.util.system.acquireWakeLock
 import eu.kanade.tachiyomi.util.system.isServiceRunning
@@ -70,7 +69,7 @@ class BackupRestoreService : Service() {
     private lateinit var wakeLock: PowerManager.WakeLock
 
     private lateinit var ioScope: CoroutineScope
-    private var backupRestore: AbstractBackupRestore<*>? = null
+    private var restorer: AbstractBackupRestore<*>? = null
     private lateinit var notifier: BackupNotifier
 
     override fun onCreate() {
@@ -94,7 +93,7 @@ class BackupRestoreService : Service() {
     }
 
     private fun destroyJob() {
-        backupRestore?.job?.cancel()
+        restorer?.job?.cancel()
         ioScope.cancel()
         if (wakeLock.isHeld) {
             wakeLock.release()
@@ -118,26 +117,26 @@ class BackupRestoreService : Service() {
         val uri = intent?.getParcelableExtra<Uri>(BackupConst.EXTRA_URI) ?: return START_NOT_STICKY
 
         // Cancel any previous job if needed.
-        backupRestore?.job?.cancel()
+        restorer?.job?.cancel()
 
-        backupRestore = FullBackupRestore(this, notifier)
+        restorer = BackupRestorer(this, notifier)
 
         val handler = CoroutineExceptionHandler { _, exception ->
             logcat(LogPriority.ERROR, exception)
-            backupRestore?.writeErrorLog()
+            restorer?.writeErrorLog()
 
             notifier.showRestoreError(exception.message)
             stopSelf(startId)
         }
         val job = ioScope.launch(handler) {
-            if (backupRestore?.restoreBackup(uri) == false) {
+            if (restorer?.restoreBackup(uri) == false) {
                 notifier.showRestoreError(getString(R.string.restoring_backup_canceled))
             }
         }
         job.invokeOnCompletion {
             stopSelf(startId)
         }
-        backupRestore?.job = job
+        restorer?.job = job
 
         return START_NOT_STICKY
     }

+ 32 - 65
app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestore.kt → app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt

@@ -1,15 +1,13 @@
-package eu.kanade.tachiyomi.data.backup.full
+package eu.kanade.tachiyomi.data.backup
 
 import android.content.Context
 import android.net.Uri
 import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.backup.AbstractBackupRestore
-import eu.kanade.tachiyomi.data.backup.BackupNotifier
-import eu.kanade.tachiyomi.data.backup.full.models.BackupCategory
-import eu.kanade.tachiyomi.data.backup.full.models.BackupHistory
-import eu.kanade.tachiyomi.data.backup.full.models.BackupManga
-import eu.kanade.tachiyomi.data.backup.full.models.BackupSerializer
-import eu.kanade.tachiyomi.data.backup.full.models.BackupSource
+import eu.kanade.tachiyomi.data.backup.models.BackupCategory
+import eu.kanade.tachiyomi.data.backup.models.BackupHistory
+import eu.kanade.tachiyomi.data.backup.models.BackupManga
+import eu.kanade.tachiyomi.data.backup.models.BackupSerializer
+import eu.kanade.tachiyomi.data.backup.models.BackupSource
 import eu.kanade.tachiyomi.data.database.models.Chapter
 import eu.kanade.tachiyomi.data.database.models.Manga
 import eu.kanade.tachiyomi.data.database.models.Track
@@ -18,12 +16,12 @@ import okio.gzip
 import okio.source
 import java.util.Date
 
-class FullBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBackupRestore<FullBackupManager>(context, notifier) {
+class BackupRestorer(context: Context, notifier: BackupNotifier) : AbstractBackupRestore<BackupManager>(context, notifier) {
 
+    @Suppress("BlockingMethodInNonBlockingContext")
     override suspend fun performRestore(uri: Uri): Boolean {
-        backupManager = FullBackupManager(context)
+        backupManager = BackupManager(context)
 
-        @Suppress("BlockingMethodInNonBlockingContext")
         val backupString = context.contentResolver.openInputStream(uri)!!.source().gzip().buffer().use { it.readByteArray() }
         val backup = backupManager.parser.decodeFromByteArray(BackupSerializer, backupString)
 
@@ -68,7 +66,17 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBa
         val tracks = backupManga.getTrackingImpl()
 
         try {
-            restoreMangaData(manga, chapters, categories, history, tracks, backupCategories)
+            val dbManga = backupManager.getMangaFromDatabase(manga.url, manga.source)
+            if (dbManga == null) {
+                // Manga not in database
+                restoreExistingManga(manga, chapters, categories, history, tracks, backupCategories)
+            } else {
+                // Manga in database
+                // Copy information from manga already in database
+                backupManager.restoreExistingManga(manga, dbManga)
+                // Fetch rest of manga information
+                restoreNewManga(manga, chapters, categories, history, tracks, backupCategories)
+            }
         } catch (e: Exception) {
             val sourceName = sourceMapping[manga.source] ?: manga.source.toString()
             errors.add(Date() to "${manga.title} [$sourceName]: ${e.message}")
@@ -78,36 +86,6 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBa
         showRestoreProgress(restoreProgress, restoreAmount, manga.title)
     }
 
-    /**
-     * Returns a manga restore observable
-     *
-     * @param manga manga data from json
-     * @param chapters chapters data from json
-     * @param categories categories data from json
-     * @param history history data from json
-     * @param tracks tracking data from json
-     */
-    private suspend fun restoreMangaData(
-        manga: Manga,
-        chapters: List<Chapter>,
-        categories: List<Int>,
-        history: List<BackupHistory>,
-        tracks: List<Track>,
-        backupCategories: List<BackupCategory>,
-    ) {
-        val dbManga = backupManager.getMangaFromDatabase(manga.url, manga.source)
-        if (dbManga == null) {
-            // Manga not in database
-            restoreMangaFetch(manga, chapters, categories, history, tracks, backupCategories)
-        } else {
-            // Manga in database
-            // Copy information from manga already in database
-            backupManager.restoreMangaNoFetch(manga, dbManga)
-            // Fetch rest of manga information
-            restoreMangaNoFetch(manga, chapters, categories, history, tracks, backupCategories)
-        }
-    }
-
     /**
      * Fetches manga information
      *
@@ -115,7 +93,7 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBa
      * @param chapters chapters of manga that needs updating
      * @param categories categories that need updating
      */
-    private suspend fun restoreMangaFetch(
+    private suspend fun restoreExistingManga(
         manga: Manga,
         chapters: List<Chapter>,
         categories: List<Int>,
@@ -123,19 +101,14 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBa
         tracks: List<Track>,
         backupCategories: List<BackupCategory>,
     ) {
-        try {
-            val fetchedManga = backupManager.restoreManga(manga)
-            fetchedManga.id ?: return
-
-            backupManager.restoreChaptersForManga(fetchedManga, chapters)
+        val fetchedManga = backupManager.restoreNewManga(manga)
+        fetchedManga.id ?: return
 
-            restoreExtraForManga(fetchedManga, categories, history, tracks, backupCategories)
-        } catch (e: Exception) {
-            errors.add(Date() to "${manga.title} - ${e.message}")
-        }
+        backupManager.restoreChapters(fetchedManga, chapters)
+        restoreExtras(fetchedManga, categories, history, tracks, backupCategories)
     }
 
-    private suspend fun restoreMangaNoFetch(
+    private suspend fun restoreNewManga(
         backupManga: Manga,
         chapters: List<Chapter>,
         categories: List<Int>,
@@ -143,19 +116,13 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBa
         tracks: List<Track>,
         backupCategories: List<BackupCategory>,
     ) {
-        backupManager.restoreChaptersForManga(backupManga, chapters)
-
-        restoreExtraForManga(backupManga, categories, history, tracks, backupCategories)
+        backupManager.restoreChapters(backupManga, chapters)
+        restoreExtras(backupManga, categories, history, tracks, backupCategories)
     }
 
-    private suspend fun restoreExtraForManga(manga: Manga, categories: List<Int>, history: List<BackupHistory>, tracks: List<Track>, backupCategories: List<BackupCategory>) {
-        // Restore categories
-        backupManager.restoreCategoriesForManga(manga, categories, backupCategories)
-
-        // Restore history
-        backupManager.restoreHistoryForManga(history)
-
-        // Restore tracking
-        backupManager.restoreTrackForManga(manga, tracks)
+    private suspend fun restoreExtras(manga: Manga, categories: List<Int>, history: List<BackupHistory>, tracks: List<Track>, backupCategories: List<BackupCategory>) {
+        backupManager.restoreCategories(manga, categories, backupCategories)
+        backupManager.restoreHistory(history)
+        backupManager.restoreTracking(manga, tracks)
     }
 }

+ 0 - 12
app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupFull.kt

@@ -1,12 +0,0 @@
-package eu.kanade.tachiyomi.data.backup.full.models
-
-import java.text.SimpleDateFormat
-import java.util.Date
-import java.util.Locale
-
-object BackupFull {
-    fun getDefaultFilename(): String {
-        val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.getDefault()).format(Date())
-        return "tachiyomi_$date.proto.gz"
-    }
-}

+ 13 - 2
app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/Backup.kt → app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt

@@ -1,7 +1,10 @@
-package eu.kanade.tachiyomi.data.backup.full.models
+package eu.kanade.tachiyomi.data.backup.models
 
 import kotlinx.serialization.Serializable
 import kotlinx.serialization.protobuf.ProtoNumber
+import java.text.SimpleDateFormat
+import java.util.Date
+import java.util.Locale
 
 @Serializable
 data class Backup(
@@ -10,4 +13,12 @@ data class Backup(
     // Bump by 100 to specify this is a 0.x value
     @ProtoNumber(100) var backupBrokenSources: List<BrokenBackupSource> = emptyList(),
     @ProtoNumber(101) var backupSources: List<BackupSource> = emptyList(),
-)
+) {
+
+    companion object {
+        fun getBackupFilename(): String {
+            val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.getDefault()).format(Date())
+            return "tachiyomi_$date.proto.gz"
+        }
+    }
+}

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupCategory.kt → app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt

@@ -1,4 +1,4 @@
-package eu.kanade.tachiyomi.data.backup.full.models
+package eu.kanade.tachiyomi.data.backup.models
 
 import eu.kanade.domain.category.model.Category
 import kotlinx.serialization.Serializable

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupChapter.kt → app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupChapter.kt

@@ -1,4 +1,4 @@
-package eu.kanade.tachiyomi.data.backup.full.models
+package eu.kanade.tachiyomi.data.backup.models
 
 import eu.kanade.tachiyomi.data.database.models.ChapterImpl
 import kotlinx.serialization.Serializable

+ 9 - 8
app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupHistory.kt → app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupHistory.kt

@@ -1,18 +1,19 @@
-package eu.kanade.tachiyomi.data.backup.full.models
+package eu.kanade.tachiyomi.data.backup.models
 
 import kotlinx.serialization.Serializable
 import kotlinx.serialization.protobuf.ProtoNumber
 
-@Serializable
-data class BrokenBackupHistory(
-    @ProtoNumber(0) var url: String,
-    @ProtoNumber(1) var lastRead: Long,
-    @ProtoNumber(2) var readDuration: Long = 0,
-)
-
 @Serializable
 data class BackupHistory(
     @ProtoNumber(1) var url: String,
     @ProtoNumber(2) var lastRead: Long,
     @ProtoNumber(3) var readDuration: Long = 0,
 )
+
+@Deprecated("Replaced with BackupHistory. This is retained for legacy reasons.")
+@Serializable
+data class BrokenBackupHistory(
+    @ProtoNumber(0) var url: String,
+    @ProtoNumber(1) var lastRead: Long,
+    @ProtoNumber(2) var readDuration: Long = 0,
+)

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupManga.kt → app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt

@@ -1,4 +1,4 @@
-package eu.kanade.tachiyomi.data.backup.full.models
+package eu.kanade.tachiyomi.data.backup.models
 
 import eu.kanade.domain.manga.model.Manga
 import eu.kanade.tachiyomi.data.database.models.ChapterImpl
@@ -8,6 +8,7 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
 import kotlinx.serialization.Serializable
 import kotlinx.serialization.protobuf.ProtoNumber
 
+@Suppress("DEPRECATION")
 @Serializable
 data class BackupManga(
     // in 1.x some of these values have different names

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupSerializer.kt → app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupSerializer.kt

@@ -1,4 +1,4 @@
-package eu.kanade.tachiyomi.data.backup.full.models
+package eu.kanade.tachiyomi.data.backup.models
 
 import kotlinx.serialization.Serializer
 

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupSource.kt → app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupSource.kt

@@ -1,4 +1,4 @@
-package eu.kanade.tachiyomi.data.backup.full.models
+package eu.kanade.tachiyomi.data.backup.models
 
 import eu.kanade.tachiyomi.source.Source
 import kotlinx.serialization.Serializable

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupTracking.kt → app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupTracking.kt

@@ -1,4 +1,4 @@
-package eu.kanade.tachiyomi.data.backup.full.models
+package eu.kanade.tachiyomi.data.backup.models
 
 import eu.kanade.tachiyomi.data.database.models.TrackImpl
 import kotlinx.serialization.Serializable

+ 4 - 5
app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt

@@ -21,9 +21,9 @@ import com.hippo.unifile.UniFile
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.backup.BackupConst
 import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
+import eu.kanade.tachiyomi.data.backup.BackupFileValidator
 import eu.kanade.tachiyomi.data.backup.BackupRestoreService
-import eu.kanade.tachiyomi.data.backup.full.FullBackupRestoreValidator
-import eu.kanade.tachiyomi.data.backup.full.models.BackupFull
+import eu.kanade.tachiyomi.data.backup.models.Backup
 import eu.kanade.tachiyomi.ui.base.controller.DialogController
 import eu.kanade.tachiyomi.ui.base.controller.requestPermissionsSafe
 import eu.kanade.tachiyomi.util.preference.bindTo
@@ -206,11 +206,10 @@ class SettingsBackupController : SettingsController() {
     fun createBackup(flags: Int) {
         backupFlags = flags
         try {
-            // Use Android's built-in file creator
             val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
                 .addCategory(Intent.CATEGORY_OPENABLE)
                 .setType("application/*")
-                .putExtra(Intent.EXTRA_TITLE, BackupFull.getDefaultFilename())
+                .putExtra(Intent.EXTRA_TITLE, Backup.getBackupFilename())
 
             startActivityForResult(intent, CODE_BACKUP_CREATE)
         } catch (e: ActivityNotFoundException) {
@@ -270,7 +269,7 @@ class SettingsBackupController : SettingsController() {
             val uri: Uri = args.getParcelable(KEY_URI)!!
 
             return try {
-                val results = FullBackupRestoreValidator().validate(activity, uri)
+                val results = BackupFileValidator().validate(activity, uri)
 
                 var message = activity.getString(R.string.backup_restore_content_full)
                 if (results.missingSources.isNotEmpty()) {