mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-03 23:58:55 +01:00 
			
		
		
		
	Decoupled Tracker Interface (#10042)
Split out Tracker to interface and created simple dummy instance for previews
This commit is contained in:
		
							
								
								
									
										169
									
								
								app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,169 @@
 | 
			
		||||
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.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.GetChapterByMangaId
 | 
			
		||||
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(
 | 
			
		||||
    override val id: Long,
 | 
			
		||||
    override val name: String,
 | 
			
		||||
) : Tracker {
 | 
			
		||||
 | 
			
		||||
    val trackPreferences: TrackPreferences by injectLazy()
 | 
			
		||||
    val networkService: NetworkHelper by injectLazy()
 | 
			
		||||
    private val insertTrack: InsertTrack by injectLazy()
 | 
			
		||||
    private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack by injectLazy()
 | 
			
		||||
 | 
			
		||||
    override val client: OkHttpClient
 | 
			
		||||
        get() = networkService.client
 | 
			
		||||
 | 
			
		||||
    // Application and remote support for reading dates
 | 
			
		||||
    override val supportsReadingDates: Boolean = false
 | 
			
		||||
 | 
			
		||||
    // TODO: Store all scores as 10 point in the future maybe?
 | 
			
		||||
    override fun get10PointScore(track: DomainTrack): Double {
 | 
			
		||||
        return track.score
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun indexToScore(index: Int): Float {
 | 
			
		||||
        return index.toFloat()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @CallSuper
 | 
			
		||||
    override fun logout() {
 | 
			
		||||
        trackPreferences.setCredentials(this, "", "")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override val isLoggedIn: Boolean
 | 
			
		||||
        get() = getUsername().isNotEmpty() &&
 | 
			
		||||
            getPassword().isNotEmpty()
 | 
			
		||||
 | 
			
		||||
    override fun getUsername() = trackPreferences.trackUsername(this).get()
 | 
			
		||||
 | 
			
		||||
    override fun getPassword() = trackPreferences.trackPassword(this).get()
 | 
			
		||||
 | 
			
		||||
    override fun saveCredentials(username: String, password: String) {
 | 
			
		||||
        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<GetChapterByMangaId>().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)
 | 
			
		||||
            }
 | 
			
		||||
        } catch (e: Throwable) {
 | 
			
		||||
            withUIContext { Injekt.get<Application>().toast(e.message) }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun setRemoteStatus(track: Track, status: Int) {
 | 
			
		||||
        track.status = status
 | 
			
		||||
        if (track.status == getCompletionStatus() && track.total_chapters != 0) {
 | 
			
		||||
            track.last_chapter_read = track.total_chapters.toFloat()
 | 
			
		||||
        }
 | 
			
		||||
        withIOContext { updateRemote(track) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun setRemoteLastChapterRead(track: Track, chapterNumber: Int) {
 | 
			
		||||
        if (track.last_chapter_read == 0f && track.last_chapter_read < chapterNumber && track.status != getRereadingStatus()) {
 | 
			
		||||
            track.status = getReadingStatus()
 | 
			
		||||
        }
 | 
			
		||||
        track.last_chapter_read = chapterNumber.toFloat()
 | 
			
		||||
        if (track.total_chapters != 0 && track.last_chapter_read.toInt() == track.total_chapters) {
 | 
			
		||||
            track.status = getCompletionStatus()
 | 
			
		||||
            track.finished_reading_date = System.currentTimeMillis()
 | 
			
		||||
        }
 | 
			
		||||
        withIOContext { updateRemote(track) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun setRemoteScore(track: Track, scoreString: String) {
 | 
			
		||||
        track.score = indexToScore(getScoreList().indexOf(scoreString))
 | 
			
		||||
        withIOContext { updateRemote(track) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun setRemoteStartDate(track: Track, epochMillis: Long) {
 | 
			
		||||
        track.started_reading_date = epochMillis
 | 
			
		||||
        withIOContext { updateRemote(track) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun setRemoteFinishDate(track: Track, epochMillis: Long) {
 | 
			
		||||
        track.finished_reading_date = epochMillis
 | 
			
		||||
        withIOContext { 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) }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,201 +1,81 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.track
 | 
			
		||||
 | 
			
		||||
import android.app.Application
 | 
			
		||||
import androidx.annotation.CallSuper
 | 
			
		||||
import androidx.annotation.ColorInt
 | 
			
		||||
import androidx.annotation.DrawableRes
 | 
			
		||||
import androidx.annotation.StringRes
 | 
			
		||||
import eu.kanade.domain.track.interactor.SyncChapterProgressWithTrack
 | 
			
		||||
import eu.kanade.domain.track.model.toDbTrack
 | 
			
		||||
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.data.track.model.TrackSearch
 | 
			
		||||
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.GetChapterByMangaId
 | 
			
		||||
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 Tracker(val id: Long, val name: String) {
 | 
			
		||||
interface Tracker {
 | 
			
		||||
 | 
			
		||||
    val trackPreferences: TrackPreferences by injectLazy()
 | 
			
		||||
    val networkService: NetworkHelper by injectLazy()
 | 
			
		||||
    private val insertTrack: InsertTrack by injectLazy()
 | 
			
		||||
    private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack by injectLazy()
 | 
			
		||||
    val id: Long
 | 
			
		||||
 | 
			
		||||
    open val client: OkHttpClient
 | 
			
		||||
        get() = networkService.client
 | 
			
		||||
    val name: String
 | 
			
		||||
 | 
			
		||||
    val client: OkHttpClient
 | 
			
		||||
 | 
			
		||||
    // Application and remote support for reading dates
 | 
			
		||||
    open val supportsReadingDates: Boolean = false
 | 
			
		||||
 | 
			
		||||
    @DrawableRes
 | 
			
		||||
    abstract fun getLogo(): Int
 | 
			
		||||
    val supportsReadingDates: Boolean
 | 
			
		||||
 | 
			
		||||
    @ColorInt
 | 
			
		||||
    abstract fun getLogoColor(): Int
 | 
			
		||||
    fun getLogoColor(): Int
 | 
			
		||||
 | 
			
		||||
    abstract fun getStatusList(): List<Int>
 | 
			
		||||
    @DrawableRes
 | 
			
		||||
    fun getLogo(): Int
 | 
			
		||||
 | 
			
		||||
    fun getStatusList(): List<Int>
 | 
			
		||||
 | 
			
		||||
    @StringRes
 | 
			
		||||
    abstract fun getStatus(status: Int): Int?
 | 
			
		||||
    fun getStatus(status: Int): Int?
 | 
			
		||||
 | 
			
		||||
    abstract fun getReadingStatus(): Int
 | 
			
		||||
    fun getReadingStatus(): Int
 | 
			
		||||
 | 
			
		||||
    abstract fun getRereadingStatus(): Int
 | 
			
		||||
    fun getRereadingStatus(): Int
 | 
			
		||||
 | 
			
		||||
    abstract fun getCompletionStatus(): Int
 | 
			
		||||
    fun getCompletionStatus(): Int
 | 
			
		||||
 | 
			
		||||
    abstract fun getScoreList(): List<String>
 | 
			
		||||
    fun getScoreList(): List<String>
 | 
			
		||||
 | 
			
		||||
    // TODO: Store all scores as 10 point in the future maybe?
 | 
			
		||||
    open fun get10PointScore(track: DomainTrack): Double {
 | 
			
		||||
        return track.score
 | 
			
		||||
    }
 | 
			
		||||
    fun get10PointScore(track: tachiyomi.domain.track.model.Track): Double
 | 
			
		||||
 | 
			
		||||
    open fun indexToScore(index: Int): Float {
 | 
			
		||||
        return index.toFloat()
 | 
			
		||||
    }
 | 
			
		||||
    fun indexToScore(index: Int): Float
 | 
			
		||||
 | 
			
		||||
    abstract fun displayScore(track: Track): String
 | 
			
		||||
    fun displayScore(track: Track): String
 | 
			
		||||
 | 
			
		||||
    abstract suspend fun update(track: Track, didReadChapter: Boolean = false): Track
 | 
			
		||||
    suspend fun update(track: Track, didReadChapter: Boolean = false): Track
 | 
			
		||||
 | 
			
		||||
    abstract suspend fun bind(track: Track, hasReadChapters: Boolean = false): Track
 | 
			
		||||
    suspend fun bind(track: Track, hasReadChapters: Boolean = false): Track
 | 
			
		||||
 | 
			
		||||
    abstract suspend fun search(query: String): List<TrackSearch>
 | 
			
		||||
    suspend fun search(query: String): List<TrackSearch>
 | 
			
		||||
 | 
			
		||||
    abstract suspend fun refresh(track: Track): Track
 | 
			
		||||
    suspend fun refresh(track: Track): Track
 | 
			
		||||
 | 
			
		||||
    abstract suspend fun login(username: String, password: String)
 | 
			
		||||
    suspend fun login(username: String, password: String)
 | 
			
		||||
 | 
			
		||||
    @CallSuper
 | 
			
		||||
    open fun logout() {
 | 
			
		||||
        trackPreferences.setCredentials(this, "", "")
 | 
			
		||||
    }
 | 
			
		||||
    fun logout()
 | 
			
		||||
 | 
			
		||||
    open val isLoggedIn: Boolean
 | 
			
		||||
        get() = getUsername().isNotEmpty() &&
 | 
			
		||||
            getPassword().isNotEmpty()
 | 
			
		||||
    val isLoggedIn: Boolean
 | 
			
		||||
 | 
			
		||||
    fun getUsername() = trackPreferences.trackUsername(this).get()
 | 
			
		||||
    fun getUsername(): String
 | 
			
		||||
 | 
			
		||||
    fun getPassword() = trackPreferences.trackPassword(this).get()
 | 
			
		||||
    fun getPassword(): String
 | 
			
		||||
 | 
			
		||||
    fun saveCredentials(username: String, password: String) {
 | 
			
		||||
        trackPreferences.setCredentials(this, username, password)
 | 
			
		||||
    }
 | 
			
		||||
    fun saveCredentials(username: String, password: String)
 | 
			
		||||
 | 
			
		||||
    // TODO: move this to an interactor, and update all trackers based on common data
 | 
			
		||||
    suspend fun register(item: Track, mangaId: Long) {
 | 
			
		||||
        item.manga_id = mangaId
 | 
			
		||||
        try {
 | 
			
		||||
            withIOContext {
 | 
			
		||||
                val allChapters = Injekt.get<GetChapterByMangaId>().await(mangaId)
 | 
			
		||||
                val hasReadChapters = allChapters.any { it.read }
 | 
			
		||||
                bind(item, hasReadChapters)
 | 
			
		||||
    suspend fun register(item: Track, mangaId: Long)
 | 
			
		||||
 | 
			
		||||
                var track = item.toDomainTrack(idRequired = false) ?: return@withIOContext
 | 
			
		||||
    suspend fun setRemoteStatus(track: Track, status: Int)
 | 
			
		||||
 | 
			
		||||
                insertTrack.await(track)
 | 
			
		||||
    suspend fun setRemoteLastChapterRead(track: Track, chapterNumber: Int)
 | 
			
		||||
 | 
			
		||||
                // 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
 | 
			
		||||
    suspend fun setRemoteScore(track: Track, scoreString: String)
 | 
			
		||||
 | 
			
		||||
                    if (latestLocalReadChapterNumber > track.lastChapterRead) {
 | 
			
		||||
                        track = track.copy(
 | 
			
		||||
                            lastChapterRead = latestLocalReadChapterNumber,
 | 
			
		||||
                        )
 | 
			
		||||
                        setRemoteLastChapterRead(track.toDbTrack(), latestLocalReadChapterNumber.toInt())
 | 
			
		||||
                    }
 | 
			
		||||
    suspend fun setRemoteStartDate(track: Track, epochMillis: Long)
 | 
			
		||||
 | 
			
		||||
                    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@Tracker)
 | 
			
		||||
            }
 | 
			
		||||
        } catch (e: Throwable) {
 | 
			
		||||
            withUIContext { Injekt.get<Application>().toast(e.message) }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun setRemoteStatus(track: Track, status: Int) {
 | 
			
		||||
        track.status = status
 | 
			
		||||
        if (track.status == getCompletionStatus() && track.total_chapters != 0) {
 | 
			
		||||
            track.last_chapter_read = track.total_chapters.toFloat()
 | 
			
		||||
        }
 | 
			
		||||
        withIOContext { updateRemote(track) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun setRemoteLastChapterRead(track: Track, chapterNumber: Int) {
 | 
			
		||||
        if (track.last_chapter_read == 0f && track.last_chapter_read < chapterNumber && track.status != getRereadingStatus()) {
 | 
			
		||||
            track.status = getReadingStatus()
 | 
			
		||||
        }
 | 
			
		||||
        track.last_chapter_read = chapterNumber.toFloat()
 | 
			
		||||
        if (track.total_chapters != 0 && track.last_chapter_read.toInt() == track.total_chapters) {
 | 
			
		||||
            track.status = getCompletionStatus()
 | 
			
		||||
            track.finished_reading_date = System.currentTimeMillis()
 | 
			
		||||
        }
 | 
			
		||||
        withIOContext { updateRemote(track) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun setRemoteScore(track: Track, scoreString: String) {
 | 
			
		||||
        track.score = indexToScore(getScoreList().indexOf(scoreString))
 | 
			
		||||
        withIOContext { updateRemote(track) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun setRemoteStartDate(track: Track, epochMillis: Long) {
 | 
			
		||||
        track.started_reading_date = epochMillis
 | 
			
		||||
        withIOContext { updateRemote(track) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun setRemoteFinishDate(track: Track, epochMillis: Long) {
 | 
			
		||||
        track.finished_reading_date = epochMillis
 | 
			
		||||
        withIOContext { 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) }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    suspend fun setRemoteFinishDate(track: Track, epochMillis: Long)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,15 +4,15 @@ import android.graphics.Color
 | 
			
		||||
import androidx.annotation.StringRes
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Track
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.BaseTracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.DeletableTracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.Tracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
 | 
			
		||||
import kotlinx.serialization.encodeToString
 | 
			
		||||
import kotlinx.serialization.json.Json
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
import tachiyomi.domain.track.model.Track as DomainTrack
 | 
			
		||||
 | 
			
		||||
class Anilist(id: Long) : Tracker(id, "AniList"), DeletableTracker {
 | 
			
		||||
class Anilist(id: Long) : BaseTracker(id, "AniList"), DeletableTracker {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        const val READING = 1
 | 
			
		||||
 
 | 
			
		||||
@@ -4,13 +4,13 @@ import android.graphics.Color
 | 
			
		||||
import androidx.annotation.StringRes
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Track
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.Tracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.BaseTracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
 | 
			
		||||
import kotlinx.serialization.encodeToString
 | 
			
		||||
import kotlinx.serialization.json.Json
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
 | 
			
		||||
class Bangumi(id: Long) : Tracker(id, "Bangumi") {
 | 
			
		||||
class Bangumi(id: Long) : BaseTracker(id, "Bangumi") {
 | 
			
		||||
 | 
			
		||||
    private val json: Json by injectLazy()
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,8 +4,8 @@ import android.graphics.Color
 | 
			
		||||
import androidx.annotation.StringRes
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Track
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.BaseTracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.EnhancedTracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.Tracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
 | 
			
		||||
import eu.kanade.tachiyomi.source.ConfigurableSource
 | 
			
		||||
import eu.kanade.tachiyomi.source.Source
 | 
			
		||||
@@ -16,7 +16,7 @@ import uy.kohesive.injekt.injectLazy
 | 
			
		||||
import java.security.MessageDigest
 | 
			
		||||
import tachiyomi.domain.track.model.Track as DomainTrack
 | 
			
		||||
 | 
			
		||||
class Kavita(id: Long) : Tracker(id, "Kavita"), EnhancedTracker {
 | 
			
		||||
class Kavita(id: Long) : BaseTracker(id, "Kavita"), EnhancedTracker {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        const val UNREAD = 1
 | 
			
		||||
 
 | 
			
		||||
@@ -4,15 +4,15 @@ import android.graphics.Color
 | 
			
		||||
import androidx.annotation.StringRes
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Track
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.BaseTracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.DeletableTracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.Tracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
 | 
			
		||||
import kotlinx.serialization.encodeToString
 | 
			
		||||
import kotlinx.serialization.json.Json
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
import java.text.DecimalFormat
 | 
			
		||||
 | 
			
		||||
class Kitsu(id: Long) : Tracker(id, "Kitsu"), DeletableTracker {
 | 
			
		||||
class Kitsu(id: Long) : BaseTracker(id, "Kitsu"), DeletableTracker {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        const val READING = 1
 | 
			
		||||
 
 | 
			
		||||
@@ -4,8 +4,8 @@ import android.graphics.Color
 | 
			
		||||
import androidx.annotation.StringRes
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Track
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.BaseTracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.EnhancedTracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.Tracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
 | 
			
		||||
import eu.kanade.tachiyomi.source.Source
 | 
			
		||||
import okhttp3.Dns
 | 
			
		||||
@@ -13,7 +13,7 @@ import okhttp3.OkHttpClient
 | 
			
		||||
import tachiyomi.domain.manga.model.Manga
 | 
			
		||||
import tachiyomi.domain.track.model.Track as DomainTrack
 | 
			
		||||
 | 
			
		||||
class Komga(id: Long) : Tracker(id, "Komga"), EnhancedTracker {
 | 
			
		||||
class Komga(id: Long) : BaseTracker(id, "Komga"), EnhancedTracker {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        const val UNREAD = 1
 | 
			
		||||
 
 | 
			
		||||
@@ -4,13 +4,13 @@ import android.graphics.Color
 | 
			
		||||
import androidx.annotation.StringRes
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Track
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.BaseTracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.DeletableTracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.Tracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.mangaupdates.dto.copyTo
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.mangaupdates.dto.toTrackSearch
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
 | 
			
		||||
 | 
			
		||||
class MangaUpdates(id: Long) : Tracker(id, "MangaUpdates"), DeletableTracker {
 | 
			
		||||
class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        const val READING_LIST = 0
 | 
			
		||||
 
 | 
			
		||||
@@ -4,14 +4,14 @@ import android.graphics.Color
 | 
			
		||||
import androidx.annotation.StringRes
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Track
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.BaseTracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.DeletableTracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.Tracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
 | 
			
		||||
import kotlinx.serialization.encodeToString
 | 
			
		||||
import kotlinx.serialization.json.Json
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
 | 
			
		||||
class MyAnimeList(id: Long) : Tracker(id, "MyAnimeList"), DeletableTracker {
 | 
			
		||||
class MyAnimeList(id: Long) : BaseTracker(id, "MyAnimeList"), DeletableTracker {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        const val READING = 1
 | 
			
		||||
 
 | 
			
		||||
@@ -4,14 +4,14 @@ import android.graphics.Color
 | 
			
		||||
import androidx.annotation.StringRes
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Track
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.BaseTracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.DeletableTracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.Tracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
 | 
			
		||||
import kotlinx.serialization.encodeToString
 | 
			
		||||
import kotlinx.serialization.json.Json
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
 | 
			
		||||
class Shikimori(id: Long) : Tracker(id, "Shikimori"), DeletableTracker {
 | 
			
		||||
class Shikimori(id: Long) : BaseTracker(id, "Shikimori"), DeletableTracker {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        const val READING = 1
 | 
			
		||||
 
 | 
			
		||||
@@ -4,14 +4,14 @@ import android.graphics.Color
 | 
			
		||||
import androidx.annotation.StringRes
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Track
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.BaseTracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.EnhancedTracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.Tracker
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
 | 
			
		||||
import eu.kanade.tachiyomi.source.Source
 | 
			
		||||
import tachiyomi.domain.manga.model.Manga as DomainManga
 | 
			
		||||
import tachiyomi.domain.track.model.Track as DomainTrack
 | 
			
		||||
 | 
			
		||||
class Suwayomi(id: Long) : Tracker(id, "Suwayomi"), EnhancedTracker {
 | 
			
		||||
class Suwayomi(id: Long) : BaseTracker(id, "Suwayomi"), EnhancedTracker {
 | 
			
		||||
 | 
			
		||||
    val api by lazy { SuwayomiApi(id) }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user