diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.kt index c3d69c1b0c..af1f84dfd4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.kt @@ -56,5 +56,7 @@ open class DatabaseHelper(context: Context) : inline fun inTransaction(block: () -> Unit) = db.inTransaction(block) + inline fun inTransactionReturn(block: () -> T): T = db.inTransactionReturn(block) + fun lowLevel() = db.lowLevel() } 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 058a97d7f2..4509835baf 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 @@ -15,7 +15,6 @@ import eu.kanade.tachiyomi.data.database.resolvers.MangaChapterGetResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaChapterHistoryGetResolver import eu.kanade.tachiyomi.data.database.tables.ChapterTable import eu.kanade.tachiyomi.util.lang.sqLite -import java.util.Date interface ChapterQueries : DbProvider { @@ -32,14 +31,12 @@ interface ChapterQueries : DbProvider { ) .prepare() - fun getRecentChapters(date: Date) = getRecentChapters(Date(), date) - - fun getRecentChapters(startDate: Date, date: Date, search: String = "") = db.get() + fun getRecentChapters(search: String = "", offset: Int, isResuming: Boolean) = db.get() .listOfObjects(MangaChapter::class.java) .withQuery( RawQuery.builder() - .query(getRecentsQuery(search.sqLite)) - .args(date.time, startDate.time) + .query(getRecentsQuery(search.sqLite, offset, isResuming)) +// .args(date.time, startDate.time) .observesTables(ChapterTable.TABLE) .build() ) @@ -51,15 +48,12 @@ interface ChapterQueries : DbProvider { * @param date recent date range * @offset offset the db by */ - fun getUpdatedManga(date: Date, search: String = "", endless: Boolean) = - getUpdatedManga(Date(), date, search, endless) - - fun getUpdatedManga(startDate: Date, date: Date, search: String = "", endless: Boolean) = db.get() + fun getUpdatedManga(search: String = "", endless: Boolean, offset: Int, isResuming: Boolean) = db.get() .listOfObjects(MangaChapterHistory::class.java) .withQuery( RawQuery.builder() - .query(getRecentsQueryDistinct(search.sqLite, endless)) - .args(date.time, startDate.time) + .query(getRecentsQueryDistinct(search.sqLite, endless, offset, isResuming)) +// .args(date.time, startDate.time) .observesTables(ChapterTable.TABLE) .build() ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt index 647678c8d1..09db6d9059 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt @@ -10,7 +10,6 @@ import eu.kanade.tachiyomi.data.database.resolvers.MangaChapterHistoryGetResolve import eu.kanade.tachiyomi.data.database.tables.HistoryTable import eu.kanade.tachiyomi.data.database.tables.MangaTable import eu.kanade.tachiyomi.util.lang.sqLite -import java.util.Date interface HistoryQueries : DbProvider { @@ -18,36 +17,36 @@ interface HistoryQueries : DbProvider { * Insert history into database * @param history object containing history information */ - fun insertHistory(history: History) = db.put().`object`(history).prepare() +// fun insertHistory(history: History) = db.put().`object`(history).prepare() + +// /** +// * Returns history of recent manga containing last read chapter in 25s +// * @param date recent date range +// * @offset offset the db by +// */ +// fun getRecentManga(date: Date, offset: Int = 0, search: String = "") = db.get() +// .listOfObjects(MangaChapterHistory::class.java) +// .withQuery( +// RawQuery.builder() +// .query(getRecentMangasQuery(offset, search.sqLite)) +// .args(date.time) +// .observesTables(HistoryTable.TABLE) +// .build() +// ) +// .withGetResolver(MangaChapterHistoryGetResolver.INSTANCE) +// .prepare() /** * Returns history of recent manga containing last read chapter in 25s * @param date recent date range * @offset offset the db by */ - fun getRecentManga(date: Date, offset: Int = 0, search: String = "") = db.get() + fun getRecentlyAdded(search: String = "", endless: Boolean, offset: Int, isResuming: Boolean) = db.get() .listOfObjects(MangaChapterHistory::class.java) .withQuery( RawQuery.builder() - .query(getRecentMangasQuery(offset, search.sqLite)) - .args(date.time) - .observesTables(HistoryTable.TABLE) - .build() - ) - .withGetResolver(MangaChapterHistoryGetResolver.INSTANCE) - .prepare() - - /** - * Returns history of recent manga containing last read chapter in 25s - * @param date recent date range - * @offset offset the db by - */ - fun getRecentlyAdded(startDate: Date, date: Date, search: String = "", endless: Boolean) = db.get() - .listOfObjects(MangaChapterHistory::class.java) - .withQuery( - RawQuery.builder() - .query(getRecentAdditionsQuery(search.sqLite, endless)) - .args(date.time, startDate.time) + .query(getRecentAdditionsQuery(search.sqLite, endless, offset, isResuming)) +// .args(date.time, startDate.time) .observesTables(MangaTable.TABLE) .build() ) @@ -59,20 +58,12 @@ interface HistoryQueries : DbProvider { * @param date recent date range * @offset offset the db by */ - fun getRecentMangaLimit(date: Date, limit: Int = 0, search: String = "") = - getRecentMangaLimit(Date(), date, limit, search) - - /** - * Returns history of recent manga containing last read chapter in 25s - * @param date recent date range - * @offset offset the db by - */ - fun getRecentMangaLimit(startDate: Date, date: Date, limit: Int = 0, search: String = "") = db.get() + fun getRecentMangaLimit(search: String = "", endless: Boolean, offset: Int, isResuming: Boolean) = db.get() .listOfObjects(MangaChapterHistory::class.java) .withQuery( RawQuery.builder() - .query(getRecentMangasLimitQuery(limit, search.sqLite)) - .args(date.time, startDate.time) + .query(getRecentMangasLimitQuery(search.sqLite, endless, offset, isResuming)) +// .args(date.time, startDate.time) .observesTables(HistoryTable.TABLE) .build() ) @@ -84,29 +75,20 @@ interface HistoryQueries : DbProvider { * @param date recent date range * @offset offset the db by */ - fun getRecentsWithUnread(startDate: Date, date: Date, search: String = "", endless: Boolean) = db.get() + fun getAllRecents(search: String = "", includeRead: Boolean, endless: Boolean, offset: Int, isResuming: Boolean) = db.get() .listOfObjects(MangaChapterHistory::class.java) .withQuery( RawQuery.builder() - .query(getRecentReadWithUnreadChapters(search.sqLite, endless)) - .args(date.time, startDate.time) - .observesTables(HistoryTable.TABLE) - .build() - ) - .withGetResolver(MangaChapterHistoryGetResolver.INSTANCE) - .prepare() - - /** - * Returns history of recent manga containing last read chapter in 25s - * @param date recent date range - * @offset offset the db by - */ - fun getAllRecents(startDate: Date, date: Date, search: String = "", endless: Boolean) = db.get() - .listOfObjects(MangaChapterHistory::class.java) - .withQuery( - RawQuery.builder() - .query(getRecentRead(search.sqLite, endless)) - .args(date.time, startDate.time) + .query( + getRecentRead( + search.sqLite, + includeRead, + endless, + offset, + isResuming + ) + ) +// .args(date.time, startDate.time) .observesTables(HistoryTable.TABLE) .build() ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/RawQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/RawQueries.kt index 6b53cefe96..3b6d821306 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/RawQueries.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/RawQueries.kt @@ -1,5 +1,6 @@ package eu.kanade.tachiyomi.data.database.queries +import eu.kanade.tachiyomi.ui.recents.RecentsPresenter import eu.kanade.tachiyomi.data.database.tables.CategoryTable as Category import eu.kanade.tachiyomi.data.database.tables.ChapterTable as Chapter import eu.kanade.tachiyomi.data.database.tables.HistoryTable as History @@ -41,56 +42,59 @@ val libraryQuery = /** * Query to get the recent chapters of manga from the library up to a date. */ -fun getRecentsQuery(search: String) = +fun getRecentsQuery(search: String, offset: Int, isResuming: Boolean) = """ SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, * FROM ${Manga.TABLE} JOIN ${Chapter.TABLE} ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} - WHERE ${Manga.COL_FAVORITE} = 1 - AND ${Chapter.COL_DATE_FETCH} > ? - AND ${Chapter.COL_DATE_FETCH} < ? + WHERE ${Manga.COL_FAVORITE} = 1 AND ${Chapter.COL_DATE_FETCH} > ${Manga.COL_DATE_ADDED} AND lower(${Manga.COL_TITLE}) LIKE '%$search%' - ORDER BY ${Chapter.COL_DATE_UPLOAD} DESC + ORDER BY ${Chapter.COL_DATE_FETCH} DESC + ${limitAndOffset(true, isResuming, offset)} """ /** * Query to get the recently added manga */ -fun getRecentAdditionsQuery(search: String, endless: Boolean) = +fun getRecentAdditionsQuery(search: String, endless: Boolean, offset: Int, isResuming: Boolean) = """ SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, * FROM ${Manga.TABLE} WHERE ${Manga.COL_FAVORITE} = 1 - AND ${Manga.COL_DATE_ADDED} > ? - AND ${Manga.COL_DATE_ADDED} < ? AND lower(${Manga.COL_TITLE}) LIKE '%$search%' ORDER BY ${Manga.COL_DATE_ADDED} DESC - ${if (endless) "" else "LIMIT 8"} + ${limitAndOffset(endless, isResuming, offset)} """ +fun limitAndOffset(endless: Boolean, isResuming: Boolean, offset: Int): String { + return when { + isResuming && endless -> "LIMIT $offset" + endless -> "LIMIT ${RecentsPresenter.ENDLESS_LIMIT}\nOFFSET $offset" + else -> "LIMIT 8" + } +} + /** * Query to get the manga with recently uploaded chapters */ -fun getRecentsQueryDistinct(search: String, endless: Boolean) = +fun getRecentsQueryDistinct(search: String, endless: Boolean, offset: Int = 0, isResuming: Boolean) = """ SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.* FROM ${Manga.TABLE} JOIN ${Chapter.TABLE} ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} JOIN ( - SELECT ${Chapter.TABLE}.${Chapter.COL_MANGA_ID},${Chapter.TABLE}.${Chapter.COL_ID} as ${History.COL_CHAPTER_ID},MAX(${Chapter.TABLE}.${Chapter.COL_DATE_UPLOAD}) - FROM ${Chapter.TABLE} JOIN ${Manga.TABLE} - ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} - WHERE ${Chapter.COL_DATE_FETCH} > ? - AND ${Chapter.COL_DATE_FETCH} < ? - AND ${Chapter.COL_READ} = 0 - GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}) AS newest_chapter + SELECT ${Chapter.TABLE}.${Chapter.COL_MANGA_ID},${Chapter.TABLE}.${Chapter.COL_ID} as ${History.COL_CHAPTER_ID},MAX(${Chapter.TABLE}.${Chapter.COL_DATE_UPLOAD}) + FROM ${Chapter.TABLE} JOIN ${Manga.TABLE} + ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} + WHERE ${Chapter.COL_READ} = 0 + GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}) AS newest_chapter ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = newest_chapter.${Chapter.COL_MANGA_ID} WHERE ${Manga.COL_FAVORITE} = 1 AND newest_chapter.${History.COL_CHAPTER_ID} = ${Chapter.TABLE}.${Chapter.COL_ID} AND ${Chapter.COL_DATE_FETCH} > ${Manga.COL_DATE_ADDED} AND lower(${Manga.COL_TITLE}) LIKE '%$search%' - ORDER BY ${Chapter.COL_DATE_UPLOAD} DESC - ${if (endless) "" else "LIMIT 8"} + ORDER BY ${Chapter.COL_DATE_FETCH} DESC + ${limitAndOffset(endless, isResuming, offset)} """ /** @@ -98,9 +102,13 @@ fun getRecentsQueryDistinct(search: String, endless: Boolean) = * The max_last_read table contains the most recent chapters grouped by manga * The select statement returns all information of chapters that have the same id as the chapter in max_last_read * and are read after the given time period - * @return return limit is 25 */ -fun getRecentMangasQuery(offset: Int = 0, search: String = "") = +fun getRecentMangasLimitQuery( + search: String = "", + endless: Boolean, + offset: Int = 0, + isResuming: Boolean +) = """ SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.* FROM ${Manga.TABLE} @@ -114,39 +122,10 @@ fun getRecentMangasQuery(offset: Int = 0, search: String = "") = ON ${Chapter.TABLE}.${Chapter.COL_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID} GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}) AS max_last_read ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID} - WHERE ${History.TABLE}.${History.COL_LAST_READ} > ? AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID} AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%' ORDER BY max_last_read.${History.COL_LAST_READ} DESC - LIMIT 25 OFFSET $offset -""" - -/** - * Query to get the recently read chapters of manga from the library up to a date. - * The max_last_read table contains the most recent chapters grouped by manga - * The select statement returns all information of chapters that have the same id as the chapter in max_last_read - * and are read after the given time period - */ -fun getRecentMangasLimitQuery(limit: Int = 25, search: String = "") = - """ - SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.* - FROM ${Manga.TABLE} - JOIN ${Chapter.TABLE} - ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} - JOIN ${History.TABLE} - ON ${Chapter.TABLE}.${Chapter.COL_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID} - JOIN ( - SELECT ${Chapter.TABLE}.${Chapter.COL_MANGA_ID},${Chapter.TABLE}.${Chapter.COL_ID} as ${History.COL_CHAPTER_ID}, MAX(${History.TABLE}.${History.COL_LAST_READ}) as ${History.COL_LAST_READ} - FROM ${Chapter.TABLE} JOIN ${History.TABLE} - ON ${Chapter.TABLE}.${Chapter.COL_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID} - GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}) AS max_last_read - ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID} - WHERE ${History.TABLE}.${History.COL_LAST_READ} > ? - AND ${History.TABLE}.${History.COL_LAST_READ} < ? - AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID} - AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%' - ORDER BY max_last_read.${History.COL_LAST_READ} DESC - LIMIT $limit + ${limitAndOffset(endless, isResuming, offset)} """ /** @@ -156,7 +135,13 @@ fun getRecentMangasLimitQuery(limit: Int = 25, search: String = "") = * The select statement returns all information of chapters that have the same id as the chapter in max_last_read * and are read after the given time period */ -fun getRecentReadWithUnreadChapters(search: String = "", endless: Boolean) = +fun getRecentRead( + search: String = "", + includeRead: Boolean, + endless: Boolean, + offset: Int = 0, + isResuming: Boolean +) = """ SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.* FROM ( @@ -165,11 +150,10 @@ fun getRecentReadWithUnreadChapters(search: String = "", endless: Boolean) = LEFT JOIN ( SELECT ${Chapter.COL_MANGA_ID}, COUNT(*) AS unread 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} - WHERE C.unread > 0 + ${if (includeRead) "" else "WHERE C.unread > 0"} GROUP BY ${Manga.COL_ID} ORDER BY ${Manga.COL_TITLE} ) AS ${Manga.TABLE} @@ -183,53 +167,10 @@ fun getRecentReadWithUnreadChapters(search: String = "", endless: Boolean) = ON ${Chapter.TABLE}.${Chapter.COL_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID} GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}) AS max_last_read ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID} - WHERE ${History.TABLE}.${History.COL_LAST_READ} > ? - AND ${History.TABLE}.${History.COL_LAST_READ} < ? AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID} AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%' ORDER BY max_last_read.${History.COL_LAST_READ} DESC - ${if (endless) "" else "LIMIT 8"} -""" - -/** - * Query to get the recently read manga that has more chapters to read - * The first from checks that there's an unread chapter - * The max_last_read table contains the most recent chapters grouped by manga - * The select statement returns all information of chapters that have the same id as the chapter in max_last_read - * and are read after the given time period - */ -fun getRecentRead(search: String = "", endless: Boolean) = - """ - SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.* - FROM ( - SELECT ${Manga.TABLE}.* - FROM ${Manga.TABLE} - LEFT JOIN ( - SELECT ${Chapter.COL_MANGA_ID}, COUNT(*) AS unread - FROM ${Chapter.TABLE} - GROUP BY ${Chapter.COL_MANGA_ID} - ) AS C - ON ${Manga.COL_ID} = C.${Chapter.COL_MANGA_ID} - WHERE C.unread > 0 - GROUP BY ${Manga.COL_ID} - ORDER BY ${Manga.COL_TITLE} - ) AS ${Manga.TABLE} - JOIN ${Chapter.TABLE} - ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} - JOIN ${History.TABLE} - ON ${Chapter.TABLE}.${Chapter.COL_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID} - JOIN ( - SELECT ${Chapter.TABLE}.${Chapter.COL_MANGA_ID},${Chapter.TABLE}.${Chapter.COL_ID} as ${History.COL_CHAPTER_ID}, MAX(${History.TABLE}.${History.COL_LAST_READ}) as ${History.COL_LAST_READ} - FROM ${Chapter.TABLE} JOIN ${History.TABLE} - ON ${Chapter.TABLE}.${Chapter.COL_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID} - GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}) AS max_last_read - ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID} - WHERE ${History.TABLE}.${History.COL_LAST_READ} > ? - AND ${History.TABLE}.${History.COL_LAST_READ} < ? - AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID} - AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%' - ORDER BY max_last_read.${History.COL_LAST_READ} DESC - ${if (endless) "" else "LIMIT 8"} + ${limitAndOffset(endless, isResuming, offset)} """ fun getHistoryByMangaId() = diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsController.kt index 8f111f607e..0ba4c6d09b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsController.kt @@ -181,6 +181,8 @@ class RecentsController(bundle: Bundle? = null) : } presenter.onCreate() + binding.swipeRefresh.isRefreshing = true + if (presenter.recentItems.isNotEmpty()) { adapter.updateDataSet(presenter.recentItems) } @@ -345,7 +347,9 @@ class RecentsController(bundle: Bundle? = null) : override fun onActivityResumed(activity: Activity) { super.onActivityResumed(activity) if (!isBindingInitialized) return - refresh() + if (!presenter.isLoading) { + refresh() + } setBottomPadding() binding.downloadBottomSheet.dlBottomSheet.update() } 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 f6eaa81a05..7a91ce1dd8 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 @@ -13,7 +13,6 @@ import eu.kanade.tachiyomi.data.library.LibraryServiceListener import eu.kanade.tachiyomi.data.library.LibraryUpdateService import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.source.SourceManager -import eu.kanade.tachiyomi.util.system.executeOnIO import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -46,7 +45,7 @@ class RecentsPresenter( var query = "" set(value) { field = value - page = 0 + resetOffsets() } private val newAdditionsHeader = RecentMangaHeaderItem(RecentMangaHeaderItem.NEWLY_ADDED) private val newChaptersHeader = RecentMangaHeaderItem(RecentMangaHeaderItem.NEW_CHAPTERS) @@ -55,23 +54,37 @@ class RecentsPresenter( .CONTINUE_READING ) var finished = false - var shouldMoveToTop = false + var heldItems: HashMap> = hashMapOf() + private var shouldMoveToTop = false var viewType: Int = preferences.recentsViewType().get() - private var page = 0 set(value) { field = value - if (value == 0) { - finished = false - shouldMoveToTop = true - } + ENDLESS_LIMIT = if (value == VIEW_TYPE_UNGROUP_ALL) 25 else 50 } + private fun resetOffsets() { + finished = false + shouldMoveToTop = true + updatesOffset = 0 + historyOffset = 0 + additionsOffset = 0 + } + + private var updatesOffset = 0 + private var historyOffset = 0 + private var additionsOffset = 0 + var isLoading = false + private set + + private val isOnFirstPage: Boolean + get() = additionsOffset + historyOffset + updatesOffset == 0 + init { preferences.showReadInAllRecents() .asFlow() .drop(1) .onEach { - page = 0 + resetOffsets() getRecents() } .launchIn(scope) @@ -97,97 +110,107 @@ class RecentsPresenter( } } - private suspend fun runRecents(oldQuery: String = "", updatePageCount: Boolean = false, retryCount: Int = 0, itemCount: Int = 0, limit: Boolean = false) { + private suspend fun runRecents( + oldQuery: String = "", + updatePageCount: Boolean = false, + retryCount: Int = 0, + itemCount: Int = 0, + limit: Boolean = false, + customViewType: Int? = null + ) { if (retryCount > 15) { finished = true setDownloadedChapters(recentItems) - withContext(Dispatchers.Main) { controller?.showLists(recentItems, false) } + if (customViewType == null) { + withContext(Dispatchers.Main) { + controller?.showLists(recentItems, false) + isLoading = false + } + } return } + val viewType = customViewType ?: viewType +// Timber.d("starting up items new page: $updatePageCount") val showRead = preferences.showReadInAllRecents().get() && !limit - if (updatePageCount) { - page++ - } - val isUngrouped = viewType > VIEW_TYPE_GROUP_ALL && query.isEmpty() - val cal = Calendar.getInstance().apply { - time = Date() - when { - query.isNotEmpty() -> add(Calendar.YEAR, -50) - isUngrouped -> add(Calendar.MONTH, -(page + 1)) - else -> add(Calendar.MONTH, -1) - } - } - val startCal = Calendar.getInstance().apply { - time = Date() - when { - query.isNotEmpty() -> {} - isUngrouped && !updatePageCount -> {} - isUngrouped -> add(Calendar.MONTH, -page) - else -> {} - } - } - - val calWeek = Calendar.getInstance().apply { - time = Date() - when { - query.isNotEmpty() -> add(Calendar.YEAR, -50) - isUngrouped -> add(Calendar.MONTH, -(page + 1)) - else -> add(Calendar.WEEK_OF_YEAR, -1) - } - } - - val calDay = Calendar.getInstance().apply { - time = Date() - when { - query.isNotEmpty() -> add(Calendar.YEAR, -50) - isUngrouped -> add(Calendar.MONTH, -(page + 1)) - else -> add(Calendar.DAY_OF_YEAR, -1) - } - } - - val cReading = if (viewType != VIEW_TYPE_ONLY_UPDATES) { - if (query.isEmpty() && viewType != VIEW_TYPE_ONLY_HISTORY) { - if (showRead) { - db.getAllRecents(startCal.time, cal.time, query, isUngrouped && !limit) - .executeOnIO() + val isCustom = customViewType != null + val isEndless = isUngrouped && !limit +// Timber.d("set up cal items") + val (cReading, rUpdates, nAdditions) = db.inTransactionReturn { + val cReading = if (viewType != VIEW_TYPE_ONLY_UPDATES) { + if (query.isEmpty() && viewType != VIEW_TYPE_ONLY_HISTORY) { + db.getAllRecents( + query, + showRead, + isEndless, + if (isCustom) ENDLESS_LIMIT else historyOffset, + !updatePageCount && !isOnFirstPage + ) } else { - db.getRecentsWithUnread(startCal.time, cal.time, query, isUngrouped && !limit) - .executeOnIO() + db.getRecentMangaLimit( + query, + isEndless, + if (isCustom) ENDLESS_LIMIT else historyOffset, + !updatePageCount && !isOnFirstPage + ) + }.executeAsBlocking() + } else emptyList() +// Timber.d("set up cReader items: ${cReading.size}") + val rUpdates = when { + viewType == VIEW_TYPE_ONLY_UPDATES -> db.getRecentChapters( + query, + if (isCustom) ENDLESS_LIMIT else updatesOffset, + !updatePageCount && !isOnFirstPage + ).executeAsBlocking().map { + MangaChapterHistory(it.manga, it.chapter, HistoryImpl()) } - } else db.getRecentMangaLimit( - startCal.time, - cal.time, - if (viewType == VIEW_TYPE_ONLY_HISTORY) 200 else 8, - query - ).executeOnIO() - } else emptyList() - val rUpdates = when { - viewType == VIEW_TYPE_ONLY_UPDATES -> db.getRecentChapters(startCal.time, calWeek.time, query).executeOnIO().map { - MangaChapterHistory(it.manga, it.chapter, HistoryImpl()) + viewType != VIEW_TYPE_ONLY_HISTORY -> db.getUpdatedManga( + query, + isEndless, + if (isCustom) ENDLESS_LIMIT else updatesOffset, + !updatePageCount && !isOnFirstPage + ).executeAsBlocking() + else -> emptyList() } - viewType != VIEW_TYPE_ONLY_HISTORY -> db.getUpdatedManga(startCal.time, calWeek.time, query, isUngrouped && !limit).executeOnIO() - else -> emptyList() + rUpdates.forEach { + it.history.last_read = it.chapter.date_fetch + } +// Timber.d("set up rUpdates items: ${rUpdates.size}") + val nAdditions = if (viewType < VIEW_TYPE_ONLY_HISTORY) { + db.getRecentlyAdded( + query, + isEndless, + if (isCustom) ENDLESS_LIMIT else additionsOffset, + !updatePageCount && !isOnFirstPage + ).executeAsBlocking() + } else emptyList() + nAdditions.forEach { + it.history.last_read = it.manga.date_added + } +// Timber.d("set up nAdditons items: ${nAdditions.size}") + Triple(cReading, rUpdates, nAdditions) } - rUpdates.forEach { - it.history.last_read = it.chapter.date_fetch - } - val nAdditions = if (viewType < VIEW_TYPE_ONLY_HISTORY) { - db.getRecentlyAdded(startCal.time, calDay.time, query, isUngrouped && !limit).executeOnIO() - } else emptyList() - nAdditions.forEach { - it.history.last_read = it.manga.date_added + + if (!isCustom && + (historyOffset + updatesOffset + additionsOffset == 0 || updatePageCount) + ) { + additionsOffset += nAdditions.size + historyOffset += cReading.size + updatesOffset += rUpdates.size } + +// Timber.d("loaded items: ") if (query != oldQuery) return +// Timber.d("query matches items: ") val mangaList = (cReading + rUpdates + nAdditions).sortedByDescending { it.history.last_read }.distinctBy { - if (query.isEmpty() && viewType != VIEW_TYPE_ONLY_HISTORY) it.manga.id else it.chapter.id + if (query.isEmpty() && viewType != VIEW_TYPE_ONLY_HISTORY && viewType != VIEW_TYPE_ONLY_UPDATES) it.manga.id else it.chapter.id }.filter { mch -> - if (updatePageCount && page > 0 && query.isEmpty()) { - if (viewType != VIEW_TYPE_ONLY_HISTORY) { + if (updatePageCount && !isOnFirstPage && query.isEmpty()) { + if (viewType != VIEW_TYPE_ONLY_HISTORY && viewType != VIEW_TYPE_ONLY_UPDATES) { recentItems.none { mch.manga.id == it.mch.manga.id } } else { recentItems.none { mch.chapter.id == it.mch.chapter.id } @@ -209,9 +232,11 @@ class RecentsPresenter( else null else Pair(it, chapter) } +// Timber.d("setting new items") val newItems = if (query.isEmpty() && !isUngrouped) { val nChaptersItems = - pairs.asSequence().filter { it.first.history.id == null && it.first.chapter.id != null } + pairs.asSequence() + .filter { it.first.history.id == null && it.first.chapter.id != null } .sortedWith { f1, f2 -> if (abs(f1.second.date_fetch - f2.second.date_fetch) <= TimeUnit.HOURS.toMillis(12) @@ -249,11 +274,11 @@ class RecentsPresenter( }.flatten() } else { if (viewType == VIEW_TYPE_ONLY_UPDATES) { - val map = TreeMap>> { - d1, d2 -> - d2 - .compareTo(d1) - } + val map = + TreeMap>> { d1, d2 -> + d2 + .compareTo(d1) + } val byDay = pairs.groupByTo(map, { getMapKey(it.first.history.last_read) }) byDay.flatMap { @@ -264,23 +289,40 @@ class RecentsPresenter( } } else pairs.map { RecentMangaItem(it.first, it.second, null) } } - recentItems = if (page == 0 || !updatePageCount) { - newItems +// Timber.d("setting some items") + if (customViewType == null) { + recentItems = if (isOnFirstPage || !updatePageCount) { + newItems + } else { + recentItems + newItems + } } else { - recentItems + newItems + heldItems[customViewType] = newItems } val newCount = itemCount + newItems.size val hasNewItems = newItems.isNotEmpty() if (updatePageCount && newCount < 25 && viewType != VIEW_TYPE_GROUP_ALL && query.isEmpty() && !limit) { - page++ + // Timber.d("needs to retry. has New items: $hasNewItems, offset: $subUpdatesOffset") runRecents(oldQuery, true, retryCount + (if (hasNewItems) 0 else 1), newCount) return } if (!limit) { setDownloadedChapters(recentItems) - withContext(Dispatchers.Main) { - controller?.showLists(recentItems, hasNewItems, shouldMoveToTop) - shouldMoveToTop = false + if (customViewType == null) { + withContext(Dispatchers.Main) { + controller?.showLists(recentItems, hasNewItems, shouldMoveToTop) + isLoading = false + shouldMoveToTop = false + } +// scope.launchIO { +// (0..3).map { +// async { +// if (this@RecentsPresenter.viewType != it) { +// runRecents(oldQuery, customViewType = it) +// } +// } +// }.awaitAll() +// } } } } @@ -312,7 +354,7 @@ class RecentsPresenter( preferences.recentsViewType().set(pref) } viewType = pref - page = 0 + resetOffsets() getRecents() } @@ -452,7 +494,10 @@ class RecentsPresenter( } fun requestNext() { - getRecents(true) + if (!isLoading) { + isLoading = true + getRecents(true) + } } companion object { @@ -462,6 +507,7 @@ class RecentsPresenter( const val VIEW_TYPE_UNGROUP_ALL = 1 const val VIEW_TYPE_ONLY_HISTORY = 2 const val VIEW_TYPE_ONLY_UPDATES = 3 + var ENDLESS_LIMIT = 50 suspend fun getRecentManga(): List> { val presenter = RecentsPresenter(null)