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