From fc4e290c49367a9ebd43bdb713788faa16ded265 Mon Sep 17 00:00:00 2001 From: Eugene Cheung Date: Wed, 13 May 2020 22:28:15 -0400 Subject: [PATCH] Show notification with error log on update failures --- .../data/library/LibraryUpdateNotifier.kt | 34 +++++++++++++++++ .../data/library/LibraryUpdateService.kt | 37 ++++++++++++++++--- .../data/notification/Notifications.kt | 1 + app/src/main/res/values/strings.xml | 4 ++ 4 files changed, 71 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt index adcceeb06..0722165ee 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt @@ -6,6 +6,7 @@ import android.content.Context import android.content.Intent import android.graphics.Bitmap import android.graphics.BitmapFactory +import android.net.Uri import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import com.bumptech.glide.Glide @@ -80,6 +81,39 @@ class LibraryUpdateNotifier(private val context: Context) { ) } + /** + * Shows notification containing update entries that failed with action to open full log. + * + * @param errors List of entry titles that failed to update. + * @param uri Uri for error log file containing all titles that failed. + */ + fun showUpdateErrorNotification(errors: List, uri: Uri) { + if (errors.isEmpty()) { + return + } + + context.notificationManager.notify( + Notifications.ID_LIBRARY_ERROR, + context.notificationBuilder(Notifications.CHANNEL_LIBRARY) { + setContentTitle(context.resources.getQuantityString(R.plurals.notification_update_error, errors.size, errors.size)) + setStyle( + NotificationCompat.BigTextStyle().bigText( + errors.joinToString("\n") { + it.chop(NOTIF_TITLE_MAX_LEN) + } + ) + ) + setSmallIcon(R.drawable.ic_tachi) + addAction( + R.drawable.nnf_ic_file_folder, + context.getString(R.string.action_open_log), + NotificationReceiver.openErrorLogPendingActivity(context, uri) + ) + } + .build() + ) + } + /** * Shows the notification containing the result of the update done by the service. * diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt index 67db6e67a..27d15b712 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt @@ -23,8 +23,10 @@ import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import eu.kanade.tachiyomi.util.prepUpdateCover +import eu.kanade.tachiyomi.util.storage.getUriCompat import eu.kanade.tachiyomi.util.system.acquireWakeLock import eu.kanade.tachiyomi.util.system.isServiceRunning +import java.io.File import java.util.ArrayList import java.util.concurrent.atomic.AtomicInteger import rx.Observable @@ -253,7 +255,7 @@ class LibraryUpdateService( // List containing new updates val newUpdates = ArrayList>>() // List containing failed updates - val failedUpdates = ArrayList() + val failedUpdates = ArrayList>() // List containing categories that get included in downloads. val categoriesToDownload = preferences.downloadNewCategories().get().map(String::toInt) // Boolean to determine if user wants to automatically download new chapters. @@ -270,7 +272,7 @@ class LibraryUpdateService( updateManga(manga) // If there's any error, return empty update and continue. .onErrorReturn { - failedUpdates.add(manga) + failedUpdates.add(Pair(manga, it.message)) Pair(emptyList(), emptyList()) } // Filter out mangas without new chapters (or failed). @@ -303,6 +305,8 @@ class LibraryUpdateService( } // Notify result of the overall update. .doOnCompleted { + notifier.cancelProgressNotification() + if (newUpdates.isNotEmpty()) { notifier.showUpdateNotifications(newUpdates) if (downloadNew && hasDownloads) { @@ -311,10 +315,12 @@ class LibraryUpdateService( } if (failedUpdates.isNotEmpty()) { - Timber.e("Failed updating: ${failedUpdates.map { it.title }}") + val errorFile = writeErrorFile(failedUpdates) + notifier.showUpdateErrorNotification( + failedUpdates.map { it.first.title }, + errorFile.getUriCompat(this) + ) } - - notifier.cancelProgressNotification() } .map { manga -> manga.first } } @@ -417,4 +423,25 @@ class LibraryUpdateService( notifier.cancelProgressNotification() } } + + /** + * Writes basic file of update errors to cache dir. + */ + private fun writeErrorFile(errors: List>): File { + try { + if (errors.isNotEmpty()) { + val destFile = File(externalCacheDir, "tachiyomi_update_errors.txt") + + destFile.bufferedWriter().use { out -> + errors.forEach { (manga, error) -> + out.write("${manga.title}: $error\n") + } + } + return destFile + } + } catch (e: Exception) { + // Empty + } + return File("") + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt index 6fd4f3c98..cd8132fac 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt @@ -25,6 +25,7 @@ object Notifications { */ const val CHANNEL_LIBRARY = "library_channel" const val ID_LIBRARY_PROGRESS = -101 + const val ID_LIBRARY_ERROR = -102 /** * Notification channel and ids used by the downloader. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 92413b79a..a0b98bb06 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -579,6 +579,10 @@ Chapters %1$s and 1 more Chapters %1$s and %2$d more + + 1 update failed + %1$d updates failed + Failed to update cover Please add the manga to your library before doing this Sync canceled