Просмотр исходного кода

Move app state banner to the very top (#8706)

This moves the banners to the root composable and so eliminates the need to
track the app states in every screen.
Ivan Iskandar 2 лет назад
Родитель
Сommit
d97eab0328
24 измененных файлов с 212 добавлено и 290 удалено
  1. 1 0
      app/build.gradle.kts
  2. 0 14
      app/src/main/java/eu/kanade/presentation/components/AppBar.kt
  3. 22 6
      app/src/main/java/eu/kanade/presentation/components/Banners.kt
  4. 0 4
      app/src/main/java/eu/kanade/presentation/components/TabbedScreen.kt
  5. 0 4
      app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt
  6. 0 4
      app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt
  7. 0 5
      app/src/main/java/eu/kanade/presentation/library/components/LibraryTabs.kt
  8. 0 14
      app/src/main/java/eu/kanade/presentation/library/components/LibraryToolbar.kt
  9. 0 4
      app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt
  10. 0 5
      app/src/main/java/eu/kanade/presentation/manga/components/MangaToolbar.kt
  11. 119 113
      app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt
  12. 0 8
      app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt
  13. 0 16
      app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt
  14. 0 3
      app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt
  15. 0 5
      app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt
  16. 0 7
      app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoryScreenModel.kt
  17. 0 2
      app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoryTab.kt
  18. 0 3
      app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt
  19. 1 6
      app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt
  20. 67 32
      app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
  21. 0 27
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt
  22. 0 5
      app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt
  23. 0 2
      app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesTab.kt
  24. 2 1
      gradle/compose.versions.toml

+ 1 - 0
app/build.gradle.kts

@@ -182,6 +182,7 @@ dependencies {
     implementation(compose.accompanist.flowlayout)
     implementation(compose.accompanist.permissions)
     implementation(compose.accompanist.themeadapter)
+    implementation(compose.accompanist.systemuicontroller)
 
     implementation(androidx.paging.runtime)
     implementation(androidx.paging.compose)

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

@@ -63,9 +63,6 @@ fun AppBar(
     actionModeCounter: Int = 0,
     onCancelActionMode: () -> Unit = {},
     actionModeActions: @Composable RowScope.() -> Unit = {},
-    // Banners
-    downloadedOnlyMode: Boolean = false,
-    incognitoMode: Boolean = false,
 
     scrollBehavior: TopAppBarScrollBehavior? = null,
 ) {
@@ -93,8 +90,6 @@ fun AppBar(
         },
         isActionMode = isActionMode,
         onCancelActionMode = onCancelActionMode,
-        downloadedOnlyMode = downloadedOnlyMode,
-        incognitoMode = incognitoMode,
         scrollBehavior = scrollBehavior,
     )
 }
@@ -112,9 +107,6 @@ fun AppBar(
     // Action mode
     isActionMode: Boolean = false,
     onCancelActionMode: () -> Unit = {},
-    // Banners
-    downloadedOnlyMode: Boolean = false,
-    incognitoMode: Boolean = false,
 
     scrollBehavior: TopAppBarScrollBehavior? = null,
 ) {
@@ -150,8 +142,6 @@ fun AppBar(
             ),
             scrollBehavior = scrollBehavior,
         )
-
-        AppStateBanners(downloadedOnlyMode, incognitoMode)
     }
 }
 
@@ -236,8 +226,6 @@ fun SearchToolbar(
     onSearch: (String) -> Unit = {},
     onClickCloseSearch: () -> Unit = { onChangeSearchQuery(null) },
     actions: @Composable RowScope.() -> Unit = {},
-    incognitoMode: Boolean = false,
-    downloadedOnlyMode: Boolean = false,
     scrollBehavior: TopAppBarScrollBehavior? = null,
     visualTransformation: VisualTransformation = VisualTransformation.None,
     interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
@@ -326,8 +314,6 @@ fun SearchToolbar(
             key("actions") { actions() }
         },
         isActionMode = false,
-        downloadedOnlyMode = downloadedOnlyMode,
-        incognitoMode = incognitoMode,
         scrollBehavior = scrollBehavior,
     )
     LaunchedEffect(searchClickCount) {

+ 22 - 6
app/src/main/java/eu/kanade/presentation/components/Banners.kt

@@ -3,8 +3,13 @@ package eu.kanade.presentation.components
 import androidx.annotation.StringRes
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
 import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.only
 import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.systemBars
+import androidx.compose.foundation.layout.windowInsetsPadding
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
@@ -37,24 +42,34 @@ fun AppStateBanners(
     incognitoMode: Boolean,
     modifier: Modifier = Modifier,
 ) {
+    val insets = WindowInsets.systemBars.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
     Column(modifier = modifier) {
         if (downloadedOnlyMode) {
-            DownloadedOnlyModeBanner()
+            DownloadedOnlyModeBanner(
+                modifier = Modifier.windowInsetsPadding(insets),
+            )
         }
         if (incognitoMode) {
-            IncognitoModeBanner()
+            IncognitoModeBanner(
+                modifier = if (!downloadedOnlyMode) {
+                    Modifier.windowInsetsPadding(insets)
+                } else {
+                    Modifier
+                },
+            )
         }
     }
 }
 
 @Composable
-private fun DownloadedOnlyModeBanner() {
+private fun DownloadedOnlyModeBanner(modifier: Modifier = Modifier) {
     Text(
         text = stringResource(R.string.label_downloaded_only),
         modifier = Modifier
             .background(color = MaterialTheme.colorScheme.tertiary)
             .fillMaxWidth()
-            .padding(4.dp),
+            .padding(4.dp)
+            .then(modifier),
         color = MaterialTheme.colorScheme.onTertiary,
         textAlign = TextAlign.Center,
         style = MaterialTheme.typography.labelMedium,
@@ -62,13 +77,14 @@ private fun DownloadedOnlyModeBanner() {
 }
 
 @Composable
-private fun IncognitoModeBanner() {
+private fun IncognitoModeBanner(modifier: Modifier = Modifier) {
     Text(
         text = stringResource(R.string.pref_incognito_mode),
         modifier = Modifier
             .background(color = MaterialTheme.colorScheme.primary)
             .fillMaxWidth()
-            .padding(4.dp),
+            .padding(4.dp)
+            .then(modifier),
         color = MaterialTheme.colorScheme.onPrimary,
         textAlign = TextAlign.Center,
         style = MaterialTheme.typography.labelMedium,

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

@@ -29,8 +29,6 @@ fun TabbedScreen(
     startIndex: Int? = null,
     searchQuery: String? = null,
     onChangeSearchQuery: (String?) -> Unit = {},
-    incognitoMode: Boolean,
-    downloadedOnlyMode: Boolean,
 ) {
     val scope = rememberCoroutineScope()
     val state = rememberPagerState()
@@ -78,8 +76,6 @@ fun TabbedScreen(
                 }
             }
 
-            AppStateBanners(downloadedOnlyMode, incognitoMode)
-
             HorizontalPager(
                 count = tabs.size,
                 modifier = Modifier.fillMaxSize(),

+ 0 - 4
app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt

@@ -26,8 +26,6 @@ import java.util.Date
 fun HistoryScreen(
     state: HistoryState,
     snackbarHostState: SnackbarHostState,
-    incognitoMode: Boolean,
-    downloadedOnlyMode: Boolean,
     onSearchQueryChange: (String?) -> Unit,
     onClickCover: (mangaId: Long) -> Unit,
     onClickResume: (mangaId: Long, chapterId: Long) -> Unit,
@@ -47,8 +45,6 @@ fun HistoryScreen(
                         )
                     }
                 },
-                downloadedOnlyMode = downloadedOnlyMode,
-                incognitoMode = incognitoMode,
                 scrollBehavior = scrollBehavior,
             )
         },

+ 0 - 4
app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt

@@ -45,8 +45,6 @@ fun LibraryContent(
     getDisplayModeForPage: @Composable (Int) -> LibraryDisplayMode,
     getColumnsForOrientation: (Boolean) -> PreferenceMutableState<Int>,
     getLibraryForPage: (Int) -> List<LibraryItem>,
-    isDownloadOnly: Boolean,
-    isIncognitoMode: Boolean,
 ) {
     Column(
         modifier = Modifier.padding(
@@ -65,8 +63,6 @@ fun LibraryContent(
             LibraryTabs(
                 categories = categories,
                 currentPageIndex = pagerState.currentPage,
-                isDownloadOnly = isDownloadOnly,
-                isIncognitoMode = isIncognitoMode,
                 getNumberOfMangaForCategory = getNumberOfMangaForCategory,
             ) { scope.launch { pagerState.animateScrollToPage(it) } }
         }

+ 0 - 5
app/src/main/java/eu/kanade/presentation/library/components/LibraryTabs.kt

@@ -8,7 +8,6 @@ import androidx.compose.runtime.Composable
 import androidx.compose.ui.unit.dp
 import eu.kanade.domain.category.model.Category
 import eu.kanade.presentation.category.visualName
-import eu.kanade.presentation.components.AppStateBanners
 import eu.kanade.presentation.components.Divider
 import eu.kanade.presentation.components.TabIndicator
 import eu.kanade.presentation.components.TabText
@@ -17,8 +16,6 @@ import eu.kanade.presentation.components.TabText
 fun LibraryTabs(
     categories: List<Category>,
     currentPageIndex: Int,
-    isDownloadOnly: Boolean,
-    isIncognitoMode: Boolean,
     getNumberOfMangaForCategory: (Category) -> Int?,
     onTabItemClick: (Int) -> Unit,
 ) {
@@ -47,7 +44,5 @@ fun LibraryTabs(
         }
 
         Divider()
-
-        AppStateBanners(isDownloadOnly, isIncognitoMode)
     }
 }

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

@@ -32,8 +32,6 @@ fun LibraryToolbar(
     hasActiveFilters: Boolean,
     selectedCount: Int,
     title: LibraryToolbarTitle,
-    incognitoMode: Boolean,
-    downloadedOnlyMode: Boolean,
     onClickUnselectAll: () -> Unit,
     onClickSelectAll: () -> Unit,
     onClickInvertSelection: () -> Unit,
@@ -46,8 +44,6 @@ fun LibraryToolbar(
 ) = when {
     selectedCount > 0 -> LibrarySelectionToolbar(
         selectedCount = selectedCount,
-        incognitoMode = incognitoMode,
-        downloadedOnlyMode = downloadedOnlyMode,
         onClickUnselectAll = onClickUnselectAll,
         onClickSelectAll = onClickSelectAll,
         onClickInvertSelection = onClickInvertSelection,
@@ -55,8 +51,6 @@ fun LibraryToolbar(
     else -> LibraryRegularToolbar(
         title = title,
         hasFilters = hasActiveFilters,
-        incognitoMode = incognitoMode,
-        downloadedOnlyMode = downloadedOnlyMode,
         searchQuery = searchQuery,
         onSearchQueryChange = onSearchQueryChange,
         onClickFilter = onClickFilter,
@@ -70,8 +64,6 @@ fun LibraryToolbar(
 fun LibraryRegularToolbar(
     title: LibraryToolbarTitle,
     hasFilters: Boolean,
-    incognitoMode: Boolean,
-    downloadedOnlyMode: Boolean,
     searchQuery: String?,
     onSearchQueryChange: (String?) -> Unit,
     onClickFilter: () -> Unit,
@@ -123,8 +115,6 @@ fun LibraryRegularToolbar(
                 )
             }
         },
-        incognitoMode = incognitoMode,
-        downloadedOnlyMode = downloadedOnlyMode,
         scrollBehavior = scrollBehavior,
     )
 }
@@ -132,8 +122,6 @@ fun LibraryRegularToolbar(
 @Composable
 fun LibrarySelectionToolbar(
     selectedCount: Int,
-    incognitoMode: Boolean,
-    downloadedOnlyMode: Boolean,
     onClickUnselectAll: () -> Unit,
     onClickSelectAll: () -> Unit,
     onClickInvertSelection: () -> Unit,
@@ -150,8 +138,6 @@ fun LibrarySelectionToolbar(
         },
         isActionMode = true,
         onCancelActionMode = onClickUnselectAll,
-        incognitoMode = incognitoMode,
-        downloadedOnlyMode = downloadedOnlyMode,
     )
 }
 

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

@@ -238,8 +238,6 @@ private fun MangaScreenSmallImpl(
                 titleAlphaProvider = { animatedTitleAlpha },
                 backgroundAlphaProvider = { animatedBgAlpha },
                 hasFilters = state.manga.chaptersFiltered(),
-                incognitoMode = state.isIncognitoMode,
-                downloadedOnlyMode = state.isDownloadedOnlyMode,
                 onBackClicked = internalOnBackPressed,
                 onClickFilter = onFilterClicked,
                 onClickShare = onShareClicked,
@@ -450,8 +448,6 @@ fun MangaScreenLargeImpl(
                     titleAlphaProvider = { if (chapters.fastAny { it.selected }) 1f else 0f },
                     backgroundAlphaProvider = { 1f },
                     hasFilters = state.manga.chaptersFiltered(),
-                    incognitoMode = state.isIncognitoMode,
-                    downloadedOnlyMode = state.isDownloadedOnlyMode,
                     onBackClicked = internalOnBackPressed,
                     onClickFilter = onFilterButtonClicked,
                     onClickShare = onShareClicked,

+ 0 - 5
app/src/main/java/eu/kanade/presentation/manga/components/MangaToolbar.kt

@@ -26,7 +26,6 @@ import androidx.compose.ui.draw.alpha
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
-import eu.kanade.presentation.components.AppStateBanners
 import eu.kanade.presentation.components.DownloadDropdownMenu
 import eu.kanade.presentation.components.OverflowMenu
 import eu.kanade.presentation.manga.DownloadAction
@@ -40,8 +39,6 @@ fun MangaToolbar(
     titleAlphaProvider: () -> Float,
     backgroundAlphaProvider: () -> Float = titleAlphaProvider,
     hasFilters: Boolean,
-    incognitoMode: Boolean,
-    downloadedOnlyMode: Boolean,
     onBackClicked: () -> Unit,
     onClickFilter: () -> Unit,
     onClickShare: (() -> Unit)?,
@@ -151,7 +148,5 @@ fun MangaToolbar(
                     .copy(alpha = if (isActionMode) 1f else backgroundAlphaProvider()),
             ),
         )
-
-        AppStateBanners(downloadedOnlyMode, incognitoMode)
     }
 }

+ 119 - 113
app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt

@@ -1,7 +1,13 @@
 package eu.kanade.presentation.more
 
 import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.systemBarsPadding
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
+import androidx.compose.foundation.layout.only
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.systemBars
+import androidx.compose.foundation.layout.windowInsetsPadding
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.outlined.CloudOff
 import androidx.compose.material.icons.outlined.GetApp
@@ -18,8 +24,8 @@ import androidx.compose.ui.platform.LocalUriHandler
 import androidx.compose.ui.res.pluralStringResource
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.res.vectorResource
-import eu.kanade.presentation.components.AppStateBanners
 import eu.kanade.presentation.components.Divider
+import eu.kanade.presentation.components.Scaffold
 import eu.kanade.presentation.components.ScrollbarLazyColumn
 import eu.kanade.presentation.components.WarningBanner
 import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget
@@ -45,125 +51,125 @@ fun MoreScreen(
 ) {
     val uriHandler = LocalUriHandler.current
 
-    ScrollbarLazyColumn(
-        modifier = Modifier.systemBarsPadding(),
-    ) {
-        if (isFDroid) {
+    Scaffold(
+        topBar = {
+            Column(
+                modifier = Modifier.windowInsetsPadding(
+                    WindowInsets.systemBars.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
+                ),
+            ) {
+                if (isFDroid) {
+                    WarningBanner(
+                        textRes = R.string.fdroid_warning,
+                        modifier = Modifier.clickable {
+                            uriHandler.openUri("https://tachiyomi.org/help/faq/#how-do-i-migrate-from-the-f-droid-version")
+                        },
+                    )
+                }
+            }
+        },
+    ) { contentPadding ->
+        ScrollbarLazyColumn(
+            modifier = Modifier.padding(contentPadding),
+        ) {
             item {
-                WarningBanner(
-                    textRes = R.string.fdroid_warning,
-                    modifier = Modifier.clickable {
-                        uriHandler.openUri("https://tachiyomi.org/help/faq/#how-do-i-migrate-from-the-f-droid-version")
-                    },
+                LogoHeader()
+            }
+            item {
+                SwitchPreferenceWidget(
+                    title = stringResource(R.string.label_downloaded_only),
+                    subtitle = stringResource(R.string.downloaded_only_summary),
+                    icon = Icons.Outlined.CloudOff,
+                    checked = downloadedOnly,
+                    onCheckedChanged = onDownloadedOnlyChange,
+                )
+            }
+            item {
+                SwitchPreferenceWidget(
+                    title = stringResource(R.string.pref_incognito_mode),
+                    subtitle = stringResource(R.string.pref_incognito_mode_summary),
+                    icon = ImageVector.vectorResource(R.drawable.ic_glasses_24dp),
+                    checked = incognitoMode,
+                    onCheckedChanged = onIncognitoModeChange,
                 )
             }
-        }
-
-        item {
-            LogoHeader()
-        }
-
-        item {
-            AppStateBanners(
-                downloadedOnlyMode = downloadedOnly,
-                incognitoMode = incognitoMode,
-            )
-        }
-
-        item {
-            SwitchPreferenceWidget(
-                title = stringResource(R.string.label_downloaded_only),
-                subtitle = stringResource(R.string.downloaded_only_summary),
-                icon = Icons.Outlined.CloudOff,
-                checked = downloadedOnly,
-                onCheckedChanged = onDownloadedOnlyChange,
-            )
-        }
-        item {
-            SwitchPreferenceWidget(
-                title = stringResource(R.string.pref_incognito_mode),
-                subtitle = stringResource(R.string.pref_incognito_mode_summary),
-                icon = ImageVector.vectorResource(R.drawable.ic_glasses_24dp),
-                checked = incognitoMode,
-                onCheckedChanged = onIncognitoModeChange,
-            )
-        }
 
-        item { Divider() }
+            item { Divider() }
 
-        item {
-            val downloadQueueState = downloadQueueStateProvider()
-            TextPreferenceWidget(
-                title = stringResource(R.string.label_download_queue),
-                subtitle = when (downloadQueueState) {
-                    DownloadQueueState.Stopped -> null
-                    is DownloadQueueState.Paused -> {
-                        val pending = downloadQueueState.pending
-                        if (pending == 0) {
-                            stringResource(R.string.paused)
-                        } else {
-                            "${stringResource(R.string.paused)} • ${
-                            pluralStringResource(
-                                id = R.plurals.download_queue_summary,
-                                count = pending,
-                                pending,
-                            )
-                            }"
+            item {
+                val downloadQueueState = downloadQueueStateProvider()
+                TextPreferenceWidget(
+                    title = stringResource(R.string.label_download_queue),
+                    subtitle = when (downloadQueueState) {
+                        DownloadQueueState.Stopped -> null
+                        is DownloadQueueState.Paused -> {
+                            val pending = downloadQueueState.pending
+                            if (pending == 0) {
+                                stringResource(R.string.paused)
+                            } else {
+                                "${stringResource(R.string.paused)} • ${
+                                pluralStringResource(
+                                    id = R.plurals.download_queue_summary,
+                                    count = pending,
+                                    pending,
+                                )
+                                }"
+                            }
                         }
-                    }
-                    is DownloadQueueState.Downloading -> {
-                        val pending = downloadQueueState.pending
-                        pluralStringResource(id = R.plurals.download_queue_summary, count = pending, pending)
-                    }
-                },
-                icon = Icons.Outlined.GetApp,
-                onPreferenceClick = onClickDownloadQueue,
-            )
-        }
-        item {
-            TextPreferenceWidget(
-                title = stringResource(R.string.categories),
-                icon = Icons.Outlined.Label,
-                onPreferenceClick = onClickCategories,
-            )
-        }
-        item {
-            TextPreferenceWidget(
-                title = stringResource(R.string.label_stats),
-                icon = Icons.Outlined.QueryStats,
-                onPreferenceClick = onClickStats,
-            )
-        }
-        item {
-            TextPreferenceWidget(
-                title = stringResource(R.string.label_backup),
-                icon = Icons.Outlined.SettingsBackupRestore,
-                onPreferenceClick = onClickBackupAndRestore,
-            )
-        }
+                        is DownloadQueueState.Downloading -> {
+                            val pending = downloadQueueState.pending
+                            pluralStringResource(id = R.plurals.download_queue_summary, count = pending, pending)
+                        }
+                    },
+                    icon = Icons.Outlined.GetApp,
+                    onPreferenceClick = onClickDownloadQueue,
+                )
+            }
+            item {
+                TextPreferenceWidget(
+                    title = stringResource(R.string.categories),
+                    icon = Icons.Outlined.Label,
+                    onPreferenceClick = onClickCategories,
+                )
+            }
+            item {
+                TextPreferenceWidget(
+                    title = stringResource(R.string.label_stats),
+                    icon = Icons.Outlined.QueryStats,
+                    onPreferenceClick = onClickStats,
+                )
+            }
+            item {
+                TextPreferenceWidget(
+                    title = stringResource(R.string.label_backup),
+                    icon = Icons.Outlined.SettingsBackupRestore,
+                    onPreferenceClick = onClickBackupAndRestore,
+                )
+            }
 
-        item { Divider() }
+            item { Divider() }
 
-        item {
-            TextPreferenceWidget(
-                title = stringResource(R.string.label_settings),
-                icon = Icons.Outlined.Settings,
-                onPreferenceClick = onClickSettings,
-            )
-        }
-        item {
-            TextPreferenceWidget(
-                title = stringResource(R.string.pref_category_about),
-                icon = Icons.Outlined.Info,
-                onPreferenceClick = onClickAbout,
-            )
-        }
-        item {
-            TextPreferenceWidget(
-                title = stringResource(R.string.label_help),
-                icon = Icons.Outlined.HelpOutline,
-                onPreferenceClick = { uriHandler.openUri(Constants.URL_HELP) },
-            )
+            item {
+                TextPreferenceWidget(
+                    title = stringResource(R.string.label_settings),
+                    icon = Icons.Outlined.Settings,
+                    onPreferenceClick = onClickSettings,
+                )
+            }
+            item {
+                TextPreferenceWidget(
+                    title = stringResource(R.string.pref_category_about),
+                    icon = Icons.Outlined.Info,
+                    onPreferenceClick = onClickAbout,
+                )
+            }
+            item {
+                TextPreferenceWidget(
+                    title = stringResource(R.string.label_help),
+                    icon = Icons.Outlined.HelpOutline,
+                    onPreferenceClick = { uriHandler.openUri(Constants.URL_HELP) },
+                )
+            }
         }
     }
 }

+ 0 - 8
app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt

@@ -43,8 +43,6 @@ import kotlin.time.Duration.Companion.seconds
 fun UpdateScreen(
     state: UpdatesState,
     snackbarHostState: SnackbarHostState,
-    incognitoMode: Boolean,
-    downloadedOnlyMode: Boolean,
     lastUpdated: Long,
     relativeTime: Int,
     onClickCover: (UpdatesItem) -> Unit,
@@ -65,8 +63,6 @@ fun UpdateScreen(
     Scaffold(
         topBar = { scrollBehavior ->
             UpdatesAppBar(
-                incognitoMode = incognitoMode,
-                downloadedOnlyMode = downloadedOnlyMode,
                 onUpdateLibrary = { onUpdateLibrary() },
                 actionModeCounter = state.selected.size,
                 onSelectAll = { onSelectAll(true) },
@@ -136,8 +132,6 @@ fun UpdateScreen(
 @Composable
 private fun UpdatesAppBar(
     modifier: Modifier = Modifier,
-    incognitoMode: Boolean,
-    downloadedOnlyMode: Boolean,
     onUpdateLibrary: () -> Unit,
     // For action mode
     actionModeCounter: Int,
@@ -173,8 +167,6 @@ private fun UpdatesAppBar(
                 )
             }
         },
-        downloadedOnlyMode = downloadedOnlyMode,
-        incognitoMode = incognitoMode,
         scrollBehavior = scrollBehavior,
     )
 }

+ 0 - 16
app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt

@@ -9,13 +9,9 @@ import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
-import cafe.adriel.voyager.core.model.ScreenModel
-import cafe.adriel.voyager.core.model.coroutineScope
 import cafe.adriel.voyager.core.model.rememberScreenModel
 import cafe.adriel.voyager.navigator.tab.LocalTabNavigator
 import cafe.adriel.voyager.navigator.tab.TabOptions
-import eu.kanade.core.prefs.asState
-import eu.kanade.domain.base.BasePreferences
 import eu.kanade.presentation.components.TabbedScreen
 import eu.kanade.presentation.util.Tab
 import eu.kanade.tachiyomi.R
@@ -25,8 +21,6 @@ import eu.kanade.tachiyomi.ui.browse.migration.sources.migrateSourceTab
 import eu.kanade.tachiyomi.ui.browse.source.sourcesTab
 import eu.kanade.tachiyomi.ui.main.MainActivity
 import eu.kanade.tachiyomi.util.storage.DiskUtil
-import uy.kohesive.injekt.Injekt
-import uy.kohesive.injekt.api.get
 
 data class BrowseTab(
     private val toExtensions: Boolean = false,
@@ -47,7 +41,6 @@ data class BrowseTab(
     @Composable
     override fun Content() {
         val context = LocalContext.current
-        val screenModel = rememberScreenModel { BrowseScreenModel() }
 
         // Hoisted for extensions tab's search bar
         val extensionsScreenModel = rememberScreenModel { ExtensionsScreenModel() }
@@ -63,8 +56,6 @@ data class BrowseTab(
             startIndex = 1.takeIf { toExtensions },
             searchQuery = extensionsQuery,
             onChangeSearchQuery = extensionsScreenModel::search,
-            incognitoMode = screenModel.isIncognitoMode,
-            downloadedOnlyMode = screenModel.isDownloadOnly,
         )
 
         // For local source
@@ -75,10 +66,3 @@ data class BrowseTab(
         }
     }
 }
-
-private class BrowseScreenModel(
-    preferences: BasePreferences = Injekt.get(),
-) : ScreenModel {
-    val isDownloadOnly: Boolean by preferences.downloadedOnly().asState(coroutineScope)
-    val isIncognitoMode: Boolean by preferences.incognitoMode().asState(coroutineScope)
-}

+ 0 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt

@@ -43,7 +43,6 @@ import eu.kanade.domain.source.interactor.GetRemoteManga
 import eu.kanade.presentation.browse.BrowseSourceContent
 import eu.kanade.presentation.browse.components.BrowseSourceToolbar
 import eu.kanade.presentation.browse.components.RemoveMangaDialog
-import eu.kanade.presentation.components.AppStateBanners
 import eu.kanade.presentation.components.ChangeCategoryDialog
 import eu.kanade.presentation.components.Divider
 import eu.kanade.presentation.components.DuplicateMangaDialog
@@ -167,8 +166,6 @@ data class BrowseSourceScreen(
                     }
 
                     Divider()
-
-                    AppStateBanners(screenModel.isDownloadOnly, screenModel.isIncognitoMode)
                 }
             },
             snackbarHost = { SnackbarHost(hostState = snackbarHostState) },

+ 0 - 5
app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt

@@ -17,7 +17,6 @@ import eu.davidea.flexibleadapter.items.IFlexible
 import eu.kanade.core.prefs.CheckboxState
 import eu.kanade.core.prefs.asState
 import eu.kanade.core.prefs.mapAsCheckboxState
-import eu.kanade.domain.base.BasePreferences
 import eu.kanade.domain.category.interactor.GetCategories
 import eu.kanade.domain.category.interactor.SetMangaCategories
 import eu.kanade.domain.category.model.Category
@@ -82,7 +81,6 @@ class BrowseSourceScreenModel(
     private val sourceId: Long,
     searchQuery: String?,
     private val sourceManager: SourceManager = Injekt.get(),
-    preferences: BasePreferences = Injekt.get(),
     sourcePreferences: SourcePreferences = Injekt.get(),
     private val libraryPreferences: LibraryPreferences = Injekt.get(),
     private val coverCache: CoverCache = Injekt.get(),
@@ -103,9 +101,6 @@ class BrowseSourceScreenModel(
 
     var displayMode by sourcePreferences.sourceDisplayMode().asState(coroutineScope)
 
-    val isDownloadOnly: Boolean by preferences.downloadedOnly().asState(coroutineScope)
-    val isIncognitoMode: Boolean by preferences.incognitoMode().asState(coroutineScope)
-
     val source = sourceManager.get(sourceId) as CatalogueSource
 
     /**

+ 0 - 7
app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoryScreenModel.kt

@@ -1,12 +1,9 @@
 package eu.kanade.tachiyomi.ui.history
 
 import androidx.compose.runtime.Immutable
-import androidx.compose.runtime.getValue
 import cafe.adriel.voyager.core.model.StateScreenModel
 import cafe.adriel.voyager.core.model.coroutineScope
-import eu.kanade.core.prefs.asState
 import eu.kanade.core.util.insertSeparators
-import eu.kanade.domain.base.BasePreferences
 import eu.kanade.domain.chapter.model.Chapter
 import eu.kanade.domain.history.interactor.GetHistory
 import eu.kanade.domain.history.interactor.GetNextChapters
@@ -37,15 +34,11 @@ class HistoryScreenModel(
     private val getHistory: GetHistory = Injekt.get(),
     private val getNextChapters: GetNextChapters = Injekt.get(),
     private val removeHistory: RemoveHistory = Injekt.get(),
-    preferences: BasePreferences = Injekt.get(),
 ) : StateScreenModel<HistoryState>(HistoryState()) {
 
     private val _events: Channel<Event> = Channel(Channel.UNLIMITED)
     val events: Flow<Event> = _events.receiveAsFlow()
 
-    val isDownloadOnly: Boolean by preferences.downloadedOnly().asState(coroutineScope)
-    val isIncognitoMode: Boolean by preferences.incognitoMode().asState(coroutineScope)
-
     init {
         coroutineScope.launch {
             state.map { it.searchQuery }

+ 0 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoryTab.kt

@@ -62,8 +62,6 @@ object HistoryTab : Tab {
         HistoryScreen(
             state = state,
             snackbarHostState = snackbarHostState,
-            incognitoMode = screenModel.isIncognitoMode,
-            downloadedOnlyMode = screenModel.isDownloadOnly,
             onSearchQueryChange = screenModel::updateSearchQuery,
             onClickCover = { navigator.push(MangaScreen(it)) },
             onClickResume = screenModel::getNextChapterForManga,

+ 0 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt

@@ -89,9 +89,6 @@ class LibraryScreenModel(
 
     var activeCategoryIndex: Int by libraryPreferences.lastUsedCategory().asState(coroutineScope)
 
-    val isDownloadOnly: Boolean by preferences.downloadedOnly().asState(coroutineScope)
-    val isIncognitoMode: Boolean by preferences.incognitoMode().asState(coroutineScope)
-
     init {
         coroutineScope.launchIO {
             combine(

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

@@ -112,8 +112,6 @@ object LibraryTab : Tab {
                     hasActiveFilters = state.hasActiveFilters,
                     selectedCount = state.selection.size,
                     title = title,
-                    incognitoMode = !tabVisible && screenModel.isIncognitoMode,
-                    downloadedOnlyMode = !tabVisible && screenModel.isDownloadOnly,
                     onClickUnselectAll = screenModel::clearSelection,
                     onClickSelectAll = { screenModel.selectAll(screenModel.activeCategoryIndex) },
                     onClickInvertSelection = { screenModel.invertSelection(screenModel.activeCategoryIndex) },
@@ -197,10 +195,7 @@ object LibraryTab : Tab {
                         getNumberOfMangaForCategory = { state.getMangaCountForCategory(it) },
                         getDisplayModeForPage = { state.categories[it].display },
                         getColumnsForOrientation = { screenModel.getColumnsPreferenceForCurrentOrientation(it) },
-                        getLibraryForPage = { state.getLibraryItemsByPage(it) },
-                        isDownloadOnly = screenModel.isDownloadOnly,
-                        isIncognitoMode = screenModel.isIncognitoMode,
-                    )
+                    ) { state.getLibraryItemsByPage(it) }
                 }
             }
         }

+ 67 - 32
app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt

@@ -10,6 +10,12 @@ import android.view.View
 import android.view.Window
 import android.widget.Toast
 import androidx.activity.compose.BackHandler
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.consumeWindowInsets
+import androidx.compose.foundation.layout.statusBars
 import androidx.compose.material3.AlertDialog
 import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
@@ -20,6 +26,7 @@ import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
 import androidx.core.animation.doOnEnd
@@ -36,12 +43,14 @@ import cafe.adriel.voyager.navigator.Navigator
 import cafe.adriel.voyager.navigator.NavigatorDisposeBehavior
 import cafe.adriel.voyager.navigator.currentOrThrow
 import cafe.adriel.voyager.transitions.ScreenTransition
+import com.google.accompanist.systemuicontroller.rememberSystemUiController
 import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback
 import eu.kanade.domain.base.BasePreferences
 import eu.kanade.domain.category.model.Category
 import eu.kanade.domain.library.service.LibraryPreferences
 import eu.kanade.domain.source.service.SourcePreferences
 import eu.kanade.domain.ui.UiPreferences
+import eu.kanade.presentation.components.AppStateBanners
 import eu.kanade.presentation.util.Transition
 import eu.kanade.presentation.util.collectAsState
 import eu.kanade.tachiyomi.BuildConfig
@@ -142,47 +151,73 @@ class MainActivity : BaseActivity() {
             .launchIn(lifecycleScope)
 
         setComposeContent {
-            Navigator(
-                screen = HomeScreen,
-                disposeBehavior = NavigatorDisposeBehavior(disposeNestedNavigators = false, disposeSteps = true),
-            ) { navigator ->
-                if (navigator.size == 1) {
-                    ConfirmExit()
+            val incognito by preferences.incognitoMode().collectAsState()
+            val download by preferences.downloadedOnly().collectAsState()
+            Column {
+                AppStateBanners(
+                    downloadedOnlyMode = download,
+                    incognitoMode = incognito,
+                )
+                val systemUiController = rememberSystemUiController()
+                val active = incognito || download
+                val useDarkIcons = if (isSystemInDarkTheme()) active else !active
+                LaunchedEffect(systemUiController, useDarkIcons) {
+                    systemUiController.setStatusBarColor(
+                        color = androidx.compose.ui.graphics.Color.Transparent,
+                        darkIcons = useDarkIcons,
+                    )
                 }
 
-                LaunchedEffect(navigator) {
-                    [email protected] = navigator
+                Navigator(
+                    screen = HomeScreen,
+                    disposeBehavior = NavigatorDisposeBehavior(disposeNestedNavigators = false, disposeSteps = true),
+                ) { navigator ->
+                    if (navigator.size == 1) {
+                        ConfirmExit()
+                    }
+
+                    LaunchedEffect(navigator) {
+                        [email protected] = navigator
 
-                    if (savedInstanceState == null) {
-                        // Set start screen
-                        handleIntentAction(intent)
+                        if (savedInstanceState == null) {
+                            // Set start screen
+                            handleIntentAction(intent)
 
-                        // Reset Incognito Mode on relaunch
-                        preferences.incognitoMode().set(false)
+                            // Reset Incognito Mode on relaunch
+                            preferences.incognitoMode().set(false)
+                        }
+                    }
+
+                    // Consume insets already used by app state banners
+                    val boxModifier = if (incognito || download) {
+                        Modifier.consumeWindowInsets(WindowInsets.statusBars)
+                    } else {
+                        Modifier
+                    }
+                    Box(modifier = boxModifier) {
+                        // Shows current screen
+                        ScreenTransition(navigator = navigator, transition = { Transition.OneWayFade })
                     }
-                }
 
-                // Shows current screen
-                ScreenTransition(navigator = navigator, transition = { Transition.OneWayFade })
-
-                // Pop source-related screens when incognito mode is turned off
-                LaunchedEffect(Unit) {
-                    preferences.incognitoMode().changes()
-                        .drop(1)
-                        .onEach {
-                            if (!it) {
-                                val currentScreen = navigator.lastItem
-                                if (currentScreen is BrowseSourceScreen ||
-                                    (currentScreen is MangaScreen && currentScreen.fromSource)
-                                ) {
-                                    navigator.popUntilRoot()
+                    // Pop source-related screens when incognito mode is turned off
+                    LaunchedEffect(Unit) {
+                        preferences.incognitoMode().changes()
+                            .drop(1)
+                            .onEach {
+                                if (!it) {
+                                    val currentScreen = navigator.lastItem
+                                    if (currentScreen is BrowseSourceScreen ||
+                                        (currentScreen is MangaScreen && currentScreen.fromSource)
+                                    ) {
+                                        navigator.popUntilRoot()
+                                    }
                                 }
                             }
-                        }
-                        .launchIn(this)
-                }
+                            .launchIn(this)
+                    }
 
-                CheckForUpdate()
+                    CheckForUpdate()
+                }
             }
 
             var showChangelog by remember { mutableStateOf(didMigration && !BuildConfig.DEBUG) }

+ 0 - 27
app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt

@@ -10,7 +10,6 @@ import eu.kanade.core.prefs.CheckboxState
 import eu.kanade.core.prefs.mapAsCheckboxState
 import eu.kanade.core.util.addOrRemove
 import eu.kanade.data.chapter.NoChaptersException
-import eu.kanade.domain.base.BasePreferences
 import eu.kanade.domain.category.interactor.GetCategories
 import eu.kanade.domain.category.interactor.SetMangaCategories
 import eu.kanade.domain.category.model.Category
@@ -53,7 +52,6 @@ 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
 import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
 import eu.kanade.tachiyomi.util.system.logcat
@@ -64,7 +62,6 @@ import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.update
 import kotlinx.coroutines.isActive
@@ -81,7 +78,6 @@ class MangaInfoScreenModel(
     val context: Context,
     val mangaId: Long,
     private val isFromSource: Boolean,
-    basePreferences: BasePreferences = Injekt.get(),
     private val downloadPreferences: DownloadPreferences = Injekt.get(),
     private val libraryPreferences: LibraryPreferences = Injekt.get(),
     private val uiPreferences: UiPreferences = Injekt.get(),
@@ -130,17 +126,6 @@ class MangaInfoScreenModel(
         mutableState.update { if (it is MangaScreenState.Success) func(it) else it }
     }
 
-    private var incognitoMode = false
-        set(value) {
-            updateSuccessState { it.copy(isIncognitoMode = value) }
-            field = value
-        }
-    private var downloadedOnlyMode = false
-        set(value) {
-            updateSuccessState { it.copy(isDownloadedOnlyMode = value) }
-            field = value
-        }
-
     init {
         val toChapterItemsParams: List<Chapter>.(manga: Manga) -> List<ChapterItem> = { manga ->
             toChapterItems(
@@ -189,8 +174,6 @@ class MangaInfoScreenModel(
                     isFromSource = isFromSource,
                     chapters = chapters,
                     isRefreshingData = needRefreshInfo || needRefreshChapter,
-                    isIncognitoMode = incognitoMode,
-                    isDownloadedOnlyMode = downloadedOnlyMode,
                     dialog = null,
                 )
             }
@@ -210,14 +193,6 @@ class MangaInfoScreenModel(
             // Initial loading finished
             updateSuccessState { it.copy(isRefreshingData = false) }
         }
-
-        basePreferences.incognitoMode()
-            .asHotFlow { incognitoMode = it }
-            .launchIn(coroutineScope)
-
-        basePreferences.downloadedOnly()
-            .asHotFlow { downloadedOnlyMode = it }
-            .launchIn(coroutineScope)
     }
 
     fun fetchAllFromSource(manualFetch: Boolean = true) {
@@ -1037,8 +1012,6 @@ sealed class MangaScreenState {
         val chapters: List<ChapterItem>,
         val trackItems: List<TrackItem> = emptyList(),
         val isRefreshingData: Boolean = false,
-        val isIncognitoMode: Boolean = false,
-        val isDownloadedOnlyMode: Boolean = false,
         val dialog: MangaInfoScreenModel.Dialog? = null,
     ) : MangaScreenState() {
 

+ 0 - 5
app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt

@@ -11,7 +11,6 @@ import cafe.adriel.voyager.core.model.coroutineScope
 import eu.kanade.core.prefs.asState
 import eu.kanade.core.util.addOrRemove
 import eu.kanade.core.util.insertSeparators
-import eu.kanade.domain.base.BasePreferences
 import eu.kanade.domain.chapter.interactor.GetChapter
 import eu.kanade.domain.chapter.interactor.SetReadStatus
 import eu.kanade.domain.chapter.interactor.UpdateChapter
@@ -62,16 +61,12 @@ class UpdatesScreenModel(
     private val getChapter: GetChapter = Injekt.get(),
     private val libraryPreferences: LibraryPreferences = Injekt.get(),
     val snackbarHostState: SnackbarHostState = SnackbarHostState(),
-    basePreferences: BasePreferences = Injekt.get(),
     uiPreferences: UiPreferences = Injekt.get(),
 ) : StateScreenModel<UpdatesState>(UpdatesState()) {
 
     private val _events: Channel<Event> = Channel(Int.MAX_VALUE)
     val events: Flow<Event> = _events.receiveAsFlow()
 
-    val isDownloadOnly: Boolean by basePreferences.downloadedOnly().asState(coroutineScope)
-    val isIncognitoMode: Boolean by basePreferences.incognitoMode().asState(coroutineScope)
-
     val lastUpdated by libraryPreferences.libraryUpdateLastTimestamp().asState(coroutineScope)
 
     val relativeTime: Int by uiPreferences.relativeTime().asState(coroutineScope)

+ 0 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesTab.kt

@@ -56,8 +56,6 @@ object UpdatesTab : Tab {
         UpdateScreen(
             state = state,
             snackbarHostState = screenModel.snackbarHostState,
-            incognitoMode = screenModel.isIncognitoMode,
-            downloadedOnlyMode = screenModel.isDownloadOnly,
             lastUpdated = screenModel.lastUpdated,
             relativeTime = screenModel.relativeTime,
             onClickCover = { item -> navigator.push(MangaScreen(item.update.mangaId)) },

+ 2 - 1
gradle/compose.versions.toml

@@ -23,4 +23,5 @@ material-core = { module = "androidx.compose.material:material", version = "1.4.
 accompanist-webview = { module = "com.google.accompanist:accompanist-webview", version.ref = "accompanist" }
 accompanist-flowlayout = { module = "com.google.accompanist:accompanist-flowlayout", version.ref = "accompanist" }
 accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" }
-accompanist-themeadapter = { module = "com.google.accompanist:accompanist-themeadapter-material3", version.ref = "accompanist" }
+accompanist-themeadapter = { module = "com.google.accompanist:accompanist-themeadapter-material3", version.ref = "accompanist" }
+accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" }