Cleanup related to fetch interval display

This commit is contained in:
arkon 2023-07-29 10:29:53 -04:00
parent fe90546821
commit 3ad4f1114a
15 changed files with 93 additions and 85 deletions

View file

@ -56,8 +56,8 @@ import tachiyomi.domain.manga.interactor.GetManga
import tachiyomi.domain.manga.interactor.GetMangaWithChapters import tachiyomi.domain.manga.interactor.GetMangaWithChapters
import tachiyomi.domain.manga.interactor.NetworkToLocalManga import tachiyomi.domain.manga.interactor.NetworkToLocalManga
import tachiyomi.domain.manga.interactor.ResetViewerFlags import tachiyomi.domain.manga.interactor.ResetViewerFlags
import tachiyomi.domain.manga.interactor.SetFetchInterval
import tachiyomi.domain.manga.interactor.SetMangaChapterFlags import tachiyomi.domain.manga.interactor.SetMangaChapterFlags
import tachiyomi.domain.manga.interactor.SetMangaUpdateInterval
import tachiyomi.domain.manga.repository.MangaRepository import tachiyomi.domain.manga.repository.MangaRepository
import tachiyomi.domain.release.interactor.GetApplicationRelease import tachiyomi.domain.release.interactor.GetApplicationRelease
import tachiyomi.domain.release.service.ReleaseService import tachiyomi.domain.release.service.ReleaseService
@ -101,7 +101,7 @@ class DomainModule : InjektModule {
addFactory { GetNextChapters(get(), get(), get()) } addFactory { GetNextChapters(get(), get(), get()) }
addFactory { ResetViewerFlags(get()) } addFactory { ResetViewerFlags(get()) }
addFactory { SetMangaChapterFlags(get()) } addFactory { SetMangaChapterFlags(get()) }
addFactory { SetMangaUpdateInterval(get()) } addFactory { SetFetchInterval(get()) }
addFactory { SetMangaDefaultChapterFlags(get(), get(), get()) } addFactory { SetMangaDefaultChapterFlags(get(), get(), get()) }
addFactory { SetMangaViewerFlags(get()) } addFactory { SetMangaViewerFlags(get()) }
addFactory { NetworkToLocalManga(get()) } addFactory { NetworkToLocalManga(get()) }

View file

@ -138,7 +138,7 @@ class SyncChaptersWithSource(
// Return if there's nothing to add, delete or change, avoiding unnecessary db transactions. // Return if there's nothing to add, delete or change, avoiding unnecessary db transactions.
if (toAdd.isEmpty() && toDelete.isEmpty() && toChange.isEmpty()) { if (toAdd.isEmpty() && toDelete.isEmpty() && toChange.isEmpty()) {
if (manualFetch || manga.calculateInterval == 0 || manga.nextUpdate < fetchRange.first) { if (manualFetch || manga.fetchInterval == 0 || manga.nextUpdate < fetchRange.first) {
updateManga.awaitUpdateFetchInterval( updateManga.awaitUpdateFetchInterval(
manga, manga,
dbChapters, dbChapters,

View file

@ -4,7 +4,7 @@ import eu.kanade.domain.manga.model.hasCustomCover
import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.model.Chapter
import tachiyomi.domain.manga.interactor.SetMangaUpdateInterval import tachiyomi.domain.manga.interactor.SetFetchInterval
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.manga.model.MangaUpdate import tachiyomi.domain.manga.model.MangaUpdate
import tachiyomi.domain.manga.repository.MangaRepository import tachiyomi.domain.manga.repository.MangaRepository
@ -16,7 +16,7 @@ import java.util.Date
class UpdateManga( class UpdateManga(
private val mangaRepository: MangaRepository, private val mangaRepository: MangaRepository,
private val setMangaUpdateInterval: SetMangaUpdateInterval, private val setFetchInterval: SetFetchInterval,
) { ) {
suspend fun await(mangaUpdate: MangaUpdate): Boolean { suspend fun await(mangaUpdate: MangaUpdate): Boolean {
@ -81,9 +81,9 @@ class UpdateManga(
manga: Manga, manga: Manga,
chapters: List<Chapter>, chapters: List<Chapter>,
zonedDateTime: ZonedDateTime = ZonedDateTime.now(), zonedDateTime: ZonedDateTime = ZonedDateTime.now(),
fetchRange: Pair<Long, Long> = setMangaUpdateInterval.getCurrentFetchRange(zonedDateTime), fetchRange: Pair<Long, Long> = setFetchInterval.getCurrent(zonedDateTime),
): Boolean { ): Boolean {
val updatedManga = setMangaUpdateInterval.updateInterval(manga, chapters, zonedDateTime, fetchRange) val updatedManga = setFetchInterval.update(manga, chapters, zonedDateTime, fetchRange)
return if (updatedManga != null) { return if (updatedManga != null) {
mangaRepository.update(updatedManga) mangaRepository.update(updatedManga)
} else { } else {

View file

@ -62,6 +62,7 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.source.getNameForMangaInfo import eu.kanade.tachiyomi.source.getNameForMangaInfo
import eu.kanade.tachiyomi.ui.manga.ChapterItem import eu.kanade.tachiyomi.ui.manga.ChapterItem
import eu.kanade.tachiyomi.ui.manga.FetchInterval
import eu.kanade.tachiyomi.ui.manga.MangaScreenModel import eu.kanade.tachiyomi.ui.manga.MangaScreenModel
import eu.kanade.tachiyomi.util.lang.toRelativeString import eu.kanade.tachiyomi.util.lang.toRelativeString
import eu.kanade.tachiyomi.util.system.copyToClipboard import eu.kanade.tachiyomi.util.system.copyToClipboard
@ -84,7 +85,7 @@ import java.util.Date
fun MangaScreen( fun MangaScreen(
state: MangaScreenModel.State.Success, state: MangaScreenModel.State.Success,
snackbarHostState: SnackbarHostState, snackbarHostState: SnackbarHostState,
intervalDisplay: () -> Pair<Int, Int>?, fetchInterval: FetchInterval?,
dateFormat: DateFormat, dateFormat: DateFormat,
isTabletUi: Boolean, isTabletUi: Boolean,
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
@ -112,7 +113,7 @@ fun MangaScreen(
onShareClicked: (() -> Unit)?, onShareClicked: (() -> Unit)?,
onDownloadActionClicked: ((DownloadAction) -> Unit)?, onDownloadActionClicked: ((DownloadAction) -> Unit)?,
onEditCategoryClicked: (() -> Unit)?, onEditCategoryClicked: (() -> Unit)?,
onEditIntervalClicked: (() -> Unit)?, onEditFetchIntervalClicked: (() -> Unit)?,
onMigrateClicked: (() -> Unit)?, onMigrateClicked: (() -> Unit)?,
// For bottom action menu // For bottom action menu
@ -141,7 +142,7 @@ fun MangaScreen(
state = state, state = state,
snackbarHostState = snackbarHostState, snackbarHostState = snackbarHostState,
dateFormat = dateFormat, dateFormat = dateFormat,
intervalDisplay = intervalDisplay, fetchInterval = fetchInterval,
chapterSwipeStartAction = chapterSwipeStartAction, chapterSwipeStartAction = chapterSwipeStartAction,
chapterSwipeEndAction = chapterSwipeEndAction, chapterSwipeEndAction = chapterSwipeEndAction,
onBackClicked = onBackClicked, onBackClicked = onBackClicked,
@ -161,7 +162,7 @@ fun MangaScreen(
onShareClicked = onShareClicked, onShareClicked = onShareClicked,
onDownloadActionClicked = onDownloadActionClicked, onDownloadActionClicked = onDownloadActionClicked,
onEditCategoryClicked = onEditCategoryClicked, onEditCategoryClicked = onEditCategoryClicked,
onEditIntervalClicked = onEditIntervalClicked, onEditIntervalClicked = onEditFetchIntervalClicked,
onMigrateClicked = onMigrateClicked, onMigrateClicked = onMigrateClicked,
onMultiBookmarkClicked = onMultiBookmarkClicked, onMultiBookmarkClicked = onMultiBookmarkClicked,
onMultiMarkAsReadClicked = onMultiMarkAsReadClicked, onMultiMarkAsReadClicked = onMultiMarkAsReadClicked,
@ -179,7 +180,7 @@ fun MangaScreen(
chapterSwipeStartAction = chapterSwipeStartAction, chapterSwipeStartAction = chapterSwipeStartAction,
chapterSwipeEndAction = chapterSwipeEndAction, chapterSwipeEndAction = chapterSwipeEndAction,
dateFormat = dateFormat, dateFormat = dateFormat,
intervalDisplay = intervalDisplay, fetchInterval = fetchInterval,
onBackClicked = onBackClicked, onBackClicked = onBackClicked,
onChapterClicked = onChapterClicked, onChapterClicked = onChapterClicked,
onDownloadChapter = onDownloadChapter, onDownloadChapter = onDownloadChapter,
@ -197,7 +198,7 @@ fun MangaScreen(
onShareClicked = onShareClicked, onShareClicked = onShareClicked,
onDownloadActionClicked = onDownloadActionClicked, onDownloadActionClicked = onDownloadActionClicked,
onEditCategoryClicked = onEditCategoryClicked, onEditCategoryClicked = onEditCategoryClicked,
onEditIntervalClicked = onEditIntervalClicked, onEditIntervalClicked = onEditFetchIntervalClicked,
onMigrateClicked = onMigrateClicked, onMigrateClicked = onMigrateClicked,
onMultiBookmarkClicked = onMultiBookmarkClicked, onMultiBookmarkClicked = onMultiBookmarkClicked,
onMultiMarkAsReadClicked = onMultiMarkAsReadClicked, onMultiMarkAsReadClicked = onMultiMarkAsReadClicked,
@ -216,7 +217,7 @@ private fun MangaScreenSmallImpl(
state: MangaScreenModel.State.Success, state: MangaScreenModel.State.Success,
snackbarHostState: SnackbarHostState, snackbarHostState: SnackbarHostState,
dateFormat: DateFormat, dateFormat: DateFormat,
intervalDisplay: () -> Pair<Int, Int>?, fetchInterval: FetchInterval?,
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
onBackClicked: () -> Unit, onBackClicked: () -> Unit,
@ -389,8 +390,8 @@ private fun MangaScreenSmallImpl(
MangaActionRow( MangaActionRow(
favorite = state.manga.favorite, favorite = state.manga.favorite,
trackingCount = state.trackingCount, trackingCount = state.trackingCount,
intervalDisplay = intervalDisplay, fetchInterval = fetchInterval,
isUserIntervalMode = state.manga.calculateInterval < 0, isUserIntervalMode = state.manga.fetchInterval < 0,
onAddToLibraryClicked = onAddToLibraryClicked, onAddToLibraryClicked = onAddToLibraryClicked,
onWebViewClicked = onWebViewClicked, onWebViewClicked = onWebViewClicked,
onWebViewLongClicked = onWebViewLongClicked, onWebViewLongClicked = onWebViewLongClicked,
@ -447,7 +448,7 @@ fun MangaScreenLargeImpl(
state: MangaScreenModel.State.Success, state: MangaScreenModel.State.Success,
snackbarHostState: SnackbarHostState, snackbarHostState: SnackbarHostState,
dateFormat: DateFormat, dateFormat: DateFormat,
intervalDisplay: () -> Pair<Int, Int>?, fetchInterval: FetchInterval?,
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
onBackClicked: () -> Unit, onBackClicked: () -> Unit,
@ -605,8 +606,8 @@ fun MangaScreenLargeImpl(
MangaActionRow( MangaActionRow(
favorite = state.manga.favorite, favorite = state.manga.favorite,
trackingCount = state.trackingCount, trackingCount = state.trackingCount,
intervalDisplay = intervalDisplay, fetchInterval = fetchInterval,
isUserIntervalMode = state.manga.calculateInterval < 0, isUserIntervalMode = state.manga.fetchInterval < 0,
onAddToLibraryClicked = onAddToLibraryClicked, onAddToLibraryClicked = onAddToLibraryClicked,
onWebViewClicked = onWebViewClicked, onWebViewClicked = onWebViewClicked,
onWebViewLongClicked = onWebViewLongClicked, onWebViewLongClicked = onWebViewLongClicked,

View file

@ -78,6 +78,7 @@ import coil.compose.AsyncImage
import eu.kanade.presentation.components.DropdownMenu import eu.kanade.presentation.components.DropdownMenu
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.ui.manga.FetchInterval
import eu.kanade.tachiyomi.util.system.copyToClipboard import eu.kanade.tachiyomi.util.system.copyToClipboard
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import tachiyomi.presentation.core.components.material.TextButton import tachiyomi.presentation.core.components.material.TextButton
@ -165,7 +166,7 @@ fun MangaActionRow(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
favorite: Boolean, favorite: Boolean,
trackingCount: Int, trackingCount: Int,
intervalDisplay: () -> Pair<Int, Int>?, fetchInterval: FetchInterval?,
isUserIntervalMode: Boolean, isUserIntervalMode: Boolean,
onAddToLibraryClicked: () -> Unit, onAddToLibraryClicked: () -> Unit,
onWebViewClicked: (() -> Unit)?, onWebViewClicked: (() -> Unit)?,
@ -174,7 +175,6 @@ fun MangaActionRow(
onEditIntervalClicked: (() -> Unit)?, onEditIntervalClicked: (() -> Unit)?,
onEditCategory: (() -> Unit)?, onEditCategory: (() -> Unit)?,
) { ) {
val interval: Pair<Int, Int>? = intervalDisplay()
val defaultActionButtonColor = MaterialTheme.colorScheme.onSurface.copy(alpha = .38f) val defaultActionButtonColor = MaterialTheme.colorScheme.onSurface.copy(alpha = .38f)
Row(modifier = modifier.padding(start = 16.dp, top = 8.dp, end = 16.dp)) { Row(modifier = modifier.padding(start = 16.dp, top = 8.dp, end = 16.dp)) {
@ -189,13 +189,14 @@ fun MangaActionRow(
onClick = onAddToLibraryClicked, onClick = onAddToLibraryClicked,
onLongClick = onEditCategory, onLongClick = onEditCategory,
) )
if (onEditIntervalClicked != null && interval != null) { if (onEditIntervalClicked != null && fetchInterval != null) {
val intervalPair = 1.coerceAtLeast(fetchInterval.interval - fetchInterval.leadDays) to (fetchInterval.interval + fetchInterval.followDays)
MangaActionButton( MangaActionButton(
title = title =
if (interval.first == interval.second) { if (intervalPair.first == intervalPair.second) {
pluralStringResource(id = R.plurals.day, count = interval.second, interval.second) pluralStringResource(id = R.plurals.day, count = intervalPair.second, intervalPair.second)
} else { } else {
pluralStringResource(id = R.plurals.range_interval_day, count = interval.second, interval.first, interval.second) pluralStringResource(id = R.plurals.range_interval_day, count = intervalPair.second, intervalPair.first, intervalPair.second)
}, },
icon = Icons.Default.HourglassEmpty, icon = Icons.Default.HourglassEmpty,
color = if (isUserIntervalMode) MaterialTheme.colorScheme.primary else defaultActionButtonColor, color = if (isUserIntervalMode) MaterialTheme.colorScheme.primary else defaultActionButtonColor,

View file

@ -14,7 +14,7 @@ import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.model.Chapter
import tachiyomi.domain.chapter.repository.ChapterRepository import tachiyomi.domain.chapter.repository.ChapterRepository
import tachiyomi.domain.manga.interactor.SetMangaUpdateInterval import tachiyomi.domain.manga.interactor.SetFetchInterval
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.track.model.Track import tachiyomi.domain.track.model.Track
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
@ -31,10 +31,10 @@ class BackupRestorer(
) { ) {
private val updateManga: UpdateManga = Injekt.get() private val updateManga: UpdateManga = Injekt.get()
private val chapterRepository: ChapterRepository = Injekt.get() private val chapterRepository: ChapterRepository = Injekt.get()
private val setMangaUpdateInterval: SetMangaUpdateInterval = Injekt.get() private val setFetchInterval: SetFetchInterval = Injekt.get()
private var zonedDateTime = ZonedDateTime.now() private var zonedDateTime = ZonedDateTime.now()
private var currentRange = setMangaUpdateInterval.getCurrentFetchRange(zonedDateTime) private var currentFetchInterval = setFetchInterval.getCurrent(zonedDateTime)
private var backupManager = BackupManager(context) private var backupManager = BackupManager(context)
@ -103,7 +103,7 @@ class BackupRestorer(
val backupMaps = backup.backupBrokenSources.map { BackupSource(it.name, it.sourceId) } + backup.backupSources val backupMaps = backup.backupBrokenSources.map { BackupSource(it.name, it.sourceId) } + backup.backupSources
sourceMapping = backupMaps.associate { it.sourceId to it.name } sourceMapping = backupMaps.associate { it.sourceId to it.name }
zonedDateTime = ZonedDateTime.now() zonedDateTime = ZonedDateTime.now()
currentRange = setMangaUpdateInterval.getCurrentFetchRange(zonedDateTime) currentFetchInterval = setFetchInterval.getCurrent(zonedDateTime)
return coroutineScope { return coroutineScope {
// Restore individual manga // Restore individual manga
@ -147,7 +147,7 @@ class BackupRestorer(
restoreNewManga(updatedManga, chapters, categories, history, tracks, backupCategories) restoreNewManga(updatedManga, chapters, categories, history, tracks, backupCategories)
} }
val updatedChapters = chapterRepository.getChapterByMangaId(restoredManga.id) val updatedChapters = chapterRepository.getChapterByMangaId(restoredManga.id)
updateManga.awaitUpdateFetchInterval(restoredManga, updatedChapters, zonedDateTime, currentRange) updateManga.awaitUpdateFetchInterval(restoredManga, updatedChapters, zonedDateTime, currentFetchInterval)
} catch (e: Exception) { } catch (e: Exception) {
val sourceName = sourceMapping[manga.source] ?: manga.source.toString() val sourceName = sourceMapping[manga.source] ?: manga.source.toString()
errors.add(Date() to "${manga.title} [$sourceName]: ${e.message}") errors.add(Date() to "${manga.title} [$sourceName]: ${e.message}")

View file

@ -69,7 +69,7 @@ import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_R
import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_OUTSIDE_RELEASE_PERIOD import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_OUTSIDE_RELEASE_PERIOD
import tachiyomi.domain.manga.interactor.GetLibraryManga import tachiyomi.domain.manga.interactor.GetLibraryManga
import tachiyomi.domain.manga.interactor.GetManga import tachiyomi.domain.manga.interactor.GetManga
import tachiyomi.domain.manga.interactor.SetMangaUpdateInterval import tachiyomi.domain.manga.interactor.SetFetchInterval
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.manga.model.toMangaUpdate import tachiyomi.domain.manga.model.toMangaUpdate
import tachiyomi.domain.source.model.SourceNotInstalledException import tachiyomi.domain.source.model.SourceNotInstalledException
@ -104,7 +104,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
private val getTracks: GetTracks = Injekt.get() private val getTracks: GetTracks = Injekt.get()
private val insertTrack: InsertTrack = Injekt.get() private val insertTrack: InsertTrack = Injekt.get()
private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay = Injekt.get() private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay = Injekt.get()
private val setMangaUpdateInterval: SetMangaUpdateInterval = Injekt.get() private val setFetchInterval: SetFetchInterval = Injekt.get()
private val notifier = LibraryUpdateNotifier(context) private val notifier = LibraryUpdateNotifier(context)
@ -232,8 +232,8 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
val restrictions = libraryPreferences.libraryUpdateMangaRestriction().get() val restrictions = libraryPreferences.libraryUpdateMangaRestriction().get()
val now = ZonedDateTime.now() val now = ZonedDateTime.now()
val fetchRange = setMangaUpdateInterval.getCurrentFetchRange(now) val fetchInterval = setFetchInterval.getCurrent(now)
val higherLimit = fetchRange.second val higherLimit = fetchInterval.second
coroutineScope { coroutineScope {
mangaToUpdate.groupBy { it.manga.source }.values mangaToUpdate.groupBy { it.manga.source }.values
@ -272,7 +272,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
else -> { else -> {
try { try {
val newChapters = updateManga(manga, now, fetchRange) val newChapters = updateManga(manga, now, fetchInterval)
.sortedByDescending { it.sourceOrder } .sortedByDescending { it.sourceOrder }
if (newChapters.isNotEmpty()) { if (newChapters.isNotEmpty()) {

View file

@ -83,6 +83,13 @@ class MangaScreen(
val successState = state as MangaScreenModel.State.Success val successState = state as MangaScreenModel.State.Success
val isHttpSource = remember { successState.source is HttpSource } val isHttpSource = remember { successState.source is HttpSource }
val fetchInterval = remember(successState.manga.fetchInterval) {
FetchInterval(
interval = successState.manga.fetchInterval,
leadDays = screenModel.leadDay,
followDays = screenModel.followDay,
)
}
LaunchedEffect(successState.manga, screenModel.source) { LaunchedEffect(successState.manga, screenModel.source) {
if (isHttpSource) { if (isHttpSource) {
@ -100,7 +107,7 @@ class MangaScreen(
state = successState, state = successState,
snackbarHostState = screenModel.snackbarHostState, snackbarHostState = screenModel.snackbarHostState,
dateFormat = screenModel.dateFormat, dateFormat = screenModel.dateFormat,
intervalDisplay = screenModel::intervalDisplay, fetchInterval = fetchInterval,
isTabletUi = isTabletUi(), isTabletUi = isTabletUi(),
chapterSwipeStartAction = screenModel.chapterSwipeStartAction, chapterSwipeStartAction = screenModel.chapterSwipeStartAction,
chapterSwipeEndAction = screenModel.chapterSwipeEndAction, chapterSwipeEndAction = screenModel.chapterSwipeEndAction,
@ -123,7 +130,7 @@ class MangaScreen(
onShareClicked = { shareManga(context, screenModel.manga, screenModel.source) }.takeIf { isHttpSource }, onShareClicked = { shareManga(context, screenModel.manga, screenModel.source) }.takeIf { isHttpSource },
onDownloadActionClicked = screenModel::runDownloadAction.takeIf { !successState.source.isLocalOrStub() }, onDownloadActionClicked = screenModel::runDownloadAction.takeIf { !successState.source.isLocalOrStub() },
onEditCategoryClicked = screenModel::showChangeCategoryDialog.takeIf { successState.manga.favorite }, onEditCategoryClicked = screenModel::showChangeCategoryDialog.takeIf { successState.manga.favorite },
onEditIntervalClicked = screenModel::showSetMangaIntervalDialog.takeIf { screenModel.isIntervalEnabled && successState.manga.favorite }, onEditFetchIntervalClicked = screenModel::showSetFetchIntervalDialog.takeIf { screenModel.isUpdateIntervalEnabled && successState.manga.favorite },
onMigrateClicked = { navigator.push(MigrateSearchScreen(successState.manga.id)) }.takeIf { successState.manga.favorite }, onMigrateClicked = { navigator.push(MigrateSearchScreen(successState.manga.id)) }.takeIf { successState.manga.favorite },
onMultiBookmarkClicked = screenModel::bookmarkChapters, onMultiBookmarkClicked = screenModel::bookmarkChapters,
onMultiMarkAsReadClicked = screenModel::markChaptersRead, onMultiMarkAsReadClicked = screenModel::markChaptersRead,
@ -209,11 +216,11 @@ class MangaScreen(
LoadingScreen(Modifier.systemBarsPadding()) LoadingScreen(Modifier.systemBarsPadding())
} }
} }
is MangaScreenModel.Dialog.SetMangaInterval -> { is MangaScreenModel.Dialog.SetFetchInterval -> {
SetIntervalDialog( SetIntervalDialog(
interval = if (dialog.manga.calculateInterval < 0) -dialog.manga.calculateInterval else 0, interval = if (dialog.manga.fetchInterval < 0) -dialog.manga.fetchInterval else 0,
onDismissRequest = onDismissRequest, onDismissRequest = onDismissRequest,
onValueChanged = { screenModel.setFetchRangeInterval(dialog.manga, it) }, onValueChanged = { screenModel.setFetchInterval(dialog.manga, it) },
) )
} }
} }

View file

@ -75,7 +75,6 @@ import tachiyomi.domain.track.interactor.GetTracks
import tachiyomi.source.local.isLocal import tachiyomi.source.local.isLocal
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import kotlin.math.absoluteValue
class MangaScreenModel( class MangaScreenModel(
val context: Context, val context: Context,
@ -129,9 +128,9 @@ class MangaScreenModel(
val dateFormat by mutableStateOf(UiPreferences.dateFormat(uiPreferences.dateFormat().get())) val dateFormat by mutableStateOf(UiPreferences.dateFormat(uiPreferences.dateFormat().get()))
private val skipFiltered by readerPreferences.skipFiltered().asState(coroutineScope) private val skipFiltered by readerPreferences.skipFiltered().asState(coroutineScope)
val isIntervalEnabled = LibraryPreferences.MANGA_OUTSIDE_RELEASE_PERIOD in libraryPreferences.libraryUpdateMangaRestriction().get() val isUpdateIntervalEnabled = LibraryPreferences.MANGA_OUTSIDE_RELEASE_PERIOD in libraryPreferences.libraryUpdateMangaRestriction().get()
private val leadDay = libraryPreferences.leadingExpectedDays().get() val leadDay = libraryPreferences.leadingExpectedDays().get()
private val followDay = libraryPreferences.followingExpectedDays().get() val followDay = libraryPreferences.followingExpectedDays().get()
private val selectedPositions: Array<Int> = arrayOf(-1, -1) // first and last selected index in list private val selectedPositions: Array<Int> = arrayOf(-1, -1) // first and last selected index in list
private val selectedChapterIds: HashSet<Long> = HashSet() private val selectedChapterIds: HashSet<Long> = HashSet()
@ -355,30 +354,23 @@ class MangaScreenModel(
} }
} }
fun showSetMangaIntervalDialog() { fun showSetFetchIntervalDialog() {
val manga = successState?.manga ?: return val manga = successState?.manga ?: return
updateSuccessState { updateSuccessState {
it.copy(dialog = Dialog.SetMangaInterval(manga)) it.copy(dialog = Dialog.SetFetchInterval(manga))
} }
} }
// TODO: this should be in the state/composables fun setFetchInterval(manga: Manga, newInterval: Int) {
fun intervalDisplay(): Pair<Int, Int>? {
val manga = successState?.manga ?: return null
val effInterval = manga.calculateInterval
return 1.coerceAtLeast(effInterval.absoluteValue - leadDay) to (effInterval.absoluteValue + followDay)
}
fun setFetchRangeInterval(manga: Manga, newInterval: Int) {
val interval = when (newInterval) { val interval = when (newInterval) {
// reset interval 0 default to trigger recalculation // reset interval 0 default to trigger recalculation
// only reset if interval is custom, which is negative // only reset if interval is custom, which is negative
0 -> if (manga.calculateInterval < 0) 0 else manga.calculateInterval 0 -> if (manga.fetchInterval < 0) 0 else manga.fetchInterval
else -> -newInterval else -> -newInterval
} }
coroutineScope.launchIO { coroutineScope.launchIO {
updateManga.awaitUpdateFetchInterval( updateManga.awaitUpdateFetchInterval(
manga.copy(calculateInterval = interval), manga.copy(fetchInterval = interval),
successState?.chapters?.map { it.chapter }.orEmpty(), successState?.chapters?.map { it.chapter }.orEmpty(),
) )
val newManga = mangaRepository.getMangaById(mangaId) val newManga = mangaRepository.getMangaById(mangaId)
@ -983,7 +975,7 @@ class MangaScreenModel(
data class ChangeCategory(val manga: Manga, val initialSelection: List<CheckboxState<Category>>) : Dialog data class ChangeCategory(val manga: Manga, val initialSelection: List<CheckboxState<Category>>) : Dialog
data class DeleteChapters(val chapters: List<Chapter>) : Dialog data class DeleteChapters(val chapters: List<Chapter>) : Dialog
data class DuplicateManga(val manga: Manga, val duplicate: Manga) : Dialog data class DuplicateManga(val manga: Manga, val duplicate: Manga) : Dialog
data class SetMangaInterval(val manga: Manga) : Dialog data class SetFetchInterval(val manga: Manga) : Dialog
data object SettingsSheet : Dialog data object SettingsSheet : Dialog
data object TrackSheet : Dialog data object TrackSheet : Dialog
data object FullCover : Dialog data object FullCover : Dialog
@ -1063,3 +1055,10 @@ data class ChapterItem(
) { ) {
val isDownloaded = downloadState == Download.State.DOWNLOADED val isDownloaded = downloadState == Download.State.DOWNLOADED
} }
@Immutable
data class FetchInterval(
val interval: Int,
val leadDays: Int,
val followDays: Int,
)

View file

@ -12,7 +12,7 @@ val mangaMapper: (Long, Long, String, String?, String?, String?, List<String>?,
favorite = favorite, favorite = favorite,
lastUpdate = lastUpdate ?: 0, lastUpdate = lastUpdate ?: 0,
nextUpdate = nextUpdate ?: 0, nextUpdate = nextUpdate ?: 0,
calculateInterval = calculateInterval.toInt(), fetchInterval = calculateInterval.toInt(),
dateAdded = dateAdded, dateAdded = dateAdded,
viewerFlags = viewerFlags, viewerFlags = viewerFlags,
chapterFlags = chapterFlags, chapterFlags = chapterFlags,

View file

@ -88,7 +88,7 @@ class MangaRepositoryImpl(
favorite = manga.favorite, favorite = manga.favorite,
lastUpdate = manga.lastUpdate, lastUpdate = manga.lastUpdate,
nextUpdate = manga.nextUpdate, nextUpdate = manga.nextUpdate,
calculateInterval = manga.calculateInterval.toLong(), calculateInterval = manga.fetchInterval.toLong(),
initialized = manga.initialized, initialized = manga.initialized,
viewerFlags = manga.viewerFlags, viewerFlags = manga.viewerFlags,
chapterFlags = manga.chapterFlags, chapterFlags = manga.chapterFlags,
@ -136,7 +136,7 @@ class MangaRepositoryImpl(
favorite = value.favorite?.toLong(), favorite = value.favorite?.toLong(),
lastUpdate = value.lastUpdate, lastUpdate = value.lastUpdate,
nextUpdate = value.nextUpdate, nextUpdate = value.nextUpdate,
calculateInterval = value.calculateInterval?.toLong(), calculateInterval = value.fetchInterval?.toLong(),
initialized = value.initialized?.toLong(), initialized = value.initialized?.toLong(),
viewer = value.viewerFlags, viewer = value.viewerFlags,
chapterFlags = value.chapterFlags, chapterFlags = value.chapterFlags,

View file

@ -13,32 +13,32 @@ import kotlin.math.absoluteValue
const val MAX_GRACE_PERIOD = 28 const val MAX_GRACE_PERIOD = 28
class SetMangaUpdateInterval( class SetFetchInterval(
private val libraryPreferences: LibraryPreferences = Injekt.get(), private val libraryPreferences: LibraryPreferences = Injekt.get(),
) { ) {
fun updateInterval( fun update(
manga: Manga, manga: Manga,
chapters: List<Chapter>, chapters: List<Chapter>,
zonedDateTime: ZonedDateTime, zonedDateTime: ZonedDateTime,
fetchRange: Pair<Long, Long>, fetchRange: Pair<Long, Long>,
): MangaUpdate? { ): MangaUpdate? {
val currentFetchRange = if (fetchRange.first == 0L && fetchRange.second == 0L) { val currentInterval = if (fetchRange.first == 0L && fetchRange.second == 0L) {
getCurrentFetchRange(ZonedDateTime.now()) getCurrent(ZonedDateTime.now())
} else { } else {
fetchRange fetchRange
} }
val interval = manga.calculateInterval.takeIf { it < 0 } ?: calculateInterval(chapters, zonedDateTime) val interval = manga.fetchInterval.takeIf { it < 0 } ?: calculateInterval(chapters, zonedDateTime)
val nextUpdate = calculateNextUpdate(manga, interval, zonedDateTime, currentFetchRange) val nextUpdate = calculateNextUpdate(manga, interval, zonedDateTime, currentInterval)
return if (manga.nextUpdate == nextUpdate && manga.calculateInterval == interval) { return if (manga.nextUpdate == nextUpdate && manga.fetchInterval == interval) {
null null
} else { } else {
MangaUpdate(id = manga.id, nextUpdate = nextUpdate, calculateInterval = interval) MangaUpdate(id = manga.id, nextUpdate = nextUpdate, fetchInterval = interval)
} }
} }
fun getCurrentFetchRange(timeToCal: ZonedDateTime): Pair<Long, Long> { fun getCurrent(timeToCal: ZonedDateTime): Pair<Long, Long> {
// lead range and the following range depend on if updateOnlyExpectedPeriod set. // lead range and the following range depend on if updateOnlyExpectedPeriod set.
var followRange = 0 var followRange = 0
var leadRange = 0 var leadRange = 0
@ -103,7 +103,7 @@ class SetMangaUpdateInterval(
): Long { ): Long {
return if ( return if (
manga.nextUpdate !in fetchRange.first.rangeTo(fetchRange.second + 1) || manga.nextUpdate !in fetchRange.first.rangeTo(fetchRange.second + 1) ||
manga.calculateInterval == 0 manga.fetchInterval == 0
) { ) {
val latestDate = ZonedDateTime.ofInstant(Instant.ofEpochMilli(manga.lastUpdate), zonedDateTime.zone).toLocalDate().atStartOfDay() val latestDate = ZonedDateTime.ofInstant(Instant.ofEpochMilli(manga.lastUpdate), zonedDateTime.zone).toLocalDate().atStartOfDay()
val timeSinceLatest = ChronoUnit.DAYS.between(latestDate, zonedDateTime).toInt() val timeSinceLatest = ChronoUnit.DAYS.between(latestDate, zonedDateTime).toInt()

View file

@ -10,7 +10,7 @@ data class Manga(
val favorite: Boolean, val favorite: Boolean,
val lastUpdate: Long, val lastUpdate: Long,
val nextUpdate: Long, val nextUpdate: Long,
val calculateInterval: Int, val fetchInterval: Int,
val dateAdded: Long, val dateAdded: Long,
val viewerFlags: Long, val viewerFlags: Long,
val chapterFlags: Long, val chapterFlags: Long,
@ -99,7 +99,7 @@ data class Manga(
favorite = false, favorite = false,
lastUpdate = 0L, lastUpdate = 0L,
nextUpdate = 0L, nextUpdate = 0L,
calculateInterval = 0, fetchInterval = 0,
dateAdded = 0L, dateAdded = 0L,
viewerFlags = 0L, viewerFlags = 0L,
chapterFlags = 0L, chapterFlags = 0L,

View file

@ -8,7 +8,7 @@ data class MangaUpdate(
val favorite: Boolean? = null, val favorite: Boolean? = null,
val lastUpdate: Long? = null, val lastUpdate: Long? = null,
val nextUpdate: Long? = null, val nextUpdate: Long? = null,
val calculateInterval: Int? = null, val fetchInterval: Int? = null,
val dateAdded: Long? = null, val dateAdded: Long? = null,
val viewerFlags: Long? = null, val viewerFlags: Long? = null,
val chapterFlags: Long? = null, val chapterFlags: Long? = null,
@ -32,7 +32,7 @@ fun Manga.toMangaUpdate(): MangaUpdate {
favorite = favorite, favorite = favorite,
lastUpdate = lastUpdate, lastUpdate = lastUpdate,
nextUpdate = nextUpdate, nextUpdate = nextUpdate,
calculateInterval = calculateInterval, fetchInterval = fetchInterval,
dateAdded = dateAdded, dateAdded = dateAdded,
viewerFlags = viewerFlags, viewerFlags = viewerFlags,
chapterFlags = chapterFlags, chapterFlags = chapterFlags,

View file

@ -10,14 +10,14 @@ import java.time.Duration
import java.time.ZonedDateTime import java.time.ZonedDateTime
@Execution(ExecutionMode.CONCURRENT) @Execution(ExecutionMode.CONCURRENT)
class SetMangaUpdateIntervalTest { class SetFetchIntervalTest {
private val testTime = ZonedDateTime.parse("2020-01-01T00:00:00Z") private val testTime = ZonedDateTime.parse("2020-01-01T00:00:00Z")
private var chapter = Chapter.create().copy( private var chapter = Chapter.create().copy(
dateFetch = testTime.toEpochSecond() * 1000, dateFetch = testTime.toEpochSecond() * 1000,
dateUpload = testTime.toEpochSecond() * 1000, dateUpload = testTime.toEpochSecond() * 1000,
) )
private val setMangaUpdateInterval = SetMangaUpdateInterval(mockk()) private val setFetchInterval = SetFetchInterval(mockk())
private fun chapterAddTime(chapter: Chapter, duration: Duration): Chapter { private fun chapterAddTime(chapter: Chapter, duration: Duration): Chapter {
val newTime = testTime.plus(duration).toEpochSecond() * 1000 val newTime = testTime.plus(duration).toEpochSecond() * 1000
@ -33,7 +33,7 @@ class SetMangaUpdateIntervalTest {
val newChapter = chapterAddTime(chapter, duration) val newChapter = chapterAddTime(chapter, duration)
chapters.add(newChapter) chapters.add(newChapter)
} }
setMangaUpdateInterval.calculateInterval(chapters, testTime) shouldBe 7 setFetchInterval.calculateInterval(chapters, testTime) shouldBe 7
} }
@Test @Test
@ -44,7 +44,7 @@ class SetMangaUpdateIntervalTest {
val newChapter = chapterAddTime(chapter, duration) val newChapter = chapterAddTime(chapter, duration)
chapters.add(newChapter) chapters.add(newChapter)
} }
setMangaUpdateInterval.calculateInterval(chapters, testTime) shouldBe 7 setFetchInterval.calculateInterval(chapters, testTime) shouldBe 7
} }
@Test @Test
@ -60,7 +60,7 @@ class SetMangaUpdateIntervalTest {
val newChapter = chapterAddTime(chapter, duration) val newChapter = chapterAddTime(chapter, duration)
chapters.add(newChapter) chapters.add(newChapter)
} }
setMangaUpdateInterval.calculateInterval(chapters, testTime) shouldBe 7 setFetchInterval.calculateInterval(chapters, testTime) shouldBe 7
} }
// Default 1 if interval less than 1 // Default 1 if interval less than 1
@ -72,7 +72,7 @@ class SetMangaUpdateIntervalTest {
val newChapter = chapterAddTime(chapter, duration) val newChapter = chapterAddTime(chapter, duration)
chapters.add(newChapter) chapters.add(newChapter)
} }
setMangaUpdateInterval.calculateInterval(chapters, testTime) shouldBe 1 setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1
} }
// Normal interval calculation // Normal interval calculation
@ -84,7 +84,7 @@ class SetMangaUpdateIntervalTest {
val newChapter = chapterAddTime(chapter, duration) val newChapter = chapterAddTime(chapter, duration)
chapters.add(newChapter) chapters.add(newChapter)
} }
setMangaUpdateInterval.calculateInterval(chapters, testTime) shouldBe 1 setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1
} }
@Test @Test
@ -95,7 +95,7 @@ class SetMangaUpdateIntervalTest {
val newChapter = chapterAddTime(chapter, duration) val newChapter = chapterAddTime(chapter, duration)
chapters.add(newChapter) chapters.add(newChapter)
} }
setMangaUpdateInterval.calculateInterval(chapters, testTime) shouldBe 2 setFetchInterval.calculateInterval(chapters, testTime) shouldBe 2
} }
// If interval is decimal, floor to closest integer // If interval is decimal, floor to closest integer
@ -107,7 +107,7 @@ class SetMangaUpdateIntervalTest {
val newChapter = chapterAddTime(chapter, duration) val newChapter = chapterAddTime(chapter, duration)
chapters.add(newChapter) chapters.add(newChapter)
} }
setMangaUpdateInterval.calculateInterval(chapters, testTime) shouldBe 1 setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1
} }
@Test @Test
@ -118,7 +118,7 @@ class SetMangaUpdateIntervalTest {
val newChapter = chapterAddTime(chapter, duration) val newChapter = chapterAddTime(chapter, duration)
chapters.add(newChapter) chapters.add(newChapter)
} }
setMangaUpdateInterval.calculateInterval(chapters, testTime) shouldBe 1 setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1
} }
// Use fetch time if upload time not available // Use fetch time if upload time not available
@ -130,6 +130,6 @@ class SetMangaUpdateIntervalTest {
val newChapter = chapterAddTime(chapter, duration).copy(dateUpload = 0L) val newChapter = chapterAddTime(chapter, duration).copy(dateUpload = 0L)
chapters.add(newChapter) chapters.add(newChapter)
} }
setMangaUpdateInterval.calculateInterval(chapters, testTime) shouldBe 1 setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1
} }
} }