diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c3b8b5a63..2338e8f8b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -291,14 +291,15 @@ tasks { // See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api(-markers) withType { 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", ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestoreValidator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestoreValidator.kt deleted file mode 100644 index b8d8f65dc..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestoreValidator.kt +++ /dev/null @@ -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, val missingTrackers: List) -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt index 8d6f395aa..cfb707c11 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt +++ b/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) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestoreValidator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt similarity index 78% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestoreValidator.kt rename to app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt index 52b4cd2fc..af1f2cebd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestoreValidator.kt +++ b/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, val missingTrackers: List) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt similarity index 90% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt rename to app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt index d629c82e9..71b742603 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt +++ b/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, flags: Int): List { - return mangas.map { - backupMangaObject(it, flags) - } - } - private fun backupExtensionInfo(mangas: List): List { return mangas .asSequence() @@ -148,6 +141,12 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) { } } + private suspend fun backupMangas(mangas: List, flags: Int): List { + 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, backupCategories: List) { + internal suspend fun restoreCategories(manga: Manga, categories: List, backupCategories: List) { val dbCategories = handler.awaitList { categoriesQueries.getCategories() } val mangaCategoriesToUpdate = mutableListOf>() @@ -299,7 +298,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) { * * @param history list containing history to be restored */ - internal suspend fun restoreHistoryForManga(history: List) { + internal suspend fun restoreHistory(history: List) { // List containing history to be updated val toUpdate = mutableListOf() 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) { + internal suspend fun restoreTracking(manga: Manga, tracks: List) { // 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) { + internal suspend fun restoreChapters(manga: Manga, chapters: List) { val dbChapters = handler.awaitList { chaptersQueries.getChaptersByMangaId(manga.id!!) } chapters.forEach { chapter -> diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt index 037efc6a9..d652c4f58 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt +++ b/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(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 } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestore.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt similarity index 51% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestore.kt rename to app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt index 978102f74..42e181984 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestore.kt +++ b/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(context, notifier) { +class BackupRestorer(context: Context, notifier: BackupNotifier) : AbstractBackupRestore(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, - categories: List, - history: List, - tracks: List, - backupCategories: List, - ) { - 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, categories: List, @@ -123,19 +101,14 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBa tracks: List, backupCategories: List, ) { - try { - val fetchedManga = backupManager.restoreManga(manga) - fetchedManga.id ?: return + val fetchedManga = backupManager.restoreNewManga(manga) + fetchedManga.id ?: return - backupManager.restoreChaptersForManga(fetchedManga, chapters) - - 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, categories: List, @@ -143,19 +116,13 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBa tracks: List, backupCategories: List, ) { - 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, history: List, tracks: List, backupCategories: List) { - // 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, history: List, tracks: List, backupCategories: List) { + backupManager.restoreCategories(manga, categories, backupCategories) + backupManager.restoreHistory(history) + backupManager.restoreTracking(manga, tracks) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupFull.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupFull.kt deleted file mode 100644 index 3ed6328b0..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupFull.kt +++ /dev/null @@ -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" - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/Backup.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt similarity index 56% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/Backup.kt rename to app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt index bc1d333d1..8a9de244d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/Backup.kt +++ b/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 = emptyList(), @ProtoNumber(101) var backupSources: List = emptyList(), -) +) { + + companion object { + fun getBackupFilename(): String { + val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.getDefault()).format(Date()) + return "tachiyomi_$date.proto.gz" + } + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupCategory.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt similarity index 94% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupCategory.kt rename to app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt index dde26daaa..d58a85ce9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupCategory.kt +++ b/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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupChapter.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupChapter.kt similarity index 97% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupChapter.kt rename to app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupChapter.kt index 9ecb7fd1f..917014080 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupChapter.kt +++ b/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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupHistory.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupHistory.kt similarity index 77% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupHistory.kt rename to app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupHistory.kt index a2b66cced..8b47f0d8d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupHistory.kt +++ b/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, +) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupManga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt similarity index 98% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupManga.kt rename to app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt index 3569d534a..0edfd6d7f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupManga.kt +++ b/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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupSerializer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupSerializer.kt similarity index 66% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupSerializer.kt rename to app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupSerializer.kt index 55b1c6afc..2e79ebecd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupSerializer.kt +++ b/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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupSource.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupSource.kt similarity index 92% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupSource.kt rename to app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupSource.kt index 8c823f71c..7bf2d0bc3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupSource.kt +++ b/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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupTracking.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupTracking.kt similarity index 98% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupTracking.kt rename to app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupTracking.kt index 0c38fefbf..80c7d28a5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupTracking.kt +++ b/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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt index 5ce5ad4e9..4a5d1fa6b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt +++ b/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()) {