mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	Reword library update restrictions setting and surface skipped entries in error notification/log
This commit is contained in:
		| @@ -5,7 +5,7 @@ import androidx.core.content.edit | ||||
| import androidx.preference.PreferenceManager | ||||
| import eu.kanade.tachiyomi.data.backup.BackupCreatorJob | ||||
| import eu.kanade.tachiyomi.data.library.LibraryUpdateJob | ||||
| import eu.kanade.tachiyomi.data.preference.MANGA_ONGOING | ||||
| import eu.kanade.tachiyomi.data.preference.MANGA_NON_COMPLETED | ||||
| import eu.kanade.tachiyomi.data.preference.PreferenceKeys | ||||
| import eu.kanade.tachiyomi.data.preference.PreferenceValues | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| @@ -244,7 +244,7 @@ object Migrations { | ||||
|             if (oldVersion < 72) { | ||||
|                 val oldUpdateOngoingOnly = prefs.getBoolean("pref_update_only_non_completed_key", true) | ||||
|                 if (!oldUpdateOngoingOnly) { | ||||
|                     preferences.libraryUpdateMangaRestriction() -= MANGA_ONGOING | ||||
|                     preferences.libraryUpdateMangaRestriction() -= MANGA_NON_COMPLETED | ||||
|                 } | ||||
|             } | ||||
|             if (oldVersion < 75) { | ||||
|   | ||||
| @@ -92,18 +92,19 @@ 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 skipped Number of entries that were skipped during the update. | ||||
|      * @param failed Number of entries that failed to update. | ||||
|      * @param uri Uri for error log file containing all titles that failed. | ||||
|      */ | ||||
|     fun showUpdateErrorNotification(errors: List<String>, uri: Uri) { | ||||
|         if (errors.isEmpty()) { | ||||
|     fun showUpdateErrorNotification(skipped: Int, failed: Int, uri: Uri) { | ||||
|         if (skipped == 0 && failed == 0) { | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         context.notificationManager.notify( | ||||
|             Notifications.ID_LIBRARY_ERROR, | ||||
|             context.notificationBuilder(Notifications.CHANNEL_LIBRARY_ERROR) { | ||||
|                 setContentTitle(context.resources.getQuantityString(R.plurals.notification_update_error, errors.size, errors.size)) | ||||
|                 setContentTitle(context.resources.getString(R.string.notification_update_skipped_error, skipped, failed)) | ||||
|                 setContentText(context.getString(R.string.action_show_errors)) | ||||
|                 setSmallIcon(R.drawable.ic_tachi) | ||||
|  | ||||
|   | ||||
| @@ -19,9 +19,9 @@ import eu.kanade.tachiyomi.data.download.DownloadManager | ||||
| import eu.kanade.tachiyomi.data.download.DownloadService | ||||
| import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Companion.start | ||||
| import eu.kanade.tachiyomi.data.notification.Notifications | ||||
| import eu.kanade.tachiyomi.data.preference.MANGA_FULLY_READ | ||||
| import eu.kanade.tachiyomi.data.preference.MANGA_ONGOING | ||||
| import eu.kanade.tachiyomi.data.preference.MANGA_STARTED | ||||
| import eu.kanade.tachiyomi.data.preference.MANGA_HAS_UNREAD | ||||
| import eu.kanade.tachiyomi.data.preference.MANGA_NON_COMPLETED | ||||
| import eu.kanade.tachiyomi.data.preference.MANGA_NON_READ | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.data.track.EnhancedTrackService | ||||
| import eu.kanade.tachiyomi.data.track.TrackManager | ||||
| @@ -141,7 +141,7 @@ class LibraryUpdateService( | ||||
|  | ||||
|                 true | ||||
|             } else { | ||||
|                 instance?.addMangaToQueue(category?.id ?: -1, target) | ||||
|                 instance?.addMangaToQueue(category?.id ?: -1) | ||||
|                 false | ||||
|             } | ||||
|         } | ||||
| @@ -213,7 +213,7 @@ class LibraryUpdateService( | ||||
|  | ||||
|         // Update favorite manga | ||||
|         val categoryId = intent.getIntExtra(KEY_CATEGORY, -1) | ||||
|         addMangaToQueue(categoryId, target) | ||||
|         addMangaToQueue(categoryId) | ||||
|  | ||||
|         // Destroy service when completed or in case of an error. | ||||
|         val handler = CoroutineExceptionHandler { _, exception -> | ||||
| @@ -238,10 +238,10 @@ class LibraryUpdateService( | ||||
|      * @param category the ID of the category to update, or -1 if no category specified. | ||||
|      * @param target the target to update. | ||||
|      */ | ||||
|     fun addMangaToQueue(categoryId: Int, target: Target) { | ||||
|     fun addMangaToQueue(categoryId: Int) { | ||||
|         val libraryManga = db.getLibraryMangas().executeAsBlocking() | ||||
|  | ||||
|         var listToUpdate = if (categoryId != -1) { | ||||
|         val listToUpdate = if (categoryId != -1) { | ||||
|             libraryManga.filter { it.category == categoryId } | ||||
|         } else { | ||||
|             val categoriesToUpdate = preferences.libraryUpdateCategories().get().map(String::toInt) | ||||
| @@ -261,23 +261,6 @@ class LibraryUpdateService( | ||||
|             listToInclude.minus(listToExclude) | ||||
|         } | ||||
|  | ||||
|         if (target == Target.CHAPTERS) { | ||||
|             val restrictions = preferences.libraryUpdateMangaRestriction().get() | ||||
|             if (MANGA_ONGOING in restrictions) { | ||||
|                 listToUpdate = listToUpdate.filterNot { it.status == SManga.COMPLETED } | ||||
|             } | ||||
|             if (MANGA_FULLY_READ in restrictions) { | ||||
|                 listToUpdate = listToUpdate.filter { it.unreadCount == 0 } | ||||
|             } | ||||
|             if (MANGA_STARTED in restrictions) { | ||||
|                 listToUpdate = listToUpdate.filter { manga -> | ||||
|                     // If the manga has 0 chapters you can't actually start reading it | ||||
|                     if (manga.totalChapters == 0) true | ||||
|                     else manga.hasStarted | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         mangaToUpdate = listToUpdate | ||||
|             .distinctBy { it.id } | ||||
|             .sortedBy { it.title } | ||||
| @@ -306,10 +289,12 @@ class LibraryUpdateService( | ||||
|         val progressCount = AtomicInteger(0) | ||||
|         val currentlyUpdatingManga = CopyOnWriteArrayList<LibraryManga>() | ||||
|         val newUpdates = CopyOnWriteArrayList<Pair<LibraryManga, Array<Chapter>>>() | ||||
|         val skippedUpdates = CopyOnWriteArrayList<Pair<Manga, String?>>() | ||||
|         val failedUpdates = CopyOnWriteArrayList<Pair<Manga, String?>>() | ||||
|         val hasDownloads = AtomicBoolean(false) | ||||
|         val loggedServices by lazy { trackManager.services.filter { it.isLogged } } | ||||
|         val currentUnreadUpdatesCount = preferences.unreadUpdatesCount().get() | ||||
|         val restrictions = preferences.libraryUpdateMangaRestriction().get() | ||||
|  | ||||
|         withIOContext { | ||||
|             mangaToUpdate.groupBy { it.source } | ||||
| @@ -328,6 +313,16 @@ class LibraryUpdateService( | ||||
|                                     manga, | ||||
|                                 ) { manga -> | ||||
|                                     try { | ||||
|                                         if (MANGA_NON_COMPLETED in restrictions && manga.status == SManga.COMPLETED) { | ||||
|                                             throw SkipUpdateException(getString(R.string.skipped_reason_completed)) | ||||
|                                         } | ||||
|                                         if (MANGA_HAS_UNREAD in restrictions && manga.unreadCount != 0) { | ||||
|                                             throw SkipUpdateException(getString(R.string.skipped_reason_not_caught_up)) | ||||
|                                         } | ||||
|                                         if (MANGA_NON_READ in restrictions && manga.totalChapters > 0 && !manga.hasStarted) { | ||||
|                                             throw SkipUpdateException(getString(R.string.skipped_reason_not_started)) | ||||
|                                         } | ||||
|  | ||||
|                                         val (newChapters, _) = updateManga(manga) | ||||
|  | ||||
|                                         if (newChapters.isNotEmpty()) { | ||||
| @@ -342,6 +337,8 @@ class LibraryUpdateService( | ||||
|                                                     .toTypedArray() | ||||
|                                             ) | ||||
|                                         } | ||||
|                                     } catch (e: SkipUpdateException) { | ||||
|                                         skippedUpdates.add(manga to e.message) | ||||
|                                     } catch (e: Throwable) { | ||||
|                                         val errorMessage = when (e) { | ||||
|                                             is NoChaptersException -> { | ||||
| @@ -380,11 +377,12 @@ class LibraryUpdateService( | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (failedUpdates.isNotEmpty()) { | ||||
|             val errorFile = writeErrorFile(failedUpdates) | ||||
|         if (skippedUpdates.isNotEmpty() || failedUpdates.isNotEmpty()) { | ||||
|             val errorFile = writeErrorFile(skippedUpdates + failedUpdates) | ||||
|             notifier.showUpdateErrorNotification( | ||||
|                 failedUpdates.map { it.first.title }, | ||||
|                 errorFile.getUriCompat(this) | ||||
|                 skippedUpdates.size, | ||||
|                 failedUpdates.size, | ||||
|                 errorFile.getUriCompat(this), | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| @@ -587,3 +585,5 @@ class LibraryUpdateService( | ||||
|  | ||||
| private const val MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD = 60 | ||||
| private const val ERROR_LOG_HELP_URL = "https://tachiyomi.org/help/guides/troubleshooting" | ||||
|  | ||||
| private class SkipUpdateException(override val message: String) : RuntimeException() | ||||
|   | ||||
| @@ -5,9 +5,9 @@ import eu.kanade.tachiyomi.R | ||||
| const val DEVICE_ONLY_ON_WIFI = "wifi" | ||||
| const val DEVICE_CHARGING = "ac" | ||||
|  | ||||
| const val MANGA_ONGOING = "manga_ongoing" | ||||
| const val MANGA_FULLY_READ = "manga_fully_read" | ||||
| const val MANGA_STARTED = "manga_started" | ||||
| const val MANGA_NON_COMPLETED = "manga_ongoing" | ||||
| const val MANGA_HAS_UNREAD = "manga_fully_read" | ||||
| const val MANGA_NON_READ = "manga_started" | ||||
|  | ||||
| /** | ||||
|  * This class stores the values for the preferences in the application. | ||||
|   | ||||
| @@ -224,7 +224,7 @@ class PreferencesHelper(val context: Context) { | ||||
|     fun libraryUpdateInterval() = flowPrefs.getInt("pref_library_update_interval_key", 24) | ||||
|  | ||||
|     fun libraryUpdateDeviceRestriction() = flowPrefs.getStringSet("library_update_restriction", setOf(DEVICE_ONLY_ON_WIFI)) | ||||
|     fun libraryUpdateMangaRestriction() = flowPrefs.getStringSet("library_update_manga_restriction", setOf(MANGA_FULLY_READ, MANGA_ONGOING, MANGA_STARTED)) | ||||
|     fun libraryUpdateMangaRestriction() = flowPrefs.getStringSet("library_update_manga_restriction", setOf(MANGA_HAS_UNREAD, MANGA_NON_COMPLETED, MANGA_NON_READ)) | ||||
|  | ||||
|     fun showUpdatesNavBadge() = flowPrefs.getBoolean("library_update_show_tab_badge", false) | ||||
|     fun unreadUpdatesCount() = flowPrefs.getInt("library_unread_updates_count", 0) | ||||
|   | ||||
| @@ -13,9 +13,9 @@ import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.tachiyomi.data.library.LibraryUpdateJob | ||||
| import eu.kanade.tachiyomi.data.preference.DEVICE_CHARGING | ||||
| import eu.kanade.tachiyomi.data.preference.DEVICE_ONLY_ON_WIFI | ||||
| import eu.kanade.tachiyomi.data.preference.MANGA_FULLY_READ | ||||
| import eu.kanade.tachiyomi.data.preference.MANGA_ONGOING | ||||
| import eu.kanade.tachiyomi.data.preference.MANGA_STARTED | ||||
| import eu.kanade.tachiyomi.data.preference.MANGA_HAS_UNREAD | ||||
| import eu.kanade.tachiyomi.data.preference.MANGA_NON_COMPLETED | ||||
| import eu.kanade.tachiyomi.data.preference.MANGA_NON_READ | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.data.track.TrackManager | ||||
| import eu.kanade.tachiyomi.databinding.PrefLibraryColumnsBinding | ||||
| @@ -196,16 +196,16 @@ class SettingsLibraryController : SettingsController() { | ||||
|             multiSelectListPreference { | ||||
|                 bindTo(preferences.libraryUpdateMangaRestriction()) | ||||
|                 titleRes = R.string.pref_library_update_manga_restriction | ||||
|                 entriesRes = arrayOf(R.string.pref_update_only_completely_read, R.string.pref_update_only_non_completed, R.string.pref_update_only_started) | ||||
|                 entryValues = arrayOf(MANGA_FULLY_READ, MANGA_ONGOING, MANGA_STARTED) | ||||
|                 entriesRes = arrayOf(R.string.pref_update_only_completely_read, R.string.pref_update_only_started, R.string.pref_update_only_non_completed) | ||||
|                 entryValues = arrayOf(MANGA_HAS_UNREAD, MANGA_NON_READ, MANGA_NON_COMPLETED) | ||||
|  | ||||
|                 fun updateSummary() { | ||||
|                     val restrictions = preferences.libraryUpdateMangaRestriction().get().sorted() | ||||
|                         .map { | ||||
|                             when (it) { | ||||
|                                 MANGA_ONGOING -> context.getString(R.string.pref_update_only_non_completed) | ||||
|                                 MANGA_FULLY_READ -> context.getString(R.string.pref_update_only_completely_read) | ||||
|                                 MANGA_STARTED -> context.getString(R.string.pref_update_only_started) | ||||
|                                 MANGA_NON_READ -> context.getString(R.string.pref_update_only_started) | ||||
|                                 MANGA_HAS_UNREAD -> context.getString(R.string.pref_update_only_completely_read) | ||||
|                                 MANGA_NON_COMPLETED -> context.getString(R.string.pref_update_only_non_completed) | ||||
|                                 else -> it | ||||
|                             } | ||||
|                         } | ||||
| @@ -215,7 +215,7 @@ class SettingsLibraryController : SettingsController() { | ||||
|                         restrictions.joinToString() | ||||
|                     } | ||||
|  | ||||
|                     summary = context.getString(R.string.only_update_restrictions, restrictionsText) | ||||
|                     summary = restrictionsText | ||||
|                 } | ||||
|  | ||||
|                 preferences.libraryUpdateMangaRestriction().asFlow() | ||||
| @@ -234,23 +234,24 @@ class SettingsLibraryController : SettingsController() { | ||||
|                     val includedCategories = preferences.libraryUpdateCategories().get() | ||||
|                         .mapNotNull { id -> categories.find { it.id == id.toInt() } } | ||||
|                         .sortedBy { it.order } | ||||
|  | ||||
|                     val excludedCategories = preferences.libraryUpdateCategoriesExclude().get() | ||||
|                         .mapNotNull { id -> categories.find { it.id == id.toInt() } } | ||||
|                         .sortedBy { it.order } | ||||
|  | ||||
|                     val includedItemsText = if (includedCategories.isEmpty()) { | ||||
|                         context.getString(R.string.none) | ||||
|                     } else { | ||||
|                         if (includedCategories.size == categories.size) context.getString(R.string.all) | ||||
|                         else includedCategories.joinToString { it.name } | ||||
|                     } | ||||
|                     val allExcluded = excludedCategories.size == categories.size | ||||
|  | ||||
|                     val excludedItemsText = if (excludedCategories.isEmpty()) { | ||||
|                         context.getString(R.string.none) | ||||
|                     } else { | ||||
|                         if (excludedCategories.size == categories.size) context.getString(R.string.all) | ||||
|                         else excludedCategories.joinToString { it.name } | ||||
|                     val includedItemsText = when { | ||||
|                         // Some selected, but not all | ||||
|                         includedCategories.isNotEmpty() && includedCategories.size != categories.size -> includedCategories.joinToString { it.name } | ||||
|                         // All explicitly selected | ||||
|                         includedCategories.size == categories.size -> context.getString(R.string.all) | ||||
|                         allExcluded -> context.getString(R.string.none) | ||||
|                         else -> context.getString(R.string.all) | ||||
|                     } | ||||
|                     val excludedItemsText = when { | ||||
|                         excludedCategories.isEmpty() -> context.getString(R.string.none) | ||||
|                         allExcluded -> context.getString(R.string.all) | ||||
|                         else -> excludedCategories.joinToString { it.name } | ||||
|                     } | ||||
|  | ||||
|                     summary = buildSpannedString { | ||||
| @@ -340,8 +341,10 @@ class SettingsLibraryController : SettingsController() { | ||||
|             var selected = categories | ||||
|                 .map { | ||||
|                     when (it.id.toString()) { | ||||
|                         in preferences.libraryUpdateCategories().get() -> QuadStateTextView.State.CHECKED.ordinal | ||||
|                         in preferences.libraryUpdateCategoriesExclude().get() -> QuadStateTextView.State.INVERSED.ordinal | ||||
|                         in preferences.libraryUpdateCategories() | ||||
|                             .get() -> QuadStateTextView.State.CHECKED.ordinal | ||||
|                         in preferences.libraryUpdateCategoriesExclude() | ||||
|                             .get() -> QuadStateTextView.State.INVERSED.ordinal | ||||
|                         else -> QuadStateTextView.State.UNCHECKED.ordinal | ||||
|                     } | ||||
|                 } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user