Account for skipped entries when showing large updates warning
Closes #6159
This commit is contained in:
parent
94cba9324c
commit
7ed99fbbd6
3 changed files with 88 additions and 73 deletions
|
@ -186,7 +186,40 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||||
.distinctBy { it.manga.id }
|
.distinctBy { it.manga.id }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val restrictions = libraryPreferences.autoUpdateMangaRestrictions().get()
|
||||||
|
val skippedUpdates = mutableListOf<Pair<Manga, String?>>()
|
||||||
|
val fetchWindow = fetchInterval.getWindow(ZonedDateTime.now())
|
||||||
|
|
||||||
mangaToUpdate = listToUpdate
|
mangaToUpdate = listToUpdate
|
||||||
|
.filter {
|
||||||
|
when {
|
||||||
|
it.manga.updateStrategy != UpdateStrategy.ALWAYS_UPDATE -> {
|
||||||
|
skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_not_always_update))
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
MANGA_NON_COMPLETED in restrictions && it.manga.status.toInt() == SManga.COMPLETED -> {
|
||||||
|
skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_completed))
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
MANGA_HAS_UNREAD in restrictions && it.unreadCount != 0L -> {
|
||||||
|
skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_not_caught_up))
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
MANGA_NON_READ in restrictions && it.totalChapters > 0L && !it.hasStarted -> {
|
||||||
|
skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_not_started))
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
MANGA_OUTSIDE_RELEASE_PERIOD in restrictions && it.manga.nextUpdate > fetchWindow.second -> {
|
||||||
|
skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_not_in_release_period))
|
||||||
|
false
|
||||||
|
}
|
||||||
|
else -> true
|
||||||
|
}
|
||||||
|
}
|
||||||
.sortedBy { it.manga.title }
|
.sortedBy { it.manga.title }
|
||||||
|
|
||||||
// Warn when excessively checking a single source
|
// Warn when excessively checking a single source
|
||||||
|
@ -197,6 +230,17 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||||
if (maxUpdatesFromSource > MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD) {
|
if (maxUpdatesFromSource > MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD) {
|
||||||
notifier.showQueueSizeWarningNotification()
|
notifier.showQueueSizeWarningNotification()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (skippedUpdates.isNotEmpty()) {
|
||||||
|
// TODO: surface skipped reasons to user?
|
||||||
|
logcat {
|
||||||
|
skippedUpdates
|
||||||
|
.groupBy { it.second }
|
||||||
|
.map { (reason, entries) -> "$reason: [${entries.map { it.first.title }.sorted().joinToString()}]" }
|
||||||
|
.joinToString()
|
||||||
|
}
|
||||||
|
notifier.showUpdateSkippedNotification(skippedUpdates.size)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -212,10 +256,8 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||||
val progressCount = AtomicInteger(0)
|
val progressCount = AtomicInteger(0)
|
||||||
val currentlyUpdatingManga = CopyOnWriteArrayList<Manga>()
|
val currentlyUpdatingManga = CopyOnWriteArrayList<Manga>()
|
||||||
val newUpdates = CopyOnWriteArrayList<Pair<Manga, Array<Chapter>>>()
|
val newUpdates = CopyOnWriteArrayList<Pair<Manga, Array<Chapter>>>()
|
||||||
val skippedUpdates = CopyOnWriteArrayList<Pair<Manga, String?>>()
|
|
||||||
val failedUpdates = CopyOnWriteArrayList<Pair<Manga, String?>>()
|
val failedUpdates = CopyOnWriteArrayList<Pair<Manga, String?>>()
|
||||||
val hasDownloads = AtomicBoolean(false)
|
val hasDownloads = AtomicBoolean(false)
|
||||||
val restrictions = libraryPreferences.autoUpdateMangaRestrictions().get()
|
|
||||||
val fetchWindow = fetchInterval.getWindow(ZonedDateTime.now())
|
val fetchWindow = fetchInterval.getWindow(ZonedDateTime.now())
|
||||||
|
|
||||||
coroutineScope {
|
coroutineScope {
|
||||||
|
@ -237,49 +279,30 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||||
progressCount,
|
progressCount,
|
||||||
manga,
|
manga,
|
||||||
) {
|
) {
|
||||||
when {
|
try {
|
||||||
manga.updateStrategy != UpdateStrategy.ALWAYS_UPDATE ->
|
val newChapters = updateManga(manga, fetchWindow)
|
||||||
skippedUpdates.add(manga to context.getString(R.string.skipped_reason_not_always_update))
|
.sortedByDescending { it.sourceOrder }
|
||||||
|
|
||||||
MANGA_NON_COMPLETED in restrictions && manga.status.toInt() == SManga.COMPLETED ->
|
if (newChapters.isNotEmpty()) {
|
||||||
skippedUpdates.add(manga to context.getString(R.string.skipped_reason_completed))
|
val categoryIds = getCategories.await(manga.id).map { it.id }
|
||||||
|
if (manga.shouldDownloadNewChapters(categoryIds, downloadPreferences)) {
|
||||||
MANGA_HAS_UNREAD in restrictions && libraryManga.unreadCount != 0L ->
|
downloadChapters(manga, newChapters)
|
||||||
skippedUpdates.add(manga to context.getString(R.string.skipped_reason_not_caught_up))
|
hasDownloads.set(true)
|
||||||
|
|
||||||
MANGA_NON_READ in restrictions && libraryManga.totalChapters > 0L && !libraryManga.hasStarted ->
|
|
||||||
skippedUpdates.add(manga to context.getString(R.string.skipped_reason_not_started))
|
|
||||||
|
|
||||||
MANGA_OUTSIDE_RELEASE_PERIOD in restrictions && manga.nextUpdate > fetchWindow.second ->
|
|
||||||
skippedUpdates.add(manga to context.getString(R.string.skipped_reason_not_in_release_period))
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
try {
|
|
||||||
val newChapters = updateManga(manga, fetchWindow)
|
|
||||||
.sortedByDescending { it.sourceOrder }
|
|
||||||
|
|
||||||
if (newChapters.isNotEmpty()) {
|
|
||||||
val categoryIds = getCategories.await(manga.id).map { it.id }
|
|
||||||
if (manga.shouldDownloadNewChapters(categoryIds, downloadPreferences)) {
|
|
||||||
downloadChapters(manga, newChapters)
|
|
||||||
hasDownloads.set(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
libraryPreferences.newUpdatesCount().getAndSet { it + newChapters.size }
|
|
||||||
|
|
||||||
// Convert to the manga that contains new chapters
|
|
||||||
newUpdates.add(manga to newChapters.toTypedArray())
|
|
||||||
}
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
val errorMessage = when (e) {
|
|
||||||
is NoChaptersException -> context.getString(R.string.no_chapters_error)
|
|
||||||
// failedUpdates will already have the source, don't need to copy it into the message
|
|
||||||
is SourceNotInstalledException -> context.getString(R.string.loader_not_implemented_error)
|
|
||||||
else -> e.message
|
|
||||||
}
|
|
||||||
failedUpdates.add(manga to errorMessage)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
libraryPreferences.newUpdatesCount().getAndSet { it + newChapters.size }
|
||||||
|
|
||||||
|
// Convert to the manga that contains new chapters
|
||||||
|
newUpdates.add(manga to newChapters.toTypedArray())
|
||||||
}
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
val errorMessage = when (e) {
|
||||||
|
is NoChaptersException -> context.getString(R.string.no_chapters_error)
|
||||||
|
// failedUpdates will already have the source, don't need to copy it into the message
|
||||||
|
is SourceNotInstalledException -> context.getString(R.string.loader_not_implemented_error)
|
||||||
|
else -> e.message
|
||||||
|
}
|
||||||
|
failedUpdates.add(manga to errorMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (libraryPreferences.autoUpdateTrackers().get()) {
|
if (libraryPreferences.autoUpdateTrackers().get()) {
|
||||||
|
@ -309,16 +332,6 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||||
errorFile.getUriCompat(context),
|
errorFile.getUriCompat(context),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (skippedUpdates.isNotEmpty()) {
|
|
||||||
// TODO: surface skipped reasons to user
|
|
||||||
logcat {
|
|
||||||
skippedUpdates
|
|
||||||
.groupBy { it.second }
|
|
||||||
.map { (reason, entries) -> "$reason: [${entries.map { it.first.title }.sorted().joinToString()}]" }
|
|
||||||
.joinToString()
|
|
||||||
}
|
|
||||||
notifier.showUpdateSkippedNotification(skippedUpdates.size)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun downloadChapters(manga: Manga, chapters: List<Chapter>) {
|
private fun downloadChapters(manga: Manga, chapters: List<Chapter>) {
|
||||||
|
@ -428,29 +441,27 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||||
completed: AtomicInteger,
|
completed: AtomicInteger,
|
||||||
manga: Manga,
|
manga: Manga,
|
||||||
block: suspend () -> Unit,
|
block: suspend () -> Unit,
|
||||||
) {
|
) = coroutineScope {
|
||||||
coroutineScope {
|
ensureActive()
|
||||||
ensureActive()
|
|
||||||
|
|
||||||
updatingManga.add(manga)
|
updatingManga.add(manga)
|
||||||
notifier.showProgressNotification(
|
notifier.showProgressNotification(
|
||||||
updatingManga,
|
updatingManga,
|
||||||
completed.get(),
|
completed.get(),
|
||||||
mangaToUpdate.size,
|
mangaToUpdate.size,
|
||||||
)
|
)
|
||||||
|
|
||||||
block()
|
block()
|
||||||
|
|
||||||
ensureActive()
|
ensureActive()
|
||||||
|
|
||||||
updatingManga.remove(manga)
|
updatingManga.remove(manga)
|
||||||
completed.getAndIncrement()
|
completed.getAndIncrement()
|
||||||
notifier.showProgressNotification(
|
notifier.showProgressNotification(
|
||||||
updatingManga,
|
updatingManga,
|
||||||
completed.get(),
|
completed.get(),
|
||||||
mangaToUpdate.size,
|
mangaToUpdate.size,
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -30,10 +30,14 @@ import tachiyomi.core.util.lang.launchUI
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.text.NumberFormat
|
||||||
|
|
||||||
class LibraryUpdateNotifier(private val context: Context) {
|
class LibraryUpdateNotifier(private val context: Context) {
|
||||||
|
|
||||||
private val preferences: SecurityPreferences by injectLazy()
|
private val preferences: SecurityPreferences by injectLazy()
|
||||||
|
private val percentFormatter = NumberFormat.getPercentInstance().apply {
|
||||||
|
maximumFractionDigits = 0
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pending intent of action that cancels the library update
|
* Pending intent of action that cancels the library update
|
||||||
|
@ -78,7 +82,7 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||||
} else {
|
} else {
|
||||||
val updatingText = manga.joinToString("\n") { it.title.chop(40) }
|
val updatingText = manga.joinToString("\n") { it.title.chop(40) }
|
||||||
progressNotificationBuilder
|
progressNotificationBuilder
|
||||||
.setContentTitle(context.getString(R.string.notification_updating, current, total))
|
.setContentTitle(context.getString(R.string.notification_updating_progress, percentFormatter.format(current.toFloat() / total)))
|
||||||
.setStyle(NotificationCompat.BigTextStyle().bigText(updatingText))
|
.setStyle(NotificationCompat.BigTextStyle().bigText(updatingText))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -837,7 +837,7 @@
|
||||||
|
|
||||||
<!-- Library update service notifications -->
|
<!-- Library update service notifications -->
|
||||||
<string name="notification_check_updates">Checking for new chapters</string>
|
<string name="notification_check_updates">Checking for new chapters</string>
|
||||||
<string name="notification_updating">Updating library… (%1$d/%2$d)</string>
|
<string name="notification_updating_progress">Updating library… (%s)</string>
|
||||||
<string name="notification_size_warning">Large updates harm sources and may lead to slower updates and also increased battery usage. Tap to learn more.</string>
|
<string name="notification_size_warning">Large updates harm sources and may lead to slower updates and also increased battery usage. Tap to learn more.</string>
|
||||||
<string name="notification_new_chapters">New chapters found</string>
|
<string name="notification_new_chapters">New chapters found</string>
|
||||||
<plurals name="notification_new_chapters_summary">
|
<plurals name="notification_new_chapters_summary">
|
||||||
|
|
Reference in a new issue