From 12b2da90581bddd7ca8f31a3aada735ba42d02e0 Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 21 May 2020 02:18:51 -0400 Subject: [PATCH] Show notification with error log on update failures + Move notification logic out of LibraryUpdateService --- .../data/library/LibraryUpdateNotifier.kt | 242 ++++++++++++++++++ .../data/library/LibraryUpdateService.kt | 229 ++++------------- .../data/notification/NotificationReceiver.kt | 16 ++ .../data/notification/Notifications.kt | 1 + .../data/preference/PreferenceKeys.kt | 4 +- .../data/preference/PreferencesHelper.kt | 2 + .../kanade/tachiyomi/network/NetworkHelper.kt | 3 +- .../ui/setting/SettingsLibraryController.kt | 6 + app/src/main/res/values/strings.xml | 5 + 9 files changed, 318 insertions(+), 190 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt 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 new file mode 100644 index 0000000000..554631321f --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt @@ -0,0 +1,242 @@ +package eu.kanade.tachiyomi.data.library + +import android.app.Notification +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import android.graphics.BitmapFactory +import android.graphics.drawable.BitmapDrawable +import android.net.Uri +import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationManagerCompat +import androidx.core.content.ContextCompat +import coil.Coil +import coil.request.CachePolicy +import coil.request.GetRequest +import coil.transform.CircleCropTransformation +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.database.models.Chapter +import eu.kanade.tachiyomi.data.database.models.LibraryManga +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.data.notification.NotificationReceiver +import eu.kanade.tachiyomi.data.notification.Notifications +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.ui.main.MainActivity +import eu.kanade.tachiyomi.util.lang.chop +import eu.kanade.tachiyomi.util.system.notification +import eu.kanade.tachiyomi.util.system.notificationBuilder +import eu.kanade.tachiyomi.util.system.notificationManager +import uy.kohesive.injekt.injectLazy +import java.util.ArrayList + +class LibraryUpdateNotifier(private val context: Context) { + + private val preferences: PreferencesHelper by injectLazy() + + /** + * Pending intent of action that cancels the library update + */ + private val cancelIntent by lazy { + NotificationReceiver.cancelLibraryUpdatePendingBroadcast(context) + } + + /** + * Bitmap of the app for notifications. + */ + private val notificationBitmap by lazy { + BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher) + } + + /** + * Cached progress notification to avoid creating a lot. + */ + val progressNotificationBuilder by lazy { + context.notificationBuilder(Notifications.CHANNEL_LIBRARY) { + setContentTitle(context.getString(R.string.app_name)) + setSmallIcon(R.drawable.ic_refresh_24dp) + setLargeIcon(notificationBitmap) + setOngoing(true) + setOnlyAlertOnce(true) + color = ContextCompat.getColor(context, R.color.colorAccent) + addAction(R.drawable.ic_close_24dp, context.getString(android.R.string.cancel), cancelIntent) + } + } + + /** + * Shows the notification containing the currently updating manga and the progress. + * + * @param manga the manga that's being updated. + * @param current the current progress. + * @param total the total progress. + */ + fun showProgressNotification(manga: Manga, current: Int, total: Int) { + val title = manga.title + + context.notificationManager.notify( + Notifications.ID_LIBRARY_PROGRESS, + progressNotificationBuilder + .setContentTitle(title) + .setProgress(total, current, false) + .build() + ) + } + + /** + * 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_failed, errors.size, errors.size)) + setStyle( + NotificationCompat.BigTextStyle().bigText( + errors.joinToString("\n") { + it.chop(TITLE_MAX_LEN) + } + ) + ) + setSmallIcon(R.drawable.ic_tachi) + addAction( + R.drawable.nnf_ic_file_folder, + context.getString(R.string.view_all_errors), + NotificationReceiver.openErrorLogPendingActivity(context, uri) + ) + } + .build() + ) + } + + /** + * Shows the notification containing the result of the update done by the service. + * + * @param updates a list of manga with new updates. + */ + suspend fun showResultNotification(updates: Map>) { + val notifications = ArrayList>() + updates.forEach { + val manga = it.key + val chapters = it.value + val chapterNames = chapters.map { chapter -> chapter.name } + notifications.add(Pair(context.notification(Notifications.CHANNEL_NEW_CHAPTERS) { + setSmallIcon(R.drawable.ic_tachi) + try { + val request = GetRequest.Builder(context).data(manga) + .networkCachePolicy(CachePolicy.DISABLED) + .transformations(CircleCropTransformation()).size(width = ICON_SIZE, height = ICON_SIZE) + .build() + + Coil.imageLoader(context) + .execute(request).drawable?.let { drawable -> + setLargeIcon((drawable as BitmapDrawable).bitmap) + } + } catch (e: Exception) { } + setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY) + setContentTitle(manga.title) + color = ContextCompat.getColor(context, R.color.colorAccent) + val chaptersNames = if (chapterNames.size > MAX_CHAPTERS) { + "${chapterNames.take(MAX_CHAPTERS - 1) + .joinToString(", ")}, " + context.resources.getQuantityString( + R.plurals.notification_and_n_more, + (chapterNames.size - (MAX_CHAPTERS - 1)), + (chapterNames.size - (MAX_CHAPTERS - 1)) + ) + } else chapterNames.joinToString(", ") + setContentText(chaptersNames) + setStyle(NotificationCompat.BigTextStyle().bigText(chaptersNames)) + priority = NotificationCompat.PRIORITY_HIGH + setGroup(Notifications.GROUP_NEW_CHAPTERS) + setContentIntent( + NotificationReceiver.openChapterPendingActivity( + context, manga, chapters.first() + ) + ) + addAction( + R.drawable.ic_glasses_black_24dp, context.getString(R.string.mark_as_read), + NotificationReceiver.markAsReadPendingBroadcast( + context, + manga, chapters, Notifications.ID_NEW_CHAPTERS + ) + ) + addAction( + R.drawable.ic_book_white_24dp, context.getString(R.string.view_chapters), + NotificationReceiver.openChapterPendingActivity( + context, + manga, Notifications.ID_NEW_CHAPTERS + ) + ) + setAutoCancel(true) + }, manga.id.hashCode())) + } + + NotificationManagerCompat.from(context).apply { + + notify( + Notifications.ID_NEW_CHAPTERS, + context.notification(Notifications.CHANNEL_NEW_CHAPTERS) { + setSmallIcon(R.drawable.ic_tachi) + setLargeIcon(notificationBitmap) + setContentTitle(context.getString(R.string.new_chapters_found)) + color = ContextCompat.getColor(context, R.color.colorAccent) + if (updates.size > 1) { + setContentText( + context.resources.getQuantityString( + R.plurals + .for_n_titles, + updates.size, updates.size + ) + ) + setStyle( + NotificationCompat.BigTextStyle() + .bigText(updates.keys.joinToString("\n") { + it.title.chop(45) + }) + ) + } else { + setContentText(updates.keys.first().title.chop(45)) + } + priority = NotificationCompat.PRIORITY_HIGH + setGroup(Notifications.GROUP_NEW_CHAPTERS) + setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY) + setGroupSummary(true) + setContentIntent(getNotificationIntent()) + setAutoCancel(true) + }) + + notifications.forEach { + notify(it.second, it.first) + } + } + } + + /** + * Cancels the progress notification. + */ + fun cancelProgressNotification() { + context.notificationManager.cancel(Notifications.ID_LIBRARY_PROGRESS) + } + + /** + * Returns an intent to open the main activity. + */ + private fun getNotificationIntent(): PendingIntent { + val intent = Intent(context, MainActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP + action = MainActivity.SHORTCUT_RECENTLY_UPDATED + } + return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + } + + companion object { + private const val MAX_CHAPTERS = 5 + private const val TITLE_MAX_LEN = 45 + private const val ICON_SIZE = 192 + } +} 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 cc64e372b0..7630972fae 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 @@ -1,25 +1,14 @@ package eu.kanade.tachiyomi.data.library -import android.app.Notification -import android.app.PendingIntent import android.app.Service import android.content.Context import android.content.Intent -import android.graphics.BitmapFactory -import android.graphics.drawable.BitmapDrawable import android.os.Build import android.os.IBinder import android.os.PowerManager -import androidx.core.app.NotificationCompat -import androidx.core.app.NotificationCompat.GROUP_ALERT_SUMMARY -import androidx.core.app.NotificationManagerCompat -import androidx.core.content.ContextCompat import coil.Coil import coil.request.CachePolicy -import coil.request.GetRequest import coil.request.LoadRequest -import coil.transform.CircleCropTransformation -import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Category @@ -30,7 +19,6 @@ import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadService import eu.kanade.tachiyomi.data.library.LibraryUpdateRanker.rankingScheme import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Companion.start -import eu.kanade.tachiyomi.data.notification.NotificationReceiver import eu.kanade.tachiyomi.data.notification.Notifications import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.getOrDefault @@ -39,12 +27,9 @@ import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.fetchMangaDetailsAsync import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.HttpSource -import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource -import eu.kanade.tachiyomi.util.lang.chop +import eu.kanade.tachiyomi.util.storage.getUriCompat import eu.kanade.tachiyomi.util.system.executeOnIO -import eu.kanade.tachiyomi.util.system.notification -import eu.kanade.tachiyomi.util.system.notificationManager import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.Dispatchers @@ -60,7 +45,7 @@ import kotlinx.coroutines.withContext import timber.log.Timber import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get -import java.util.ArrayList +import java.io.File import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicInteger @@ -86,19 +71,7 @@ class LibraryUpdateService( */ private lateinit var wakeLock: PowerManager.WakeLock - /** - * Pending intent of action that cancels the library update - */ - private val cancelIntent by lazy { - NotificationReceiver.cancelLibraryUpdatePendingBroadcast(this) - } - - /** - * Bitmap of the app for notifications. - */ - private val notificationBitmap by lazy { - BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher) - } + private lateinit var notifier: LibraryUpdateNotifier private var job: Job? = null @@ -111,6 +84,9 @@ class LibraryUpdateService( // List containing new updates private val newUpdates = mutableMapOf>() + // List containing failed updates + private val failedUpdates = mutableMapOf() + val count = AtomicInteger(0) val jobCount = AtomicInteger(0) @@ -131,19 +107,6 @@ class LibraryUpdateService( preferences.deleteRemovedChapters().get() != 1 } - /** - * Cached progress notification to avoid creating a lot. - */ - private val progressNotification by lazy { - NotificationCompat.Builder(this, Notifications.CHANNEL_LIBRARY) - .setContentTitle(getString(R.string.app_name)) - .setSmallIcon(R.drawable.ic_refresh_white_24dp_img).setLargeIcon(notificationBitmap) - .setOngoing(true).setOnlyAlertOnce(true) - .setColor(ContextCompat.getColor(this, R.color.colorAccent)).addAction( - R.drawable.ic_clear_grey_24dp_img, getString(android.R.string.cancel), cancelIntent - ) - } - /** * Defines what should be updated within a service execution. */ @@ -315,11 +278,12 @@ class LibraryUpdateService( */ override fun onCreate() { super.onCreate() - startForeground(Notifications.ID_LIBRARY_PROGRESS, progressNotification.build()) + notifier = LibraryUpdateNotifier(this) wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, "LibraryUpdateService:WakeLock" ) wakeLock.acquire(TimeUnit.MINUTES.toMillis(30)) + startForeground(Notifications.ID_LIBRARY_PROGRESS, notifier.progressNotificationBuilder.build()) } /** @@ -407,11 +371,11 @@ class LibraryUpdateService( private suspend fun finishUpdates() { if (jobCount.get() != 0) return if (newUpdates.isNotEmpty()) { - showResultNotification(newUpdates) + notifier.showResultNotification(newUpdates) if (preferences.refreshCoversToo().getOrDefault() && job?.isCancelled == false) { updateDetails(newUpdates.keys.toList()) - cancelProgressNotification() + notifier.cancelProgressNotification() if (downloadNew && hasDownloads) { DownloadService.start(this) } @@ -420,7 +384,15 @@ class LibraryUpdateService( } newUpdates.clear() } - cancelProgressNotification() + if (preferences.showLibraryUpdateErrors() && failedUpdates.isNotEmpty()) { + val errorFile = writeErrorFile(failedUpdates) + notifier.showUpdateErrorNotification( + failedUpdates.map { it.key.title }, + errorFile.getUriCompat(this) + ) + } + failedUpdates.clear() + notifier.cancelProgressNotification() } private suspend fun updateMangaInSource( @@ -459,7 +431,7 @@ class LibraryUpdateService( if (job?.isCancelled == true) { return false } - showProgressNotification(manga, progress, mangaToUpdate.size) + notifier.showProgressNotification(manga, progress, mangaToUpdate.size) val source = sourceManager.get(manga.source) as? HttpSource ?: return false val fetchedChapters = withContext(Dispatchers.IO) { source.fetchChapterList(manga).toBlocking().single() @@ -489,6 +461,7 @@ class LibraryUpdateService( return hasDownloads } catch (e: Exception) { if (e !is CancellationException) { + failedUpdates[manga] = e.message Timber.e("Failed updating: ${manga.title}: $e") } return false @@ -496,14 +469,9 @@ class LibraryUpdateService( } private fun downloadChapters(manga: Manga, chapters: List) { - // we need to get the chapters from the db so we have chapter ids - val mangaChapters = db.getChapters(manga).executeAsBlocking() - val dbChapters = chapters.map { - mangaChapters.find { mangaChapter -> mangaChapter.url == it.url }!! - } // We don't want to start downloading while the library is updating, because websites // may don't like it and they could ban the user. - downloadManager.downloadChapters(manga, dbChapters, false) + downloadManager.downloadChapters(manga, chapters, false) } /** @@ -523,7 +491,11 @@ class LibraryUpdateService( return@async } val source = sourceManager.get(manga.source) as? HttpSource ?: return@async - showProgressNotification(manga, count.andIncrement, mangaToUpdate.size) + notifier.showProgressNotification( + manga, + count.andIncrement, + mangaToUpdate.size + ) val networkManga = try { source.fetchMangaDetailsAsync(manga) @@ -550,7 +522,7 @@ class LibraryUpdateService( } } asyncList.awaitAll() - cancelProgressNotification() + notifier.cancelProgressNotification() } /** @@ -565,7 +537,7 @@ class LibraryUpdateService( val loggedServices = trackManager.services.filter { it.isLogged } mangaToUpdate.forEach { manga -> - showProgressNotification(manga, count++, mangaToUpdate.size) + notifier.showProgressNotification(manga, count++, mangaToUpdate.size) val tracks = db.getTracks(manga).executeAsBlocking() @@ -581,143 +553,28 @@ class LibraryUpdateService( } } } - cancelProgressNotification() + notifier.cancelProgressNotification() } /** - * Shows the notification containing the currently updating manga and the progress. - * - * @param manga the manga that's being updated. - * @param current the current progress. - * @param total the total progress. + * Writes basic file of update errors to cache dir. */ - private fun showProgressNotification(manga: Manga, current: Int, total: Int) { - notificationManager.notify( - Notifications.ID_LIBRARY_PROGRESS, progressNotification - .setContentTitle(manga.title) - .setProgress(total, current, false) - .build() - ) - } - - /** - * Shows the notification containing the result of the update done by the service. - * - * @param updates a list of manga with new updates. - */ - private suspend fun showResultNotification(updates: Map>) { - val notifications = ArrayList>() - updates.forEach { - val manga = it.key - val chapters = it.value - val chapterNames = chapters.map { chapter -> chapter.name } - notifications.add(Pair(notification(Notifications.CHANNEL_NEW_CHAPTERS) { - setSmallIcon(R.drawable.ic_tachi) - try { - - val request = GetRequest.Builder(this@LibraryUpdateService).data(manga) - .networkCachePolicy(CachePolicy.DISABLED) - .transformations(CircleCropTransformation()).size(width = 256, height = 256) - .build() - - Coil.imageLoader(this@LibraryUpdateService) - .execute(request).drawable?.let { drawable -> - setLargeIcon((drawable as BitmapDrawable).bitmap) - } - } catch (e: Exception) { - } - setGroupAlertBehavior(GROUP_ALERT_SUMMARY) - setContentTitle(manga.title) - color = ContextCompat.getColor(this@LibraryUpdateService, R.color.colorAccent) - val chaptersNames = if (chapterNames.size > 5) { - "${chapterNames.take(4).joinToString(", ")}, " + - resources.getQuantityString( - R.plurals.notification_and_n_more, - (chapterNames.size - 4), (chapterNames.size - 4) - ) - } else chapterNames.joinToString(", ") - setContentText(chaptersNames) - setStyle(NotificationCompat.BigTextStyle().bigText(chaptersNames)) - priority = NotificationCompat.PRIORITY_HIGH - setGroup(Notifications.GROUP_NEW_CHAPTERS) - setContentIntent( - NotificationReceiver.openChapterPendingActivity( - this@LibraryUpdateService, manga, chapters.first() - ) - ) - addAction( - R.drawable.ic_glasses_black_24dp, getString(R.string.mark_as_read), - NotificationReceiver.markAsReadPendingBroadcast( - this@LibraryUpdateService, - manga, chapters, Notifications.ID_NEW_CHAPTERS - ) - ) - addAction( - R.drawable.ic_book_white_24dp, getString(R.string.view_chapters), - NotificationReceiver.openChapterPendingActivity( - this@LibraryUpdateService, - manga, Notifications.ID_NEW_CHAPTERS - ) - ) - setAutoCancel(true) - }, manga.id.hashCode())) - } + private fun writeErrorFile(errors: Map): File { + try { + if (errors.isNotEmpty()) { + val destFile = File(externalCacheDir, "tachiyomi_update_errors.txt") - NotificationManagerCompat.from(this).apply { - - notify( - Notifications.ID_NEW_CHAPTERS, - notification(Notifications.CHANNEL_NEW_CHAPTERS) { - setSmallIcon(R.drawable.ic_tachi) - setLargeIcon(notificationBitmap) - setContentTitle(getString(R.string.new_chapters_found)) - color = ContextCompat.getColor(applicationContext, R.color.colorAccent) - if (updates.size > 1) { - setContentText( - resources.getQuantityString( - R.plurals - .for_n_titles, - updates.size, updates.size - ) - ) - setStyle( - NotificationCompat.BigTextStyle() - .bigText(updates.keys.joinToString("\n") { - it.title.chop(45) - }) - ) - } else { - setContentText(updates.keys.first().title.chop(45)) + destFile.bufferedWriter().use { out -> + errors.forEach { (manga, error) -> + out.write("${manga.title}: $error\n") } - priority = NotificationCompat.PRIORITY_HIGH - setGroup(Notifications.GROUP_NEW_CHAPTERS) - setGroupAlertBehavior(GROUP_ALERT_SUMMARY) - setGroupSummary(true) - setContentIntent(getNotificationIntent()) - setAutoCancel(true) - }) - - notifications.forEach { - notify(it.second, it.first) + } + return destFile } + } catch (e: Exception) { + // Empty } - } - - /** - * Cancels the progress notification. - */ - private fun cancelProgressNotification() { - notificationManager.cancel(Notifications.ID_LIBRARY_PROGRESS) - } - - /** - * Returns an intent to open the main activity. - */ - private fun getNotificationIntent(): PendingIntent { - val intent = Intent(this, MainActivity::class.java) - intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP - intent.action = MainActivity.SHORTCUT_RECENTLY_UPDATED - return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + return File("") } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt index 3f2b96b062..74869196b6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt @@ -435,6 +435,22 @@ class NotificationReceiver : BroadcastReceiver() { ) } + /** + * Returns [PendingIntent] that opens the error log file in an external viewer + * + * @param context context of application + * @param uri uri of error log file + * @return [PendingIntent] + */ + internal fun openErrorLogPendingActivity(context: Context, uri: Uri): PendingIntent { + val intent = Intent().apply { + action = Intent.ACTION_VIEW + setDataAndType(uri, "text/plain") + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION + } + return PendingIntent.getActivity(context, 0, intent, 0) + } + /** * Returns [PendingIntent] that opens the extensions controller, * 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 ee55c2dee4..07b36d116f 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 @@ -24,6 +24,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/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt index 7c2379c084..38d685214c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt @@ -121,8 +121,6 @@ object PreferenceKeys { const val uniformGrid = "uniform_grid" - const val libraryAsSingleList = "library_as_single_list" - const val lang = "app_language" const val dateFormat = "app_date_format" @@ -149,6 +147,8 @@ object PreferenceKeys { const val updateOnRefresh = "update_on_refresh" + const val showLibraryUpdateErrors = "show_library_update_errors" + const val alwaysShowChapterTransition = "always_show_chapter_transition" @Deprecated("Use the preferences of the source") diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index 7603039831..7c097cbd49 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -278,6 +278,8 @@ class PreferencesHelper(val context: Context) { fun onlySearchPinned() = flowPrefs.getBoolean(Keys.onlySearchPinned, true) + fun showLibraryUpdateErrors() = prefs.getBoolean(Keys.showLibraryUpdateErrors, false) + // Tutorial preferences fun shownFilterTutorial() = flowPrefs.getBoolean("shown_filter_tutorial", false) diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt index b0a0a27c50..62b499db52 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt @@ -1,7 +1,6 @@ package eu.kanade.tachiyomi.network import android.content.Context -import com.chuckerteam.chucker.api.ChuckerInterceptor import okhttp3.Cache import okhttp3.OkHttpClient import java.io.File @@ -17,7 +16,7 @@ class NetworkHelper(context: Context) { val client = OkHttpClient.Builder() .cookieJar(cookieManager) .cache(Cache(cacheDir, cacheSize)) - .addInterceptor(ChuckerInterceptor(context)) +// .addInterceptor(ChuckerInterceptor(context)) .build() val cloudflareClient = client.newBuilder() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt index dff4bcc44a..5630733a23 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt @@ -159,6 +159,12 @@ class SettingsLibraryController : SettingsController() { summaryRes = R.string.auto_refresh_covers_summary defaultValue = true } + + switchPreference { + key = Keys.showLibraryUpdateErrors + titleRes = R.string.show_notification_error + defaultValue = false + } } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 241725b029..64129da337 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -170,6 +170,10 @@ and %1$d more chapter and %1$d more chapters + + 1 update failed + %1$d updates failed + Library update frequency @@ -186,6 +190,7 @@ Automatically refresh covers Refresh covers in library as well when updating library + Show a notification for errors Recents