Migrate more track DB calls to SQLDelight

This commit is contained in:
arkon 2022-06-26 19:46:41 -04:00
parent 4ca0fc7a4d
commit 65264e3ef5
36 changed files with 98 additions and 185 deletions

View File

@ -28,7 +28,7 @@ data class Track(
} }
} }
fun Track.toDbTrack(): DbTrack = DbTrack.create(syncId.toInt()).also { fun Track.toDbTrack(): DbTrack = DbTrack.create(syncId).also {
it.id = id it.id = id
it.manga_id = mangaId it.manga_id = mangaId
it.media_id = remoteId it.media_id = remoteId

View File

@ -87,7 +87,7 @@ abstract class AbstractBackupRestore<T : AbstractBackupManager>(protected val co
*/ */
internal suspend fun updateTracking(manga: Manga, tracks: List<Track>) { internal suspend fun updateTracking(manga: Manga, tracks: List<Track>) {
tracks.forEach { track -> tracks.forEach { track ->
val service = trackManager.getService(track.sync_id) val service = trackManager.getService(track.sync_id.toLong())
if (service != null && service.isLogged) { if (service != null && service.isLogged) {
try { try {
val updatedTrack = service.refresh(track) val updatedTrack = service.refresh(track)

View File

@ -56,7 +56,7 @@ class FullBackupRestoreValidator : AbstractBackupRestoreValidator() {
.map { it.syncId } .map { it.syncId }
.distinct() .distinct()
val missingTrackers = trackers val missingTrackers = trackers
.mapNotNull { trackManager.getService(it) } .mapNotNull { trackManager.getService(it.toLong()) }
.filter { !it.isLogged } .filter { !it.isLogged }
.map { context.getString(it.nameRes()) } .map { context.getString(it.nameRes()) }
.sorted() .sorted()

View File

@ -39,8 +39,8 @@ interface Track : Serializable {
} }
companion object { companion object {
fun create(serviceId: Int): Track = TrackImpl().apply { fun create(serviceId: Long): Track = TrackImpl().apply {
sync_id = serviceId sync_id = serviceId.toInt()
} }
} }
} }

View File

@ -7,8 +7,6 @@ import eu.kanade.tachiyomi.data.database.DbProvider
import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.resolvers.LibraryMangaGetResolver import eu.kanade.tachiyomi.data.database.resolvers.LibraryMangaGetResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaCoverLastModifiedPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaFavoritePutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaFlagsPutResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaFlagsPutResolver
import eu.kanade.tachiyomi.data.database.tables.CategoryTable import eu.kanade.tachiyomi.data.database.tables.CategoryTable
import eu.kanade.tachiyomi.data.database.tables.ChapterTable import eu.kanade.tachiyomi.data.database.tables.ChapterTable
@ -85,16 +83,6 @@ interface MangaQueries : DbProvider {
.withPutResolver(MangaFlagsPutResolver(MangaTable.COL_VIEWER, Manga::viewer_flags)) .withPutResolver(MangaFlagsPutResolver(MangaTable.COL_VIEWER, Manga::viewer_flags))
.prepare() .prepare()
fun updateMangaFavorite(manga: Manga) = db.put()
.`object`(manga)
.withPutResolver(MangaFavoritePutResolver())
.prepare()
fun updateMangaCoverLastModified(manga: Manga) = db.put()
.`object`(manga)
.withPutResolver(MangaCoverLastModifiedPutResolver())
.prepare()
fun getLastReadManga() = db.get() fun getLastReadManga() = db.get()
.listOfObjects(Manga::class.java) .listOfObjects(Manga::class.java)
.withQuery( .withQuery(

View File

@ -1,12 +1,9 @@
package eu.kanade.tachiyomi.data.database.queries package eu.kanade.tachiyomi.data.database.queries
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
import com.pushtorefresh.storio.sqlite.queries.Query import com.pushtorefresh.storio.sqlite.queries.Query
import eu.kanade.tachiyomi.data.database.DbProvider import eu.kanade.tachiyomi.data.database.DbProvider
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.database.tables.TrackTable import eu.kanade.tachiyomi.data.database.tables.TrackTable
import eu.kanade.tachiyomi.data.track.TrackService
interface TrackQueries : DbProvider { interface TrackQueries : DbProvider {
@ -19,28 +16,5 @@ interface TrackQueries : DbProvider {
) )
.prepare() .prepare()
fun getTracks(mangaId: Long?) = db.get()
.listOfObjects(Track::class.java)
.withQuery(
Query.builder()
.table(TrackTable.TABLE)
.where("${TrackTable.COL_MANGA_ID} = ?")
.whereArgs(mangaId)
.build(),
)
.prepare()
fun insertTrack(track: Track) = db.put().`object`(track).prepare() fun insertTrack(track: Track) = db.put().`object`(track).prepare()
fun insertTracks(tracks: List<Track>) = db.put().objects(tracks).prepare()
fun deleteTrackForManga(manga: Manga, sync: TrackService) = db.delete()
.byQuery(
DeleteQuery.builder()
.table(TrackTable.TABLE)
.where("${TrackTable.COL_MANGA_ID} = ? AND ${TrackTable.COL_SYNC_ID} = ?")
.whereArgs(manga.id, sync.id)
.build(),
)
.prepare()
} }

View File

@ -1,32 +0,0 @@
package eu.kanade.tachiyomi.data.database.resolvers
import androidx.core.content.contentValuesOf
import com.pushtorefresh.storio.sqlite.StorIOSQLite
import com.pushtorefresh.storio.sqlite.operations.put.PutResolver
import com.pushtorefresh.storio.sqlite.operations.put.PutResult
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
import eu.kanade.tachiyomi.data.database.inTransactionReturn
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.tables.MangaTable
class MangaCoverLastModifiedPutResolver : PutResolver<Manga>() {
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
val updateQuery = mapToUpdateQuery(manga)
val contentValues = mapToContentValues(manga)
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
}
fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
.table(MangaTable.TABLE)
.where("${MangaTable.COL_ID} = ?")
.whereArgs(manga.id)
.build()
fun mapToContentValues(manga: Manga) =
contentValuesOf(
MangaTable.COL_COVER_LAST_MODIFIED to manga.cover_last_modified,
)
}

View File

@ -1,32 +0,0 @@
package eu.kanade.tachiyomi.data.database.resolvers
import androidx.core.content.contentValuesOf
import com.pushtorefresh.storio.sqlite.StorIOSQLite
import com.pushtorefresh.storio.sqlite.operations.put.PutResolver
import com.pushtorefresh.storio.sqlite.operations.put.PutResult
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
import eu.kanade.tachiyomi.data.database.inTransactionReturn
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.tables.MangaTable
class MangaFavoritePutResolver : PutResolver<Manga>() {
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
val updateQuery = mapToUpdateQuery(manga)
val contentValues = mapToContentValues(manga)
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
}
fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
.table(MangaTable.TABLE)
.where("${MangaTable.COL_ID} = ?")
.whereArgs(manga.id)
.build()
fun mapToContentValues(manga: Manga) =
contentValuesOf(
MangaTable.COL_FAVORITE to manga.favorite,
)
}

View File

@ -12,6 +12,10 @@ import eu.kanade.domain.chapter.model.toDbChapter
import eu.kanade.domain.manga.interactor.GetMangaById import eu.kanade.domain.manga.interactor.GetMangaById
import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.toMangaInfo import eu.kanade.domain.manga.model.toMangaInfo
import eu.kanade.domain.track.interactor.GetTracks
import eu.kanade.domain.track.interactor.InsertTrack
import eu.kanade.domain.track.model.toDbTrack
import eu.kanade.domain.track.model.toDomainTrack
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
@ -87,6 +91,8 @@ class LibraryUpdateService(
private val getMangaById: GetMangaById = Injekt.get(), private val getMangaById: GetMangaById = Injekt.get(),
private val updateManga: UpdateManga = Injekt.get(), private val updateManga: UpdateManga = Injekt.get(),
private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(), private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(),
private val getTracks: GetTracks = Injekt.get(),
private val insertTrack: InsertTrack = Injekt.get(),
) : Service() { ) : Service() {
private lateinit var wakeLock: PowerManager.WakeLock private lateinit var wakeLock: PowerManager.WakeLock
@ -500,18 +506,18 @@ class LibraryUpdateService(
} }
private suspend fun updateTrackings(manga: LibraryManga, loggedServices: List<TrackService>) { private suspend fun updateTrackings(manga: LibraryManga, loggedServices: List<TrackService>) {
db.getTracks(manga.id).executeAsBlocking() getTracks.await(manga.id!!)
.map { track -> .map { track ->
supervisorScope { supervisorScope {
async { async {
val service = trackManager.getService(track.sync_id) val service = trackManager.getService(track.syncId)
if (service != null && service in loggedServices) { if (service != null && service in loggedServices) {
try { try {
val updatedTrack = service.refresh(track) val updatedTrack = service.refresh(track.toDbTrack())
db.insertTrack(updatedTrack).executeAsBlocking() insertTrack.await(updatedTrack.toDomainTrack()!!)
if (service is EnhancedTrackService) { if (service is EnhancedTrackService) {
syncChaptersWithTrackServiceTwoWay(db, db.getChapters(manga).executeAsBlocking(), track, service) syncChaptersWithTrackServiceTwoWay(db, db.getChapters(manga).executeAsBlocking(), track.toDbTrack(), service)
} }
} catch (e: Throwable) { } catch (e: Throwable) {
// Ignore errors and continue // Ignore errors and continue

View File

@ -75,9 +75,9 @@ object PreferenceKeys {
const val autoClearChapterCache = "auto_clear_chapter_cache" const val autoClearChapterCache = "auto_clear_chapter_cache"
fun trackUsername(syncId: Int) = "pref_mangasync_username_$syncId" fun trackUsername(syncId: Long) = "pref_mangasync_username_$syncId"
fun trackPassword(syncId: Int) = "pref_mangasync_password_$syncId" fun trackPassword(syncId: Long) = "pref_mangasync_password_$syncId"
fun trackToken(syncId: Int) = "track_token_$syncId" fun trackToken(syncId: Long) = "track_token_$syncId"
} }

View File

@ -12,13 +12,13 @@ import eu.kanade.tachiyomi.data.track.shikimori.Shikimori
class TrackManager(context: Context) { class TrackManager(context: Context) {
companion object { companion object {
const val MYANIMELIST = 1 const val MYANIMELIST = 1L
const val ANILIST = 2 const val ANILIST = 2L
const val KITSU = 3 const val KITSU = 3L
const val SHIKIMORI = 4 const val SHIKIMORI = 4L
const val BANGUMI = 5 const val BANGUMI = 5L
const val KOMGA = 6 const val KOMGA = 6L
const val MANGA_UPDATES = 7 const val MANGA_UPDATES = 7L
} }
val myAnimeList = MyAnimeList(context, MYANIMELIST) val myAnimeList = MyAnimeList(context, MYANIMELIST)
@ -37,7 +37,7 @@ class TrackManager(context: Context) {
val services = listOf(myAnimeList, aniList, kitsu, shikimori, bangumi, komga, mangaUpdates) val services = listOf(myAnimeList, aniList, kitsu, shikimori, bangumi, komga, mangaUpdates)
fun getService(id: Int) = 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.isLogged }
} }

View File

@ -11,7 +11,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: Int) { abstract class TrackService(val id: Long) {
val preferences: PreferencesHelper by injectLazy() val preferences: PreferencesHelper by injectLazy()
val networkService: NetworkHelper by injectLazy() val networkService: NetworkHelper by injectLazy()

View File

@ -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 Anilist(private val context: Context, id: Int) : TrackService(id) { class Anilist(private val context: Context, id: Long) : TrackService(id) {
companion object { companion object {
const val READING = 1 const val READING = 1

View File

@ -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 Bangumi(private val context: Context, id: Int) : TrackService(id) { class Bangumi(private val context: Context, id: Long) : TrackService(id) {
private val json: Json by injectLazy() private val json: Json by injectLazy()

View File

@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.data.track.job
import android.content.Context import android.content.Context
import androidx.core.content.edit import androidx.core.content.edit
import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.domain.track.model.Track
import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.system.logcat
import logcat.LogPriority import logcat.LogPriority
@ -16,8 +16,8 @@ class DelayedTrackingStore(context: Context) {
fun addItem(track: Track) { fun addItem(track: Track) {
val trackId = track.id.toString() val trackId = track.id.toString()
val (_, lastChapterRead) = preferences.getString(trackId, "0:0.0")!!.split(":") val (_, lastChapterRead) = preferences.getString(trackId, "0:0.0")!!.split(":")
if (track.last_chapter_read > lastChapterRead.toFloat()) { if (track.lastChapterRead > lastChapterRead.toFloat()) {
val value = "${track.manga_id}:${track.last_chapter_read}" val value = "${track.mangaId}:${track.lastChapterRead}"
logcat(LogPriority.DEBUG) { "Queuing track item: $trackId, $value" } logcat(LogPriority.DEBUG) { "Queuing track item: $trackId, $value" }
preferences.edit { preferences.edit {
putString(trackId, value) putString(trackId, value)

View File

@ -9,7 +9,10 @@ import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager import androidx.work.WorkManager
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.domain.manga.interactor.GetMangaById
import eu.kanade.domain.track.interactor.GetTracks
import eu.kanade.domain.track.interactor.InsertTrack
import eu.kanade.domain.track.model.toDbTrack
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -23,26 +26,27 @@ class DelayedTrackingUpdateJob(context: Context, workerParams: WorkerParameters)
CoroutineWorker(context, workerParams) { CoroutineWorker(context, workerParams) {
override suspend fun doWork(): Result { override suspend fun doWork(): Result {
val db = Injekt.get<DatabaseHelper>() val getMangaById = Injekt.get<GetMangaById>()
val getTracks = Injekt.get<GetTracks>()
val insertTrack = Injekt.get<InsertTrack>()
val trackManager = Injekt.get<TrackManager>() val trackManager = Injekt.get<TrackManager>()
val delayedTrackingStore = Injekt.get<DelayedTrackingStore>() val delayedTrackingStore = Injekt.get<DelayedTrackingStore>()
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
val tracks = delayedTrackingStore.getItems().mapNotNull { val tracks = delayedTrackingStore.getItems().mapNotNull {
val manga = db.getManga(it.mangaId).executeAsBlocking() ?: return@withContext val manga = getMangaById.await(it.mangaId) ?: return@withContext
db.getTracks(manga.id).executeAsBlocking() getTracks.await(manga.id)
.find { track -> track.id == it.trackId } .find { track -> track.id == it.trackId }
?.also { track -> ?.copy(lastChapterRead = it.lastChapterRead.toDouble())
track.last_chapter_read = it.lastChapterRead
}
} }
tracks.forEach { track -> tracks.forEach { track ->
try { try {
val service = trackManager.getService(track.sync_id) val service = trackManager.getService(track.syncId)
if (service != null && service.isLogged) { if (service != null && service.isLogged) {
service.update(track, true) service.update(track.toDbTrack(), true)
db.insertTrack(track).executeAsBlocking() insertTrack.await(track)
} }
} catch (e: Exception) { } catch (e: Exception) {
logcat(LogPriority.ERROR, e) logcat(LogPriority.ERROR, e)

View File

@ -13,7 +13,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(private val context: Context, id: Int) : TrackService(id) { class Kitsu(private val context: Context, id: Long) : TrackService(id) {
companion object { companion object {
const val READING = 1 const val READING = 1

View File

@ -16,7 +16,7 @@ import okhttp3.OkHttpClient
import eu.kanade.domain.manga.model.Manga as DomainManga import eu.kanade.domain.manga.model.Manga as DomainManga
import eu.kanade.domain.track.model.Track as DomainTrack import eu.kanade.domain.track.model.Track as DomainTrack
class Komga(private val context: Context, id: Int) : TrackService(id), EnhancedTrackService, NoLoginTrackService { class Komga(private val context: Context, id: Long) : TrackService(id), EnhancedTrackService, NoLoginTrackService {
companion object { companion object {
const val UNREAD = 1 const val UNREAD = 1

View File

@ -10,7 +10,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.TrackSearch import eu.kanade.tachiyomi.data.track.model.TrackSearch
class MangaUpdates(private val context: Context, id: Int) : TrackService(id) { class MangaUpdates(private val context: Context, id: Long) : TrackService(id) {
companion object { companion object {
const val READING_LIST = 0 const val READING_LIST = 0

View File

@ -23,7 +23,7 @@ data class Record(
val latestChapter: Int? = null, val latestChapter: Int? = null,
) )
fun Record.toTrackSearch(id: Int): TrackSearch { fun Record.toTrackSearch(id: Long): TrackSearch {
return TrackSearch.create(id).apply { return TrackSearch.create(id).apply {
media_id = this@toTrackSearch.seriesId ?: 0L media_id = this@toTrackSearch.seriesId ?: 0L
title = this@toTrackSearch.title?.htmlDecode() ?: "" title = this@toTrackSearch.title?.htmlDecode() ?: ""

View File

@ -61,8 +61,8 @@ class TrackSearch : Track {
} }
companion object { companion object {
fun create(serviceId: Int): TrackSearch = TrackSearch().apply { fun create(serviceId: Long): TrackSearch = TrackSearch().apply {
sync_id = serviceId sync_id = serviceId.toInt()
} }
} }
} }

View File

@ -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 MyAnimeList(private val context: Context, id: Int) : TrackService(id) { class MyAnimeList(private val context: Context, id: Long) : TrackService(id) {
companion object { companion object {
const val READING = 1 const val READING = 1

View File

@ -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 Shikimori(private val context: Context, id: Int) : TrackService(id) { class Shikimori(private val context: Context, id: Long) : TrackService(id) {
companion object { companion object {
const val READING = 1 const val READING = 1

View File

@ -1,10 +1,11 @@
package eu.kanade.tachiyomi.ui.browse.migration package eu.kanade.tachiyomi.ui.browse.migration
import eu.kanade.domain.track.interactor.GetTracks
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.util.hasCustomCover import eu.kanade.tachiyomi.util.hasCustomCover
import kotlinx.coroutines.runBlocking
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 uy.kohesive.injekt.injectLazy
@ -17,7 +18,7 @@ object MigrationFlags {
private const val CUSTOM_COVER = 0b1000 private const val CUSTOM_COVER = 0b1000
private val coverCache: CoverCache by injectLazy() private val coverCache: CoverCache by injectLazy()
private val db: DatabaseHelper = Injekt.get() private val getTracks: GetTracks = Injekt.get()
val flags get() = arrayOf(CHAPTERS, CATEGORIES, TRACK, CUSTOM_COVER) val flags get() = arrayOf(CHAPTERS, CATEGORIES, TRACK, CUSTOM_COVER)
@ -48,14 +49,12 @@ object MigrationFlags {
fun titles(manga: Manga?): Array<Int> { fun titles(manga: Manga?): Array<Int> {
val titles = arrayOf(R.string.chapters, R.string.categories).toMutableList() val titles = arrayOf(R.string.chapters, R.string.categories).toMutableList()
if (manga != null) { if (manga != null) {
db.inTransaction { if (runBlocking { getTracks.await(manga.id!!) }.isNotEmpty()) {
if (db.getTracks(manga.id).executeAsBlocking().isNotEmpty()) { titles.add(R.string.track)
titles.add(R.string.track) }
}
if (manga.hasCustomCover(coverCache)) { if (manga.hasCustomCover(coverCache)) {
titles.add(R.string.custom_cover) titles.add(R.string.custom_cover)
}
} }
} }
return titles.toTypedArray() return titles.toTypedArray()

View File

@ -5,6 +5,8 @@ import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.domain.category.interactor.GetCategories import eu.kanade.domain.category.interactor.GetCategories
import eu.kanade.domain.manga.interactor.GetDuplicateLibraryManga import eu.kanade.domain.manga.interactor.GetDuplicateLibraryManga
import eu.kanade.domain.manga.model.toDbManga import eu.kanade.domain.manga.model.toDbManga
import eu.kanade.domain.track.interactor.InsertTrack
import eu.kanade.domain.track.model.toDomainTrack
import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
@ -67,6 +69,7 @@ open class BrowseSourcePresenter(
private val coverCache: CoverCache = Injekt.get(), private val coverCache: CoverCache = Injekt.get(),
private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(), private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(),
private val getCategories: GetCategories = Injekt.get(), private val getCategories: GetCategories = Injekt.get(),
private val insertTrack: InsertTrack = Injekt.get(),
) : BasePresenter<BrowseSourceController>() { ) : BasePresenter<BrowseSourceController>() {
/** /**
@ -286,7 +289,7 @@ open class BrowseSourcePresenter(
service.match(manga)?.let { track -> service.match(manga)?.let { track ->
track.manga_id = manga.id!! track.manga_id = manga.id!!
(service as TrackService).bind(track) (service as TrackService).bind(track)
db.insertTrack(track).executeAsBlocking() insertTrack.await(track.toDomainTrack()!!)
syncChaptersWithTrackServiceTwoWay(db, db.getChapters(manga).executeAsBlocking(), track, service as TrackService) syncChaptersWithTrackServiceTwoWay(db, db.getChapters(manga).executeAsBlocking(), track, service as TrackService)
} }

View File

@ -123,7 +123,7 @@ class LibraryPresenter(
val filterCompleted = preferences.filterCompleted().get() val filterCompleted = preferences.filterCompleted().get()
val loggedInServices = trackManager.services.filter { trackService -> trackService.isLogged } val loggedInServices = trackManager.services.filter { trackService -> trackService.isLogged }
.associate { trackService -> .associate { trackService ->
Pair(trackService.id, preferences.filterTracking(trackService.id).get()) Pair(trackService.id, preferences.filterTracking(trackService.id.toInt()).get())
} }
val isNotAnyLoggedIn = !loggedInServices.values.any() val isNotAnyLoggedIn = !loggedInServices.values.any()
@ -173,8 +173,8 @@ class LibraryPresenter(
if (!containsExclude.any() && !containsInclude.any()) return@tracking true if (!containsExclude.any() && !containsInclude.any()) return@tracking true
val exclude = trackedManga?.filterKeys { containsExclude.containsKey(it) }?.values ?: emptyList() val exclude = trackedManga?.filterKeys { containsExclude.containsKey(it.toLong()) }?.values ?: emptyList()
val include = trackedManga?.filterKeys { containsInclude.containsKey(it) }?.values ?: emptyList() val include = trackedManga?.filterKeys { containsInclude.containsKey(it.toLong()) }?.values ?: emptyList()
if (containsInclude.any() && containsExclude.any()) { if (containsInclude.any() && containsExclude.any()) {
return@tracking if (exclude.isNotEmpty()) !exclude.any() else include.any() return@tracking if (exclude.isNotEmpty()) !exclude.any() else include.any()
@ -411,7 +411,7 @@ class LibraryPresenter(
.mapValues { tracksForMangaId -> .mapValues { tracksForMangaId ->
// Check if any of the trackers is logged in for the current manga id // Check if any of the trackers is logged in for the current manga id
tracksForMangaId.value.associate { tracksForMangaId.value.associate {
Pair(it.sync_id, trackManager.getService(it.sync_id)?.isLogged ?: false) Pair(it.sync_id, trackManager.getService(it.sync_id.toLong())?.isLogged ?: false)
} }
} }
}.observeOn(Schedulers.io()) }.observeOn(Schedulers.io())

View File

@ -91,7 +91,7 @@ class LibrarySettingsSheet(
private val unread = Item.TriStateGroup(R.string.action_filter_unread, this) private val unread = Item.TriStateGroup(R.string.action_filter_unread, this)
private val started = Item.TriStateGroup(R.string.action_filter_started, this) private val started = Item.TriStateGroup(R.string.action_filter_started, this)
private val completed = Item.TriStateGroup(R.string.completed, this) private val completed = Item.TriStateGroup(R.string.completed, this)
private val trackFilters: Map<Int, Item.TriStateGroup> private val trackFilters: Map<Long, Item.TriStateGroup>
override val header = null override val header = null
override val items: List<Item> override val items: List<Item>
@ -127,7 +127,7 @@ class LibrarySettingsSheet(
completed.state = preferences.filterCompleted().get() completed.state = preferences.filterCompleted().get()
trackFilters.forEach { trackFilter -> trackFilters.forEach { trackFilter ->
trackFilter.value.state = preferences.filterTracking(trackFilter.key).get() trackFilter.value.state = preferences.filterTracking(trackFilter.key.toInt()).get()
} }
} }
@ -148,7 +148,7 @@ class LibrarySettingsSheet(
else -> { else -> {
trackFilters.forEach { trackFilter -> trackFilters.forEach { trackFilter ->
if (trackFilter.value == item) { if (trackFilter.value == item) {
preferences.filterTracking(trackFilter.key).set(newState) preferences.filterTracking(trackFilter.key.toInt()).set(newState)
} }
} }
} }

View File

@ -692,7 +692,7 @@ class MangaPresenter(
.map { tracks -> .map { tracks ->
val dbTracks = tracks.map { it.toDbTrack() } val dbTracks = tracks.map { it.toDbTrack() }
loggedServices.map { service -> loggedServices.map { service ->
TrackItem(dbTracks.find { it.sync_id == service.id }, service) TrackItem(dbTracks.find { it.sync_id.toLong() == service.id }, service)
} }
} }
.collectLatest { trackItems -> .collectLatest { trackItems ->

View File

@ -32,7 +32,7 @@ class SetTrackChaptersDialog<T> : DialogController
@Suppress("unused") @Suppress("unused")
constructor(bundle: Bundle) : super(bundle) { constructor(bundle: Bundle) : super(bundle) {
val track = bundle.getSerializable(KEY_ITEM_TRACK) as Track val track = bundle.getSerializable(KEY_ITEM_TRACK) as Track
val service = Injekt.get<TrackManager>().getService(track.sync_id)!! val service = Injekt.get<TrackManager>().getService(track.sync_id.toLong())!!
item = TrackItem(track, service) item = TrackItem(track, service)
} }

View File

@ -32,7 +32,7 @@ class SetTrackScoreDialog<T> : DialogController
@Suppress("unused") @Suppress("unused")
constructor(bundle: Bundle) : super(bundle) { constructor(bundle: Bundle) : super(bundle) {
val track = bundle.getSerializable(KEY_ITEM_TRACK) as Track val track = bundle.getSerializable(KEY_ITEM_TRACK) as Track
val service = Injekt.get<TrackManager>().getService(track.sync_id)!! val service = Injekt.get<TrackManager>().getService(track.sync_id.toLong())!!
item = TrackItem(track, service) item = TrackItem(track, service)
} }

View File

@ -30,7 +30,7 @@ class SetTrackStatusDialog<T> : DialogController
@Suppress("unused") @Suppress("unused")
constructor(bundle: Bundle) : super(bundle) { constructor(bundle: Bundle) : super(bundle) {
val track = bundle.getSerializable(KEY_ITEM_TRACK) as Track val track = bundle.getSerializable(KEY_ITEM_TRACK) as Track
val service = Injekt.get<TrackManager>().getService(track.sync_id)!! val service = Injekt.get<TrackManager>().getService(track.sync_id.toLong())!!
item = TrackItem(track, service) item = TrackItem(track, service)
} }

View File

@ -54,7 +54,7 @@ class TrackSearchDialog : DialogController {
@Suppress("unused") @Suppress("unused")
constructor(bundle: Bundle) : super(bundle) { constructor(bundle: Bundle) : super(bundle) {
service = Injekt.get<TrackManager>().getService(bundle.getInt(KEY_SERVICE))!! service = Injekt.get<TrackManager>().getService(bundle.getLong(KEY_SERVICE))!!
currentTrackUrl = bundle.getString(KEY_CURRENT_URL) currentTrackUrl = bundle.getString(KEY_CURRENT_URL)
} }

View File

@ -10,7 +10,9 @@ import eu.kanade.domain.chapter.model.ChapterUpdate
import eu.kanade.domain.history.interactor.UpsertHistory import eu.kanade.domain.history.interactor.UpsertHistory
import eu.kanade.domain.history.model.HistoryUpdate import eu.kanade.domain.history.model.HistoryUpdate
import eu.kanade.domain.manga.model.isLocal import eu.kanade.domain.manga.model.isLocal
import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.domain.track.interactor.GetTracks
import eu.kanade.domain.track.interactor.InsertTrack
import eu.kanade.domain.track.model.toDbTrack
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.toDomainManga import eu.kanade.tachiyomi.data.database.models.toDomainManga
@ -45,6 +47,7 @@ import eu.kanade.tachiyomi.util.system.isOnline
import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.runBlocking
import logcat.LogPriority import logcat.LogPriority
import rx.Observable import rx.Observable
import rx.Subscription import rx.Subscription
@ -63,9 +66,10 @@ class ReaderPresenter(
private val db: DatabaseHelper = Injekt.get(), private val db: DatabaseHelper = Injekt.get(),
private val sourceManager: SourceManager = Injekt.get(), private val sourceManager: SourceManager = Injekt.get(),
private val downloadManager: DownloadManager = Injekt.get(), private val downloadManager: DownloadManager = Injekt.get(),
private val coverCache: CoverCache = Injekt.get(),
private val preferences: PreferencesHelper = Injekt.get(), private val preferences: PreferencesHelper = Injekt.get(),
private val delayedTrackingStore: DelayedTrackingStore = Injekt.get(), private val delayedTrackingStore: DelayedTrackingStore = Injekt.get(),
private val getTracks: GetTracks = Injekt.get(),
private val insertTrack: InsertTrack = Injekt.get(),
private val upsertHistory: UpsertHistory = Injekt.get(), private val upsertHistory: UpsertHistory = Injekt.get(),
private val updateChapter: UpdateChapter = Injekt.get(), private val updateChapter: UpdateChapter = Injekt.get(),
) : BasePresenter<ReaderActivity>() { ) : BasePresenter<ReaderActivity>() {
@ -152,9 +156,8 @@ class ReaderPresenter(
private var hasTrackers: Boolean = false private var hasTrackers: Boolean = false
private val checkTrackers: (Manga) -> Unit = { manga -> private val checkTrackers: (Manga) -> Unit = { manga ->
val tracks = db.getTracks(manga.id).executeAsBlocking() val tracks = runBlocking { getTracks.await(manga.id!!) }
hasTrackers = tracks.isNotEmpty()
hasTrackers = tracks.size > 0
} }
private val incognitoMode = preferences.incognitoMode().get() private val incognitoMode = preferences.incognitoMode().get()
@ -740,27 +743,27 @@ class ReaderPresenter(
if (!preferences.autoUpdateTrack()) return if (!preferences.autoUpdateTrack()) return
val manga = manga ?: return val manga = manga ?: return
val chapterRead = readerChapter.chapter.chapter_number val chapterRead = readerChapter.chapter.chapter_number.toDouble()
val trackManager = Injekt.get<TrackManager>() val trackManager = Injekt.get<TrackManager>()
val context = Injekt.get<Application>() val context = Injekt.get<Application>()
launchIO { launchIO {
db.getTracks(manga.id).executeAsBlocking() getTracks.await(manga.id!!)
.mapNotNull { track -> .mapNotNull { track ->
val service = trackManager.getService(track.sync_id) val service = trackManager.getService(track.syncId)
if (service != null && service.isLogged && chapterRead > track.last_chapter_read) { if (service != null && service.isLogged && chapterRead > track.lastChapterRead) {
track.last_chapter_read = 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
// for a while. The view can still be garbage collected. // for a while. The view can still be garbage collected.
async { async {
runCatching { runCatching {
if (context.isOnline()) { if (context.isOnline()) {
service.update(track, true) service.update(updatedTrack.toDbTrack(), true)
db.insertTrack(track).executeAsBlocking() insertTrack.await(updatedTrack)
} else { } else {
delayedTrackingStore.addItem(track) delayedTrackingStore.addItem(updatedTrack)
DelayedTrackingUpdateJob.setupTask(context) DelayedTrackingUpdateJob.setupTask(context)
} }
} }

View File

@ -146,7 +146,7 @@ class SettingsTrackingController :
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
private fun updatePreference(id: Int) { private fun updatePreference(id: Long) {
val pref = findPreference(Keys.trackUsername(id)) as? TrackerPreference val pref = findPreference(Keys.trackUsername(id)) as? TrackerPreference
pref?.notifyChanged() pref?.notifyChanged()
} }

View File

@ -19,7 +19,7 @@ class TrackLoginDialog(
bundle: Bundle? = null, bundle: Bundle? = null,
) : LoginDialogPreference(usernameLabelRes, bundle) { ) : LoginDialogPreference(usernameLabelRes, bundle) {
private val service = Injekt.get<TrackManager>().getService(args.getInt("serviceId"))!! private val service = Injekt.get<TrackManager>().getService(args.getLong("serviceId"))!!
constructor(service: TrackService) : this(service, null) constructor(service: TrackService) : this(service, null)

View File

@ -14,7 +14,7 @@ import uy.kohesive.injekt.api.get
class TrackLogoutDialog(bundle: Bundle? = null) : DialogController(bundle) { class TrackLogoutDialog(bundle: Bundle? = null) : DialogController(bundle) {
private val service = Injekt.get<TrackManager>().getService(args.getInt("serviceId"))!! private val service = Injekt.get<TrackManager>().getService(args.getLong("serviceId"))!!
constructor(service: TrackService) : this(bundleOf("serviceId" to service.id)) constructor(service: TrackService) : this(bundleOf("serviceId" to service.id))