Ivan Iskandar 2 жил өмнө
parent
commit
98a4f6cccb

+ 4 - 0
app/src/main/java/eu/kanade/domain/manga/interactor/GetMangaWithChapters.kt

@@ -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)
+    }
 }

+ 2 - 2
app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt

@@ -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(

+ 72 - 56
app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt

@@ -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,72 +159,97 @@ class MangaPresenter(
     override fun onCreate(savedState: Bundle?) {
         super.onCreate(savedState)
 
+        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.toChapterItemsParams(manga)
+                    updateSuccessState {
+                        it.copy(
+                            manga = manga,
+                            chapters = chapterItems,
+                        )
+                    }
+
+                    observeDownloads()
+                }
+        }
+
+        basePreferences.incognitoMode()
+            .asHotFlow { incognitoMode = it }
+            .launchIn(presenterScope)
+
+        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.
-            // 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,
+                    chapters = chapters,
+                    isRefreshingData = needRefreshInfo || needRefreshChapter,
                     isIncognitoMode = incognitoMode,
                     isDownloadedOnlyMode = downloadedOnlyMode,
                     dialog = null,
                 )
             }
 
-            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()),
-                    )
-                    updateSuccessState {
-                        it.copy(
-                            manga = manga,
-                            chapters = chapterItems,
-                            isRefreshingChapter = false,
-                            isRefreshingInfo = false,
-                        )
-                    }
+            // Start observe tracking since it only needs mangaId
+            observeTrackers()
+            observeTrackingCount()
 
-                    observeTrackers()
-                    observeTrackingCount()
-                    observeDownloads()
+            // Fetch info-chapters when needed
+            if (presenterScope.isActive) {
+                val fetchFromSourceTasks = listOf(
+                    async { if (needRefreshInfo) fetchMangaFromSource() },
+                    async { if (needRefreshChapter) fetchChaptersFromSource() },
+                )
+                fetchFromSourceTasks.awaitAll()
+            }
 
-                    if (!manga.initialized) {
-                        fetchAllFromSource(manualFetch = false)
-                    } else if (chapterItems.isEmpty()) {
-                        fetchChaptersFromSource()
-                    }
-                }
+            // Initial loading finished
+            updateSuccessState { it.copy(isRefreshingData = false) }
         }
-
-        basePreferences.incognitoMode()
-            .asHotFlow { incognitoMode = it }
-            .launchIn(presenterScope)
-
-        basePreferences.downloadedOnly()
-            .asHotFlow { downloadedOnlyMode = it }
-            .launchIn(presenterScope)
     }
 
     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,