Move tracker binding logic to interactor
This commit is contained in:
parent
4b225a4ff1
commit
69223df27c
5 changed files with 97 additions and 88 deletions
|
@ -118,7 +118,7 @@ class DomainModule : InjektModule {
|
|||
|
||||
addSingletonFactory<TrackRepository> { 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()) }
|
||||
|
|
|
@ -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<EnhancedTracker>()
|
||||
.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<GetHistory>().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<EnhancedTracker>()
|
||||
.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" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<GetChaptersByMangaId>().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<GetHistory>().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<Application>().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<Application>().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<Application>().toast(e.message) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -319,7 +319,7 @@ class MangaScreenModel(
|
|||
}
|
||||
|
||||
// Finally match with enhanced tracking when available
|
||||
addTracks.bindEnhancedTracks(manga, state.source)
|
||||
addTracks.bindEnhancedTrackers(manga, state.source)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue