Match infinite history and search history from preview (#3827)

* Add infinite history and search history

* Cleanup code

(cherry picked from commit 9d2adcd512c28872c9e958e9fcdcbccbd11b3b35)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/database/queries/RawQueries.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryPresenter.kt
This commit is contained in:
jobobby04 2020-09-27 18:17:14 -04:00 committed by Jobobby04
parent 8acd834783
commit 9c76f1fd8f
4 changed files with 32 additions and 94 deletions

View File

@ -18,16 +18,18 @@ interface HistoryQueries : DbProvider {
*/ */
fun insertHistory(history: History) = db.put().`object`(history).prepare() fun insertHistory(history: History) = db.put().`object`(history).prepare()
// SY -->
/** /**
* Returns history of recent manga containing last read chapter * Returns history of recent manga containing last read chapter
* @param date recent date range * @param date recent date range
* @param limit the limit of manga to grab
* @param offset offset the db by
* @param search what to search in the db history
*/ */
fun getRecentManga(date: Date, offset: Int = 0, search: String = "") = db.get() fun getRecentManga(date: Date, limit: Int = 25, offset: Int = 0, search: String = "") = db.get()
.listOfObjects(MangaChapterHistory::class.java) .listOfObjects(MangaChapterHistory::class.java)
.withQuery( .withQuery(
RawQuery.builder() RawQuery.builder()
.query(getRecentMangasQuery(offset, search)) .query(getRecentMangasQuery(limit, offset, search))
.args(date.time) .args(date.time)
.observesTables(HistoryTable.TABLE) .observesTables(HistoryTable.TABLE)
.build() .build()
@ -35,24 +37,6 @@ interface HistoryQueries : DbProvider {
.withGetResolver(MangaChapterHistoryGetResolver.INSTANCE) .withGetResolver(MangaChapterHistoryGetResolver.INSTANCE)
.prepare() .prepare()
/**
* Returns history of recent manga containing last read chapter in 25s
* @param date recent date range
* @offset offset the db by
*/
fun getRecentMangaLimit(date: Date, limit: Int = 0, search: String = "") = db.get()
.listOfObjects(MangaChapterHistory::class.java)
.withQuery(
RawQuery.builder()
.query(getRecentMangasLimitQuery(limit, search))
.args(date.time)
.observesTables(HistoryTable.TABLE)
.build()
)
.withGetResolver(MangaChapterHistoryGetResolver.INSTANCE)
.prepare()
// SY <--
fun getHistoryByMangaId(mangaId: Long) = db.get() fun getHistoryByMangaId(mangaId: Long) = db.get()
.listOfObjects(History::class.java) .listOfObjects(History::class.java)
.withQuery( .withQuery(

View File

@ -136,36 +136,8 @@ fun getRecentsQuery() =
* The max_last_read table contains the most recent chapters grouped by manga * 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 * 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 * and are read after the given time period
* @return return limit is 25
*/ */
// SY --> fun getRecentMangasQuery(limit: Int = 25, offset: Int = 0, search: String = "") =
fun getRecentMangasQuery(offset: Int = 0, 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 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}.* SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.*
FROM ${Manga.TABLE} FROM ${Manga.TABLE}
@ -183,9 +155,8 @@ fun getRecentMangasLimitQuery(limit: Int = 25, search: String = "") =
AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID} AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID}
AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%' AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%'
ORDER BY max_last_read.${History.COL_LAST_READ} DESC ORDER BY max_last_read.${History.COL_LAST_READ} DESC
LIMIT $limit LIMIT $limit OFFSET $offset
""" """
// SY <--
fun getHistoryByMangaId() = fun getHistoryByMangaId() =
""" """

View File

@ -25,7 +25,6 @@ import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.appcompat.queryTextChanges import reactivecircus.flowbinding.appcompat.queryTextChanges
import uy.kohesive.injekt.api.get
/** /**
* Fragment that shows recently read manga. * Fragment that shows recently read manga.
@ -53,6 +52,10 @@ class HistoryController :
* Endless loading item. * Endless loading item.
*/ */
private var progressItem: ProgressItem? = null private var progressItem: ProgressItem? = null
/**
* Search query.
*/
private var query = "" private var query = ""
override fun getTitle(): String? { override fun getTitle(): String? {
@ -105,6 +108,9 @@ class HistoryController :
} }
} }
/**
* Safely error if next page load fails
*/
fun onAddPageError(error: Throwable) { fun onAddPageError(error: Throwable) {
adapter?.onLoadMoreComplete(null) adapter?.onLoadMoreComplete(null)
adapter?.endlessTargetCount = 1 adapter?.endlessTargetCount = 1

View File

@ -13,7 +13,6 @@ import rx.Observable
import rx.android.schedulers.AndroidSchedulers import rx.android.schedulers.AndroidSchedulers
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.util.Calendar import java.util.Calendar
import java.util.Comparator
import java.util.Date import java.util.Date
import java.util.TreeMap import java.util.TreeMap
@ -28,8 +27,6 @@ class HistoryPresenter : BasePresenter<HistoryController>() {
* Used to connect to database * Used to connect to database
*/ */
val db: DatabaseHelper by injectLazy() val db: DatabaseHelper by injectLazy()
var lastCount = 25
var lastSearch = ""
override fun onCreate(savedState: Bundle?) { override fun onCreate(savedState: Bundle?) {
super.onCreate(savedState) super.onCreate(savedState)
@ -39,9 +36,7 @@ class HistoryPresenter : BasePresenter<HistoryController>() {
} }
fun requestNext(offset: Int, search: String = "") { fun requestNext(offset: Int, search: String = "") {
lastCount = offset getRecentMangaObservable(offset = offset, search = search)
lastSearch = search
getRecentMangaObservable((offset), search)
.subscribeLatestCache( .subscribeLatestCache(
{ view, mangas -> { view, mangas ->
view.onNextManga(mangas) view.onNextManga(mangas)
@ -54,37 +49,14 @@ class HistoryPresenter : BasePresenter<HistoryController>() {
* Get recent manga observable * Get recent manga observable
* @return list of history * @return list of history
*/ */
fun getRecentMangaObservable(offset: Int = 0, search: String = ""): Observable<List<HistoryItem>> { private fun getRecentMangaObservable(limit: Int = 25, offset: Int = 0, search: String = ""): Observable<List<HistoryItem>> {
// Set date limit for recent manga // Set date limit for recent manga
val cal = Calendar.getInstance().apply { val cal = Calendar.getInstance().apply {
time = Date() time = Date()
add(Calendar.YEAR, -50) add(Calendar.YEAR, -50)
} }
return db.getRecentManga(cal.time, offset, search).asRxObservable() return db.getRecentManga(cal.time, limit, offset, search).asRxObservable()
.map { recents ->
val map = TreeMap<Date, MutableList<MangaChapterHistory>> { d1, d2 -> d2.compareTo(d1) }
val byDay = recents
.groupByTo(map, { it.history.last_read.toDateKey() })
byDay.flatMap { entry ->
val dateItem = DateSectionItem(entry.key)
entry.value.map { HistoryItem(it, dateItem) }
}
}
.observeOn(AndroidSchedulers.mainThread())
}
/**
* Get recent manga observable
* @return list of history
*/
private fun getRecentMangaLimitObservable(offset: Int = 0, search: String = ""): Observable<List<HistoryItem>> {
// Set limit for recent manga
val cal = Calendar.getInstance()
cal.time = Date()
cal.add(Calendar.YEAR, -50)
return db.getRecentMangaLimit(cal.time, lastCount, search).asRxObservable()
.map { recents -> .map { recents ->
val map = TreeMap<Date, MutableList<MangaChapterHistory>> { d1, d2 -> d2.compareTo(d1) } val map = TreeMap<Date, MutableList<MangaChapterHistory>> { d1, d2 -> d2.compareTo(d1) }
val byDay = recents val byDay = recents
@ -103,13 +75,16 @@ class HistoryPresenter : BasePresenter<HistoryController>() {
*/ */
fun removeFromHistory(history: History) { fun removeFromHistory(history: History) {
history.last_read = 0L history.last_read = 0L
db.updateHistoryLastRead(history).executeAsBlocking() db.updateHistoryLastRead(history).asRxObservable()
updateList() .subscribe()
} }
fun updateList(search: String? = null) { /**
lastSearch = search ?: lastSearch * Pull a list of history from the db
getRecentMangaLimitObservable(lastCount, lastSearch).take(1) * @param search a search query to use for filtering
*/
fun updateList(search: String = "") {
getRecentMangaObservable(search = search).take(1)
.subscribeLatestCache( .subscribeLatestCache(
{ view, mangas -> { view, mangas ->
view.onNextManga(mangas, true) view.onNextManga(mangas, true)
@ -123,10 +98,12 @@ class HistoryPresenter : BasePresenter<HistoryController>() {
* @param mangaId id of manga * @param mangaId id of manga
*/ */
fun removeAllFromHistory(mangaId: Long) { fun removeAllFromHistory(mangaId: Long) {
val history = db.getHistoryByMangaId(mangaId).executeAsBlocking() db.getHistoryByMangaId(mangaId).asRxSingle()
history.forEach { it.last_read = 0L } .map { list ->
db.updateHistoryLastRead(history).executeAsBlocking() list.forEach { it.last_read = 0L }
updateList() db.updateHistoryLastRead(list).executeAsBlocking()
}
.subscribe()
} }
/** /**
@ -148,7 +125,7 @@ class HistoryPresenter : BasePresenter<HistoryController>() {
} }
val chapters = db.getChapters(manga).executeAsBlocking() val chapters = db.getChapters(manga).executeAsBlocking()
.sortedWith(Comparator { c1, c2 -> sortFunction(c1, c2) }) .sortedWith { c1, c2 -> sortFunction(c1, c2) }
val currChapterIndex = chapters.indexOfFirst { chapter.id == it.id } val currChapterIndex = chapters.indexOfFirst { chapter.id == it.id }
return when (manga.sorting) { return when (manga.sorting) {