diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index 9967e000f3..49c1308525 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -118,7 +118,7 @@ class DomainModule : InjektModule { addSingletonFactory { TrackRepositoryImpl(get()) } addFactory { TrackChapter(get(), get(), get(), get()) } - addFactory { AddTracks(get(), get(), get()) } + addFactory { AddTracks(get(), get(), get(), get()) } addFactory { RefreshTracks(get(), get(), get(), get()) } addFactory { DeleteTrack(get()) } addFactory { GetTracksPerManga(get()) } diff --git a/app/src/main/java/eu/kanade/domain/track/interactor/AddTracks.kt b/app/src/main/java/eu/kanade/domain/track/interactor/AddTracks.kt index 45340e44ad..885a6249f7 100644 --- a/app/src/main/java/eu/kanade/domain/track/interactor/AddTracks.kt +++ b/app/src/main/java/eu/kanade/domain/track/interactor/AddTracks.kt @@ -1,45 +1,104 @@ package eu.kanade.domain.track.interactor +import eu.kanade.domain.track.model.toDbTrack import eu.kanade.domain.track.model.toDomainTrack +import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.EnhancedTracker import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.source.Source +import eu.kanade.tachiyomi.util.lang.convertEpochMillisZone import logcat.LogPriority +import tachiyomi.core.util.lang.withIOContext import tachiyomi.core.util.lang.withNonCancellableContext import tachiyomi.core.util.system.logcat +import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId +import tachiyomi.domain.history.interactor.GetHistory import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.track.interactor.GetTracks import tachiyomi.domain.track.interactor.InsertTrack +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get +import java.time.ZoneOffset class AddTracks( private val getTracks: GetTracks, private val insertTrack: InsertTrack, private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack, + private val getChaptersByMangaId: GetChaptersByMangaId, ) { - suspend fun bindEnhancedTracks(manga: Manga, source: Source) = withNonCancellableContext { - getTracks.await(manga.id) - .filterIsInstance() - .filter { it.accept(source) } - .forEach { service -> - try { - service.match(manga)?.let { track -> - track.manga_id = manga.id - (service as Tracker).bind(track) - insertTrack.await(track.toDomainTrack()!!) + // TODO: update all trackers based on common data + suspend fun bind(tracker: Tracker, item: Track, mangaId: Long) = withNonCancellableContext { + withIOContext { + val allChapters = getChaptersByMangaId.await(mangaId) + val hasReadChapters = allChapters.any { it.read } + tracker.bind(item, hasReadChapters) - syncChapterProgressWithTrack.await( - manga.id, - track.toDomainTrack()!!, - service, + var track = item.toDomainTrack(idRequired = false) ?: return@withIOContext + + insertTrack.await(track) + + // TODO: merge into [SyncChapterProgressWithTrack]? + // Update chapter progress if newer chapters marked read locally + if (hasReadChapters) { + val latestLocalReadChapterNumber = allChapters + .sortedBy { it.chapterNumber } + .takeWhile { it.read } + .lastOrNull() + ?.chapterNumber ?: -1.0 + + if (latestLocalReadChapterNumber > track.lastChapterRead) { + track = track.copy( + lastChapterRead = latestLocalReadChapterNumber, + ) + tracker.setRemoteLastChapterRead(track.toDbTrack(), latestLocalReadChapterNumber.toInt()) + } + + if (track.startDate <= 0) { + val firstReadChapterDate = Injekt.get().await(mangaId) + .sortedBy { it.readAt } + .firstOrNull() + ?.readAt + + firstReadChapterDate?.let { + val startDate = firstReadChapterDate.time.convertEpochMillisZone(ZoneOffset.systemDefault(), ZoneOffset.UTC) + track = track.copy( + startDate = startDate, ) + tracker.setRemoteStartDate(track.toDbTrack(), startDate) } - } catch (e: Exception) { - logcat( - LogPriority.WARN, - e, - ) { "Could not match manga: ${manga.title} with service $service" } } } + + syncChapterProgressWithTrack.await(mangaId, track, tracker) + } + } + + suspend fun bindEnhancedTrackers(manga: Manga, source: Source) = withNonCancellableContext { + withIOContext { + getTracks.await(manga.id) + .filterIsInstance() + .filter { it.accept(source) } + .forEach { service -> + try { + service.match(manga)?.let { track -> + track.manga_id = manga.id + (service as Tracker).bind(track) + insertTrack.await(track.toDomainTrack()!!) + + syncChapterProgressWithTrack.await( + manga.id, + track.toDomainTrack()!!, + service, + ) + } + } catch (e: Exception) { + logcat( + LogPriority.WARN, + e, + ) { "Could not match manga: ${manga.title} with service $service" } + } + } + } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt index 94b81783d5..277638bc1d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt @@ -2,26 +2,21 @@ package eu.kanade.tachiyomi.data.track import android.app.Application import androidx.annotation.CallSuper -import eu.kanade.domain.track.interactor.SyncChapterProgressWithTrack -import eu.kanade.domain.track.model.toDbTrack +import eu.kanade.domain.track.interactor.AddTracks import eu.kanade.domain.track.model.toDomainTrack import eu.kanade.domain.track.service.TrackPreferences import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.network.NetworkHelper -import eu.kanade.tachiyomi.util.lang.convertEpochMillisZone import eu.kanade.tachiyomi.util.system.toast import logcat.LogPriority import okhttp3.OkHttpClient import tachiyomi.core.util.lang.withIOContext import tachiyomi.core.util.lang.withUIContext import tachiyomi.core.util.system.logcat -import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId -import tachiyomi.domain.history.interactor.GetHistory import tachiyomi.domain.track.interactor.InsertTrack import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy -import java.time.ZoneOffset import tachiyomi.domain.track.model.Track as DomainTrack abstract class BaseTracker( @@ -31,8 +26,8 @@ abstract class BaseTracker( val trackPreferences: TrackPreferences by injectLazy() val networkService: NetworkHelper by injectLazy() + private val addTracks: AddTracks by injectLazy() private val insertTrack: InsertTrack by injectLazy() - private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack by injectLazy() override val client: OkHttpClient get() = networkService.client @@ -66,53 +61,10 @@ abstract class BaseTracker( trackPreferences.setCredentials(this, username, password) } - // TODO: move this to an interactor, and update all trackers based on common data override suspend fun register(item: Track, mangaId: Long) { item.manga_id = mangaId try { - withIOContext { - val allChapters = Injekt.get().await(mangaId) - val hasReadChapters = allChapters.any { it.read } - bind(item, hasReadChapters) - - var track = item.toDomainTrack(idRequired = false) ?: return@withIOContext - - insertTrack.await(track) - - // TODO: merge into [SyncChapterProgressWithTrack]? - // Update chapter progress if newer chapters marked read locally - if (hasReadChapters) { - val latestLocalReadChapterNumber = allChapters - .sortedBy { it.chapterNumber } - .takeWhile { it.read } - .lastOrNull() - ?.chapterNumber ?: -1.0 - - if (latestLocalReadChapterNumber > track.lastChapterRead) { - track = track.copy( - lastChapterRead = latestLocalReadChapterNumber, - ) - setRemoteLastChapterRead(track.toDbTrack(), latestLocalReadChapterNumber.toInt()) - } - - if (track.startDate <= 0) { - val firstReadChapterDate = Injekt.get().await(mangaId) - .sortedBy { it.readAt } - .firstOrNull() - ?.readAt - - firstReadChapterDate?.let { - val startDate = firstReadChapterDate.time.convertEpochMillisZone(ZoneOffset.systemDefault(), ZoneOffset.UTC) - track = track.copy( - startDate = startDate, - ) - setRemoteStartDate(track.toDbTrack(), startDate) - } - } - } - - syncChapterProgressWithTrack.await(mangaId, track, this@BaseTracker) - } + addTracks.bind(this, item, mangaId) } catch (e: Throwable) { withUIContext { Injekt.get().toast(e.message) } } @@ -123,7 +75,7 @@ abstract class BaseTracker( if (track.status == getCompletionStatus() && track.total_chapters != 0) { track.last_chapter_read = track.total_chapters.toFloat() } - withIOContext { updateRemote(track) } + updateRemote(track) } override suspend fun setRemoteLastChapterRead(track: Track, chapterNumber: Int) { @@ -135,35 +87,33 @@ abstract class BaseTracker( track.status = getCompletionStatus() track.finished_reading_date = System.currentTimeMillis() } - withIOContext { updateRemote(track) } + updateRemote(track) } override suspend fun setRemoteScore(track: Track, scoreString: String) { track.score = indexToScore(getScoreList().indexOf(scoreString)) - withIOContext { updateRemote(track) } + updateRemote(track) } override suspend fun setRemoteStartDate(track: Track, epochMillis: Long) { track.started_reading_date = epochMillis - withIOContext { updateRemote(track) } + updateRemote(track) } override suspend fun setRemoteFinishDate(track: Track, epochMillis: Long) { track.finished_reading_date = epochMillis - withIOContext { updateRemote(track) } + updateRemote(track) } - private suspend fun updateRemote(track: Track) { - withIOContext { - try { - update(track) - track.toDomainTrack(idRequired = false)?.let { - insertTrack.await(it) - } - } catch (e: Exception) { - logcat(LogPriority.ERROR, e) { "Failed to update remote track data id=$id" } - withUIContext { Injekt.get().toast(e.message) } + private suspend fun updateRemote(track: Track): Unit = withIOContext { + try { + update(track) + track.toDomainTrack(idRequired = false)?.let { + insertTrack.await(it) } + } catch (e: Exception) { + logcat(LogPriority.ERROR, e) { "Failed to update remote track data id=$id" } + withUIContext { Injekt.get().toast(e.message) } } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt index 2abd5e0ac9..37203015af 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt @@ -233,7 +233,7 @@ class BrowseSourceScreenModel( new = new.removeCovers(coverCache) } else { setMangaDefaultChapterFlags.await(manga) - addTracks.bindEnhancedTracks(manga, source) + addTracks.bindEnhancedTrackers(manga, source) } updateManga.await(new.toMangaUpdate()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt index 4fa4baba5d..37c4dab9b9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt @@ -319,7 +319,7 @@ class MangaScreenModel( } // Finally match with enhanced tracking when available - addTracks.bindEnhancedTracks(manga, state.source) + addTracks.bindEnhancedTrackers(manga, state.source) } } }