mirror of
https://github.com/mihonapp/mihon.git
synced 2024-11-21 20:47:03 -05:00
manga-refresh-state (#8090)
This commit is contained in:
parent
633bd6eb46
commit
98a4f6cccb
3 changed files with 79 additions and 59 deletions
|
@ -24,4 +24,8 @@ class GetMangaWithChapters(
|
|||
suspend fun awaitManga(id: Long): Manga {
|
||||
return mangaRepository.getMangaById(id)
|
||||
}
|
||||
|
||||
suspend fun awaitChapters(id: Long): List<Chapter> {
|
||||
return chapterRepository.getChapterByMangaId(id)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -295,7 +295,7 @@ private fun MangaScreenSmallImpl(
|
|||
val topPadding = contentPadding.calculateTopPadding()
|
||||
|
||||
SwipeRefresh(
|
||||
state = rememberSwipeRefreshState(state.isRefreshingInfo || state.isRefreshingChapter),
|
||||
state = rememberSwipeRefreshState(state.isRefreshingData),
|
||||
onRefresh = onRefresh,
|
||||
swipeEnabled = !chapters.any { it.selected },
|
||||
indicatorPadding = contentPadding,
|
||||
|
@ -429,7 +429,7 @@ fun MangaScreenLargeImpl(
|
|||
val insetPadding = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal).asPaddingValues()
|
||||
val (topBarHeight, onTopBarHeightChanged) = remember { mutableStateOf(0) }
|
||||
SwipeRefresh(
|
||||
state = rememberSwipeRefreshState(state.isRefreshingInfo || state.isRefreshingChapter),
|
||||
state = rememberSwipeRefreshState(state.isRefreshingData),
|
||||
onRefresh = onRefresh,
|
||||
swipeEnabled = !chapters.any { it.selected },
|
||||
indicatorPadding = PaddingValues(
|
||||
|
|
|
@ -47,6 +47,7 @@ import eu.kanade.tachiyomi.util.chapter.getChapterSort
|
|||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.launchNonCancellable
|
||||
import eu.kanade.tachiyomi.util.lang.toRelativeString
|
||||
import eu.kanade.tachiyomi.util.lang.withIOContext
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import eu.kanade.tachiyomi.util.preference.asHotFlow
|
||||
import eu.kanade.tachiyomi.util.removeCovers
|
||||
|
@ -67,6 +68,7 @@ import kotlinx.coroutines.flow.filter
|
|||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
import kotlinx.coroutines.withContext
|
||||
|
@ -84,7 +86,6 @@ class MangaPresenter(
|
|||
val mangaId: Long,
|
||||
val isFromSource: Boolean,
|
||||
private val basePreferences: BasePreferences = Injekt.get(),
|
||||
private val uiPreferences: UiPreferences = Injekt.get(),
|
||||
private val downloadPreferences: DownloadPreferences = Injekt.get(),
|
||||
private val libraryPreferences: LibraryPreferences = Injekt.get(),
|
||||
private val trackManager: TrackManager = Injekt.get(),
|
||||
|
@ -112,9 +113,6 @@ class MangaPresenter(
|
|||
private val successState: MangaScreenState.Success?
|
||||
get() = state.value as? MangaScreenState.Success
|
||||
|
||||
private var fetchMangaJob: Job? = null
|
||||
private var fetchChaptersJob: Job? = null
|
||||
|
||||
private var observeDownloadsStatusJob: Job? = null
|
||||
private var observeDownloadsPageJob: Job? = null
|
||||
|
||||
|
@ -161,57 +159,30 @@ class MangaPresenter(
|
|||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
|
||||
presenterScope.launchIO {
|
||||
val manga = getMangaAndChapters.awaitManga(mangaId)
|
||||
|
||||
if (!manga.favorite) {
|
||||
setMangaDefaultChapterFlags.await(manga)
|
||||
}
|
||||
|
||||
// Show what we have earlier.
|
||||
// Defaults set by the block above won't apply until next update but it doesn't matter
|
||||
// since we don't have any chapter yet.
|
||||
_state.update {
|
||||
MangaScreenState.Success(
|
||||
manga = manga,
|
||||
source = Injekt.get<SourceManager>().getOrStub(manga.source),
|
||||
isFromSource = isFromSource,
|
||||
trackingAvailable = trackManager.hasLoggedServices(),
|
||||
chapters = emptyList(),
|
||||
isRefreshingChapter = true,
|
||||
isIncognitoMode = incognitoMode,
|
||||
isDownloadedOnlyMode = downloadedOnlyMode,
|
||||
dialog = null,
|
||||
)
|
||||
}
|
||||
val toChapterItemsParams: List<DomainChapter>.(manga: DomainManga) -> List<ChapterItem> = { manga ->
|
||||
val uiPreferences = Injekt.get<UiPreferences>()
|
||||
toChapterItems(
|
||||
context = view?.activity ?: Injekt.get<Application>(),
|
||||
manga = manga,
|
||||
dateRelativeTime = uiPreferences.relativeTime().get(),
|
||||
dateFormat = UiPreferences.dateFormat(uiPreferences.dateFormat().get()),
|
||||
)
|
||||
}
|
||||
|
||||
// For UI changes
|
||||
presenterScope.launch {
|
||||
getMangaAndChapters.subscribe(mangaId)
|
||||
.distinctUntilChanged()
|
||||
.collectLatest { (manga, chapters) ->
|
||||
val chapterItems = chapters.toChapterItems(
|
||||
context = view?.activity ?: Injekt.get<Application>(),
|
||||
manga = manga,
|
||||
dateRelativeTime = uiPreferences.relativeTime().get(),
|
||||
dateFormat = UiPreferences.dateFormat(uiPreferences.dateFormat().get()),
|
||||
)
|
||||
val chapterItems = chapters.toChapterItemsParams(manga)
|
||||
updateSuccessState {
|
||||
it.copy(
|
||||
manga = manga,
|
||||
chapters = chapterItems,
|
||||
isRefreshingChapter = false,
|
||||
isRefreshingInfo = false,
|
||||
)
|
||||
}
|
||||
|
||||
observeTrackers()
|
||||
observeTrackingCount()
|
||||
observeDownloads()
|
||||
|
||||
if (!manga.initialized) {
|
||||
fetchAllFromSource(manualFetch = false)
|
||||
} else if (chapterItems.isEmpty()) {
|
||||
fetchChaptersFromSource()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,11 +193,63 @@ class MangaPresenter(
|
|||
basePreferences.downloadedOnly()
|
||||
.asHotFlow { downloadedOnlyMode = it }
|
||||
.launchIn(presenterScope)
|
||||
|
||||
// This block runs once on create
|
||||
presenterScope.launchIO {
|
||||
val manga = getMangaAndChapters.awaitManga(mangaId)
|
||||
val chapters = getMangaAndChapters.awaitChapters(mangaId)
|
||||
.toChapterItemsParams(manga)
|
||||
|
||||
if (!manga.favorite) {
|
||||
setMangaDefaultChapterFlags.await(manga)
|
||||
}
|
||||
|
||||
val needRefreshInfo = !manga.initialized
|
||||
val needRefreshChapter = chapters.isEmpty()
|
||||
|
||||
// Show what we have earlier.
|
||||
_state.update {
|
||||
MangaScreenState.Success(
|
||||
manga = manga,
|
||||
source = Injekt.get<SourceManager>().getOrStub(manga.source),
|
||||
isFromSource = isFromSource,
|
||||
trackingAvailable = trackManager.hasLoggedServices(),
|
||||
chapters = chapters,
|
||||
isRefreshingData = needRefreshInfo || needRefreshChapter,
|
||||
isIncognitoMode = incognitoMode,
|
||||
isDownloadedOnlyMode = downloadedOnlyMode,
|
||||
dialog = null,
|
||||
)
|
||||
}
|
||||
|
||||
// Start observe tracking since it only needs mangaId
|
||||
observeTrackers()
|
||||
observeTrackingCount()
|
||||
|
||||
// Fetch info-chapters when needed
|
||||
if (presenterScope.isActive) {
|
||||
val fetchFromSourceTasks = listOf(
|
||||
async { if (needRefreshInfo) fetchMangaFromSource() },
|
||||
async { if (needRefreshChapter) fetchChaptersFromSource() },
|
||||
)
|
||||
fetchFromSourceTasks.awaitAll()
|
||||
}
|
||||
|
||||
// Initial loading finished
|
||||
updateSuccessState { it.copy(isRefreshingData = false) }
|
||||
}
|
||||
}
|
||||
|
||||
fun fetchAllFromSource(manualFetch: Boolean = true) {
|
||||
fetchMangaFromSource(manualFetch)
|
||||
fetchChaptersFromSource(manualFetch)
|
||||
presenterScope.launch {
|
||||
updateSuccessState { it.copy(isRefreshingData = true) }
|
||||
val fetchFromSourceTasks = listOf(
|
||||
async { fetchMangaFromSource(manualFetch) },
|
||||
async { fetchChaptersFromSource(manualFetch) },
|
||||
)
|
||||
fetchFromSourceTasks.awaitAll()
|
||||
updateSuccessState { it.copy(isRefreshingData = false) }
|
||||
}
|
||||
}
|
||||
|
||||
// Manga info - start
|
||||
|
@ -234,10 +257,8 @@ class MangaPresenter(
|
|||
/**
|
||||
* Fetch manga information from source.
|
||||
*/
|
||||
private fun fetchMangaFromSource(manualFetch: Boolean = false) {
|
||||
if (fetchMangaJob?.isActive == true) return
|
||||
fetchMangaJob = presenterScope.launchIO {
|
||||
updateSuccessState { it.copy(isRefreshingInfo = true) }
|
||||
private suspend fun fetchMangaFromSource(manualFetch: Boolean = false) {
|
||||
withIOContext {
|
||||
try {
|
||||
successState?.let {
|
||||
val networkManga = it.source.getMangaDetails(it.manga.toSManga())
|
||||
|
@ -246,7 +267,6 @@ class MangaPresenter(
|
|||
} catch (e: Throwable) {
|
||||
withUIContext { view?.onFetchMangaInfoError(e) }
|
||||
}
|
||||
updateSuccessState { it.copy(isRefreshingInfo = false) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -534,10 +554,8 @@ class MangaPresenter(
|
|||
/**
|
||||
* Requests an updated list of chapters from the source.
|
||||
*/
|
||||
private fun fetchChaptersFromSource(manualFetch: Boolean = false) {
|
||||
if (fetchChaptersJob?.isActive == true) return
|
||||
fetchChaptersJob = presenterScope.launchIO {
|
||||
updateSuccessState { it.copy(isRefreshingChapter = true) }
|
||||
private suspend fun fetchChaptersFromSource(manualFetch: Boolean = false) {
|
||||
withIOContext {
|
||||
try {
|
||||
successState?.let { successState ->
|
||||
val chapters = successState.source.getChapterList(successState.manga.toSManga())
|
||||
|
@ -555,7 +573,6 @@ class MangaPresenter(
|
|||
} catch (e: Throwable) {
|
||||
withUIContext { view?.onFetchChaptersError(e) }
|
||||
}
|
||||
updateSuccessState { it.copy(isRefreshingChapter = false) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1082,8 +1099,7 @@ sealed class MangaScreenState {
|
|||
val chapters: List<ChapterItem>,
|
||||
val trackingAvailable: Boolean = false,
|
||||
val trackingCount: Int = 0,
|
||||
val isRefreshingInfo: Boolean = false,
|
||||
val isRefreshingChapter: Boolean = false,
|
||||
val isRefreshingData: Boolean = false,
|
||||
val isIncognitoMode: Boolean = false,
|
||||
val isDownloadedOnlyMode: Boolean = false,
|
||||
val dialog: MangaPresenter.Dialog? = null,
|
||||
|
|
Loading…
Reference in a new issue