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
24 changed files with 217 additions and 295 deletions

View File

@@ -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) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 { 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,
)
}"
}
}
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 {
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 {
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 {
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,
)
}
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) },
)
}
}
}

View File

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