mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 06:17:57 +01:00 
			
		
		
		
	Consider individual manga as transactions rather than entire restore job (closes #2482)
This commit is contained in:
		| @@ -10,6 +10,7 @@ import android.os.PowerManager | ||||
| import com.github.salomonbrys.kotson.fromJson | ||||
| import com.google.gson.JsonArray | ||||
| import com.google.gson.JsonElement | ||||
| import com.google.gson.JsonObject | ||||
| import com.google.gson.JsonParser | ||||
| import com.google.gson.stream.JsonReader | ||||
| import eu.kanade.tachiyomi.R | ||||
| @@ -32,18 +33,17 @@ import eu.kanade.tachiyomi.data.notification.Notifications | ||||
| import eu.kanade.tachiyomi.data.track.TrackManager | ||||
| import eu.kanade.tachiyomi.source.Source | ||||
| import eu.kanade.tachiyomi.ui.setting.backup.BackupNotifier | ||||
| import eu.kanade.tachiyomi.util.lang.chop | ||||
| import eu.kanade.tachiyomi.util.system.isServiceRunning | ||||
| import eu.kanade.tachiyomi.util.system.sendLocalBroadcast | ||||
| import java.io.File | ||||
| import java.text.SimpleDateFormat | ||||
| import java.util.Date | ||||
| import java.util.Locale | ||||
| import java.util.concurrent.ExecutorService | ||||
| import java.util.concurrent.Executors | ||||
| import kotlinx.coroutines.CoroutineExceptionHandler | ||||
| import kotlinx.coroutines.GlobalScope | ||||
| import kotlinx.coroutines.Job | ||||
| import kotlinx.coroutines.launch | ||||
| import rx.Observable | ||||
| import rx.Subscription | ||||
| import rx.schedulers.Schedulers | ||||
| import timber.log.Timber | ||||
| import uy.kohesive.injekt.injectLazy | ||||
|  | ||||
| @@ -60,7 +60,7 @@ class BackupRestoreService : Service() { | ||||
|          * @param context the application context. | ||||
|          * @return true if the service is running, false otherwise. | ||||
|          */ | ||||
|         private fun isRunning(context: Context): Boolean = | ||||
|         fun isRunning(context: Context): Boolean = | ||||
|             context.isServiceRunning(BackupRestoreService::class.java) | ||||
|  | ||||
|         /** | ||||
| @@ -103,10 +103,7 @@ class BackupRestoreService : Service() { | ||||
|      */ | ||||
|     private lateinit var wakeLock: PowerManager.WakeLock | ||||
|  | ||||
|     /** | ||||
|      * Subscription where the update is done. | ||||
|      */ | ||||
|     private var subscription: Subscription? = null | ||||
|     private var job: Job? = null | ||||
|  | ||||
|     /** | ||||
|      * The progress of a backup restore | ||||
| @@ -131,15 +128,12 @@ class BackupRestoreService : Service() { | ||||
|  | ||||
|     private lateinit var notifier: BackupNotifier | ||||
|  | ||||
|     private lateinit var executor: ExecutorService | ||||
|  | ||||
|     /** | ||||
|      * Method called when the service is created. It injects dependencies and acquire the wake lock. | ||||
|      */ | ||||
|     override fun onCreate() { | ||||
|         super.onCreate() | ||||
|         notifier = BackupNotifier(this) | ||||
|         executor = Executors.newSingleThreadExecutor() | ||||
|  | ||||
|         startForeground(Notifications.ID_RESTORE, notifier.showRestoreProgress().build()) | ||||
|  | ||||
| @@ -149,17 +143,21 @@ class BackupRestoreService : Service() { | ||||
|         wakeLock.acquire() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method called when the service is destroyed. It destroys the running subscription and | ||||
|      * releases the wake lock. | ||||
|      */ | ||||
|     override fun stopService(name: Intent?): Boolean { | ||||
|         destroyJob() | ||||
|         return super.stopService(name) | ||||
|     } | ||||
|  | ||||
|     override fun onDestroy() { | ||||
|         subscription?.unsubscribe() | ||||
|         executor.shutdown() // must be called after unsubscribe | ||||
|         destroyJob() | ||||
|         super.onDestroy() | ||||
|     } | ||||
|  | ||||
|     private fun destroyJob() { | ||||
|         job?.cancel() | ||||
|         if (wakeLock.isHeld) { | ||||
|             wakeLock.release() | ||||
|         } | ||||
|         super.onDestroy() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -176,146 +174,119 @@ class BackupRestoreService : Service() { | ||||
|      * @return the start value of the command. | ||||
|      */ | ||||
|     override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { | ||||
|         if (intent == null) return START_NOT_STICKY | ||||
|         val uri = intent?.getParcelableExtra<Uri>(BackupConst.EXTRA_URI) ?: return START_NOT_STICKY | ||||
|  | ||||
|         val uri = intent.getParcelableExtra<Uri>(BackupConst.EXTRA_URI) | ||||
|         // Cancel any previous job if needed. | ||||
|         job?.cancel() | ||||
|         val handler = CoroutineExceptionHandler { _, exception -> | ||||
|             Timber.e(exception) | ||||
|             writeErrorLog() | ||||
|  | ||||
|         // Unsubscribe from any previous subscription if needed. | ||||
|         subscription?.unsubscribe() | ||||
|             val errorIntent = Intent(BackupConst.INTENT_FILTER).apply { | ||||
|                 putExtra(BackupConst.ACTION, BackupConst.ACTION_RESTORE_ERROR) | ||||
|                 putExtra(BackupConst.EXTRA_ERROR_MESSAGE, exception.message) | ||||
|             } | ||||
|             sendLocalBroadcast(errorIntent) | ||||
|  | ||||
|         subscription = Observable.using( | ||||
|             { db.lowLevel().beginTransaction() }, | ||||
|             { getRestoreObservable(uri).doOnNext { db.lowLevel().setTransactionSuccessful() } }, | ||||
|             { executor.execute { db.lowLevel().endTransaction() } } | ||||
|         ) | ||||
|             .doAfterTerminate { stopSelf(startId) } | ||||
|             .subscribeOn(Schedulers.from(executor)) | ||||
|             .subscribe() | ||||
|             stopSelf(startId) | ||||
|         } | ||||
|         job = GlobalScope.launch(handler) { | ||||
|             restoreBackup(uri) | ||||
|         } | ||||
|         job?.invokeOnCompletion { | ||||
|             stopSelf(startId) | ||||
|         } | ||||
|  | ||||
|         return START_NOT_STICKY | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns an [Observable] containing restore process. | ||||
|      * Restores data from backup file. | ||||
|      * | ||||
|      * @param uri restore file | ||||
|      * @return [Observable<Manga>] | ||||
|      * @param uri backup file to restore | ||||
|      */ | ||||
|     private fun getRestoreObservable(uri: Uri): Observable<List<Manga>> { | ||||
|     private fun restoreBackup(uri: Uri) { | ||||
|         val startTime = System.currentTimeMillis() | ||||
|  | ||||
|         return Observable.just(Unit) | ||||
|             .map { | ||||
|                 val reader = JsonReader(contentResolver.openInputStream(uri)!!.bufferedReader()) | ||||
|                 val json = JsonParser.parseReader(reader).asJsonObject | ||||
|         val reader = JsonReader(contentResolver.openInputStream(uri)!!.bufferedReader()) | ||||
|         val json = JsonParser.parseReader(reader).asJsonObject | ||||
|  | ||||
|                 // Get parser version | ||||
|                 val version = json.get(VERSION)?.asInt ?: 1 | ||||
|         // Get parser version | ||||
|         val version = json.get(VERSION)?.asInt ?: 1 | ||||
|  | ||||
|                 // Initialize manager | ||||
|                 backupManager = BackupManager(this, version) | ||||
|         // Initialize manager | ||||
|         backupManager = BackupManager(this, version) | ||||
|  | ||||
|                 val mangasJson = json.get(MANGAS).asJsonArray | ||||
|         val mangasJson = json.get(MANGAS).asJsonArray | ||||
|  | ||||
|                 restoreAmount = mangasJson.size() + 1 // +1 for categories | ||||
|                 restoreProgress = 0 | ||||
|                 errors.clear() | ||||
|         restoreAmount = mangasJson.size() + 1 // +1 for categories | ||||
|         restoreProgress = 0 | ||||
|         errors.clear() | ||||
|  | ||||
|                 // Restore categories | ||||
|                 restoreCategories(json.get(CATEGORIES)) | ||||
|         // Restore categories | ||||
|         restoreCategories(json.get(CATEGORIES)) | ||||
|  | ||||
|                 mangasJson | ||||
|             } | ||||
|             .flatMap { Observable.from(it) } | ||||
|             .concatMap { | ||||
|                 restoreManga(it) | ||||
|             } | ||||
|             .toList() | ||||
|             .doOnNext { | ||||
|                 val endTime = System.currentTimeMillis() | ||||
|                 val time = endTime - startTime | ||||
|                 val logFile = writeErrorLog() | ||||
|                 val completeIntent = Intent(BackupConst.INTENT_FILTER).apply { | ||||
|                     putExtra(BackupConst.EXTRA_TIME, time) | ||||
|                     putExtra(BackupConst.EXTRA_ERRORS, errors.size) | ||||
|                     putExtra(BackupConst.EXTRA_ERROR_FILE_PATH, logFile.parent) | ||||
|                     putExtra(BackupConst.EXTRA_ERROR_FILE, logFile.name) | ||||
|                     putExtra(BackupConst.ACTION, BackupConst.ACTION_RESTORE_COMPLETED) | ||||
|                 } | ||||
|                 sendLocalBroadcast(completeIntent) | ||||
|             } | ||||
|             .doOnError { error -> | ||||
|                 Timber.e(error) | ||||
|                 writeErrorLog() | ||||
|                 val errorIntent = Intent(BackupConst.INTENT_FILTER).apply { | ||||
|                     putExtra(BackupConst.ACTION, BackupConst.ACTION_RESTORE_ERROR) | ||||
|                     putExtra(BackupConst.EXTRA_ERROR_MESSAGE, error.message) | ||||
|                 } | ||||
|                 sendLocalBroadcast(errorIntent) | ||||
|             } | ||||
|             .onErrorReturn { emptyList() } | ||||
|         // Restore individual manga | ||||
|         mangasJson.forEach { | ||||
|             restoreManga(it.asJsonObject) | ||||
|         } | ||||
|  | ||||
|         val endTime = System.currentTimeMillis() | ||||
|         val time = endTime - startTime | ||||
|  | ||||
|         val logFile = writeErrorLog() | ||||
|         val completeIntent = Intent(BackupConst.INTENT_FILTER).apply { | ||||
|             putExtra(BackupConst.EXTRA_TIME, time) | ||||
|             putExtra(BackupConst.EXTRA_ERRORS, errors.size) | ||||
|             putExtra(BackupConst.EXTRA_ERROR_FILE_PATH, logFile.parent) | ||||
|             putExtra(BackupConst.EXTRA_ERROR_FILE, logFile.name) | ||||
|             putExtra(BackupConst.ACTION, BackupConst.ACTION_RESTORE_COMPLETED) | ||||
|         } | ||||
|         sendLocalBroadcast(completeIntent) | ||||
|     } | ||||
|  | ||||
|     private fun restoreCategories(categoriesJson: JsonElement) { | ||||
|         backupManager.restoreCategories(categoriesJson.asJsonArray) | ||||
|         restoreProgress += 1 | ||||
|         showRestoreProgress(restoreProgress, restoreAmount, getString(R.string.categories)) | ||||
|     } | ||||
|         db.executeTransaction { | ||||
|             backupManager.restoreCategories(categoriesJson.asJsonArray) | ||||
|  | ||||
|     private fun restoreManga(mangaJson: JsonElement): Observable<out Manga>? { | ||||
|         val obj = mangaJson.asJsonObject | ||||
|  | ||||
|         val manga = backupManager.parser.fromJson<MangaImpl>(obj.get(MANGA)) | ||||
|         val chapters = backupManager.parser.fromJson<List<ChapterImpl>>( | ||||
|             obj.get(CHAPTERS) | ||||
|                 ?: JsonArray() | ||||
|         ) | ||||
|         val categories = backupManager.parser.fromJson<List<String>>( | ||||
|             obj.get(CATEGORIES) | ||||
|                 ?: JsonArray() | ||||
|         ) | ||||
|         val history = backupManager.parser.fromJson<List<DHistory>>( | ||||
|             obj.get(HISTORY) | ||||
|                 ?: JsonArray() | ||||
|         ) | ||||
|         val tracks = backupManager.parser.fromJson<List<TrackImpl>>( | ||||
|             obj.get(TRACK) | ||||
|                 ?: JsonArray() | ||||
|         ) | ||||
|  | ||||
|         val observable = getMangaRestoreObservable(manga, chapters, categories, history, tracks) | ||||
|         return if (observable != null) { | ||||
|             observable | ||||
|         } else { | ||||
|             errors.add(Date() to "${manga.title} - ${getString(R.string.source_not_found)}") | ||||
|             restoreProgress += 1 | ||||
|             val content = | ||||
|                 getString(R.string.dialog_restoring_source_not_found, manga.title.chop(15)) | ||||
|             showRestoreProgress(restoreProgress, restoreAmount, manga.title, content) | ||||
|             Observable.just(manga) | ||||
|             showRestoreProgress(restoreProgress, restoreAmount, getString(R.string.categories)) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Write errors to error log | ||||
|      */ | ||||
|     private fun writeErrorLog(): File { | ||||
|         try { | ||||
|             if (errors.isNotEmpty()) { | ||||
|                 val destFile = File(externalCacheDir, "tachiyomi_restore.txt") | ||||
|                 val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault()) | ||||
|     private fun restoreManga(mangaJson: JsonObject) { | ||||
|         db.executeTransaction { | ||||
|             val manga = backupManager.parser.fromJson<MangaImpl>(mangaJson.get(MANGA)) | ||||
|             val chapters = backupManager.parser.fromJson<List<ChapterImpl>>( | ||||
|                 mangaJson.get(CHAPTERS) | ||||
|                     ?: JsonArray() | ||||
|             ) | ||||
|             val categories = backupManager.parser.fromJson<List<String>>( | ||||
|                 mangaJson.get(CATEGORIES) | ||||
|                     ?: JsonArray() | ||||
|             ) | ||||
|             val history = backupManager.parser.fromJson<List<DHistory>>( | ||||
|                 mangaJson.get(HISTORY) | ||||
|                     ?: JsonArray() | ||||
|             ) | ||||
|             val tracks = backupManager.parser.fromJson<List<TrackImpl>>( | ||||
|                 mangaJson.get(TRACK) | ||||
|                     ?: JsonArray() | ||||
|             ) | ||||
|  | ||||
|                 destFile.bufferedWriter().use { out -> | ||||
|                     errors.forEach { (date, message) -> | ||||
|                         out.write("[${sdf.format(date)}] $message\n") | ||||
|                     } | ||||
|                 } | ||||
|                 return destFile | ||||
|             if (job?.isActive != true) { | ||||
|                 throw Exception(getString(R.string.restoring_backup_canceled)) | ||||
|             } | ||||
|         } catch (e: Exception) { | ||||
|             // Empty | ||||
|  | ||||
|             try { | ||||
|                 restoreMangaData(manga, chapters, categories, history, tracks) | ||||
|             } catch (e: Exception) { | ||||
|                 errors.add(Date() to "${manga.title} - ${getString(R.string.source_not_found)}") | ||||
|             } | ||||
|  | ||||
|             restoreProgress += 1 | ||||
|             showRestoreProgress(restoreProgress, restoreAmount, manga.title) | ||||
|         } | ||||
|         return File("") | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -326,27 +297,26 @@ class BackupRestoreService : Service() { | ||||
|      * @param categories categories data from json | ||||
|      * @param history history data from json | ||||
|      * @param tracks tracking data from json | ||||
|      * @return [Observable] containing manga restore information | ||||
|      */ | ||||
|     private fun getMangaRestoreObservable( | ||||
|     private fun restoreMangaData( | ||||
|         manga: Manga, | ||||
|         chapters: List<Chapter>, | ||||
|         categories: List<String>, | ||||
|         history: List<DHistory>, | ||||
|         tracks: List<Track> | ||||
|     ): Observable<Manga>? { | ||||
|     ) { | ||||
|         // Get source | ||||
|         val source = backupManager.sourceManager.getOrStub(manga.source) | ||||
|         val dbManga = backupManager.getMangaFromDatabase(manga) | ||||
|  | ||||
|         return if (dbManga == null) { | ||||
|         if (dbManga == null) { | ||||
|             // Manga not in database | ||||
|             mangaFetchObservable(source, manga, chapters, categories, history, tracks) | ||||
|             restoreMangaFetch(source, manga, chapters, categories, history, tracks) | ||||
|         } else { // Manga in database | ||||
|             // Copy information from manga already in database | ||||
|             backupManager.restoreMangaNoFetch(manga, dbManga) | ||||
|             // Fetch rest of manga information | ||||
|             mangaNoFetchObservable(source, manga, chapters, categories, history, tracks) | ||||
|             restoreMangaNoFetch(source, manga, chapters, categories, history, tracks) | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -357,15 +327,15 @@ class BackupRestoreService : Service() { | ||||
|      * @param chapters chapters of manga that needs updating | ||||
|      * @param categories categories that need updating | ||||
|      */ | ||||
|     private fun mangaFetchObservable( | ||||
|     private fun restoreMangaFetch( | ||||
|         source: Source, | ||||
|         manga: Manga, | ||||
|         chapters: List<Chapter>, | ||||
|         categories: List<String>, | ||||
|         history: List<DHistory>, | ||||
|         tracks: List<Track> | ||||
|     ): Observable<Manga> { | ||||
|         return backupManager.restoreMangaFetchObservable(source, manga) | ||||
|     ) { | ||||
|         backupManager.restoreMangaFetchObservable(source, manga) | ||||
|             .onErrorReturn { | ||||
|                 errors.add(Date() to "${manga.title} - ${it.message}") | ||||
|                 manga | ||||
| @@ -381,24 +351,19 @@ class BackupRestoreService : Service() { | ||||
|             } | ||||
|             .flatMap { | ||||
|                 trackingFetchObservable(it, tracks) | ||||
|                     // Convert to the manga that contains new chapters. | ||||
|                     .map { manga } | ||||
|             } | ||||
|             .doOnCompleted { | ||||
|                 restoreProgress += 1 | ||||
|                 showRestoreProgress(restoreProgress, restoreAmount, manga.title) | ||||
|             } | ||||
|             .subscribe() | ||||
|     } | ||||
|  | ||||
|     private fun mangaNoFetchObservable( | ||||
|     private fun restoreMangaNoFetch( | ||||
|         source: Source, | ||||
|         backupManga: Manga, | ||||
|         chapters: List<Chapter>, | ||||
|         categories: List<String>, | ||||
|         history: List<DHistory>, | ||||
|         tracks: List<Track> | ||||
|     ): Observable<Manga> { | ||||
|         return Observable.just(backupManga) | ||||
|     ) { | ||||
|         Observable.just(backupManga) | ||||
|             .flatMap { manga -> | ||||
|                 if (!backupManager.restoreChaptersForManga(manga, chapters)) { | ||||
|                     chapterFetchObservable(source, manga, chapters) | ||||
| @@ -412,13 +377,8 @@ class BackupRestoreService : Service() { | ||||
|             } | ||||
|             .flatMap { manga -> | ||||
|                 trackingFetchObservable(manga, tracks) | ||||
|                     // Convert to the manga that contains new chapters. | ||||
|                     .map { manga } | ||||
|             } | ||||
|             .doOnCompleted { | ||||
|                 restoreProgress += 1 | ||||
|                 showRestoreProgress(restoreProgress, restoreAmount, backupManga.title) | ||||
|             } | ||||
|             .subscribe() | ||||
|     } | ||||
|  | ||||
|     private fun restoreExtraForManga(manga: Manga, categories: List<String>, history: List<DHistory>, tracks: List<Track>) { | ||||
| @@ -482,9 +442,30 @@ class BackupRestoreService : Service() { | ||||
|     private fun showRestoreProgress( | ||||
|         progress: Int, | ||||
|         amount: Int, | ||||
|         title: String, | ||||
|         content: String = title.chop(30) | ||||
|         title: String | ||||
|     ) { | ||||
|         notifier.showRestoreProgress(content, progress, amount) | ||||
|         notifier.showRestoreProgress(title, progress, amount) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Write errors to error log | ||||
|      */ | ||||
|     private fun writeErrorLog(): File { | ||||
|         try { | ||||
|             if (errors.isNotEmpty()) { | ||||
|                 val destFile = File(externalCacheDir, "tachiyomi_restore.txt") | ||||
|                 val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault()) | ||||
|  | ||||
|                 destFile.bufferedWriter().use { out -> | ||||
|                     errors.forEach { (date, message) -> | ||||
|                         out.write("[${sdf.format(date)}] $message\n") | ||||
|                     } | ||||
|                 } | ||||
|                 return destFile | ||||
|             } | ||||
|         } catch (e: Exception) { | ||||
|             // Empty | ||||
|         } | ||||
|         return File("") | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -46,5 +46,12 @@ open class DatabaseHelper(context: Context) : | ||||
|  | ||||
|     inline fun inTransaction(block: () -> Unit) = db.inTransaction(block) | ||||
|  | ||||
|     fun lowLevel() = db.lowLevel() | ||||
|     fun executeTransaction(block: () -> Unit) { | ||||
|         db.lowLevel().beginTransaction() | ||||
|  | ||||
|         block() | ||||
|  | ||||
|         db.lowLevel().setTransactionSuccessful() | ||||
|         db.lowLevel().endTransaction() | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -88,7 +88,7 @@ class SettingsBackupController : SettingsController() { | ||||
|             summaryRes = R.string.pref_restore_backup_summ | ||||
|  | ||||
|             onClick { | ||||
|                 if (!isRestoreStarted) { | ||||
|                 if (!BackupRestoreService.isRunning(context)) { | ||||
|                     val intent = Intent(Intent.ACTION_GET_CONTENT) | ||||
|                     intent.addCategory(Intent.CATEGORY_OPENABLE) | ||||
|                     intent.type = "application/*" | ||||
| @@ -277,7 +277,6 @@ class SettingsBackupController : SettingsController() { | ||||
|                     val context = applicationContext | ||||
|                     if (context != null) { | ||||
|                         BackupRestoreService.start(context, args.getParcelable(KEY_URI)!!) | ||||
|                         isRestoreStarted = true | ||||
|                     } | ||||
|                 } | ||||
|         } | ||||
| @@ -303,8 +302,6 @@ class SettingsBackupController : SettingsController() { | ||||
|                     notifier.showBackupError(intent.getStringExtra(BackupConst.EXTRA_ERROR_MESSAGE)) | ||||
|                 } | ||||
|                 BackupConst.ACTION_RESTORE_COMPLETED -> { | ||||
|                     isRestoreStarted = false | ||||
|  | ||||
|                     val time = intent.getLongExtra(BackupConst.EXTRA_TIME, 0) | ||||
|                     val errorCount = intent.getIntExtra(BackupConst.EXTRA_ERRORS, 0) | ||||
|                     val path = intent.getStringExtra(BackupConst.EXTRA_ERROR_FILE_PATH) | ||||
| @@ -312,8 +309,6 @@ class SettingsBackupController : SettingsController() { | ||||
|                     notifier.showRestoreComplete(time, errorCount, path, file) | ||||
|                 } | ||||
|                 BackupConst.ACTION_RESTORE_ERROR -> { | ||||
|                     isRestoreStarted = false | ||||
|  | ||||
|                     notifier.showRestoreError(intent.getStringExtra(BackupConst.EXTRA_ERROR_MESSAGE)) | ||||
|                 } | ||||
|             } | ||||
| @@ -326,6 +321,5 @@ class SettingsBackupController : SettingsController() { | ||||
|         const val CODE_BACKUP_DIR = 503 | ||||
|  | ||||
|         var isBackupStarted = false | ||||
|         var isRestoreStarted = false | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -31,6 +31,7 @@ internal class BackupNotifier(private val context: Context) { | ||||
|             setContentText(context.getString(R.string.creating_backup)) | ||||
|  | ||||
|             setProgress(0, 0, true) | ||||
|             setOngoing(true) | ||||
|         } | ||||
|  | ||||
|         notificationBuilder.show(Notifications.ID_BACKUP) | ||||
| @@ -43,6 +44,7 @@ internal class BackupNotifier(private val context: Context) { | ||||
|  | ||||
|             // Remove progress bar | ||||
|             setProgress(0, 0, false) | ||||
|             setOngoing(false) | ||||
|         } | ||||
|  | ||||
|         notificationBuilder.show(Notifications.ID_BACKUP) | ||||
| @@ -58,6 +60,7 @@ internal class BackupNotifier(private val context: Context) { | ||||
|  | ||||
|             // Remove progress bar | ||||
|             setProgress(0, 0, false) | ||||
|             setOngoing(false) | ||||
|  | ||||
|             // Clear old actions if they exist | ||||
|             if (mActions.isNotEmpty()) { | ||||
| @@ -80,6 +83,7 @@ internal class BackupNotifier(private val context: Context) { | ||||
|             setContentText(content) | ||||
|  | ||||
|             setProgress(maxAmount, progress, false) | ||||
|             setOngoing(true) | ||||
|  | ||||
|             // Clear old actions if they exist | ||||
|             if (mActions.isNotEmpty()) { | ||||
| @@ -105,6 +109,7 @@ internal class BackupNotifier(private val context: Context) { | ||||
|  | ||||
|             // Remove progress bar | ||||
|             setProgress(0, 0, false) | ||||
|             setOngoing(false) | ||||
|         } | ||||
|  | ||||
|         notificationBuilder.show(Notifications.ID_RESTORE) | ||||
| @@ -128,6 +133,7 @@ internal class BackupNotifier(private val context: Context) { | ||||
|  | ||||
|             // Remove progress bar | ||||
|             setProgress(0, 0, false) | ||||
|             setOngoing(false) | ||||
|  | ||||
|             // Clear old actions if they exist | ||||
|             if (mActions.isNotEmpty()) { | ||||
|   | ||||
| @@ -316,7 +316,6 @@ | ||||
|     <string name="pref_backup_interval">Backup frequency</string> | ||||
|     <string name="pref_backup_slots">Max automatic backups</string> | ||||
|     <string name="source_not_found">Source not found</string> | ||||
|     <string name="dialog_restoring_source_not_found">Restoring backup\n%1$s source not found</string> | ||||
|     <string name="backup_created">Backup created</string> | ||||
|     <string name="restore_completed">Restore completed</string> | ||||
|     <string name="restore_duration">%02d min, %02d sec</string> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user