Browse Source

Minor tweaks to download custom dialog

- Allow large decrements (just goes to 0)
- Use Material3 text field for proper theming
- Move dialog composable to presentation package
arkon 2 years ago
parent
commit
03b9950fa1
19 changed files with 190 additions and 181 deletions
  1. 1 1
      app/src/main/java/eu/kanade/presentation/category/CategoryExtensions.kt
  2. 1 1
      app/src/main/java/eu/kanade/presentation/components/AppBar.kt
  3. 7 7
      app/src/main/java/eu/kanade/presentation/components/ChangeCategoryDialog.kt
  4. 4 4
      app/src/main/java/eu/kanade/presentation/components/DeleteLibraryMangaDialog.kt
  5. 2 2
      app/src/main/java/eu/kanade/presentation/history/components/HistoryToolbar.kt
  6. 1 1
      app/src/main/java/eu/kanade/presentation/library/components/LibraryToolbar.kt
  7. 12 7
      app/src/main/java/eu/kanade/presentation/manga/components/DownloadCustomChaptersDialog.kt
  8. 57 0
      app/src/main/java/eu/kanade/presentation/manga/components/DuplicateMangaDialog.kt
  9. 4 4
      app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt
  10. 1 1
      app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseContent.kt
  11. 3 3
      app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseDialogs.kt
  12. 1 1
      app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseFloatingActionButton.kt
  13. 1 1
      app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseItem.kt
  14. 3 3
      app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseToolbar.kt
  15. 2 2
      app/src/main/java/eu/kanade/tachiyomi/glance/UpdatesGridGlanceWidget.kt
  16. 1 1
      app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt
  17. 0 54
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/AddDuplicateMangaDialog.kt
  18. 89 87
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
  19. 0 1
      build.gradle.kts

+ 1 - 1
app/src/main/java/eu/kanade/presentation/category/CategoryExtensions.kt

@@ -9,7 +9,7 @@ import eu.kanade.tachiyomi.R
 val Category.visualName: String
     @Composable
     get() = when {
-        isSystemCategory -> stringResource(id = R.string.label_default)
+        isSystemCategory -> stringResource(R.string.label_default)
         else -> name
     }
 

+ 1 - 1
app/src/main/java/eu/kanade/presentation/components/AppBar.kt

@@ -110,7 +110,7 @@ fun AppBar(
                     IconButton(onClick = onCancelActionMode) {
                         Icon(
                             imageVector = Icons.Default.Close,
-                            contentDescription = stringResource(id = R.string.action_cancel),
+                            contentDescription = stringResource(R.string.action_cancel),
                         )
                     }
                 } else {

+ 7 - 7
app/src/main/java/eu/kanade/presentation/components/ChangeCategoryDialog.kt

@@ -39,14 +39,14 @@ fun ChangeCategoryDialog(
                         onEditCategories()
                     },
                 ) {
-                    Text(text = stringResource(id = R.string.action_edit_categories))
+                    Text(text = stringResource(R.string.action_edit_categories))
                 }
             },
             title = {
-                Text(text = stringResource(id = R.string.action_move_category))
+                Text(text = stringResource(R.string.action_move_category))
             },
             text = {
-                Text(text = stringResource(id = R.string.information_empty_category_dialog))
+                Text(text = stringResource(R.string.information_empty_category_dialog))
             },
         )
         return
@@ -60,11 +60,11 @@ fun ChangeCategoryDialog(
                     onDismissRequest()
                     onEditCategories()
                 },) {
-                    Text(text = stringResource(id = R.string.action_edit))
+                    Text(text = stringResource(R.string.action_edit))
                 }
                 Spacer(modifier = Modifier.weight(1f))
                 TextButton(onClick = onDismissRequest) {
-                    Text(text = stringResource(id = android.R.string.cancel))
+                    Text(text = stringResource(android.R.string.cancel))
                 }
                 TextButton(
                     onClick = {
@@ -75,12 +75,12 @@ fun ChangeCategoryDialog(
                         )
                     },
                 ) {
-                    Text(text = stringResource(id = R.string.action_add))
+                    Text(text = stringResource(R.string.action_add))
                 }
             }
         },
         title = {
-            Text(text = stringResource(id = R.string.action_move_category))
+            Text(text = stringResource(R.string.action_move_category))
         },
         text = {
             Column {

+ 4 - 4
app/src/main/java/eu/kanade/presentation/components/DeleteLibraryMangaDialog.kt

@@ -36,7 +36,7 @@ fun DeleteLibraryMangaDialog(
         onDismissRequest = onDismissRequest,
         dismissButton = {
             TextButton(onClick = onDismissRequest) {
-                Text(text = stringResource(id = android.R.string.cancel))
+                Text(text = stringResource(android.R.string.cancel))
             }
         },
         confirmButton = {
@@ -49,11 +49,11 @@ fun DeleteLibraryMangaDialog(
                     )
                 },
             ) {
-                Text(text = stringResource(id = android.R.string.ok))
+                Text(text = stringResource(android.R.string.ok))
             }
         },
         title = {
-            Text(text = stringResource(id = R.string.action_remove))
+            Text(text = stringResource(R.string.action_remove))
         },
         text = {
             Column {
@@ -69,7 +69,7 @@ fun DeleteLibraryMangaDialog(
                                 list = mutableList.toList()
                             },
                         )
-                        Text(text = stringResource(id = state.value))
+                        Text(text = stringResource(state.value))
                     }
                 }
             }

+ 2 - 2
app/src/main/java/eu/kanade/presentation/history/components/HistoryToolbar.kt

@@ -62,7 +62,7 @@ fun HistoryRegularToolbar(
     scrollBehavior: TopAppBarScrollBehavior,
 ) {
     AppBar(
-        title = stringResource(id = R.string.history),
+        title = stringResource(R.string.history),
         actions = {
             IconButton(onClick = onClickSearch) {
                 Icon(Icons.Outlined.Search, contentDescription = stringResource(R.string.action_search))
@@ -105,7 +105,7 @@ fun HistorySearchToolbar(
         actions = {
             AnimatedVisibility(visible = searchQuery.isNotEmpty()) {
                 IconButton(onClick = onClickResetSearch) {
-                    Icon(Icons.Outlined.Close, contentDescription = stringResource(id = R.string.action_reset))
+                    Icon(Icons.Outlined.Close, contentDescription = stringResource(R.string.action_reset))
                 }
             }
         },

+ 1 - 1
app/src/main/java/eu/kanade/presentation/library/components/LibraryToolbar.kt

@@ -193,7 +193,7 @@ fun LibrarySearchToolbar(
         actions = {
             AnimatedVisibility(visible = searchQuery.isNotEmpty()) {
                 IconButton(onClick = onClickResetSearch) {
-                    Icon(Icons.Outlined.Close, contentDescription = stringResource(id = R.string.action_reset))
+                    Icon(Icons.Outlined.Close, contentDescription = stringResource(R.string.action_reset))
                 }
             }
         },

+ 12 - 7
app/src/main/java/eu/kanade/presentation/manga/components/DownloadCustomChaptersDialog.kt

@@ -1,7 +1,6 @@
-package eu.kanade.tachiyomi.ui.manga.chapter
+package eu.kanade.presentation.manga.components
 
 import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.text.BasicTextField
 import androidx.compose.foundation.text.KeyboardOptions
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.outlined.ChevronLeft
@@ -11,6 +10,8 @@ import androidx.compose.material.icons.outlined.KeyboardDoubleArrowRight
 import androidx.compose.material3.AlertDialog
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
+import androidx.compose.material3.LocalTextStyle
+import androidx.compose.material3.OutlinedTextField
 import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
@@ -19,8 +20,10 @@ import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.text.style.TextAlign
 import eu.kanade.tachiyomi.R
 
 @Composable
@@ -34,7 +37,7 @@ fun DownloadCustomAmountDialog(
         onDismissRequest = onDismissRequest,
         dismissButton = {
             TextButton(onClick = onDismissRequest) {
-                Text(text = stringResource(id = android.R.string.cancel))
+                Text(text = stringResource(android.R.string.cancel))
             }
         },
         confirmButton = {
@@ -44,11 +47,11 @@ fun DownloadCustomAmountDialog(
                     onConfirm(amount.coerceIn(0, maxAmount))
                 },
             ) {
-                Text(text = stringResource(id = android.R.string.ok))
+                Text(text = stringResource(R.string.action_download))
             }
         },
         title = {
-            Text(text = stringResource(id = R.string.custom_download))
+            Text(text = stringResource(R.string.custom_download))
         },
         text = {
             val onChangeAmount: (Int) -> Unit = { amount = (amount + it).coerceIn(0, maxAmount) }
@@ -57,7 +60,7 @@ fun DownloadCustomAmountDialog(
             ) {
                 IconButton(
                     onClick = { onChangeAmount(-10) },
-                    enabled = amount > 10,
+                    enabled = amount > 0,
                 ) {
                     Icon(imageVector = Icons.Outlined.KeyboardDoubleArrowLeft, contentDescription = "")
                 }
@@ -67,10 +70,12 @@ fun DownloadCustomAmountDialog(
                 ) {
                     Icon(imageVector = Icons.Outlined.ChevronLeft, contentDescription = "")
                 }
-                BasicTextField(
+                OutlinedTextField(
+                    modifier = Modifier.weight(1f),
                     value = amount.toString(),
                     onValueChange = { onChangeAmount(it.toIntOrNull() ?: 0) },
                     keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
+                    textStyle = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
                 )
                 IconButton(
                     onClick = { onChangeAmount(1) },

+ 57 - 0
app/src/main/java/eu/kanade/presentation/manga/components/DuplicateMangaDialog.kt

@@ -0,0 +1,57 @@
+package eu.kanade.presentation.manga.components
+
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.material3.AlertDialog
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import eu.kanade.tachiyomi.R
+import eu.kanade.tachiyomi.source.Source
+
+@Composable
+fun DuplicateMangaDialog(
+    onDismissRequest: () -> Unit,
+    onConfirm: () -> Unit,
+    onOpenManga: () -> Unit,
+    duplicateFrom: Source,
+) {
+    AlertDialog(
+        onDismissRequest = onDismissRequest,
+        confirmButton = {
+            Row {
+                TextButton(onClick = {
+                    onDismissRequest()
+                    onOpenManga()
+                },) {
+                    Text(text = stringResource(R.string.action_show_manga))
+                }
+                Spacer(modifier = Modifier.weight(1f))
+                TextButton(onClick = onDismissRequest) {
+                    Text(text = stringResource(android.R.string.cancel))
+                }
+                TextButton(
+                    onClick = {
+                        onDismissRequest()
+                        onConfirm()
+                    },
+                ) {
+                    Text(text = stringResource(R.string.action_add))
+                }
+            }
+        },
+        title = {
+            Text(text = stringResource(R.string.are_you_sure))
+        },
+        text = {
+            Text(
+                text = stringResource(
+                    id = R.string.confirm_manga_add_duplicate,
+                    duplicateFrom.name,
+                ),
+            )
+        },
+    )
+}

+ 4 - 4
app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt

@@ -16,7 +16,7 @@ fun DeleteChaptersDialog(
         onDismissRequest = onDismissRequest,
         dismissButton = {
             TextButton(onClick = onDismissRequest) {
-                Text(text = stringResource(id = android.R.string.cancel))
+                Text(text = stringResource(android.R.string.cancel))
             }
         },
         confirmButton = {
@@ -26,14 +26,14 @@ fun DeleteChaptersDialog(
                     onConfirm()
                 },
             ) {
-                Text(text = stringResource(id = android.R.string.ok))
+                Text(text = stringResource(android.R.string.ok))
             }
         },
         title = {
-            Text(text = stringResource(id = R.string.are_you_sure))
+            Text(text = stringResource(R.string.are_you_sure))
         },
         text = {
-            Text(text = stringResource(id = R.string.confirm_delete_chapters))
+            Text(text = stringResource(R.string.confirm_delete_chapters))
         },
     )
 }

+ 1 - 1
app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseContent.kt

@@ -35,7 +35,7 @@ fun ClearDatabaseContent(
                     )
                 }
             }
-            false -> EmptyScreen(message = stringResource(id = R.string.database_clean))
+            false -> EmptyScreen(message = stringResource(R.string.database_clean))
         }
     }
 }

+ 3 - 3
app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseDialogs.kt

@@ -16,16 +16,16 @@ fun ClearDatabaseDeleteDialog(
         onDismissRequest = onDismissRequest,
         confirmButton = {
             TextButton(onClick = onDelete) {
-                Text(text = stringResource(id = android.R.string.ok))
+                Text(text = stringResource(android.R.string.ok))
             }
         },
         dismissButton = {
             TextButton(onClick = onDismissRequest) {
-                Text(text = stringResource(id = android.R.string.cancel))
+                Text(text = stringResource(android.R.string.cancel))
             }
         },
         text = {
-            Text(text = stringResource(id = R.string.clear_database_confirmation))
+            Text(text = stringResource(R.string.clear_database_confirmation))
         },
     )
 }

+ 1 - 1
app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseFloatingActionButton.kt

@@ -27,7 +27,7 @@ fun ClearDatabaseFloatingActionButton(
         ExtendedFloatingActionButton(
             modifier = Modifier.navigationBarsPadding(),
             text = {
-                Text(text = stringResource(id = R.string.action_delete))
+                Text(text = stringResource(R.string.action_delete))
             },
             icon = {
                 Icon(Icons.Outlined.Delete, contentDescription = "")

+ 1 - 1
app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseItem.kt

@@ -43,7 +43,7 @@ fun ClearDatabaseItem(
                 text = source.visualName,
                 style = MaterialTheme.typography.bodyMedium,
             )
-            Text(text = stringResource(id = R.string.clear_database_source_item_count, count))
+            Text(text = stringResource(R.string.clear_database_source_item_count, count))
         }
         Checkbox(
             checked = isSelected,

+ 3 - 3
app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseToolbar.kt

@@ -18,19 +18,19 @@ fun ClearDatabaseToolbar(
     onClickInvertSelection: () -> Unit,
 ) {
     AppBar(
-        title = stringResource(id = R.string.pref_clear_database),
+        title = stringResource(R.string.pref_clear_database),
         navigateUp = navigateUp,
         actions = {
             if (state.isEmpty.not()) {
                 AppBarActions(
                     actions = listOf(
                         AppBar.Action(
-                            title = stringResource(id = R.string.action_select_all),
+                            title = stringResource(R.string.action_select_all),
                             icon = Icons.Outlined.SelectAll,
                             onClick = onClickSelectAll,
                         ),
                         AppBar.Action(
-                            title = stringResource(id = R.string.action_select_all),
+                            title = stringResource(R.string.action_select_all),
                             icon = Icons.Outlined.FlipToBack,
                             onClick = onClickInvertSelection,
                         ),

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/glance/UpdatesGridGlanceWidget.kt

@@ -92,7 +92,7 @@ class UpdatesGridGlanceWidget : GlanceAppWidget() {
             contentAlignment = Alignment.Center,
         ) {
             Text(
-                text = stringResource(id = R.string.appwidget_unavailable_locked),
+                text = stringResource(R.string.appwidget_unavailable_locked),
                 style = TextStyle(
                     color = ColorProvider(R.color.appwidget_on_secondary_container),
                     fontSize = 12.sp,
@@ -114,7 +114,7 @@ class UpdatesGridGlanceWidget : GlanceAppWidget() {
             if (inData == null) {
                 CircularProgressIndicator()
             } else if (inData.isEmpty()) {
-                Text(text = stringResource(id = R.string.information_no_recent))
+                Text(text = stringResource(R.string.information_no_recent))
             } else {
                 (0 until rowCount).forEach { i ->
                     val coverRow = (0 until columnCount).mapNotNull { j ->

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt

@@ -641,7 +641,7 @@ class LibraryPresenter(
     fun getToolbarTitle(): androidx.compose.runtime.State<LibraryToolbarTitle> {
         val category = categories.getOrNull(activeCategory)
 
-        val defaultTitle = stringResource(id = R.string.label_library)
+        val defaultTitle = stringResource(R.string.label_library)
         val categoryName = category?.visualName ?: defaultTitle
 
         val default = remember { LibraryToolbarTitle(defaultTitle) }

+ 0 - 54
app/src/main/java/eu/kanade/tachiyomi/ui/manga/AddDuplicateMangaDialog.kt

@@ -2,19 +2,10 @@ package eu.kanade.tachiyomi.ui.manga
 
 import android.app.Dialog
 import android.os.Bundle
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.material3.AlertDialog
-import androidx.compose.material3.Text
-import androidx.compose.material3.TextButton
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.res.stringResource
 import com.bluelinelabs.conductor.Controller
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import eu.kanade.domain.manga.model.Manga
 import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.source.Source
 import eu.kanade.tachiyomi.source.SourceManager
 import eu.kanade.tachiyomi.ui.base.controller.DialogController
 import eu.kanade.tachiyomi.ui.base.controller.pushController
@@ -55,48 +46,3 @@ class AddDuplicateMangaDialog(bundle: Bundle? = null) : DialogController(bundle)
             .create()
     }
 }
-
-@Composable
-fun DuplicateDialog(
-    onDismissRequest: () -> Unit,
-    onConfirm: () -> Unit,
-    onOpenManga: () -> Unit,
-    duplicateFrom: Source,
-) {
-    AlertDialog(
-        onDismissRequest = onDismissRequest,
-        confirmButton = {
-            Row {
-                TextButton(onClick = {
-                    onDismissRequest()
-                    onOpenManga()
-                },) {
-                    Text(text = stringResource(id = R.string.action_show_manga))
-                }
-                Spacer(modifier = Modifier.weight(1f))
-                TextButton(onClick = onDismissRequest) {
-                    Text(text = stringResource(id = android.R.string.cancel))
-                }
-                TextButton(
-                    onClick = {
-                        onDismissRequest()
-                        onConfirm()
-                    },
-                ) {
-                    Text(text = stringResource(id = R.string.action_add))
-                }
-            }
-        },
-        title = {
-            Text(text = stringResource(id = R.string.are_you_sure))
-        },
-        text = {
-            Text(
-                text = stringResource(
-                    id = R.string.confirm_manga_add_duplicate,
-                    duplicateFrom.name,
-                ),
-            )
-        },
-    )
-}

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

@@ -26,6 +26,8 @@ import eu.kanade.presentation.components.LoadingScreen
 import eu.kanade.presentation.manga.DownloadAction
 import eu.kanade.presentation.manga.MangaScreen
 import eu.kanade.presentation.manga.components.DeleteChaptersDialog
+import eu.kanade.presentation.manga.components.DownloadCustomAmountDialog
+import eu.kanade.presentation.manga.components.DuplicateMangaDialog
 import eu.kanade.presentation.util.calculateWindowWidthSizeClass
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.download.DownloadService
@@ -46,7 +48,6 @@ import eu.kanade.tachiyomi.ui.library.LibraryController
 import eu.kanade.tachiyomi.ui.main.MainActivity
 import eu.kanade.tachiyomi.ui.manga.MangaPresenter.Dialog
 import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersSettingsSheet
-import eu.kanade.tachiyomi.ui.manga.chapter.DownloadCustomAmountDialog
 import eu.kanade.tachiyomi.ui.manga.info.MangaFullCoverDialog
 import eu.kanade.tachiyomi.ui.manga.track.TrackItem
 import eu.kanade.tachiyomi.ui.manga.track.TrackSearchDialog
@@ -105,6 +106,12 @@ class MangaController : FullComposeController<MangaPresenter> {
     @Composable
     override fun ComposeContent() {
         val state by presenter.state.collectAsState()
+
+        if (state is MangaScreenState.Loading) {
+            LoadingScreen()
+            return
+        }
+
         val dialog by derivedStateOf {
             when (val state = state) {
                 MangaScreenState.Loading -> null
@@ -112,93 +119,88 @@ class MangaController : FullComposeController<MangaPresenter> {
             }
         }
 
-        if (state is MangaScreenState.Success) {
-            val successState = state as MangaScreenState.Success
-            val isHttpSource = remember { successState.source is HttpSource }
-
-            val scope = rememberCoroutineScope()
-
-            MangaScreen(
-                state = successState,
-                snackbarHostState = snackbarHostState,
-                windowWidthSizeClass = calculateWindowWidthSizeClass(),
-                onBackClicked = router::popCurrentController,
-                onChapterClicked = this::openChapter,
-                onDownloadChapter = this::onDownloadChapters.takeIf { !successState.source.isLocalOrStub() },
-                onAddToLibraryClicked = this::onFavoriteClick,
-                onWebViewClicked = this::openMangaInWebView.takeIf { isHttpSource },
-                onTrackingClicked = trackSheet::show.takeIf { successState.trackingAvailable },
-                onTagClicked = this::performGenreSearch,
-                onFilterButtonClicked = settingsSheet::show,
-                onRefresh = presenter::fetchAllFromSource,
-                onContinueReading = this::continueReading,
-                onSearch = this::performSearch,
-                onCoverClicked = this::openCoverDialog,
-                onShareClicked = this::shareManga.takeIf { isHttpSource },
-                onDownloadActionClicked = this::runDownloadChapterAction.takeIf { !successState.source.isLocalOrStub() },
-                onEditCategoryClicked = presenter::promptChangeCategories.takeIf { successState.manga.favorite },
-                onMigrateClicked = this::migrateManga.takeIf { successState.manga.favorite },
-                onMultiBookmarkClicked = presenter::bookmarkChapters,
-                onMultiMarkAsReadClicked = presenter::markChaptersRead,
-                onMarkPreviousAsReadClicked = presenter::markPreviousChapterRead,
-                onMultiDeleteClicked = presenter::showDeleteChapterDialog,
-                onChapterSelected = presenter::toggleSelection,
-                onAllChapterSelected = presenter::toggleAllSelection,
-                onInvertSelection = presenter::invertSelection,
-            )
+        val successState = state as MangaScreenState.Success
+        val isHttpSource = remember { successState.source is HttpSource }
+        val scope = rememberCoroutineScope()
+
+        MangaScreen(
+            state = successState,
+            snackbarHostState = snackbarHostState,
+            windowWidthSizeClass = calculateWindowWidthSizeClass(),
+            onBackClicked = router::popCurrentController,
+            onChapterClicked = this::openChapter,
+            onDownloadChapter = this::onDownloadChapters.takeIf { !successState.source.isLocalOrStub() },
+            onAddToLibraryClicked = this::onFavoriteClick,
+            onWebViewClicked = this::openMangaInWebView.takeIf { isHttpSource },
+            onTrackingClicked = trackSheet::show.takeIf { successState.trackingAvailable },
+            onTagClicked = this::performGenreSearch,
+            onFilterButtonClicked = settingsSheet::show,
+            onRefresh = presenter::fetchAllFromSource,
+            onContinueReading = this::continueReading,
+            onSearch = this::performSearch,
+            onCoverClicked = this::openCoverDialog,
+            onShareClicked = this::shareManga.takeIf { isHttpSource },
+            onDownloadActionClicked = this::runDownloadChapterAction.takeIf { !successState.source.isLocalOrStub() },
+            onEditCategoryClicked = presenter::promptChangeCategories.takeIf { successState.manga.favorite },
+            onMigrateClicked = this::migrateManga.takeIf { successState.manga.favorite },
+            onMultiBookmarkClicked = presenter::bookmarkChapters,
+            onMultiMarkAsReadClicked = presenter::markChaptersRead,
+            onMarkPreviousAsReadClicked = presenter::markPreviousChapterRead,
+            onMultiDeleteClicked = presenter::showDeleteChapterDialog,
+            onChapterSelected = presenter::toggleSelection,
+            onAllChapterSelected = presenter::toggleAllSelection,
+            onInvertSelection = presenter::invertSelection,
+        )
 
-            val onDismissRequest = { presenter.dismissDialog() }
-            when (val dialog = dialog) {
-                is Dialog.ChangeCategory -> {
-                    ChangeCategoryDialog(
-                        initialSelection = dialog.initialSelection,
-                        onDismissRequest = onDismissRequest,
-                        onEditCategories = {
-                            router.pushController(CategoryController())
-                        },
-                        onConfirm = { include, _ ->
-                            presenter.moveMangaToCategoriesAndAddToLibrary(dialog.manga, include)
-                        },
-                    )
-                }
-                is Dialog.DeleteChapters -> {
-                    DeleteChaptersDialog(
-                        onDismissRequest = onDismissRequest,
-                        onConfirm = {
-                            deleteChapters(dialog.chapters)
-                        },
-                    )
-                }
-                is Dialog.DownloadCustomAmount -> {
-                    DownloadCustomAmountDialog(
-                        maxAmount = dialog.max,
-                        onDismissRequest = onDismissRequest,
-                        onConfirm = { amount ->
-                            val chaptersToDownload = presenter.getUnreadChaptersSorted().take(amount)
-                            if (chaptersToDownload.isNotEmpty()) {
-                                scope.launch { downloadChapters(chaptersToDownload) }
-                            }
-                        },
-                    )
-                }
-                is Dialog.DuplicateManga -> {
-                    DuplicateDialog(
-                        onDismissRequest = onDismissRequest,
-                        onConfirm = {
-                            presenter.toggleFavorite(
-                                onRemoved = {},
-                                onAdded = {},
-                                checkDuplicate = false,
-                            )
-                        },
-                        onOpenManga = { router.pushController(MangaController(dialog.duplicate.id)) },
-                        duplicateFrom = presenter.getSourceOrStub(dialog.duplicate),
-                    )
-                }
-                null -> {}
+        val onDismissRequest = { presenter.dismissDialog() }
+        when (val dialog = dialog) {
+            is Dialog.ChangeCategory -> {
+                ChangeCategoryDialog(
+                    initialSelection = dialog.initialSelection,
+                    onDismissRequest = onDismissRequest,
+                    onEditCategories = {
+                        router.pushController(CategoryController())
+                    },
+                    onConfirm = { include, _ ->
+                        presenter.moveMangaToCategoriesAndAddToLibrary(dialog.manga, include)
+                    },
+                )
             }
-        } else {
-            LoadingScreen()
+            is Dialog.DeleteChapters -> {
+                DeleteChaptersDialog(
+                    onDismissRequest = onDismissRequest,
+                    onConfirm = {
+                        deleteChapters(dialog.chapters)
+                    },
+                )
+            }
+            is Dialog.DownloadCustomAmount -> {
+                DownloadCustomAmountDialog(
+                    maxAmount = dialog.max,
+                    onDismissRequest = onDismissRequest,
+                    onConfirm = { amount ->
+                        val chaptersToDownload = presenter.getUnreadChaptersSorted().take(amount)
+                        if (chaptersToDownload.isNotEmpty()) {
+                            scope.launch { downloadChapters(chaptersToDownload) }
+                        }
+                    },
+                )
+            }
+            is Dialog.DuplicateManga -> {
+                DuplicateMangaDialog(
+                    onDismissRequest = onDismissRequest,
+                    onConfirm = {
+                        presenter.toggleFavorite(
+                            onRemoved = {},
+                            onAdded = {},
+                            checkDuplicate = false,
+                        )
+                    },
+                    onOpenManga = { router.pushController(MangaController(dialog.duplicate.id)) },
+                    duplicateFrom = presenter.getSourceOrStub(dialog.duplicate),
+                )
+            }
+            null -> {}
         }
     }
 
@@ -427,7 +429,7 @@ class MangaController : FullComposeController<MangaPresenter> {
         }
     }
 
-    fun deleteChapters(chapters: List<DomainChapter>) {
+    private fun deleteChapters(chapters: List<DomainChapter>) {
         if (chapters.isEmpty()) return
         presenter.deleteChapters(chapters)
     }

+ 0 - 1
build.gradle.kts

@@ -26,7 +26,6 @@ subprojects {
     kotlinter {
         experimentalRules = true
 
-
         disabledRules = arrayOf(
             "experimental:argument-list-wrapping", // Doesn't play well with Android Studio
             "filename", // Often broken to give a more general name