refactor(db): Migrate GetTrack to SQLDelight

This commit is contained in:
Ahmad Ansori Palembani 2024-11-28 20:53:26 +07:00
parent e9a68f661f
commit c183802096
Signed by: null2264
GPG key ID: BA64F8B60AF3EFB6
26 changed files with 154 additions and 48 deletions

View file

@ -5,19 +5,23 @@ import eu.kanade.tachiyomi.data.backup.models.BackupChapter
import eu.kanade.tachiyomi.data.backup.models.BackupHistory import eu.kanade.tachiyomi.data.backup.models.BackupHistory
import eu.kanade.tachiyomi.data.backup.models.BackupManga import eu.kanade.tachiyomi.data.backup.models.BackupManga
import eu.kanade.tachiyomi.data.backup.models.BackupTracking import eu.kanade.tachiyomi.data.backup.models.BackupTracking
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.library.CustomMangaManager import eu.kanade.tachiyomi.data.library.CustomMangaManager
import eu.kanade.tachiyomi.domain.manga.models.Manga import eu.kanade.tachiyomi.domain.manga.models.Manga
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import yokai.data.DatabaseHandler import yokai.data.DatabaseHandler
import yokai.domain.category.interactor.GetCategories
import yokai.domain.chapter.interactor.GetChapter import yokai.domain.chapter.interactor.GetChapter
import yokai.domain.history.interactor.GetHistory
import yokai.domain.track.interactor.GetTrack
class MangaBackupCreator( class MangaBackupCreator(
private val db: DatabaseHelper = Injekt.get(),
private val customMangaManager: CustomMangaManager = Injekt.get(), private val customMangaManager: CustomMangaManager = Injekt.get(),
private val handler: DatabaseHandler = Injekt.get(), private val handler: DatabaseHandler = Injekt.get(),
private val getCategories: GetCategories = Injekt.get(),
private val getChapter: GetChapter = Injekt.get(), private val getChapter: GetChapter = Injekt.get(),
private val getHistory: GetHistory = Injekt.get(),
private val getTrack: GetTrack = Injekt.get(),
) { ) {
suspend operator fun invoke(mangas: List<Manga>, options: BackupOptions): List<BackupManga> { suspend operator fun invoke(mangas: List<Manga>, options: BackupOptions): List<BackupManga> {
return mangas.map { return mangas.map {
@ -55,7 +59,7 @@ class MangaBackupCreator(
// Check if user wants category information in backup // Check if user wants category information in backup
if (options.categories) { if (options.categories) {
// Backup categories for this manga // Backup categories for this manga
val categoriesForManga = db.getCategoriesForManga(manga).executeAsBlocking() val categoriesForManga = getCategories.awaitByMangaId(manga.id!!)
if (categoriesForManga.isNotEmpty()) { if (categoriesForManga.isNotEmpty()) {
mangaObject.categories = categoriesForManga.mapNotNull { it.order } mangaObject.categories = categoriesForManga.mapNotNull { it.order }
} }
@ -63,7 +67,7 @@ class MangaBackupCreator(
// Check if user wants track information in backup // Check if user wants track information in backup
if (options.tracking) { if (options.tracking) {
val tracks = db.getTracks(manga).executeAsBlocking() val tracks = getTrack.awaitAllByMangaId(manga.id!!)
if (tracks.isNotEmpty()) { if (tracks.isNotEmpty()) {
mangaObject.tracking = tracks.map { BackupTracking.copyFrom(it) } mangaObject.tracking = tracks.map { BackupTracking.copyFrom(it) }
} }
@ -71,7 +75,7 @@ class MangaBackupCreator(
// Check if user wants history information in backup // Check if user wants history information in backup
if (options.history) { if (options.history) {
val historyForManga = db.getHistoryByMangaId(manga.id!!).executeAsBlocking() val historyForManga = getHistory.awaitAllByMangaId(manga.id!!)
if (historyForManga.isNotEmpty()) { if (historyForManga.isNotEmpty()) {
val history = historyForManga.mapNotNull { history -> val history = historyForManga.mapNotNull { history ->
val url = getChapter.awaitById(history.chapter_id)?.url val url = getChapter.awaitById(history.chapter_id)?.url

View file

@ -28,6 +28,7 @@ import yokai.domain.library.custom.model.CustomMangaInfo
import yokai.domain.manga.interactor.GetManga import yokai.domain.manga.interactor.GetManga
import yokai.domain.manga.interactor.InsertManga import yokai.domain.manga.interactor.InsertManga
import yokai.domain.manga.interactor.UpdateManga import yokai.domain.manga.interactor.UpdateManga
import yokai.domain.track.interactor.GetTrack
class MangaBackupRestorer( class MangaBackupRestorer(
private val db: DatabaseHelper = Injekt.get(), private val db: DatabaseHelper = Injekt.get(),
@ -41,6 +42,7 @@ class MangaBackupRestorer(
private val updateManga: UpdateManga = Injekt.get(), private val updateManga: UpdateManga = Injekt.get(),
private val getHistory: GetHistory = Injekt.get(), private val getHistory: GetHistory = Injekt.get(),
private val upsertHistory: UpsertHistory = Injekt.get(), private val upsertHistory: UpsertHistory = Injekt.get(),
private val getTrack: GetTrack = Injekt.get(),
) { ) {
suspend fun restoreManga( suspend fun restoreManga(
backupManga: BackupManga, backupManga: BackupManga,
@ -239,7 +241,7 @@ class MangaBackupRestorer(
tracks.map { it.manga_id = manga.id!! } tracks.map { it.manga_id = manga.id!! }
// Get tracks from database // Get tracks from database
val dbTracks = db.getTracks(manga).executeAsBlocking() val dbTracks = getTrack.awaitAllByMangaId(manga.id!!)
val trackToUpdate = mutableListOf<Track>() val trackToUpdate = mutableListOf<Track>()
tracks.forEach { track -> tracks.forEach { track ->

View file

@ -42,5 +42,35 @@ interface Track : Serializable {
fun create(serviceId: Long): Track = TrackImpl().apply { fun create(serviceId: Long): Track = TrackImpl().apply {
sync_id = serviceId sync_id = serviceId
} }
fun mapper(
id: Long,
mangaId: Long,
syncId: Long,
remoteId: Long,
libraryId: Long?,
title: String,
lastChapterRead: Double,
totalChapters: Long,
status: Long,
score: Double,
remoteUrl: String,
startDate: Long,
finishDate: Long,
) = TrackImpl().apply {
this.id = id
this.manga_id = mangaId
this.sync_id = syncId
this.media_id = remoteId
this.library_id = libraryId
this.title = title
this.last_chapter_read = lastChapterRead.toFloat()
this.total_chapters = totalChapters
this.score = score.toFloat()
this.status = status.toInt()
this.started_reading_date = startDate
this.finished_reading_date = finishDate
this.tracking_url = remoteUrl
}
} }
} }

View file

@ -10,15 +10,14 @@ import eu.kanade.tachiyomi.domain.manga.models.Manga
interface TrackQueries : DbProvider { interface TrackQueries : DbProvider {
fun getTracks(manga: Manga) = getTracks(manga.id) // FIXME: Migrate to SQLDelight, on halt: in StorIO transaction
fun getTracks(manga: Manga) = db.get()
fun getTracks(mangaId: Long?) = db.get()
.listOfObjects(Track::class.java) .listOfObjects(Track::class.java)
.withQuery( .withQuery(
Query.builder() Query.builder()
.table(TrackTable.TABLE) .table(TrackTable.TABLE)
.where("${TrackTable.COL_MANGA_ID} = ?") .where("${TrackTable.COL_MANGA_ID} = ?")
.whereArgs(mangaId) .whereArgs(manga.id)
.build(), .build(),
) )
.prepare() .prepare()

View file

@ -85,6 +85,7 @@ import yokai.domain.chapter.interactor.GetChapter
import yokai.domain.manga.interactor.GetLibraryManga import yokai.domain.manga.interactor.GetLibraryManga
import yokai.domain.manga.interactor.UpdateManga import yokai.domain.manga.interactor.UpdateManga
import yokai.domain.manga.models.cover import yokai.domain.manga.models.cover
import yokai.domain.track.interactor.GetTrack
import yokai.i18n.MR import yokai.i18n.MR
import yokai.util.lang.getString import yokai.util.lang.getString
@ -103,6 +104,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
private val mangaShortcutManager: MangaShortcutManager = Injekt.get() private val mangaShortcutManager: MangaShortcutManager = Injekt.get()
private val getLibraryManga: GetLibraryManga = Injekt.get() private val getLibraryManga: GetLibraryManga = Injekt.get()
private val updateManga: UpdateManga = Injekt.get() private val updateManga: UpdateManga = Injekt.get()
private val getTrack: GetTrack = Injekt.get()
private var extraDeferredJobs = mutableListOf<Deferred<Any>>() private var extraDeferredJobs = mutableListOf<Deferred<Any>>()
@ -302,7 +304,6 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
* Method that updates the metadata of the connected tracking services. It's called in a * Method that updates the metadata of the connected tracking services. It's called in a
* background thread, so it's safe to do heavy operations or network calls here. * background thread, so it's safe to do heavy operations or network calls here.
*/ */
private suspend fun updateTrackings(mangaToUpdate: List<LibraryManga>) { private suspend fun updateTrackings(mangaToUpdate: List<LibraryManga>) {
// Initialize the variables holding the progress of the updates. // Initialize the variables holding the progress of the updates.
var count = 0 var count = 0
@ -312,7 +313,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
mangaToUpdate.forEach { manga -> mangaToUpdate.forEach { manga ->
notifier.showProgressNotification(manga, count++, mangaToUpdate.size) notifier.showProgressNotification(manga, count++, mangaToUpdate.size)
val tracks = db.getTracks(manga).executeAsBlocking() val tracks = getTrack.awaitAllByMangaId(manga.id!!)
tracks.forEach { track -> tracks.forEach { track ->
val service = trackManager.getService(track.sync_id) val service = trackManager.getService(track.sync_id)

View file

@ -18,10 +18,16 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
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 yokai.domain.manga.interactor.GetManga
import yokai.domain.track.interactor.GetTrack
class DelayedTrackingUpdateJob(context: Context, workerParams: WorkerParameters) : class DelayedTrackingUpdateJob(context: Context, workerParams: WorkerParameters) :
CoroutineWorker(context, workerParams) { CoroutineWorker(context, workerParams) {
private val getManga: GetManga by injectLazy()
private val getTrack: GetTrack by injectLazy()
override suspend fun doWork(): Result { override suspend fun doWork(): Result {
val preferences = Injekt.get<PreferencesHelper>() val preferences = Injekt.get<PreferencesHelper>()
val db = Injekt.get<DatabaseHelper>() val db = Injekt.get<DatabaseHelper>()
@ -40,8 +46,8 @@ class DelayedTrackingUpdateJob(context: Context, workerParams: WorkerParameters)
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
trackings.forEach { trackings.forEach {
val mangaId = it.key val mangaId = it.key
val manga = db.getManga(mangaId).executeAsBlocking() ?: return@withContext val manga = getManga.awaitById(mangaId) ?: return@withContext
val trackList = db.getTracks(manga).executeAsBlocking() val trackList = getTrack.awaitAllByMangaId(manga.id)
it.value.map { tC -> it.value.map { tC ->
val trackChapter = tC.second val trackChapter = tC.second
val service = trackManager.getService(trackChapter.first) val service = trackManager.getService(trackChapter.first)

View file

@ -73,6 +73,7 @@ import yokai.domain.manga.interactor.GetLibraryManga
import yokai.domain.manga.interactor.GetManga import yokai.domain.manga.interactor.GetManga
import yokai.domain.manga.interactor.UpdateManga import yokai.domain.manga.interactor.UpdateManga
import yokai.domain.manga.models.MangaUpdate import yokai.domain.manga.models.MangaUpdate
import yokai.domain.track.interactor.GetTrack
import yokai.i18n.MR import yokai.i18n.MR
import yokai.util.isLewd import yokai.util.isLewd
import yokai.util.lang.getString import yokai.util.lang.getString
@ -94,6 +95,7 @@ class LibraryPresenter(
private val getChapter: GetChapter by injectLazy() private val getChapter: GetChapter by injectLazy()
private val updateChapter: UpdateChapter by injectLazy() private val updateChapter: UpdateChapter by injectLazy()
private val updateManga: UpdateManga by injectLazy() private val updateManga: UpdateManga by injectLazy()
private val getTrack: GetTrack by injectLazy()
private val context = preferences.context private val context = preferences.context
private val viewContext private val viewContext
@ -423,7 +425,7 @@ class LibraryPresenter(
return filteredItems return filteredItems
} }
private fun matchesFilters( private suspend fun matchesFilters(
item: LibraryItem, item: LibraryItem,
filterPrefs: ItemPreferences, filterPrefs: ItemPreferences,
filterTrackers: String, filterTrackers: String,
@ -475,7 +477,7 @@ class LibraryPresenter(
return true return true
} }
private fun matchesCustomFilters( private suspend fun matchesCustomFilters(
item: LibraryItem, item: LibraryItem,
customFilters: FilteredLibraryController, customFilters: FilteredLibraryController,
filterTrackers: String, filterTrackers: String,
@ -498,7 +500,7 @@ class LibraryPresenter(
} }
val trackingScore = customFilters.filterTrackingScore val trackingScore = customFilters.filterTrackingScore
if (trackingScore > 0 || trackingScore == -1) { if (trackingScore > 0 || trackingScore == -1) {
val tracks = db.getTracks(item.manga).executeAsBlocking() val tracks = getTrack.awaitAllByMangaId(item.manga.id!!)
val hasTrack = loggedServices.any { service -> val hasTrack = loggedServices.any { service ->
tracks.any { it.sync_id == service.id } tracks.any { it.sync_id == service.id }
@ -556,14 +558,14 @@ class LibraryPresenter(
return service?.get10PointScore(this.score) return service?.get10PointScore(this.score)
} }
private fun matchesFilterTracking( private suspend fun matchesFilterTracking(
item: LibraryItem, item: LibraryItem,
filterTracked: Int, filterTracked: Int,
filterTrackers: String, filterTrackers: String,
): Boolean { ): Boolean {
// Filter for tracked (or per tracked service) // Filter for tracked (or per tracked service)
if (filterTracked != STATE_IGNORE) { if (filterTracked != STATE_IGNORE) {
val tracks = db.getTracks(item.manga).executeAsBlocking() val tracks = getTrack.awaitAllByMangaId(item.manga.id!!)
val hasTrack = loggedServices.any { service -> val hasTrack = loggedServices.any { service ->
tracks.any { it.sync_id == service.id } tracks.any { it.sync_id == service.id }
@ -992,7 +994,7 @@ class LibraryPresenter(
) )
} }
private fun getDynamicLibraryItems( private suspend fun getDynamicLibraryItems(
libraryManga: List<LibraryManga>, libraryManga: List<LibraryManga>,
sortingMode: Int, sortingMode: Int,
isAscending: Boolean, isAscending: Boolean,
@ -1031,7 +1033,7 @@ class LibraryPresenter(
} }
} }
BY_TRACK_STATUS -> { BY_TRACK_STATUS -> {
val tracks = db.getTracks(manga).executeAsBlocking() val tracks = getTrack.awaitAllByMangaId(manga.id!!)
val track = tracks.find { track -> val track = tracks.find { track ->
loggedServices.any { it.id == track?.sync_id } loggedServices.any { it.id == track?.sync_id }
} }

View file

@ -94,6 +94,7 @@ import yokai.domain.manga.interactor.UpdateManga
import yokai.domain.manga.models.MangaUpdate import yokai.domain.manga.models.MangaUpdate
import yokai.domain.manga.models.cover import yokai.domain.manga.models.cover
import yokai.domain.storage.StorageManager import yokai.domain.storage.StorageManager
import yokai.domain.track.interactor.GetTrack
import yokai.i18n.MR import yokai.i18n.MR
import yokai.util.lang.getString import yokai.util.lang.getString
@ -112,6 +113,7 @@ class MangaDetailsPresenter(
private val getManga: GetManga by injectLazy() private val getManga: GetManga by injectLazy()
private val updateChapter: UpdateChapter by injectLazy() private val updateChapter: UpdateChapter by injectLazy()
private val updateManga: UpdateManga by injectLazy() private val updateManga: UpdateManga by injectLazy()
private val getTrack: GetTrack by injectLazy()
private val networkPreferences: NetworkPreferences by injectLazy() private val networkPreferences: NetworkPreferences by injectLazy()
@ -176,7 +178,9 @@ class MangaDetailsPresenter(
downloadManager.addListener(this) downloadManager.addListener(this)
tracks = db.getTracks(manga).executeAsBlocking() runBlocking {
tracks = getTrack.awaitAllByMangaId(manga.id!!)
}
} }
/** /**
@ -1008,7 +1012,7 @@ class MangaDetailsPresenter(
} }
suspend fun fetchTracks() { suspend fun fetchTracks() {
tracks = withContext(Dispatchers.IO) { db.getTracks(manga).executeAsBlocking() } tracks = withContext(Dispatchers.IO) { getTrack.awaitAllByMangaId(manga.id!!) }
setTrackItems() setTrackItems()
withContext(Dispatchers.Main) { view?.refreshTracking(trackList) } withContext(Dispatchers.Main) { view?.refreshTracking(trackList) }
} }

View file

@ -7,7 +7,9 @@ import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.library.CustomMangaManager import eu.kanade.tachiyomi.data.library.CustomMangaManager
import eu.kanade.tachiyomi.domain.manga.models.Manga import eu.kanade.tachiyomi.domain.manga.models.Manga
import eu.kanade.tachiyomi.util.system.toInt import eu.kanade.tachiyomi.util.system.toInt
import kotlinx.coroutines.runBlocking
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import yokai.domain.track.interactor.GetTrack
import yokai.i18n.MR import yokai.i18n.MR
import yokai.util.lang.getString import yokai.util.lang.getString
@ -21,6 +23,7 @@ object MigrationFlags {
private val coverCache: CoverCache by injectLazy() private val coverCache: CoverCache by injectLazy()
private val db: DatabaseHelper by injectLazy() private val db: DatabaseHelper by injectLazy()
private val customMangaManager: CustomMangaManager by injectLazy() private val customMangaManager: CustomMangaManager by injectLazy()
private val getTrack: GetTrack by injectLazy()
val titles get() = arrayOf(MR.strings.chapters, MR.strings.categories, MR.strings.tracking, MR.strings.custom_manga_info) val titles get() = arrayOf(MR.strings.chapters, MR.strings.categories, MR.strings.tracking, MR.strings.custom_manga_info)
val flags get() = arrayOf(CHAPTERS, CATEGORIES, TRACK, CUSTOM_MANGA_INFO) val flags get() = arrayOf(CHAPTERS, CATEGORIES, TRACK, CUSTOM_MANGA_INFO)
@ -61,7 +64,7 @@ object MigrationFlags {
fun flags(manga: Manga?): Array<Int> { fun flags(manga: Manga?): Array<Int> {
val flags = arrayOf(CHAPTERS, CATEGORIES).toMutableList() val flags = arrayOf(CHAPTERS, CATEGORIES).toMutableList()
if (manga != null) { if (manga != null) {
if (db.getTracks(manga).executeAsBlocking().isNotEmpty()) { if (runBlocking { getTrack.awaitAllByMangaId(manga.id) }.isNotEmpty()) {
flags.add(TRACK) flags.add(TRACK)
} }

View file

@ -14,12 +14,14 @@ import eu.kanade.tachiyomi.domain.manga.models.Manga
import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.ui.base.presenter.BaseCoroutinePresenter
import eu.kanade.tachiyomi.ui.more.stats.StatsHelper.getReadDuration import eu.kanade.tachiyomi.ui.more.stats.StatsHelper.getReadDuration
import kotlinx.coroutines.runBlocking 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
import yokai.domain.manga.interactor.GetLibraryManga import yokai.domain.manga.interactor.GetLibraryManga
import yokai.domain.track.interactor.GetTrack
import yokai.i18n.MR import yokai.i18n.MR
import yokai.util.lang.getString import yokai.util.lang.getString
@ -32,8 +34,9 @@ class StatsPresenter(
private val trackManager: TrackManager = Injekt.get(), private val trackManager: TrackManager = Injekt.get(),
private val downloadManager: DownloadManager = Injekt.get(), private val downloadManager: DownloadManager = Injekt.get(),
private val sourceManager: SourceManager = Injekt.get(), private val sourceManager: SourceManager = Injekt.get(),
) { ): BaseCoroutinePresenter<StatsController>() {
private val getLibraryManga: GetLibraryManga by injectLazy() private val getLibraryManga: GetLibraryManga by injectLazy()
private val getTrack: GetTrack by injectLazy()
private val libraryMangas = getLibrary() private val libraryMangas = getLibrary()
val mangaDistinct = libraryMangas.distinct() val mangaDistinct = libraryMangas.distinct()
@ -43,7 +46,7 @@ class StatsPresenter(
} }
fun getTracks(manga: Manga): MutableList<Track> { fun getTracks(manga: Manga): MutableList<Track> {
return db.getTracks(manga).executeAsBlocking() return runBlocking { getTrack.awaitAllByMangaId(manga.id) }.toMutableList()
} }
fun getLoggedTrackers(): List<TrackService> { fun getLoggedTrackers(): List<TrackService> {

View file

@ -39,6 +39,7 @@ import yokai.util.lang.getString
import java.util.* import java.util.*
import java.util.concurrent.* import java.util.concurrent.*
import kotlin.math.roundToInt import kotlin.math.roundToInt
import yokai.domain.track.interactor.GetTrack
class StatsDetailsPresenter( class StatsDetailsPresenter(
private val db: DatabaseHelper = Injekt.get(), private val db: DatabaseHelper = Injekt.get(),
@ -47,6 +48,7 @@ class StatsDetailsPresenter(
private val sourceManager: SourceManager = Injekt.get(), private val sourceManager: SourceManager = Injekt.get(),
) : BaseCoroutinePresenter<StatsDetailsController>() { ) : BaseCoroutinePresenter<StatsDetailsController>() {
private val getLibraryManga: GetLibraryManga by injectLazy() private val getLibraryManga: GetLibraryManga by injectLazy()
private val getTrack: GetTrack by injectLazy()
private val context private val context
get() = view?.view?.context ?: prefs.context get() = view?.view?.context ?: prefs.context
@ -557,7 +559,7 @@ class StatsDetailsPresenter(
} }
fun getTracks(manga: Manga): MutableList<Track> { fun getTracks(manga: Manga): MutableList<Track> {
return db.getTracks(manga).executeAsBlocking() return runBlocking { getTrack.awaitAllByMangaId(manga.id) }.toMutableList()
} }
fun getLibrary(): MutableList<LibraryManga> { fun getLibrary(): MutableList<LibraryManga> {

View file

@ -88,6 +88,7 @@ import yokai.domain.manga.interactor.InsertManga
import yokai.domain.manga.interactor.UpdateManga import yokai.domain.manga.interactor.UpdateManga
import yokai.domain.manga.models.MangaUpdate import yokai.domain.manga.models.MangaUpdate
import yokai.domain.storage.StorageManager import yokai.domain.storage.StorageManager
import yokai.domain.track.interactor.GetTrack
import yokai.i18n.MR import yokai.i18n.MR
import yokai.util.lang.getString import yokai.util.lang.getString
@ -113,6 +114,7 @@ class ReaderViewModel(
private val updateManga: UpdateManga by injectLazy() private val updateManga: UpdateManga by injectLazy()
private val getHistory: GetHistory by injectLazy() private val getHistory: GetHistory by injectLazy()
private val upsertHistory: UpsertHistory by injectLazy() private val upsertHistory: UpsertHistory by injectLazy()
private val getTrack: GetTrack by injectLazy()
private val mutableState = MutableStateFlow(State()) private val mutableState = MutableStateFlow(State())
val state = mutableState.asStateFlow() val state = mutableState.asStateFlow()
@ -178,11 +180,7 @@ class ReaderViewModel(
private var scope = CoroutineScope(Job() + Dispatchers.Default) private var scope = CoroutineScope(Job() + Dispatchers.Default)
private var hasTrackers: Boolean = false private var hasTrackers: Boolean = false
private val checkTrackers: (Manga) -> Unit = { manga -> private suspend fun checkTrackers(manga: Manga) = getTrack.awaitAllByMangaId(manga.id).isNotEmpty()
val tracks = db.getTracks(manga).executeAsBlocking()
hasTrackers = tracks.size > 0
}
init { init {
var secondRun = false var secondRun = false
@ -251,7 +249,7 @@ class ReaderViewModel(
chapterId = initialChapterId chapterId = initialChapterId
} }
checkTrackers(manga) hasTrackers = checkTrackers(manga)
NotificationReceiver.dismissNotification( NotificationReceiver.dismissNotification(
preferences.context, preferences.context,

View file

@ -42,9 +42,12 @@ import eu.kanade.tachiyomi.util.view.withFadeTransaction
import eu.kanade.tachiyomi.widget.TriStateCheckBox import eu.kanade.tachiyomi.widget.TriStateCheckBox
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
import kotlinx.coroutines.Dispatchers
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 yokai.domain.chapter.interactor.GetChapter import yokai.domain.chapter.interactor.GetChapter
import yokai.domain.manga.interactor.GetManga
import yokai.i18n.MR import yokai.i18n.MR
import yokai.util.lang.getString import yokai.util.lang.getString
import android.R as AR import android.R as AR
@ -144,20 +147,16 @@ fun Manga.addOrRemoveToFavorites(
onMangaAdded: (Pair<Long, Boolean>?) -> Unit, onMangaAdded: (Pair<Long, Boolean>?) -> Unit,
onMangaMoved: () -> Unit, onMangaMoved: () -> Unit,
onMangaDeleted: () -> Unit, onMangaDeleted: () -> Unit,
getManga: GetManga = Injekt.get()
): Snackbar? { ): Snackbar? {
if (!favorite) { if (!favorite) {
if (checkForDupes) { if (checkForDupes) {
// TODO val duplicateManga = runBlocking(Dispatchers.IO) {
/* getManga.awaitDuplicateFavorite(
val duplicateManga = runBlocking(Dispatchers.IO) { handler.awaitOne {
mangasQueries.findDuplicateFavorite(
this@addOrRemoveToFavorites.title, this@addOrRemoveToFavorites.title,
this@addOrRemoveToFavorites.source, this@addOrRemoveToFavorites.source,
Manga::mapper,
) )
} } }
*/
val duplicateManga = db.getDuplicateLibraryManga(this).executeAsBlocking()
if (duplicateManga != null) { if (duplicateManga != null) {
showAddDuplicateDialog( showAddDuplicateDialog(
this, this,

View file

@ -19,6 +19,7 @@ import kotlinx.coroutines.delay
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import yokai.domain.chapter.interactor.UpdateChapter import yokai.domain.chapter.interactor.UpdateChapter
import yokai.domain.track.interactor.GetTrack
/** /**
* Helper method for syncing a remote track with the local chapters, and back * Helper method for syncing a remote track with the local chapters, and back
@ -98,9 +99,10 @@ suspend fun updateTrackChapterRead(
mangaId: Long?, mangaId: Long?,
newChapterRead: Float, newChapterRead: Float,
retryWhenOnline: Boolean = false, retryWhenOnline: Boolean = false,
getTrack: GetTrack = Injekt.get()
): List<Pair<TrackService, String?>> { ): List<Pair<TrackService, String?>> {
val trackManager = Injekt.get<TrackManager>() val trackManager = Injekt.get<TrackManager>()
val trackList = db.getTracks(mangaId).executeAsBlocking() val trackList = getTrack.awaitAllByMangaId(mangaId)
val failures = mutableListOf<Pair<TrackService, String?>>() val failures = mutableListOf<Pair<TrackService, String?>>()
trackList.map { track -> trackList.map { track ->
val service = trackManager.getService(track.sync_id) val service = trackManager.getService(track.sync_id)

View file

@ -7,6 +7,7 @@ import yokai.data.extension.repo.ExtensionRepoRepositoryImpl
import yokai.data.history.HistoryRepositoryImpl import yokai.data.history.HistoryRepositoryImpl
import yokai.data.library.custom.CustomMangaRepositoryImpl import yokai.data.library.custom.CustomMangaRepositoryImpl
import yokai.data.manga.MangaRepositoryImpl import yokai.data.manga.MangaRepositoryImpl
import yokai.data.track.TrackRepositoryImpl
import yokai.domain.category.CategoryRepository import yokai.domain.category.CategoryRepository
import yokai.domain.category.interactor.GetCategories import yokai.domain.category.interactor.GetCategories
import yokai.domain.chapter.ChapterRepository import yokai.domain.chapter.ChapterRepository
@ -37,10 +38,15 @@ import yokai.domain.manga.interactor.GetManga
import yokai.domain.manga.interactor.InsertManga import yokai.domain.manga.interactor.InsertManga
import yokai.domain.manga.interactor.UpdateManga import yokai.domain.manga.interactor.UpdateManga
import yokai.domain.recents.interactor.GetRecents import yokai.domain.recents.interactor.GetRecents
import yokai.domain.track.TrackRepository
import yokai.domain.track.interactor.GetTrack
fun domainModule() = module { fun domainModule() = module {
factory { TrustExtension(get(), get()) } factory { TrustExtension(get(), get()) }
single<CategoryRepository> { CategoryRepositoryImpl(get()) }
factory { GetCategories(get()) }
single<ExtensionRepoRepository> { ExtensionRepoRepositoryImpl(get()) } single<ExtensionRepoRepository> { ExtensionRepoRepositoryImpl(get()) }
factory { CreateExtensionRepo(get()) } factory { CreateExtensionRepo(get()) }
factory { DeleteExtensionRepo(get()) } factory { DeleteExtensionRepo(get()) }
@ -74,6 +80,6 @@ fun domainModule() = module {
factory { GetRecents(get(), get()) } factory { GetRecents(get(), get()) }
single<CategoryRepository> { CategoryRepositoryImpl(get()) } single<TrackRepository> { TrackRepositoryImpl(get()) }
factory { GetCategories(get()) } factory { GetTrack(get()) }
} }

View file

@ -9,6 +9,9 @@ class CategoryRepositoryImpl(private val handler: DatabaseHandler) : CategoryRep
override suspend fun getAll(): List<Category> = override suspend fun getAll(): List<Category> =
handler.awaitList { categoriesQueries.findAll(Category::mapper) } handler.awaitList { categoriesQueries.findAll(Category::mapper) }
override suspend fun getAllByMangaId(mangaId: Long): List<Category> =
handler.awaitList { categoriesQueries.findAllByMangaId(mangaId, Category::mapper) }
override fun getAllAsFlow(): Flow<List<Category>> = override fun getAllAsFlow(): Flow<List<Category>> =
handler.subscribeToList { categoriesQueries.findAll(Category::mapper) } handler.subscribeToList { categoriesQueries.findAll(Category::mapper) }
} }

View file

@ -35,6 +35,9 @@ class MangaRepositoryImpl(private val handler: DatabaseHandler) : MangaRepositor
override fun getLibraryMangaAsFlow(): Flow<List<LibraryManga>> = override fun getLibraryMangaAsFlow(): Flow<List<LibraryManga>> =
handler.subscribeToList { library_viewQueries.findAll(LibraryManga::mapper) } handler.subscribeToList { library_viewQueries.findAll(LibraryManga::mapper) }
override suspend fun getDuplicateFavorite(title: String, source: Long): Manga? =
handler.awaitOneOrNull { mangasQueries.findDuplicateFavorite(title, source, Manga::mapper) }
override suspend fun update(update: MangaUpdate): Boolean { override suspend fun update(update: MangaUpdate): Boolean {
return try { return try {
partialUpdate(update) partialUpdate(update)

View file

@ -0,0 +1,10 @@
package yokai.data.track
import eu.kanade.tachiyomi.data.database.models.Track
import yokai.data.DatabaseHandler
import yokai.domain.track.TrackRepository
class TrackRepositoryImpl(private val handler: DatabaseHandler) : TrackRepository {
override suspend fun getAllByMangaId(mangaId: Long): List<Track> =
handler.awaitList { manga_syncQueries.getAllByMangaId(mangaId, Track::mapper) }
}

View file

@ -5,5 +5,6 @@ import kotlinx.coroutines.flow.Flow
interface CategoryRepository { interface CategoryRepository {
suspend fun getAll(): List<Category> suspend fun getAll(): List<Category>
suspend fun getAllByMangaId(mangaId: Long): List<Category>
fun getAllAsFlow(): Flow<List<Category>> fun getAllAsFlow(): Flow<List<Category>>
} }

View file

@ -6,5 +6,6 @@ class GetCategories(
private val categoryRepository: CategoryRepository, private val categoryRepository: CategoryRepository,
) { ) {
suspend fun await() = categoryRepository.getAll() suspend fun await() = categoryRepository.getAll()
suspend fun awaitByMangaId(mangaId: Long) = categoryRepository.getAllByMangaId(mangaId)
fun subscribe() = categoryRepository.getAllAsFlow() fun subscribe() = categoryRepository.getAllAsFlow()
} }

View file

@ -11,6 +11,7 @@ interface MangaRepository {
suspend fun getMangaById(id: Long): Manga? suspend fun getMangaById(id: Long): Manga?
suspend fun getFavorites(): List<Manga> suspend fun getFavorites(): List<Manga>
suspend fun getReadNotFavorites(): List<Manga> suspend fun getReadNotFavorites(): List<Manga>
suspend fun getDuplicateFavorite(title: String, source: Long): Manga?
fun getMangaListAsFlow(): Flow<List<Manga>> fun getMangaListAsFlow(): Flow<List<Manga>>
suspend fun getLibraryManga(): List<LibraryManga> suspend fun getLibraryManga(): List<LibraryManga>
fun getLibraryMangaAsFlow(): Flow<List<LibraryManga>> fun getLibraryMangaAsFlow(): Flow<List<LibraryManga>>

View file

@ -12,4 +12,5 @@ class GetManga (
suspend fun awaitById(id: Long) = mangaRepository.getMangaById(id) suspend fun awaitById(id: Long) = mangaRepository.getMangaById(id)
suspend fun awaitFavorites() = mangaRepository.getFavorites() suspend fun awaitFavorites() = mangaRepository.getFavorites()
suspend fun awaitReadNotFavorites() = mangaRepository.getReadNotFavorites() suspend fun awaitReadNotFavorites() = mangaRepository.getReadNotFavorites()
suspend fun awaitDuplicateFavorite(title: String, source: Long) = mangaRepository.getDuplicateFavorite(title, source)
} }

View file

@ -0,0 +1,7 @@
package yokai.domain.track
import eu.kanade.tachiyomi.data.database.models.Track
interface TrackRepository {
suspend fun getAllByMangaId(mangaId: Long): List<Track>
}

View file

@ -0,0 +1,9 @@
package yokai.domain.track.interactor
import yokai.domain.track.TrackRepository
class GetTrack(
private val trackRepository: TrackRepository,
) {
suspend fun awaitAllByMangaId(mangaId: Long?) = mangaId?.let { trackRepository.getAllByMangaId(it) } ?: listOf()
}

View file

@ -10,3 +10,8 @@ findAll:
SELECT * SELECT *
FROM categories FROM categories
ORDER BY sort; ORDER BY sort;
findAllByMangaId:
SELECT categories.* FROM categories
JOIN mangas_categories ON categories._id = mangas_categories.category_id
WHERE mangas_categories.manga_id = :mangaId;

View file

@ -1,5 +1,4 @@
import kotlin.Float; import kotlin.Float;
import kotlin.Long;
CREATE TABLE manga_sync( CREATE TABLE manga_sync(
_id INTEGER NOT NULL PRIMARY KEY, _id INTEGER NOT NULL PRIMARY KEY,
@ -11,11 +10,16 @@ CREATE TABLE manga_sync(
last_chapter_read REAL NOT NULL, last_chapter_read REAL NOT NULL,
total_chapters INTEGER NOT NULL, total_chapters INTEGER NOT NULL,
status INTEGER NOT NULL, status INTEGER NOT NULL,
score REAL AS Float NOT NULL, score REAL NOT NULL,
remote_url TEXT NOT NULL, remote_url TEXT NOT NULL,
start_date INTEGER AS Long NOT NULL, start_date INTEGER NOT NULL,
finish_date INTEGER AS Long NOT NULL, finish_date INTEGER NOT NULL,
UNIQUE (manga_id, sync_id) ON CONFLICT REPLACE, UNIQUE (manga_id, sync_id) ON CONFLICT REPLACE,
FOREIGN KEY(manga_id) REFERENCES mangas (_id) FOREIGN KEY(manga_id) REFERENCES mangas (_id)
ON DELETE CASCADE ON DELETE CASCADE
); );
getAllByMangaId:
SELECT *
FROM manga_sync
WHERE manga_id = :mangaId;