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.
This commit is contained in:
Ivan Iskandar 2022-12-09 23:20:13 +07:00 committed by GitHub
parent a61e2799db
commit d97eab0328
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 217 additions and 295 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,13 @@
package eu.kanade.presentation.more package eu.kanade.presentation.more
import androidx.compose.foundation.clickable 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.Icons
import androidx.compose.material.icons.outlined.CloudOff import androidx.compose.material.icons.outlined.CloudOff
import androidx.compose.material.icons.outlined.GetApp 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.pluralStringResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource import androidx.compose.ui.res.vectorResource
import eu.kanade.presentation.components.AppStateBanners
import eu.kanade.presentation.components.Divider import eu.kanade.presentation.components.Divider
import eu.kanade.presentation.components.Scaffold
import eu.kanade.presentation.components.ScrollbarLazyColumn import eu.kanade.presentation.components.ScrollbarLazyColumn
import eu.kanade.presentation.components.WarningBanner import eu.kanade.presentation.components.WarningBanner
import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget
@ -45,11 +51,14 @@ fun MoreScreen(
) { ) {
val uriHandler = LocalUriHandler.current val uriHandler = LocalUriHandler.current
ScrollbarLazyColumn( Scaffold(
modifier = Modifier.systemBarsPadding(), topBar = {
Column(
modifier = Modifier.windowInsetsPadding(
WindowInsets.systemBars.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
),
) { ) {
if (isFDroid) { if (isFDroid) {
item {
WarningBanner( WarningBanner(
textRes = R.string.fdroid_warning, textRes = R.string.fdroid_warning,
modifier = Modifier.clickable { modifier = Modifier.clickable {
@ -58,18 +67,14 @@ fun MoreScreen(
) )
} }
} }
},
) { contentPadding ->
ScrollbarLazyColumn(
modifier = Modifier.padding(contentPadding),
) {
item { item {
LogoHeader() LogoHeader()
} }
item {
AppStateBanners(
downloadedOnlyMode = downloadedOnly,
incognitoMode = incognitoMode,
)
}
item { item {
SwitchPreferenceWidget( SwitchPreferenceWidget(
title = stringResource(R.string.label_downloaded_only), title = stringResource(R.string.label_downloaded_only),
@ -167,3 +172,4 @@ fun MoreScreen(
} }
} }
} }
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -89,9 +89,6 @@ class LibraryScreenModel(
var activeCategoryIndex: Int by libraryPreferences.lastUsedCategory().asState(coroutineScope) 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 { init {
coroutineScope.launchIO { coroutineScope.launchIO {
combine( combine(

View File

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

View File

@ -10,6 +10,12 @@ import android.view.View
import android.view.Window import android.view.Window
import android.widget.Toast import android.widget.Toast
import androidx.activity.compose.BackHandler 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.AlertDialog
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
@ -20,6 +26,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.core.animation.doOnEnd 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.NavigatorDisposeBehavior
import cafe.adriel.voyager.navigator.currentOrThrow import cafe.adriel.voyager.navigator.currentOrThrow
import cafe.adriel.voyager.transitions.ScreenTransition import cafe.adriel.voyager.transitions.ScreenTransition
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback
import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.base.BasePreferences
import eu.kanade.domain.category.model.Category import eu.kanade.domain.category.model.Category
import eu.kanade.domain.library.service.LibraryPreferences import eu.kanade.domain.library.service.LibraryPreferences
import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.domain.ui.UiPreferences import eu.kanade.domain.ui.UiPreferences
import eu.kanade.presentation.components.AppStateBanners
import eu.kanade.presentation.util.Transition import eu.kanade.presentation.util.Transition
import eu.kanade.presentation.util.collectAsState import eu.kanade.presentation.util.collectAsState
import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.BuildConfig
@ -142,6 +151,23 @@ class MainActivity : BaseActivity() {
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
setComposeContent { setComposeContent {
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,
)
}
Navigator( Navigator(
screen = HomeScreen, screen = HomeScreen,
disposeBehavior = NavigatorDisposeBehavior(disposeNestedNavigators = false, disposeSteps = true), disposeBehavior = NavigatorDisposeBehavior(disposeNestedNavigators = false, disposeSteps = true),
@ -162,8 +188,16 @@ class MainActivity : BaseActivity() {
} }
} }
// 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 // Shows current screen
ScreenTransition(navigator = navigator, transition = { Transition.OneWayFade }) ScreenTransition(navigator = navigator, transition = { Transition.OneWayFade })
}
// Pop source-related screens when incognito mode is turned off // Pop source-related screens when incognito mode is turned off
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
@ -184,6 +218,7 @@ class MainActivity : BaseActivity() {
CheckForUpdate() CheckForUpdate()
} }
}
var showChangelog by remember { mutableStateOf(didMigration && !BuildConfig.DEBUG) } var showChangelog by remember { mutableStateOf(didMigration && !BuildConfig.DEBUG) }
if (showChangelog) { if (showChangelog) {

View File

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

View File

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

View File

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

View File

@ -24,3 +24,4 @@ accompanist-webview = { module = "com.google.accompanist:accompanist-webview", v
accompanist-flowlayout = { module = "com.google.accompanist:accompanist-flowlayout", 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-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" }