mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	Use SQLDelight for all Manga related queries (#7447)
This commit is contained in:
		@@ -2,6 +2,7 @@ package eu.kanade.data.manga
 | 
			
		||||
 | 
			
		||||
import eu.kanade.domain.chapter.model.Chapter
 | 
			
		||||
import eu.kanade.domain.manga.model.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
 | 
			
		||||
 | 
			
		||||
val mangaMapper: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long) -> Manga =
 | 
			
		||||
    { id, source, url, artist, author, description, genre, title, status, thumbnailUrl, favorite, lastUpdate, _, initialized, viewer, chapterFlags, coverLastModified, dateAdded ->
 | 
			
		||||
@@ -61,3 +62,29 @@ val mangaChapterMapper: (Long, Long, String, String?, String?, String?, List<Str
 | 
			
		||||
            scanlator = scanlator,
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
val libraryManga: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, Long, Long, Long) -> LibraryManga =
 | 
			
		||||
    { _id, source, url, artist, author, description, genre, title, status, thumbnail_url, favorite, last_update, next_update, initialized, viewer, chapter_flags, cover_last_modified, date_added, unread_count, read_count, category ->
 | 
			
		||||
        LibraryManga().apply {
 | 
			
		||||
            this.id = _id
 | 
			
		||||
            this.source = source
 | 
			
		||||
            this.url = url
 | 
			
		||||
            this.artist = artist
 | 
			
		||||
            this.author = author
 | 
			
		||||
            this.description = description
 | 
			
		||||
            this.genre = genre?.joinToString()
 | 
			
		||||
            this.title = title
 | 
			
		||||
            this.status = status.toInt()
 | 
			
		||||
            this.thumbnail_url = thumbnail_url
 | 
			
		||||
            this.favorite = favorite
 | 
			
		||||
            this.last_update = last_update ?: 0
 | 
			
		||||
            this.initialized = initialized
 | 
			
		||||
            this.viewer_flags = viewer.toInt()
 | 
			
		||||
            this.chapter_flags = chapter_flags.toInt()
 | 
			
		||||
            this.cover_last_modified = cover_last_modified
 | 
			
		||||
            this.date_added = date_added
 | 
			
		||||
            this.unreadCount = unread_count.toInt()
 | 
			
		||||
            this.readCount = read_count.toInt()
 | 
			
		||||
            this.category = category.toInt()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ import eu.kanade.data.toLong
 | 
			
		||||
import eu.kanade.domain.manga.model.Manga
 | 
			
		||||
import eu.kanade.domain.manga.model.MangaUpdate
 | 
			
		||||
import eu.kanade.domain.manga.repository.MangaRepository
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.logcat
 | 
			
		||||
import kotlinx.coroutines.flow.Flow
 | 
			
		||||
import logcat.LogPriority
 | 
			
		||||
@@ -18,18 +19,26 @@ class MangaRepositoryImpl(
 | 
			
		||||
        return handler.awaitOne { mangasQueries.getMangaById(id, mangaMapper) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun subscribeMangaById(id: Long): Flow<Manga> {
 | 
			
		||||
        return handler.subscribeToOne { mangasQueries.getMangaById(id, mangaMapper) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun getMangaByIdAsFlow(id: Long): Flow<Manga> {
 | 
			
		||||
        return handler.subscribeToOne { mangasQueries.getMangaById(id, mangaMapper) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun getMangaByUrlAndSourceId(url: String, sourceId: Long): Manga? {
 | 
			
		||||
        return handler.awaitOneOrNull { mangasQueries.getMangaByUrlAndSource(url, sourceId, mangaMapper) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun getFavorites(): List<Manga> {
 | 
			
		||||
        return handler.awaitList { mangasQueries.getFavorites(mangaMapper) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun getLibraryManga(): List<LibraryManga> {
 | 
			
		||||
        return handler.awaitList { mangasQueries.getLibrary(libraryManga) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getLibraryMangaAsFlow(): Flow<List<LibraryManga>> {
 | 
			
		||||
        return handler.subscribeToList { mangasQueries.getLibrary(libraryManga) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getFavoritesBySourceId(sourceId: Long): Flow<List<Manga>> {
 | 
			
		||||
        return handler.subscribeToList { mangasQueries.getFavoriteBySourceId(sourceId, mangaMapper) }
 | 
			
		||||
    }
 | 
			
		||||
@@ -59,6 +68,31 @@ class MangaRepositoryImpl(
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun insert(manga: Manga): Long? {
 | 
			
		||||
        return handler.awaitOneOrNull {
 | 
			
		||||
            mangasQueries.insert(
 | 
			
		||||
                source = manga.source,
 | 
			
		||||
                url = manga.url,
 | 
			
		||||
                artist = manga.artist,
 | 
			
		||||
                author = manga.author,
 | 
			
		||||
                description = manga.description,
 | 
			
		||||
                genre = manga.genre,
 | 
			
		||||
                title = manga.title,
 | 
			
		||||
                status = manga.status,
 | 
			
		||||
                thumbnail_url = manga.thumbnailUrl,
 | 
			
		||||
                favorite = manga.favorite,
 | 
			
		||||
                last_update = manga.lastUpdate,
 | 
			
		||||
                next_update = null,
 | 
			
		||||
                initialized = manga.initialized,
 | 
			
		||||
                viewer = manga.viewerFlags,
 | 
			
		||||
                chapter_flags = manga.chapterFlags,
 | 
			
		||||
                cover_last_modified = manga.coverLastModified,
 | 
			
		||||
                date_added = manga.dateAdded,
 | 
			
		||||
            )
 | 
			
		||||
            mangasQueries.selectLastInsertedRowId()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun update(update: MangaUpdate): Boolean {
 | 
			
		||||
        return try {
 | 
			
		||||
            partialUpdate(update)
 | 
			
		||||
 
 | 
			
		||||
@@ -32,10 +32,13 @@ import eu.kanade.domain.history.interactor.UpsertHistory
 | 
			
		||||
import eu.kanade.domain.history.repository.HistoryRepository
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetDuplicateLibraryManga
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetFavorites
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetMangaById
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetLibraryManga
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetManga
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetMangaWithChapters
 | 
			
		||||
import eu.kanade.domain.manga.interactor.InsertManga
 | 
			
		||||
import eu.kanade.domain.manga.interactor.ResetViewerFlags
 | 
			
		||||
import eu.kanade.domain.manga.interactor.SetMangaChapterFlags
 | 
			
		||||
import eu.kanade.domain.manga.interactor.SetMangaViewerFlags
 | 
			
		||||
import eu.kanade.domain.manga.interactor.UpdateManga
 | 
			
		||||
import eu.kanade.domain.manga.repository.MangaRepository
 | 
			
		||||
import eu.kanade.domain.source.interactor.GetEnabledSources
 | 
			
		||||
@@ -71,11 +74,14 @@ class DomainModule : InjektModule {
 | 
			
		||||
        addSingletonFactory<MangaRepository> { MangaRepositoryImpl(get()) }
 | 
			
		||||
        addFactory { GetDuplicateLibraryManga(get()) }
 | 
			
		||||
        addFactory { GetFavorites(get()) }
 | 
			
		||||
        addFactory { GetLibraryManga(get()) }
 | 
			
		||||
        addFactory { GetMangaWithChapters(get(), get()) }
 | 
			
		||||
        addFactory { GetMangaById(get()) }
 | 
			
		||||
        addFactory { GetManga(get()) }
 | 
			
		||||
        addFactory { GetNextChapter(get()) }
 | 
			
		||||
        addFactory { ResetViewerFlags(get()) }
 | 
			
		||||
        addFactory { SetMangaChapterFlags(get()) }
 | 
			
		||||
        addFactory { SetMangaViewerFlags(get()) }
 | 
			
		||||
        addFactory { InsertManga(get()) }
 | 
			
		||||
        addFactory { UpdateManga(get()) }
 | 
			
		||||
        addFactory { SetMangaCategories(get()) }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,18 @@
 | 
			
		||||
package eu.kanade.domain.manga.interactor
 | 
			
		||||
 | 
			
		||||
import eu.kanade.domain.manga.repository.MangaRepository
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
 | 
			
		||||
import kotlinx.coroutines.flow.Flow
 | 
			
		||||
 | 
			
		||||
class GetLibraryManga(
 | 
			
		||||
    private val mangaRepository: MangaRepository,
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    suspend fun await(): List<LibraryManga> {
 | 
			
		||||
        return mangaRepository.getLibraryManga()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun subscribe(): Flow<List<LibraryManga>> {
 | 
			
		||||
        return mangaRepository.getLibraryMangaAsFlow()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -6,7 +6,7 @@ import eu.kanade.tachiyomi.util.system.logcat
 | 
			
		||||
import kotlinx.coroutines.flow.Flow
 | 
			
		||||
import logcat.LogPriority
 | 
			
		||||
 | 
			
		||||
class GetMangaById(
 | 
			
		||||
class GetManga(
 | 
			
		||||
    private val mangaRepository: MangaRepository,
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
@@ -20,6 +20,10 @@ class GetMangaById(
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun subscribe(id: Long): Flow<Manga> {
 | 
			
		||||
        return mangaRepository.subscribeMangaById(id)
 | 
			
		||||
        return mangaRepository.getMangaByIdAsFlow(id)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun await(url: String, sourceId: Long): Manga? {
 | 
			
		||||
        return mangaRepository.getMangaByUrlAndSourceId(url, sourceId)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -14,7 +14,7 @@ class GetMangaWithChapters(
 | 
			
		||||
 | 
			
		||||
    suspend fun subscribe(id: Long): Flow<Pair<Manga, List<Chapter>>> {
 | 
			
		||||
        return combine(
 | 
			
		||||
            mangaRepository.subscribeMangaById(id),
 | 
			
		||||
            mangaRepository.getMangaByIdAsFlow(id),
 | 
			
		||||
            chapterRepository.getChapterByMangaIdAsFlow(id),
 | 
			
		||||
        ) { manga, chapters ->
 | 
			
		||||
            Pair(manga, chapters)
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,13 @@
 | 
			
		||||
package eu.kanade.domain.manga.interactor
 | 
			
		||||
 | 
			
		||||
import eu.kanade.domain.manga.model.Manga
 | 
			
		||||
import eu.kanade.domain.manga.repository.MangaRepository
 | 
			
		||||
 | 
			
		||||
class InsertManga(
 | 
			
		||||
    private val mangaRepository: MangaRepository,
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    suspend fun await(manga: Manga): Long? {
 | 
			
		||||
        return mangaRepository.insert(manga)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,33 @@
 | 
			
		||||
package eu.kanade.domain.manga.interactor
 | 
			
		||||
 | 
			
		||||
import eu.kanade.domain.manga.model.MangaUpdate
 | 
			
		||||
import eu.kanade.domain.manga.repository.MangaRepository
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
 | 
			
		||||
 | 
			
		||||
class SetMangaViewerFlags(
 | 
			
		||||
    private val mangaRepository: MangaRepository,
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    suspend fun awaitSetMangaReadingMode(id: Long, flag: Long) {
 | 
			
		||||
        mangaRepository.update(
 | 
			
		||||
            MangaUpdate(
 | 
			
		||||
                id = id,
 | 
			
		||||
                viewerFlags = flag.setFlag(flag, ReadingModeType.MASK.toLong()),
 | 
			
		||||
            ),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun awaitSetOrientationType(id: Long, flag: Long) {
 | 
			
		||||
        mangaRepository.update(
 | 
			
		||||
            MangaUpdate(
 | 
			
		||||
                id = id,
 | 
			
		||||
                viewerFlags = flag.setFlag(flag, OrientationType.MASK.toLong()),
 | 
			
		||||
            ),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun Long.setFlag(flag: Long, mask: Long): Long {
 | 
			
		||||
        return this and mask.inv() or (flag and mask)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -175,6 +175,28 @@ fun Manga.toMangaInfo(): MangaInfo = MangaInfo(
 | 
			
		||||
    title = title,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
fun Manga.toMangaUpdate(): MangaUpdate {
 | 
			
		||||
    return MangaUpdate(
 | 
			
		||||
        id = id,
 | 
			
		||||
        source = source,
 | 
			
		||||
        favorite = favorite,
 | 
			
		||||
        lastUpdate = lastUpdate,
 | 
			
		||||
        dateAdded = dateAdded,
 | 
			
		||||
        viewerFlags = viewerFlags,
 | 
			
		||||
        chapterFlags = chapterFlags,
 | 
			
		||||
        coverLastModified = coverLastModified,
 | 
			
		||||
        url = url,
 | 
			
		||||
        title = title,
 | 
			
		||||
        artist = artist,
 | 
			
		||||
        author = author,
 | 
			
		||||
        description = description,
 | 
			
		||||
        genre = genre,
 | 
			
		||||
        status = status,
 | 
			
		||||
        thumbnailUrl = thumbnailUrl,
 | 
			
		||||
        initialized = initialized,
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun Manga.isLocal(): Boolean = source == LocalSource.ID
 | 
			
		||||
 | 
			
		||||
fun Manga.hasCustomCover(coverCache: CoverCache = Injekt.get()): Boolean {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,18 +2,23 @@ package eu.kanade.domain.manga.repository
 | 
			
		||||
 | 
			
		||||
import eu.kanade.domain.manga.model.Manga
 | 
			
		||||
import eu.kanade.domain.manga.model.MangaUpdate
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
 | 
			
		||||
import kotlinx.coroutines.flow.Flow
 | 
			
		||||
 | 
			
		||||
interface MangaRepository {
 | 
			
		||||
 | 
			
		||||
    suspend fun getMangaById(id: Long): Manga
 | 
			
		||||
 | 
			
		||||
    suspend fun subscribeMangaById(id: Long): Flow<Manga>
 | 
			
		||||
 | 
			
		||||
    suspend fun getMangaByIdAsFlow(id: Long): Flow<Manga>
 | 
			
		||||
 | 
			
		||||
    suspend fun getMangaByUrlAndSourceId(url: String, sourceId: Long): Manga?
 | 
			
		||||
 | 
			
		||||
    suspend fun getFavorites(): List<Manga>
 | 
			
		||||
 | 
			
		||||
    suspend fun getLibraryManga(): List<LibraryManga>
 | 
			
		||||
 | 
			
		||||
    fun getLibraryMangaAsFlow(): Flow<List<LibraryManga>>
 | 
			
		||||
 | 
			
		||||
    fun getFavoritesBySourceId(sourceId: Long): Flow<List<Manga>>
 | 
			
		||||
 | 
			
		||||
    suspend fun getDuplicateLibraryManga(title: String, sourceId: Long): Manga?
 | 
			
		||||
@@ -22,6 +27,8 @@ interface MangaRepository {
 | 
			
		||||
 | 
			
		||||
    suspend fun setMangaCategories(mangaId: Long, categoryIds: List<Long>)
 | 
			
		||||
 | 
			
		||||
    suspend fun insert(manga: Manga): Long?
 | 
			
		||||
 | 
			
		||||
    suspend fun update(update: MangaUpdate): Boolean
 | 
			
		||||
 | 
			
		||||
    suspend fun updateAll(values: List<MangaUpdate>): Boolean
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,6 @@ import eu.kanade.data.dateAdapter
 | 
			
		||||
import eu.kanade.data.listOfStringsAdapter
 | 
			
		||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
 | 
			
		||||
import eu.kanade.tachiyomi.data.cache.CoverCache
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.DbOpenCallback
 | 
			
		||||
import eu.kanade.tachiyomi.data.download.DownloadManager
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 | 
			
		||||
@@ -76,8 +75,6 @@ class AppModule(val app: Application) : InjektModule {
 | 
			
		||||
 | 
			
		||||
        addSingletonFactory { PreferencesHelper(app) }
 | 
			
		||||
 | 
			
		||||
        addSingletonFactory { DatabaseHelper(get()) }
 | 
			
		||||
 | 
			
		||||
        addSingletonFactory { ChapterCache(app) }
 | 
			
		||||
 | 
			
		||||
        addSingletonFactory { CoverCache(app) }
 | 
			
		||||
@@ -106,8 +103,6 @@ class AppModule(val app: Application) : InjektModule {
 | 
			
		||||
 | 
			
		||||
            get<Database>()
 | 
			
		||||
 | 
			
		||||
            get<DatabaseHelper>()
 | 
			
		||||
 | 
			
		||||
            get<DownloadManager>()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,27 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.database
 | 
			
		||||
 | 
			
		||||
import androidx.sqlite.db.SupportSQLiteOpenHelper
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.impl.DefaultStorIOSQLite
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.mappers.ChapterTypeMapping
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.mappers.MangaCategoryTypeMapping
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.mappers.MangaTypeMapping
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Chapter
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.queries.MangaQueries
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class provides operations to manage the database through its interfaces.
 | 
			
		||||
 */
 | 
			
		||||
class DatabaseHelper(
 | 
			
		||||
    openHelper: SupportSQLiteOpenHelper,
 | 
			
		||||
) :
 | 
			
		||||
    MangaQueries {
 | 
			
		||||
 | 
			
		||||
    override val db = DefaultStorIOSQLite.builder()
 | 
			
		||||
        .sqliteOpenHelper(openHelper)
 | 
			
		||||
        .addTypeMapping(Manga::class.java, MangaTypeMapping())
 | 
			
		||||
        .addTypeMapping(Chapter::class.java, ChapterTypeMapping())
 | 
			
		||||
        .addTypeMapping(MangaCategory::class.java, MangaCategoryTypeMapping())
 | 
			
		||||
        .build()
 | 
			
		||||
}
 | 
			
		||||
@@ -1,24 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.database
 | 
			
		||||
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.StorIOSQLite
 | 
			
		||||
 | 
			
		||||
inline fun StorIOSQLite.inTransaction(block: () -> Unit) {
 | 
			
		||||
    lowLevel().beginTransaction()
 | 
			
		||||
    try {
 | 
			
		||||
        block()
 | 
			
		||||
        lowLevel().setTransactionSuccessful()
 | 
			
		||||
    } finally {
 | 
			
		||||
        lowLevel().endTransaction()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline fun <T> StorIOSQLite.inTransactionReturn(block: () -> T): T {
 | 
			
		||||
    lowLevel().beginTransaction()
 | 
			
		||||
    try {
 | 
			
		||||
        val result = block()
 | 
			
		||||
        lowLevel().setTransactionSuccessful()
 | 
			
		||||
        return result
 | 
			
		||||
    } finally {
 | 
			
		||||
        lowLevel().endTransaction()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.database
 | 
			
		||||
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.impl.DefaultStorIOSQLite
 | 
			
		||||
 | 
			
		||||
interface DbProvider {
 | 
			
		||||
    val db: DefaultStorIOSQLite
 | 
			
		||||
}
 | 
			
		||||
@@ -1,88 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.database.mappers
 | 
			
		||||
 | 
			
		||||
import android.database.Cursor
 | 
			
		||||
import androidx.core.content.contentValuesOf
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.operations.delete.DefaultDeleteResolver
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.queries.InsertQuery
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Chapter
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_BOOKMARK
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_CHAPTER_NUMBER
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_DATE_FETCH
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_DATE_UPLOAD
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_ID
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_LAST_PAGE_READ
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_MANGA_ID
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_NAME
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_READ
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_SCANLATOR
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_SOURCE_ORDER
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_URL
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.TABLE
 | 
			
		||||
 | 
			
		||||
class ChapterTypeMapping : SQLiteTypeMapping<Chapter>(
 | 
			
		||||
    ChapterPutResolver(),
 | 
			
		||||
    ChapterGetResolver(),
 | 
			
		||||
    ChapterDeleteResolver(),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
class ChapterPutResolver : DefaultPutResolver<Chapter>() {
 | 
			
		||||
 | 
			
		||||
    override fun mapToInsertQuery(obj: Chapter) = InsertQuery.builder()
 | 
			
		||||
        .table(TABLE)
 | 
			
		||||
        .build()
 | 
			
		||||
 | 
			
		||||
    override fun mapToUpdateQuery(obj: Chapter) = UpdateQuery.builder()
 | 
			
		||||
        .table(TABLE)
 | 
			
		||||
        .where("$COL_ID = ?")
 | 
			
		||||
        .whereArgs(obj.id)
 | 
			
		||||
        .build()
 | 
			
		||||
 | 
			
		||||
    override fun mapToContentValues(obj: Chapter) =
 | 
			
		||||
        contentValuesOf(
 | 
			
		||||
            COL_ID to obj.id,
 | 
			
		||||
            COL_MANGA_ID to obj.manga_id,
 | 
			
		||||
            COL_URL to obj.url,
 | 
			
		||||
            COL_NAME to obj.name,
 | 
			
		||||
            COL_READ to obj.read,
 | 
			
		||||
            COL_SCANLATOR to obj.scanlator,
 | 
			
		||||
            COL_BOOKMARK to obj.bookmark,
 | 
			
		||||
            COL_DATE_FETCH to obj.date_fetch,
 | 
			
		||||
            COL_DATE_UPLOAD to obj.date_upload,
 | 
			
		||||
            COL_LAST_PAGE_READ to obj.last_page_read,
 | 
			
		||||
            COL_CHAPTER_NUMBER to obj.chapter_number,
 | 
			
		||||
            COL_SOURCE_ORDER to obj.source_order,
 | 
			
		||||
        )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class ChapterGetResolver : DefaultGetResolver<Chapter>() {
 | 
			
		||||
 | 
			
		||||
    override fun mapFromCursor(cursor: Cursor): Chapter = ChapterImpl().apply {
 | 
			
		||||
        id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_ID))
 | 
			
		||||
        manga_id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_MANGA_ID))
 | 
			
		||||
        url = cursor.getString(cursor.getColumnIndexOrThrow(COL_URL))
 | 
			
		||||
        name = cursor.getString(cursor.getColumnIndexOrThrow(COL_NAME))
 | 
			
		||||
        scanlator = cursor.getString(cursor.getColumnIndexOrThrow(COL_SCANLATOR))
 | 
			
		||||
        read = cursor.getInt(cursor.getColumnIndexOrThrow(COL_READ)) == 1
 | 
			
		||||
        bookmark = cursor.getInt(cursor.getColumnIndexOrThrow(COL_BOOKMARK)) == 1
 | 
			
		||||
        date_fetch = cursor.getLong(cursor.getColumnIndexOrThrow(COL_DATE_FETCH))
 | 
			
		||||
        date_upload = cursor.getLong(cursor.getColumnIndexOrThrow(COL_DATE_UPLOAD))
 | 
			
		||||
        last_page_read = cursor.getInt(cursor.getColumnIndexOrThrow(COL_LAST_PAGE_READ))
 | 
			
		||||
        chapter_number = cursor.getFloat(cursor.getColumnIndexOrThrow(COL_CHAPTER_NUMBER))
 | 
			
		||||
        source_order = cursor.getInt(cursor.getColumnIndexOrThrow(COL_SOURCE_ORDER))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class ChapterDeleteResolver : DefaultDeleteResolver<Chapter>() {
 | 
			
		||||
 | 
			
		||||
    override fun mapToDeleteQuery(obj: Chapter) = DeleteQuery.builder()
 | 
			
		||||
        .table(TABLE)
 | 
			
		||||
        .where("$COL_ID = ?")
 | 
			
		||||
        .whereArgs(obj.id)
 | 
			
		||||
        .build()
 | 
			
		||||
}
 | 
			
		||||
@@ -1,60 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.database.mappers
 | 
			
		||||
 | 
			
		||||
import android.database.Cursor
 | 
			
		||||
import androidx.core.content.contentValuesOf
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.operations.delete.DefaultDeleteResolver
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.queries.InsertQuery
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable.COL_CATEGORY_ID
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable.COL_ID
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable.COL_MANGA_ID
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable.TABLE
 | 
			
		||||
 | 
			
		||||
class MangaCategoryTypeMapping : SQLiteTypeMapping<MangaCategory>(
 | 
			
		||||
    MangaCategoryPutResolver(),
 | 
			
		||||
    MangaCategoryGetResolver(),
 | 
			
		||||
    MangaCategoryDeleteResolver(),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
class MangaCategoryPutResolver : DefaultPutResolver<MangaCategory>() {
 | 
			
		||||
 | 
			
		||||
    override fun mapToInsertQuery(obj: MangaCategory) = InsertQuery.builder()
 | 
			
		||||
        .table(TABLE)
 | 
			
		||||
        .build()
 | 
			
		||||
 | 
			
		||||
    override fun mapToUpdateQuery(obj: MangaCategory) = UpdateQuery.builder()
 | 
			
		||||
        .table(TABLE)
 | 
			
		||||
        .where("$COL_ID = ?")
 | 
			
		||||
        .whereArgs(obj.id)
 | 
			
		||||
        .build()
 | 
			
		||||
 | 
			
		||||
    override fun mapToContentValues(obj: MangaCategory) =
 | 
			
		||||
        contentValuesOf(
 | 
			
		||||
            COL_ID to obj.id,
 | 
			
		||||
            COL_MANGA_ID to obj.manga_id,
 | 
			
		||||
            COL_CATEGORY_ID to obj.category_id,
 | 
			
		||||
        )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class MangaCategoryGetResolver : DefaultGetResolver<MangaCategory>() {
 | 
			
		||||
 | 
			
		||||
    override fun mapFromCursor(cursor: Cursor): MangaCategory = MangaCategory().apply {
 | 
			
		||||
        id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_ID))
 | 
			
		||||
        manga_id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_MANGA_ID))
 | 
			
		||||
        category_id = cursor.getInt(cursor.getColumnIndexOrThrow(COL_CATEGORY_ID))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class MangaCategoryDeleteResolver : DefaultDeleteResolver<MangaCategory>() {
 | 
			
		||||
 | 
			
		||||
    override fun mapToDeleteQuery(obj: MangaCategory) = DeleteQuery.builder()
 | 
			
		||||
        .table(TABLE)
 | 
			
		||||
        .where("$COL_ID = ?")
 | 
			
		||||
        .whereArgs(obj.id)
 | 
			
		||||
        .build()
 | 
			
		||||
}
 | 
			
		||||
@@ -1,109 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.database.mappers
 | 
			
		||||
 | 
			
		||||
import android.database.Cursor
 | 
			
		||||
import androidx.core.content.contentValuesOf
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.operations.delete.DefaultDeleteResolver
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.queries.InsertQuery
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_ARTIST
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_AUTHOR
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_CHAPTER_FLAGS
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_COVER_LAST_MODIFIED
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_DATE_ADDED
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_DESCRIPTION
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_FAVORITE
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_GENRE
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_ID
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_INITIALIZED
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_LAST_UPDATE
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_SOURCE
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_STATUS
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_THUMBNAIL_URL
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_TITLE
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_URL
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_VIEWER
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.TABLE
 | 
			
		||||
 | 
			
		||||
class MangaTypeMapping : SQLiteTypeMapping<Manga>(
 | 
			
		||||
    MangaPutResolver(),
 | 
			
		||||
    MangaGetResolver(),
 | 
			
		||||
    MangaDeleteResolver(),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
class MangaPutResolver : DefaultPutResolver<Manga>() {
 | 
			
		||||
 | 
			
		||||
    override fun mapToInsertQuery(obj: Manga) = InsertQuery.builder()
 | 
			
		||||
        .table(TABLE)
 | 
			
		||||
        .build()
 | 
			
		||||
 | 
			
		||||
    override fun mapToUpdateQuery(obj: Manga) = UpdateQuery.builder()
 | 
			
		||||
        .table(TABLE)
 | 
			
		||||
        .where("$COL_ID = ?")
 | 
			
		||||
        .whereArgs(obj.id)
 | 
			
		||||
        .build()
 | 
			
		||||
 | 
			
		||||
    override fun mapToContentValues(obj: Manga) =
 | 
			
		||||
        contentValuesOf(
 | 
			
		||||
            COL_ID to obj.id,
 | 
			
		||||
            COL_SOURCE to obj.source,
 | 
			
		||||
            COL_URL to obj.url,
 | 
			
		||||
            COL_ARTIST to obj.artist,
 | 
			
		||||
            COL_AUTHOR to obj.author,
 | 
			
		||||
            COL_DESCRIPTION to obj.description,
 | 
			
		||||
            COL_GENRE to obj.genre,
 | 
			
		||||
            COL_TITLE to obj.title,
 | 
			
		||||
            COL_STATUS to obj.status,
 | 
			
		||||
            COL_THUMBNAIL_URL to obj.thumbnail_url,
 | 
			
		||||
            COL_FAVORITE to obj.favorite,
 | 
			
		||||
            COL_LAST_UPDATE to obj.last_update,
 | 
			
		||||
            COL_INITIALIZED to obj.initialized,
 | 
			
		||||
            COL_VIEWER to obj.viewer_flags,
 | 
			
		||||
            COL_CHAPTER_FLAGS to obj.chapter_flags,
 | 
			
		||||
            COL_COVER_LAST_MODIFIED to obj.cover_last_modified,
 | 
			
		||||
            COL_DATE_ADDED to obj.date_added,
 | 
			
		||||
        )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface BaseMangaGetResolver {
 | 
			
		||||
    fun mapBaseFromCursor(manga: Manga, cursor: Cursor) = manga.apply {
 | 
			
		||||
        id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_ID))
 | 
			
		||||
        source = cursor.getLong(cursor.getColumnIndexOrThrow(COL_SOURCE))
 | 
			
		||||
        url = cursor.getString(cursor.getColumnIndexOrThrow(COL_URL))
 | 
			
		||||
        artist = cursor.getString(cursor.getColumnIndexOrThrow(COL_ARTIST))
 | 
			
		||||
        author = cursor.getString(cursor.getColumnIndexOrThrow(COL_AUTHOR))
 | 
			
		||||
        description = cursor.getString(cursor.getColumnIndexOrThrow(COL_DESCRIPTION))
 | 
			
		||||
        genre = cursor.getString(cursor.getColumnIndexOrThrow(COL_GENRE))
 | 
			
		||||
        title = cursor.getString(cursor.getColumnIndexOrThrow(COL_TITLE))
 | 
			
		||||
        status = cursor.getInt(cursor.getColumnIndexOrThrow(COL_STATUS))
 | 
			
		||||
        thumbnail_url = cursor.getString(cursor.getColumnIndexOrThrow(COL_THUMBNAIL_URL))
 | 
			
		||||
        favorite = cursor.getInt(cursor.getColumnIndexOrThrow(COL_FAVORITE)) == 1
 | 
			
		||||
        last_update = cursor.getLong(cursor.getColumnIndexOrThrow(COL_LAST_UPDATE))
 | 
			
		||||
        initialized = cursor.getInt(cursor.getColumnIndexOrThrow(COL_INITIALIZED)) == 1
 | 
			
		||||
        viewer_flags = cursor.getInt(cursor.getColumnIndexOrThrow(COL_VIEWER))
 | 
			
		||||
        chapter_flags = cursor.getInt(cursor.getColumnIndexOrThrow(COL_CHAPTER_FLAGS))
 | 
			
		||||
        cover_last_modified = cursor.getLong(cursor.getColumnIndexOrThrow(COL_COVER_LAST_MODIFIED))
 | 
			
		||||
        date_added = cursor.getLong(cursor.getColumnIndexOrThrow(COL_DATE_ADDED))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
open class MangaGetResolver : DefaultGetResolver<Manga>(), BaseMangaGetResolver {
 | 
			
		||||
 | 
			
		||||
    override fun mapFromCursor(cursor: Cursor): Manga {
 | 
			
		||||
        return mapBaseFromCursor(MangaImpl(), cursor)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class MangaDeleteResolver : DefaultDeleteResolver<Manga>() {
 | 
			
		||||
 | 
			
		||||
    override fun mapToDeleteQuery(obj: Manga) = DeleteQuery.builder()
 | 
			
		||||
        .table(TABLE)
 | 
			
		||||
        .where("$COL_ID = ?")
 | 
			
		||||
        .whereArgs(obj.id)
 | 
			
		||||
        .build()
 | 
			
		||||
}
 | 
			
		||||
@@ -1,77 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.database.queries
 | 
			
		||||
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.queries.Query
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.queries.RawQuery
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.DbProvider
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.resolvers.LibraryMangaGetResolver
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.resolvers.MangaFlagsPutResolver
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.CategoryTable
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
 | 
			
		||||
 | 
			
		||||
interface MangaQueries : DbProvider {
 | 
			
		||||
 | 
			
		||||
    fun getLibraryMangas() = db.get()
 | 
			
		||||
        .listOfObjects(LibraryManga::class.java)
 | 
			
		||||
        .withQuery(
 | 
			
		||||
            RawQuery.builder()
 | 
			
		||||
                .query(libraryQuery)
 | 
			
		||||
                .observesTables(MangaTable.TABLE, ChapterTable.TABLE, MangaCategoryTable.TABLE, CategoryTable.TABLE)
 | 
			
		||||
                .build(),
 | 
			
		||||
        )
 | 
			
		||||
        .withGetResolver(LibraryMangaGetResolver.INSTANCE)
 | 
			
		||||
        .prepare()
 | 
			
		||||
 | 
			
		||||
    fun getFavoriteMangas() = db.get()
 | 
			
		||||
        .listOfObjects(Manga::class.java)
 | 
			
		||||
        .withQuery(
 | 
			
		||||
            Query.builder()
 | 
			
		||||
                .table(MangaTable.TABLE)
 | 
			
		||||
                .where("${MangaTable.COL_FAVORITE} = ?")
 | 
			
		||||
                .whereArgs(1)
 | 
			
		||||
                .build(),
 | 
			
		||||
        )
 | 
			
		||||
        .prepare()
 | 
			
		||||
 | 
			
		||||
    fun getManga(url: String, sourceId: Long) = db.get()
 | 
			
		||||
        .`object`(Manga::class.java)
 | 
			
		||||
        .withQuery(
 | 
			
		||||
            Query.builder()
 | 
			
		||||
                .table(MangaTable.TABLE)
 | 
			
		||||
                .where("${MangaTable.COL_URL} = ? AND ${MangaTable.COL_SOURCE} = ?")
 | 
			
		||||
                .whereArgs(url, sourceId)
 | 
			
		||||
                .build(),
 | 
			
		||||
        )
 | 
			
		||||
        .prepare()
 | 
			
		||||
 | 
			
		||||
    fun getManga(id: Long) = db.get()
 | 
			
		||||
        .`object`(Manga::class.java)
 | 
			
		||||
        .withQuery(
 | 
			
		||||
            Query.builder()
 | 
			
		||||
                .table(MangaTable.TABLE)
 | 
			
		||||
                .where("${MangaTable.COL_ID} = ?")
 | 
			
		||||
                .whereArgs(id)
 | 
			
		||||
                .build(),
 | 
			
		||||
        )
 | 
			
		||||
        .prepare()
 | 
			
		||||
 | 
			
		||||
    fun insertManga(manga: Manga) = db.put().`object`(manga).prepare()
 | 
			
		||||
 | 
			
		||||
    fun updateChapterFlags(manga: Manga) = db.put()
 | 
			
		||||
        .`object`(manga)
 | 
			
		||||
        .withPutResolver(MangaFlagsPutResolver(MangaTable.COL_CHAPTER_FLAGS, Manga::chapter_flags))
 | 
			
		||||
        .prepare()
 | 
			
		||||
 | 
			
		||||
    fun updateChapterFlags(manga: List<Manga>) = db.put()
 | 
			
		||||
        .objects(manga)
 | 
			
		||||
        .withPutResolver(MangaFlagsPutResolver(MangaTable.COL_CHAPTER_FLAGS, Manga::chapter_flags))
 | 
			
		||||
        .prepare()
 | 
			
		||||
 | 
			
		||||
    fun updateViewerFlags(manga: Manga) = db.put()
 | 
			
		||||
        .`object`(manga)
 | 
			
		||||
        .withPutResolver(MangaFlagsPutResolver(MangaTable.COL_VIEWER, Manga::viewer_flags))
 | 
			
		||||
        .prepare()
 | 
			
		||||
}
 | 
			
		||||
@@ -1,37 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.database.queries
 | 
			
		||||
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable as Chapter
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable as MangaCategory
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable as Manga
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Query to get the manga from the library, with their categories, read and unread count.
 | 
			
		||||
 */
 | 
			
		||||
val libraryQuery =
 | 
			
		||||
    """
 | 
			
		||||
    SELECT M.*, COALESCE(MC.${MangaCategory.COL_CATEGORY_ID}, 0) AS ${Manga.COL_CATEGORY}
 | 
			
		||||
    FROM (
 | 
			
		||||
        SELECT ${Manga.TABLE}.*, COALESCE(C.unreadCount, 0) AS ${Manga.COMPUTED_COL_UNREAD_COUNT}, COALESCE(R.readCount, 0) AS ${Manga.COMPUTED_COL_READ_COUNT}
 | 
			
		||||
        FROM ${Manga.TABLE}
 | 
			
		||||
        LEFT JOIN (
 | 
			
		||||
            SELECT ${Chapter.COL_MANGA_ID}, COUNT(*) AS unreadCount
 | 
			
		||||
            FROM ${Chapter.TABLE}
 | 
			
		||||
            WHERE ${Chapter.COL_READ} = 0
 | 
			
		||||
            GROUP BY ${Chapter.COL_MANGA_ID}
 | 
			
		||||
        ) AS C
 | 
			
		||||
        ON ${Manga.COL_ID} = C.${Chapter.COL_MANGA_ID}
 | 
			
		||||
        LEFT JOIN (
 | 
			
		||||
            SELECT ${Chapter.COL_MANGA_ID}, COUNT(*) AS readCount
 | 
			
		||||
            FROM ${Chapter.TABLE}
 | 
			
		||||
            WHERE ${Chapter.COL_READ} = 1
 | 
			
		||||
            GROUP BY ${Chapter.COL_MANGA_ID}
 | 
			
		||||
        ) AS R
 | 
			
		||||
        ON ${Manga.COL_ID} = R.${Chapter.COL_MANGA_ID}
 | 
			
		||||
        WHERE ${Manga.COL_FAVORITE} = 1
 | 
			
		||||
        GROUP BY ${Manga.COL_ID}
 | 
			
		||||
        ORDER BY ${Manga.COL_TITLE}
 | 
			
		||||
    ) AS M
 | 
			
		||||
    LEFT JOIN (
 | 
			
		||||
        SELECT * FROM ${MangaCategory.TABLE}) AS MC
 | 
			
		||||
        ON MC.${MangaCategory.COL_MANGA_ID} = M.${Manga.COL_ID}
 | 
			
		||||
"""
 | 
			
		||||
@@ -1,34 +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.Chapter
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable
 | 
			
		||||
 | 
			
		||||
class ChapterProgressPutResolver : PutResolver<Chapter>() {
 | 
			
		||||
 | 
			
		||||
    override fun performPut(db: StorIOSQLite, chapter: Chapter) = db.inTransactionReturn {
 | 
			
		||||
        val updateQuery = mapToUpdateQuery(chapter)
 | 
			
		||||
        val contentValues = mapToContentValues(chapter)
 | 
			
		||||
 | 
			
		||||
        val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
 | 
			
		||||
        PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun mapToUpdateQuery(chapter: Chapter) = UpdateQuery.builder()
 | 
			
		||||
        .table(ChapterTable.TABLE)
 | 
			
		||||
        .where("${ChapterTable.COL_ID} = ?")
 | 
			
		||||
        .whereArgs(chapter.id)
 | 
			
		||||
        .build()
 | 
			
		||||
 | 
			
		||||
    fun mapToContentValues(chapter: Chapter) =
 | 
			
		||||
        contentValuesOf(
 | 
			
		||||
            ChapterTable.COL_READ to chapter.read,
 | 
			
		||||
            ChapterTable.COL_BOOKMARK to chapter.bookmark,
 | 
			
		||||
            ChapterTable.COL_LAST_PAGE_READ to chapter.last_page_read,
 | 
			
		||||
        )
 | 
			
		||||
}
 | 
			
		||||
@@ -1,25 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.database.resolvers
 | 
			
		||||
 | 
			
		||||
import android.database.Cursor
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.mappers.BaseMangaGetResolver
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
 | 
			
		||||
 | 
			
		||||
class LibraryMangaGetResolver : DefaultGetResolver<LibraryManga>(), BaseMangaGetResolver {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        val INSTANCE = LibraryMangaGetResolver()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun mapFromCursor(cursor: Cursor): LibraryManga {
 | 
			
		||||
        val manga = LibraryManga()
 | 
			
		||||
 | 
			
		||||
        mapBaseFromCursor(manga, cursor)
 | 
			
		||||
        manga.unreadCount = cursor.getInt(cursor.getColumnIndexOrThrow(MangaTable.COMPUTED_COL_UNREAD_COUNT))
 | 
			
		||||
        manga.category = cursor.getInt(cursor.getColumnIndexOrThrow(MangaTable.COL_CATEGORY))
 | 
			
		||||
        manga.readCount = cursor.getInt(cursor.getColumnIndexOrThrow(MangaTable.COMPUTED_COL_READ_COUNT))
 | 
			
		||||
 | 
			
		||||
        return manga
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,33 +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
 | 
			
		||||
import kotlin.reflect.KProperty1
 | 
			
		||||
 | 
			
		||||
class MangaFlagsPutResolver(private val colName: String, private val fieldGetter: KProperty1<Manga, Int>) : 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(
 | 
			
		||||
            colName to fieldGetter.get(manga),
 | 
			
		||||
        )
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.database.tables
 | 
			
		||||
 | 
			
		||||
object CategoryTable {
 | 
			
		||||
 | 
			
		||||
    const val TABLE = "categories"
 | 
			
		||||
}
 | 
			
		||||
@@ -1,30 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.database.tables
 | 
			
		||||
 | 
			
		||||
object ChapterTable {
 | 
			
		||||
 | 
			
		||||
    const val TABLE = "chapters"
 | 
			
		||||
 | 
			
		||||
    const val COL_ID = "_id"
 | 
			
		||||
 | 
			
		||||
    const val COL_MANGA_ID = "manga_id"
 | 
			
		||||
 | 
			
		||||
    const val COL_URL = "url"
 | 
			
		||||
 | 
			
		||||
    const val COL_NAME = "name"
 | 
			
		||||
 | 
			
		||||
    const val COL_READ = "read"
 | 
			
		||||
 | 
			
		||||
    const val COL_SCANLATOR = "scanlator"
 | 
			
		||||
 | 
			
		||||
    const val COL_BOOKMARK = "bookmark"
 | 
			
		||||
 | 
			
		||||
    const val COL_DATE_FETCH = "date_fetch"
 | 
			
		||||
 | 
			
		||||
    const val COL_DATE_UPLOAD = "date_upload"
 | 
			
		||||
 | 
			
		||||
    const val COL_LAST_PAGE_READ = "last_page_read"
 | 
			
		||||
 | 
			
		||||
    const val COL_CHAPTER_NUMBER = "chapter_number"
 | 
			
		||||
 | 
			
		||||
    const val COL_SOURCE_ORDER = "source_order"
 | 
			
		||||
}
 | 
			
		||||
@@ -1,12 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.database.tables
 | 
			
		||||
 | 
			
		||||
object MangaCategoryTable {
 | 
			
		||||
 | 
			
		||||
    const val TABLE = "mangas_categories"
 | 
			
		||||
 | 
			
		||||
    const val COL_ID = "_id"
 | 
			
		||||
 | 
			
		||||
    const val COL_MANGA_ID = "manga_id"
 | 
			
		||||
 | 
			
		||||
    const val COL_CATEGORY_ID = "category_id"
 | 
			
		||||
}
 | 
			
		||||
@@ -1,50 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.database.tables
 | 
			
		||||
 | 
			
		||||
object MangaTable {
 | 
			
		||||
 | 
			
		||||
    const val TABLE = "mangas"
 | 
			
		||||
 | 
			
		||||
    const val COL_ID = "_id"
 | 
			
		||||
 | 
			
		||||
    const val COL_SOURCE = "source"
 | 
			
		||||
 | 
			
		||||
    const val COL_URL = "url"
 | 
			
		||||
 | 
			
		||||
    const val COL_ARTIST = "artist"
 | 
			
		||||
 | 
			
		||||
    const val COL_AUTHOR = "author"
 | 
			
		||||
 | 
			
		||||
    const val COL_DESCRIPTION = "description"
 | 
			
		||||
 | 
			
		||||
    const val COL_GENRE = "genre"
 | 
			
		||||
 | 
			
		||||
    const val COL_TITLE = "title"
 | 
			
		||||
 | 
			
		||||
    const val COL_STATUS = "status"
 | 
			
		||||
 | 
			
		||||
    const val COL_THUMBNAIL_URL = "thumbnail_url"
 | 
			
		||||
 | 
			
		||||
    const val COL_FAVORITE = "favorite"
 | 
			
		||||
 | 
			
		||||
    const val COL_LAST_UPDATE = "last_update"
 | 
			
		||||
 | 
			
		||||
    // Not actually used anymore
 | 
			
		||||
    const val COL_NEXT_UPDATE = "next_update"
 | 
			
		||||
 | 
			
		||||
    const val COL_DATE_ADDED = "date_added"
 | 
			
		||||
 | 
			
		||||
    const val COL_INITIALIZED = "initialized"
 | 
			
		||||
 | 
			
		||||
    const val COL_VIEWER = "viewer"
 | 
			
		||||
 | 
			
		||||
    const val COL_CHAPTER_FLAGS = "chapter_flags"
 | 
			
		||||
 | 
			
		||||
    const val COL_CATEGORY = "category"
 | 
			
		||||
 | 
			
		||||
    const val COL_COVER_LAST_MODIFIED = "cover_last_modified"
 | 
			
		||||
 | 
			
		||||
    // Not an actual value but computed when created
 | 
			
		||||
    const val COMPUTED_COL_UNREAD_COUNT = "unread_count"
 | 
			
		||||
 | 
			
		||||
    const val COMPUTED_COL_READ_COUNT = "read_count"
 | 
			
		||||
}
 | 
			
		||||
@@ -5,7 +5,6 @@ import com.hippo.unifile.UniFile
 | 
			
		||||
import com.jakewharton.rxrelay.BehaviorRelay
 | 
			
		||||
import eu.kanade.domain.category.interactor.GetCategories
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Chapter
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.data.download.model.Download
 | 
			
		||||
@@ -32,7 +31,6 @@ import uy.kohesive.injekt.injectLazy
 | 
			
		||||
 */
 | 
			
		||||
class DownloadManager(
 | 
			
		||||
    private val context: Context,
 | 
			
		||||
    private val db: DatabaseHelper = Injekt.get(),
 | 
			
		||||
    private val getCategories: GetCategories = Injekt.get(),
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ import android.content.Context
 | 
			
		||||
import androidx.core.content.edit
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.GetChapter
 | 
			
		||||
import eu.kanade.domain.chapter.model.toDbChapter
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetMangaById
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetManga
 | 
			
		||||
import eu.kanade.domain.manga.model.toDbManga
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.data.download.model.Download
 | 
			
		||||
@@ -34,7 +34,7 @@ class DownloadStore(
 | 
			
		||||
 | 
			
		||||
    private val json: Json by injectLazy()
 | 
			
		||||
 | 
			
		||||
    private val getMangaById: GetMangaById by injectLazy()
 | 
			
		||||
    private val getManga: GetManga by injectLazy()
 | 
			
		||||
    private val getChapter: GetChapter by injectLazy()
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -96,7 +96,7 @@ class DownloadStore(
 | 
			
		||||
            val cachedManga = mutableMapOf<Long, Manga?>()
 | 
			
		||||
            for ((mangaId, chapterId) in objs) {
 | 
			
		||||
                val manga = cachedManga.getOrPut(mangaId) {
 | 
			
		||||
                    runBlocking { getMangaById.await(mangaId)?.toDbManga() }
 | 
			
		||||
                    runBlocking { getManga.await(mangaId)?.toDbManga() }
 | 
			
		||||
                } ?: continue
 | 
			
		||||
                val source = sourceManager.get(manga.source) as? HttpSource ?: continue
 | 
			
		||||
                val chapter = runBlocking { getChapter.await(chapterId) }?.toDbChapter() ?: continue
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.data.download.model
 | 
			
		||||
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.GetChapter
 | 
			
		||||
import eu.kanade.domain.chapter.model.toDbChapter
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetMangaById
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetManga
 | 
			
		||||
import eu.kanade.domain.manga.model.toDbManga
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Chapter
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
@@ -69,11 +69,11 @@ data class Download(
 | 
			
		||||
        suspend fun fromChapterId(
 | 
			
		||||
            chapterId: Long,
 | 
			
		||||
            getChapter: GetChapter = Injekt.get(),
 | 
			
		||||
            getMangaById: GetMangaById = Injekt.get(),
 | 
			
		||||
            getManga: GetManga = Injekt.get(),
 | 
			
		||||
            sourceManager: SourceManager = Injekt.get(),
 | 
			
		||||
        ): Download? {
 | 
			
		||||
            val chapter = getChapter.await(chapterId) ?: return null
 | 
			
		||||
            val manga = getMangaById.await(chapter.mangaId) ?: return null
 | 
			
		||||
            val manga = getManga.await(chapter.mangaId) ?: return null
 | 
			
		||||
            val source = sourceManager.get(manga.source) as? HttpSource ?: return null
 | 
			
		||||
 | 
			
		||||
            return Download(source, manga.toDbManga(), chapter.toDbChapter())
 | 
			
		||||
 
 | 
			
		||||
@@ -13,16 +13,17 @@ import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
 | 
			
		||||
import eu.kanade.domain.chapter.model.toDbChapter
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetMangaById
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetLibraryManga
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetManga
 | 
			
		||||
import eu.kanade.domain.manga.interactor.UpdateManga
 | 
			
		||||
import eu.kanade.domain.manga.model.toMangaInfo
 | 
			
		||||
import eu.kanade.domain.manga.model.toMangaUpdate
 | 
			
		||||
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.data.cache.CoverCache
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Chapter
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
@@ -61,6 +62,7 @@ import kotlinx.coroutines.async
 | 
			
		||||
import kotlinx.coroutines.awaitAll
 | 
			
		||||
import kotlinx.coroutines.cancel
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import kotlinx.coroutines.runBlocking
 | 
			
		||||
import kotlinx.coroutines.supervisorScope
 | 
			
		||||
import kotlinx.coroutines.sync.Semaphore
 | 
			
		||||
import kotlinx.coroutines.sync.withPermit
 | 
			
		||||
@@ -84,13 +86,13 @@ import eu.kanade.domain.manga.model.Manga as DomainManga
 | 
			
		||||
 * destroyed.
 | 
			
		||||
 */
 | 
			
		||||
class LibraryUpdateService(
 | 
			
		||||
    val db: DatabaseHelper = Injekt.get(),
 | 
			
		||||
    val sourceManager: SourceManager = Injekt.get(),
 | 
			
		||||
    val preferences: PreferencesHelper = Injekt.get(),
 | 
			
		||||
    val downloadManager: DownloadManager = Injekt.get(),
 | 
			
		||||
    val trackManager: TrackManager = Injekt.get(),
 | 
			
		||||
    val coverCache: CoverCache = Injekt.get(),
 | 
			
		||||
    private val getMangaById: GetMangaById = Injekt.get(),
 | 
			
		||||
    private val getLibraryManga: GetLibraryManga = Injekt.get(),
 | 
			
		||||
    private val getManga: GetManga = Injekt.get(),
 | 
			
		||||
    private val updateManga: UpdateManga = Injekt.get(),
 | 
			
		||||
    private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
 | 
			
		||||
    private val getCategories: GetCategories = Injekt.get(),
 | 
			
		||||
@@ -255,7 +257,7 @@ class LibraryUpdateService(
 | 
			
		||||
     * @param categoryId the ID of the category to update, or -1 if no category specified.
 | 
			
		||||
     */
 | 
			
		||||
    fun addMangaToQueue(categoryId: Long) {
 | 
			
		||||
        val libraryManga = db.getLibraryMangas().executeAsBlocking()
 | 
			
		||||
        val libraryManga = runBlocking { getLibraryManga.await() }
 | 
			
		||||
 | 
			
		||||
        val listToUpdate = if (categoryId != -1L) {
 | 
			
		||||
            libraryManga.filter { it.category.toLong() == categoryId }
 | 
			
		||||
@@ -323,7 +325,7 @@ class LibraryUpdateService(
 | 
			
		||||
                                }
 | 
			
		||||
 | 
			
		||||
                                // Don't continue to update if manga not in library
 | 
			
		||||
                                manga.id?.let { getMangaById.await(it) } ?: return@forEach
 | 
			
		||||
                                manga.id?.let { getManga.await(it) } ?: return@forEach
 | 
			
		||||
 | 
			
		||||
                                withUpdateNotification(
 | 
			
		||||
                                    currentlyUpdatingManga,
 | 
			
		||||
@@ -434,7 +436,7 @@ class LibraryUpdateService(
 | 
			
		||||
            .map { it.toSChapter() }
 | 
			
		||||
 | 
			
		||||
        // Get manga from database to account for if it was removed during the update
 | 
			
		||||
        val dbManga = getMangaById.await(manga.id)
 | 
			
		||||
        val dbManga = getManga.await(manga.id)
 | 
			
		||||
            ?: return Pair(emptyList(), emptyList())
 | 
			
		||||
 | 
			
		||||
        // [dbmanga] was used so that manga data doesn't get overwritten
 | 
			
		||||
@@ -471,7 +473,14 @@ class LibraryUpdateService(
 | 
			
		||||
                                            mangaWithNotif.prepUpdateCover(coverCache, sManga, true)
 | 
			
		||||
                                            sManga.thumbnail_url?.let {
 | 
			
		||||
                                                mangaWithNotif.thumbnail_url = it
 | 
			
		||||
                                                db.insertManga(mangaWithNotif).executeAsBlocking()
 | 
			
		||||
                                                try {
 | 
			
		||||
                                                    updateManga.await(
 | 
			
		||||
                                                        mangaWithNotif.toDomainManga()!!
 | 
			
		||||
                                                            .toMangaUpdate(),
 | 
			
		||||
                                                    )
 | 
			
		||||
                                                } catch (e: Exception) {
 | 
			
		||||
                                                    logcat(LogPriority.ERROR) { "Manga don't exist anymore" }
 | 
			
		||||
                                                }
 | 
			
		||||
                                            }
 | 
			
		||||
                                        } catch (e: Throwable) {
 | 
			
		||||
                                            // Ignore errors and continue
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ import eu.kanade.domain.chapter.interactor.GetChapter
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.UpdateChapter
 | 
			
		||||
import eu.kanade.domain.chapter.model.toChapterUpdate
 | 
			
		||||
import eu.kanade.domain.chapter.model.toDbChapter
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetMangaById
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetManga
 | 
			
		||||
import eu.kanade.domain.manga.model.toDbManga
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.backup.BackupRestoreService
 | 
			
		||||
@@ -46,7 +46,7 @@ import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
 | 
			
		||||
 */
 | 
			
		||||
class NotificationReceiver : BroadcastReceiver() {
 | 
			
		||||
 | 
			
		||||
    private val getMangaById: GetMangaById by injectLazy()
 | 
			
		||||
    private val getManga: GetManga by injectLazy()
 | 
			
		||||
    private val getChapter: GetChapter by injectLazy()
 | 
			
		||||
    private val updateChapter: UpdateChapter by injectLazy()
 | 
			
		||||
    private val downloadManager: DownloadManager by injectLazy()
 | 
			
		||||
@@ -178,7 +178,7 @@ class NotificationReceiver : BroadcastReceiver() {
 | 
			
		||||
     * @param chapterId id of chapter
 | 
			
		||||
     */
 | 
			
		||||
    private fun openChapter(context: Context, mangaId: Long, chapterId: Long) {
 | 
			
		||||
        val manga = runBlocking { getMangaById.await(mangaId) }
 | 
			
		||||
        val manga = runBlocking { getManga.await(mangaId) }
 | 
			
		||||
        val chapter = runBlocking { getChapter.await(chapterId) }
 | 
			
		||||
        if (manga != null && chapter != null) {
 | 
			
		||||
            val intent = ReaderActivity.newIntent(context, manga.id, chapter.id).apply {
 | 
			
		||||
@@ -248,7 +248,7 @@ class NotificationReceiver : BroadcastReceiver() {
 | 
			
		||||
                .map {
 | 
			
		||||
                    val chapter = it.copy(read = true)
 | 
			
		||||
                    if (preferences.removeAfterMarkedAsRead()) {
 | 
			
		||||
                        val manga = getMangaById.await(mangaId)
 | 
			
		||||
                        val manga = getManga.await(mangaId)
 | 
			
		||||
                        if (manga != null) {
 | 
			
		||||
                            val source = sourceManager.get(manga.source)
 | 
			
		||||
                            if (source != null) {
 | 
			
		||||
@@ -270,7 +270,7 @@ class NotificationReceiver : BroadcastReceiver() {
 | 
			
		||||
     */
 | 
			
		||||
    private fun downloadChapters(chapterUrls: Array<String>, mangaId: Long) {
 | 
			
		||||
        launchIO {
 | 
			
		||||
            val manga = getMangaById.await(mangaId)?.toDbManga()
 | 
			
		||||
            val manga = getManga.await(mangaId)?.toDbManga()
 | 
			
		||||
            val chapters = chapterUrls.mapNotNull { getChapter.await(it, mangaId)?.toDbChapter() }
 | 
			
		||||
            if (manga != null && chapters.isNotEmpty()) {
 | 
			
		||||
                downloadManager.downloadChapters(manga, chapters)
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ import androidx.work.NetworkType
 | 
			
		||||
import androidx.work.OneTimeWorkRequestBuilder
 | 
			
		||||
import androidx.work.WorkManager
 | 
			
		||||
import androidx.work.WorkerParameters
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetMangaById
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetManga
 | 
			
		||||
import eu.kanade.domain.track.interactor.GetTracks
 | 
			
		||||
import eu.kanade.domain.track.interactor.InsertTrack
 | 
			
		||||
import eu.kanade.domain.track.model.toDbTrack
 | 
			
		||||
@@ -26,7 +26,7 @@ class DelayedTrackingUpdateJob(context: Context, workerParams: WorkerParameters)
 | 
			
		||||
    CoroutineWorker(context, workerParams) {
 | 
			
		||||
 | 
			
		||||
    override suspend fun doWork(): Result {
 | 
			
		||||
        val getMangaById = Injekt.get<GetMangaById>()
 | 
			
		||||
        val getManga = Injekt.get<GetManga>()
 | 
			
		||||
        val getTracks = Injekt.get<GetTracks>()
 | 
			
		||||
        val insertTrack = Injekt.get<InsertTrack>()
 | 
			
		||||
 | 
			
		||||
@@ -35,7 +35,7 @@ class DelayedTrackingUpdateJob(context: Context, workerParams: WorkerParameters)
 | 
			
		||||
 | 
			
		||||
        withContext(Dispatchers.IO) {
 | 
			
		||||
            val tracks = delayedTrackingStore.getItems().mapNotNull {
 | 
			
		||||
                val manga = getMangaById.await(it.mangaId) ?: return@withContext
 | 
			
		||||
                val manga = getManga.await(it.mangaId) ?: return@withContext
 | 
			
		||||
                getTracks.await(manga.id)
 | 
			
		||||
                    .find { track -> track.id == it.trackId }
 | 
			
		||||
                    ?.copy(lastChapterRead = it.lastChapterRead.toDouble())
 | 
			
		||||
 
 | 
			
		||||
@@ -6,8 +6,9 @@ import androidx.core.view.isVisible
 | 
			
		||||
import com.bluelinelabs.conductor.Controller
 | 
			
		||||
import com.bluelinelabs.conductor.RouterTransaction
 | 
			
		||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetManga
 | 
			
		||||
import eu.kanade.domain.manga.model.toDbManga
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.toDomainManga
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 | 
			
		||||
@@ -18,6 +19,7 @@ import eu.kanade.tachiyomi.ui.browse.migration.MigrationFlags
 | 
			
		||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchPresenter
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.MangaController
 | 
			
		||||
import kotlinx.coroutines.runBlocking
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
@@ -27,9 +29,11 @@ class SearchController(
 | 
			
		||||
) : GlobalSearchController(manga?.title) {
 | 
			
		||||
 | 
			
		||||
    constructor(mangaId: Long) : this(
 | 
			
		||||
        Injekt.get<DatabaseHelper>()
 | 
			
		||||
            .getManga(mangaId)
 | 
			
		||||
            .executeAsBlocking(),
 | 
			
		||||
        runBlocking {
 | 
			
		||||
            Injekt.get<GetManga>()
 | 
			
		||||
                .await(mangaId)
 | 
			
		||||
                ?.toDbManga()
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    private var newManga: Manga? = null
 | 
			
		||||
 
 | 
			
		||||
@@ -7,11 +7,14 @@ import eu.kanade.domain.category.interactor.SetMangaCategories
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetDuplicateLibraryManga
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetManga
 | 
			
		||||
import eu.kanade.domain.manga.interactor.InsertManga
 | 
			
		||||
import eu.kanade.domain.manga.interactor.UpdateManga
 | 
			
		||||
import eu.kanade.domain.manga.model.toDbManga
 | 
			
		||||
import eu.kanade.domain.manga.model.toMangaUpdate
 | 
			
		||||
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.database.DatabaseHelper
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.toDomainManga
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.toMangaInfo
 | 
			
		||||
@@ -67,13 +70,15 @@ open class BrowseSourcePresenter(
 | 
			
		||||
    private val sourceId: Long,
 | 
			
		||||
    searchQuery: String? = null,
 | 
			
		||||
    private val sourceManager: SourceManager = Injekt.get(),
 | 
			
		||||
    private val db: DatabaseHelper = Injekt.get(),
 | 
			
		||||
    private val prefs: PreferencesHelper = Injekt.get(),
 | 
			
		||||
    private val coverCache: CoverCache = Injekt.get(),
 | 
			
		||||
    private val getManga: GetManga = Injekt.get(),
 | 
			
		||||
    private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(),
 | 
			
		||||
    private val getCategories: GetCategories = Injekt.get(),
 | 
			
		||||
    private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
 | 
			
		||||
    private val setMangaCategories: SetMangaCategories = Injekt.get(),
 | 
			
		||||
    private val insertManga: InsertManga = Injekt.get(),
 | 
			
		||||
    private val updateManga: UpdateManga = Injekt.get(),
 | 
			
		||||
    private val insertTrack: InsertTrack = Injekt.get(),
 | 
			
		||||
    private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay = Injekt.get(),
 | 
			
		||||
) : BasePresenter<BrowseSourceController>() {
 | 
			
		||||
@@ -208,19 +213,22 @@ open class BrowseSourcePresenter(
 | 
			
		||||
     * @return a manga from the database.
 | 
			
		||||
     */
 | 
			
		||||
    private fun networkToLocalManga(sManga: SManga, sourceId: Long): Manga {
 | 
			
		||||
        var localManga = db.getManga(sManga.url, sourceId).executeAsBlocking()
 | 
			
		||||
        var localManga = runBlocking { getManga.await(sManga.url, sourceId) }
 | 
			
		||||
        if (localManga == null) {
 | 
			
		||||
            val newManga = Manga.create(sManga.url, sManga.title, sourceId)
 | 
			
		||||
            newManga.copyFrom(sManga)
 | 
			
		||||
            val result = db.insertManga(newManga).executeAsBlocking()
 | 
			
		||||
            newManga.id = result.insertedId()
 | 
			
		||||
            localManga = newManga
 | 
			
		||||
            newManga.id = -1
 | 
			
		||||
            val result = runBlocking {
 | 
			
		||||
                val id = insertManga.await(newManga.toDomainManga()!!)
 | 
			
		||||
                getManga.await(id!!)
 | 
			
		||||
            }
 | 
			
		||||
            localManga = result
 | 
			
		||||
        } else if (!localManga.favorite) {
 | 
			
		||||
            // if the manga isn't a favorite, set its display title from source
 | 
			
		||||
            // if it later becomes a favorite, updated title will go to db
 | 
			
		||||
            localManga.title = sManga.title
 | 
			
		||||
            localManga = localManga.copy(title = sManga.title)
 | 
			
		||||
        }
 | 
			
		||||
        return localManga
 | 
			
		||||
        return localManga?.toDbManga()!!
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -255,7 +263,11 @@ open class BrowseSourcePresenter(
 | 
			
		||||
            val networkManga = source.getMangaDetails(manga.toMangaInfo())
 | 
			
		||||
            manga.copyFrom(networkManga.toSManga())
 | 
			
		||||
            manga.initialized = true
 | 
			
		||||
            db.insertManga(manga).executeAsBlocking()
 | 
			
		||||
            updateManga.await(
 | 
			
		||||
                manga
 | 
			
		||||
                    .toDomainManga()
 | 
			
		||||
                    ?.toMangaUpdate()!!,
 | 
			
		||||
            )
 | 
			
		||||
        } catch (e: Exception) {
 | 
			
		||||
            logcat(LogPriority.ERROR, e)
 | 
			
		||||
        }
 | 
			
		||||
@@ -282,7 +294,13 @@ open class BrowseSourcePresenter(
 | 
			
		||||
            autoAddTrack(manga)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        db.insertManga(manga).executeAsBlocking()
 | 
			
		||||
        runBlocking {
 | 
			
		||||
            updateManga.await(
 | 
			
		||||
                manga
 | 
			
		||||
                    .toDomainManga()
 | 
			
		||||
                    ?.toMangaUpdate()!!,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun autoAddTrack(manga: Manga) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,13 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.browse.source.globalsearch
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetManga
 | 
			
		||||
import eu.kanade.domain.manga.interactor.InsertManga
 | 
			
		||||
import eu.kanade.domain.manga.interactor.UpdateManga
 | 
			
		||||
import eu.kanade.domain.manga.model.toDbManga
 | 
			
		||||
import eu.kanade.domain.manga.model.toMangaUpdate
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.toDomainManga
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.toMangaInfo
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 | 
			
		||||
import eu.kanade.tachiyomi.extension.ExtensionManager
 | 
			
		||||
@@ -16,6 +21,7 @@ import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
 | 
			
		||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
 | 
			
		||||
import eu.kanade.tachiyomi.util.lang.runAsObservable
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.logcat
 | 
			
		||||
import kotlinx.coroutines.runBlocking
 | 
			
		||||
import logcat.LogPriority
 | 
			
		||||
import rx.Observable
 | 
			
		||||
import rx.Subscription
 | 
			
		||||
@@ -38,8 +44,10 @@ open class GlobalSearchPresenter(
 | 
			
		||||
    private val initialQuery: String? = "",
 | 
			
		||||
    private val initialExtensionFilter: String? = null,
 | 
			
		||||
    val sourceManager: SourceManager = Injekt.get(),
 | 
			
		||||
    val db: DatabaseHelper = Injekt.get(),
 | 
			
		||||
    val preferences: PreferencesHelper = Injekt.get(),
 | 
			
		||||
    private val getManga: GetManga = Injekt.get(),
 | 
			
		||||
    private val insertManga: InsertManga = Injekt.get(),
 | 
			
		||||
    private val updateManga: UpdateManga = Injekt.get(),
 | 
			
		||||
) : BasePresenter<GlobalSearchController>() {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -248,7 +256,7 @@ open class GlobalSearchPresenter(
 | 
			
		||||
        val networkManga = source.getMangaDetails(manga.toMangaInfo())
 | 
			
		||||
        manga.copyFrom(networkManga.toSManga())
 | 
			
		||||
        manga.initialized = true
 | 
			
		||||
        db.insertManga(manga).executeAsBlocking()
 | 
			
		||||
        runBlocking { updateManga.await(manga.toDomainManga()!!.toMangaUpdate()) }
 | 
			
		||||
        return manga
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -260,18 +268,21 @@ open class GlobalSearchPresenter(
 | 
			
		||||
     * @return a manga from the database.
 | 
			
		||||
     */
 | 
			
		||||
    protected open fun networkToLocalManga(sManga: SManga, sourceId: Long): Manga {
 | 
			
		||||
        var localManga = db.getManga(sManga.url, sourceId).executeAsBlocking()
 | 
			
		||||
        var localManga = runBlocking { getManga.await(sManga.url, sourceId) }
 | 
			
		||||
        if (localManga == null) {
 | 
			
		||||
            val newManga = Manga.create(sManga.url, sManga.title, sourceId)
 | 
			
		||||
            newManga.copyFrom(sManga)
 | 
			
		||||
            val result = db.insertManga(newManga).executeAsBlocking()
 | 
			
		||||
            newManga.id = result.insertedId()
 | 
			
		||||
            localManga = newManga
 | 
			
		||||
            newManga.id = -1
 | 
			
		||||
            val result = runBlocking {
 | 
			
		||||
                val id = insertManga.await(newManga.toDomainManga()!!)
 | 
			
		||||
                getManga.await(id!!)
 | 
			
		||||
            }
 | 
			
		||||
            localManga = result
 | 
			
		||||
        } else if (!localManga.favorite) {
 | 
			
		||||
            // if the manga isn't a favorite, set its display title from source
 | 
			
		||||
            // if it later becomes a favorite, updated title will go to db
 | 
			
		||||
            localManga.title = sManga.title
 | 
			
		||||
            localManga = localManga.copy(title = sManga.title)
 | 
			
		||||
        }
 | 
			
		||||
        return localManga
 | 
			
		||||
        return localManga!!.toDbManga()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,13 +11,13 @@ import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.UpdateChapter
 | 
			
		||||
import eu.kanade.domain.chapter.model.ChapterUpdate
 | 
			
		||||
import eu.kanade.domain.chapter.model.toDbChapter
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetLibraryManga
 | 
			
		||||
import eu.kanade.domain.manga.interactor.UpdateManga
 | 
			
		||||
import eu.kanade.domain.manga.model.Manga
 | 
			
		||||
import eu.kanade.domain.manga.model.MangaUpdate
 | 
			
		||||
import eu.kanade.domain.track.interactor.GetTracks
 | 
			
		||||
import eu.kanade.tachiyomi.data.cache.CoverCache
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Chapter
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
 | 
			
		||||
import eu.kanade.tachiyomi.data.download.DownloadManager
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.TrackManager
 | 
			
		||||
@@ -60,6 +60,7 @@ typealias LibraryMap = Map<Long, List<LibraryItem>>
 | 
			
		||||
 */
 | 
			
		||||
class LibraryPresenter(
 | 
			
		||||
    private val handler: DatabaseHandler = Injekt.get(),
 | 
			
		||||
    private val getLibraryManga: GetLibraryManga = Injekt.get(),
 | 
			
		||||
    private val getTracks: GetTracks = Injekt.get(),
 | 
			
		||||
    private val getCategories: GetCategories = Injekt.get(),
 | 
			
		||||
    private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
 | 
			
		||||
@@ -410,35 +411,7 @@ class LibraryPresenter(
 | 
			
		||||
        val defaultLibraryDisplayMode = preferences.libraryDisplayMode()
 | 
			
		||||
        val shouldSetFromCategory = preferences.categorizedDisplaySettings()
 | 
			
		||||
 | 
			
		||||
        // TODO: Move this to domain/data layer
 | 
			
		||||
        return handler
 | 
			
		||||
            .subscribeToList {
 | 
			
		||||
                mangasQueries.getLibrary { _id: Long, source: Long, url: String, artist: String?, author: String?, description: String?, genre: List<String>?, title: String, status: Long, thumbnail_url: String?, favorite: Boolean, last_update: Long?, next_update: Long?, initialized: Boolean, viewer: Long, chapter_flags: Long, cover_last_modified: Long, date_added: Long, unread_count: Long, read_count: Long, category: Long ->
 | 
			
		||||
                    LibraryManga().apply {
 | 
			
		||||
                        this.id = _id
 | 
			
		||||
                        this.source = source
 | 
			
		||||
                        this.url = url
 | 
			
		||||
                        this.artist = artist
 | 
			
		||||
                        this.author = author
 | 
			
		||||
                        this.description = description
 | 
			
		||||
                        this.genre = genre?.joinToString()
 | 
			
		||||
                        this.title = title
 | 
			
		||||
                        this.status = status.toInt()
 | 
			
		||||
                        this.thumbnail_url = thumbnail_url
 | 
			
		||||
                        this.favorite = favorite
 | 
			
		||||
                        this.last_update = last_update ?: 0
 | 
			
		||||
                        this.initialized = initialized
 | 
			
		||||
                        this.viewer_flags = viewer.toInt()
 | 
			
		||||
                        this.chapter_flags = chapter_flags.toInt()
 | 
			
		||||
                        this.cover_last_modified = cover_last_modified
 | 
			
		||||
                        this.date_added = date_added
 | 
			
		||||
                        this.unreadCount = unread_count.toInt()
 | 
			
		||||
                        this.readCount = read_count.toInt()
 | 
			
		||||
                        this.category = category.toInt()
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .asObservable()
 | 
			
		||||
        return getLibraryManga.subscribe().asObservable()
 | 
			
		||||
            .map { list ->
 | 
			
		||||
                list.map { libraryManga ->
 | 
			
		||||
                    // Display mode based on user preference: take it from global library setting or category
 | 
			
		||||
 
 | 
			
		||||
@@ -149,7 +149,7 @@ class MangaPresenter(
 | 
			
		||||
 | 
			
		||||
        presenterScope.launchIO {
 | 
			
		||||
            if (!getMangaAndChapters.awaitManga(mangaId).favorite) {
 | 
			
		||||
                ChapterSettingsHelper.applySettingDefaults(mangaId, setMangaChapterFlags)
 | 
			
		||||
                ChapterSettingsHelper.applySettingDefaults(mangaId)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            getMangaAndChapters.subscribe(mangaId)
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ import androidx.core.os.bundleOf
 | 
			
		||||
import coil.imageLoader
 | 
			
		||||
import coil.request.ImageRequest
 | 
			
		||||
import coil.size.Size
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetMangaById
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetManga
 | 
			
		||||
import eu.kanade.domain.manga.interactor.UpdateManga
 | 
			
		||||
import eu.kanade.domain.manga.model.Manga
 | 
			
		||||
import eu.kanade.domain.manga.model.hasCustomCover
 | 
			
		||||
@@ -161,7 +161,7 @@ class MangaFullCoverDialog : FullComposeController<MangaFullCoverDialog.MangaFul
 | 
			
		||||
 | 
			
		||||
    inner class MangaFullCoverPresenter(
 | 
			
		||||
        private val mangaId: Long,
 | 
			
		||||
        private val getMangaById: GetMangaById = Injekt.get(),
 | 
			
		||||
        private val getManga: GetManga = Injekt.get(),
 | 
			
		||||
    ) : Presenter<MangaFullCoverDialog>() {
 | 
			
		||||
 | 
			
		||||
        private var presenterScope: CoroutineScope = MainScope()
 | 
			
		||||
@@ -176,7 +176,7 @@ class MangaFullCoverDialog : FullComposeController<MangaFullCoverDialog.MangaFul
 | 
			
		||||
        override fun onCreate(savedState: Bundle?) {
 | 
			
		||||
            super.onCreate(savedState)
 | 
			
		||||
            presenterScope.launchIO {
 | 
			
		||||
                getMangaById.subscribe(mangaId)
 | 
			
		||||
                getManga.subscribe(mangaId)
 | 
			
		||||
                    .collect { _mangaFlow.value = it }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -11,13 +11,13 @@ import eu.kanade.domain.chapter.model.ChapterUpdate
 | 
			
		||||
import eu.kanade.domain.chapter.model.toDbChapter
 | 
			
		||||
import eu.kanade.domain.history.interactor.UpsertHistory
 | 
			
		||||
import eu.kanade.domain.history.model.HistoryUpdate
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetMangaById
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetManga
 | 
			
		||||
import eu.kanade.domain.manga.interactor.SetMangaViewerFlags
 | 
			
		||||
import eu.kanade.domain.manga.model.isLocal
 | 
			
		||||
import eu.kanade.domain.manga.model.toDbManga
 | 
			
		||||
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.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.toDomainManga
 | 
			
		||||
import eu.kanade.tachiyomi.data.download.DownloadManager
 | 
			
		||||
@@ -68,17 +68,17 @@ import java.util.concurrent.TimeUnit
 | 
			
		||||
 * Presenter used by the activity to perform background operations.
 | 
			
		||||
 */
 | 
			
		||||
class ReaderPresenter(
 | 
			
		||||
    private val db: DatabaseHelper = Injekt.get(),
 | 
			
		||||
    private val sourceManager: SourceManager = Injekt.get(),
 | 
			
		||||
    private val downloadManager: DownloadManager = Injekt.get(),
 | 
			
		||||
    private val preferences: PreferencesHelper = Injekt.get(),
 | 
			
		||||
    private val delayedTrackingStore: DelayedTrackingStore = Injekt.get(),
 | 
			
		||||
    private val getMangaById: GetMangaById = Injekt.get(),
 | 
			
		||||
    private val getManga: GetManga = Injekt.get(),
 | 
			
		||||
    private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
 | 
			
		||||
    private val getTracks: GetTracks = Injekt.get(),
 | 
			
		||||
    private val insertTrack: InsertTrack = Injekt.get(),
 | 
			
		||||
    private val upsertHistory: UpsertHistory = Injekt.get(),
 | 
			
		||||
    private val updateChapter: UpdateChapter = Injekt.get(),
 | 
			
		||||
    private val setMangaViewerFlags: SetMangaViewerFlags = Injekt.get(),
 | 
			
		||||
) : BasePresenter<ReaderActivity>() {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -242,7 +242,7 @@ class ReaderPresenter(
 | 
			
		||||
 | 
			
		||||
        launchIO {
 | 
			
		||||
            try {
 | 
			
		||||
                val manga = getMangaById.await(mangaId)
 | 
			
		||||
                val manga = getManga.await(mangaId)
 | 
			
		||||
                withUIContext {
 | 
			
		||||
                    manga?.let { init(it.toDbManga(), initialChapterId) }
 | 
			
		||||
                }
 | 
			
		||||
@@ -570,7 +570,9 @@ class ReaderPresenter(
 | 
			
		||||
    fun setMangaReadingMode(readingModeType: Int) {
 | 
			
		||||
        val manga = manga ?: return
 | 
			
		||||
        manga.readingModeType = readingModeType
 | 
			
		||||
        db.updateViewerFlags(manga).executeAsBlocking()
 | 
			
		||||
        runBlocking {
 | 
			
		||||
            setMangaViewerFlags.awaitSetMangaReadingMode(manga.id!!.toLong(), readingModeType.toLong())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Observable.timer(250, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
 | 
			
		||||
            .subscribeFirst({ view, _ ->
 | 
			
		||||
@@ -605,7 +607,9 @@ class ReaderPresenter(
 | 
			
		||||
    fun setMangaOrientationType(rotationType: Int) {
 | 
			
		||||
        val manga = manga ?: return
 | 
			
		||||
        manga.orientationType = rotationType
 | 
			
		||||
        db.updateViewerFlags(manga).executeAsBlocking()
 | 
			
		||||
        runBlocking {
 | 
			
		||||
            setMangaViewerFlags.awaitSetOrientationType(manga.id!!.toLong(), rotationType.toLong())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        logcat(LogPriority.INFO) { "Manga orientation is ${manga.orientationType}" }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
package eu.kanade.tachiyomi.util.chapter
 | 
			
		||||
 | 
			
		||||
import eu.kanade.domain.manga.interactor.GetFavorites
 | 
			
		||||
import eu.kanade.domain.manga.interactor.SetMangaChapterFlags
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 | 
			
		||||
import eu.kanade.tachiyomi.util.lang.launchIO
 | 
			
		||||
@@ -10,7 +10,8 @@ import uy.kohesive.injekt.injectLazy
 | 
			
		||||
object ChapterSettingsHelper {
 | 
			
		||||
 | 
			
		||||
    private val prefs: PreferencesHelper by injectLazy()
 | 
			
		||||
    private val db: DatabaseHelper by injectLazy()
 | 
			
		||||
    private val getFavorites: GetFavorites by injectLazy()
 | 
			
		||||
    private val setMangaChapterFlags: SetMangaChapterFlags by injectLazy()
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the global Chapter Settings in Preferences.
 | 
			
		||||
@@ -23,19 +24,20 @@ object ChapterSettingsHelper {
 | 
			
		||||
     * Updates a single manga's Chapter Settings to match what's set in Preferences.
 | 
			
		||||
     */
 | 
			
		||||
    fun applySettingDefaults(manga: Manga) {
 | 
			
		||||
        with(manga) {
 | 
			
		||||
            readFilter = prefs.filterChapterByRead()
 | 
			
		||||
            downloadedFilter = prefs.filterChapterByDownloaded()
 | 
			
		||||
            bookmarkedFilter = prefs.filterChapterByBookmarked()
 | 
			
		||||
            sorting = prefs.sortChapterBySourceOrNumber()
 | 
			
		||||
            displayMode = prefs.displayChapterByNameOrNumber()
 | 
			
		||||
            setChapterOrder(prefs.sortChapterByAscendingOrDescending())
 | 
			
		||||
        launchIO {
 | 
			
		||||
            setMangaChapterFlags.awaitSetAllFlags(
 | 
			
		||||
                mangaId = manga.id!!,
 | 
			
		||||
                unreadFilter = prefs.filterChapterByRead().toLong(),
 | 
			
		||||
                downloadedFilter = prefs.filterChapterByDownloaded().toLong(),
 | 
			
		||||
                bookmarkedFilter = prefs.filterChapterByBookmarked().toLong(),
 | 
			
		||||
                sortingMode = prefs.sortChapterBySourceOrNumber().toLong(),
 | 
			
		||||
                sortingDirection = prefs.sortChapterByAscendingOrDescending().toLong(),
 | 
			
		||||
                displayMode = prefs.displayChapterByNameOrNumber().toLong(),
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        db.updateChapterFlags(manga).executeAsBlocking()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun applySettingDefaults(mangaId: Long, setMangaChapterFlags: SetMangaChapterFlags) {
 | 
			
		||||
    suspend fun applySettingDefaults(mangaId: Long) {
 | 
			
		||||
        setMangaChapterFlags.awaitSetAllFlags(
 | 
			
		||||
            mangaId = mangaId,
 | 
			
		||||
            unreadFilter = prefs.filterChapterByRead().toLong(),
 | 
			
		||||
@@ -52,21 +54,18 @@ object ChapterSettingsHelper {
 | 
			
		||||
     */
 | 
			
		||||
    fun updateAllMangasWithGlobalDefaults() {
 | 
			
		||||
        launchIO {
 | 
			
		||||
            val updatedMangas = db.getFavoriteMangas()
 | 
			
		||||
                .executeAsBlocking()
 | 
			
		||||
            getFavorites.await()
 | 
			
		||||
                .map { manga ->
 | 
			
		||||
                    with(manga) {
 | 
			
		||||
                        readFilter = prefs.filterChapterByRead()
 | 
			
		||||
                        downloadedFilter = prefs.filterChapterByDownloaded()
 | 
			
		||||
                        bookmarkedFilter = prefs.filterChapterByBookmarked()
 | 
			
		||||
                        sorting = prefs.sortChapterBySourceOrNumber()
 | 
			
		||||
                        displayMode = prefs.displayChapterByNameOrNumber()
 | 
			
		||||
                        setChapterOrder(prefs.sortChapterByAscendingOrDescending())
 | 
			
		||||
                    }
 | 
			
		||||
                    manga
 | 
			
		||||
                    setMangaChapterFlags.awaitSetAllFlags(
 | 
			
		||||
                        mangaId = manga.id,
 | 
			
		||||
                        unreadFilter = prefs.filterChapterByRead().toLong(),
 | 
			
		||||
                        downloadedFilter = prefs.filterChapterByDownloaded().toLong(),
 | 
			
		||||
                        bookmarkedFilter = prefs.filterChapterByBookmarked().toLong(),
 | 
			
		||||
                        sortingMode = prefs.sortChapterBySourceOrNumber().toLong(),
 | 
			
		||||
                        sortingDirection = prefs.sortChapterByAscendingOrDescending().toLong(),
 | 
			
		||||
                        displayMode = prefs.displayChapterByNameOrNumber().toLong(),
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            db.updateChapterFlags(updatedMangas).executeAsBlocking()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user