diff --git a/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt b/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt index a3592e1f4..d5cfc248d 100644 --- a/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt +++ b/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt @@ -81,9 +81,9 @@ class UpdateManga( dateTime: ZonedDateTime = ZonedDateTime.now(), window: Pair = fetchInterval.getWindow(dateTime), ): Boolean { - return fetchInterval.toMangaUpdateOrNull(manga, dateTime, window) - ?.let { mangaRepository.update(it) } - ?: false + return mangaRepository.update( + fetchInterval.toMangaUpdate(manga, dateTime, window), + ) } suspend fun awaitUpdateLastUpdate(mangaId: Long): Boolean { diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt index 655601a0a..a6ef3f9a5 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt @@ -30,6 +30,7 @@ import tachiyomi.presentation.core.i18n.pluralStringResource import tachiyomi.presentation.core.i18n.stringResource import java.time.Instant import java.time.temporal.ChronoUnit +import kotlin.math.absoluteValue @Composable fun DeleteChaptersDialog( @@ -85,7 +86,7 @@ fun SetIntervalDialog( title = { Text(stringResource(MR.strings.pref_library_update_smart_update)) }, text = { Column { - if (nextUpdateDays != null && nextUpdateDays >= 0) { + if (nextUpdateDays != null && nextUpdateDays >= 0 && interval >= 0) { Text( stringResource( MR.strings.manga_interval_expected_update, @@ -96,8 +97,8 @@ fun SetIntervalDialog( ), pluralStringResource( MR.plurals.day, - count = interval, - interval, + count = interval.absoluteValue, + interval.absoluteValue, ), ), ) @@ -105,7 +106,6 @@ fun SetIntervalDialog( Spacer(Modifier.height(MaterialTheme.padding.small)) } - // TODO: selecting "1" then doesn't allow for future changes unless defaulting first? if (onValueChanged != null && (isDevFlavor || isPreviewBuildType)) { Text(stringResource(MR.strings.manga_interval_custom_amount)) diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt index f1d228534..0ad66a9a8 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt @@ -201,14 +201,14 @@ fun MangaActionRow( onLongClick = onEditCategory, ) MangaActionButton( - title = if (nextUpdateDays != null) { - pluralStringResource( + title = when (nextUpdateDays) { + null -> stringResource(MR.strings.not_applicable) + 0 -> stringResource(MR.strings.manga_interval_expected_update_soon) + else -> pluralStringResource( MR.plurals.day, count = nextUpdateDays, nextUpdateDays, ) - } else { - stringResource(MR.strings.not_applicable) }, icon = Icons.Default.HourglassEmpty, color = if (isUserIntervalMode) MaterialTheme.colorScheme.primary else defaultActionButtonColor, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt index e7446e600..ae61519ee 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt @@ -378,12 +378,15 @@ class MangaScreenModel( fun setFetchInterval(manga: Manga, interval: Int) { screenModelScope.launchIO { - updateManga.awaitUpdateFetchInterval( - // Custom intervals are negative - manga.copy(fetchInterval = -interval), - ) - val updatedManga = mangaRepository.getMangaById(manga.id) - updateSuccessState { it.copy(manga = updatedManga) } + if ( + updateManga.awaitUpdateFetchInterval( + // Custom intervals are negative + manga.copy(fetchInterval = -interval), + ) + ) { + val updatedManga = mangaRepository.getMangaById(manga.id) + updateSuccessState { it.copy(manga = updatedManga) } + } } } diff --git a/domain/src/main/java/tachiyomi/domain/manga/interactor/FetchInterval.kt b/domain/src/main/java/tachiyomi/domain/manga/interactor/FetchInterval.kt index 6c8413a75..f77f34a7e 100644 --- a/domain/src/main/java/tachiyomi/domain/manga/interactor/FetchInterval.kt +++ b/domain/src/main/java/tachiyomi/domain/manga/interactor/FetchInterval.kt @@ -14,11 +14,11 @@ class FetchInterval( private val getChaptersByMangaId: GetChaptersByMangaId, ) { - suspend fun toMangaUpdateOrNull( + suspend fun toMangaUpdate( manga: Manga, dateTime: ZonedDateTime, window: Pair, - ): MangaUpdate? { + ): MangaUpdate { val interval = manga.fetchInterval.takeIf { it < 0 } ?: calculateInterval( chapters = getChaptersByMangaId.await(manga.id, applyScanlatorFilter = true), zone = dateTime.zone, @@ -30,11 +30,7 @@ class FetchInterval( } val nextUpdate = calculateNextUpdate(manga, interval, dateTime, currentWindow) - return if (manga.nextUpdate == nextUpdate && manga.fetchInterval == interval) { - null - } else { - MangaUpdate(id = manga.id, nextUpdate = nextUpdate, fetchInterval = interval) - } + return MangaUpdate(id = manga.id, nextUpdate = nextUpdate, fetchInterval = interval) } fun getWindow(dateTime: ZonedDateTime): Pair { @@ -96,34 +92,31 @@ class FetchInterval( dateTime: ZonedDateTime, window: Pair, ): Long { - return if ( - manga.nextUpdate !in window.first.rangeTo(window.second + 1) || - manga.fetchInterval == 0 - ) { - val latestDate = ZonedDateTime.ofInstant( - if (manga.lastUpdate > 0) Instant.ofEpochMilli(manga.lastUpdate) else Instant.now(), - dateTime.zone, - ) - .toLocalDate() - .atStartOfDay() - val timeSinceLatest = ChronoUnit.DAYS.between(latestDate, dateTime).toInt() - val cycle = timeSinceLatest.floorDiv( - interval.absoluteValue.takeIf { interval < 0 } - ?: doubleInterval(interval, timeSinceLatest, doubleWhenOver = 10), - ) - latestDate.plusDays((cycle + 1) * interval.toLong()).toEpochSecond(dateTime.offset) * 1000 - } else { - manga.nextUpdate + if (manga.nextUpdate in window.first.rangeTo(window.second + 1)) { + return manga.nextUpdate } + + val latestDate = ZonedDateTime.ofInstant( + if (manga.lastUpdate > 0) Instant.ofEpochMilli(manga.lastUpdate) else Instant.now(), + dateTime.zone, + ) + .toLocalDate() + .atStartOfDay() + val timeSinceLatest = ChronoUnit.DAYS.between(latestDate, dateTime).toInt() + val cycle = timeSinceLatest.floorDiv( + interval.absoluteValue.takeIf { interval < 0 } + ?: increaseInterval(interval, timeSinceLatest, increaseWhenOver = 10), + ) + return latestDate.plusDays((cycle + 1) * interval.toLong()).toEpochSecond(dateTime.offset) * 1000 } - private fun doubleInterval(delta: Int, timeSinceLatest: Int, doubleWhenOver: Int): Int { + private fun increaseInterval(delta: Int, timeSinceLatest: Int, increaseWhenOver: Int): Int { if (delta >= MAX_INTERVAL) return MAX_INTERVAL // double delta again if missed more than 9 check in new delta val cycle = timeSinceLatest.floorDiv(delta) + 1 - return if (cycle > doubleWhenOver) { - doubleInterval(delta * 2, timeSinceLatest, doubleWhenOver) + return if (cycle > increaseWhenOver) { + increaseInterval(delta * 2, timeSinceLatest, increaseWhenOver) } else { delta } diff --git a/i18n/src/commonMain/resources/MR/base/strings.xml b/i18n/src/commonMain/resources/MR/base/strings.xml index 24b29f303..ff02bcf34 100644 --- a/i18n/src/commonMain/resources/MR/base/strings.xml +++ b/i18n/src/commonMain/resources/MR/base/strings.xml @@ -683,9 +683,9 @@ Chapter %1$s Estimate every Set to update every - Next update - Next update expected in around %1$s, checking around every %2$s + New chapters predicted to be released in around %1$s, checking around every %2$s. + Soon Custom update frequency: Downloading (%1$d/%2$d) Error