diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaChapter.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaChapter.kt index c6b280602e..f4136aecdf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaChapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaChapter.kt @@ -2,4 +2,78 @@ package eu.kanade.tachiyomi.data.database.models import eu.kanade.tachiyomi.domain.manga.models.Manga -class MangaChapter(val manga: Manga, val chapter: Chapter) +class MangaChapter(val manga: Manga, val chapter: Chapter) { + companion object { + fun mapper( + mangaId: Long, + source: Long, + mangaUrl: String, + artist: String?, + author: String?, + description: String?, + genre: String?, + title: String, + status: Long, + thumbnailUrl: String?, + favorite: Long, + lastUpdate: Long?, + initialized: Boolean, + viewer: Long, + hideTitle: Long, + chapterFlags: Long, + dateAdded: Long?, + filteredScanlators: String?, + updateStrategy: Long, + chapterId: Long, + _mangaId: Long, + chapterUrl: String, + name: String, + scanlator: String?, + read: Boolean, + bookmark: Boolean, + lastPageRead: Long, + pagesLeft: Long, + chapterNumber: Double, + sourceOrder: Long, + dateFetch: Long, + dateUpload: Long, + ) = MangaChapter( + Manga.mapper( + id = mangaId, + source = source, + url = mangaUrl, + artist = artist, + author = author, + description = description, + genre = genre, + title = title, + status = status, + thumbnailUrl = thumbnailUrl, + favorite = favorite, + lastUpdate = lastUpdate, + initialized = initialized, + viewerFlags = viewer, + hideTitle = hideTitle, + chapterFlags = chapterFlags, + dateAdded = dateAdded, + filteredScanlators = filteredScanlators, + updateStrategy = updateStrategy, + ), + Chapter.mapper( + id = chapterId, + mangaId = _mangaId, + url = chapterUrl, + name = name, + scanlator = scanlator, + read = read, + bookmark = bookmark, + lastPageRead = lastPageRead, + pagesLeft = pagesLeft, + chapterNumber = chapterNumber, + sourceOrder = sourceOrder, + dateFetch = dateFetch, + dateUpload = dateUpload, + ), + ) + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt index 1d8c8a885c..360c836974 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt @@ -1,16 +1,12 @@ 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.Chapter -import eu.kanade.tachiyomi.data.database.models.MangaChapter import eu.kanade.tachiyomi.data.database.resolvers.ChapterKnownBackupPutResolver import eu.kanade.tachiyomi.data.database.resolvers.ChapterProgressPutResolver -import eu.kanade.tachiyomi.data.database.resolvers.MangaChapterGetResolver import eu.kanade.tachiyomi.data.database.tables.ChapterTable import eu.kanade.tachiyomi.domain.manga.models.Manga -import eu.kanade.tachiyomi.util.lang.sqLite interface ChapterQueries : DbProvider { @@ -27,17 +23,6 @@ interface ChapterQueries : DbProvider { ) .prepare() - fun getRecentChapters(search: String = "", offset: Int, isResuming: Boolean) = db.get() - .listOfObjects(MangaChapter::class.java) - .withQuery( - RawQuery.builder() - .query(getRecentsQuery(search.sqLite, offset, isResuming)) - .observesTables(ChapterTable.TABLE) - .build(), - ) - .withGetResolver(MangaChapterGetResolver.INSTANCE) - .prepare() - fun getChapter(id: Long) = db.get() .`object`(Chapter::class.java) .withQuery( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsPresenter.kt index f860152829..67a4fa35f8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsPresenter.kt @@ -22,6 +22,14 @@ import eu.kanade.tachiyomi.util.system.launchIO import eu.kanade.tachiyomi.util.system.launchUI import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.withUIContext +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Date +import java.util.Locale +import java.util.TreeMap +import java.util.concurrent.TimeUnit +import kotlin.math.abs +import kotlin.math.roundToInt import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.flow.drop @@ -33,14 +41,10 @@ import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy import yokai.domain.chapter.interactor.GetChapter +import yokai.domain.chapter.interactor.RecentChapter import yokai.domain.recents.RecentsPreferences import yokai.domain.ui.UiPreferences import yokai.i18n.MR -import java.text.SimpleDateFormat -import java.util.* -import java.util.concurrent.* -import kotlin.math.abs -import kotlin.math.roundToInt class RecentsPresenter( val uiPreferences: UiPreferences = Injekt.get(), @@ -51,6 +55,7 @@ class RecentsPresenter( private val chapterFilter: ChapterFilter = Injekt.get(), ) : BaseCoroutinePresenter(), DownloadQueue.DownloadListener { private val getChapter: GetChapter by injectLazy() + private val recentChapter: RecentChapter by injectLazy() private var recentsJob: Job? = null var recentItems = listOf() @@ -235,11 +240,12 @@ class RecentsPresenter( dateFormat.applyPattern("yyyy-MM-dd") dateFormat.calendar.firstDayOfWeek = Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - db.getRecentChapters( - query, - if (isCustom) ENDLESS_LIMIT else pageOffset, + recentChapter.await( + true, !updatePageCount && !isOnFirstPage, - ).executeOnIO().groupBy { + query, + (if (isCustom) ENDLESS_LIMIT else pageOffset).toLong(), + ).groupBy { val date = it.chapter.date_fetch it.manga.id to if (date <= 0L) "-1" else dateFormat.format(Date(date)) } diff --git a/app/src/main/java/yokai/core/di/DomainModule.kt b/app/src/main/java/yokai/core/di/DomainModule.kt index 7d8aaa375c..3feda772a9 100644 --- a/app/src/main/java/yokai/core/di/DomainModule.kt +++ b/app/src/main/java/yokai/core/di/DomainModule.kt @@ -17,6 +17,7 @@ import yokai.domain.chapter.interactor.DeleteChapter import yokai.domain.chapter.interactor.GetAvailableScanlators import yokai.domain.chapter.interactor.GetChapter import yokai.domain.chapter.interactor.InsertChapter +import yokai.domain.chapter.interactor.RecentChapter import yokai.domain.chapter.interactor.UpdateChapter import yokai.domain.extension.interactor.TrustExtension import yokai.domain.extension.repo.ExtensionRepoRepository @@ -66,6 +67,7 @@ class DomainModule : InjektModule { addFactory { GetAvailableScanlators(get()) } addFactory { GetChapter(get()) } addFactory { InsertChapter(get()) } + addFactory { RecentChapter(get()) } addFactory { UpdateChapter(get()) } addSingletonFactory { CategoryRepositoryImpl(get()) } diff --git a/app/src/main/java/yokai/data/chapter/ChapterRepositoryImpl.kt b/app/src/main/java/yokai/data/chapter/ChapterRepositoryImpl.kt index 7c7274122d..836abdcfde 100644 --- a/app/src/main/java/yokai/data/chapter/ChapterRepositoryImpl.kt +++ b/app/src/main/java/yokai/data/chapter/ChapterRepositoryImpl.kt @@ -2,6 +2,7 @@ package yokai.data.chapter import co.touchlab.kermit.Logger import eu.kanade.tachiyomi.data.database.models.Chapter +import eu.kanade.tachiyomi.data.database.models.MangaChapter import eu.kanade.tachiyomi.util.system.toInt import kotlinx.coroutines.flow.Flow import yokai.data.DatabaseHandler @@ -15,6 +16,9 @@ class ChapterRepositoryImpl(private val handler: DatabaseHandler) : ChapterRepos override fun getChaptersAsFlow(mangaId: Long, filterScanlators: Boolean): Flow> = handler.subscribeToList { chaptersQueries.getChaptersByMangaId(mangaId, filterScanlators.toInt().toLong(), Chapter::mapper) } + override suspend fun getRecents(filterScanlators: Boolean, search: String, limit: Long, offset: Long): List = + handler.awaitList { chaptersQueries.getRecents(search, filterScanlators.toInt().toLong(), limit, offset, MangaChapter::mapper) } + override suspend fun getScanlatorsByChapter(mangaId: Long): List = handler.awaitList { chaptersQueries.getScanlatorsByMangaId(mangaId) { it.orEmpty() } } diff --git a/app/src/main/java/yokai/domain/chapter/ChapterRepository.kt b/app/src/main/java/yokai/domain/chapter/ChapterRepository.kt index bdc5829a71..4c0f84f9a6 100644 --- a/app/src/main/java/yokai/domain/chapter/ChapterRepository.kt +++ b/app/src/main/java/yokai/domain/chapter/ChapterRepository.kt @@ -1,6 +1,7 @@ package yokai.domain.chapter import eu.kanade.tachiyomi.data.database.models.Chapter +import eu.kanade.tachiyomi.data.database.models.MangaChapter import kotlinx.coroutines.flow.Flow import yokai.domain.chapter.models.ChapterUpdate @@ -8,6 +9,8 @@ interface ChapterRepository { suspend fun getChapters(mangaId: Long, filterScanlators: Boolean): List fun getChaptersAsFlow(mangaId: Long, filterScanlators: Boolean): Flow> + suspend fun getRecents(filterScanlators: Boolean, search: String = "", limit: Long = 25L, offset: Long = 0L): List + suspend fun getScanlatorsByChapter(mangaId: Long): List fun getScanlatorsByChapterAsFlow(mangaId: Long): Flow> diff --git a/app/src/main/java/yokai/domain/chapter/interactor/RecentChapter.kt b/app/src/main/java/yokai/domain/chapter/interactor/RecentChapter.kt new file mode 100644 index 0000000000..f9bc3205bf --- /dev/null +++ b/app/src/main/java/yokai/domain/chapter/interactor/RecentChapter.kt @@ -0,0 +1,21 @@ +package yokai.domain.chapter.interactor + +import eu.kanade.tachiyomi.data.database.models.MangaChapter +import eu.kanade.tachiyomi.util.lang.sqLite +import yokai.domain.chapter.ChapterRepository +import yokai.util.limitAndOffset + +class RecentChapter( + private val chapterRepository: ChapterRepository, +) { + suspend fun await(filterScanlators: Boolean, isResuming: Boolean, search: String = "", offset: Long = 0L): List { + val (limit, actualOffset) = limitAndOffset(true, isResuming, offset) + + return chapterRepository.getRecents( + filterScanlators, + "%${search.sqLite}%", + limit, + actualOffset, + ) + } +} diff --git a/app/src/main/java/yokai/util/SQLDelight.kt b/app/src/main/java/yokai/util/SQLDelight.kt new file mode 100644 index 0000000000..bb3cb90775 --- /dev/null +++ b/app/src/main/java/yokai/util/SQLDelight.kt @@ -0,0 +1,17 @@ +package yokai.util + +import eu.kanade.tachiyomi.ui.recents.RecentsPresenter + +fun limitAndOffset(isEndless: Boolean, isResuming: Boolean, offset: Long): Pair { + return when { + isResuming && isEndless && offset > 0 -> { + offset to 0L + } + isEndless -> { + RecentsPresenter.ENDLESS_LIMIT.toLong() to offset + } + else -> { + RecentsPresenter.SHORT_LIMIT.toLong() to 0L + } + } +} diff --git a/data/src/commonMain/sqldelight/tachiyomi/data/chapters.sq b/data/src/commonMain/sqldelight/tachiyomi/data/chapters.sq index e1e25e063d..f03a675da1 100644 --- a/data/src/commonMain/sqldelight/tachiyomi/data/chapters.sq +++ b/data/src/commonMain/sqldelight/tachiyomi/data/chapters.sq @@ -34,7 +34,6 @@ AND ( getRecents: SELECT - M.url AS mangaUrl, M.*, C.* FROM mangas AS M @@ -54,7 +53,6 @@ LIMIT :limit OFFSET :offset; getRecentsUngrouped: SELECT - M.url AS mangaUrl, M.*, C.*, H.* diff --git a/data/src/commonMain/sqldelight/tachiyomi/data/history.sq b/data/src/commonMain/sqldelight/tachiyomi/data/history.sq index e702010df0..0e4efe018c 100644 --- a/data/src/commonMain/sqldelight/tachiyomi/data/history.sq +++ b/data/src/commonMain/sqldelight/tachiyomi/data/history.sq @@ -1,10 +1,8 @@ -import kotlin.Long; - CREATE TABLE history( history_id INTEGER NOT NULL PRIMARY KEY, history_chapter_id INTEGER NOT NULL UNIQUE, - history_last_read INTEGER AS Long, - history_time_read INTEGER AS Long, + history_last_read INTEGER, + history_time_read INTEGER, FOREIGN KEY(history_chapter_id) REFERENCES chapters (_id) ON DELETE CASCADE );