mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-23 21:27:40 +03:00
parent
1b6301cc95
commit
a2a445fdc5
69 changed files with 445 additions and 325 deletions
|
@ -177,6 +177,7 @@ dependencies {
|
|||
implementation(androidx.paging.compose)
|
||||
|
||||
implementation(libs.bundles.sqlite)
|
||||
implementation(libs.sqldelight.primitive.adapters)
|
||||
|
||||
implementation(kotlinx.reflect)
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ import tachiyomi.domain.entries.anime.interactor.GetLibraryAnime
|
|||
import tachiyomi.domain.entries.anime.interactor.NetworkToLocalAnime
|
||||
import tachiyomi.domain.entries.anime.interactor.ResetAnimeViewerFlags
|
||||
import tachiyomi.domain.entries.anime.interactor.SetAnimeEpisodeFlags
|
||||
import tachiyomi.domain.entries.anime.interactor.SetAnimeUpdateInterval
|
||||
import tachiyomi.domain.entries.anime.interactor.SetAnimeFetchInterval
|
||||
import tachiyomi.domain.entries.anime.repository.AnimeRepository
|
||||
import tachiyomi.domain.entries.manga.interactor.GetDuplicateLibraryManga
|
||||
import tachiyomi.domain.entries.manga.interactor.GetLibraryManga
|
||||
|
@ -91,7 +91,7 @@ import tachiyomi.domain.entries.manga.interactor.GetMangaWithChapters
|
|||
import tachiyomi.domain.entries.manga.interactor.NetworkToLocalManga
|
||||
import tachiyomi.domain.entries.manga.interactor.ResetMangaViewerFlags
|
||||
import tachiyomi.domain.entries.manga.interactor.SetMangaChapterFlags
|
||||
import tachiyomi.domain.entries.manga.interactor.SetMangaUpdateInterval
|
||||
import tachiyomi.domain.entries.manga.interactor.SetMangaFetchInterval
|
||||
import tachiyomi.domain.entries.manga.repository.MangaRepository
|
||||
import tachiyomi.domain.history.anime.interactor.GetAnimeHistory
|
||||
import tachiyomi.domain.history.anime.interactor.GetNextEpisodes
|
||||
|
@ -184,7 +184,7 @@ class DomainModule : InjektModule {
|
|||
addFactory { GetNextEpisodes(get(), get(), get()) }
|
||||
addFactory { ResetAnimeViewerFlags(get()) }
|
||||
addFactory { SetAnimeEpisodeFlags(get()) }
|
||||
addFactory { SetAnimeUpdateInterval(get()) }
|
||||
addFactory { SetAnimeFetchInterval(get()) }
|
||||
addFactory { SetAnimeDefaultEpisodeFlags(get(), get(), get()) }
|
||||
addFactory { SetAnimeViewerFlags(get()) }
|
||||
addFactory { NetworkToLocalAnime(get()) }
|
||||
|
@ -200,7 +200,7 @@ class DomainModule : InjektModule {
|
|||
addFactory { GetNextChapters(get(), get(), get()) }
|
||||
addFactory { ResetMangaViewerFlags(get()) }
|
||||
addFactory { SetMangaChapterFlags(get()) }
|
||||
addFactory { SetMangaUpdateInterval(get()) }
|
||||
addFactory { SetMangaFetchInterval(get()) }
|
||||
addFactory {
|
||||
SetMangaDefaultChapterFlags(
|
||||
get(),
|
||||
|
|
|
@ -3,7 +3,7 @@ package eu.kanade.domain.entries.anime.interactor
|
|||
import eu.kanade.domain.entries.anime.model.hasCustomCover
|
||||
import eu.kanade.tachiyomi.animesource.model.SAnime
|
||||
import eu.kanade.tachiyomi.data.cache.AnimeCoverCache
|
||||
import tachiyomi.domain.entries.anime.interactor.SetAnimeUpdateInterval
|
||||
import tachiyomi.domain.entries.anime.interactor.SetAnimeFetchInterval
|
||||
import tachiyomi.domain.entries.anime.model.Anime
|
||||
import tachiyomi.domain.entries.anime.model.AnimeUpdate
|
||||
import tachiyomi.domain.entries.anime.repository.AnimeRepository
|
||||
|
@ -16,7 +16,7 @@ import java.util.Date
|
|||
|
||||
class UpdateAnime(
|
||||
private val animeRepository: AnimeRepository,
|
||||
private val setAnimeUpdateInterval: SetAnimeUpdateInterval,
|
||||
private val setAnimeFetchInterval: SetAnimeFetchInterval,
|
||||
) {
|
||||
|
||||
suspend fun await(animeUpdate: AnimeUpdate): Boolean {
|
||||
|
@ -81,9 +81,9 @@ class UpdateAnime(
|
|||
anime: Anime,
|
||||
episodes: List<Episode>,
|
||||
zonedDateTime: ZonedDateTime = ZonedDateTime.now(),
|
||||
fetchRange: Pair<Long, Long> = setAnimeUpdateInterval.getCurrentFetchRange(zonedDateTime),
|
||||
fetchRange: Pair<Long, Long> = setAnimeFetchInterval.getCurrent(zonedDateTime),
|
||||
): Boolean {
|
||||
val updateAnime = setAnimeUpdateInterval.updateInterval(anime, episodes, zonedDateTime, fetchRange)
|
||||
val updateAnime = setAnimeFetchInterval.update(anime, episodes, zonedDateTime, fetchRange)
|
||||
return if (updateAnime != null) {
|
||||
animeRepository.updateAnime(updateAnime)
|
||||
} else {
|
||||
|
|
|
@ -3,7 +3,7 @@ package eu.kanade.domain.entries.manga.interactor
|
|||
import eu.kanade.domain.entries.manga.model.hasCustomCover
|
||||
import eu.kanade.tachiyomi.data.cache.MangaCoverCache
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import tachiyomi.domain.entries.manga.interactor.SetMangaUpdateInterval
|
||||
import tachiyomi.domain.entries.manga.interactor.SetMangaFetchInterval
|
||||
import tachiyomi.domain.entries.manga.model.Manga
|
||||
import tachiyomi.domain.entries.manga.model.MangaUpdate
|
||||
import tachiyomi.domain.entries.manga.repository.MangaRepository
|
||||
|
@ -16,7 +16,7 @@ import java.util.Date
|
|||
|
||||
class UpdateManga(
|
||||
private val mangaRepository: MangaRepository,
|
||||
private val setMangaUpdateInterval: SetMangaUpdateInterval,
|
||||
private val setMangaFetchInterval: SetMangaFetchInterval,
|
||||
) {
|
||||
|
||||
suspend fun await(mangaUpdate: MangaUpdate): Boolean {
|
||||
|
@ -81,9 +81,9 @@ class UpdateManga(
|
|||
manga: Manga,
|
||||
chapters: List<Chapter>,
|
||||
zonedDateTime: ZonedDateTime = ZonedDateTime.now(),
|
||||
fetchRange: Pair<Long, Long> = setMangaUpdateInterval.getCurrentFetchRange(zonedDateTime),
|
||||
fetchRange: Pair<Long, Long> = setMangaFetchInterval.getCurrent(zonedDateTime),
|
||||
): Boolean {
|
||||
val updatedManga = setMangaUpdateInterval.updateInterval(manga, chapters, zonedDateTime, fetchRange)
|
||||
val updatedManga = setMangaFetchInterval.update(manga, chapters, zonedDateTime, fetchRange)
|
||||
return if (updatedManga != null) {
|
||||
mangaRepository.updateManga(updatedManga)
|
||||
} else {
|
||||
|
|
|
@ -138,7 +138,7 @@ class SyncChaptersWithSource(
|
|||
|
||||
// Return if there's nothing to add, delete or change, avoiding unnecessary db transactions.
|
||||
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(
|
||||
manga,
|
||||
dbChapters,
|
||||
|
|
|
@ -138,7 +138,7 @@ class SyncEpisodesWithSource(
|
|||
|
||||
// Return if there's nothing to add, delete or change, avoiding unnecessary db transactions.
|
||||
if (toAdd.isEmpty() && toDelete.isEmpty() && toChange.isEmpty()) {
|
||||
if (manualFetch || anime.calculateInterval == 0 || anime.nextUpdate < fetchRange.first) {
|
||||
if (manualFetch || anime.fetchInterval == 0 || anime.nextUpdate < fetchRange.first) {
|
||||
updateAnime.awaitUpdateFetchInterval(
|
||||
anime,
|
||||
dbEpisodes,
|
||||
|
|
|
@ -74,6 +74,7 @@ import eu.kanade.tachiyomi.source.anime.getNameForAnimeInfo
|
|||
import eu.kanade.tachiyomi.ui.browse.anime.extension.details.SourcePreferencesScreen
|
||||
import eu.kanade.tachiyomi.ui.entries.anime.AnimeScreenModel
|
||||
import eu.kanade.tachiyomi.ui.entries.anime.EpisodeItem
|
||||
import eu.kanade.tachiyomi.ui.entries.anime.FetchAnimeInterval
|
||||
import eu.kanade.tachiyomi.util.lang.toRelativeString
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import kotlinx.coroutines.delay
|
||||
|
@ -97,7 +98,7 @@ import java.util.concurrent.TimeUnit
|
|||
fun AnimeScreen(
|
||||
state: AnimeScreenModel.State.Success,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
intervalDisplay: () -> Pair<Int, Int>?,
|
||||
fetchInterval: FetchAnimeInterval?,
|
||||
dateFormat: DateFormat,
|
||||
isTabletUi: Boolean,
|
||||
episodeSwipeStartAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
|
@ -127,7 +128,7 @@ fun AnimeScreen(
|
|||
onShareClicked: (() -> Unit)?,
|
||||
onDownloadActionClicked: ((DownloadAction) -> Unit)?,
|
||||
onEditCategoryClicked: (() -> Unit)?,
|
||||
onEditIntervalClicked: (() -> Unit)?,
|
||||
onEditFetchIntervalClicked: (() -> Unit)?,
|
||||
onMigrateClicked: (() -> Unit)?,
|
||||
changeAnimeSkipIntro: (() -> Unit)?,
|
||||
|
||||
|
@ -162,7 +163,7 @@ fun AnimeScreen(
|
|||
state = state,
|
||||
snackbarHostState = snackbarHostState,
|
||||
dateFormat = dateFormat,
|
||||
intervalDisplay = intervalDisplay,
|
||||
fetchInterval = fetchInterval,
|
||||
episodeSwipeStartAction = episodeSwipeStartAction,
|
||||
episodeSwipeEndAction = episodeSwipeEndAction,
|
||||
showNextEpisodeAirTime = showNextEpisodeAirTime,
|
||||
|
@ -184,7 +185,7 @@ fun AnimeScreen(
|
|||
onShareClicked = onShareClicked,
|
||||
onDownloadActionClicked = onDownloadActionClicked,
|
||||
onEditCategoryClicked = onEditCategoryClicked,
|
||||
onEditIntervalClicked = onEditIntervalClicked,
|
||||
onEditIntervalClicked = onEditFetchIntervalClicked,
|
||||
onMigrateClicked = onMigrateClicked,
|
||||
changeAnimeSkipIntro = changeAnimeSkipIntro,
|
||||
onMultiBookmarkClicked = onMultiBookmarkClicked,
|
||||
|
@ -206,7 +207,7 @@ fun AnimeScreen(
|
|||
showNextEpisodeAirTime = showNextEpisodeAirTime,
|
||||
alwaysUseExternalPlayer = alwaysUseExternalPlayer,
|
||||
dateFormat = dateFormat,
|
||||
intervalDisplay = intervalDisplay,
|
||||
fetchInterval = fetchInterval,
|
||||
onBackClicked = onBackClicked,
|
||||
onEpisodeClicked = onEpisodeClicked,
|
||||
onDownloadEpisode = onDownloadEpisode,
|
||||
|
@ -224,7 +225,7 @@ fun AnimeScreen(
|
|||
onShareClicked = onShareClicked,
|
||||
onDownloadActionClicked = onDownloadActionClicked,
|
||||
onEditCategoryClicked = onEditCategoryClicked,
|
||||
onEditIntervalClicked = onEditIntervalClicked,
|
||||
onEditIntervalClicked = onEditFetchIntervalClicked,
|
||||
changeAnimeSkipIntro = changeAnimeSkipIntro,
|
||||
onMigrateClicked = onMigrateClicked,
|
||||
onMultiBookmarkClicked = onMultiBookmarkClicked,
|
||||
|
@ -246,7 +247,7 @@ private fun AnimeScreenSmallImpl(
|
|||
state: AnimeScreenModel.State.Success,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
dateFormat: DateFormat,
|
||||
intervalDisplay: () -> Pair<Int, Int>?,
|
||||
fetchInterval: FetchAnimeInterval?,
|
||||
episodeSwipeStartAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
showNextEpisodeAirTime: Boolean,
|
||||
|
@ -432,8 +433,8 @@ private fun AnimeScreenSmallImpl(
|
|||
AnimeActionRow(
|
||||
favorite = state.anime.favorite,
|
||||
trackingCount = state.trackingCount,
|
||||
intervalDisplay = intervalDisplay,
|
||||
isUserIntervalMode = state.anime.calculateInterval < 0,
|
||||
fetchInterval = fetchInterval,
|
||||
isUserIntervalMode = state.anime.fetchInterval < 0,
|
||||
onAddToLibraryClicked = onAddToLibraryClicked,
|
||||
onWebViewClicked = onWebViewClicked,
|
||||
onWebViewLongClicked = onWebViewLongClicked,
|
||||
|
@ -517,7 +518,7 @@ fun AnimeScreenLargeImpl(
|
|||
state: AnimeScreenModel.State.Success,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
dateFormat: DateFormat,
|
||||
intervalDisplay: () -> Pair<Int, Int>?,
|
||||
fetchInterval: FetchAnimeInterval?,
|
||||
episodeSwipeStartAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
showNextEpisodeAirTime: Boolean,
|
||||
|
@ -685,8 +686,8 @@ fun AnimeScreenLargeImpl(
|
|||
AnimeActionRow(
|
||||
favorite = state.anime.favorite,
|
||||
trackingCount = state.trackingCount,
|
||||
intervalDisplay = intervalDisplay,
|
||||
isUserIntervalMode = state.anime.calculateInterval < 0,
|
||||
fetchInterval = fetchInterval,
|
||||
isUserIntervalMode = state.anime.fetchInterval < 0,
|
||||
onAddToLibraryClicked = onAddToLibraryClicked,
|
||||
onWebViewClicked = onWebViewClicked,
|
||||
onWebViewLongClicked = onWebViewLongClicked,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package eu.kanade.presentation.entries.anime
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -8,6 +9,7 @@ import androidx.compose.material3.TextButton
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
||||
@Composable
|
||||
|
@ -18,15 +20,27 @@ fun DuplicateAnimeDialog(
|
|||
) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
title = {
|
||||
Text(text = stringResource(R.string.are_you_sure))
|
||||
},
|
||||
text = {
|
||||
Text(text = stringResource(R.string.confirm_add_duplicate_manga))
|
||||
},
|
||||
confirmButton = {
|
||||
Row {
|
||||
TextButton(onClick = {
|
||||
onDismissRequest()
|
||||
onOpenAnime()
|
||||
},) {
|
||||
FlowRow(
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
TextButton(
|
||||
onClick = {
|
||||
onDismissRequest()
|
||||
onOpenAnime()
|
||||
},
|
||||
) {
|
||||
Text(text = stringResource(R.string.action_show_anime))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
TextButton(onClick = onDismissRequest) {
|
||||
Text(text = stringResource(R.string.action_cancel))
|
||||
}
|
||||
|
@ -40,11 +54,5 @@ fun DuplicateAnimeDialog(
|
|||
}
|
||||
}
|
||||
},
|
||||
title = {
|
||||
Text(text = stringResource(R.string.are_you_sure))
|
||||
},
|
||||
text = {
|
||||
Text(text = stringResource(R.string.confirm_add_duplicate_manga))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -80,6 +80,7 @@ import eu.kanade.presentation.entries.DotSeparatorText
|
|||
import eu.kanade.presentation.entries.ItemCover
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.animesource.model.SAnime
|
||||
import eu.kanade.tachiyomi.ui.entries.anime.FetchAnimeInterval
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import tachiyomi.domain.entries.anime.model.Anime
|
||||
import tachiyomi.presentation.core.components.material.TextButton
|
||||
|
@ -167,7 +168,7 @@ fun AnimeActionRow(
|
|||
modifier: Modifier = Modifier,
|
||||
favorite: Boolean,
|
||||
trackingCount: Int,
|
||||
intervalDisplay: () -> Pair<Int, Int>?,
|
||||
fetchInterval: FetchAnimeInterval?,
|
||||
isUserIntervalMode: Boolean,
|
||||
onAddToLibraryClicked: () -> Unit,
|
||||
onWebViewClicked: (() -> Unit)?,
|
||||
|
@ -176,7 +177,6 @@ fun AnimeActionRow(
|
|||
onEditIntervalClicked: (() -> Unit)?,
|
||||
onEditCategory: (() -> Unit)?,
|
||||
) {
|
||||
val interval: Pair<Int, Int>? = intervalDisplay()
|
||||
val defaultActionButtonColor = MaterialTheme.colorScheme.onSurface.copy(alpha = .38f)
|
||||
|
||||
Row(modifier = modifier.padding(start = 16.dp, top = 8.dp, end = 16.dp)) {
|
||||
|
@ -191,13 +191,14 @@ fun AnimeActionRow(
|
|||
onClick = onAddToLibraryClicked,
|
||||
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)
|
||||
AnimeActionButton(
|
||||
title =
|
||||
if (interval.first == interval.second) {
|
||||
pluralStringResource(id = R.plurals.day, count = interval.second, interval.second)
|
||||
if (intervalPair.first == intervalPair.second) {
|
||||
pluralStringResource(id = R.plurals.day, count = intervalPair.second, intervalPair.second)
|
||||
} 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,
|
||||
color = if (isUserIntervalMode) MaterialTheme.colorScheme.primary else defaultActionButtonColor,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package eu.kanade.presentation.entries.manga
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -8,6 +9,7 @@ import androidx.compose.material3.TextButton
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
||||
@Composable
|
||||
|
@ -18,15 +20,27 @@ fun DuplicateMangaDialog(
|
|||
) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
title = {
|
||||
Text(text = stringResource(R.string.are_you_sure))
|
||||
},
|
||||
text = {
|
||||
Text(text = stringResource(R.string.confirm_add_duplicate_manga))
|
||||
},
|
||||
confirmButton = {
|
||||
Row {
|
||||
TextButton(onClick = {
|
||||
onDismissRequest()
|
||||
onOpenManga()
|
||||
},) {
|
||||
FlowRow(
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
TextButton(
|
||||
onClick = {
|
||||
onDismissRequest()
|
||||
onOpenManga()
|
||||
},
|
||||
) {
|
||||
Text(text = stringResource(R.string.action_show_manga))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
TextButton(onClick = onDismissRequest) {
|
||||
Text(text = stringResource(R.string.action_cancel))
|
||||
}
|
||||
|
@ -40,11 +54,5 @@ fun DuplicateMangaDialog(
|
|||
}
|
||||
}
|
||||
},
|
||||
title = {
|
||||
Text(text = stringResource(R.string.are_you_sure))
|
||||
},
|
||||
text = {
|
||||
Text(text = stringResource(R.string.confirm_add_duplicate_manga))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ import eu.kanade.tachiyomi.source.ConfigurableSource
|
|||
import eu.kanade.tachiyomi.source.manga.getNameForMangaInfo
|
||||
import eu.kanade.tachiyomi.ui.browse.manga.extension.details.MangaSourcePreferencesScreen
|
||||
import eu.kanade.tachiyomi.ui.entries.manga.ChapterItem
|
||||
import eu.kanade.tachiyomi.ui.entries.manga.FetchMangaInterval
|
||||
import eu.kanade.tachiyomi.ui.entries.manga.MangaScreenModel
|
||||
import eu.kanade.tachiyomi.util.lang.toRelativeString
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
|
@ -90,7 +91,7 @@ import java.util.Date
|
|||
fun MangaScreen(
|
||||
state: MangaScreenModel.State.Success,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
intervalDisplay: () -> Pair<Int, Int>?,
|
||||
fetchInterval: FetchMangaInterval?,
|
||||
dateFormat: DateFormat,
|
||||
isTabletUi: Boolean,
|
||||
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
||||
|
@ -118,7 +119,7 @@ fun MangaScreen(
|
|||
onShareClicked: (() -> Unit)?,
|
||||
onDownloadActionClicked: ((DownloadAction) -> Unit)?,
|
||||
onEditCategoryClicked: (() -> Unit)?,
|
||||
onEditIntervalClicked: (() -> Unit)?,
|
||||
onEditFetchIntervalClicked: (() -> Unit)?,
|
||||
onMigrateClicked: (() -> Unit)?,
|
||||
|
||||
// For bottom action menu
|
||||
|
@ -152,7 +153,7 @@ fun MangaScreen(
|
|||
state = state,
|
||||
snackbarHostState = snackbarHostState,
|
||||
dateFormat = dateFormat,
|
||||
intervalDisplay = intervalDisplay,
|
||||
fetchInterval = fetchInterval,
|
||||
chapterSwipeStartAction = chapterSwipeStartAction,
|
||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||
onBackClicked = onBackClicked,
|
||||
|
@ -172,7 +173,7 @@ fun MangaScreen(
|
|||
onShareClicked = onShareClicked,
|
||||
onDownloadActionClicked = onDownloadActionClicked,
|
||||
onEditCategoryClicked = onEditCategoryClicked,
|
||||
onEditIntervalClicked = onEditIntervalClicked,
|
||||
onEditIntervalClicked = onEditFetchIntervalClicked,
|
||||
onMigrateClicked = onMigrateClicked,
|
||||
onMultiBookmarkClicked = onMultiBookmarkClicked,
|
||||
onMultiMarkAsReadClicked = onMultiMarkAsReadClicked,
|
||||
|
@ -191,7 +192,7 @@ fun MangaScreen(
|
|||
chapterSwipeStartAction = chapterSwipeStartAction,
|
||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||
dateFormat = dateFormat,
|
||||
intervalDisplay = intervalDisplay,
|
||||
fetchInterval = fetchInterval,
|
||||
onBackClicked = onBackClicked,
|
||||
onChapterClicked = onChapterClicked,
|
||||
onDownloadChapter = onDownloadChapter,
|
||||
|
@ -209,7 +210,7 @@ fun MangaScreen(
|
|||
onShareClicked = onShareClicked,
|
||||
onDownloadActionClicked = onDownloadActionClicked,
|
||||
onEditCategoryClicked = onEditCategoryClicked,
|
||||
onEditIntervalClicked = onEditIntervalClicked,
|
||||
onEditIntervalClicked = onEditFetchIntervalClicked,
|
||||
onMigrateClicked = onMigrateClicked,
|
||||
onMultiBookmarkClicked = onMultiBookmarkClicked,
|
||||
onMultiMarkAsReadClicked = onMultiMarkAsReadClicked,
|
||||
|
@ -229,7 +230,7 @@ private fun MangaScreenSmallImpl(
|
|||
state: MangaScreenModel.State.Success,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
dateFormat: DateFormat,
|
||||
intervalDisplay: () -> Pair<Int, Int>?,
|
||||
fetchInterval: FetchMangaInterval?,
|
||||
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||
onBackClicked: () -> Unit,
|
||||
|
@ -406,8 +407,8 @@ private fun MangaScreenSmallImpl(
|
|||
MangaActionRow(
|
||||
favorite = state.manga.favorite,
|
||||
trackingCount = state.trackingCount,
|
||||
intervalDisplay = intervalDisplay,
|
||||
isUserIntervalMode = state.manga.calculateInterval < 0,
|
||||
fetchInterval = fetchInterval,
|
||||
isUserIntervalMode = state.manga.fetchInterval < 0,
|
||||
onAddToLibraryClicked = onAddToLibraryClicked,
|
||||
onWebViewClicked = onWebViewClicked,
|
||||
onWebViewLongClicked = onWebViewLongClicked,
|
||||
|
@ -465,7 +466,7 @@ fun MangaScreenLargeImpl(
|
|||
state: MangaScreenModel.State.Success,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
dateFormat: DateFormat,
|
||||
intervalDisplay: () -> Pair<Int, Int>?,
|
||||
fetchInterval: FetchMangaInterval?,
|
||||
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||
onBackClicked: () -> Unit,
|
||||
|
@ -627,8 +628,8 @@ fun MangaScreenLargeImpl(
|
|||
MangaActionRow(
|
||||
favorite = state.manga.favorite,
|
||||
trackingCount = state.trackingCount,
|
||||
intervalDisplay = intervalDisplay,
|
||||
isUserIntervalMode = state.manga.calculateInterval < 0,
|
||||
fetchInterval = fetchInterval,
|
||||
isUserIntervalMode = state.manga.fetchInterval < 0,
|
||||
onAddToLibraryClicked = onAddToLibraryClicked,
|
||||
onWebViewClicked = onWebViewClicked,
|
||||
onWebViewLongClicked = onWebViewLongClicked,
|
||||
|
|
|
@ -80,6 +80,7 @@ import eu.kanade.presentation.entries.DotSeparatorText
|
|||
import eu.kanade.presentation.entries.ItemCover
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.ui.entries.manga.FetchMangaInterval
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import tachiyomi.domain.entries.manga.model.Manga
|
||||
import tachiyomi.presentation.core.components.material.TextButton
|
||||
|
@ -167,7 +168,7 @@ fun MangaActionRow(
|
|||
modifier: Modifier = Modifier,
|
||||
favorite: Boolean,
|
||||
trackingCount: Int,
|
||||
intervalDisplay: () -> Pair<Int, Int>?,
|
||||
fetchInterval: FetchMangaInterval?,
|
||||
isUserIntervalMode: Boolean,
|
||||
onAddToLibraryClicked: () -> Unit,
|
||||
onWebViewClicked: (() -> Unit)?,
|
||||
|
@ -176,7 +177,6 @@ fun MangaActionRow(
|
|||
onEditIntervalClicked: (() -> Unit)?,
|
||||
onEditCategory: (() -> Unit)?,
|
||||
) {
|
||||
val interval: Pair<Int, Int>? = intervalDisplay()
|
||||
val defaultActionButtonColor = MaterialTheme.colorScheme.onSurface.copy(alpha = .38f)
|
||||
|
||||
Row(modifier = modifier.padding(start = 16.dp, top = 8.dp, end = 16.dp)) {
|
||||
|
@ -191,13 +191,14 @@ fun MangaActionRow(
|
|||
onClick = onAddToLibraryClicked,
|
||||
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(
|
||||
title =
|
||||
if (interval.first == interval.second) {
|
||||
pluralStringResource(id = R.plurals.day, count = interval.second, interval.second)
|
||||
if (intervalPair.first == intervalPair.second) {
|
||||
pluralStringResource(id = R.plurals.day, count = intervalPair.second, intervalPair.second)
|
||||
} 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,
|
||||
color = if (isUserIntervalMode) MaterialTheme.colorScheme.primary else defaultActionButtonColor,
|
||||
|
|
|
@ -235,6 +235,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||
onClick = {
|
||||
Injekt.get<MangaDownloadCache>().invalidateCache()
|
||||
Injekt.get<AnimeDownloadCache>().invalidateCache()
|
||||
context.toast(R.string.download_cache_invalidated)
|
||||
},
|
||||
),
|
||||
Preference.PreferenceItem.TextPreference(
|
||||
|
|
|
@ -5,11 +5,16 @@ import android.os.Build
|
|||
import androidx.core.content.ContextCompat
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
|
||||
import com.squareup.sqldelight.android.AndroidSqliteDriver
|
||||
import app.cash.sqldelight.adapter.primitive.FloatColumnAdapter
|
||||
import app.cash.sqldelight.driver.android.AndroidSqliteDriver
|
||||
import data.Chapters
|
||||
import data.History
|
||||
import data.Manga_sync
|
||||
import data.Mangas
|
||||
import dataanime.Anime_sync
|
||||
import dataanime.Animehistory
|
||||
import dataanime.Animes
|
||||
import dataanime.Episodes
|
||||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.domain.source.service.SourcePreferences
|
||||
import eu.kanade.domain.track.anime.store.DelayedAnimeTrackingStore
|
||||
|
@ -131,9 +136,15 @@ class AppModule(val app: Application) : InjektModule {
|
|||
addSingletonFactory {
|
||||
Database(
|
||||
driver = sqlDriverManga,
|
||||
chaptersAdapter = Chapters.Adapter(
|
||||
chapter_numberAdapter = FloatColumnAdapter,
|
||||
),
|
||||
historyAdapter = History.Adapter(
|
||||
last_readAdapter = dateAdapter,
|
||||
),
|
||||
manga_syncAdapter = Manga_sync.Adapter(
|
||||
scoreAdapter = FloatColumnAdapter,
|
||||
),
|
||||
mangasAdapter = Mangas.Adapter(
|
||||
genreAdapter = listOfStringsAdapter,
|
||||
update_strategyAdapter = updateStrategyAdapter,
|
||||
|
@ -144,9 +155,15 @@ class AppModule(val app: Application) : InjektModule {
|
|||
addSingletonFactory {
|
||||
AnimeDatabase(
|
||||
driver = sqlDriverAnime,
|
||||
episodesAdapter = Episodes.Adapter(
|
||||
episode_numberAdapter = FloatColumnAdapter,
|
||||
),
|
||||
animehistoryAdapter = Animehistory.Adapter(
|
||||
last_seenAdapter = dateAdapter,
|
||||
),
|
||||
anime_syncAdapter = Anime_sync.Adapter(
|
||||
scoreAdapter = FloatColumnAdapter,
|
||||
),
|
||||
animesAdapter = Animes.Adapter(
|
||||
genreAdapter = listOfStringsAdapter,
|
||||
update_strategyAdapter = updateStrategyAdapter,
|
||||
|
|
|
@ -511,7 +511,7 @@ class BackupManager(
|
|||
}
|
||||
if (!found) {
|
||||
// Let the db assign the id
|
||||
val id = mangaHandler.awaitOne {
|
||||
val id = mangaHandler.awaitOneExecutable {
|
||||
categoriesQueries.insert(category.name, category.order, category.flags)
|
||||
categoriesQueries.selectLastInsertedRowId()
|
||||
}
|
||||
|
@ -551,7 +551,7 @@ class BackupManager(
|
|||
}
|
||||
if (!found) {
|
||||
// Let the db assign the id
|
||||
val id = animeHandler.awaitOne {
|
||||
val id = animeHandler.awaitOneExecutable {
|
||||
categoriesQueries.insert(category.name, category.order, category.flags)
|
||||
categoriesQueries.selectLastInsertedRowId()
|
||||
}
|
||||
|
@ -970,7 +970,7 @@ class BackupManager(
|
|||
* @return id of [Manga], null if not found
|
||||
*/
|
||||
private suspend fun insertManga(manga: Manga): Long {
|
||||
return mangaHandler.awaitOne(true) {
|
||||
return mangaHandler.awaitOneExecutable(true) {
|
||||
mangasQueries.insert(
|
||||
source = manga.source,
|
||||
url = manga.url,
|
||||
|
@ -1002,7 +1002,7 @@ class BackupManager(
|
|||
* @return id of [Anime], null if not found
|
||||
*/
|
||||
private suspend fun insertAnime(anime: Anime): Long {
|
||||
return animeHandler.awaitOne(true) {
|
||||
return animeHandler.awaitOneExecutable(true) {
|
||||
animesQueries.insert(
|
||||
source = anime.source,
|
||||
url = anime.url,
|
||||
|
@ -1040,11 +1040,11 @@ class BackupManager(
|
|||
title = manga.title,
|
||||
status = manga.status,
|
||||
thumbnailUrl = manga.thumbnailUrl,
|
||||
favorite = manga.favorite.toLong(),
|
||||
favorite = manga.favorite,
|
||||
lastUpdate = manga.lastUpdate,
|
||||
nextUpdate = null,
|
||||
calculateInterval = null,
|
||||
initialized = manga.initialized.toLong(),
|
||||
initialized = manga.initialized,
|
||||
viewer = manga.viewerFlags,
|
||||
chapterFlags = manga.chapterFlags,
|
||||
coverLastModified = manga.coverLastModified,
|
||||
|
@ -1068,11 +1068,11 @@ class BackupManager(
|
|||
title = anime.title,
|
||||
status = anime.status,
|
||||
thumbnailUrl = anime.thumbnailUrl,
|
||||
favorite = anime.favorite.toLong(),
|
||||
favorite = anime.favorite,
|
||||
lastUpdate = anime.lastUpdate,
|
||||
nextUpdate = null,
|
||||
calculateInterval = null,
|
||||
initialized = anime.initialized.toLong(),
|
||||
initialized = anime.initialized,
|
||||
viewer = anime.viewerFlags,
|
||||
episodeFlags = anime.episodeFlags,
|
||||
coverLastModified = anime.coverLastModified,
|
||||
|
@ -1142,8 +1142,8 @@ class BackupManager(
|
|||
url = null,
|
||||
name = null,
|
||||
scanlator = null,
|
||||
read = chapter.read.toLong(),
|
||||
bookmark = chapter.bookmark.toLong(),
|
||||
read = chapter.read,
|
||||
bookmark = chapter.bookmark,
|
||||
lastPageRead = chapter.lastPageRead,
|
||||
chapterNumber = null,
|
||||
sourceOrder = null,
|
||||
|
@ -1166,8 +1166,8 @@ class BackupManager(
|
|||
url = null,
|
||||
name = null,
|
||||
scanlator = null,
|
||||
seen = episode.seen.toLong(),
|
||||
bookmark = episode.bookmark.toLong(),
|
||||
seen = episode.seen,
|
||||
bookmark = episode.bookmark,
|
||||
lastSecondSeen = episode.lastSecondSeen,
|
||||
totalSeconds = episode.totalSeconds,
|
||||
episodeNumber = null,
|
||||
|
|
|
@ -30,9 +30,9 @@ import eu.kanade.tachiyomi.util.system.createFileInCacheDir
|
|||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.isActive
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.entries.anime.interactor.SetAnimeUpdateInterval
|
||||
import tachiyomi.domain.entries.anime.interactor.SetAnimeFetchInterval
|
||||
import tachiyomi.domain.entries.anime.model.Anime
|
||||
import tachiyomi.domain.entries.manga.interactor.SetMangaUpdateInterval
|
||||
import tachiyomi.domain.entries.manga.interactor.SetMangaFetchInterval
|
||||
import tachiyomi.domain.entries.manga.model.Manga
|
||||
import tachiyomi.domain.items.chapter.model.Chapter
|
||||
import tachiyomi.domain.items.chapter.repository.ChapterRepository
|
||||
|
@ -54,15 +54,15 @@ class BackupRestorer(
|
|||
) {
|
||||
private val updateManga: UpdateManga = Injekt.get()
|
||||
private val chapterRepository: ChapterRepository = Injekt.get()
|
||||
private val setMangaUpdateInterval: SetMangaUpdateInterval = Injekt.get()
|
||||
private val setMangaFetchInterval: SetMangaFetchInterval = Injekt.get()
|
||||
|
||||
private val updateAnime: UpdateAnime = Injekt.get()
|
||||
private val episodeRepository: EpisodeRepository = Injekt.get()
|
||||
private val setAnimeUpdateInterval: SetAnimeUpdateInterval = Injekt.get()
|
||||
private val setAnimeFetchInterval: SetAnimeFetchInterval = Injekt.get()
|
||||
|
||||
private var zonedDateTime = ZonedDateTime.now()
|
||||
private var currentMangaRange = setMangaUpdateInterval.getCurrentFetchRange(zonedDateTime)
|
||||
private var currentAnimeRange = setAnimeUpdateInterval.getCurrentFetchRange(zonedDateTime)
|
||||
private var currentMangaFetchInterval = setMangaFetchInterval.getCurrent(zonedDateTime)
|
||||
private var currentAnimeFetchInterval = setAnimeFetchInterval.getCurrent(zonedDateTime)
|
||||
|
||||
private var backupManager = BackupManager(context)
|
||||
|
||||
|
@ -141,8 +141,8 @@ class BackupRestorer(
|
|||
animeSourceMapping = backupAnimeMaps.associate { it.sourceId to it.name }
|
||||
|
||||
zonedDateTime = ZonedDateTime.now()
|
||||
currentMangaRange = setMangaUpdateInterval.getCurrentFetchRange(zonedDateTime)
|
||||
currentAnimeRange = setAnimeUpdateInterval.getCurrentFetchRange(zonedDateTime)
|
||||
currentMangaFetchInterval = setMangaFetchInterval.getCurrent(zonedDateTime)
|
||||
currentAnimeFetchInterval = setAnimeFetchInterval.getCurrent(zonedDateTime)
|
||||
|
||||
return coroutineScope {
|
||||
// Restore individual manga
|
||||
|
@ -217,7 +217,7 @@ class BackupRestorer(
|
|||
restoreNewManga(updateManga, chapters, categories, history, tracks, backupCategories)
|
||||
}
|
||||
val updatedChapters = chapterRepository.getChapterByMangaId(restoredManga.id)
|
||||
updateManga.awaitUpdateFetchInterval(restoredManga, updatedChapters, zonedDateTime, currentMangaRange)
|
||||
updateManga.awaitUpdateFetchInterval(restoredManga, updatedChapters, zonedDateTime, currentMangaFetchInterval)
|
||||
} catch (e: Exception) {
|
||||
val sourceName = sourceMapping[manga.source] ?: manga.source.toString()
|
||||
errors.add(Date() to "${manga.title} [$sourceName]: ${e.message}")
|
||||
|
@ -292,7 +292,7 @@ class BackupRestorer(
|
|||
restoreNewAnime(updateAnime, episodes, categories, history, tracks, backupCategories)
|
||||
}
|
||||
val updatedEpisodes = episodeRepository.getEpisodeByAnimeId(restoredAnime.id)
|
||||
updateAnime.awaitUpdateFetchInterval(restoredAnime, updatedEpisodes, zonedDateTime, currentAnimeRange)
|
||||
updateAnime.awaitUpdateFetchInterval(restoredAnime, updatedEpisodes, zonedDateTime, currentAnimeFetchInterval)
|
||||
} catch (e: Exception) {
|
||||
val sourceName = sourceMapping[anime.source] ?: anime.source.toString()
|
||||
errors.add(Date() to "${anime.title} [$sourceName]: ${e.message}")
|
||||
|
|
|
@ -56,7 +56,7 @@ import tachiyomi.domain.category.model.Category
|
|||
import tachiyomi.domain.download.service.DownloadPreferences
|
||||
import tachiyomi.domain.entries.anime.interactor.GetAnime
|
||||
import tachiyomi.domain.entries.anime.interactor.GetLibraryAnime
|
||||
import tachiyomi.domain.entries.anime.interactor.SetAnimeUpdateInterval
|
||||
import tachiyomi.domain.entries.anime.interactor.SetAnimeFetchInterval
|
||||
import tachiyomi.domain.entries.anime.model.Anime
|
||||
import tachiyomi.domain.entries.anime.model.toAnimeUpdate
|
||||
import tachiyomi.domain.items.episode.interactor.GetEpisodeByAnimeId
|
||||
|
@ -104,7 +104,7 @@ class AnimeLibraryUpdateJob(private val context: Context, workerParams: WorkerPa
|
|||
private val getTracks: GetAnimeTracks = Injekt.get()
|
||||
private val insertTrack: InsertAnimeTrack = Injekt.get()
|
||||
private val syncEpisodesWithTrackServiceTwoWay: SyncEpisodesWithTrackServiceTwoWay = Injekt.get()
|
||||
private val setAnimeUpdateInterval: SetAnimeUpdateInterval = Injekt.get()
|
||||
private val setAnimeFetchInterval: SetAnimeFetchInterval = Injekt.get()
|
||||
|
||||
private val notifier = AnimeLibraryUpdateNotifier(context)
|
||||
|
||||
|
@ -232,8 +232,8 @@ class AnimeLibraryUpdateJob(private val context: Context, workerParams: WorkerPa
|
|||
val restrictions = libraryPreferences.libraryUpdateItemRestriction().get()
|
||||
|
||||
val now = ZonedDateTime.now()
|
||||
val fetchRange = setAnimeUpdateInterval.getCurrentFetchRange(now)
|
||||
val higherLimit = fetchRange.second
|
||||
val fetchInterval = setAnimeFetchInterval.getCurrent(now)
|
||||
val higherLimit = fetchInterval.second
|
||||
|
||||
coroutineScope {
|
||||
animeToUpdate.groupBy { it.anime.source }.values
|
||||
|
@ -272,7 +272,7 @@ class AnimeLibraryUpdateJob(private val context: Context, workerParams: WorkerPa
|
|||
|
||||
else -> {
|
||||
try {
|
||||
val newEpisodes = updateAnime(anime, now, fetchRange)
|
||||
val newEpisodes = updateAnime(anime, now, fetchInterval)
|
||||
.sortedByDescending { it.sourceOrder }
|
||||
|
||||
if (newEpisodes.isNotEmpty()) {
|
||||
|
|
|
@ -56,7 +56,7 @@ import tachiyomi.domain.category.model.Category
|
|||
import tachiyomi.domain.download.service.DownloadPreferences
|
||||
import tachiyomi.domain.entries.manga.interactor.GetLibraryManga
|
||||
import tachiyomi.domain.entries.manga.interactor.GetManga
|
||||
import tachiyomi.domain.entries.manga.interactor.SetMangaUpdateInterval
|
||||
import tachiyomi.domain.entries.manga.interactor.SetMangaFetchInterval
|
||||
import tachiyomi.domain.entries.manga.model.Manga
|
||||
import tachiyomi.domain.entries.manga.model.toMangaUpdate
|
||||
import tachiyomi.domain.items.chapter.interactor.GetChapterByMangaId
|
||||
|
@ -104,7 +104,7 @@ class MangaLibraryUpdateJob(private val context: Context, workerParams: WorkerPa
|
|||
private val getTracks: GetMangaTracks = Injekt.get()
|
||||
private val insertTrack: InsertMangaTrack = Injekt.get()
|
||||
private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay = Injekt.get()
|
||||
private val setMangaUpdateInterval: SetMangaUpdateInterval = Injekt.get()
|
||||
private val setMangaFetchInterval: SetMangaFetchInterval = Injekt.get()
|
||||
|
||||
private val notifier = MangaLibraryUpdateNotifier(context)
|
||||
|
||||
|
@ -232,8 +232,8 @@ class MangaLibraryUpdateJob(private val context: Context, workerParams: WorkerPa
|
|||
val restrictions = libraryPreferences.libraryUpdateItemRestriction().get()
|
||||
|
||||
val now = ZonedDateTime.now()
|
||||
val fetchRange = setMangaUpdateInterval.getCurrentFetchRange(now)
|
||||
val higherLimit = fetchRange.second
|
||||
val fetchInterval = setMangaFetchInterval.getCurrent(now)
|
||||
val higherLimit = fetchInterval.second
|
||||
|
||||
coroutineScope {
|
||||
mangaToUpdate.groupBy { it.manga.source }.values
|
||||
|
@ -272,7 +272,7 @@ class MangaLibraryUpdateJob(private val context: Context, workerParams: WorkerPa
|
|||
|
||||
else -> {
|
||||
try {
|
||||
val newChapters = updateManga(manga, now, fetchRange)
|
||||
val newChapters = updateManga(manga, now, fetchInterval)
|
||||
.sortedByDescending { it.sourceOrder }
|
||||
|
||||
if (newChapters.isNotEmpty()) {
|
||||
|
|
|
@ -121,8 +121,8 @@ internal fun MigrateAnimeDialog(
|
|||
) {
|
||||
TextButton(
|
||||
onClick = {
|
||||
onClickTitle()
|
||||
onDismissRequest()
|
||||
onClickTitle()
|
||||
},
|
||||
) {
|
||||
Text(text = stringResource(R.string.action_show_anime))
|
||||
|
|
|
@ -329,7 +329,7 @@ class BrowseAnimeSourceScreenModel(
|
|||
}
|
||||
|
||||
suspend fun getDuplicateAnimelibAnime(anime: Anime): Anime? {
|
||||
return getDuplicateAnimelibAnime.await(anime.title)
|
||||
return getDuplicateAnimelibAnime.await(anime).getOrNull(0)
|
||||
}
|
||||
|
||||
private fun moveAnimeToCategories(anime: Anime, vararg categories: Category) {
|
||||
|
|
|
@ -121,8 +121,8 @@ internal fun MigrateMangaDialog(
|
|||
) {
|
||||
TextButton(
|
||||
onClick = {
|
||||
onClickTitle()
|
||||
onDismissRequest()
|
||||
onClickTitle()
|
||||
},
|
||||
) {
|
||||
Text(text = stringResource(R.string.action_show_manga))
|
||||
|
|
|
@ -323,7 +323,7 @@ class BrowseMangaSourceScreenModel(
|
|||
}
|
||||
|
||||
suspend fun getDuplicateLibraryManga(manga: Manga): Manga? {
|
||||
return getDuplicateLibraryManga.await(manga.title)
|
||||
return getDuplicateLibraryManga.await(manga).getOrNull(0)
|
||||
}
|
||||
|
||||
private fun moveMangaToCategories(manga: Manga, vararg categories: Category) {
|
||||
|
|
|
@ -89,6 +89,13 @@ class AnimeScreen(
|
|||
|
||||
val successState = state as AnimeScreenModel.State.Success
|
||||
val isAnimeHttpSource = remember { successState.source is AnimeHttpSource }
|
||||
val fetchInterval = remember(successState.anime.fetchInterval) {
|
||||
FetchAnimeInterval(
|
||||
interval = successState.anime.fetchInterval,
|
||||
leadDays = screenModel.leadDay,
|
||||
followDays = screenModel.followDay,
|
||||
)
|
||||
}
|
||||
|
||||
LaunchedEffect(successState.anime, screenModel.source) {
|
||||
if (isAnimeHttpSource) {
|
||||
|
@ -106,7 +113,7 @@ class AnimeScreen(
|
|||
state = successState,
|
||||
snackbarHostState = screenModel.snackbarHostState,
|
||||
dateFormat = screenModel.dateFormat,
|
||||
intervalDisplay = screenModel::intervalDisplay,
|
||||
fetchInterval = fetchInterval,
|
||||
isTabletUi = isTabletUi(),
|
||||
episodeSwipeStartAction = screenModel.episodeSwipeStartAction,
|
||||
episodeSwipeEndAction = screenModel.episodeSwipeEndAction,
|
||||
|
@ -141,7 +148,7 @@ class AnimeScreen(
|
|||
onShareClicked = { shareAnime(context, screenModel.anime, screenModel.source) }.takeIf { isAnimeHttpSource },
|
||||
onDownloadActionClicked = screenModel::runDownloadAction.takeIf { !successState.source.isLocalOrStub() },
|
||||
onEditCategoryClicked = screenModel::showChangeCategoryDialog.takeIf { successState.anime.favorite },
|
||||
onEditIntervalClicked = screenModel::showSetAnimeIntervalDialog.takeIf { screenModel.isIntervalEnabled && successState.anime.favorite },
|
||||
onEditFetchIntervalClicked = screenModel::showSetAnimeFetchIntervalDialog.takeIf { screenModel.isUpdateIntervalEnabled && successState.anime.favorite },
|
||||
onMigrateClicked = { navigator.push(MigrateAnimeSearchScreen(successState.anime.id)) }.takeIf { successState.anime.favorite },
|
||||
changeAnimeSkipIntro = screenModel::showAnimeSkipIntroDialog.takeIf { successState.anime.favorite },
|
||||
onMultiBookmarkClicked = screenModel::bookmarkEpisodes,
|
||||
|
@ -235,11 +242,11 @@ class AnimeScreen(
|
|||
LoadingScreen(Modifier.systemBarsPadding())
|
||||
}
|
||||
}
|
||||
is AnimeScreenModel.Dialog.SetAnimeInterval -> {
|
||||
is AnimeScreenModel.Dialog.SetAnimeFetchInterval -> {
|
||||
SetIntervalDialog(
|
||||
interval = if (dialog.anime.calculateInterval < 0) -dialog.anime.calculateInterval else 0,
|
||||
interval = if (dialog.anime.fetchInterval < 0) -dialog.anime.fetchInterval else 0,
|
||||
onDismissRequest = onDismissRequest,
|
||||
onValueChanged = { screenModel.setFetchRangeInterval(dialog.anime, it) },
|
||||
onValueChanged = { screenModel.setFetchInterval(dialog.anime, it) },
|
||||
)
|
||||
}
|
||||
AnimeScreenModel.Dialog.ChangeAnimeSkipIntro -> {
|
||||
|
|
|
@ -79,7 +79,6 @@ import tachiyomi.source.local.entries.anime.isLocal
|
|||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.Calendar
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
class AnimeScreenModel(
|
||||
val context: Context,
|
||||
|
@ -135,9 +134,9 @@ class AnimeScreenModel(
|
|||
|
||||
val dateFormat by mutableStateOf(UiPreferences.dateFormat(uiPreferences.dateFormat().get()))
|
||||
|
||||
val isIntervalEnabled = LibraryPreferences.ENTRY_OUTSIDE_RELEASE_PERIOD in libraryPreferences.libraryUpdateItemRestriction().get()
|
||||
private val leadDay = libraryPreferences.leadingAnimeExpectedDays().get()
|
||||
private val followDay = libraryPreferences.followingAnimeExpectedDays().get()
|
||||
val isUpdateIntervalEnabled = LibraryPreferences.ENTRY_OUTSIDE_RELEASE_PERIOD in libraryPreferences.libraryUpdateItemRestriction().get()
|
||||
val leadDay = libraryPreferences.leadingAnimeExpectedDays().get()
|
||||
val followDay = libraryPreferences.followingAnimeExpectedDays().get()
|
||||
|
||||
private val selectedPositions: Array<Int> = arrayOf(-1, -1) // first and last selected index in list
|
||||
private val selectedEpisodeIds: HashSet<Long> = HashSet()
|
||||
|
@ -296,7 +295,7 @@ class AnimeScreenModel(
|
|||
// Add to library
|
||||
// First, check if duplicate exists if callback is provided
|
||||
if (checkDuplicate) {
|
||||
val duplicate = getDuplicateLibraryAnime.await(anime.title)
|
||||
val duplicate = getDuplicateLibraryAnime.await(anime).getOrNull(0)
|
||||
if (duplicate != null) {
|
||||
updateSuccessState { it.copy(dialog = Dialog.DuplicateAnime(anime, duplicate)) }
|
||||
return@launchIO
|
||||
|
@ -371,30 +370,23 @@ class AnimeScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun showSetAnimeIntervalDialog() {
|
||||
fun showSetAnimeFetchIntervalDialog() {
|
||||
val anime = successState?.anime ?: return
|
||||
updateSuccessState {
|
||||
it.copy(dialog = Dialog.SetAnimeInterval(anime))
|
||||
it.copy(dialog = Dialog.SetAnimeFetchInterval(anime))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this should be in the state/composables
|
||||
fun intervalDisplay(): Pair<Int, Int>? {
|
||||
val anime = successState?.anime ?: return null
|
||||
val effInterval = anime.calculateInterval
|
||||
return 1.coerceAtLeast(effInterval.absoluteValue - leadDay) to (effInterval.absoluteValue + followDay)
|
||||
}
|
||||
|
||||
fun setFetchRangeInterval(anime: Anime, newInterval: Int) {
|
||||
fun setFetchInterval(anime: Anime, newInterval: Int) {
|
||||
val interval = when (newInterval) {
|
||||
// reset interval 0 default to trigger recalculation
|
||||
// only reset if interval is custom, which is negative
|
||||
0 -> if (anime.calculateInterval < 0) 0 else anime.calculateInterval
|
||||
0 -> if (anime.fetchInterval < 0) 0 else anime.fetchInterval
|
||||
else -> -newInterval
|
||||
}
|
||||
coroutineScope.launchIO {
|
||||
updateAnime.awaitUpdateFetchInterval(
|
||||
anime.copy(calculateInterval = interval),
|
||||
anime.copy(fetchInterval = interval),
|
||||
successState?.episodes?.map { it.episode }.orEmpty(),
|
||||
)
|
||||
val newAnime = animeRepository.getAnimeById(animeId)
|
||||
|
@ -1011,7 +1003,7 @@ class AnimeScreenModel(
|
|||
data class ChangeCategory(val anime: Anime, val initialSelection: List<CheckboxState<Category>>) : Dialog
|
||||
data class DeleteEpisodes(val episodes: List<Episode>) : Dialog
|
||||
data class DuplicateAnime(val anime: Anime, val duplicate: Anime) : Dialog
|
||||
data class SetAnimeInterval(val anime: Anime) : Dialog
|
||||
data class SetAnimeFetchInterval(val anime: Anime) : Dialog
|
||||
data class ShowQualities(val episode: Episode, val anime: Anime, val source: AnimeSource) : Dialog
|
||||
data object ChangeAnimeSkipIntro : Dialog
|
||||
data object SettingsSheet : Dialog
|
||||
|
@ -1113,3 +1105,10 @@ data class EpisodeItem(
|
|||
) {
|
||||
val isDownloaded = downloadState == AnimeDownload.State.DOWNLOADED
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class FetchAnimeInterval(
|
||||
val interval: Int,
|
||||
val leadDays: Int,
|
||||
val followDays: Int,
|
||||
)
|
||||
|
|
|
@ -84,6 +84,13 @@ class MangaScreen(
|
|||
|
||||
val successState = state as MangaScreenModel.State.Success
|
||||
val isHttpSource = remember { successState.source is HttpSource }
|
||||
val fetchInterval = remember(successState.manga.fetchInterval) {
|
||||
FetchMangaInterval(
|
||||
interval = successState.manga.fetchInterval,
|
||||
leadDays = screenModel.leadDay,
|
||||
followDays = screenModel.followDay,
|
||||
)
|
||||
}
|
||||
|
||||
LaunchedEffect(successState.manga, screenModel.source) {
|
||||
if (isHttpSource) {
|
||||
|
@ -101,7 +108,7 @@ class MangaScreen(
|
|||
state = successState,
|
||||
snackbarHostState = screenModel.snackbarHostState,
|
||||
dateFormat = screenModel.dateFormat,
|
||||
intervalDisplay = screenModel::intervalDisplay,
|
||||
fetchInterval = fetchInterval,
|
||||
isTabletUi = isTabletUi(),
|
||||
chapterSwipeStartAction = screenModel.chapterSwipeStartAction,
|
||||
chapterSwipeEndAction = screenModel.chapterSwipeEndAction,
|
||||
|
@ -124,7 +131,7 @@ class MangaScreen(
|
|||
onShareClicked = { shareManga(context, screenModel.manga, screenModel.source) }.takeIf { isHttpSource },
|
||||
onDownloadActionClicked = screenModel::runDownloadAction.takeIf { !successState.source.isLocalOrStub() },
|
||||
onEditCategoryClicked = screenModel::showChangeCategoryDialog.takeIf { successState.manga.favorite },
|
||||
onEditIntervalClicked = screenModel::showSetMangaIntervalDialog.takeIf { screenModel.isIntervalEnabled && successState.manga.favorite },
|
||||
onEditFetchIntervalClicked = screenModel::showSetMangaFetchIntervalDialog.takeIf { screenModel.isUpdateIntervalEnabled && successState.manga.favorite },
|
||||
onMigrateClicked = { navigator.push(MigrateSearchScreen(successState.manga.id)) }.takeIf { successState.manga.favorite },
|
||||
onMultiBookmarkClicked = screenModel::bookmarkChapters,
|
||||
onMultiMarkAsReadClicked = screenModel::markChaptersRead,
|
||||
|
@ -217,11 +224,11 @@ class MangaScreen(
|
|||
LoadingScreen(Modifier.systemBarsPadding())
|
||||
}
|
||||
}
|
||||
is MangaScreenModel.Dialog.SetMangaInterval -> {
|
||||
is MangaScreenModel.Dialog.SetMangaFetchInterval -> {
|
||||
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,
|
||||
onValueChanged = { screenModel.setFetchRangeInterval(dialog.manga, it) },
|
||||
onValueChanged = { screenModel.setFetchInterval(dialog.manga, it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,6 @@ import tachiyomi.domain.track.manga.interactor.GetMangaTracks
|
|||
import tachiyomi.source.local.entries.manga.isLocal
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
class MangaScreenModel(
|
||||
val context: Context,
|
||||
|
@ -131,9 +130,9 @@ class MangaScreenModel(
|
|||
val dateFormat by mutableStateOf(UiPreferences.dateFormat(uiPreferences.dateFormat().get()))
|
||||
val skipFiltered by readerPreferences.skipFiltered().asState(coroutineScope)
|
||||
|
||||
val isIntervalEnabled = LibraryPreferences.ENTRY_OUTSIDE_RELEASE_PERIOD in libraryPreferences.libraryUpdateItemRestriction().get()
|
||||
private val leadDay = libraryPreferences.leadingMangaExpectedDays().get()
|
||||
private val followDay = libraryPreferences.followingMangaExpectedDays().get()
|
||||
val isUpdateIntervalEnabled = LibraryPreferences.ENTRY_OUTSIDE_RELEASE_PERIOD in libraryPreferences.libraryUpdateItemRestriction().get()
|
||||
val leadDay = libraryPreferences.leadingMangaExpectedDays().get()
|
||||
val followDay = libraryPreferences.followingMangaExpectedDays().get()
|
||||
|
||||
private val selectedPositions: Array<Int> = arrayOf(-1, -1) // first and last selected index in list
|
||||
private val selectedChapterIds: HashSet<Long> = HashSet()
|
||||
|
@ -292,7 +291,7 @@ class MangaScreenModel(
|
|||
// Add to library
|
||||
// First, check if duplicate exists if callback is provided
|
||||
if (checkDuplicate) {
|
||||
val duplicate = getDuplicateLibraryManga.await(manga.title)
|
||||
val duplicate = getDuplicateLibraryManga.await(manga).getOrNull(0)
|
||||
|
||||
if (duplicate != null) {
|
||||
updateSuccessState { it.copy(dialog = Dialog.DuplicateManga(manga, duplicate)) }
|
||||
|
@ -368,30 +367,23 @@ class MangaScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun showSetMangaIntervalDialog() {
|
||||
fun showSetMangaFetchIntervalDialog() {
|
||||
val manga = successState?.manga ?: return
|
||||
updateSuccessState {
|
||||
it.copy(dialog = Dialog.SetMangaInterval(manga))
|
||||
it.copy(dialog = Dialog.SetMangaFetchInterval(manga))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this should be in the state/composables
|
||||
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) {
|
||||
fun setFetchInterval(manga: Manga, newInterval: Int) {
|
||||
val interval = when (newInterval) {
|
||||
// reset interval 0 default to trigger recalculation
|
||||
// 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
|
||||
}
|
||||
coroutineScope.launchIO {
|
||||
updateManga.awaitUpdateFetchInterval(
|
||||
manga.copy(calculateInterval = interval),
|
||||
manga.copy(fetchInterval = interval),
|
||||
successState?.chapters?.map { it.chapter }.orEmpty(),
|
||||
)
|
||||
val newManga = mangaRepository.getMangaById(mangaId)
|
||||
|
@ -996,7 +988,7 @@ class MangaScreenModel(
|
|||
data class ChangeCategory(val manga: Manga, val initialSelection: List<CheckboxState<Category>>) : Dialog
|
||||
data class DeleteChapters(val chapters: List<Chapter>) : Dialog
|
||||
data class DuplicateManga(val manga: Manga, val duplicate: Manga) : Dialog
|
||||
data class SetMangaInterval(val manga: Manga) : Dialog
|
||||
data class SetMangaFetchInterval(val manga: Manga) : Dialog
|
||||
data object SettingsSheet : Dialog
|
||||
data object TrackSheet : Dialog
|
||||
data object FullCover : Dialog
|
||||
|
@ -1081,3 +1073,10 @@ data class ChapterItem(
|
|||
) {
|
||||
val isDownloaded = downloadState == MangaDownload.State.DOWNLOADED
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class FetchMangaInterval(
|
||||
val interval: Int,
|
||||
val leadDays: Int,
|
||||
val followDays: Int,
|
||||
)
|
||||
|
|
|
@ -85,7 +85,8 @@ class AnimeUpdatesScreenModel(
|
|||
combine(
|
||||
getUpdates.subscribe(calendar).distinctUntilChanged(),
|
||||
downloadCache.changes,
|
||||
) { updates, _ -> updates }
|
||||
downloadManager.queueState,
|
||||
) { updates, _, _ -> updates }
|
||||
.catch {
|
||||
logcat(LogPriority.ERROR, it)
|
||||
_events.send(Event.InternalError)
|
||||
|
|
|
@ -81,7 +81,8 @@ class MangaUpdatesScreenModel(
|
|||
combine(
|
||||
getUpdates.subscribe(calendar).distinctUntilChanged(),
|
||||
downloadCache.changes,
|
||||
) { updates, _ -> updates }
|
||||
downloadManager.queueState,
|
||||
) { updates, _, _ -> updates }
|
||||
.catch {
|
||||
logcat(LogPriority.ERROR, it)
|
||||
_events.send(Event.InternalError)
|
||||
|
|
|
@ -120,7 +120,7 @@ fun Date.toRelativeString(
|
|||
val difference = now.timeWithOffset.floorNearest(MILLISECONDS_IN_DAY) - this.timeWithOffset.floorNearest(MILLISECONDS_IN_DAY)
|
||||
val days = difference.floorDiv(MILLISECONDS_IN_DAY).toInt()
|
||||
return when {
|
||||
difference < 0 -> context.getString(R.string.recently)
|
||||
difference < 0 -> dateFormat.format(this)
|
||||
difference < MILLISECONDS_IN_DAY -> context.getString(R.string.relative_time_today)
|
||||
difference < MILLISECONDS_IN_DAY.times(7) -> context.resources.getQuantityString(
|
||||
R.plurals.relative_time,
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import org.jetbrains.kotlin.cli.jvm.main
|
||||
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
kotlin("android")
|
||||
kotlin("plugin.serialization")
|
||||
id("com.squareup.sqldelight")
|
||||
id("app.cash.sqldelight")
|
||||
}
|
||||
|
||||
android {
|
||||
|
@ -13,17 +15,19 @@ android {
|
|||
}
|
||||
|
||||
sqldelight {
|
||||
database("Database") {
|
||||
packageName = "tachiyomi.data"
|
||||
dialect = "sqlite:3.24"
|
||||
schemaOutputDirectory = project.file("./src/main/sqldelight")
|
||||
sourceFolders = listOf("sqldelight")
|
||||
}
|
||||
database("AnimeDatabase") {
|
||||
packageName = "tachiyomi.mi.data"
|
||||
dialect = "sqlite:3.24"
|
||||
schemaOutputDirectory = project.file("./src/main/sqldelightanime")
|
||||
sourceFolders = listOf("sqldelightanime")
|
||||
databases {
|
||||
create("Database") {
|
||||
packageName.set("tachiyomi.data")
|
||||
dialect(libs.sqldelight.dialects.sql)
|
||||
schemaOutputDirectory.set(project.file("./src/main/sqldelight"))
|
||||
srcDirs.from(project.file("./src/main/sqldelight"))
|
||||
}
|
||||
create("AnimeDatabase") {
|
||||
packageName.set("tachiyomi.mi.data")
|
||||
dialect(libs.sqldelight.dialects.sql)
|
||||
schemaOutputDirectory.set(project.file("./src/main/sqldelightanime"))
|
||||
srcDirs.from(project.file("./src/main/sqldelightanime"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,9 +37,7 @@ dependencies {
|
|||
implementation(project(":domain"))
|
||||
implementation(project(":core"))
|
||||
|
||||
api(libs.sqldelight.android.driver)
|
||||
api(libs.sqldelight.coroutines)
|
||||
api(libs.sqldelight.android.paging)
|
||||
api(libs.bundles.sqldelight)
|
||||
}
|
||||
|
||||
tasks {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package tachiyomi.data
|
||||
|
||||
import com.squareup.sqldelight.ColumnAdapter
|
||||
import app.cash.sqldelight.ColumnAdapter
|
||||
import eu.kanade.tachiyomi.source.model.UpdateStrategy
|
||||
import java.util.Date
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ val animeMapper: (Long, Long, String, String?, String?, String?, List<String>?,
|
|||
favorite = favorite,
|
||||
lastUpdate = lastUpdate ?: 0,
|
||||
nextUpdate = nextUpdate ?: 0,
|
||||
calculateInterval = calculateInterval.toInt(),
|
||||
fetchInterval = calculateInterval.toInt(),
|
||||
dateAdded = dateAdded,
|
||||
viewerFlags = viewerFlags,
|
||||
episodeFlags = episodeFlags,
|
||||
|
@ -32,7 +32,7 @@ val animeMapper: (Long, Long, String, String?, String?, String?, List<String>?,
|
|||
)
|
||||
}
|
||||
|
||||
val libraryAnime: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, UpdateStrategy, Long, Long, Long?, Long, Long, Long, Long, Long, Long, Long) -> LibraryAnime =
|
||||
val libraryAnime: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, UpdateStrategy, Long, Long, Long?, Long, Double, Long, Long, Long, Double, Long) -> LibraryAnime =
|
||||
{ id, source, url, artist, author, description, genre, title, status, thumbnailUrl, favorite, lastUpdate, nextUpdate, initialized, viewerFlags, episodeFlags, coverLastModified, dateAdded, updateStrategy, calculateInterval, lastModifiedAt, favoriteModifiedAt, totalCount, seenCount, latestUpload, episodeFetchedAt, lastSeen, bookmarkCount, category ->
|
||||
LibraryAnime(
|
||||
anime = animeMapper(
|
||||
|
@ -61,8 +61,8 @@ val libraryAnime: (Long, Long, String, String?, String?, String?, List<String>?,
|
|||
),
|
||||
category = category,
|
||||
totalEpisodes = totalCount,
|
||||
seenCount = seenCount,
|
||||
bookmarkCount = bookmarkCount,
|
||||
seenCount = seenCount.toLong(),
|
||||
bookmarkCount = bookmarkCount.toLong(),
|
||||
latestUpload = latestUpload,
|
||||
episodeFetchedAt = episodeFetchedAt,
|
||||
lastSeen = lastSeen,
|
||||
|
|
|
@ -48,9 +48,9 @@ class AnimeRepositoryImpl(
|
|||
return handler.subscribeToList { animesQueries.getFavoriteBySourceId(sourceId, animeMapper) }
|
||||
}
|
||||
|
||||
override suspend fun getDuplicateLibraryAnime(title: String): Anime? {
|
||||
return handler.awaitOneOrNull {
|
||||
animesQueries.getDuplicateLibraryAnime(title, animeMapper)
|
||||
override suspend fun getDuplicateLibraryAnime(id: Long, title: String): List<Anime> {
|
||||
return handler.awaitList {
|
||||
animesQueries.getDuplicateLibraryAnime(title, id, animeMapper)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ class AnimeRepositoryImpl(
|
|||
}
|
||||
|
||||
override suspend fun insertAnime(anime: Anime): Long? {
|
||||
return handler.awaitOneOrNull(inTransaction = true) {
|
||||
return handler.awaitOneOrNullExecutable(inTransaction = true) {
|
||||
animesQueries.insert(
|
||||
source = anime.source,
|
||||
url = anime.url,
|
||||
|
@ -88,7 +88,7 @@ class AnimeRepositoryImpl(
|
|||
favorite = anime.favorite,
|
||||
lastUpdate = anime.lastUpdate,
|
||||
nextUpdate = anime.nextUpdate,
|
||||
calculateInterval = anime.calculateInterval.toLong(),
|
||||
calculateInterval = anime.fetchInterval.toLong(),
|
||||
initialized = anime.initialized,
|
||||
viewerFlags = anime.viewerFlags,
|
||||
episodeFlags = anime.episodeFlags,
|
||||
|
@ -133,11 +133,11 @@ class AnimeRepositoryImpl(
|
|||
title = value.title,
|
||||
status = value.status,
|
||||
thumbnailUrl = value.thumbnailUrl,
|
||||
favorite = value.favorite?.toLong(),
|
||||
favorite = value.favorite,
|
||||
lastUpdate = value.lastUpdate,
|
||||
nextUpdate = value.nextUpdate,
|
||||
calculateInterval = value.calculateInterval?.toLong(),
|
||||
initialized = value.initialized?.toLong(),
|
||||
calculateInterval = value.fetchInterval?.toLong(),
|
||||
initialized = value.initialized,
|
||||
viewer = value.viewerFlags,
|
||||
episodeFlags = value.episodeFlags,
|
||||
coverLastModified = value.coverLastModified,
|
||||
|
|
|
@ -12,7 +12,7 @@ val mangaMapper: (Long, Long, String, String?, String?, String?, List<String>?,
|
|||
favorite = favorite,
|
||||
lastUpdate = lastUpdate ?: 0,
|
||||
nextUpdate = nextUpdate ?: 0,
|
||||
calculateInterval = calculateInterval.toInt(),
|
||||
fetchInterval = calculateInterval.toInt(),
|
||||
dateAdded = dateAdded,
|
||||
viewerFlags = viewerFlags,
|
||||
chapterFlags = chapterFlags,
|
||||
|
@ -32,7 +32,7 @@ val mangaMapper: (Long, Long, String, String?, String?, String?, List<String>?,
|
|||
)
|
||||
}
|
||||
|
||||
val libraryManga: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, UpdateStrategy, Long, Long, Long?, Long, Long, Long, Long, Long, Long, Long) -> LibraryManga =
|
||||
val libraryManga: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, UpdateStrategy, Long, Long, Long?, Long, Double, Long, Long, Long, Double, Long) -> LibraryManga =
|
||||
{ id, source, url, artist, author, description, genre, title, status, thumbnailUrl, favorite, lastUpdate, nextUpdate, initialized, viewerFlags, chapterFlags, coverLastModified, dateAdded, updateStrategy, calculateInterval, lastModifiedAt, favoriteModifiedAt, totalCount, readCount, latestUpload, chapterFetchedAt, lastRead, bookmarkCount, category ->
|
||||
LibraryManga(
|
||||
manga = mangaMapper(
|
||||
|
@ -61,8 +61,8 @@ val libraryManga: (Long, Long, String, String?, String?, String?, List<String>?,
|
|||
),
|
||||
category = category,
|
||||
totalChapters = totalCount,
|
||||
readCount = readCount,
|
||||
bookmarkCount = bookmarkCount,
|
||||
readCount = readCount.toLong(),
|
||||
bookmarkCount = bookmarkCount.toLong(),
|
||||
latestUpload = latestUpload,
|
||||
chapterFetchedAt = chapterFetchedAt,
|
||||
lastRead = lastRead,
|
||||
|
|
|
@ -48,9 +48,9 @@ class MangaRepositoryImpl(
|
|||
return handler.subscribeToList { mangasQueries.getFavoriteBySourceId(sourceId, mangaMapper) }
|
||||
}
|
||||
|
||||
override suspend fun getDuplicateLibraryManga(title: String): Manga? {
|
||||
return handler.awaitOneOrNull {
|
||||
mangasQueries.getDuplicateLibraryManga(title, mangaMapper)
|
||||
override suspend fun getDuplicateLibraryManga(id: Long, title: String): List<Manga> {
|
||||
return handler.awaitList {
|
||||
mangasQueries.getDuplicateLibraryManga(title, id, mangaMapper)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ class MangaRepositoryImpl(
|
|||
}
|
||||
|
||||
override suspend fun insertManga(manga: Manga): Long? {
|
||||
return handler.awaitOneOrNull(inTransaction = true) {
|
||||
return handler.awaitOneOrNullExecutable(inTransaction = true) {
|
||||
mangasQueries.insert(
|
||||
source = manga.source,
|
||||
url = manga.url,
|
||||
|
@ -88,7 +88,7 @@ class MangaRepositoryImpl(
|
|||
favorite = manga.favorite,
|
||||
lastUpdate = manga.lastUpdate,
|
||||
nextUpdate = manga.nextUpdate,
|
||||
calculateInterval = manga.calculateInterval.toLong(),
|
||||
calculateInterval = manga.fetchInterval.toLong(),
|
||||
initialized = manga.initialized,
|
||||
viewerFlags = manga.viewerFlags,
|
||||
chapterFlags = manga.chapterFlags,
|
||||
|
@ -133,11 +133,11 @@ class MangaRepositoryImpl(
|
|||
title = value.title,
|
||||
status = value.status,
|
||||
thumbnailUrl = value.thumbnailUrl,
|
||||
favorite = value.favorite?.toLong(),
|
||||
favorite = value.favorite,
|
||||
lastUpdate = value.lastUpdate,
|
||||
nextUpdate = value.nextUpdate,
|
||||
calculateInterval = value.calculateInterval?.toLong(),
|
||||
initialized = value.initialized?.toLong(),
|
||||
calculateInterval = value.fetchInterval?.toLong(),
|
||||
initialized = value.initialized,
|
||||
viewer = value.viewerFlags,
|
||||
chapterFlags = value.chapterFlags,
|
||||
coverLastModified = value.coverLastModified,
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package tachiyomi.data.handlers.anime
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import com.squareup.sqldelight.Query
|
||||
import com.squareup.sqldelight.db.SqlDriver
|
||||
import com.squareup.sqldelight.runtime.coroutines.asFlow
|
||||
import com.squareup.sqldelight.runtime.coroutines.mapToList
|
||||
import com.squareup.sqldelight.runtime.coroutines.mapToOne
|
||||
import com.squareup.sqldelight.runtime.coroutines.mapToOneOrNull
|
||||
import app.cash.sqldelight.ExecutableQuery
|
||||
import app.cash.sqldelight.Query
|
||||
import app.cash.sqldelight.coroutines.asFlow
|
||||
import app.cash.sqldelight.coroutines.mapToList
|
||||
import app.cash.sqldelight.coroutines.mapToOne
|
||||
import app.cash.sqldelight.coroutines.mapToOneOrNull
|
||||
import app.cash.sqldelight.db.SqlDriver
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
@ -40,6 +41,13 @@ class AndroidAnimeDatabaseHandler(
|
|||
return dispatch(inTransaction) { block(db).executeAsOne() }
|
||||
}
|
||||
|
||||
override suspend fun <T : Any> awaitOneExecutable(
|
||||
inTransaction: Boolean,
|
||||
block: suspend AnimeDatabase.() -> ExecutableQuery<T>,
|
||||
): T {
|
||||
return dispatch(inTransaction) { block(db).executeAsOne() }
|
||||
}
|
||||
|
||||
override suspend fun <T : Any> awaitOneOrNull(
|
||||
inTransaction: Boolean,
|
||||
block: suspend AnimeDatabase.() -> Query<T>,
|
||||
|
@ -47,6 +55,13 @@ class AndroidAnimeDatabaseHandler(
|
|||
return dispatch(inTransaction) { block(db).executeAsOneOrNull() }
|
||||
}
|
||||
|
||||
override suspend fun <T : Any> awaitOneOrNullExecutable(
|
||||
inTransaction: Boolean,
|
||||
block: suspend AnimeDatabase.() -> ExecutableQuery<T>,
|
||||
): T? {
|
||||
return dispatch(inTransaction) { block(db).executeAsOneOrNull() }
|
||||
}
|
||||
|
||||
override fun <T : Any> subscribeToList(block: AnimeDatabase.() -> Query<T>): Flow<List<T>> {
|
||||
return block(db).asFlow().mapToList(queryDispatcher)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package tachiyomi.data.handlers.anime
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import com.squareup.sqldelight.Query
|
||||
import app.cash.sqldelight.ExecutableQuery
|
||||
import app.cash.sqldelight.Query
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import tachiyomi.mi.data.AnimeDatabase
|
||||
|
||||
|
@ -19,11 +20,21 @@ interface AnimeDatabaseHandler {
|
|||
block: suspend AnimeDatabase.() -> Query<T>,
|
||||
): T
|
||||
|
||||
suspend fun <T : Any> awaitOneExecutable(
|
||||
inTransaction: Boolean = false,
|
||||
block: suspend AnimeDatabase.() -> ExecutableQuery<T>,
|
||||
): T
|
||||
|
||||
suspend fun <T : Any> awaitOneOrNull(
|
||||
inTransaction: Boolean = false,
|
||||
block: suspend AnimeDatabase.() -> Query<T>,
|
||||
): T?
|
||||
|
||||
suspend fun <T : Any> awaitOneOrNullExecutable(
|
||||
inTransaction: Boolean = false,
|
||||
block: suspend AnimeDatabase.() -> ExecutableQuery<T>,
|
||||
): T?
|
||||
|
||||
fun <T : Any> subscribeToList(block: AnimeDatabase.() -> Query<T>): Flow<List<T>>
|
||||
|
||||
fun <T : Any> subscribeToOne(block: AnimeDatabase.() -> Query<T>): Flow<T>
|
||||
|
|
|
@ -2,7 +2,7 @@ package tachiyomi.data.handlers.anime
|
|||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import com.squareup.sqldelight.Query
|
||||
import app.cash.sqldelight.Query
|
||||
import tachiyomi.mi.data.AnimeDatabase
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package tachiyomi.data.handlers.manga
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import com.squareup.sqldelight.Query
|
||||
import com.squareup.sqldelight.db.SqlDriver
|
||||
import com.squareup.sqldelight.runtime.coroutines.asFlow
|
||||
import com.squareup.sqldelight.runtime.coroutines.mapToList
|
||||
import com.squareup.sqldelight.runtime.coroutines.mapToOne
|
||||
import com.squareup.sqldelight.runtime.coroutines.mapToOneOrNull
|
||||
import app.cash.sqldelight.ExecutableQuery
|
||||
import app.cash.sqldelight.Query
|
||||
import app.cash.sqldelight.coroutines.asFlow
|
||||
import app.cash.sqldelight.coroutines.mapToList
|
||||
import app.cash.sqldelight.coroutines.mapToOne
|
||||
import app.cash.sqldelight.coroutines.mapToOneOrNull
|
||||
import app.cash.sqldelight.db.SqlDriver
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
@ -40,6 +41,13 @@ class AndroidMangaDatabaseHandler(
|
|||
return dispatch(inTransaction) { block(db).executeAsOne() }
|
||||
}
|
||||
|
||||
override suspend fun <T : Any> awaitOneExecutable(
|
||||
inTransaction: Boolean,
|
||||
block: suspend Database.() -> ExecutableQuery<T>,
|
||||
): T {
|
||||
return dispatch(inTransaction) { block(db).executeAsOne() }
|
||||
}
|
||||
|
||||
override suspend fun <T : Any> awaitOneOrNull(
|
||||
inTransaction: Boolean,
|
||||
block: suspend Database.() -> Query<T>,
|
||||
|
@ -47,6 +55,13 @@ class AndroidMangaDatabaseHandler(
|
|||
return dispatch(inTransaction) { block(db).executeAsOneOrNull() }
|
||||
}
|
||||
|
||||
override suspend fun <T : Any> awaitOneOrNullExecutable(
|
||||
inTransaction: Boolean,
|
||||
block: suspend Database.() -> ExecutableQuery<T>,
|
||||
): T? {
|
||||
return dispatch(inTransaction) { block(db).executeAsOneOrNull() }
|
||||
}
|
||||
|
||||
override fun <T : Any> subscribeToList(block: Database.() -> Query<T>): Flow<List<T>> {
|
||||
return block(db).asFlow().mapToList(queryDispatcher)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package tachiyomi.data.handlers.manga
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import com.squareup.sqldelight.Query
|
||||
import app.cash.sqldelight.ExecutableQuery
|
||||
import app.cash.sqldelight.Query
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import tachiyomi.data.Database
|
||||
|
||||
|
@ -19,11 +20,21 @@ interface MangaDatabaseHandler {
|
|||
block: suspend Database.() -> Query<T>,
|
||||
): T
|
||||
|
||||
suspend fun <T : Any> awaitOneExecutable(
|
||||
inTransaction: Boolean = false,
|
||||
block: suspend Database.() -> ExecutableQuery<T>,
|
||||
): T
|
||||
|
||||
suspend fun <T : Any> awaitOneOrNull(
|
||||
inTransaction: Boolean = false,
|
||||
block: suspend Database.() -> Query<T>,
|
||||
): T?
|
||||
|
||||
suspend fun <T : Any> awaitOneOrNullExecutable(
|
||||
inTransaction: Boolean = false,
|
||||
block: suspend Database.() -> ExecutableQuery<T>,
|
||||
): T?
|
||||
|
||||
fun <T : Any> subscribeToList(block: Database.() -> Query<T>): Flow<List<T>>
|
||||
|
||||
fun <T : Any> subscribeToOne(block: Database.() -> Query<T>): Flow<T>
|
||||
|
|
|
@ -2,7 +2,7 @@ package tachiyomi.data.handlers.manga
|
|||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import com.squareup.sqldelight.Query
|
||||
import app.cash.sqldelight.Query
|
||||
import tachiyomi.data.Database
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package tachiyomi.data.items.chapter
|
|||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.util.lang.toLong
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.data.handlers.manga.MangaDatabaseHandler
|
||||
import tachiyomi.domain.items.chapter.model.Chapter
|
||||
|
@ -56,8 +55,8 @@ class ChapterRepositoryImpl(
|
|||
url = chapterUpdate.url,
|
||||
name = chapterUpdate.name,
|
||||
scanlator = chapterUpdate.scanlator,
|
||||
read = chapterUpdate.read?.toLong(),
|
||||
bookmark = chapterUpdate.bookmark?.toLong(),
|
||||
read = chapterUpdate.read,
|
||||
bookmark = chapterUpdate.bookmark,
|
||||
lastPageRead = chapterUpdate.lastPageRead,
|
||||
chapterNumber = chapterUpdate.chapterNumber?.toDouble(),
|
||||
sourceOrder = chapterUpdate.sourceOrder,
|
||||
|
|
|
@ -2,7 +2,6 @@ package tachiyomi.data.items.episode
|
|||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.util.lang.toLong
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.data.handlers.anime.AnimeDatabaseHandler
|
||||
import tachiyomi.domain.items.episode.model.Episode
|
||||
|
@ -57,8 +56,8 @@ class EpisodeRepositoryImpl(
|
|||
url = episodeUpdate.url,
|
||||
name = episodeUpdate.name,
|
||||
scanlator = episodeUpdate.scanlator,
|
||||
seen = episodeUpdate.seen?.toLong(),
|
||||
bookmark = episodeUpdate.bookmark?.toLong(),
|
||||
seen = episodeUpdate.seen,
|
||||
bookmark = episodeUpdate.bookmark,
|
||||
lastSecondSeen = episodeUpdate.lastSecondSeen,
|
||||
totalSeconds = episodeUpdate.totalSeconds,
|
||||
episodeNumber = episodeUpdate.episodeNumber?.toDouble(),
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import kotlin.Boolean;
|
||||
import kotlin.Float;
|
||||
|
||||
CREATE TABLE chapters(
|
||||
_id INTEGER NOT NULL PRIMARY KEY,
|
||||
manga_id INTEGER NOT NULL,
|
||||
|
@ -9,9 +12,9 @@ CREATE TABLE chapters(
|
|||
last_page_read INTEGER NOT NULL,
|
||||
chapter_number REAL AS Float NOT NULL,
|
||||
source_order INTEGER NOT NULL,
|
||||
date_fetch INTEGER AS Long NOT NULL,
|
||||
date_upload INTEGER AS Long NOT NULL,
|
||||
last_modified_at INTEGER AS Long NOT NULL DEFAULT 0,
|
||||
date_fetch INTEGER NOT NULL,
|
||||
date_upload INTEGER NOT NULL,
|
||||
last_modified_at INTEGER NOT NULL DEFAULT 0,
|
||||
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import kotlin.Float;
|
||||
|
||||
CREATE TABLE manga_sync(
|
||||
_id INTEGER NOT NULL PRIMARY KEY,
|
||||
manga_id INTEGER NOT NULL,
|
||||
|
@ -10,8 +12,8 @@ CREATE TABLE manga_sync(
|
|||
status INTEGER NOT NULL,
|
||||
score REAL AS Float NOT NULL,
|
||||
remote_url TEXT NOT NULL,
|
||||
start_date INTEGER AS Long NOT NULL,
|
||||
finish_date INTEGER AS Long NOT NULL,
|
||||
start_date INTEGER NOT NULL,
|
||||
finish_date INTEGER NOT NULL,
|
||||
UNIQUE (manga_id, sync_id) ON CONFLICT REPLACE,
|
||||
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
||||
ON DELETE CASCADE
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import eu.kanade.tachiyomi.source.model.UpdateStrategy;
|
||||
import java.lang.String;
|
||||
import kotlin.collections.List;
|
||||
import kotlin.Boolean;
|
||||
import kotlin.String;
|
||||
|
||||
CREATE TABLE mangas(
|
||||
_id INTEGER NOT NULL PRIMARY KEY,
|
||||
|
@ -14,17 +15,17 @@ CREATE TABLE mangas(
|
|||
status INTEGER NOT NULL,
|
||||
thumbnail_url TEXT,
|
||||
favorite INTEGER AS Boolean NOT NULL,
|
||||
last_update INTEGER AS Long,
|
||||
next_update INTEGER AS Long,
|
||||
last_update INTEGER,
|
||||
next_update INTEGER,
|
||||
initialized INTEGER AS Boolean NOT NULL,
|
||||
viewer INTEGER NOT NULL,
|
||||
chapter_flags INTEGER NOT NULL,
|
||||
cover_last_modified INTEGER AS Long NOT NULL,
|
||||
date_added INTEGER AS Long NOT NULL,
|
||||
cover_last_modified INTEGER NOT NULL,
|
||||
date_added INTEGER NOT NULL,
|
||||
update_strategy INTEGER AS UpdateStrategy NOT NULL DEFAULT 0,
|
||||
calculate_interval INTEGER DEFAULT 0 NOT NULL,
|
||||
last_modified_at INTEGER AS Long NOT NULL DEFAULT 0,
|
||||
favorite_modified_at INTEGER AS Long
|
||||
last_modified_at INTEGER NOT NULL DEFAULT 0,
|
||||
favorite_modified_at INTEGER
|
||||
);
|
||||
|
||||
CREATE INDEX library_favorite_index ON mangas(favorite) WHERE favorite = 1;
|
||||
|
@ -92,7 +93,7 @@ SELECT *
|
|||
FROM mangas
|
||||
WHERE favorite = 1
|
||||
AND LOWER(title) = :title
|
||||
LIMIT 1;
|
||||
AND _id != :id;
|
||||
|
||||
resetViewerFlags:
|
||||
UPDATE mangas
|
||||
|
|
|
@ -2,7 +2,7 @@ CREATE TABLE mangas_categories(
|
|||
_id INTEGER NOT NULL PRIMARY KEY,
|
||||
manga_id INTEGER NOT NULL,
|
||||
category_id INTEGER NOT NULL,
|
||||
last_modified_at INTEGER AS Long NOT NULL DEFAULT 0,
|
||||
last_modified_at INTEGER NOT NULL DEFAULT 0,
|
||||
FOREIGN KEY(category_id) REFERENCES categories (_id)
|
||||
ON DELETE CASCADE,
|
||||
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import kotlin.Float;
|
||||
|
||||
CREATE TABLE anime_sync(
|
||||
_id INTEGER NOT NULL PRIMARY KEY,
|
||||
anime_id INTEGER NOT NULL,
|
||||
|
@ -10,8 +12,8 @@ CREATE TABLE anime_sync(
|
|||
status INTEGER NOT NULL,
|
||||
score REAL AS Float NOT NULL,
|
||||
remote_url TEXT NOT NULL,
|
||||
start_date INTEGER AS Long NOT NULL,
|
||||
finish_date INTEGER AS Long NOT NULL,
|
||||
start_date INTEGER NOT NULL,
|
||||
finish_date INTEGER NOT NULL,
|
||||
UNIQUE (anime_id, sync_id) ON CONFLICT REPLACE,
|
||||
FOREIGN KEY(anime_id) REFERENCES animes (_id)
|
||||
ON DELETE CASCADE
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import eu.kanade.tachiyomi.source.model.UpdateStrategy;
|
||||
import java.lang.String;
|
||||
import kotlin.collections.List;
|
||||
import kotlin.Boolean;
|
||||
import kotlin.String;
|
||||
|
||||
CREATE TABLE animes(
|
||||
_id INTEGER NOT NULL PRIMARY KEY,
|
||||
|
@ -14,17 +15,17 @@ CREATE TABLE animes(
|
|||
status INTEGER NOT NULL,
|
||||
thumbnail_url TEXT,
|
||||
favorite INTEGER AS Boolean NOT NULL,
|
||||
last_update INTEGER AS Long,
|
||||
next_update INTEGER AS Long,
|
||||
last_update INTEGER,
|
||||
next_update INTEGER,
|
||||
initialized INTEGER AS Boolean NOT NULL,
|
||||
viewer INTEGER NOT NULL,
|
||||
episode_flags INTEGER NOT NULL,
|
||||
cover_last_modified INTEGER AS Long NOT NULL,
|
||||
date_added INTEGER AS Long NOT NULL,
|
||||
cover_last_modified INTEGER NOT NULL,
|
||||
date_added INTEGER NOT NULL,
|
||||
update_strategy INTEGER AS UpdateStrategy NOT NULL DEFAULT 0,
|
||||
calculate_interval INTEGER DEFAULT 0 NOT NULL,
|
||||
last_modified_at INTEGER AS Long NOT NULL DEFAULT 0,
|
||||
favorite_modified_at INTEGER AS Long
|
||||
last_modified_at INTEGER NOT NULL DEFAULT 0,
|
||||
favorite_modified_at INTEGER
|
||||
);
|
||||
|
||||
CREATE INDEX animelib_favorite_index ON animes(favorite) WHERE favorite = 1;
|
||||
|
@ -92,7 +93,7 @@ SELECT *
|
|||
FROM animes
|
||||
WHERE favorite = 1
|
||||
AND LOWER(title) = :title
|
||||
LIMIT 1;
|
||||
AND _id != :id;
|
||||
|
||||
resetViewerFlags:
|
||||
UPDATE animes
|
||||
|
|
|
@ -2,7 +2,7 @@ CREATE TABLE animes_categories(
|
|||
_id INTEGER NOT NULL PRIMARY KEY,
|
||||
anime_id INTEGER NOT NULL,
|
||||
category_id INTEGER NOT NULL,
|
||||
last_modified_at INTEGER AS Long NOT NULL DEFAULT 0,
|
||||
last_modified_at INTEGER NOT NULL DEFAULT 0,
|
||||
FOREIGN KEY(category_id) REFERENCES categories (_id)
|
||||
ON DELETE CASCADE,
|
||||
FOREIGN KEY(anime_id) REFERENCES animes (_id)
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import kotlin.Boolean;
|
||||
import kotlin.Float;
|
||||
|
||||
CREATE TABLE episodes(
|
||||
_id INTEGER NOT NULL PRIMARY KEY,
|
||||
anime_id INTEGER NOT NULL,
|
||||
|
@ -10,9 +13,9 @@ CREATE TABLE episodes(
|
|||
total_seconds INTEGER NOT NULL,
|
||||
episode_number REAL AS Float NOT NULL,
|
||||
source_order INTEGER NOT NULL,
|
||||
date_fetch INTEGER AS Long NOT NULL,
|
||||
date_upload INTEGER AS Long NOT NULL,
|
||||
last_modified_at INTEGER AS Long NOT NULL DEFAULT 0,
|
||||
date_fetch INTEGER NOT NULL,
|
||||
date_upload INTEGER NOT NULL,
|
||||
last_modified_at INTEGER NOT NULL DEFAULT 0,
|
||||
FOREIGN KEY(anime_id) REFERENCES animes (_id)
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
|
@ -54,7 +57,7 @@ WHERE url = :episodeUrl;
|
|||
getEpisodeByUrlAndAnimeId:
|
||||
SELECT *
|
||||
FROM episodes
|
||||
WHERE url = :chapterUrl
|
||||
WHERE url = :episodeUrl
|
||||
AND anime_id = :animeId;
|
||||
|
||||
removeEpisodesWithIds:
|
||||
|
|
|
@ -30,7 +30,7 @@ SELECT
|
|||
episodes._id AS episodeId,
|
||||
animes.title,
|
||||
animes.thumbnail_url AS thumbnailUrl,
|
||||
episodes.chapter_number AS episodeNumber,
|
||||
episodes.episode_number AS episodeNumber,
|
||||
animehistory.last_seen AS seenAt,
|
||||
max_last_seen.last_seen AS maxSeenAt,
|
||||
max_last_seen.episode_id AS maxSeenAtEpisodeId
|
||||
|
@ -47,4 +47,4 @@ JOIN (
|
|||
) AS max_last_seen
|
||||
ON episodes.anime_id = max_last_seen.anime_id;
|
||||
|
||||
CREATE INDEX animehistory_history_chapter_id_index ON animehistory(episode_id);
|
||||
CREATE INDEX animehistory_history_episode_id_index ON animehistory(episode_id);
|
|
@ -9,8 +9,8 @@ UPDATE animes_categories SET last_modified_at = strftime('%s', 'now');
|
|||
UPDATE episodes SET last_modified_at = strftime('%s', 'now');
|
||||
|
||||
-- Create triggers
|
||||
DROP TRIGGER IF EXISTS update_last_modified_at_mangas;
|
||||
CREATE TRIGGER update_last_modified_at_mangas
|
||||
DROP TRIGGER IF EXISTS update_last_modified_at_animes;
|
||||
CREATE TRIGGER update_last_modified_at_animes
|
||||
AFTER UPDATE ON animes
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
|
@ -19,8 +19,8 @@ BEGIN
|
|||
WHERE _id = new._id;
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS update_favorite_modified_at_mangas;
|
||||
CREATE TRIGGER update_last_favorited_at_mangas
|
||||
DROP TRIGGER IF EXISTS update_favorite_modified_at_animes;
|
||||
CREATE TRIGGER update_last_favorited_at_animes
|
||||
AFTER UPDATE OF favorite ON animes
|
||||
BEGIN
|
||||
UPDATE animes
|
||||
|
@ -28,8 +28,8 @@ BEGIN
|
|||
WHERE _id = new._id;
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS update_last_modified_at_chapters;
|
||||
CREATE TRIGGER update_last_modified_at_chapters
|
||||
DROP TRIGGER IF EXISTS update_last_modified_at_episodes;
|
||||
CREATE TRIGGER update_last_modified_at_episodes
|
||||
AFTER UPDATE ON episodes
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
|
@ -38,8 +38,8 @@ BEGIN
|
|||
WHERE _id = new._id;
|
||||
END;
|
||||
|
||||
DROP TRIGGER IF EXISTS update_last_modified_at_mangas_categories;
|
||||
CREATE TRIGGER update_last_modified_at_mangas_categories
|
||||
DROP TRIGGER IF EXISTS update_last_modified_at_animes_categories;
|
||||
CREATE TRIGGER update_last_modified_at_animes_categories
|
||||
AFTER UPDATE ON animes_categories
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
|
|
|
@ -7,7 +7,7 @@ class GetDuplicateLibraryAnime(
|
|||
private val animeRepository: AnimeRepository,
|
||||
) {
|
||||
|
||||
suspend fun await(title: String): Anime? {
|
||||
return animeRepository.getDuplicateLibraryAnime(title.lowercase())
|
||||
suspend fun await(anime: Anime): List<Anime> {
|
||||
return animeRepository.getDuplicateLibraryAnime(anime.id, anime.title.lowercase())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,32 +13,32 @@ import kotlin.math.absoluteValue
|
|||
|
||||
const val MAX_GRACE_PERIOD = 28
|
||||
|
||||
class SetAnimeUpdateInterval(
|
||||
class SetAnimeFetchInterval(
|
||||
private val libraryPreferences: LibraryPreferences = Injekt.get(),
|
||||
) {
|
||||
|
||||
fun updateInterval(
|
||||
fun update(
|
||||
anime: Anime,
|
||||
episodes: List<Episode>,
|
||||
zonedDateTime: ZonedDateTime,
|
||||
fetchRange: Pair<Long, Long>,
|
||||
): AnimeUpdate? {
|
||||
val currentFetchRange = if (fetchRange.first == 0L && fetchRange.second == 0L) {
|
||||
getCurrentFetchRange(ZonedDateTime.now())
|
||||
val currentInterval = if (fetchRange.first == 0L && fetchRange.second == 0L) {
|
||||
getCurrent(ZonedDateTime.now())
|
||||
} else {
|
||||
fetchRange
|
||||
}
|
||||
val interval = anime.calculateInterval.takeIf { it < 0 } ?: calculateInterval(episodes, zonedDateTime)
|
||||
val nextUpdate = calculateNextUpdate(anime, interval, zonedDateTime, currentFetchRange)
|
||||
val interval = anime.fetchInterval.takeIf { it < 0 } ?: calculateInterval(episodes, zonedDateTime)
|
||||
val nextUpdate = calculateNextUpdate(anime, interval, zonedDateTime, currentInterval)
|
||||
|
||||
return if (anime.nextUpdate == nextUpdate && anime.calculateInterval == interval) {
|
||||
return if (anime.nextUpdate == nextUpdate && anime.fetchInterval == interval) {
|
||||
null
|
||||
} else {
|
||||
AnimeUpdate(id = anime.id, nextUpdate = nextUpdate, calculateInterval = interval)
|
||||
AnimeUpdate(id = anime.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.
|
||||
var followRange = 0
|
||||
var leadRange = 0
|
||||
|
@ -103,7 +103,7 @@ class SetAnimeUpdateInterval(
|
|||
): Long {
|
||||
return if (
|
||||
anime.nextUpdate !in fetchRange.first.rangeTo(fetchRange.second + 1) ||
|
||||
anime.calculateInterval == 0
|
||||
anime.fetchInterval == 0
|
||||
) {
|
||||
val latestDate = ZonedDateTime.ofInstant(Instant.ofEpochMilli(anime.lastUpdate), zonedDateTime.zone).toLocalDate().atStartOfDay()
|
||||
val timeSinceLatest = ChronoUnit.DAYS.between(latestDate, zonedDateTime).toInt()
|
|
@ -11,7 +11,7 @@ data class Anime(
|
|||
val favorite: Boolean,
|
||||
val lastUpdate: Long,
|
||||
val nextUpdate: Long,
|
||||
val calculateInterval: Int,
|
||||
val fetchInterval: Int,
|
||||
val dateAdded: Long,
|
||||
val viewerFlags: Long,
|
||||
val episodeFlags: Long,
|
||||
|
@ -118,7 +118,7 @@ data class Anime(
|
|||
favorite = false,
|
||||
lastUpdate = 0L,
|
||||
nextUpdate = 0L,
|
||||
calculateInterval = 0,
|
||||
fetchInterval = 0,
|
||||
dateAdded = 0L,
|
||||
viewerFlags = 0L,
|
||||
episodeFlags = 0L,
|
||||
|
|
|
@ -8,7 +8,7 @@ data class AnimeUpdate(
|
|||
val favorite: Boolean? = null,
|
||||
val lastUpdate: Long? = null,
|
||||
val nextUpdate: Long? = null,
|
||||
val calculateInterval: Int? = null,
|
||||
val fetchInterval: Int? = null,
|
||||
val dateAdded: Long? = null,
|
||||
val viewerFlags: Long? = null,
|
||||
val episodeFlags: Long? = null,
|
||||
|
@ -32,7 +32,7 @@ fun Anime.toAnimeUpdate(): AnimeUpdate {
|
|||
favorite = favorite,
|
||||
lastUpdate = lastUpdate,
|
||||
nextUpdate = nextUpdate,
|
||||
calculateInterval = calculateInterval,
|
||||
fetchInterval = fetchInterval,
|
||||
dateAdded = dateAdded,
|
||||
viewerFlags = viewerFlags,
|
||||
episodeFlags = episodeFlags,
|
||||
|
|
|
@ -23,7 +23,7 @@ interface AnimeRepository {
|
|||
|
||||
fun getAnimeFavoritesBySourceId(sourceId: Long): Flow<List<Anime>>
|
||||
|
||||
suspend fun getDuplicateLibraryAnime(title: String): Anime?
|
||||
suspend fun getDuplicateLibraryAnime(id: Long, title: String): List<Anime>
|
||||
|
||||
suspend fun resetAnimeViewerFlags(): Boolean
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ class GetDuplicateLibraryManga(
|
|||
private val mangaRepository: MangaRepository,
|
||||
) {
|
||||
|
||||
suspend fun await(title: String): Manga? {
|
||||
return mangaRepository.getDuplicateLibraryManga(title.lowercase())
|
||||
suspend fun await(manga: Manga): List<Manga> {
|
||||
return mangaRepository.getDuplicateLibraryManga(manga.id, manga.title.lowercase())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,32 +13,32 @@ import kotlin.math.absoluteValue
|
|||
|
||||
const val MAX_GRACE_PERIOD = 28
|
||||
|
||||
class SetMangaUpdateInterval(
|
||||
class SetMangaFetchInterval(
|
||||
private val libraryPreferences: LibraryPreferences = Injekt.get(),
|
||||
) {
|
||||
|
||||
fun updateInterval(
|
||||
fun update(
|
||||
manga: Manga,
|
||||
chapters: List<Chapter>,
|
||||
zonedDateTime: ZonedDateTime,
|
||||
fetchRange: Pair<Long, Long>,
|
||||
): MangaUpdate? {
|
||||
val currentFetchRange = if (fetchRange.first == 0L && fetchRange.second == 0L) {
|
||||
getCurrentFetchRange(ZonedDateTime.now())
|
||||
val currentInterval = if (fetchRange.first == 0L && fetchRange.second == 0L) {
|
||||
getCurrent(ZonedDateTime.now())
|
||||
} else {
|
||||
fetchRange
|
||||
}
|
||||
val interval = manga.calculateInterval.takeIf { it < 0 } ?: calculateInterval(chapters, zonedDateTime)
|
||||
val nextUpdate = calculateNextUpdate(manga, interval, zonedDateTime, currentFetchRange)
|
||||
val interval = manga.fetchInterval.takeIf { it < 0 } ?: calculateInterval(chapters, zonedDateTime)
|
||||
val nextUpdate = calculateNextUpdate(manga, interval, zonedDateTime, currentInterval)
|
||||
|
||||
return if (manga.nextUpdate == nextUpdate && manga.calculateInterval == interval) {
|
||||
return if (manga.nextUpdate == nextUpdate && manga.fetchInterval == interval) {
|
||||
null
|
||||
} 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.
|
||||
var followRange = 0
|
||||
var leadRange = 0
|
||||
|
@ -103,7 +103,7 @@ class SetMangaUpdateInterval(
|
|||
): Long {
|
||||
return if (
|
||||
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 timeSinceLatest = ChronoUnit.DAYS.between(latestDate, zonedDateTime).toInt()
|
|
@ -10,7 +10,7 @@ data class Manga(
|
|||
val favorite: Boolean,
|
||||
val lastUpdate: Long,
|
||||
val nextUpdate: Long,
|
||||
val calculateInterval: Int,
|
||||
val fetchInterval: Int,
|
||||
val dateAdded: Long,
|
||||
val viewerFlags: Long,
|
||||
val chapterFlags: Long,
|
||||
|
@ -99,7 +99,7 @@ data class Manga(
|
|||
favorite = false,
|
||||
lastUpdate = 0L,
|
||||
nextUpdate = 0L,
|
||||
calculateInterval = 0,
|
||||
fetchInterval = 0,
|
||||
dateAdded = 0L,
|
||||
viewerFlags = 0L,
|
||||
chapterFlags = 0L,
|
||||
|
|
|
@ -8,7 +8,7 @@ data class MangaUpdate(
|
|||
val favorite: Boolean? = null,
|
||||
val lastUpdate: Long? = null,
|
||||
val nextUpdate: Long? = null,
|
||||
val calculateInterval: Int? = null,
|
||||
val fetchInterval: Int? = null,
|
||||
val dateAdded: Long? = null,
|
||||
val viewerFlags: Long? = null,
|
||||
val chapterFlags: Long? = null,
|
||||
|
@ -32,7 +32,7 @@ fun Manga.toMangaUpdate(): MangaUpdate {
|
|||
favorite = favorite,
|
||||
lastUpdate = lastUpdate,
|
||||
nextUpdate = nextUpdate,
|
||||
calculateInterval = calculateInterval,
|
||||
fetchInterval = fetchInterval,
|
||||
dateAdded = dateAdded,
|
||||
viewerFlags = viewerFlags,
|
||||
chapterFlags = chapterFlags,
|
||||
|
|
|
@ -23,7 +23,7 @@ interface MangaRepository {
|
|||
|
||||
fun getMangaFavoritesBySourceId(sourceId: Long): Flow<List<Manga>>
|
||||
|
||||
suspend fun getDuplicateLibraryManga(title: String): Manga?
|
||||
suspend fun getDuplicateLibraryManga(id: Long, title: String): List<Manga>
|
||||
|
||||
suspend fun resetMangaViewerFlags(): Boolean
|
||||
|
||||
|
|
|
@ -10,14 +10,14 @@ import java.time.Duration
|
|||
import java.time.ZonedDateTime
|
||||
|
||||
@Execution(ExecutionMode.CONCURRENT)
|
||||
class SetAnimeUpdateIntervalTest {
|
||||
class SetAnimeFetchIntervalTest {
|
||||
private val testTime = ZonedDateTime.parse("2020-01-01T00:00:00Z")
|
||||
private var episode = Episode.create().copy(
|
||||
dateFetch = testTime.toEpochSecond() * 1000,
|
||||
dateUpload = testTime.toEpochSecond() * 1000,
|
||||
)
|
||||
|
||||
private val setAnimeUpdateInterval = SetAnimeUpdateInterval(mockk())
|
||||
private val setAnimeFetchInterval = SetAnimeFetchInterval(mockk())
|
||||
|
||||
private fun episodeAddTime(episode: Episode, duration: Duration): Episode {
|
||||
val newTime = testTime.plus(duration).toEpochSecond() * 1000
|
||||
|
@ -33,7 +33,7 @@ class SetAnimeUpdateIntervalTest {
|
|||
val newEpisode = episodeAddTime(episode, duration)
|
||||
episodes.add(newEpisode)
|
||||
}
|
||||
setAnimeUpdateInterval.calculateInterval(episodes, testTime) shouldBe 7
|
||||
setAnimeFetchInterval.calculateInterval(episodes, testTime) shouldBe 7
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -44,7 +44,7 @@ class SetAnimeUpdateIntervalTest {
|
|||
val newEpisode = episodeAddTime(episode, duration)
|
||||
episodes.add(newEpisode)
|
||||
}
|
||||
setAnimeUpdateInterval.calculateInterval(episodes, testTime) shouldBe 7
|
||||
setAnimeFetchInterval.calculateInterval(episodes, testTime) shouldBe 7
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -60,7 +60,7 @@ class SetAnimeUpdateIntervalTest {
|
|||
val newEpisode = episodeAddTime(episode, duration)
|
||||
episodes.add(newEpisode)
|
||||
}
|
||||
setAnimeUpdateInterval.calculateInterval(episodes, testTime) shouldBe 7
|
||||
setAnimeFetchInterval.calculateInterval(episodes, testTime) shouldBe 7
|
||||
}
|
||||
|
||||
// Default 1 if interval less than 1
|
||||
|
@ -72,7 +72,7 @@ class SetAnimeUpdateIntervalTest {
|
|||
val newEpisode = episodeAddTime(episode, duration)
|
||||
episodes.add(newEpisode)
|
||||
}
|
||||
setAnimeUpdateInterval.calculateInterval(episodes, testTime) shouldBe 1
|
||||
setAnimeFetchInterval.calculateInterval(episodes, testTime) shouldBe 1
|
||||
}
|
||||
|
||||
// Normal interval calculation
|
||||
|
@ -84,7 +84,7 @@ class SetAnimeUpdateIntervalTest {
|
|||
val newEpisode = episodeAddTime(episode, duration)
|
||||
episodes.add(newEpisode)
|
||||
}
|
||||
setAnimeUpdateInterval.calculateInterval(episodes, testTime) shouldBe 1
|
||||
setAnimeFetchInterval.calculateInterval(episodes, testTime) shouldBe 1
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -95,7 +95,7 @@ class SetAnimeUpdateIntervalTest {
|
|||
val newEpisode = episodeAddTime(episode, duration)
|
||||
episodes.add(newEpisode)
|
||||
}
|
||||
setAnimeUpdateInterval.calculateInterval(episodes, testTime) shouldBe 2
|
||||
setAnimeFetchInterval.calculateInterval(episodes, testTime) shouldBe 2
|
||||
}
|
||||
|
||||
// If interval is decimal, floor to closest integer
|
||||
|
@ -107,7 +107,7 @@ class SetAnimeUpdateIntervalTest {
|
|||
val newEpisode = episodeAddTime(episode, duration)
|
||||
episodes.add(newEpisode)
|
||||
}
|
||||
setAnimeUpdateInterval.calculateInterval(episodes, testTime) shouldBe 1
|
||||
setAnimeFetchInterval.calculateInterval(episodes, testTime) shouldBe 1
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -118,7 +118,7 @@ class SetAnimeUpdateIntervalTest {
|
|||
val newEpisode = episodeAddTime(episode, duration)
|
||||
episodes.add(newEpisode)
|
||||
}
|
||||
setAnimeUpdateInterval.calculateInterval(episodes, testTime) shouldBe 1
|
||||
setAnimeFetchInterval.calculateInterval(episodes, testTime) shouldBe 1
|
||||
}
|
||||
|
||||
// Use fetch time if upload time not available
|
||||
|
@ -130,6 +130,6 @@ class SetAnimeUpdateIntervalTest {
|
|||
val newEpisode = episodeAddTime(episode, duration).copy(dateUpload = 0L)
|
||||
episodes.add(newEpisode)
|
||||
}
|
||||
setAnimeUpdateInterval.calculateInterval(episodes, testTime) shouldBe 1
|
||||
setAnimeFetchInterval.calculateInterval(episodes, testTime) shouldBe 1
|
||||
}
|
||||
}
|
|
@ -10,14 +10,14 @@ import java.time.Duration
|
|||
import java.time.ZonedDateTime
|
||||
|
||||
@Execution(ExecutionMode.CONCURRENT)
|
||||
class SetMangaUpdateIntervalTest {
|
||||
class SetMangaFetchIntervalTest {
|
||||
private val testTime = ZonedDateTime.parse("2020-01-01T00:00:00Z")
|
||||
private var chapter = Chapter.create().copy(
|
||||
dateFetch = testTime.toEpochSecond() * 1000,
|
||||
dateUpload = testTime.toEpochSecond() * 1000,
|
||||
)
|
||||
|
||||
private val setMangaUpdateInterval = SetMangaUpdateInterval(mockk())
|
||||
private val setMangaFetchInterval = SetMangaFetchInterval(mockk())
|
||||
|
||||
private fun chapterAddTime(chapter: Chapter, duration: Duration): Chapter {
|
||||
val newTime = testTime.plus(duration).toEpochSecond() * 1000
|
||||
|
@ -33,7 +33,7 @@ class SetMangaUpdateIntervalTest {
|
|||
val newChapter = chapterAddTime(chapter, duration)
|
||||
chapters.add(newChapter)
|
||||
}
|
||||
setMangaUpdateInterval.calculateInterval(chapters, testTime) shouldBe 7
|
||||
setMangaFetchInterval.calculateInterval(chapters, testTime) shouldBe 7
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -44,7 +44,7 @@ class SetMangaUpdateIntervalTest {
|
|||
val newChapter = chapterAddTime(chapter, duration)
|
||||
chapters.add(newChapter)
|
||||
}
|
||||
setMangaUpdateInterval.calculateInterval(chapters, testTime) shouldBe 7
|
||||
setMangaFetchInterval.calculateInterval(chapters, testTime) shouldBe 7
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -60,7 +60,7 @@ class SetMangaUpdateIntervalTest {
|
|||
val newChapter = chapterAddTime(chapter, duration)
|
||||
chapters.add(newChapter)
|
||||
}
|
||||
setMangaUpdateInterval.calculateInterval(chapters, testTime) shouldBe 7
|
||||
setMangaFetchInterval.calculateInterval(chapters, testTime) shouldBe 7
|
||||
}
|
||||
|
||||
// Default 1 if interval less than 1
|
||||
|
@ -72,7 +72,7 @@ class SetMangaUpdateIntervalTest {
|
|||
val newChapter = chapterAddTime(chapter, duration)
|
||||
chapters.add(newChapter)
|
||||
}
|
||||
setMangaUpdateInterval.calculateInterval(chapters, testTime) shouldBe 1
|
||||
setMangaFetchInterval.calculateInterval(chapters, testTime) shouldBe 1
|
||||
}
|
||||
|
||||
// Normal interval calculation
|
||||
|
@ -84,7 +84,7 @@ class SetMangaUpdateIntervalTest {
|
|||
val newChapter = chapterAddTime(chapter, duration)
|
||||
chapters.add(newChapter)
|
||||
}
|
||||
setMangaUpdateInterval.calculateInterval(chapters, testTime) shouldBe 1
|
||||
setMangaFetchInterval.calculateInterval(chapters, testTime) shouldBe 1
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -95,7 +95,7 @@ class SetMangaUpdateIntervalTest {
|
|||
val newChapter = chapterAddTime(chapter, duration)
|
||||
chapters.add(newChapter)
|
||||
}
|
||||
setMangaUpdateInterval.calculateInterval(chapters, testTime) shouldBe 2
|
||||
setMangaFetchInterval.calculateInterval(chapters, testTime) shouldBe 2
|
||||
}
|
||||
|
||||
// If interval is decimal, floor to closest integer
|
||||
|
@ -107,7 +107,7 @@ class SetMangaUpdateIntervalTest {
|
|||
val newChapter = chapterAddTime(chapter, duration)
|
||||
chapters.add(newChapter)
|
||||
}
|
||||
setMangaUpdateInterval.calculateInterval(chapters, testTime) shouldBe 1
|
||||
setMangaFetchInterval.calculateInterval(chapters, testTime) shouldBe 1
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -118,7 +118,7 @@ class SetMangaUpdateIntervalTest {
|
|||
val newChapter = chapterAddTime(chapter, duration)
|
||||
chapters.add(newChapter)
|
||||
}
|
||||
setMangaUpdateInterval.calculateInterval(chapters, testTime) shouldBe 1
|
||||
setMangaFetchInterval.calculateInterval(chapters, testTime) shouldBe 1
|
||||
}
|
||||
|
||||
// Use fetch time if upload time not available
|
||||
|
@ -130,6 +130,6 @@ class SetMangaUpdateIntervalTest {
|
|||
val newChapter = chapterAddTime(chapter, duration).copy(dateUpload = 0L)
|
||||
chapters.add(newChapter)
|
||||
}
|
||||
setMangaUpdateInterval.calculateInterval(chapters, testTime) shouldBe 1
|
||||
setMangaFetchInterval.calculateInterval(chapters, testTime) shouldBe 1
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ aboutlib_version = "10.8.3"
|
|||
okhttp_version = "5.0.0-alpha.11"
|
||||
shizuku_version = "12.2.0"
|
||||
sqlite = "2.3.1"
|
||||
sqldelight = "1.5.5"
|
||||
sqldelight = "2.0.0"
|
||||
leakcanary = "2.12"
|
||||
voyager = "1.0.0-rc06"
|
||||
richtext = "0.17.0"
|
||||
|
@ -76,10 +76,12 @@ shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizu
|
|||
leakcanary-android = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakcanary" }
|
||||
leakcanary-plumber = { module = "com.squareup.leakcanary:plumber-android", version.ref = "leakcanary" }
|
||||
|
||||
sqldelight-android-driver = { module = "com.squareup.sqldelight:android-driver", version.ref = "sqldelight" }
|
||||
sqldelight-coroutines = { module = "com.squareup.sqldelight:coroutines-extensions-jvm", version.ref = "sqldelight" }
|
||||
sqldelight-android-paging = { module = "com.squareup.sqldelight:android-paging3-extensions", version.ref = "sqldelight" }
|
||||
sqldelight-gradle = { module = "com.squareup.sqldelight:gradle-plugin", version.ref = "sqldelight" }
|
||||
sqldelight-android-driver = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
|
||||
sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions-jvm", version.ref = "sqldelight" }
|
||||
sqldelight-android-paging = { module = "app.cash.sqldelight:androidx-paging3-extensions", version.ref = "sqldelight" }
|
||||
sqldelight-primitive-adapters = { module = "app.cash.sqldelight:primitive-adapters", version.ref = "sqldelight" }
|
||||
sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", version.ref = "sqldelight" }
|
||||
sqldelight-gradle = { module = "app.cash.sqldelight:gradle-plugin", version.ref = "sqldelight" }
|
||||
|
||||
junit = "org.junit.jupiter:junit-jupiter:5.10.0"
|
||||
kotest-assertions = "io.kotest:kotest-assertions-core:5.6.2"
|
||||
|
@ -106,6 +108,7 @@ js-engine = ["quickjs-android"]
|
|||
sqlite = ["sqlite-framework", "sqlite-ktx", "sqlite-android"]
|
||||
coil = ["coil-core", "coil-gif", "coil-compose"]
|
||||
shizuku = ["shizuku-api", "shizuku-provider"]
|
||||
sqldelight = ["sqldelight-android-driver", "sqldelight-coroutines", "sqldelight-android-paging", "sqldelight-primitive-adapters"]
|
||||
voyager = ["voyager-navigator", "voyager-tab-navigator", "voyager-transitions"]
|
||||
richtext = ["richtext-commonmark", "richtext-m3"]
|
||||
test = ["junit", "kotest-assertions", "mockk"]
|
||||
|
|
|
@ -226,7 +226,6 @@
|
|||
<string name="pref_show_nsfw_source">Show in sources and extensions lists</string>
|
||||
<string name="parental_controls_info">This does not prevent unofficial or potentially incorrectly flagged extensions from surfacing NSFW (18+) content within the app.</string>
|
||||
|
||||
<string name="recently">Recently</string>
|
||||
<string name="relative_time_today">Today</string>
|
||||
<plurals name="relative_time">
|
||||
<item quantity="one">Yesterday</item>
|
||||
|
@ -524,6 +523,7 @@
|
|||
<string name="cache_deleted">Cache cleared. %1$d files have been deleted</string>
|
||||
<string name="cache_delete_error">Error occurred while clearing</string>
|
||||
<string name="pref_invalidate_download_cache">Invalidate downloads index</string>
|
||||
<string name="download_cache_invalidated">Downloads index invalidated</string>
|
||||
<string name="pref_clear_database">Clear database</string>
|
||||
<string name="pref_clear_database_summary">Delete history for entries that are not saved in your library</string>
|
||||
<string name="clear_database_source_item_count">%1$d non-library entries in database</string>
|
||||
|
|
|
@ -5,7 +5,7 @@ plugins {
|
|||
}
|
||||
|
||||
kotlin {
|
||||
android()
|
||||
androidTarget()
|
||||
sourceSets {
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
|
|
|
@ -4,7 +4,7 @@ plugins {
|
|||
}
|
||||
|
||||
kotlin {
|
||||
android()
|
||||
androidTarget()
|
||||
sourceSets {
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
|
|
Loading…
Reference in a new issue