Explorar o código

Clean up UpdatesController

- Move loading state into scaffold (closes #7704)
- Move logic into presenter
- Make some composables private
arkon %!s(int64=2) %!d(string=hai) anos
pai
achega
0e3176a77c

+ 1 - 1
app/src/main/java/eu/kanade/presentation/browse/ExtensionDetailsScreen.kt

@@ -406,7 +406,7 @@ private fun SourceSwitchPreference(
 }
 
 @Composable
-fun NsfwWarningDialog(
+private fun NsfwWarningDialog(
     onClickConfirm: () -> Unit,
 ) {
     AlertDialog(

+ 2 - 2
app/src/main/java/eu/kanade/presentation/browse/ExtensionFilterScreen.kt

@@ -61,7 +61,7 @@ fun ExtensionFilterScreen(
 }
 
 @Composable
-fun SourceFilterContent(
+private fun SourceFilterContent(
     contentPadding: PaddingValues,
     state: ExtensionFilterState,
     onClickLang: (String) -> Unit,
@@ -83,7 +83,7 @@ fun SourceFilterContent(
 }
 
 @Composable
-fun ExtensionFilterItem(
+private fun ExtensionFilterItem(
     modifier: Modifier,
     lang: String,
     enabled: Boolean,

+ 7 - 7
app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt

@@ -91,7 +91,7 @@ fun ExtensionScreen(
 }
 
 @Composable
-fun ExtensionContent(
+private fun ExtensionContent(
     state: ExtensionsState,
     onLongClickItem: (Extension) -> Unit,
     onClickItemCancel: (Extension) -> Unit,
@@ -201,7 +201,7 @@ fun ExtensionContent(
 }
 
 @Composable
-fun ExtensionItem(
+private fun ExtensionItem(
     modifier: Modifier = Modifier,
     item: ExtensionUiModel.Item,
     onClickItem: (Extension) -> Unit,
@@ -238,7 +238,7 @@ fun ExtensionItem(
 }
 
 @Composable
-fun ExtensionItemContent(
+private fun ExtensionItemContent(
     extension: Extension,
     modifier: Modifier = Modifier,
 ) {
@@ -294,7 +294,7 @@ fun ExtensionItemContent(
 }
 
 @Composable
-fun ExtensionItemActions(
+private fun ExtensionItemActions(
     extension: Extension,
     installStep: InstallStep,
     modifier: Modifier = Modifier,
@@ -348,7 +348,7 @@ fun ExtensionItemActions(
 }
 
 @Composable
-fun ExtensionHeader(
+private fun ExtensionHeader(
     @StringRes textRes: Int,
     modifier: Modifier = Modifier,
     action: @Composable RowScope.() -> Unit = {},
@@ -361,7 +361,7 @@ fun ExtensionHeader(
 }
 
 @Composable
-fun ExtensionHeader(
+private fun ExtensionHeader(
     text: String,
     modifier: Modifier = Modifier,
     action: @Composable RowScope.() -> Unit = {},
@@ -382,7 +382,7 @@ fun ExtensionHeader(
 }
 
 @Composable
-fun ExtensionTrustDialog(
+private fun ExtensionTrustDialog(
     onClickConfirm: () -> Unit,
     onClickDismiss: () -> Unit,
     onDismissRequest: () -> Unit,

+ 2 - 2
app/src/main/java/eu/kanade/presentation/browse/MigrateMangaScreen.kt

@@ -62,7 +62,7 @@ fun MigrateMangaScreen(
 }
 
 @Composable
-fun MigrateMangaContent(
+private fun MigrateMangaContent(
     contentPadding: PaddingValues,
     state: MigrateMangaState,
     onClickItem: (Manga) -> Unit,
@@ -82,7 +82,7 @@ fun MigrateMangaContent(
 }
 
 @Composable
-fun MigrateMangaItem(
+private fun MigrateMangaItem(
     modifier: Modifier = Modifier,
     manga: Manga,
     onClickItem: (Manga) -> Unit,

+ 2 - 2
app/src/main/java/eu/kanade/presentation/browse/MigrateSourceScreen.kt

@@ -70,7 +70,7 @@ fun MigrateSourceScreen(
 }
 
 @Composable
-fun MigrateSourceList(
+private fun MigrateSourceList(
     list: List<Pair<Source, Long>>,
     onClickItem: (Source) -> Unit,
     onLongClickItem: (Source) -> Unit,
@@ -126,7 +126,7 @@ fun MigrateSourceList(
 }
 
 @Composable
-fun MigrateSourceItem(
+private fun MigrateSourceItem(
     modifier: Modifier = Modifier,
     source: Source,
     count: Long,

+ 3 - 3
app/src/main/java/eu/kanade/presentation/browse/SourcesFilterScreen.kt

@@ -66,7 +66,7 @@ fun SourcesFilterScreen(
 }
 
 @Composable
-fun SourcesFilterContent(
+private fun SourcesFilterContent(
     contentPadding: PaddingValues,
     state: SourcesFilterState,
     onClickLang: (String) -> Unit,
@@ -111,7 +111,7 @@ fun SourcesFilterContent(
 }
 
 @Composable
-fun SourcesFilterHeader(
+private fun SourcesFilterHeader(
     modifier: Modifier,
     language: String,
     enabled: Boolean,
@@ -128,7 +128,7 @@ fun SourcesFilterHeader(
 }
 
 @Composable
-fun SourcesFilterItem(
+private fun SourcesFilterItem(
     modifier: Modifier,
     source: Source,
     enabled: Boolean,

+ 5 - 5
app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt

@@ -75,7 +75,7 @@ fun SourcesScreen(
 }
 
 @Composable
-fun SourceList(
+private fun SourceList(
     state: SourcesState,
     onClickItem: (Source, String) -> Unit,
     onClickDisable: (Source) -> Unit,
@@ -135,7 +135,7 @@ fun SourceList(
 }
 
 @Composable
-fun SourceHeader(
+private fun SourceHeader(
     modifier: Modifier = Modifier,
     language: String,
 ) {
@@ -149,7 +149,7 @@ fun SourceHeader(
 }
 
 @Composable
-fun SourceItem(
+private fun SourceItem(
     modifier: Modifier = Modifier,
     source: Source,
     onClickItem: (Source, String) -> Unit,
@@ -181,7 +181,7 @@ fun SourceItem(
 }
 
 @Composable
-fun SourcePinButton(
+private fun SourcePinButton(
     isPinned: Boolean,
     onClick: () -> Unit,
 ) {
@@ -197,7 +197,7 @@ fun SourcePinButton(
 }
 
 @Composable
-fun SourceOptionsDialog(
+private fun SourceOptionsDialog(
     source: Source,
     onClickPin: () -> Unit,
     onClickDisable: () -> Unit,

+ 86 - 65
app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt

@@ -30,6 +30,7 @@ import eu.kanade.presentation.components.AppBar
 import eu.kanade.presentation.components.ChapterDownloadAction
 import eu.kanade.presentation.components.EmptyScreen
 import eu.kanade.presentation.components.LazyColumn
+import eu.kanade.presentation.components.LoadingScreen
 import eu.kanade.presentation.components.MangaBottomActionMenu
 import eu.kanade.presentation.components.Scaffold
 import eu.kanade.presentation.components.SwipeRefreshIndicator
@@ -55,10 +56,7 @@ fun UpdateScreen(
     presenter: UpdatesPresenter,
     onClickCover: (UpdatesItem) -> Unit,
     onBackClicked: () -> Unit,
-    onDownloadChapter: (List<UpdatesItem>, ChapterDownloadAction) -> Unit,
 ) {
-    val updatesListState = rememberLazyListState()
-
     val internalOnBackPressed = {
         if (presenter.selectionMode) {
             presenter.toggleAllSelection(false)
@@ -69,7 +67,6 @@ fun UpdateScreen(
     BackHandler(onBack = internalOnBackPressed)
 
     val context = LocalContext.current
-
     val onUpdateLibrary = {
         val started = LibraryUpdateService.start(context)
         context.toast(if (started) R.string.updating_library else R.string.update_already_running)
@@ -92,7 +89,7 @@ fun UpdateScreen(
         bottomBar = {
             UpdatesBottomBar(
                 selected = presenter.selected,
-                onDownloadChapter = onDownloadChapter,
+                onDownloadChapter = presenter::downloadChapters,
                 onMultiBookmarkClicked = presenter::bookmarkUpdates,
                 onMultiMarkAsReadClicked = presenter::markUpdatesRead,
                 onMultiDeleteClicked = {
@@ -102,69 +99,93 @@ fun UpdateScreen(
             )
         },
     ) { contentPadding ->
-        // During selection mode bottom nav is not visible
-        val contentPaddingWithNavBar = contentPadding +
-            if (presenter.selectionMode) {
-                PaddingValues()
-            } else {
-                bottomNavPaddingValues
+        when {
+            presenter.isLoading -> LoadingScreen()
+            presenter.uiModels.isEmpty() -> EmptyScreen(textResource = R.string.information_no_recent)
+            else -> {
+                UpdateScreenContent(
+                    presenter = presenter,
+                    contentPadding = contentPadding,
+                    onUpdateLibrary = onUpdateLibrary,
+                    onClickCover = onClickCover,
+                )
             }
+        }
+    }
+}
+
+@Composable
+private fun UpdateScreenContent(
+    presenter: UpdatesPresenter,
+    contentPadding: PaddingValues,
+    onUpdateLibrary: () -> Boolean,
+    onClickCover: (UpdatesItem) -> Unit,
+) {
+    val context = LocalContext.current
+    val updatesListState = rememberLazyListState()
 
-        val scope = rememberCoroutineScope()
-        var isRefreshing by remember { mutableStateOf(false) }
+    // During selection mode bottom nav is not visible
+    val contentPaddingWithNavBar = contentPadding +
+        if (presenter.selectionMode) {
+            PaddingValues()
+        } else {
+            bottomNavPaddingValues
+        }
 
-        SwipeRefresh(
-            state = rememberSwipeRefreshState(isRefreshing = isRefreshing),
-            onRefresh = {
-                val started = onUpdateLibrary()
-                if (!started) return@SwipeRefresh
-                scope.launch {
-                    // Fake refresh status but hide it after a second as it's a long running task
-                    isRefreshing = true
-                    delay(1000)
-                    isRefreshing = false
-                }
-            },
-            swipeEnabled = presenter.selectionMode.not(),
-            indicatorPadding = contentPaddingWithNavBar,
-            indicator = { s, trigger ->
-                SwipeRefreshIndicator(
-                    state = s,
-                    refreshTriggerDistance = trigger,
-                )
-            },
-        ) {
-            if (presenter.uiModels.isEmpty()) {
-                EmptyScreen(textResource = R.string.information_no_recent)
-            } else {
-                VerticalFastScroller(
-                    listState = updatesListState,
-                    topContentPadding = contentPaddingWithNavBar.calculateTopPadding(),
-                    endContentPadding = contentPaddingWithNavBar.calculateEndPadding(LocalLayoutDirection.current),
-                ) {
-                    LazyColumn(
-                        modifier = Modifier.fillMaxHeight(),
-                        state = updatesListState,
-                        contentPadding = contentPaddingWithNavBar,
-                    ) {
-                        if (presenter.lastUpdated > 0L) {
-                            updatesLastUpdatedItem(presenter.lastUpdated)
-                        }
+    val scope = rememberCoroutineScope()
+    var isRefreshing by remember { mutableStateOf(false) }
 
-                        updatesUiItems(
-                            uiModels = presenter.uiModels,
-                            selectionMode = presenter.selectionMode,
-                            onUpdateSelected = presenter::toggleSelection,
-                            onClickCover = onClickCover,
-                            onClickUpdate = {
-                                val intent = ReaderActivity.newIntent(context, it.update.mangaId, it.update.chapterId)
-                                context.startActivity(intent)
-                            },
-                            onDownloadChapter = onDownloadChapter,
-                            relativeTime = presenter.relativeTime,
-                            dateFormat = presenter.dateFormat,
-                        )
+    SwipeRefresh(
+        state = rememberSwipeRefreshState(isRefreshing = isRefreshing),
+        onRefresh = {
+            val started = onUpdateLibrary()
+            if (!started) return@SwipeRefresh
+            scope.launch {
+                // Fake refresh status but hide it after a second as it's a long running task
+                isRefreshing = true
+                delay(1000)
+                isRefreshing = false
+            }
+        },
+        swipeEnabled = presenter.selectionMode.not(),
+        indicatorPadding = contentPaddingWithNavBar,
+        indicator = { s, trigger ->
+            SwipeRefreshIndicator(
+                state = s,
+                refreshTriggerDistance = trigger,
+            )
+        },
+    ) {
+        if (presenter.uiModels.isEmpty()) {
+            EmptyScreen(textResource = R.string.information_no_recent)
+        } else {
+            VerticalFastScroller(
+                listState = updatesListState,
+                topContentPadding = contentPaddingWithNavBar.calculateTopPadding(),
+                endContentPadding = contentPaddingWithNavBar.calculateEndPadding(LocalLayoutDirection.current),
+            ) {
+                LazyColumn(
+                    modifier = Modifier.fillMaxHeight(),
+                    state = updatesListState,
+                    contentPadding = contentPaddingWithNavBar,
+                ) {
+                    if (presenter.lastUpdated > 0L) {
+                        updatesLastUpdatedItem(presenter.lastUpdated)
                     }
+
+                    updatesUiItems(
+                        uiModels = presenter.uiModels,
+                        selectionMode = presenter.selectionMode,
+                        onUpdateSelected = presenter::toggleSelection,
+                        onClickCover = onClickCover,
+                        onClickUpdate = {
+                            val intent = ReaderActivity.newIntent(context, it.update.mangaId, it.update.chapterId)
+                            context.startActivity(intent)
+                        },
+                        onDownloadChapter = presenter::downloadChapters,
+                        relativeTime = presenter.relativeTime,
+                        dateFormat = presenter.dateFormat,
+                    )
                 }
             }
         }
@@ -193,7 +214,7 @@ fun UpdateScreen(
 }
 
 @Composable
-fun UpdatesAppBar(
+private fun UpdatesAppBar(
     modifier: Modifier = Modifier,
     incognitoMode: Boolean,
     downloadedOnlyMode: Boolean,
@@ -239,7 +260,7 @@ fun UpdatesAppBar(
 }
 
 @Composable
-fun UpdatesBottomBar(
+private fun UpdatesBottomBar(
     selected: List<UpdatesUiModel.Item>,
     onDownloadChapter: (List<UpdatesItem>, ChapterDownloadAction) -> Unit,
     onMultiBookmarkClicked: (List<UpdatesItem>, bookmark: Boolean) -> Unit,

+ 2 - 2
app/src/main/java/eu/kanade/presentation/webview/WebViewScreen.kt

@@ -30,7 +30,7 @@ import eu.kanade.tachiyomi.util.system.setDefaultSettings
 
 @Composable
 fun WebViewScreen(
-    onUp: () -> Unit,
+    onNavigateUp: () -> Unit,
     initialTitle: String?,
     url: String,
     headers: Map<String, String> = emptyMap(),
@@ -47,7 +47,7 @@ fun WebViewScreen(
                 AppBar(
                     title = state.pageTitle ?: initialTitle,
                     subtitle = state.content.getCurrentUrl(),
-                    navigateUp = onUp,
+                    navigateUp = onNavigateUp,
                     navigationIcon = Icons.Default.Close,
                     actions = {
                         AppBarActions(

+ 2 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt

@@ -95,14 +95,13 @@ class LibraryController(
         }
 
         LaunchedEffect(presenter.selectionMode) {
-            val activity = (activity as? MainActivity) ?: return@LaunchedEffect
             // Could perhaps be removed when navigation is in a Compose world
             if (router.backstackSize == 1) {
-                activity.showBottomNav(presenter.selectionMode.not())
+                (activity as? MainActivity)?.showBottomNav(presenter.selectionMode.not())
             }
         }
         LaunchedEffect(presenter.isLoading) {
-            if (presenter.isLoading.not()) {
+            if (!presenter.isLoading) {
                 (activity as? MainActivity)?.ready = true
             }
         }

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt

@@ -195,7 +195,7 @@ class MangaController : FullComposeController<MangaPresenter> {
         }
     }
 
-    // Let compose view handle this
+    // Let Compose view handle this
     override fun handleBack(): Boolean {
         val dispatcher = (activity as? OnBackPressedDispatcherOwner)?.onBackPressedDispatcher ?: return false
         return if (dispatcher.hasEnabledCallbacks()) {

+ 12 - 57
app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesController.kt

@@ -1,24 +1,15 @@
 package eu.kanade.tachiyomi.ui.recent.updates
 
 import androidx.activity.OnBackPressedDispatcherOwner
-import androidx.compose.animation.Crossfade
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
-import eu.kanade.presentation.components.ChapterDownloadAction
-import eu.kanade.presentation.components.LoadingScreen
 import eu.kanade.presentation.updates.UpdateScreen
-import eu.kanade.tachiyomi.data.download.DownloadService
-import eu.kanade.tachiyomi.data.download.model.Download
 import eu.kanade.tachiyomi.ui.base.controller.FullComposeController
 import eu.kanade.tachiyomi.ui.base.controller.RootController
 import eu.kanade.tachiyomi.ui.base.controller.pushController
 import eu.kanade.tachiyomi.ui.main.MainActivity
 import eu.kanade.tachiyomi.ui.manga.MangaController
-import kotlinx.coroutines.launch
 
-/**
- * Fragment that shows recent chapters.
- */
 class UpdatesController :
     FullComposeController<UpdatesPresenter>(),
     RootController {
@@ -27,32 +18,26 @@ class UpdatesController :
 
     @Composable
     override fun ComposeContent() {
-        Crossfade(targetState = presenter.isLoading) { isLoading ->
-            if (isLoading) {
-                LoadingScreen()
-            } else {
-                UpdateScreen(
-                    presenter = presenter,
-                    onClickCover = { item ->
-                        router.pushController(MangaController(item.update.mangaId))
-                    },
-                    onBackClicked = this::onBackClicked,
-                    onDownloadChapter = this::downloadChapters,
-                )
-            }
-        }
+        UpdateScreen(
+            presenter = presenter,
+            onClickCover = { item ->
+                router.pushController(MangaController(item.update.mangaId))
+            },
+            onBackClicked = {
+                (activity as? MainActivity)?.moveToStartScreen()
+            },
+        )
         LaunchedEffect(presenter.selectionMode) {
-            val activity = (activity as? MainActivity) ?: return@LaunchedEffect
-            activity.showBottomNav(presenter.selectionMode.not())
+            (activity as? MainActivity)?.showBottomNav(presenter.selectionMode.not())
         }
         LaunchedEffect(presenter.isLoading) {
-            if (presenter.isLoading.not()) {
+            if (!presenter.isLoading) {
                 (activity as? MainActivity)?.ready = true
             }
         }
     }
 
-    // Let compose view handle this
+    // Let Compose view handle this
     override fun handleBack(): Boolean {
         val dispatcher = (activity as? OnBackPressedDispatcherOwner)?.onBackPressedDispatcher ?: return false
         return if (dispatcher.hasEnabledCallbacks()) {
@@ -62,34 +47,4 @@ class UpdatesController :
             false
         }
     }
-
-    private fun onBackClicked() {
-        (activity as? MainActivity)?.moveToStartScreen()
-    }
-
-    private fun downloadChapters(items: List<UpdatesItem>, action: ChapterDownloadAction) {
-        if (items.isEmpty()) return
-        viewScope.launch {
-            when (action) {
-                ChapterDownloadAction.START -> {
-                    presenter.downloadChapters(items)
-                    if (items.any { it.downloadStateProvider() == Download.State.ERROR }) {
-                        DownloadService.start(activity!!)
-                    }
-                }
-                ChapterDownloadAction.START_NOW -> {
-                    val chapterId = items.singleOrNull()?.update?.chapterId ?: return@launch
-                    presenter.startDownloadingNow(chapterId)
-                }
-                ChapterDownloadAction.CANCEL -> {
-                    val chapterId = items.singleOrNull()?.update?.chapterId ?: return@launch
-                    presenter.cancelDownload(chapterId)
-                }
-                ChapterDownloadAction.DELETE -> {
-                    presenter.deleteChapters(items)
-                }
-            }
-            presenter.toggleAllSelection(false)
-        }
-    }
 }

+ 31 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt

@@ -13,10 +13,12 @@ import eu.kanade.domain.chapter.model.toDbChapter
 import eu.kanade.domain.manga.interactor.GetManga
 import eu.kanade.domain.updates.interactor.GetUpdates
 import eu.kanade.domain.updates.model.UpdatesWithRelations
+import eu.kanade.presentation.components.ChapterDownloadAction
 import eu.kanade.presentation.updates.UpdatesState
 import eu.kanade.presentation.updates.UpdatesStateImpl
 import eu.kanade.presentation.updates.UpdatesUiModel
 import eu.kanade.tachiyomi.data.download.DownloadManager
+import eu.kanade.tachiyomi.data.download.DownloadService
 import eu.kanade.tachiyomi.data.download.model.Download
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.source.SourceManager
@@ -33,6 +35,7 @@ import kotlinx.coroutines.flow.catch
 import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.receiveAsFlow
+import kotlinx.coroutines.launch
 import logcat.LogPriority
 import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.api.get
@@ -178,11 +181,37 @@ class UpdatesPresenter(
         }
     }
 
-    fun startDownloadingNow(chapterId: Long) {
+    fun downloadChapters(items: List<UpdatesItem>, action: ChapterDownloadAction) {
+        if (items.isEmpty()) return
+        presenterScope.launch {
+            when (action) {
+                ChapterDownloadAction.START -> {
+                    downloadChapters(items)
+                    if (items.any { it.downloadStateProvider() == Download.State.ERROR }) {
+                        DownloadService.start(view!!.activity!!)
+                    }
+                }
+                ChapterDownloadAction.START_NOW -> {
+                    val chapterId = items.singleOrNull()?.update?.chapterId ?: return@launch
+                    startDownloadingNow(chapterId)
+                }
+                ChapterDownloadAction.CANCEL -> {
+                    val chapterId = items.singleOrNull()?.update?.chapterId ?: return@launch
+                    cancelDownload(chapterId)
+                }
+                ChapterDownloadAction.DELETE -> {
+                    deleteChapters(items)
+                }
+            }
+            toggleAllSelection(false)
+        }
+    }
+
+    private fun startDownloadingNow(chapterId: Long) {
         downloadManager.startDownloadNow(chapterId)
     }
 
-    fun cancelDownload(chapterId: Long) {
+    private fun cancelDownload(chapterId: Long) {
         val activeDownload = downloadManager.queue.find { chapterId == it.chapter.id } ?: return
         downloadManager.deletePendingDownload(activeDownload)
         updateDownloadState(activeDownload.apply { status = Download.State.NOT_DOWNLOADED })

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/webview/WebViewActivity.kt

@@ -45,7 +45,7 @@ class WebViewActivity : BaseActivity() {
 
         setComposeContent {
             WebViewScreen(
-                onUp = { finish() },
+                onNavigateUp = { finish() },
                 initialTitle = intent.extras?.getString(TITLE_KEY),
                 url = url,
                 headers = headers,