mirror of
https://github.com/null2264/yokai.git
synced 2025-07-16 22:06:54 +00:00
refactor(manga): Slowly using flow attempt 2
This commit is contained in:
parent
f8d74a6b2f
commit
f81be429df
3 changed files with 183 additions and 169 deletions
|
@ -182,6 +182,37 @@ var Manga.vibrantCoverColor: Int?
|
||||||
id?.let { MangaCoverMetadata.setVibrantColor(it, value) }
|
id?.let { MangaCoverMetadata.setVibrantColor(it, value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Manga.copyDomain(): Manga = MangaImpl().also { other ->
|
||||||
|
other.url = this.url
|
||||||
|
other.title = this.title
|
||||||
|
other.artist = this.artist
|
||||||
|
other.author = this.author
|
||||||
|
other.description = this.description
|
||||||
|
other.genre = this.genre
|
||||||
|
other.status = this.status
|
||||||
|
other.thumbnail_url = this.thumbnail_url
|
||||||
|
other.initialized = this.initialized
|
||||||
|
|
||||||
|
other.id = this.id
|
||||||
|
other.source = this.source
|
||||||
|
other.favorite = this.favorite
|
||||||
|
other.last_update = this.last_update
|
||||||
|
other.date_added = this.date_added
|
||||||
|
other.viewer_flags = this.viewer_flags
|
||||||
|
other.chapter_flags = this.chapter_flags
|
||||||
|
other.hide_title = this.hide_title
|
||||||
|
other.filtered_scanlators = this.filtered_scanlators
|
||||||
|
|
||||||
|
other.ogTitle = this.ogTitle
|
||||||
|
other.ogAuthor = this.ogAuthor
|
||||||
|
other.ogArtist = this.ogArtist
|
||||||
|
other.ogDesc = this.ogDesc
|
||||||
|
other.ogGenre = this.ogGenre
|
||||||
|
other.ogStatus = this.ogStatus
|
||||||
|
|
||||||
|
other.cover_last_modified = this.cover_last_modified
|
||||||
|
}
|
||||||
|
|
||||||
fun Manga.Companion.create(source: Long) = MangaImpl().apply {
|
fun Manga.Companion.create(source: Long) = MangaImpl().apply {
|
||||||
this.source = source
|
this.source = source
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,7 +194,7 @@ class MangaDetailsController :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val manga: Manga? get() = if (presenter.isMangaLateInitInitialized()) presenter.manga else null
|
private val manga: Manga? get() = presenter.currentManga.value
|
||||||
private var colorAnimator: ValueAnimator? = null
|
private var colorAnimator: ValueAnimator? = null
|
||||||
override val presenter: MangaDetailsPresenter
|
override val presenter: MangaDetailsPresenter
|
||||||
private var coverColor: Int? = null
|
private var coverColor: Int? = null
|
||||||
|
@ -674,7 +674,7 @@ class MangaDetailsController :
|
||||||
returningFromReader = false
|
returningFromReader = false
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val itemAnimator = binding.recycler.itemAnimator
|
val itemAnimator = binding.recycler.itemAnimator
|
||||||
val chapters = withTimeoutOrNull(1000) { presenter.getChaptersNow() } ?: return@runBlocking
|
val chapters = withTimeoutOrNull(1000) { presenter.setAndGetChapters() } ?: return@runBlocking
|
||||||
binding.recycler.itemAnimator = null
|
binding.recycler.itemAnimator = null
|
||||||
tabletAdapter?.notifyItemChanged(0)
|
tabletAdapter?.notifyItemChanged(0)
|
||||||
adapter?.setChapters(chapters)
|
adapter?.setChapters(chapters)
|
||||||
|
@ -821,15 +821,11 @@ class MangaDetailsController :
|
||||||
updateMenuVisibility(activityBinding?.toolbar?.menu)
|
updateMenuVisibility(activityBinding?.toolbar?.menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateChapters(chapters: List<ChapterItem>) {
|
fun updateChapters() {
|
||||||
view ?: return
|
view ?: return
|
||||||
binding.swipeRefresh.isRefreshing = presenter.isLoading
|
binding.swipeRefresh.isRefreshing = presenter.isLoading
|
||||||
if (presenter.chapters.isEmpty() && fromCatalogue && !presenter.hasRequested) {
|
adapter?.setChapters(presenter.chapters)
|
||||||
launchUI { binding.swipeRefresh.isRefreshing = true }
|
|
||||||
presenter.fetchChaptersFromSource()
|
|
||||||
}
|
|
||||||
tabletAdapter?.notifyItemChanged(0)
|
tabletAdapter?.notifyItemChanged(0)
|
||||||
adapter?.setChapters(chapters)
|
|
||||||
addMangaHeader()
|
addMangaHeader()
|
||||||
colorToolbar(binding.recycler.canScrollVertically(-1))
|
colorToolbar(binding.recycler.canScrollVertically(-1))
|
||||||
updateMenuVisibility(activityBinding?.toolbar?.menu)
|
updateMenuVisibility(activityBinding?.toolbar?.menu)
|
||||||
|
|
|
@ -18,6 +18,7 @@ import eu.kanade.tachiyomi.data.database.models.History
|
||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
import eu.kanade.tachiyomi.data.database.models.bookmarkedFilter
|
import eu.kanade.tachiyomi.data.database.models.bookmarkedFilter
|
||||||
import eu.kanade.tachiyomi.data.database.models.chapterOrder
|
import eu.kanade.tachiyomi.data.database.models.chapterOrder
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.copyDomain
|
||||||
import eu.kanade.tachiyomi.data.database.models.downloadedFilter
|
import eu.kanade.tachiyomi.data.database.models.downloadedFilter
|
||||||
import eu.kanade.tachiyomi.data.database.models.prepareCoverUpdate
|
import eu.kanade.tachiyomi.data.database.models.prepareCoverUpdate
|
||||||
import eu.kanade.tachiyomi.data.database.models.readFilter
|
import eu.kanade.tachiyomi.data.database.models.readFilter
|
||||||
|
@ -34,6 +35,7 @@ import eu.kanade.tachiyomi.data.track.EnhancedTrackService
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.data.track.TrackService
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
import eu.kanade.tachiyomi.domain.manga.models.Manga
|
import eu.kanade.tachiyomi.domain.manga.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.network.HttpException
|
||||||
import eu.kanade.tachiyomi.network.NetworkPreferences
|
import eu.kanade.tachiyomi.network.NetworkPreferences
|
||||||
import eu.kanade.tachiyomi.source.LocalSource
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
|
@ -76,11 +78,15 @@ import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.filter
|
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 kotlinx.coroutines.flow.update
|
||||||
|
import kotlinx.coroutines.flow.updateAndGet
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
@ -127,11 +133,15 @@ class MangaDetailsPresenter(
|
||||||
|
|
||||||
private val networkPreferences: NetworkPreferences by injectLazy()
|
private val networkPreferences: NetworkPreferences by injectLazy()
|
||||||
|
|
||||||
// private val currentMangaInternal: MutableStateFlow<Manga?> = MutableStateFlow(null)
|
private val currentMangaInternal = MutableStateFlow<Manga?>(null)
|
||||||
// val currentManga get() = currentMangaInternal.asStateFlow()
|
val currentManga = currentMangaInternal.asStateFlow()
|
||||||
|
|
||||||
lateinit var manga: Manga
|
/**
|
||||||
fun isMangaLateInitInitialized() = ::manga.isInitialized
|
* Unsafe, call only after currentManga is no longer null
|
||||||
|
*/
|
||||||
|
var manga: Manga
|
||||||
|
get() = currentManga.value!!
|
||||||
|
set(value) { currentMangaInternal.value = value }
|
||||||
|
|
||||||
private val customMangaManager: CustomMangaManager by injectLazy()
|
private val customMangaManager: CustomMangaManager by injectLazy()
|
||||||
private val mangaShortcutManager: MangaShortcutManager by injectLazy()
|
private val mangaShortcutManager: MangaShortcutManager by injectLazy()
|
||||||
|
@ -151,8 +161,12 @@ class MangaDetailsPresenter(
|
||||||
|
|
||||||
var trackList: List<TrackItem> = emptyList()
|
var trackList: List<TrackItem> = emptyList()
|
||||||
|
|
||||||
var chapters: List<ChapterItem> = emptyList()
|
private val currentChaptersInternal = MutableStateFlow<List<ChapterItem>>(emptyList())
|
||||||
private set
|
val currentChapters = currentChaptersInternal.asStateFlow()
|
||||||
|
|
||||||
|
var chapters: List<ChapterItem>
|
||||||
|
get() = currentChapters.value
|
||||||
|
private set(value) { currentChaptersInternal.value = value }
|
||||||
|
|
||||||
var allChapters: List<ChapterItem> = emptyList()
|
var allChapters: List<ChapterItem> = emptyList()
|
||||||
private set
|
private set
|
||||||
|
@ -186,7 +200,7 @@ class MangaDetailsPresenter(
|
||||||
val controller = view ?: return
|
val controller = view ?: return
|
||||||
|
|
||||||
isLockedFromSearch = controller.shouldLockIfNeeded && SecureActivityDelegate.shouldBeLocked()
|
isLockedFromSearch = controller.shouldLockIfNeeded && SecureActivityDelegate.shouldBeLocked()
|
||||||
if (!::manga.isInitialized) runBlocking { refreshMangaFromDb() }
|
if (currentManga.value == null) runBlocking { refreshMangaFromDb() }
|
||||||
syncData()
|
syncData()
|
||||||
|
|
||||||
presenterScope.launchUI {
|
presenterScope.launchUI {
|
||||||
|
@ -204,6 +218,26 @@ class MangaDetailsPresenter(
|
||||||
presenterScope.launchIO {
|
presenterScope.launchIO {
|
||||||
downloadManager.queueState.collectLatest(::onQueueUpdate)
|
downloadManager.queueState.collectLatest(::onQueueUpdate)
|
||||||
}
|
}
|
||||||
|
presenterScope.launchUI {
|
||||||
|
currentManga.collectLatest {
|
||||||
|
if (it == null) return@collectLatest
|
||||||
|
|
||||||
|
controller.updateHeader()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
presenterScope.launchIO {
|
||||||
|
currentChapters.collectLatest { chapters ->
|
||||||
|
allChapters = if (!isScanlatorFiltered()) chapters else getChapter.awaitAll(mangaId, false).map { it.toModel() }
|
||||||
|
|
||||||
|
allChapterScanlators = allChapters.mapNotNull { it.chapter.scanlator }.toSet()
|
||||||
|
|
||||||
|
getHistory()
|
||||||
|
|
||||||
|
withUIContext {
|
||||||
|
controller.updateChapters()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
tracks = getTrack.awaitAllByMangaId(mangaId)
|
tracks = getTrack.awaitAllByMangaId(mangaId)
|
||||||
|
@ -216,25 +250,24 @@ class MangaDetailsPresenter(
|
||||||
fun onCreateLate() {
|
fun onCreateLate() {
|
||||||
val controller = view ?: return
|
val controller = view ?: return
|
||||||
|
|
||||||
|
isLoading = true
|
||||||
|
controller.setRefresh(true) // FIXME: Use progress indicator instead
|
||||||
|
|
||||||
LibraryUpdateJob.updateFlow
|
LibraryUpdateJob.updateFlow
|
||||||
.filter { it == mangaId }
|
.filter { it == mangaId }
|
||||||
.onEach { onUpdateManga() }
|
.onEach { onUpdateManga() }
|
||||||
.launchIn(presenterScope)
|
.launchIn(presenterScope)
|
||||||
|
|
||||||
if (manga.isLocal()) {
|
val updateMangaNeeded = !manga.initialized
|
||||||
refreshAll()
|
val updateChaptersNeeded = runBlocking { setAndGetChapters() }.isEmpty()
|
||||||
} else if (!manga.initialized) {
|
|
||||||
isLoading = true
|
|
||||||
controller.setRefresh(true)
|
|
||||||
controller.updateHeader()
|
|
||||||
refreshAll()
|
|
||||||
} else {
|
|
||||||
runBlocking { getChapters() }
|
|
||||||
controller.updateChapters(this.chapters)
|
|
||||||
getHistory()
|
|
||||||
}
|
|
||||||
|
|
||||||
presenterScope.launch {
|
presenterScope.launch {
|
||||||
|
val tasks = listOf(
|
||||||
|
async { if (updateMangaNeeded) fetchMangaFromSource() },
|
||||||
|
async { if (updateChaptersNeeded) fetchChaptersFromSource(false) },
|
||||||
|
)
|
||||||
|
tasks.awaitAll()
|
||||||
|
|
||||||
setTrackItems()
|
setTrackItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,16 +276,14 @@ class MangaDetailsPresenter(
|
||||||
|
|
||||||
fun fetchChapters(andTracking: Boolean = true) {
|
fun fetchChapters(andTracking: Boolean = true) {
|
||||||
presenterScope.launch {
|
presenterScope.launch {
|
||||||
getChapters()
|
setCurrentChapters(getChapters())
|
||||||
if (andTracking) fetchTracks()
|
if (andTracking) fetchTracks()
|
||||||
withContext(Dispatchers.Main) { view?.updateChapters(chapters) }
|
|
||||||
getHistory()
|
getHistory()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setCurrentManga(manga: Manga?) {
|
fun setCurrentManga(manga: Manga?) {
|
||||||
// currentMangaInternal.update { manga }
|
currentMangaInternal.update { manga }
|
||||||
this.manga = manga!!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Use flow to "sync" data instead
|
// TODO: Use flow to "sync" data instead
|
||||||
|
@ -264,20 +295,18 @@ class MangaDetailsPresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getChaptersNow(): List<ChapterItem> {
|
// TODO: Use getChapter.subscribe() flow instead
|
||||||
getChapters()
|
suspend fun setAndGetChapters(): List<ChapterItem> {
|
||||||
return chapters
|
return currentChaptersInternal.updateAndGet { getChapters().applyChapterFilters() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getChapters(queue: List<Download> = downloadManager.queueState.value) {
|
// TODO: Use getChapter.subscribe() flow instead
|
||||||
val chapters = getChapter.awaitAll(mangaId, isScanlatorFiltered()).map { it.toModel() }
|
private fun setCurrentChapters(chapters: List<ChapterItem>) {
|
||||||
allChapters = if (!isScanlatorFiltered()) chapters else getChapter.awaitAll(mangaId, false).map { it.toModel() }
|
currentChaptersInternal.update { chapters.applyChapterFilters() }
|
||||||
|
}
|
||||||
|
|
||||||
// Find downloaded chapters
|
private suspend fun getChapters(): List<ChapterItem> {
|
||||||
setDownloadedChapters(chapters, queue)
|
return getChapter.awaitAll(mangaId, isScanlatorFiltered()).map { it.toModel() }
|
||||||
allChapterScanlators = allChapters.mapNotNull { it.chapter.scanlator }.toSet()
|
|
||||||
|
|
||||||
this.chapters = applyChapterFilters(chapters)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getHistory() {
|
private fun getHistory() {
|
||||||
|
@ -291,14 +320,17 @@ class MangaDetailsPresenter(
|
||||||
*
|
*
|
||||||
* @param chapters the list of chapter from the database.
|
* @param chapters the list of chapter from the database.
|
||||||
*/
|
*/
|
||||||
private fun setDownloadedChapters(chapters: List<ChapterItem>, queue: List<Download>) {
|
private fun setDownloadedChapters(queue: List<Download>) {
|
||||||
for (chapter in chapters) {
|
currentChaptersInternal.update { chapters ->
|
||||||
if (downloadManager.isChapterDownloaded(chapter, manga)) {
|
for (chapter in chapters) {
|
||||||
chapter.status = Download.State.DOWNLOADED
|
if (downloadManager.isChapterDownloaded(chapter, manga)) {
|
||||||
} else if (queue.isNotEmpty()) {
|
chapter.status = Download.State.DOWNLOADED
|
||||||
chapter.status = queue.find { it.chapter.id == chapter.id }
|
} else if (queue.isNotEmpty()) {
|
||||||
?.status ?: Download.State.default
|
chapter.status = queue.find { it.chapter.id == chapter.id }
|
||||||
|
?.status ?: Download.State.default
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
chapters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,12 +364,12 @@ class MangaDetailsPresenter(
|
||||||
* @param chapterList the list of chapters from the database
|
* @param chapterList the list of chapters from the database
|
||||||
* @return an observable of the list of chapters filtered and sorted.
|
* @return an observable of the list of chapters filtered and sorted.
|
||||||
*/
|
*/
|
||||||
private fun applyChapterFilters(chapterList: List<ChapterItem>): List<ChapterItem> {
|
private fun List<ChapterItem>.applyChapterFilters(): List<ChapterItem> {
|
||||||
if (isLockedFromSearch) {
|
if (isLockedFromSearch) {
|
||||||
return chapterList
|
return this
|
||||||
}
|
}
|
||||||
getScrollType(chapterList)
|
getScrollType(this)
|
||||||
return chapterSort.getChaptersSorted(chapterList)
|
return chapterSort.getChaptersSorted(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getChapterUrl(chapter: Chapter): String? {
|
fun getChapterUrl(chapter: Chapter): String? {
|
||||||
|
@ -394,7 +426,7 @@ class MangaDetailsPresenter(
|
||||||
download = null
|
download = null
|
||||||
}
|
}
|
||||||
|
|
||||||
view?.updateChapters(this.chapters)
|
view?.updateChapters()
|
||||||
|
|
||||||
downloadManager.deleteChapters(listOf(chapter), manga, source, true)
|
downloadManager.deleteChapters(listOf(chapter), manga, source, true)
|
||||||
}
|
}
|
||||||
|
@ -412,7 +444,7 @@ class MangaDetailsPresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update) view?.updateChapters(this.chapters)
|
if (update) view?.updateChapters()
|
||||||
|
|
||||||
if (isEverything) {
|
if (isEverything) {
|
||||||
downloadManager.deleteManga(manga, source)
|
downloadManager.deleteManga(manga, source)
|
||||||
|
@ -432,125 +464,80 @@ class MangaDetailsPresenter(
|
||||||
if (view?.isNotOnline() == true && !manga.isLocal()) return
|
if (view?.isNotOnline() == true && !manga.isLocal()) return
|
||||||
presenterScope.launch {
|
presenterScope.launch {
|
||||||
isLoading = true
|
isLoading = true
|
||||||
var mangaError: java.lang.Exception? = null
|
val tasks = listOf(
|
||||||
var chapterError: java.lang.Exception? = null
|
async { fetchMangaFromSource() },
|
||||||
val chapters = async(Dispatchers.IO) {
|
async { fetchChaptersFromSource() },
|
||||||
try {
|
)
|
||||||
source.getChapterList(manga.copy())
|
tasks.awaitAll()
|
||||||
} catch (e: Exception) {
|
isLoading = false
|
||||||
chapterError = e
|
}
|
||||||
emptyList()
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
val nManga = async(Dispatchers.IO) {
|
|
||||||
try {
|
|
||||||
source.getMangaDetails(manga.copy())
|
|
||||||
} catch (e: java.lang.Exception) {
|
|
||||||
mangaError = e
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val networkManga = nManga.await()
|
private suspend fun fetchMangaFromSource() {
|
||||||
if (networkManga != null) {
|
try {
|
||||||
manga.prepareCoverUpdate(coverCache, networkManga, false)
|
val manga = manga.copyDomain()
|
||||||
manga.copyFrom(networkManga)
|
val networkManga = source.getMangaDetails(manga.copy())
|
||||||
manga.initialized = true
|
|
||||||
|
|
||||||
updateManga.await(manga.toMangaUpdate())
|
manga.prepareCoverUpdate(coverCache, networkManga, false)
|
||||||
|
manga.copyFrom(networkManga)
|
||||||
|
manga.initialized = true
|
||||||
|
|
||||||
launchIO {
|
updateManga.await(manga.toMangaUpdate())
|
||||||
val request =
|
|
||||||
ImageRequest.Builder(preferences.context).data(manga.cover())
|
|
||||||
.memoryCachePolicy(CachePolicy.DISABLED)
|
|
||||||
.diskCachePolicy(CachePolicy.WRITE_ONLY)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
if (preferences.context.imageLoader.execute(request) is SuccessResult) {
|
setCurrentManga(manga)
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
view?.setPaletteColor()
|
presenterScope.launchNonCancellableIO {
|
||||||
}
|
val request =
|
||||||
|
ImageRequest.Builder(preferences.context).data(manga.cover())
|
||||||
|
.memoryCachePolicy(CachePolicy.DISABLED)
|
||||||
|
.diskCachePolicy(CachePolicy.WRITE_ONLY)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
if (preferences.context.imageLoader.execute(request) is SuccessResult) {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
view?.setPaletteColor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val finChapters = chapters.await()
|
} catch (e: Exception) {
|
||||||
if (finChapters.isNotEmpty()) {
|
if (e is HttpException && e.code == 103) return
|
||||||
val newChapters = withIOContext { syncChaptersWithSource(finChapters, manga, source) }
|
|
||||||
if (newChapters.first.isNotEmpty()) {
|
withUIContext {
|
||||||
|
view?.showError(trimException(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun fetchChaptersFromSource(manualFetch: Boolean = true) {
|
||||||
|
try {
|
||||||
|
withIOContext {
|
||||||
|
val chapters = source.getChapterList(manga.copy())
|
||||||
|
val (added, removed) = syncChaptersWithSource(chapters, manga, source)
|
||||||
|
if (added.isNotEmpty() && manualFetch) {
|
||||||
if (manga.shouldDownloadNewChapters(preferences)) {
|
if (manga.shouldDownloadNewChapters(preferences)) {
|
||||||
downloadChapters(
|
downloadChapters(added.sortedBy { it.chapter_number }.map { it.toModel() })
|
||||||
newChapters.first.sortedBy { it.chapter_number }
|
}
|
||||||
.map { it.toModel() },
|
withUIContext {
|
||||||
)
|
view?.view?.context?.let { mangaShortcutManager.updateShortcuts(it) }
|
||||||
}
|
}
|
||||||
view?.view?.context?.let { mangaShortcutManager.updateShortcuts(it) }
|
|
||||||
}
|
}
|
||||||
if (newChapters.second.isNotEmpty()) {
|
if (removed.isNotEmpty() && manualFetch) {
|
||||||
val removedChaptersId = newChapters.second.map { it.id }
|
val removedChaptersId = removed.map { it.id }
|
||||||
val removedChapters = this@MangaDetailsPresenter.chapters.filter {
|
val removedChapters = this@MangaDetailsPresenter.chapters.filter {
|
||||||
it.id in removedChaptersId && it.isDownloaded
|
it.id in removedChaptersId && it.isDownloaded
|
||||||
}
|
}
|
||||||
if (removedChapters.isNotEmpty()) {
|
if (removedChapters.isNotEmpty()) {
|
||||||
withContext(Dispatchers.Main) {
|
withUIContext {
|
||||||
view?.showChaptersRemovedPopup(
|
view?.showChaptersRemovedPopup(removedChapters)
|
||||||
removedChapters,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getChapters()
|
setCurrentChapters(getChapters())
|
||||||
}
|
|
||||||
isLoading = false
|
|
||||||
if (chapterError == null) {
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
view?.updateChapters(this@MangaDetailsPresenter.chapters)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (chapterError != null) {
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
view?.showError(
|
|
||||||
trimException(chapterError!!),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return@launch
|
|
||||||
} else if (mangaError != null) {
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
view?.showError(
|
|
||||||
trimException(mangaError!!),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getHistory()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Requests an updated list of chapters from the source.
|
|
||||||
*/
|
|
||||||
fun fetchChaptersFromSource() {
|
|
||||||
hasRequested = true
|
|
||||||
isLoading = true
|
|
||||||
|
|
||||||
presenterScope.launch(Dispatchers.IO) {
|
|
||||||
val chapters = try {
|
|
||||||
source.getChapterList(manga.copy())
|
|
||||||
} catch (e: Exception) {
|
|
||||||
withContext(Dispatchers.Main) { view?.showError(trimException(e)) }
|
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
isLoading = false
|
|
||||||
try {
|
|
||||||
syncChaptersWithSource(chapters, manga, source)
|
|
||||||
|
|
||||||
getChapters()
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
view?.updateChapters(this@MangaDetailsPresenter.chapters)
|
|
||||||
}
|
|
||||||
getHistory()
|
getHistory()
|
||||||
} catch (e: java.lang.Exception) {
|
}
|
||||||
withContext(Dispatchers.Main) {
|
} catch (e: Exception) {
|
||||||
view?.showError(trimException(e))
|
withUIContext {
|
||||||
}
|
view?.showError(trimException(e))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -579,8 +566,7 @@ class MangaDetailsPresenter(
|
||||||
it.toProgressUpdate()
|
it.toProgressUpdate()
|
||||||
}
|
}
|
||||||
updateChapter.awaitAll(updates)
|
updateChapter.awaitAll(updates)
|
||||||
getChapters()
|
setCurrentChapters(getChapters())
|
||||||
withContext(Dispatchers.Main) { view?.updateChapters(chapters) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,8 +595,7 @@ class MangaDetailsPresenter(
|
||||||
if (read && deleteNow && preferences.removeAfterMarkedAsRead().get()) {
|
if (read && deleteNow && preferences.removeAfterMarkedAsRead().get()) {
|
||||||
deleteChapters(selectedChapters, false)
|
deleteChapters(selectedChapters, false)
|
||||||
}
|
}
|
||||||
getChapters()
|
setCurrentChapters(getChapters())
|
||||||
withContext(Dispatchers.Main) { view?.updateChapters(chapters) }
|
|
||||||
if (read && deleteNow) {
|
if (read && deleteNow) {
|
||||||
val latestReadChapter = selectedChapters.maxByOrNull { it.chapter_number.toInt() }?.chapter
|
val latestReadChapter = selectedChapters.maxByOrNull { it.chapter_number.toInt() }?.chapter
|
||||||
updateTrackChapterMarkedAsRead(preferences, latestReadChapter, manga.id) {
|
updateTrackChapterMarkedAsRead(preferences, latestReadChapter, manga.id) {
|
||||||
|
@ -741,8 +726,7 @@ class MangaDetailsPresenter(
|
||||||
|
|
||||||
private suspend fun asyncUpdateMangaAndChapters(justChapters: Boolean = false) {
|
private suspend fun asyncUpdateMangaAndChapters(justChapters: Boolean = false) {
|
||||||
if (!justChapters) updateManga.await(MangaUpdate(manga.id!!, chapterFlags = manga.chapter_flags))
|
if (!justChapters) updateManga.await(MangaUpdate(manga.id!!, chapterFlags = manga.chapter_flags))
|
||||||
getChapters()
|
setCurrentChapters(getChapters())
|
||||||
withUIContext { view?.updateChapters(chapters) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isScanlatorFiltered() = manga.filtered_scanlators?.isNotEmpty() == true
|
private fun isScanlatorFiltered() = manga.filtered_scanlators?.isNotEmpty() == true
|
||||||
|
@ -811,7 +795,7 @@ class MangaDetailsPresenter(
|
||||||
withUIContext {
|
withUIContext {
|
||||||
view?.shareManga(uri.uri.toFile())
|
view?.shareManga(uri.uri.toFile())
|
||||||
}
|
}
|
||||||
} catch (_: java.lang.Exception) {
|
} catch (_: Exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1153,15 +1137,15 @@ class MangaDetailsPresenter(
|
||||||
|
|
||||||
override fun onStatusChange(download: Download) {
|
override fun onStatusChange(download: Download) {
|
||||||
super.onStatusChange(download)
|
super.onStatusChange(download)
|
||||||
chapters.find { it.id == download.chapter.id }?.status = download.status
|
currentChaptersInternal.update { chapters ->
|
||||||
|
chapters.find { it.id == download.chapter.id }?.status = download.status
|
||||||
|
chapters
|
||||||
|
}
|
||||||
onPageProgressUpdate(download)
|
onPageProgressUpdate(download)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun onQueueUpdate(queue: List<Download>) = withIOContext {
|
private suspend fun onQueueUpdate(queue: List<Download>) = withIOContext {
|
||||||
getChapters(queue)
|
setDownloadedChapters(queue)
|
||||||
withUIContext {
|
|
||||||
view?.updateChapters(chapters)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onQueueUpdate(download: Download) {
|
override fun onQueueUpdate(download: Download) {
|
||||||
|
@ -1173,7 +1157,10 @@ class MangaDetailsPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPageProgressUpdate(download: Download) {
|
override fun onPageProgressUpdate(download: Download) {
|
||||||
chapters.find { it.id == download.chapter.id }?.download = download
|
currentChaptersInternal.update { chapters ->
|
||||||
|
chapters.find { it.id == download.chapter.id }?.download = download
|
||||||
|
chapters
|
||||||
|
}
|
||||||
view?.updateChapterDownload(download)
|
view?.updateChapterDownload(download)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue