Use SQLDelight on Updates screen (#7423)
This commit is contained in:
parent
b9e108eb4d
commit
1f10b79ee8
@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.data.manga
|
package eu.kanade.data.manga
|
||||||
|
|
||||||
|
import eu.kanade.domain.chapter.model.Chapter
|
||||||
import eu.kanade.domain.manga.model.Manga
|
import eu.kanade.domain.manga.model.Manga
|
||||||
|
|
||||||
val mangaMapper: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long) -> Manga =
|
val mangaMapper: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long) -> Manga =
|
||||||
@ -24,3 +25,39 @@ val mangaMapper: (Long, Long, String, String?, String?, String?, List<String>?,
|
|||||||
initialized = initialized,
|
initialized = initialized,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val mangaChapterMapper: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, Long, Long, String, String, String?, Boolean, Boolean, Long, Float, Long, Long, Long) -> Pair<Manga, Chapter> =
|
||||||
|
{ _id, source, url, artist, author, description, genre, title, status, thumbnailUrl, favorite, lastUpdate, next_update, initialized, viewerFlags, chapterFlags, coverLastModified, dateAdded, chapterId, mangaId, chapterUrl, name, scanlator, read, bookmark, lastPageRead, chapterNumber, sourceOrder, dateFetch, dateUpload ->
|
||||||
|
Manga(
|
||||||
|
id = _id,
|
||||||
|
source = source,
|
||||||
|
favorite = favorite,
|
||||||
|
lastUpdate = lastUpdate ?: 0,
|
||||||
|
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,
|
||||||
|
) to Chapter(
|
||||||
|
id = chapterId,
|
||||||
|
mangaId = mangaId,
|
||||||
|
read = read,
|
||||||
|
bookmark = bookmark,
|
||||||
|
lastPageRead = lastPageRead,
|
||||||
|
dateFetch = dateFetch,
|
||||||
|
sourceOrder = sourceOrder,
|
||||||
|
url = chapterUrl,
|
||||||
|
name = name,
|
||||||
|
dateUpload = dateUpload,
|
||||||
|
chapterNumber = chapterNumber,
|
||||||
|
scanlator = scanlator,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
package eu.kanade.tachiyomi.data.database.queries
|
package eu.kanade.tachiyomi.data.database.queries
|
||||||
|
|
||||||
import com.pushtorefresh.storio.sqlite.queries.Query
|
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.DbProvider
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaChapter
|
|
||||||
import eu.kanade.tachiyomi.data.database.resolvers.ChapterProgressPutResolver
|
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.data.database.tables.ChapterTable
|
||||||
import java.util.Date
|
|
||||||
|
|
||||||
interface ChapterQueries : DbProvider {
|
interface ChapterQueries : DbProvider {
|
||||||
|
|
||||||
@ -24,18 +20,6 @@ interface ChapterQueries : DbProvider {
|
|||||||
)
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun getRecentChapters(date: Date) = db.get()
|
|
||||||
.listOfObjects(MangaChapter::class.java)
|
|
||||||
.withQuery(
|
|
||||||
RawQuery.builder()
|
|
||||||
.query(getRecentsQuery())
|
|
||||||
.args(date.time)
|
|
||||||
.observesTables(ChapterTable.TABLE)
|
|
||||||
.build(),
|
|
||||||
)
|
|
||||||
.withGetResolver(MangaChapterGetResolver.INSTANCE)
|
|
||||||
.prepare()
|
|
||||||
|
|
||||||
fun getChapter(id: Long) = db.get()
|
fun getChapter(id: Long) = db.get()
|
||||||
.`object`(Chapter::class.java)
|
.`object`(Chapter::class.java)
|
||||||
.withQuery(
|
.withQuery(
|
||||||
|
@ -38,19 +38,6 @@ val libraryQuery =
|
|||||||
ON MC.${MangaCategory.COL_MANGA_ID} = M.${Manga.COL_ID}
|
ON MC.${MangaCategory.COL_MANGA_ID} = M.${Manga.COL_ID}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
/**
|
|
||||||
* Query to get the recent chapters of manga from the library up to a date.
|
|
||||||
*/
|
|
||||||
fun getRecentsQuery() =
|
|
||||||
"""
|
|
||||||
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_UPLOAD} > ?
|
|
||||||
AND ${Chapter.COL_DATE_FETCH} > ${Manga.COL_DATE_ADDED}
|
|
||||||
ORDER BY ${Chapter.COL_DATE_UPLOAD} DESC
|
|
||||||
"""
|
|
||||||
|
|
||||||
fun getLastReadMangaQuery() =
|
fun getLastReadMangaQuery() =
|
||||||
"""
|
"""
|
||||||
SELECT ${Manga.TABLE}.*, MAX(${History.TABLE}.${History.COL_LAST_READ}) AS max
|
SELECT ${Manga.TABLE}.*, MAX(${History.TABLE}.${History.COL_LAST_READ}) AS max
|
||||||
|
@ -2,16 +2,14 @@ package eu.kanade.tachiyomi.ui.manga.chapter.base
|
|||||||
|
|
||||||
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
|
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
|
||||||
import eu.davidea.flexibleadapter.items.AbstractSectionableItem
|
import eu.davidea.flexibleadapter.items.AbstractSectionableItem
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.domain.chapter.model.Chapter
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
|
|
||||||
abstract class BaseChapterItem<T : BaseChapterHolder, H : AbstractHeaderItem<*>>(
|
abstract class BaseChapterItem<T : BaseChapterHolder, H : AbstractHeaderItem<*>>(
|
||||||
val chapter: Chapter,
|
val chapter: Chapter,
|
||||||
header: H? = null,
|
header: H? = null,
|
||||||
) :
|
) : AbstractSectionableItem<T, H?>(header) {
|
||||||
AbstractSectionableItem<T, H?>(header),
|
|
||||||
Chapter by chapter {
|
|
||||||
|
|
||||||
private var _status: Download.State = Download.State.NOT_DOWNLOADED
|
private var _status: Download.State = Download.State.NOT_DOWNLOADED
|
||||||
|
|
||||||
@ -36,12 +34,14 @@ abstract class BaseChapterItem<T : BaseChapterHolder, H : AbstractHeaderItem<*>>
|
|||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other is BaseChapterItem<*, *>) {
|
if (other is BaseChapterItem<*, *>) {
|
||||||
return chapter.id!! == other.chapter.id!!
|
return chapter.id == other.chapter.id && chapter.read == other.chapter.read
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
return chapter.id!!.hashCode()
|
var result = chapter.id.hashCode()
|
||||||
|
result = 31 * result + chapter.read.hashCode()
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||||||
import dev.chrisbanes.insetter.applyInsetter
|
import dev.chrisbanes.insetter.applyInsetter
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.SelectableAdapter
|
import eu.davidea.flexibleadapter.SelectableAdapter
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadService
|
import eu.kanade.tachiyomi.data.download.DownloadService
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
@ -30,8 +29,10 @@ import eu.kanade.tachiyomi.util.system.notificationManager
|
|||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import eu.kanade.tachiyomi.util.view.onAnimationsFinished
|
import eu.kanade.tachiyomi.util.view.onAnimationsFinished
|
||||||
import eu.kanade.tachiyomi.widget.ActionModeWithToolbar
|
import eu.kanade.tachiyomi.widget.ActionModeWithToolbar
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import reactivecircus.flowbinding.recyclerview.scrollStateChanges
|
import reactivecircus.flowbinding.recyclerview.scrollStateChanges
|
||||||
import reactivecircus.flowbinding.swiperefreshlayout.refreshes
|
import reactivecircus.flowbinding.swiperefreshlayout.refreshes
|
||||||
@ -107,6 +108,24 @@ class UpdatesController :
|
|||||||
binding.swipeRefresh.isRefreshing = false
|
binding.swipeRefresh.isRefreshing = false
|
||||||
}
|
}
|
||||||
.launchIn(viewScope)
|
.launchIn(viewScope)
|
||||||
|
|
||||||
|
viewScope.launch {
|
||||||
|
presenter.updates.collectLatest { updatesItems ->
|
||||||
|
destroyActionModeIfNeeded()
|
||||||
|
if (adapter == null) {
|
||||||
|
adapter = UpdatesAdapter(this@UpdatesController, binding.recycler.context, updatesItems)
|
||||||
|
binding.recycler.adapter = adapter
|
||||||
|
adapter!!.fastScroller = binding.fastScroller
|
||||||
|
} else {
|
||||||
|
adapter?.updateDataSet(updatesItems)
|
||||||
|
}
|
||||||
|
binding.swipeRefresh.isRefreshing = false
|
||||||
|
binding.fastScroller.isVisible = true
|
||||||
|
binding.recycler.onAnimationsFinished {
|
||||||
|
(activity as? MainActivity)?.ready = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView(view: View) {
|
override fun onDestroyView(view: View) {
|
||||||
@ -191,7 +210,7 @@ class UpdatesController :
|
|||||||
*/
|
*/
|
||||||
private fun openChapter(item: UpdatesItem) {
|
private fun openChapter(item: UpdatesItem) {
|
||||||
val activity = activity ?: return
|
val activity = activity ?: return
|
||||||
val intent = ReaderActivity.newIntent(activity, item.manga, item.chapter)
|
val intent = ReaderActivity.newIntent(activity, item.manga.id, item.chapter.id)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,26 +223,6 @@ class UpdatesController :
|
|||||||
destroyActionModeIfNeeded()
|
destroyActionModeIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Populate adapter with chapters
|
|
||||||
* @param chapters list of [Any]
|
|
||||||
*/
|
|
||||||
fun onNextRecentChapters(chapters: List<IFlexible<*>>) {
|
|
||||||
destroyActionModeIfNeeded()
|
|
||||||
if (adapter == null) {
|
|
||||||
adapter = UpdatesAdapter(this@UpdatesController, binding.recycler.context, chapters)
|
|
||||||
binding.recycler.adapter = adapter
|
|
||||||
adapter!!.fastScroller = binding.fastScroller
|
|
||||||
} else {
|
|
||||||
adapter?.updateDataSet(chapters)
|
|
||||||
}
|
|
||||||
binding.swipeRefresh.isRefreshing = false
|
|
||||||
binding.fastScroller.isVisible = true
|
|
||||||
binding.recycler.onAnimationsFinished {
|
|
||||||
(activity as? MainActivity)?.ready = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onUpdateEmptyView(size: Int) {
|
override fun onUpdateEmptyView(size: Int) {
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
binding.emptyView.hide()
|
binding.emptyView.hide()
|
||||||
@ -317,8 +316,8 @@ class UpdatesController :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun startDownloadNow(position: Int) {
|
override fun startDownloadNow(position: Int) {
|
||||||
val chapter = adapter?.getItem(position) as? UpdatesItem ?: return
|
val item = adapter?.getItem(position) as? UpdatesItem ?: return
|
||||||
presenter.startDownloadingNow(chapter)
|
presenter.startDownloadingNow(item.chapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bookmarkChapters(chapters: List<UpdatesItem>, bookmarked: Boolean) {
|
private fun bookmarkChapters(chapters: List<UpdatesItem>, bookmarked: Boolean) {
|
||||||
@ -357,8 +356,8 @@ class UpdatesController :
|
|||||||
if (chapters.isEmpty()) return
|
if (chapters.isEmpty()) return
|
||||||
toolbar.findToolbarItem(R.id.action_download)?.isVisible = chapters.any { !it.isDownloaded }
|
toolbar.findToolbarItem(R.id.action_download)?.isVisible = chapters.any { !it.isDownloaded }
|
||||||
toolbar.findToolbarItem(R.id.action_delete)?.isVisible = chapters.any { it.isDownloaded }
|
toolbar.findToolbarItem(R.id.action_delete)?.isVisible = chapters.any { it.isDownloaded }
|
||||||
toolbar.findToolbarItem(R.id.action_bookmark)?.isVisible = chapters.any { !it.bookmark }
|
toolbar.findToolbarItem(R.id.action_bookmark)?.isVisible = chapters.any { !it.chapter.bookmark }
|
||||||
toolbar.findToolbarItem(R.id.action_remove_bookmark)?.isVisible = chapters.all { it.bookmark }
|
toolbar.findToolbarItem(R.id.action_remove_bookmark)?.isVisible = chapters.all { it.chapter.bookmark }
|
||||||
toolbar.findToolbarItem(R.id.action_mark_as_read)?.isVisible = chapters.any { !it.chapter.read }
|
toolbar.findToolbarItem(R.id.action_mark_as_read)?.isVisible = chapters.any { !it.chapter.read }
|
||||||
toolbar.findToolbarItem(R.id.action_mark_as_unread)?.isVisible = chapters.all { it.chapter.read }
|
toolbar.findToolbarItem(R.id.action_mark_as_unread)?.isVisible = chapters.all { it.chapter.read }
|
||||||
}
|
}
|
||||||
|
@ -44,12 +44,12 @@ class UpdatesHolder(private val view: View, private val adapter: UpdatesAdapter)
|
|||||||
} else {
|
} else {
|
||||||
binding.mangaTitle.setTextColor(adapter.unreadColor)
|
binding.mangaTitle.setTextColor(adapter.unreadColor)
|
||||||
binding.chapterTitle.setTextColor(
|
binding.chapterTitle.setTextColor(
|
||||||
if (item.bookmark) adapter.bookmarkedColor else adapter.unreadColorSecondary,
|
if (item.chapter.bookmark) adapter.bookmarkedColor else adapter.unreadColorSecondary,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set bookmark status
|
// Set bookmark status
|
||||||
binding.bookmarkIcon.isVisible = item.bookmark
|
binding.bookmarkIcon.isVisible = item.chapter.bookmark
|
||||||
|
|
||||||
// Set chapter status
|
// Set chapter status
|
||||||
binding.download.isVisible = item.manga.source != LocalSource.ID
|
binding.download.isVisible = item.manga.source != LocalSource.ID
|
||||||
|
@ -4,9 +4,9 @@ import android.view.View
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
import eu.kanade.domain.chapter.model.Chapter
|
||||||
|
import eu.kanade.domain.manga.model.Manga
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
|
||||||
import eu.kanade.tachiyomi.ui.manga.chapter.base.BaseChapterItem
|
import eu.kanade.tachiyomi.ui.manga.chapter.base.BaseChapterItem
|
||||||
import eu.kanade.tachiyomi.ui.recent.DateSectionItem
|
import eu.kanade.tachiyomi.ui.recent.DateSectionItem
|
||||||
|
|
||||||
|
@ -1,17 +1,28 @@
|
|||||||
package eu.kanade.tachiyomi.ui.recent.updates
|
package eu.kanade.tachiyomi.ui.recent.updates
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.data.DatabaseHandler
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.data.manga.mangaChapterMapper
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaChapter
|
import eu.kanade.domain.chapter.interactor.UpdateChapter
|
||||||
|
import eu.kanade.domain.chapter.model.Chapter
|
||||||
|
import eu.kanade.domain.chapter.model.ChapterUpdate
|
||||||
|
import eu.kanade.domain.chapter.model.toDbChapter
|
||||||
|
import eu.kanade.domain.manga.model.Manga
|
||||||
|
import eu.kanade.domain.manga.model.toDbManga
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||||
import eu.kanade.tachiyomi.ui.recent.DateSectionItem
|
import eu.kanade.tachiyomi.ui.recent.DateSectionItem
|
||||||
|
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||||
import eu.kanade.tachiyomi.util.lang.toDateKey
|
import eu.kanade.tachiyomi.util.lang.toDateKey
|
||||||
import eu.kanade.tachiyomi.util.system.logcat
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
@ -25,24 +36,22 @@ import java.util.TreeMap
|
|||||||
class UpdatesPresenter : BasePresenter<UpdatesController>() {
|
class UpdatesPresenter : BasePresenter<UpdatesController>() {
|
||||||
|
|
||||||
val preferences: PreferencesHelper by injectLazy()
|
val preferences: PreferencesHelper by injectLazy()
|
||||||
private val db: DatabaseHelper by injectLazy()
|
|
||||||
private val downloadManager: DownloadManager by injectLazy()
|
private val downloadManager: DownloadManager by injectLazy()
|
||||||
private val sourceManager: SourceManager by injectLazy()
|
private val sourceManager: SourceManager by injectLazy()
|
||||||
|
|
||||||
|
private val handler: DatabaseHandler by injectLazy()
|
||||||
|
private val updateChapter: UpdateChapter by injectLazy()
|
||||||
|
|
||||||
private val relativeTime: Int = preferences.relativeTime().get()
|
private val relativeTime: Int = preferences.relativeTime().get()
|
||||||
private val dateFormat: DateFormat = preferences.dateFormat()
|
private val dateFormat: DateFormat = preferences.dateFormat()
|
||||||
|
|
||||||
/**
|
private val _updates: MutableStateFlow<List<UpdatesItem>> = MutableStateFlow(listOf())
|
||||||
* List containing chapter and manga information
|
val updates: StateFlow<List<UpdatesItem>> = _updates.asStateFlow()
|
||||||
*/
|
|
||||||
private var chapters: List<UpdatesItem> = emptyList()
|
|
||||||
|
|
||||||
override fun onCreate(savedState: Bundle?) {
|
override fun onCreate(savedState: Bundle?) {
|
||||||
super.onCreate(savedState)
|
super.onCreate(savedState)
|
||||||
|
|
||||||
getUpdatesObservable()
|
getUpdatesObservable()
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribeLatestCache(UpdatesController::onNextRecentChapters)
|
|
||||||
|
|
||||||
downloadManager.queue.getStatusObservable()
|
downloadManager.queue.getStatusObservable()
|
||||||
.observeOn(Schedulers.io())
|
.observeOn(Schedulers.io())
|
||||||
@ -72,27 +81,29 @@ class UpdatesPresenter : BasePresenter<UpdatesController>() {
|
|||||||
*
|
*
|
||||||
* @return observable containing recent chapters and date
|
* @return observable containing recent chapters and date
|
||||||
*/
|
*/
|
||||||
private fun getUpdatesObservable(): Observable<List<UpdatesItem>> {
|
private fun getUpdatesObservable() {
|
||||||
// Set date limit for recent chapters
|
// Set date limit for recent chapters
|
||||||
|
presenterScope.launchIO {
|
||||||
val cal = Calendar.getInstance().apply {
|
val cal = Calendar.getInstance().apply {
|
||||||
time = Date()
|
time = Date()
|
||||||
add(Calendar.MONTH, -3)
|
add(Calendar.MONTH, -3)
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.getRecentChapters(cal.time).asRxObservable()
|
handler
|
||||||
// Convert to a list of recent chapters.
|
.subscribeToList {
|
||||||
.map { mangaChapters ->
|
mangasQueries.getRecentlyUpdated(after = cal.timeInMillis, mangaChapterMapper)
|
||||||
val map = TreeMap<Date, MutableList<MangaChapter>> { d1, d2 -> d2.compareTo(d1) }
|
}
|
||||||
val byDay = mangaChapters
|
.map { mangaChapter ->
|
||||||
.groupByTo(map) { it.chapter.date_fetch.toDateKey() }
|
val map = TreeMap<Date, MutableList<Pair<Manga, Chapter>>> { d1, d2 -> d2.compareTo(d1) }
|
||||||
byDay.flatMap { entry ->
|
val byDate = mangaChapter.groupByTo(map) { it.second.dateFetch.toDateKey() }
|
||||||
|
byDate.flatMap { entry ->
|
||||||
val dateItem = DateSectionItem(entry.key, relativeTime, dateFormat)
|
val dateItem = DateSectionItem(entry.key, relativeTime, dateFormat)
|
||||||
entry.value
|
entry.value
|
||||||
.sortedWith(compareBy({ it.chapter.date_fetch }, { it.chapter.chapter_number })).asReversed()
|
.sortedWith(compareBy({ it.second.dateFetch }, { it.second.chapterNumber })).asReversed()
|
||||||
.map { UpdatesItem(it.chapter, it.manga, dateItem) }
|
.map { UpdatesItem(it.second, it.first, dateItem) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.doOnNext { list ->
|
.collectLatest { list ->
|
||||||
list.forEach { item ->
|
list.forEach { item ->
|
||||||
// Find an active download for this chapter.
|
// Find an active download for this chapter.
|
||||||
val download = downloadManager.queue.find { it.chapter.id == item.chapter.id }
|
val download = downloadManager.queue.find { it.chapter.id == item.chapter.id }
|
||||||
@ -104,10 +115,12 @@ class UpdatesPresenter : BasePresenter<UpdatesController>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
setDownloadedChapters(list)
|
setDownloadedChapters(list)
|
||||||
chapters = list
|
|
||||||
|
_updates.value = list
|
||||||
|
|
||||||
// Set unread chapter count for bottom bar badge
|
// Set unread chapter count for bottom bar badge
|
||||||
preferences.unreadUpdatesCount().set(list.count { !it.read })
|
preferences.unreadUpdatesCount().set(list.count { !it.chapter.read })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +148,7 @@ class UpdatesPresenter : BasePresenter<UpdatesController>() {
|
|||||||
private fun onDownloadStatusChange(download: Download) {
|
private fun onDownloadStatusChange(download: Download) {
|
||||||
// Assign the download to the model object.
|
// Assign the download to the model object.
|
||||||
if (download.status == Download.State.QUEUE) {
|
if (download.status == Download.State.QUEUE) {
|
||||||
|
val chapters = (view?.adapter?.currentItems ?: emptyList()).filterIsInstance<UpdatesItem>()
|
||||||
val chapter = chapters.find { it.chapter.id == download.chapter.id }
|
val chapter = chapters.find { it.chapter.id == download.chapter.id }
|
||||||
if (chapter != null && chapter.download == null) {
|
if (chapter != null && chapter.download == null) {
|
||||||
chapter.download = download
|
chapter.download = download
|
||||||
@ -153,17 +167,16 @@ class UpdatesPresenter : BasePresenter<UpdatesController>() {
|
|||||||
* @param read read status
|
* @param read read status
|
||||||
*/
|
*/
|
||||||
fun markChapterRead(items: List<UpdatesItem>, read: Boolean) {
|
fun markChapterRead(items: List<UpdatesItem>, read: Boolean) {
|
||||||
val chapters = items.map { it.chapter }
|
presenterScope.launchIO {
|
||||||
chapters.forEach {
|
val toUpdate = items.map {
|
||||||
it.read = read
|
ChapterUpdate(
|
||||||
if (!read) {
|
read = read,
|
||||||
it.last_page_read = 0
|
lastPageRead = if (!read) 0 else null,
|
||||||
|
id = it.chapter.id,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
updateChapter.awaitAll(toUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
Observable.fromCallable { db.updateChaptersProgress(chapters).executeAsBlocking() }
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.subscribe()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -190,14 +203,15 @@ class UpdatesPresenter : BasePresenter<UpdatesController>() {
|
|||||||
* @param bookmarked bookmark status
|
* @param bookmarked bookmark status
|
||||||
*/
|
*/
|
||||||
fun bookmarkChapters(items: List<UpdatesItem>, bookmarked: Boolean) {
|
fun bookmarkChapters(items: List<UpdatesItem>, bookmarked: Boolean) {
|
||||||
val chapters = items.map { it.chapter }
|
presenterScope.launchIO {
|
||||||
chapters.forEach {
|
val toUpdate = items.map {
|
||||||
it.bookmark = bookmarked
|
ChapterUpdate(
|
||||||
|
bookmark = bookmarked,
|
||||||
|
id = it.chapter.id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
updateChapter.awaitAll(toUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
Observable.fromCallable { db.updateChaptersProgress(chapters).executeAsBlocking() }
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.subscribe()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -205,7 +219,7 @@ class UpdatesPresenter : BasePresenter<UpdatesController>() {
|
|||||||
* @param items list of recent chapters seleted.
|
* @param items list of recent chapters seleted.
|
||||||
*/
|
*/
|
||||||
fun downloadChapters(items: List<UpdatesItem>) {
|
fun downloadChapters(items: List<UpdatesItem>) {
|
||||||
items.forEach { downloadManager.downloadChapters(it.manga, listOf(it.chapter)) }
|
items.forEach { downloadManager.downloadChapters(it.manga.toDbManga(), listOf(it.chapter.toDbChapter())) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -216,9 +230,9 @@ class UpdatesPresenter : BasePresenter<UpdatesController>() {
|
|||||||
private fun deleteChaptersInternal(chapterItems: List<UpdatesItem>) {
|
private fun deleteChaptersInternal(chapterItems: List<UpdatesItem>) {
|
||||||
val itemsByManga = chapterItems.groupBy { it.manga.id }
|
val itemsByManga = chapterItems.groupBy { it.manga.id }
|
||||||
for ((_, items) in itemsByManga) {
|
for ((_, items) in itemsByManga) {
|
||||||
val manga = items.first().manga
|
val manga = items.first().manga.toDbManga()
|
||||||
val source = sourceManager.get(manga.source) ?: continue
|
val source = sourceManager.get(manga.source) ?: continue
|
||||||
val chapters = items.map { it.chapter }
|
val chapters = items.map { it.chapter.toDbChapter() }
|
||||||
|
|
||||||
downloadManager.deleteChapters(chapters, manga, source)
|
downloadManager.deleteChapters(chapters, manga, source)
|
||||||
items.forEach {
|
items.forEach {
|
||||||
|
@ -76,6 +76,16 @@ FROM mangas
|
|||||||
WHERE favorite = 0
|
WHERE favorite = 0
|
||||||
GROUP BY source;
|
GROUP BY source;
|
||||||
|
|
||||||
|
getRecentlyUpdated:
|
||||||
|
SELECT *
|
||||||
|
FROM mangas M
|
||||||
|
JOIN chapters C
|
||||||
|
ON M._id = C.manga_id
|
||||||
|
WHERE M.favorite = 1
|
||||||
|
AND C.date_upload > :after
|
||||||
|
AND C.date_fetch > M.date_added
|
||||||
|
ORDER BY C.date_upload DESC;
|
||||||
|
|
||||||
deleteMangasNotInLibraryBySourceIds:
|
deleteMangasNotInLibraryBySourceIds:
|
||||||
DELETE FROM mangas
|
DELETE FROM mangas
|
||||||
WHERE favorite = 0 AND source IN :sourceIds;
|
WHERE favorite = 0 AND source IN :sourceIds;
|
||||||
|
Loading…
Reference in New Issue
Block a user