mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-21 20:27:06 +03:00
parent
2c4230376c
commit
f1cd8f69d3
67 changed files with 355 additions and 414 deletions
|
@ -1,5 +1,4 @@
|
|||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.jmailen.gradle.kotlinter.tasks.LintTask
|
||||
import java.io.FileInputStream
|
||||
import java.util.Properties
|
||||
|
||||
|
@ -293,10 +292,6 @@ androidComponents {
|
|||
}
|
||||
|
||||
tasks {
|
||||
withType<LintTask>().configureEach {
|
||||
exclude { it.file.path.contains("generated[\\\\/]".toRegex()) }
|
||||
}
|
||||
|
||||
// See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api(-markers)
|
||||
withType<KotlinCompile> {
|
||||
kotlinOptions.freeCompilerArgs += listOf(
|
||||
|
|
|
@ -13,11 +13,11 @@ import eu.kanade.domain.extension.manga.interactor.GetExtensionSources
|
|||
import eu.kanade.domain.extension.manga.interactor.GetMangaExtensionLanguages
|
||||
import eu.kanade.domain.extension.manga.interactor.GetMangaExtensionsByType
|
||||
import eu.kanade.domain.items.chapter.interactor.SetReadStatus
|
||||
import eu.kanade.domain.items.chapter.interactor.SyncChapterProgressWithTrack
|
||||
import eu.kanade.domain.items.chapter.interactor.SyncChaptersWithSource
|
||||
import eu.kanade.domain.items.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.items.episode.interactor.SetSeenStatus
|
||||
import eu.kanade.domain.items.episode.interactor.SyncEpisodeProgressWithTrack
|
||||
import eu.kanade.domain.items.episode.interactor.SyncEpisodesWithSource
|
||||
import eu.kanade.domain.items.episode.interactor.SyncEpisodesWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.source.anime.interactor.GetAnimeSourcesWithFavoriteCount
|
||||
import eu.kanade.domain.source.anime.interactor.GetEnabledAnimeSources
|
||||
import eu.kanade.domain.source.anime.interactor.GetLanguagesWithAnimeSources
|
||||
|
@ -235,7 +235,7 @@ class DomainModule : InjektModule {
|
|||
addFactory { SetSeenStatus(get(), get(), get(), get()) }
|
||||
addFactory { ShouldUpdateDbEpisode() }
|
||||
addFactory { SyncEpisodesWithSource(get(), get(), get(), get(), get(), get(), get()) }
|
||||
addFactory { SyncEpisodesWithTrackServiceTwoWay(get(), get()) }
|
||||
addFactory { SyncEpisodeProgressWithTrack(get(), get(), get()) }
|
||||
|
||||
addSingletonFactory<ChapterRepository> { ChapterRepositoryImpl(get()) }
|
||||
addFactory { GetChapter(get()) }
|
||||
|
@ -244,7 +244,7 @@ class DomainModule : InjektModule {
|
|||
addFactory { SetReadStatus(get(), get(), get(), get()) }
|
||||
addFactory { ShouldUpdateDbChapter() }
|
||||
addFactory { SyncChaptersWithSource(get(), get(), get(), get(), get(), get(), get()) }
|
||||
addFactory { SyncChaptersWithTrackServiceTwoWay(get(), get()) }
|
||||
addFactory { SyncChapterProgressWithTrack(get(), get(), get()) }
|
||||
|
||||
addSingletonFactory<AnimeHistoryRepository> { AnimeHistoryRepositoryImpl(get()) }
|
||||
addFactory { GetAnimeHistory(get()) }
|
||||
|
|
|
@ -1,27 +1,35 @@
|
|||
package eu.kanade.domain.items.chapter.interactor
|
||||
|
||||
import eu.kanade.domain.track.manga.model.toDbTrack
|
||||
import eu.kanade.tachiyomi.data.track.EnhancedMangaTrackService
|
||||
import eu.kanade.tachiyomi.data.track.MangaTrackService
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.items.chapter.interactor.GetChapterByMangaId
|
||||
import tachiyomi.domain.items.chapter.interactor.UpdateChapter
|
||||
import tachiyomi.domain.items.chapter.model.Chapter
|
||||
import tachiyomi.domain.items.chapter.model.toChapterUpdate
|
||||
import tachiyomi.domain.track.manga.interactor.InsertMangaTrack
|
||||
import tachiyomi.domain.track.manga.model.MangaTrack
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class SyncChaptersWithTrackServiceTwoWay(
|
||||
class SyncChapterProgressWithTrack(
|
||||
private val updateChapter: UpdateChapter,
|
||||
private val insertTrack: InsertMangaTrack,
|
||||
private val getChapterByMangaId: GetChapterByMangaId,
|
||||
) {
|
||||
|
||||
suspend fun await(
|
||||
chapters: List<Chapter>,
|
||||
mangaId: Long,
|
||||
remoteTrack: MangaTrack,
|
||||
service: MangaTrackService,
|
||||
) {
|
||||
val sortedChapters = chapters.sortedBy { it.chapterNumber }
|
||||
if (service !is EnhancedMangaTrackService) {
|
||||
return
|
||||
}
|
||||
|
||||
val sortedChapters = getChapterByMangaId.await(mangaId)
|
||||
.sortedBy { it.chapterNumber }
|
||||
.filter { it.isRecognizedNumber }
|
||||
|
||||
val chapterUpdates = sortedChapters
|
||||
.filter { chapter -> chapter.chapterNumber <= remoteTrack.lastChapterRead && !chapter.read }
|
||||
.map { it.copy(read = true).toChapterUpdate() }
|
|
@ -2,26 +2,35 @@ package eu.kanade.domain.items.episode.interactor
|
|||
|
||||
import eu.kanade.domain.track.anime.model.toDbTrack
|
||||
import eu.kanade.tachiyomi.data.track.AnimeTrackService
|
||||
import eu.kanade.tachiyomi.data.track.EnhancedAnimeTrackService
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.items.episode.interactor.GetEpisodeByAnimeId
|
||||
import tachiyomi.domain.items.episode.interactor.UpdateEpisode
|
||||
import tachiyomi.domain.items.episode.model.Episode
|
||||
import tachiyomi.domain.items.episode.model.toEpisodeUpdate
|
||||
import tachiyomi.domain.track.anime.interactor.InsertAnimeTrack
|
||||
import tachiyomi.domain.track.anime.model.AnimeTrack
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class SyncEpisodesWithTrackServiceTwoWay(
|
||||
class SyncEpisodeProgressWithTrack(
|
||||
private val updateEpisode: UpdateEpisode,
|
||||
private val insertTrack: InsertAnimeTrack,
|
||||
private val getEpisodeByAnimeId: GetEpisodeByAnimeId,
|
||||
) {
|
||||
|
||||
suspend fun await(
|
||||
episodes: List<Episode>,
|
||||
animeId: Long,
|
||||
remoteTrack: AnimeTrack,
|
||||
service: AnimeTrackService,
|
||||
) {
|
||||
val sortedEpisodes = episodes.sortedBy { it.episodeNumber }
|
||||
if (service !is EnhancedAnimeTrackService) {
|
||||
return
|
||||
}
|
||||
|
||||
val sortedEpisodes = getEpisodeByAnimeId.await(animeId)
|
||||
.sortedBy { it.episodeNumber }
|
||||
.filter { it.isRecognizedNumber }
|
||||
|
||||
val episodeUpdates = sortedEpisodes
|
||||
.filter { episode -> episode.episodeNumber <= remoteTrack.lastEpisodeSeen && !episode.seen }
|
||||
.map { it.copy(seen = true).toEpisodeUpdate() }
|
|
@ -0,0 +1,48 @@
|
|||
package eu.kanade.domain.track.anime.interactor
|
||||
|
||||
import eu.kanade.domain.items.episode.interactor.SyncEpisodeProgressWithTrack
|
||||
import eu.kanade.domain.track.anime.model.toDbTrack
|
||||
import eu.kanade.domain.track.anime.model.toDomainTrack
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
import tachiyomi.domain.track.anime.interactor.GetAnimeTracks
|
||||
import tachiyomi.domain.track.anime.interactor.InsertAnimeTrack
|
||||
|
||||
class RefreshAnimeTracks(
|
||||
private val getTracks: GetAnimeTracks,
|
||||
private val trackManager: TrackManager,
|
||||
private val insertTrack: InsertAnimeTrack,
|
||||
private val syncEpisodeProgressWithTrack: SyncEpisodeProgressWithTrack,
|
||||
) {
|
||||
|
||||
/**
|
||||
* Fetches updated tracking data from all logged in trackers.
|
||||
*
|
||||
* @return Failed updates.
|
||||
*/
|
||||
suspend fun await(animeId: Long): List<Pair<TrackService?, Throwable>> {
|
||||
return supervisorScope {
|
||||
return@supervisorScope getTracks.await(animeId)
|
||||
.map { track ->
|
||||
async {
|
||||
val service = trackManager.getService(track.syncId)
|
||||
return@async try {
|
||||
if (service?.isLoggedIn == true) {
|
||||
val updatedTrack = service.animeService.refresh(track.toDbTrack())
|
||||
insertTrack.await(updatedTrack.toDomainTrack()!!)
|
||||
syncEpisodeProgressWithTrack.await(animeId, track, service.animeService)
|
||||
}
|
||||
null
|
||||
} catch (e: Throwable) {
|
||||
service to e
|
||||
}
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
.filterNotNull()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -48,7 +48,7 @@ class DelayedAnimeTrackingUpdateJob(context: Context, workerParams: WorkerParame
|
|||
.forEach { animeTrack ->
|
||||
try {
|
||||
val service = trackManager.getService(animeTrack.syncId)
|
||||
if (service != null && service.isLogged) {
|
||||
if (service != null && service.isLoggedIn) {
|
||||
logcat(LogPriority.DEBUG) { "Updating delayed track item: ${animeTrack.id}, last episode seen: ${animeTrack.lastEpisodeSeen}" }
|
||||
service.animeService.update(animeTrack.toDbTrack(), true)
|
||||
insertTrack.await(animeTrack)
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package eu.kanade.domain.track.manga.interactor
|
||||
|
||||
import eu.kanade.domain.items.chapter.interactor.SyncChapterProgressWithTrack
|
||||
import eu.kanade.domain.track.manga.model.toDbTrack
|
||||
import eu.kanade.domain.track.manga.model.toDomainTrack
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
import tachiyomi.domain.track.manga.interactor.GetMangaTracks
|
||||
import tachiyomi.domain.track.manga.interactor.InsertMangaTrack
|
||||
|
||||
class RefreshMangaTracks(
|
||||
private val getTracks: GetMangaTracks,
|
||||
private val trackManager: TrackManager,
|
||||
private val insertTrack: InsertMangaTrack,
|
||||
private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack,
|
||||
) {
|
||||
|
||||
/**
|
||||
* Fetches updated tracking data from all logged in trackers.
|
||||
*
|
||||
* @return Failed updates.
|
||||
*/
|
||||
suspend fun await(mangaId: Long): List<Pair<TrackService?, Throwable>> {
|
||||
return supervisorScope {
|
||||
return@supervisorScope getTracks.await(mangaId)
|
||||
.map { track ->
|
||||
async {
|
||||
val service = trackManager.getService(track.syncId)
|
||||
return@async try {
|
||||
if (service?.isLoggedIn == true) {
|
||||
val updatedTrack = service.mangaService.refresh(track.toDbTrack())
|
||||
insertTrack.await(updatedTrack.toDomainTrack()!!)
|
||||
syncChapterProgressWithTrack.await(
|
||||
mangaId,
|
||||
track,
|
||||
service.mangaService,
|
||||
)
|
||||
}
|
||||
null
|
||||
} catch (e: Throwable) {
|
||||
service to e
|
||||
}
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
.filterNotNull()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -48,7 +48,7 @@ class DelayedMangaTrackingUpdateJob(context: Context, workerParams: WorkerParame
|
|||
.forEach { track ->
|
||||
try {
|
||||
val service = trackManager.getService(track.syncId)
|
||||
if (service != null && service.isLogged) {
|
||||
if (service != null && service.isLoggedIn) {
|
||||
logcat(LogPriority.DEBUG) { "Updating delayed track item: ${track.id}, last chapter read: ${track.lastChapterRead}" }
|
||||
service.mangaService.update(track.toDbTrack(), true)
|
||||
insertTrack.await(track)
|
||||
|
|
|
@ -127,7 +127,7 @@ private fun ColumnScope.FilterPage(
|
|||
trackServices.map { service ->
|
||||
val filterTracker by screenModel.libraryPreferences.filterTrackedAnime(service.id.toInt()).collectAsState()
|
||||
TriStateItem(
|
||||
label = stringResource(service.nameRes()),
|
||||
label = service.name,
|
||||
state = filterTracker,
|
||||
onClick = { screenModel.toggleTracker(service.id.toInt()) },
|
||||
)
|
||||
|
|
|
@ -127,7 +127,7 @@ private fun ColumnScope.FilterPage(
|
|||
trackServices.map { service ->
|
||||
val filterTracker by screenModel.libraryPreferences.filterTrackedManga(service.id.toInt()).collectAsState()
|
||||
TriStateItem(
|
||||
label = stringResource(service.nameRes()),
|
||||
label = service.name,
|
||||
state = filterTracker,
|
||||
onClick = { screenModel.toggleTracker(service.id.toInt()) },
|
||||
)
|
||||
|
|
|
@ -179,7 +179,7 @@ internal fun PreferenceItem(
|
|||
TrackingPreferenceWidget(
|
||||
service = this,
|
||||
checked = uName.isNotEmpty(),
|
||||
onClick = { if (isLogged) item.logout() else item.login() },
|
||||
onClick = { if (isLoggedIn) item.logout() else item.login() },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,9 +115,7 @@ object SettingsTrackingScreen : SearchableSettings {
|
|||
if (enhancedMangaTrackers.second.isNotEmpty()) {
|
||||
val missingMangaSourcesInfo = stringResource(
|
||||
R.string.enhanced_services_not_installed,
|
||||
enhancedMangaTrackers.second
|
||||
.map { stringResource(it.nameRes()) }
|
||||
.joinToString(),
|
||||
enhancedMangaTrackers.second.joinToString { it.name },
|
||||
)
|
||||
enhancedMangaTrackerInfo += "\n\n$missingMangaSourcesInfo"
|
||||
}
|
||||
|
@ -139,43 +137,43 @@ object SettingsTrackingScreen : SearchableSettings {
|
|||
title = stringResource(R.string.services),
|
||||
preferenceItems = listOf(
|
||||
Preference.PreferenceItem.TrackingPreference(
|
||||
title = stringResource(trackManager.myAnimeList.nameRes()),
|
||||
title = trackManager.myAnimeList.name,
|
||||
service = trackManager.myAnimeList,
|
||||
login = { context.openInBrowser(MyAnimeListApi.authUrl(), forceDefaultBrowser = true) },
|
||||
logout = { dialog = LogoutDialog(trackManager.myAnimeList) },
|
||||
),
|
||||
Preference.PreferenceItem.TrackingPreference(
|
||||
title = stringResource(trackManager.aniList.nameRes()),
|
||||
title = trackManager.aniList.name,
|
||||
service = trackManager.aniList,
|
||||
login = { context.openInBrowser(AnilistApi.authUrl(), forceDefaultBrowser = true) },
|
||||
logout = { dialog = LogoutDialog(trackManager.aniList) },
|
||||
),
|
||||
Preference.PreferenceItem.TrackingPreference(
|
||||
title = stringResource(trackManager.kitsu.nameRes()),
|
||||
title = trackManager.kitsu.name,
|
||||
service = trackManager.kitsu,
|
||||
login = { dialog = LoginDialog(trackManager.kitsu, R.string.email) },
|
||||
logout = { dialog = LogoutDialog(trackManager.kitsu) },
|
||||
),
|
||||
Preference.PreferenceItem.TrackingPreference(
|
||||
title = stringResource(trackManager.mangaUpdates.nameRes()),
|
||||
title = trackManager.mangaUpdates.name,
|
||||
service = trackManager.mangaUpdates,
|
||||
login = { dialog = LoginDialog(trackManager.mangaUpdates, R.string.username) },
|
||||
logout = { dialog = LogoutDialog(trackManager.mangaUpdates) },
|
||||
),
|
||||
Preference.PreferenceItem.TrackingPreference(
|
||||
title = stringResource(trackManager.shikimori.nameRes()),
|
||||
title = trackManager.shikimori.name,
|
||||
service = trackManager.shikimori,
|
||||
login = { context.openInBrowser(ShikimoriApi.authUrl(), forceDefaultBrowser = true) },
|
||||
logout = { dialog = LogoutDialog(trackManager.shikimori) },
|
||||
),
|
||||
Preference.PreferenceItem.TrackingPreference(
|
||||
title = stringResource(trackManager.simkl.nameRes()),
|
||||
title = trackManager.simkl.name,
|
||||
service = trackManager.simkl,
|
||||
login = { context.openInBrowser(SimklApi.authUrl(), forceDefaultBrowser = true) },
|
||||
logout = { dialog = LogoutDialog(trackManager.simkl) },
|
||||
),
|
||||
Preference.PreferenceItem.TrackingPreference(
|
||||
title = stringResource(trackManager.bangumi.nameRes()),
|
||||
title = trackManager.bangumi.name,
|
||||
service = trackManager.bangumi,
|
||||
login = { context.openInBrowser(BangumiApi.authUrl(), forceDefaultBrowser = true) },
|
||||
logout = { dialog = LogoutDialog(trackManager.bangumi) },
|
||||
|
@ -188,7 +186,7 @@ object SettingsTrackingScreen : SearchableSettings {
|
|||
preferenceItems = enhancedMangaTrackers.first
|
||||
.map { service ->
|
||||
Preference.PreferenceItem.TrackingPreference(
|
||||
title = stringResource(service.nameRes()),
|
||||
title = service.name,
|
||||
service = service,
|
||||
login = { (service as EnhancedMangaTrackService).loginNoop() },
|
||||
logout = service::logout,
|
||||
|
@ -218,7 +216,7 @@ object SettingsTrackingScreen : SearchableSettings {
|
|||
title = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = stringResource(R.string.login_title, stringResource(service.nameRes())),
|
||||
text = stringResource(R.string.login_title, service.name),
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
IconButton(onClick = onDismissRequest) {
|
||||
|
@ -326,7 +324,7 @@ object SettingsTrackingScreen : SearchableSettings {
|
|||
onDismissRequest = onDismissRequest,
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(R.string.logout_title, stringResource(service.nameRes())),
|
||||
text = stringResource(R.string.logout_title, service.name),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
|
|
|
@ -40,7 +40,7 @@ fun TrackingPreferenceWidget(
|
|||
) {
|
||||
TrackLogoIcon(service)
|
||||
Text(
|
||||
text = stringResource(service.nameRes()),
|
||||
text = service.name,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = 16.dp),
|
||||
|
|
|
@ -11,7 +11,6 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import tachiyomi.presentation.core.util.clickableNoIndication
|
||||
|
@ -36,7 +35,7 @@ fun TrackLogoIcon(
|
|||
) {
|
||||
Image(
|
||||
painter = painterResource(service.getLogo()),
|
||||
contentDescription = stringResource(service.nameRes()),
|
||||
contentDescription = service.name,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ object Migrations {
|
|||
// Force MAL log out due to login flow change
|
||||
// v52: switched from scraping to WebView
|
||||
// v53: switched from WebView to OAuth
|
||||
if (trackManager.myAnimeList.isLogged) {
|
||||
if (trackManager.myAnimeList.isLoggedIn) {
|
||||
trackManager.myAnimeList.logout()
|
||||
context.toast(R.string.myanimelist_relogin)
|
||||
}
|
||||
|
|
|
@ -69,8 +69,8 @@ class BackupFileValidator(
|
|||
.distinct()
|
||||
val missingTrackers = trackers
|
||||
.mapNotNull { trackManager.getService(it.toLong()) }
|
||||
.filter { !it.isLogged }
|
||||
.map { context.getString(it.nameRes()) }
|
||||
.filter { !it.isLoggedIn }
|
||||
.map { it.name }
|
||||
.sorted()
|
||||
|
||||
return Results(missingSources, missingTrackers)
|
||||
|
|
|
@ -18,18 +18,13 @@ import eu.kanade.domain.entries.anime.interactor.UpdateAnime
|
|||
import eu.kanade.domain.entries.anime.model.copyFrom
|
||||
import eu.kanade.domain.entries.anime.model.toSAnime
|
||||
import eu.kanade.domain.items.episode.interactor.SyncEpisodesWithSource
|
||||
import eu.kanade.domain.items.episode.interactor.SyncEpisodesWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.track.anime.model.toDbTrack
|
||||
import eu.kanade.domain.track.anime.model.toDomainTrack
|
||||
import eu.kanade.domain.track.anime.interactor.RefreshAnimeTracks
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.animesource.UnmeteredSource
|
||||
import eu.kanade.tachiyomi.animesource.model.SAnime
|
||||
import eu.kanade.tachiyomi.data.cache.AnimeCoverCache
|
||||
import eu.kanade.tachiyomi.data.download.anime.AnimeDownloadManager
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.data.track.EnhancedAnimeTrackService
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.model.UpdateStrategy
|
||||
import eu.kanade.tachiyomi.util.prepUpdateCover
|
||||
import eu.kanade.tachiyomi.util.shouldDownloadNewEpisodes
|
||||
|
@ -44,7 +39,6 @@ import kotlinx.coroutines.awaitAll
|
|||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.ensureActive
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
import kotlinx.coroutines.sync.Semaphore
|
||||
import kotlinx.coroutines.sync.withPermit
|
||||
import logcat.LogPriority
|
||||
|
@ -59,7 +53,6 @@ import tachiyomi.domain.entries.anime.interactor.GetLibraryAnime
|
|||
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
|
||||
import tachiyomi.domain.items.episode.model.Episode
|
||||
import tachiyomi.domain.items.episode.model.NoEpisodesException
|
||||
import tachiyomi.domain.library.anime.LibraryAnime
|
||||
|
@ -73,8 +66,6 @@ import tachiyomi.domain.library.service.LibraryPreferences.Companion.ENTRY_NON_V
|
|||
import tachiyomi.domain.library.service.LibraryPreferences.Companion.ENTRY_OUTSIDE_RELEASE_PERIOD
|
||||
import tachiyomi.domain.source.anime.model.AnimeSourceNotInstalledException
|
||||
import tachiyomi.domain.source.anime.service.AnimeSourceManager
|
||||
import tachiyomi.domain.track.anime.interactor.GetAnimeTracks
|
||||
import tachiyomi.domain.track.anime.interactor.InsertAnimeTrack
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.File
|
||||
|
@ -92,17 +83,13 @@ class AnimeLibraryUpdateJob(private val context: Context, workerParams: WorkerPa
|
|||
private val downloadPreferences: DownloadPreferences = Injekt.get()
|
||||
private val libraryPreferences: LibraryPreferences = Injekt.get()
|
||||
private val downloadManager: AnimeDownloadManager = Injekt.get()
|
||||
private val trackManager: TrackManager = Injekt.get()
|
||||
private val coverCache: AnimeCoverCache = Injekt.get()
|
||||
private val getLibraryAnime: GetLibraryAnime = Injekt.get()
|
||||
private val getAnime: GetAnime = Injekt.get()
|
||||
private val updateAnime: UpdateAnime = Injekt.get()
|
||||
private val getEpisodeByAnimeId: GetEpisodeByAnimeId = Injekt.get()
|
||||
private val getCategories: GetAnimeCategories = Injekt.get()
|
||||
private val syncEpisodesWithSource: SyncEpisodesWithSource = Injekt.get()
|
||||
private val getTracks: GetAnimeTracks = Injekt.get()
|
||||
private val insertTrack: InsertAnimeTrack = Injekt.get()
|
||||
private val syncEpisodesWithTrackServiceTwoWay: SyncEpisodesWithTrackServiceTwoWay = Injekt.get()
|
||||
private val refreshAnimeTracks: RefreshAnimeTracks = Injekt.get()
|
||||
private val setAnimeFetchInterval: SetAnimeFetchInterval = Injekt.get()
|
||||
|
||||
private val notifier = AnimeLibraryUpdateNotifier(context)
|
||||
|
@ -296,8 +283,7 @@ class AnimeLibraryUpdateJob(private val context: Context, workerParams: WorkerPa
|
|||
}
|
||||
|
||||
if (libraryPreferences.autoUpdateTrackers().get()) {
|
||||
val loggedServices = trackManager.services.filter { it.isLogged }
|
||||
updateTrackings(anime, loggedServices)
|
||||
refreshAnimeTracks(anime.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -417,48 +403,25 @@ class AnimeLibraryUpdateJob(private val context: Context, workerParams: WorkerPa
|
|||
private suspend fun updateTrackings() {
|
||||
coroutineScope {
|
||||
var progressCount = 0
|
||||
val loggedServices = trackManager.services.filter { it.isLogged }
|
||||
|
||||
animeToUpdate.forEach { libraryAnime ->
|
||||
val anime = libraryAnime.anime
|
||||
|
||||
ensureActive()
|
||||
|
||||
val anime = libraryAnime.anime
|
||||
notifier.showProgressNotification(listOf(anime), progressCount++, animeToUpdate.size)
|
||||
|
||||
// Update the tracking details.
|
||||
updateTrackings(anime, loggedServices)
|
||||
refreshAnimeTracks(anime.id)
|
||||
}
|
||||
|
||||
notifier.cancelProgressNotification()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateTrackings(anime: Anime, loggedServices: List<TrackService>) {
|
||||
getTracks.await(anime.id)
|
||||
.map { track ->
|
||||
supervisorScope {
|
||||
async {
|
||||
val service = trackManager.getService(track.syncId)
|
||||
if (service != null && service in loggedServices) {
|
||||
try {
|
||||
val updatedTrack = service.animeService.refresh(track.toDbTrack())
|
||||
insertTrack.await(updatedTrack.toDomainTrack()!!)
|
||||
|
||||
if (service is EnhancedAnimeTrackService) {
|
||||
val episodes = getEpisodeByAnimeId.await(anime.id)
|
||||
syncEpisodesWithTrackServiceTwoWay.await(episodes, track, service.animeService)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
private suspend fun refreshAnimeTracks(animeId: Long) {
|
||||
refreshAnimeTracks.await(animeId).forEach { (_, e) ->
|
||||
// Ignore errors and continue
|
||||
logcat(LogPriority.ERROR, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
}
|
||||
|
||||
private suspend fun withUpdateNotification(
|
||||
updatingAnime: CopyOnWriteArrayList<Anime>,
|
||||
|
|
|
@ -18,16 +18,11 @@ import eu.kanade.domain.entries.manga.interactor.UpdateManga
|
|||
import eu.kanade.domain.entries.manga.model.copyFrom
|
||||
import eu.kanade.domain.entries.manga.model.toSManga
|
||||
import eu.kanade.domain.items.chapter.interactor.SyncChaptersWithSource
|
||||
import eu.kanade.domain.items.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.track.manga.model.toDbTrack
|
||||
import eu.kanade.domain.track.manga.model.toDomainTrack
|
||||
import eu.kanade.domain.track.manga.interactor.RefreshMangaTracks
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.MangaCoverCache
|
||||
import eu.kanade.tachiyomi.data.download.manga.MangaDownloadManager
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.data.track.EnhancedMangaTrackService
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.model.UpdateStrategy
|
||||
import eu.kanade.tachiyomi.source.UnmeteredSource
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
|
@ -44,7 +39,6 @@ import kotlinx.coroutines.awaitAll
|
|||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.ensureActive
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
import kotlinx.coroutines.sync.Semaphore
|
||||
import kotlinx.coroutines.sync.withPermit
|
||||
import logcat.LogPriority
|
||||
|
@ -59,7 +53,6 @@ import tachiyomi.domain.entries.manga.interactor.GetManga
|
|||
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
|
||||
import tachiyomi.domain.items.chapter.model.Chapter
|
||||
import tachiyomi.domain.items.chapter.model.NoChaptersException
|
||||
import tachiyomi.domain.library.manga.LibraryManga
|
||||
|
@ -73,8 +66,6 @@ import tachiyomi.domain.library.service.LibraryPreferences.Companion.ENTRY_NON_V
|
|||
import tachiyomi.domain.library.service.LibraryPreferences.Companion.ENTRY_OUTSIDE_RELEASE_PERIOD
|
||||
import tachiyomi.domain.source.manga.model.SourceNotInstalledException
|
||||
import tachiyomi.domain.source.manga.service.MangaSourceManager
|
||||
import tachiyomi.domain.track.manga.interactor.GetMangaTracks
|
||||
import tachiyomi.domain.track.manga.interactor.InsertMangaTrack
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.File
|
||||
|
@ -92,17 +83,13 @@ class MangaLibraryUpdateJob(private val context: Context, workerParams: WorkerPa
|
|||
private val downloadPreferences: DownloadPreferences = Injekt.get()
|
||||
private val libraryPreferences: LibraryPreferences = Injekt.get()
|
||||
private val downloadManager: MangaDownloadManager = Injekt.get()
|
||||
private val trackManager: TrackManager = Injekt.get()
|
||||
private val coverCache: MangaCoverCache = Injekt.get()
|
||||
private val getLibraryManga: GetLibraryManga = Injekt.get()
|
||||
private val getManga: GetManga = Injekt.get()
|
||||
private val updateManga: UpdateManga = Injekt.get()
|
||||
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get()
|
||||
private val getCategories: GetMangaCategories = Injekt.get()
|
||||
private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get()
|
||||
private val getTracks: GetMangaTracks = Injekt.get()
|
||||
private val insertTrack: InsertMangaTrack = Injekt.get()
|
||||
private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay = Injekt.get()
|
||||
private val refreshMangaTracks: RefreshMangaTracks = Injekt.get()
|
||||
private val setMangaFetchInterval: SetMangaFetchInterval = Injekt.get()
|
||||
|
||||
private val notifier = MangaLibraryUpdateNotifier(context)
|
||||
|
@ -296,8 +283,7 @@ class MangaLibraryUpdateJob(private val context: Context, workerParams: WorkerPa
|
|||
}
|
||||
|
||||
if (libraryPreferences.autoUpdateTrackers().get()) {
|
||||
val loggedServices = trackManager.services.filter { it.isLogged }
|
||||
updateTrackings(manga, loggedServices)
|
||||
refreshMangaTracks(manga.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -417,48 +403,25 @@ class MangaLibraryUpdateJob(private val context: Context, workerParams: WorkerPa
|
|||
private suspend fun updateTrackings() {
|
||||
coroutineScope {
|
||||
var progressCount = 0
|
||||
val loggedServices = trackManager.services.filter { it.isLogged }
|
||||
|
||||
mangaToUpdate.forEach { libraryManga ->
|
||||
val manga = libraryManga.manga
|
||||
|
||||
ensureActive()
|
||||
|
||||
val manga = libraryManga.manga
|
||||
notifier.showProgressNotification(listOf(manga), progressCount++, mangaToUpdate.size)
|
||||
|
||||
// Update the tracking details.
|
||||
updateTrackings(manga, loggedServices)
|
||||
refreshMangaTracks(manga.id)
|
||||
}
|
||||
|
||||
notifier.cancelProgressNotification()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateTrackings(manga: Manga, loggedServices: List<TrackService>) {
|
||||
getTracks.await(manga.id)
|
||||
.map { track ->
|
||||
supervisorScope {
|
||||
async {
|
||||
val service = trackManager.getService(track.syncId)
|
||||
if (service != null && service in loggedServices) {
|
||||
try {
|
||||
val updatedTrack = service.mangaService.refresh(track.toDbTrack())
|
||||
insertTrack.await(updatedTrack.toDomainTrack()!!)
|
||||
|
||||
if (service is EnhancedMangaTrackService) {
|
||||
val chapters = getChapterByMangaId.await(manga.id)
|
||||
syncChaptersWithTrackServiceTwoWay.await(chapters, track, service.mangaService)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
private suspend fun refreshMangaTracks(mangaId: Long) {
|
||||
refreshMangaTracks.await(mangaId).forEach { (_, e) ->
|
||||
// Ignore errors and continue
|
||||
logcat(LogPriority.ERROR, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
}
|
||||
|
||||
private suspend fun withUpdateNotification(
|
||||
updatingManga: CopyOnWriteArrayList<Manga>,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package eu.kanade.tachiyomi.data.track
|
||||
|
||||
import android.app.Application
|
||||
import eu.kanade.domain.items.episode.interactor.SyncEpisodesWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.items.episode.interactor.SyncEpisodeProgressWithTrack
|
||||
import eu.kanade.domain.track.anime.model.toDbTrack
|
||||
import eu.kanade.domain.track.anime.model.toDomainTrack
|
||||
import eu.kanade.tachiyomi.data.database.models.anime.AnimeTrack
|
||||
|
@ -22,6 +22,7 @@ import java.time.ZoneOffset
|
|||
import tachiyomi.domain.track.anime.model.AnimeTrack as DomainAnimeTrack
|
||||
|
||||
private val insertTrack: InsertAnimeTrack by injectLazy()
|
||||
private val syncEpisodeProgressWithTrack: SyncEpisodeProgressWithTrack by injectLazy()
|
||||
|
||||
interface AnimeTrackService {
|
||||
|
||||
|
@ -56,7 +57,8 @@ interface AnimeTrackService {
|
|||
|
||||
suspend fun refresh(track: AnimeTrack): AnimeTrack
|
||||
|
||||
suspend fun registerTracking(item: AnimeTrack, animeId: Long) {
|
||||
// TODO: move this to an interactor, and update all trackers based on common data
|
||||
suspend fun register(item: AnimeTrack, animeId: Long) {
|
||||
item.anime_id = animeId
|
||||
try {
|
||||
withIOContext {
|
||||
|
@ -68,6 +70,7 @@ interface AnimeTrackService {
|
|||
|
||||
insertTrack.await(track)
|
||||
|
||||
// TODO: merge into SyncChaptersWithTrackServiceTwoWay?
|
||||
// Update episode progress if newer episodes marked seen locally
|
||||
if (hasSeenEpisodes) {
|
||||
val latestLocalSeenEpisodeNumber = allEpisodes
|
||||
|
@ -102,9 +105,7 @@ interface AnimeTrackService {
|
|||
}
|
||||
}
|
||||
|
||||
if (this is EnhancedAnimeTrackService) {
|
||||
Injekt.get<SyncEpisodesWithTrackServiceTwoWay>().await(allEpisodes, track, this@AnimeTrackService)
|
||||
}
|
||||
syncEpisodeProgressWithTrack.await(animeId, track, this@AnimeTrackService)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
withUIContext { Injekt.get<Application>().toast(e.message) }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package eu.kanade.tachiyomi.data.track
|
||||
|
||||
import android.app.Application
|
||||
import eu.kanade.domain.items.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.items.chapter.interactor.SyncChapterProgressWithTrack
|
||||
import eu.kanade.domain.track.manga.model.toDbTrack
|
||||
import eu.kanade.domain.track.manga.model.toDomainTrack
|
||||
import eu.kanade.tachiyomi.data.database.models.manga.MangaTrack
|
||||
|
@ -22,6 +22,7 @@ import java.time.ZoneOffset
|
|||
import tachiyomi.domain.track.manga.model.MangaTrack as DomainTrack
|
||||
|
||||
private val insertTrack: InsertMangaTrack by injectLazy()
|
||||
private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack by injectLazy()
|
||||
|
||||
interface MangaTrackService {
|
||||
|
||||
|
@ -56,7 +57,8 @@ interface MangaTrackService {
|
|||
|
||||
suspend fun refresh(track: MangaTrack): MangaTrack
|
||||
|
||||
suspend fun registerTracking(item: MangaTrack, mangaId: Long) {
|
||||
// TODO: move this to an interactor, and update all trackers based on common data
|
||||
suspend fun register(item: MangaTrack, mangaId: Long) {
|
||||
item.manga_id = mangaId
|
||||
try {
|
||||
withIOContext {
|
||||
|
@ -68,6 +70,7 @@ interface MangaTrackService {
|
|||
|
||||
insertTrack.await(track)
|
||||
|
||||
// TODO: merge into SyncChaptersWithTrackServiceTwoWay?
|
||||
// Update chapter progress if newer chapters marked read locally
|
||||
if (hasReadChapters) {
|
||||
val latestLocalReadChapterNumber = allChapters
|
||||
|
@ -102,9 +105,7 @@ interface MangaTrackService {
|
|||
}
|
||||
}
|
||||
|
||||
if (this is EnhancedMangaTrackService) {
|
||||
Injekt.get<SyncChaptersWithTrackServiceTwoWay>().await(allChapters, track, this@MangaTrackService)
|
||||
}
|
||||
syncChapterProgressWithTrack.await(mangaId, track, this@MangaTrackService)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
withUIContext { Injekt.get<Application>().toast(e.message) }
|
||||
|
|
|
@ -32,7 +32,7 @@ class TrackManager(context: Context) {
|
|||
val kitsu = Kitsu(KITSU)
|
||||
val shikimori = Shikimori(SHIKIMORI)
|
||||
val bangumi = Bangumi(BANGUMI)
|
||||
val komga = Komga(context, KOMGA)
|
||||
val komga = Komga(KOMGA)
|
||||
val mangaUpdates = MangaUpdates(MANGA_UPDATES)
|
||||
val kavita = Kavita(context, KAVITA)
|
||||
val suwayomi = Suwayomi(SUWAYOMI)
|
||||
|
@ -42,5 +42,5 @@ class TrackManager(context: Context) {
|
|||
|
||||
fun getService(id: Long) = services.find { it.id == id }
|
||||
|
||||
fun hasLoggedServices() = services.any { it.isLogged }
|
||||
fun hasLoggedServices() = services.any { it.isLoggedIn }
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import eu.kanade.tachiyomi.network.NetworkHelper
|
|||
import okhttp3.OkHttpClient
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
abstract class TrackService(val id: Long) {
|
||||
abstract class TrackService(val id: Long, val name: String) {
|
||||
|
||||
val trackPreferences: TrackPreferences by injectLazy()
|
||||
val networkService: NetworkHelper by injectLazy()
|
||||
|
@ -17,10 +17,6 @@ abstract class TrackService(val id: Long) {
|
|||
open val client: OkHttpClient
|
||||
get() = networkService.client
|
||||
|
||||
// Name of the manga sync service to display
|
||||
@StringRes
|
||||
abstract fun nameRes(): Int
|
||||
|
||||
// Application and remote support for reading dates
|
||||
open val supportsReadingDates: Boolean = false
|
||||
|
||||
|
@ -40,7 +36,7 @@ abstract class TrackService(val id: Long) {
|
|||
trackPreferences.setTrackCredentials(this, "", "")
|
||||
}
|
||||
|
||||
open val isLogged: Boolean
|
||||
open val isLoggedIn: Boolean
|
||||
get() = getUsername().isNotEmpty() &&
|
||||
getPassword().isNotEmpty()
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import uy.kohesive.injekt.injectLazy
|
|||
import tachiyomi.domain.track.anime.model.AnimeTrack as DomainAnimeTrack
|
||||
import tachiyomi.domain.track.manga.model.MangaTrack as DomainTrack
|
||||
|
||||
class Anilist(id: Long) : TrackService(id), MangaTrackService, AnimeTrackService, DeletableMangaTrackService, DeletableAnimeTrackService {
|
||||
class Anilist(id: Long) : TrackService(id, "AniList"), MangaTrackService, AnimeTrackService, DeletableMangaTrackService, DeletableAnimeTrackService {
|
||||
|
||||
companion object {
|
||||
const val READING = 1
|
||||
|
@ -59,9 +59,6 @@ class Anilist(id: Long) : TrackService(id), MangaTrackService, AnimeTrackService
|
|||
}
|
||||
}
|
||||
|
||||
@StringRes
|
||||
override fun nameRes() = R.string.tracker_anilist
|
||||
|
||||
override fun getLogo() = R.drawable.ic_tracker_anilist
|
||||
|
||||
override fun getLogoColor() = Color.rgb(18, 25, 35)
|
||||
|
|
|
@ -15,7 +15,7 @@ import kotlinx.serialization.encodeToString
|
|||
import kotlinx.serialization.json.Json
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class Bangumi(id: Long) : TrackService(id), MangaTrackService, AnimeTrackService {
|
||||
class Bangumi(id: Long) : TrackService(id, "Bangumi"), MangaTrackService, AnimeTrackService {
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
|
@ -23,9 +23,6 @@ class Bangumi(id: Long) : TrackService(id), MangaTrackService, AnimeTrackService
|
|||
|
||||
private val api by lazy { BangumiApi(client, interceptor) }
|
||||
|
||||
@StringRes
|
||||
override fun nameRes() = R.string.tracker_bangumi
|
||||
|
||||
override fun getScoreList(): List<String> {
|
||||
return IntRange(0, 10).map(Int::toString)
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import tachiyomi.domain.entries.manga.model.Manga
|
|||
import java.security.MessageDigest
|
||||
import tachiyomi.domain.track.manga.model.MangaTrack as DomainTrack
|
||||
|
||||
class Kavita(private val context: Context, id: Long) : TrackService(id), EnhancedMangaTrackService, MangaTrackService {
|
||||
class Kavita(private val context: Context, id: Long) : TrackService(id, "Kavita"), EnhancedMangaTrackService, MangaTrackService {
|
||||
|
||||
companion object {
|
||||
const val UNREAD = 1
|
||||
|
@ -28,9 +28,6 @@ class Kavita(private val context: Context, id: Long) : TrackService(id), Enhance
|
|||
private val interceptor by lazy { KavitaInterceptor(this) }
|
||||
val api by lazy { KavitaApi(client, interceptor) }
|
||||
|
||||
@StringRes
|
||||
override fun nameRes() = R.string.tracker_kavita
|
||||
|
||||
override fun getLogo(): Int = R.drawable.ic_tracker_kavita
|
||||
|
||||
override fun getLogoColor() = Color.rgb(74, 198, 148)
|
||||
|
|
|
@ -115,8 +115,8 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
|
|||
}
|
||||
|
||||
private fun getLatestChapterRead(url: String): Float {
|
||||
val serieId = getIdFromUrl(url)
|
||||
val requestUrl = "${getApiFromUrl(url)}/Tachiyomi/latest-chapter?seriesId=$serieId"
|
||||
val seriesId = getIdFromUrl(url)
|
||||
val requestUrl = "${getApiFromUrl(url)}/Tachiyomi/latest-chapter?seriesId=$seriesId"
|
||||
try {
|
||||
with(json) {
|
||||
authClient.newCall(GET(requestUrl)).execute().use {
|
||||
|
@ -137,21 +137,21 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
|
|||
|
||||
suspend fun getTrackSearch(url: String): MangaTrackSearch = withIOContext {
|
||||
try {
|
||||
val serieDto: SeriesDto = with(json) {
|
||||
val seriesDto: SeriesDto = with(json) {
|
||||
authClient.newCall(GET(url))
|
||||
.awaitSuccess()
|
||||
.parseAs()
|
||||
}
|
||||
|
||||
val track = serieDto.toTrack()
|
||||
val track = seriesDto.toTrack()
|
||||
track.apply {
|
||||
cover_url = serieDto.thumbnail_url.toString()
|
||||
cover_url = seriesDto.thumbnail_url.toString()
|
||||
tracking_url = url
|
||||
total_chapters = getTotalChapters(url)
|
||||
|
||||
title = serieDto.name
|
||||
status = when (serieDto.pagesRead) {
|
||||
serieDto.pages -> Kavita.COMPLETED
|
||||
title = seriesDto.name
|
||||
status = when (seriesDto.pagesRead) {
|
||||
seriesDto.pages -> Kavita.COMPLETED
|
||||
0 -> Kavita.UNREAD
|
||||
else -> Kavita.READING
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import kotlinx.serialization.json.Json
|
|||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.DecimalFormat
|
||||
|
||||
class Kitsu(id: Long) : TrackService(id), AnimeTrackService, MangaTrackService, DeletableMangaTrackService, DeletableAnimeTrackService {
|
||||
class Kitsu(id: Long) : TrackService(id, "Kitsu"), AnimeTrackService, MangaTrackService, DeletableMangaTrackService, DeletableAnimeTrackService {
|
||||
|
||||
companion object {
|
||||
const val READING = 1
|
||||
|
@ -30,9 +30,6 @@ class Kitsu(id: Long) : TrackService(id), AnimeTrackService, MangaTrackService,
|
|||
const val PLAN_TO_WATCH = 15
|
||||
}
|
||||
|
||||
@StringRes
|
||||
override fun nameRes() = R.string.tracker_kitsu
|
||||
|
||||
override val supportsReadingDates: Boolean = true
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package eu.kanade.tachiyomi.data.track.komga
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import androidx.annotation.StringRes
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
@ -15,7 +14,7 @@ import okhttp3.OkHttpClient
|
|||
import tachiyomi.domain.entries.manga.model.Manga
|
||||
import tachiyomi.domain.track.manga.model.MangaTrack as DomainTrack
|
||||
|
||||
class Komga(private val context: Context, id: Long) : TrackService(id), EnhancedMangaTrackService, MangaTrackService {
|
||||
class Komga(id: Long) : TrackService(id, "Komga"), EnhancedMangaTrackService, MangaTrackService {
|
||||
|
||||
companion object {
|
||||
const val UNREAD = 1
|
||||
|
@ -30,9 +29,6 @@ class Komga(private val context: Context, id: Long) : TrackService(id), Enhanced
|
|||
|
||||
val api by lazy { KomgaApi(client) }
|
||||
|
||||
@StringRes
|
||||
override fun nameRes() = R.string.tracker_komga
|
||||
|
||||
override fun getLogo() = R.drawable.ic_tracker_komga
|
||||
|
||||
override fun getLogoColor() = Color.rgb(51, 37, 50)
|
||||
|
|
|
@ -17,7 +17,7 @@ import tachiyomi.core.util.lang.withIOContext
|
|||
import tachiyomi.core.util.system.logcat
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
const val READLIST_API = "/api/v1/readlists"
|
||||
private const val READLIST_API = "/api/v1/readlists"
|
||||
|
||||
class KomgaApi(private val client: OkHttpClient) {
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.data.track.mangaupdates.dto.copyTo
|
|||
import eu.kanade.tachiyomi.data.track.mangaupdates.dto.toTrackSearch
|
||||
import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch
|
||||
|
||||
class MangaUpdates(id: Long) : TrackService(id), MangaTrackService, DeletableMangaTrackService {
|
||||
class MangaUpdates(id: Long) : TrackService(id, "MangaUpdates"), MangaTrackService, DeletableMangaTrackService {
|
||||
|
||||
companion object {
|
||||
const val READING_LIST = 0
|
||||
|
@ -25,9 +25,6 @@ class MangaUpdates(id: Long) : TrackService(id), MangaTrackService, DeletableMan
|
|||
|
||||
private val api by lazy { MangaUpdatesApi(interceptor, client) }
|
||||
|
||||
@StringRes
|
||||
override fun nameRes(): Int = R.string.tracker_manga_updates
|
||||
|
||||
override fun getLogo(): Int = R.drawable.ic_manga_updates
|
||||
|
||||
override fun getLogoColor(): Int = Color.rgb(146, 160, 173)
|
||||
|
|
|
@ -17,7 +17,7 @@ import kotlinx.serialization.encodeToString
|
|||
import kotlinx.serialization.json.Json
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class MyAnimeList(id: Long) : TrackService(id), MangaTrackService, AnimeTrackService, DeletableMangaTrackService, DeletableAnimeTrackService {
|
||||
class MyAnimeList(id: Long) : TrackService(id, "MyAnimeList"), MangaTrackService, AnimeTrackService, DeletableMangaTrackService, DeletableAnimeTrackService {
|
||||
|
||||
companion object {
|
||||
const val READING = 1
|
||||
|
@ -39,9 +39,6 @@ class MyAnimeList(id: Long) : TrackService(id), MangaTrackService, AnimeTrackSer
|
|||
private val interceptor by lazy { MyAnimeListInterceptor(this, getPassword()) }
|
||||
private val api by lazy { MyAnimeListApi(client, interceptor) }
|
||||
|
||||
@StringRes
|
||||
override fun nameRes() = R.string.tracker_myanimelist
|
||||
|
||||
override val supportsReadingDates: Boolean = true
|
||||
|
||||
override fun getLogo() = R.drawable.ic_tracker_mal
|
||||
|
|
|
@ -17,7 +17,7 @@ import kotlinx.serialization.encodeToString
|
|||
import kotlinx.serialization.json.Json
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class Shikimori(id: Long) : TrackService(id), MangaTrackService, AnimeTrackService, DeletableMangaTrackService, DeletableAnimeTrackService {
|
||||
class Shikimori(id: Long) : TrackService(id, "Shikimori"), MangaTrackService, AnimeTrackService, DeletableMangaTrackService, DeletableAnimeTrackService {
|
||||
|
||||
companion object {
|
||||
const val READING = 1
|
||||
|
@ -34,9 +34,6 @@ class Shikimori(id: Long) : TrackService(id), MangaTrackService, AnimeTrackServi
|
|||
|
||||
private val api by lazy { ShikimoriApi(client, interceptor) }
|
||||
|
||||
@StringRes
|
||||
override fun nameRes() = R.string.tracker_shikimori
|
||||
|
||||
override fun getScoreList(): List<String> {
|
||||
return IntRange(0, 10).map(Int::toString)
|
||||
}
|
||||
|
|
|
@ -212,7 +212,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun findLibManga(track: MangaTrack, user_id: String): MangaTrack? {
|
||||
suspend fun findLibManga(track: MangaTrack, userId: String): MangaTrack? {
|
||||
return withIOContext {
|
||||
val urlMangas = "$apiUrl/mangas".toUri().buildUpon()
|
||||
.appendPath(track.media_id.toString())
|
||||
|
@ -224,7 +224,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
|
|||
}
|
||||
|
||||
val url = "$apiUrl/v2/user_rates".toUri().buildUpon()
|
||||
.appendQueryParameter("user_id", user_id)
|
||||
.appendQueryParameter("user_id", userId)
|
||||
.appendQueryParameter("target_id", track.media_id.toString())
|
||||
.appendQueryParameter("target_type", "Manga")
|
||||
.build()
|
||||
|
|
|
@ -12,7 +12,7 @@ import kotlinx.serialization.encodeToString
|
|||
import kotlinx.serialization.json.Json
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class Simkl(id: Long) : TrackService(id), AnimeTrackService {
|
||||
class Simkl(id: Long) : TrackService(id, "Simkl"), AnimeTrackService {
|
||||
|
||||
companion object {
|
||||
const val WATCHING = 1
|
||||
|
@ -28,9 +28,6 @@ class Simkl(id: Long) : TrackService(id), AnimeTrackService {
|
|||
|
||||
private val api by lazy { SimklApi(client, interceptor) }
|
||||
|
||||
@StringRes
|
||||
override fun nameRes() = R.string.tracker_simkl
|
||||
|
||||
override fun getScoreList(): List<String> {
|
||||
return IntRange(0, 10).map(Int::toString)
|
||||
}
|
||||
|
|
|
@ -12,12 +12,9 @@ import eu.kanade.tachiyomi.source.MangaSource
|
|||
import tachiyomi.domain.entries.manga.model.Manga as DomainManga
|
||||
import tachiyomi.domain.track.manga.model.MangaTrack as DomainTrack
|
||||
|
||||
class Suwayomi(id: Long) : TrackService(id), EnhancedMangaTrackService, MangaTrackService {
|
||||
class Suwayomi(id: Long) : TrackService(id, "Suwayomi"), EnhancedMangaTrackService, MangaTrackService {
|
||||
val api by lazy { TachideskApi() }
|
||||
|
||||
@StringRes
|
||||
override fun nameRes() = R.string.tracker_suwayomi
|
||||
|
||||
override fun getLogo() = R.drawable.ic_tracker_suwayomi
|
||||
|
||||
override fun getLogoColor() = Color.rgb(255, 35, 35) // TODO
|
||||
|
|
|
@ -28,12 +28,12 @@ class TachideskApi {
|
|||
private val network by injectLazy<NetworkHelper>()
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
val client: OkHttpClient =
|
||||
private val client: OkHttpClient =
|
||||
network.client.newBuilder()
|
||||
.dns(Dns.SYSTEM) // don't use DNS over HTTPS as it breaks IP addressing
|
||||
.build()
|
||||
|
||||
fun headersBuilder(): Headers.Builder = Headers.Builder().apply {
|
||||
private fun headersBuilder(): Headers.Builder = Headers.Builder().apply {
|
||||
add("User-Agent", network.defaultUserAgentProvider())
|
||||
if (basePassword.isNotEmpty() && baseLogin.isNotEmpty()) {
|
||||
val credentials = Credentials.basic(baseLogin, basePassword)
|
||||
|
@ -41,7 +41,7 @@ class TachideskApi {
|
|||
}
|
||||
}
|
||||
|
||||
val headers: Headers by lazy { headersBuilder().build() }
|
||||
private val headers: Headers by lazy { headersBuilder().build() }
|
||||
|
||||
private val baseUrl by lazy { getPrefBaseUrl() }
|
||||
private val baseLogin by lazy { getPrefBaseLogin() }
|
||||
|
@ -101,7 +101,7 @@ class TachideskApi {
|
|||
return getTrackSearch(track.tracking_url)
|
||||
}
|
||||
|
||||
val tachideskExtensionId by lazy {
|
||||
private val tachideskExtensionId by lazy {
|
||||
val key = "tachidesk/en/1"
|
||||
val bytes = MessageDigest.getInstance("MD5").digest(key.toByteArray())
|
||||
(0..7).map { bytes[it].toLong() and 0xff shl 8 * (7 - it) }.reduce(Long::or) and Long.MAX_VALUE
|
||||
|
@ -111,6 +111,10 @@ class TachideskApi {
|
|||
Injekt.get<Application>().getSharedPreferences("source_$tachideskExtensionId", 0x0000)
|
||||
}
|
||||
|
||||
private fun getPrefBaseUrl(): String = preferences.getString(ADDRESS_TITLE, ADDRESS_DEFAULT)!!
|
||||
private fun getPrefBaseLogin(): String = preferences.getString(LOGIN_TITLE, LOGIN_DEFAULT)!!
|
||||
private fun getPrefBasePassword(): String = preferences.getString(PASSWORD_TITLE, PASSWORD_DEFAULT)!!
|
||||
|
||||
companion object {
|
||||
private const val ADDRESS_TITLE = "Server URL Address"
|
||||
private const val ADDRESS_DEFAULT = ""
|
||||
|
@ -119,8 +123,4 @@ class TachideskApi {
|
|||
private const val PASSWORD_TITLE = "Password (Basic Auth)"
|
||||
private const val PASSWORD_DEFAULT = ""
|
||||
}
|
||||
|
||||
private fun getPrefBaseUrl(): String = preferences.getString(ADDRESS_TITLE, ADDRESS_DEFAULT)!!
|
||||
private fun getPrefBaseLogin(): String = preferences.getString(LOGIN_TITLE, LOGIN_DEFAULT)!!
|
||||
private fun getPrefBasePassword(): String = preferences.getString(PASSWORD_TITLE, PASSWORD_DEFAULT)!!
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import eu.kanade.core.preference.asState
|
|||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.domain.entries.anime.interactor.UpdateAnime
|
||||
import eu.kanade.domain.entries.anime.model.toDomainAnime
|
||||
import eu.kanade.domain.items.episode.interactor.SyncEpisodesWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.items.episode.interactor.SyncEpisodeProgressWithTrack
|
||||
import eu.kanade.domain.source.service.SourcePreferences
|
||||
import eu.kanade.domain.track.anime.model.toDomainTrack
|
||||
import eu.kanade.presentation.util.ioCoroutineScope
|
||||
|
@ -52,7 +52,6 @@ import tachiyomi.domain.entries.anime.interactor.GetDuplicateLibraryAnime
|
|||
import tachiyomi.domain.entries.anime.interactor.NetworkToLocalAnime
|
||||
import tachiyomi.domain.entries.anime.model.Anime
|
||||
import tachiyomi.domain.entries.anime.model.toAnimeUpdate
|
||||
import tachiyomi.domain.items.episode.interactor.GetEpisodeByAnimeId
|
||||
import tachiyomi.domain.items.episode.interactor.SetAnimeDefaultEpisodeFlags
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.domain.source.anime.interactor.GetRemoteAnime
|
||||
|
@ -74,17 +73,16 @@ class BrowseAnimeSourceScreenModel(
|
|||
private val getRemoteAnime: GetRemoteAnime = Injekt.get(),
|
||||
private val getDuplicateAnimelibAnime: GetDuplicateLibraryAnime = Injekt.get(),
|
||||
private val getCategories: GetAnimeCategories = Injekt.get(),
|
||||
private val getEpisodeByAnimeId: GetEpisodeByAnimeId = Injekt.get(),
|
||||
private val setAnimeCategories: SetAnimeCategories = Injekt.get(),
|
||||
private val setAnimeDefaultEpisodeFlags: SetAnimeDefaultEpisodeFlags = Injekt.get(),
|
||||
private val getAnime: GetAnime = Injekt.get(),
|
||||
private val networkToLocalAnime: NetworkToLocalAnime = Injekt.get(),
|
||||
private val updateAnime: UpdateAnime = Injekt.get(),
|
||||
private val insertTrack: InsertAnimeTrack = Injekt.get(),
|
||||
private val syncEpisodesWithTrackServiceTwoWay: SyncEpisodesWithTrackServiceTwoWay = Injekt.get(),
|
||||
private val syncEpisodeProgressWithTrack: SyncEpisodeProgressWithTrack = Injekt.get(),
|
||||
) : StateScreenModel<BrowseAnimeSourceScreenModel.State>(State(Listing.valueOf(listingQuery))) {
|
||||
|
||||
private val loggedServices by lazy { Injekt.get<TrackManager>().services.filter { it.isLogged } }
|
||||
private val loggedServices by lazy { Injekt.get<TrackManager>().services.filter { it.isLoggedIn } }
|
||||
|
||||
var displayMode by sourcePreferences.sourceDisplayMode().asState(coroutineScope)
|
||||
|
||||
|
@ -304,8 +302,7 @@ class BrowseAnimeSourceScreenModel(
|
|||
(service as TrackService).animeService.bind(track)
|
||||
insertTrack.await(track.toDomainTrack()!!)
|
||||
|
||||
val chapters = getEpisodeByAnimeId.await(anime.id)
|
||||
syncEpisodesWithTrackServiceTwoWay.await(chapters, track.toDomainTrack()!!, service.animeService)
|
||||
syncEpisodeProgressWithTrack.await(anime.id, track.toDomainTrack()!!, service.animeService)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logcat(
|
||||
|
|
|
@ -9,7 +9,6 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.cachedIn
|
||||
import androidx.paging.filter
|
||||
import androidx.paging.map
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import cafe.adriel.voyager.core.model.coroutineScope
|
||||
|
@ -17,7 +16,7 @@ import eu.kanade.core.preference.asState
|
|||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.domain.entries.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.entries.manga.model.toDomainManga
|
||||
import eu.kanade.domain.items.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.items.chapter.interactor.SyncChapterProgressWithTrack
|
||||
import eu.kanade.domain.source.service.SourcePreferences
|
||||
import eu.kanade.domain.track.manga.model.toDomainTrack
|
||||
import eu.kanade.presentation.util.ioCoroutineScope
|
||||
|
@ -34,7 +33,6 @@ import kotlinx.coroutines.flow.emptyFlow
|
|||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
|
@ -52,7 +50,6 @@ import tachiyomi.domain.entries.manga.interactor.GetManga
|
|||
import tachiyomi.domain.entries.manga.interactor.NetworkToLocalManga
|
||||
import tachiyomi.domain.entries.manga.model.Manga
|
||||
import tachiyomi.domain.entries.manga.model.toMangaUpdate
|
||||
import tachiyomi.domain.items.chapter.interactor.GetChapterByMangaId
|
||||
import tachiyomi.domain.items.chapter.interactor.SetMangaDefaultChapterFlags
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.domain.source.manga.interactor.GetRemoteManga
|
||||
|
@ -74,17 +71,16 @@ class BrowseMangaSourceScreenModel(
|
|||
private val getRemoteManga: GetRemoteManga = Injekt.get(),
|
||||
private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(),
|
||||
private val getCategories: GetMangaCategories = Injekt.get(),
|
||||
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
||||
private val setMangaCategories: SetMangaCategories = Injekt.get(),
|
||||
private val setMangaDefaultChapterFlags: SetMangaDefaultChapterFlags = Injekt.get(),
|
||||
private val getManga: GetManga = Injekt.get(),
|
||||
private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
||||
private val updateManga: UpdateManga = Injekt.get(),
|
||||
private val insertTrack: InsertMangaTrack = Injekt.get(),
|
||||
private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay = Injekt.get(),
|
||||
private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack = Injekt.get(),
|
||||
) : StateScreenModel<BrowseMangaSourceScreenModel.State>(State(Listing.valueOf(listingQuery))) {
|
||||
|
||||
private val loggedServices by lazy { Injekt.get<TrackManager>().services.filter { it.isLogged } }
|
||||
private val loggedServices by lazy { Injekt.get<TrackManager>().services.filter { it.isLoggedIn } }
|
||||
|
||||
var displayMode by sourcePreferences.sourceDisplayMode().asState(coroutineScope)
|
||||
|
||||
|
@ -301,8 +297,7 @@ class BrowseMangaSourceScreenModel(
|
|||
(service as TrackService).mangaService.bind(track)
|
||||
insertTrack.await(track.toDomainTrack()!!)
|
||||
|
||||
val chapters = getChapterByMangaId.await(manga.id)
|
||||
syncChaptersWithTrackServiceTwoWay.await(chapters, track.toDomainTrack()!!, service.mangaService)
|
||||
syncChapterProgressWithTrack.await(manga.id, track.toDomainTrack()!!, service.mangaService)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.WARN, e) { "Could not match manga: ${manga.title} with service $service" }
|
||||
|
|
|
@ -111,7 +111,7 @@ class AnimeScreenModel(
|
|||
private val successState: State.Success?
|
||||
get() = state.value as? State.Success
|
||||
|
||||
private val loggedServices by lazy { trackManager.services.filter { it.isLogged && it is AnimeTrackService } }
|
||||
private val loggedServices by lazy { trackManager.services.filter { it.isLoggedIn && it is AnimeTrackService } }
|
||||
|
||||
val anime: Anime?
|
||||
get() = successState?.anime
|
||||
|
@ -336,7 +336,7 @@ class AnimeScreenModel(
|
|||
launchIO {
|
||||
try {
|
||||
service.match(anime)?.let { track ->
|
||||
(service as AnimeTrackService).registerTracking(track, animeId)
|
||||
(service as AnimeTrackService).register(track, animeId)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.WARN, e) {
|
||||
|
|
|
@ -39,9 +39,8 @@ import cafe.adriel.voyager.core.model.rememberScreenModel
|
|||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.domain.items.episode.interactor.SyncEpisodesWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.track.anime.interactor.RefreshAnimeTracks
|
||||
import eu.kanade.domain.track.anime.model.toDbTrack
|
||||
import eu.kanade.domain.track.anime.model.toDomainTrack
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.track.TrackDateSelector
|
||||
import eu.kanade.presentation.track.TrackItemSelector
|
||||
|
@ -72,11 +71,9 @@ import tachiyomi.core.util.lang.withIOContext
|
|||
import tachiyomi.core.util.lang.withUIContext
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.entries.anime.interactor.GetAnime
|
||||
import tachiyomi.domain.entries.anime.interactor.GetAnimeWithEpisodes
|
||||
import tachiyomi.domain.source.anime.service.AnimeSourceManager
|
||||
import tachiyomi.domain.track.anime.interactor.DeleteAnimeTrack
|
||||
import tachiyomi.domain.track.anime.interactor.GetAnimeTracks
|
||||
import tachiyomi.domain.track.anime.interactor.InsertAnimeTrack
|
||||
import tachiyomi.domain.track.anime.model.AnimeTrack
|
||||
import tachiyomi.presentation.core.components.material.AlertDialogContent
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
|
@ -210,7 +207,7 @@ data class AnimeTrackInfoDialogHomeScreen(
|
|||
val anime = Injekt.get<GetAnime>().await(animeId) ?: return@launchNonCancellable
|
||||
try {
|
||||
val matchResult = item.service.match(anime) ?: throw Exception()
|
||||
item.service.animeService.registerTracking(matchResult, animeId)
|
||||
item.service.animeService.register(matchResult, animeId)
|
||||
} catch (e: Exception) {
|
||||
withUIContext { Injekt.get<Application>().toast(R.string.error_no_match) }
|
||||
}
|
||||
|
@ -218,49 +215,30 @@ data class AnimeTrackInfoDialogHomeScreen(
|
|||
}
|
||||
|
||||
private suspend fun refreshTrackers() {
|
||||
val insertAnimeTrack = Injekt.get<InsertAnimeTrack>()
|
||||
val getAnimeWithEpisodes = Injekt.get<GetAnimeWithEpisodes>()
|
||||
val syncTwoWayService = Injekt.get<SyncEpisodesWithTrackServiceTwoWay>()
|
||||
val refreshTracks = Injekt.get<RefreshAnimeTracks>()
|
||||
val context = Injekt.get<Application>()
|
||||
|
||||
try {
|
||||
val trackItems = getTracks.await(animeId).mapToTrackItem()
|
||||
for (trackItem in trackItems) {
|
||||
try {
|
||||
val track = trackItem.track ?: continue
|
||||
val domainAnimeTrack = trackItem.service.animeService.refresh(track.toDbTrack()).toDomainTrack() ?: continue
|
||||
insertAnimeTrack.await(domainAnimeTrack)
|
||||
|
||||
if (trackItem.service is EnhancedAnimeTrackService) {
|
||||
val allEpisodes = getAnimeWithEpisodes.awaitEpisodes(animeId)
|
||||
syncTwoWayService.await(allEpisodes, domainAnimeTrack, trackItem.service.animeService)
|
||||
refreshTracks.await(animeId)
|
||||
.filter { it.first != null }
|
||||
.forEach { (track, e) ->
|
||||
logcat(LogPriority.ERROR, e) {
|
||||
"Failed to refresh track data mangaId=$animeId for service ${track!!.id}"
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logcat(
|
||||
LogPriority.ERROR,
|
||||
e,
|
||||
) { "Failed to refresh track data mangaId=$animeId for service ${trackItem.service.id}" }
|
||||
withUIContext {
|
||||
context.toast(
|
||||
context.getString(
|
||||
R.string.track_error,
|
||||
context.getString(trackItem.service.nameRes()),
|
||||
track!!.name,
|
||||
e.message,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR, e) { "Failed to refresh track data animeId=$animeId" }
|
||||
withUIContext { context.toast(e.message) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<AnimeTrack>.mapToTrackItem(): List<AnimeTrackItem> {
|
||||
val dbTracks = map { it.toDbTrack() }
|
||||
val loggedServices = Injekt.get<TrackManager>().services.filter {
|
||||
it.isLogged && it is AnimeTrackService
|
||||
it.isLoggedIn && it is AnimeTrackService
|
||||
}
|
||||
val source = Injekt.get<AnimeSourceManager>().getOrStub(sourceId)
|
||||
return loggedServices
|
||||
|
@ -594,7 +572,7 @@ private data class TrackDateRemoverScreen(
|
|||
)
|
||||
},
|
||||
text = {
|
||||
val serviceName = stringResource(sm.getServiceNameRes())
|
||||
val serviceName = sm.getServiceName()
|
||||
Text(
|
||||
text = if (start) {
|
||||
stringResource(R.string.track_remove_start_date_conf_text, serviceName)
|
||||
|
@ -631,7 +609,7 @@ private data class TrackDateRemoverScreen(
|
|||
private val start: Boolean,
|
||||
) : ScreenModel {
|
||||
|
||||
fun getServiceNameRes() = service.nameRes()
|
||||
fun getServiceName() = service.name
|
||||
|
||||
fun removeDate() {
|
||||
coroutineScope.launchNonCancellable {
|
||||
|
@ -716,7 +694,7 @@ data class TrackServiceSearchScreen(
|
|||
}
|
||||
|
||||
fun registerTracking(item: AnimeTrackSearch) {
|
||||
coroutineScope.launchNonCancellable { service.animeService.registerTracking(item, animeId) }
|
||||
coroutineScope.launchNonCancellable { service.animeService.register(item, animeId) }
|
||||
}
|
||||
|
||||
fun updateSelection(selected: AnimeTrackSearch) {
|
||||
|
@ -747,7 +725,7 @@ private data class TrackAnimeServiceRemoveScreen(
|
|||
service = Injekt.get<TrackManager>().getService(serviceId)!!,
|
||||
)
|
||||
}
|
||||
val serviceName = stringResource(sm.getServiceNameRes())
|
||||
val serviceName = sm.getServiceName()
|
||||
var removeRemoteTrack by remember { mutableStateOf(false) }
|
||||
AlertDialogContent(
|
||||
modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars),
|
||||
|
@ -812,7 +790,7 @@ private data class TrackAnimeServiceRemoveScreen(
|
|||
private val deleteTrack: DeleteAnimeTrack = Injekt.get(),
|
||||
) : ScreenModel {
|
||||
|
||||
fun getServiceNameRes() = service.nameRes()
|
||||
fun getServiceName() = service.name
|
||||
|
||||
fun isServiceDeletable() = service is DeletableAnimeTrackService
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ class MangaScreenModel(
|
|||
private val successState: State.Success?
|
||||
get() = state.value as? State.Success
|
||||
|
||||
private val loggedServices by lazy { trackManager.services.filter { it.isLogged && it is MangaTrackService } }
|
||||
private val loggedServices by lazy { trackManager.services.filter { it.isLoggedIn && it is MangaTrackService } }
|
||||
|
||||
val manga: Manga?
|
||||
get() = successState?.manga
|
||||
|
@ -333,7 +333,7 @@ class MangaScreenModel(
|
|||
launchIO {
|
||||
try {
|
||||
service.match(manga)?.let { track ->
|
||||
(service as MangaTrackService).registerTracking(track, mangaId)
|
||||
(service as MangaTrackService).register(track, mangaId)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.WARN, e) {
|
||||
|
|
|
@ -39,9 +39,8 @@ import cafe.adriel.voyager.core.model.rememberScreenModel
|
|||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.domain.items.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.track.manga.interactor.RefreshMangaTracks
|
||||
import eu.kanade.domain.track.manga.model.toDbTrack
|
||||
import eu.kanade.domain.track.manga.model.toDomainTrack
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.track.TrackDateSelector
|
||||
import eu.kanade.presentation.track.TrackItemSelector
|
||||
|
@ -72,11 +71,9 @@ import tachiyomi.core.util.lang.withIOContext
|
|||
import tachiyomi.core.util.lang.withUIContext
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.entries.manga.interactor.GetManga
|
||||
import tachiyomi.domain.entries.manga.interactor.GetMangaWithChapters
|
||||
import tachiyomi.domain.source.manga.service.MangaSourceManager
|
||||
import tachiyomi.domain.track.manga.interactor.DeleteMangaTrack
|
||||
import tachiyomi.domain.track.manga.interactor.GetMangaTracks
|
||||
import tachiyomi.domain.track.manga.interactor.InsertMangaTrack
|
||||
import tachiyomi.domain.track.manga.model.MangaTrack
|
||||
import tachiyomi.presentation.core.components.material.AlertDialogContent
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
|
@ -210,7 +207,7 @@ data class MangaTrackInfoDialogHomeScreen(
|
|||
val manga = Injekt.get<GetManga>().await(mangaId) ?: return@launchNonCancellable
|
||||
try {
|
||||
val matchResult = item.service.match(manga) ?: throw Exception()
|
||||
item.service.mangaService.registerTracking(matchResult, mangaId)
|
||||
item.service.mangaService.register(matchResult, mangaId)
|
||||
} catch (e: Exception) {
|
||||
withUIContext { Injekt.get<Application>().toast(R.string.error_no_match) }
|
||||
}
|
||||
|
@ -218,48 +215,30 @@ data class MangaTrackInfoDialogHomeScreen(
|
|||
}
|
||||
|
||||
private suspend fun refreshTrackers() {
|
||||
val insertTrack = Injekt.get<InsertMangaTrack>()
|
||||
val getMangaWithChapters = Injekt.get<GetMangaWithChapters>()
|
||||
val syncTwoWayService = Injekt.get<SyncChaptersWithTrackServiceTwoWay>()
|
||||
val refreshTracks = Injekt.get<RefreshMangaTracks>()
|
||||
val context = Injekt.get<Application>()
|
||||
|
||||
try {
|
||||
val trackItems = getTracks.await(mangaId).mapToTrackItem()
|
||||
for (trackItem in trackItems) {
|
||||
try {
|
||||
val track = trackItem.track ?: continue
|
||||
val domainMangaTrack = trackItem.service.mangaService.refresh(track.toDbTrack()).toDomainTrack() ?: continue
|
||||
insertTrack.await(domainMangaTrack)
|
||||
|
||||
if (trackItem.service is EnhancedMangaTrackService) {
|
||||
val allChapters = getMangaWithChapters.awaitChapters(mangaId)
|
||||
syncTwoWayService.await(allChapters, domainMangaTrack, trackItem.service.mangaService)
|
||||
refreshTracks.await(mangaId)
|
||||
.filter { it.first != null }
|
||||
.forEach { (track, e) ->
|
||||
logcat(LogPriority.ERROR, e) {
|
||||
"Failed to refresh track data mangaId=$mangaId for service ${track!!.name}"
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logcat(
|
||||
LogPriority.ERROR,
|
||||
e,
|
||||
) { "Failed to refresh track data mangaId=$mangaId for service ${trackItem.service.id}" }
|
||||
withUIContext {
|
||||
context.toast(
|
||||
context.getString(
|
||||
R.string.track_error,
|
||||
context.getString(trackItem.service.nameRes()),
|
||||
track!!.name,
|
||||
e.message,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR, e) { "Failed to refresh track data mangaId=$mangaId" }
|
||||
withUIContext { context.toast(e.message) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<MangaTrack>.mapToTrackItem(): List<MangaTrackItem> {
|
||||
val loggedServices = Injekt.get<TrackManager>().services.filter {
|
||||
it.isLogged && it is MangaTrackService
|
||||
it.isLoggedIn && it is MangaTrackService
|
||||
}
|
||||
val source = Injekt.get<MangaSourceManager>().getOrStub(sourceId)
|
||||
return loggedServices
|
||||
|
@ -593,7 +572,7 @@ private data class TrackDateRemoverScreen(
|
|||
)
|
||||
},
|
||||
text = {
|
||||
val serviceName = stringResource(sm.getServiceNameRes())
|
||||
val serviceName = sm.getServiceName()
|
||||
Text(
|
||||
text = if (start) {
|
||||
stringResource(R.string.track_remove_start_date_conf_text, serviceName)
|
||||
|
@ -630,7 +609,7 @@ private data class TrackDateRemoverScreen(
|
|||
private val start: Boolean,
|
||||
) : ScreenModel {
|
||||
|
||||
fun getServiceNameRes() = service.nameRes()
|
||||
fun getServiceName() = service.name
|
||||
|
||||
fun removeDate() {
|
||||
coroutineScope.launchNonCancellable {
|
||||
|
@ -715,7 +694,7 @@ data class TrackServiceSearchScreen(
|
|||
}
|
||||
|
||||
fun registerTracking(item: MangaTrackSearch) {
|
||||
coroutineScope.launchNonCancellable { service.mangaService.registerTracking(item, mangaId) }
|
||||
coroutineScope.launchNonCancellable { service.mangaService.register(item, mangaId) }
|
||||
}
|
||||
|
||||
fun updateSelection(selected: MangaTrackSearch) {
|
||||
|
@ -746,7 +725,7 @@ private data class TrackMangaServiceRemoveScreen(
|
|||
service = Injekt.get<TrackManager>().getService(serviceId)!!,
|
||||
)
|
||||
}
|
||||
val serviceName = stringResource(sm.getServiceNameRes())
|
||||
val serviceName = sm.getServiceName()
|
||||
var removeRemoteTrack by remember { mutableStateOf(false) }
|
||||
AlertDialogContent(
|
||||
modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars),
|
||||
|
@ -811,7 +790,7 @@ private data class TrackMangaServiceRemoveScreen(
|
|||
private val deleteTrack: DeleteMangaTrack = Injekt.get(),
|
||||
) : ScreenModel {
|
||||
|
||||
fun getServiceNameRes() = service.nameRes()
|
||||
fun getServiceName() = service.name
|
||||
|
||||
fun isServiceDeletable() = service is DeletableMangaTrackService
|
||||
|
||||
|
|
|
@ -373,7 +373,7 @@ class AnimeLibraryScreenModel(
|
|||
* @return map of track id with the filter value
|
||||
*/
|
||||
private fun getTrackingFilterFlow(): Flow<Map<Long, TriState>> {
|
||||
val loggedServices = trackManager.services.filter { it.isLogged && it is AnimeTrackService }
|
||||
val loggedServices = trackManager.services.filter { it.isLoggedIn && it is AnimeTrackService }
|
||||
return if (loggedServices.isNotEmpty()) {
|
||||
val prefFlows = loggedServices
|
||||
.map { libraryPreferences.filterTrackedAnime(it.id.toInt()).changes() }
|
||||
|
|
|
@ -26,7 +26,7 @@ class AnimeLibrarySettingsScreenModel(
|
|||
) : ScreenModel {
|
||||
|
||||
val trackServices
|
||||
get() = trackManager.services.filter { it.isLogged }
|
||||
get() = trackManager.services.filter { it.isLoggedIn }
|
||||
|
||||
fun toggleFilter(preference: (LibraryPreferences) -> Preference<TriState>) {
|
||||
preference(libraryPreferences).getAndSet {
|
||||
|
|
|
@ -367,7 +367,7 @@ class MangaLibraryScreenModel(
|
|||
* @return map of track id with the filter value
|
||||
*/
|
||||
private fun getTrackingFilterFlow(): Flow<Map<Long, TriState>> {
|
||||
val loggedServices = trackManager.services.filter { it.isLogged && it is MangaTrackService }
|
||||
val loggedServices = trackManager.services.filter { it.isLoggedIn && it is MangaTrackService }
|
||||
return if (loggedServices.isNotEmpty()) {
|
||||
val prefFlows = loggedServices
|
||||
.map { libraryPreferences.filterTrackedManga(it.id.toInt()).changes() }
|
||||
|
|
|
@ -26,7 +26,7 @@ class MangaLibrarySettingsScreenModel(
|
|||
) : ScreenModel {
|
||||
|
||||
val trackServices
|
||||
get() = trackManager.services.filter { it.isLogged }
|
||||
get() = trackManager.services.filter { it.isLoggedIn }
|
||||
|
||||
fun toggleFilter(preference: (LibraryPreferences) -> Preference<TriState>) {
|
||||
preference(libraryPreferences).getAndSet {
|
||||
|
|
|
@ -481,7 +481,7 @@ class ExternalIntents {
|
|||
getTracks.await(anime.id)
|
||||
.mapNotNull { track ->
|
||||
val service = trackManager.getService(track.syncId)
|
||||
if (service != null && service.isLogged &&
|
||||
if (service != null && service.isLoggedIn &&
|
||||
service is AnimeTrackService && episodeNumber > track.lastEpisodeSeen
|
||||
) {
|
||||
val updatedTrack = track.copy(lastEpisodeSeen = episodeNumber)
|
||||
|
|
|
@ -575,7 +575,7 @@ class PlayerViewModel @JvmOverloads constructor(
|
|||
getTracks.await(anime.id)
|
||||
.mapNotNull { track ->
|
||||
val service = trackManager.getService(track.syncId)
|
||||
if (service != null && service.isLogged && episodeSeen > track.lastEpisodeSeen) {
|
||||
if (service != null && service.isLoggedIn && episodeSeen > track.lastEpisodeSeen) {
|
||||
val updatedTrack = track.copy(lastEpisodeSeen = episodeSeen)
|
||||
|
||||
// We want these to execute even if the presenter is destroyed and leaks
|
||||
|
|
|
@ -869,7 +869,7 @@ class ReaderViewModel @JvmOverloads constructor(
|
|||
getTracks.await(manga.id)
|
||||
.mapNotNull { track ->
|
||||
val service = trackManager.getService(track.syncId)
|
||||
if (service != null && service.isLogged && chapterRead > track.lastChapterRead) {
|
||||
if (service != null && service.isLoggedIn && chapterRead > track.lastChapterRead) {
|
||||
val updatedTrack = track.copy(lastChapterRead = chapterRead)
|
||||
|
||||
// We want these to execute even if the presenter is destroyed and leaks
|
||||
|
|
|
@ -37,7 +37,7 @@ class AnimeStatsScreenModel(
|
|||
private val trackManager: TrackManager = Injekt.get(),
|
||||
) : StateScreenModel<StatsScreenState>(StatsScreenState.Loading) {
|
||||
|
||||
private val loggedServices by lazy { trackManager.services.fastFilter { it.isLogged && it is AnimeTrackService } }
|
||||
private val loggedServices by lazy { trackManager.services.fastFilter { it.isLoggedIn && it is AnimeTrackService } }
|
||||
|
||||
init {
|
||||
coroutineScope.launchIO {
|
||||
|
|
|
@ -37,7 +37,7 @@ class MangaStatsScreenModel(
|
|||
private val trackManager: TrackManager = Injekt.get(),
|
||||
) : StateScreenModel<StatsScreenState>(StatsScreenState.Loading) {
|
||||
|
||||
private val loggedServices by lazy { trackManager.services.fastFilter { it.isLogged && it is MangaTrackService } }
|
||||
private val loggedServices by lazy { trackManager.services.fastFilter { it.isLoggedIn && it is MangaTrackService } }
|
||||
|
||||
init {
|
||||
coroutineScope.launchIO {
|
||||
|
|
|
@ -6,7 +6,7 @@ dependencies {
|
|||
implementation(androidxLibs.gradle)
|
||||
|
||||
implementation(kotlinLibs.gradle)
|
||||
implementation(libs.kotlinter)
|
||||
implementation(libs.ktlint)
|
||||
implementation(gradleApi())
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +1,15 @@
|
|||
|
||||
import org.jmailen.gradle.kotlinter.KotlinterExtension
|
||||
import org.jmailen.gradle.kotlinter.KotlinterPlugin
|
||||
import org.jlleitschuh.gradle.ktlint.KtlintExtension
|
||||
import org.jlleitschuh.gradle.ktlint.KtlintPlugin
|
||||
|
||||
apply<KotlinterPlugin>()
|
||||
apply<KtlintPlugin>()
|
||||
|
||||
extensions.configure<KotlinterExtension>("kotlinter") {
|
||||
experimentalRules = true
|
||||
extensions.configure<KtlintExtension>("ktlint") {
|
||||
version.set("0.50.0")
|
||||
android.set(true)
|
||||
enableExperimentalRules.set(true)
|
||||
|
||||
disabledRules = arrayOf(
|
||||
"experimental:argument-list-wrapping", // Doesn't play well with Android Studio
|
||||
"filename", // Often broken to give a more general name
|
||||
)
|
||||
}
|
||||
|
||||
tasks {
|
||||
named<DefaultTask>("preBuild").configure {
|
||||
if (!System.getenv("CI").toBoolean())
|
||||
dependsOn("formatKotlin")
|
||||
filter {
|
||||
exclude("**/generated/**")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,11 +9,12 @@ class AnimeUpdatesRepositoryImpl(
|
|||
private val databaseHandler: AnimeDatabaseHandler,
|
||||
) : AnimeUpdatesRepository {
|
||||
|
||||
override suspend fun awaitWithSeen(seen: Boolean, after: Long): List<AnimeUpdatesWithRelations> {
|
||||
override suspend fun awaitWithSeen(seen: Boolean, after: Long, limit: Long): List<AnimeUpdatesWithRelations> {
|
||||
return databaseHandler.awaitList {
|
||||
animeupdatesViewQueries.getUpdatesBySeenStatus(
|
||||
seen = seen,
|
||||
after = after,
|
||||
limit = limit,
|
||||
mapper = animeUpdateWithRelationMapper,
|
||||
)
|
||||
}
|
||||
|
@ -25,11 +26,12 @@ class AnimeUpdatesRepositoryImpl(
|
|||
}
|
||||
}
|
||||
|
||||
override fun subscribeWithSeen(seen: Boolean, after: Long): Flow<List<AnimeUpdatesWithRelations>> {
|
||||
override fun subscribeWithSeen(seen: Boolean, after: Long, limit: Long): Flow<List<AnimeUpdatesWithRelations>> {
|
||||
return databaseHandler.subscribeToList {
|
||||
animeupdatesViewQueries.getUpdatesBySeenStatus(
|
||||
seen = seen,
|
||||
after = after,
|
||||
limit = limit,
|
||||
mapper = animeUpdateWithRelationMapper,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -9,11 +9,12 @@ class MangaUpdatesRepositoryImpl(
|
|||
private val databaseHandler: MangaDatabaseHandler,
|
||||
) : MangaUpdatesRepository {
|
||||
|
||||
override suspend fun awaitWithRead(read: Boolean, after: Long): List<MangaUpdatesWithRelations> {
|
||||
override suspend fun awaitWithRead(read: Boolean, after: Long, limit: Long): List<MangaUpdatesWithRelations> {
|
||||
return databaseHandler.awaitList {
|
||||
updatesViewQueries.getUpdatesByReadStatus(
|
||||
read = read,
|
||||
after = after,
|
||||
limit = limit,
|
||||
mapper = mangaUpdateWithRelationMapper,
|
||||
)
|
||||
}
|
||||
|
@ -25,11 +26,12 @@ class MangaUpdatesRepositoryImpl(
|
|||
}
|
||||
}
|
||||
|
||||
override fun subscribeWithRead(read: Boolean, after: Long): Flow<List<MangaUpdatesWithRelations>> {
|
||||
override fun subscribeWithRead(read: Boolean, after: Long, limit: Long): Flow<List<MangaUpdatesWithRelations>> {
|
||||
return databaseHandler.subscribeToList {
|
||||
updatesViewQueries.getUpdatesByReadStatus(
|
||||
read = read,
|
||||
after = after,
|
||||
limit = limit,
|
||||
mapper = mangaUpdateWithRelationMapper,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -30,4 +30,6 @@ getUpdatesByReadStatus:
|
|||
SELECT *
|
||||
FROM updatesView
|
||||
WHERE read = :read
|
||||
AND dateUpload > :after;
|
||||
AND dateUpload > :after
|
||||
|
||||
LIMIT :limit;
|
|
@ -31,4 +31,6 @@ getUpdatesBySeenStatus:
|
|||
SELECT *
|
||||
FROM animeupdatesView
|
||||
WHERE seen = :seen
|
||||
AND dateUpload > :after;
|
||||
AND dateUpload > :after
|
||||
|
||||
LIMIT :limit;
|
|
@ -10,7 +10,7 @@ class GetAnimeUpdates(
|
|||
) {
|
||||
|
||||
suspend fun await(seen: Boolean, after: Long): List<AnimeUpdatesWithRelations> {
|
||||
return repository.awaitWithSeen(seen, after)
|
||||
return repository.awaitWithSeen(seen, after, limit = 500)
|
||||
}
|
||||
|
||||
fun subscribe(calendar: Calendar): Flow<List<AnimeUpdatesWithRelations>> {
|
||||
|
@ -18,6 +18,6 @@ class GetAnimeUpdates(
|
|||
}
|
||||
|
||||
fun subscribe(seen: Boolean, after: Long): Flow<List<AnimeUpdatesWithRelations>> {
|
||||
return repository.subscribeWithSeen(seen, after)
|
||||
return repository.subscribeWithSeen(seen, after, limit = 500)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@ import tachiyomi.domain.updates.anime.model.AnimeUpdatesWithRelations
|
|||
|
||||
interface AnimeUpdatesRepository {
|
||||
|
||||
suspend fun awaitWithSeen(seen: Boolean, after: Long): List<AnimeUpdatesWithRelations>
|
||||
suspend fun awaitWithSeen(seen: Boolean, after: Long, limit: Long): List<AnimeUpdatesWithRelations>
|
||||
|
||||
fun subscribeAllAnimeUpdates(after: Long, limit: Long): Flow<List<AnimeUpdatesWithRelations>>
|
||||
|
||||
fun subscribeWithSeen(seen: Boolean, after: Long): Flow<List<AnimeUpdatesWithRelations>>
|
||||
fun subscribeWithSeen(seen: Boolean, after: Long, limit: Long): Flow<List<AnimeUpdatesWithRelations>>
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ class GetMangaUpdates(
|
|||
) {
|
||||
|
||||
suspend fun await(read: Boolean, after: Long): List<MangaUpdatesWithRelations> {
|
||||
return repository.awaitWithRead(read, after)
|
||||
return repository.awaitWithRead(read, after, limit = 500)
|
||||
}
|
||||
|
||||
fun subscribe(calendar: Calendar): Flow<List<MangaUpdatesWithRelations>> {
|
||||
|
@ -18,6 +18,6 @@ class GetMangaUpdates(
|
|||
}
|
||||
|
||||
fun subscribe(read: Boolean, after: Long): Flow<List<MangaUpdatesWithRelations>> {
|
||||
return repository.subscribeWithRead(read, after)
|
||||
return repository.subscribeWithRead(read, after, limit = 500)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@ import tachiyomi.domain.updates.manga.model.MangaUpdatesWithRelations
|
|||
|
||||
interface MangaUpdatesRepository {
|
||||
|
||||
suspend fun awaitWithRead(read: Boolean, after: Long): List<MangaUpdatesWithRelations>
|
||||
suspend fun awaitWithRead(read: Boolean, after: Long, limit: Long): List<MangaUpdatesWithRelations>
|
||||
|
||||
fun subscribeAllMangaUpdates(after: Long, limit: Long): Flow<List<MangaUpdatesWithRelations>>
|
||||
|
||||
fun subscribeWithRead(read: Boolean, after: Long): Flow<List<MangaUpdatesWithRelations>>
|
||||
fun subscribeWithRead(read: Boolean, after: Long, limit: Long): Flow<List<MangaUpdatesWithRelations>>
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ guava = "com.google.guava:guava:32.1.2-android"
|
|||
paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "paging_version" }
|
||||
paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging_version" }
|
||||
|
||||
benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.0-beta04"
|
||||
benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.0-beta05"
|
||||
test-ext = "androidx.test.ext:junit-ktx:1.2.0-alpha01"
|
||||
test-espresso-core = "androidx.test.espresso:espresso-core:3.6.0-alpha01"
|
||||
test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0-alpha04"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[versions]
|
||||
kotlin_version = "1.9.0"
|
||||
serialization_version = "1.5.1"
|
||||
serialization_version = "1.6.0"
|
||||
xml_serialization_version = "0.86.1"
|
||||
|
||||
[libraries]
|
||||
|
|
|
@ -32,7 +32,7 @@ junrar = "com.github.junrar:junrar:7.5.5"
|
|||
|
||||
sqlite-framework = { module = "androidx.sqlite:sqlite-framework", version.ref = "sqlite" }
|
||||
sqlite-ktx = { module = "androidx.sqlite:sqlite-ktx", version.ref = "sqlite" }
|
||||
sqlite-android = "com.github.requery:sqlite-android:3.42.0"
|
||||
sqlite-android = "com.github.requery:sqlite-android:3.43.0"
|
||||
|
||||
preferencektx = "androidx.preference:preference-ktx:1.2.1"
|
||||
|
||||
|
@ -89,7 +89,7 @@ voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.
|
|||
voyager-tab-navigator = { module = "cafe.adriel.voyager:voyager-tab-navigator", version.ref = "voyager" }
|
||||
voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" }
|
||||
|
||||
kotlinter = "org.jmailen.gradle:kotlinter-gradle:3.13.0"
|
||||
ktlint = "org.jlleitschuh.gradle:ktlint-gradle:11.5.1"
|
||||
|
||||
aniyomi-mpv = "com.github.aniyomiorg:aniyomi-mpv-lib:1.10.n"
|
||||
ffmpeg-kit = "com.github.jmir1:ffmpeg-kit:1.10"
|
||||
|
|
|
@ -682,16 +682,6 @@
|
|||
<string name="are_you_sure">Are you sure?</string>
|
||||
|
||||
<!-- Tracking Screen -->
|
||||
<string name="tracker_anilist" translatable="false">AniList</string>
|
||||
<string name="tracker_myanimelist" translatable="false">MyAnimeList</string>
|
||||
<string name="tracker_kitsu" translatable="false">Kitsu</string>
|
||||
<string name="tracker_komga" translatable="false">Komga</string>
|
||||
<string name="tracker_bangumi" translatable="false">Bangumi</string>
|
||||
<string name="tracker_shikimori" translatable="false">Shikimori</string>
|
||||
<string name="tracker_simkl" translatable="false">Simkl</string>
|
||||
<string name="tracker_manga_updates" translatable="false">MangaUpdates</string>
|
||||
<string name="tracker_kavita" translatable="false">Kavita</string>
|
||||
<string name="tracker_suwayomi" translatable="false">Suwayomi</string>
|
||||
<string name="manga_tracking_tab">Tracking</string>
|
||||
<plurals name="num_trackers">
|
||||
<item quantity="one">%d tracker</item>
|
||||
|
|
|
@ -37,14 +37,14 @@ import tachiyomi.presentation.widget.util.appWidgetBackgroundRadius
|
|||
import tachiyomi.presentation.widget.util.calculateRowAndColumnCount
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
|
||||
class AnimeUpdatesGridGlanceWidget : GlanceAppWidget() {
|
||||
|
||||
private val app: Application by injectLazy()
|
||||
private val preferences: SecurityPreferences by injectLazy()
|
||||
class AnimeUpdatesGridGlanceWidget(
|
||||
private val context: Context = Injekt.get<Application>(),
|
||||
private val getUpdates: GetAnimeUpdates = Injekt.get(),
|
||||
private val preferences: SecurityPreferences = Injekt.get(),
|
||||
) : GlanceAppWidget() {
|
||||
|
||||
private var data: List<Pair<Long, Bitmap?>>? = null
|
||||
|
||||
|
@ -64,14 +64,13 @@ class AnimeUpdatesGridGlanceWidget : GlanceAppWidget() {
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun loadData(list: List<AnimeUpdatesWithRelations>? = null) {
|
||||
withIOContext {
|
||||
val manager = GlanceAppWidgetManager(app)
|
||||
private suspend fun loadData() {
|
||||
val manager = GlanceAppWidgetManager(context)
|
||||
val ids = manager.getGlanceIds(this@AnimeUpdatesGridGlanceWidget::class.java)
|
||||
if (ids.isEmpty()) return@withIOContext
|
||||
if (ids.isEmpty()) return
|
||||
|
||||
val processList = list
|
||||
?: Injekt.get<GetAnimeUpdates>().await(
|
||||
withIOContext {
|
||||
val updates = getUpdates.await(
|
||||
seen = false,
|
||||
after = DateLimit.timeInMillis,
|
||||
)
|
||||
|
@ -80,7 +79,7 @@ class AnimeUpdatesGridGlanceWidget : GlanceAppWidget() {
|
|||
.maxBy { it.height.value * it.width.value }
|
||||
.calculateRowAndColumnCount()
|
||||
|
||||
data = prepareList(processList, rowCount * columnCount)
|
||||
data = prepareList(updates, rowCount * columnCount)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,12 +87,12 @@ class AnimeUpdatesGridGlanceWidget : GlanceAppWidget() {
|
|||
// Resize to cover size
|
||||
val widthPx = CoverWidth.value.toInt().dpToPx
|
||||
val heightPx = CoverHeight.value.toInt().dpToPx
|
||||
val roundPx = app.resources.getDimension(R.dimen.appwidget_inner_radius)
|
||||
val roundPx = context.resources.getDimension(R.dimen.appwidget_inner_radius)
|
||||
return processList
|
||||
.distinctBy { it.animeId }
|
||||
.take(take)
|
||||
.map { animeupdatesView ->
|
||||
val request = ImageRequest.Builder(app)
|
||||
val request = ImageRequest.Builder(context)
|
||||
.data(
|
||||
AnimeCover(
|
||||
animeId = animeupdatesView.animeId,
|
||||
|
@ -115,7 +114,7 @@ class AnimeUpdatesGridGlanceWidget : GlanceAppWidget() {
|
|||
}
|
||||
}
|
||||
.build()
|
||||
Pair(animeupdatesView.animeId, app.imageLoader.executeBlocking(request).drawable?.toBitmap())
|
||||
Pair(animeupdatesView.animeId, context.imageLoader.executeBlocking(request).drawable?.toBitmap())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,14 +37,14 @@ import tachiyomi.presentation.widget.util.appWidgetBackgroundRadius
|
|||
import tachiyomi.presentation.widget.util.calculateRowAndColumnCount
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
|
||||
class MangaUpdatesGridGlanceWidget : GlanceAppWidget() {
|
||||
|
||||
private val app: Application by injectLazy()
|
||||
private val preferences: SecurityPreferences by injectLazy()
|
||||
class MangaUpdatesGridGlanceWidget(
|
||||
private val context: Context = Injekt.get<Application>(),
|
||||
private val getUpdates: GetMangaUpdates = Injekt.get(),
|
||||
private val preferences: SecurityPreferences = Injekt.get(),
|
||||
) : GlanceAppWidget() {
|
||||
|
||||
private var data: List<Pair<Long, Bitmap?>>? = null
|
||||
|
||||
|
@ -64,14 +64,13 @@ class MangaUpdatesGridGlanceWidget : GlanceAppWidget() {
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun loadData(list: List<MangaUpdatesWithRelations>? = null) {
|
||||
withIOContext {
|
||||
val manager = GlanceAppWidgetManager(app)
|
||||
private suspend fun loadData() {
|
||||
val manager = GlanceAppWidgetManager(context)
|
||||
val ids = manager.getGlanceIds(this@MangaUpdatesGridGlanceWidget::class.java)
|
||||
if (ids.isEmpty()) return@withIOContext
|
||||
if (ids.isEmpty()) return
|
||||
|
||||
val processList = list
|
||||
?: Injekt.get<GetMangaUpdates>().await(
|
||||
withIOContext {
|
||||
val updates = getUpdates.await(
|
||||
read = false,
|
||||
after = DateLimit.timeInMillis,
|
||||
)
|
||||
|
@ -80,7 +79,7 @@ class MangaUpdatesGridGlanceWidget : GlanceAppWidget() {
|
|||
.maxBy { it.height.value * it.width.value }
|
||||
.calculateRowAndColumnCount()
|
||||
|
||||
data = prepareList(processList, rowCount * columnCount)
|
||||
data = prepareList(updates, rowCount * columnCount)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,12 +87,12 @@ class MangaUpdatesGridGlanceWidget : GlanceAppWidget() {
|
|||
// Resize to cover size
|
||||
val widthPx = CoverWidth.value.toInt().dpToPx
|
||||
val heightPx = CoverHeight.value.toInt().dpToPx
|
||||
val roundPx = app.resources.getDimension(R.dimen.appwidget_inner_radius)
|
||||
val roundPx = context.resources.getDimension(R.dimen.appwidget_inner_radius)
|
||||
return processList
|
||||
.distinctBy { it.mangaId }
|
||||
.take(take)
|
||||
.map { updatesView ->
|
||||
val request = ImageRequest.Builder(app)
|
||||
val request = ImageRequest.Builder(context)
|
||||
.data(
|
||||
MangaCover(
|
||||
mangaId = updatesView.mangaId,
|
||||
|
@ -115,7 +114,7 @@ class MangaUpdatesGridGlanceWidget : GlanceAppWidget() {
|
|||
}
|
||||
}
|
||||
.build()
|
||||
Pair(updatesView.mangaId, app.imageLoader.executeBlocking(request).drawable?.toBitmap())
|
||||
Pair(updatesView.mangaId, context.imageLoader.executeBlocking(request).drawable?.toBitmap())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue