Add scroll overlay to LibraryToolbar (#7669)

Works when category tab is not shown
This commit is contained in:
Ivan Iskandar 2022-08-04 04:41:15 +07:00 committed by GitHub
parent 3d4e56948d
commit afceac15c8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 29 deletions

View file

@ -89,7 +89,7 @@ fun AppBar(
// Menu // Menu
actions: @Composable RowScope.() -> Unit = {}, actions: @Composable RowScope.() -> Unit = {},
// Action mode // Action mode
isActionMode: Boolean, isActionMode: Boolean = false,
onCancelActionMode: () -> Unit = {}, onCancelActionMode: () -> Unit = {},
// Banners // Banners
downloadedOnlyMode: Boolean = false, downloadedOnlyMode: Boolean = false,

View file

@ -1,10 +1,17 @@
package eu.kanade.presentation.library package eu.kanade.presentation.library
import androidx.compose.animation.Crossfade import androidx.compose.animation.Crossfade
import androidx.compose.foundation.layout.safeDrawingPadding import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import eu.kanade.domain.category.model.Category import eu.kanade.domain.category.model.Category
import eu.kanade.presentation.components.LibraryBottomActionMenu import eu.kanade.presentation.components.LibraryBottomActionMenu
import eu.kanade.presentation.components.LoadingScreen import eu.kanade.presentation.components.LoadingScreen
@ -30,21 +37,29 @@ fun LibraryScreen(
onClickFilter: () -> Unit, onClickFilter: () -> Unit,
onClickRefresh: (Category?) -> Unit, onClickRefresh: (Category?) -> Unit,
) { ) {
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
val insets = WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal)
Crossfade(targetState = presenter.isLoading) { state -> Crossfade(targetState = presenter.isLoading) { state ->
when (state) { when (state) {
true -> LoadingScreen() true -> LoadingScreen()
false -> Scaffold( false -> Scaffold(
modifier = Modifier.safeDrawingPadding(), modifier = Modifier
.windowInsetsPadding(insets)
.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar = {
val title by presenter.getToolbarTitle() val title by presenter.getToolbarTitle()
val tabVisible = presenter.tabVisibility && presenter.categories.size > 1
LibraryToolbar( LibraryToolbar(
state = presenter, state = presenter,
title = title, title = title,
incognitoMode = !tabVisible && presenter.isIncognitoMode,
downloadedOnlyMode = !tabVisible && presenter.isDownloadOnly,
onClickUnselectAll = onClickUnselectAll, onClickUnselectAll = onClickUnselectAll,
onClickSelectAll = onClickSelectAll, onClickSelectAll = onClickSelectAll,
onClickInvertSelection = onClickInvertSelection, onClickInvertSelection = onClickInvertSelection,
onClickFilter = onClickFilter, onClickFilter = onClickFilter,
onClickRefresh = { onClickRefresh(null) }, onClickRefresh = { onClickRefresh(null) },
scrollBehavior = scrollBehavior.takeIf { !tabVisible }, // For scroll overlay when no tab
) )
}, },
bottomBar = { bottomBar = {

View file

@ -5,8 +5,6 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.BasicTextField
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.ArrowBack
import androidx.compose.material.icons.outlined.Close
import androidx.compose.material.icons.outlined.FilterList import androidx.compose.material.icons.outlined.FilterList
import androidx.compose.material.icons.outlined.FlipToBack import androidx.compose.material.icons.outlined.FlipToBack
import androidx.compose.material.icons.outlined.Refresh import androidx.compose.material.icons.outlined.Refresh
@ -16,9 +14,9 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SmallTopAppBar
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@ -28,10 +26,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.components.Pill import eu.kanade.presentation.components.Pill
import eu.kanade.presentation.library.LibraryState import eu.kanade.presentation.library.LibraryState
import eu.kanade.presentation.theme.active import eu.kanade.presentation.theme.active
@ -41,29 +39,40 @@ import kotlinx.coroutines.delay
fun LibraryToolbar( fun LibraryToolbar(
state: LibraryState, state: LibraryState,
title: LibraryToolbarTitle, title: LibraryToolbarTitle,
incognitoMode: Boolean,
downloadedOnlyMode: Boolean,
onClickUnselectAll: () -> Unit, onClickUnselectAll: () -> Unit,
onClickSelectAll: () -> Unit, onClickSelectAll: () -> Unit,
onClickInvertSelection: () -> Unit, onClickInvertSelection: () -> Unit,
onClickFilter: () -> Unit, onClickFilter: () -> Unit,
onClickRefresh: () -> Unit, onClickRefresh: () -> Unit,
scrollBehavior: TopAppBarScrollBehavior?,
) = when { ) = when {
state.selectionMode -> LibrarySelectionToolbar( state.selectionMode -> LibrarySelectionToolbar(
state = state, state = state,
incognitoMode = incognitoMode,
downloadedOnlyMode = downloadedOnlyMode,
onClickUnselectAll = onClickUnselectAll, onClickUnselectAll = onClickUnselectAll,
onClickSelectAll = onClickSelectAll, onClickSelectAll = onClickSelectAll,
onClickInvertSelection = onClickInvertSelection, onClickInvertSelection = onClickInvertSelection,
) )
state.searchQuery != null -> LibrarySearchToolbar( state.searchQuery != null -> LibrarySearchToolbar(
searchQuery = state.searchQuery!!, searchQuery = state.searchQuery!!,
incognitoMode = incognitoMode,
downloadedOnlyMode = downloadedOnlyMode,
onChangeSearchQuery = { state.searchQuery = it }, onChangeSearchQuery = { state.searchQuery = it },
onClickCloseSearch = { state.searchQuery = null }, onClickCloseSearch = { state.searchQuery = null },
scrollBehavior = scrollBehavior,
) )
else -> LibraryRegularToolbar( else -> LibraryRegularToolbar(
title = title, title = title,
hasFilters = state.hasActiveFilters, hasFilters = state.hasActiveFilters,
incognitoMode = incognitoMode,
downloadedOnlyMode = downloadedOnlyMode,
onClickSearch = { state.searchQuery = "" }, onClickSearch = { state.searchQuery = "" },
onClickFilter = onClickFilter, onClickFilter = onClickFilter,
onClickRefresh = onClickRefresh, onClickRefresh = onClickRefresh,
scrollBehavior = scrollBehavior,
) )
} }
@ -71,14 +80,17 @@ fun LibraryToolbar(
fun LibraryRegularToolbar( fun LibraryRegularToolbar(
title: LibraryToolbarTitle, title: LibraryToolbarTitle,
hasFilters: Boolean, hasFilters: Boolean,
incognitoMode: Boolean,
downloadedOnlyMode: Boolean,
onClickSearch: () -> Unit, onClickSearch: () -> Unit,
onClickFilter: () -> Unit, onClickFilter: () -> Unit,
onClickRefresh: () -> Unit, onClickRefresh: () -> Unit,
scrollBehavior: TopAppBarScrollBehavior?,
) { ) {
val pillAlpha = if (isSystemInDarkTheme()) 0.12f else 0.08f val pillAlpha = if (isSystemInDarkTheme()) 0.12f else 0.08f
val filterTint = if (hasFilters) MaterialTheme.colorScheme.active else LocalContentColor.current val filterTint = if (hasFilters) MaterialTheme.colorScheme.active else LocalContentColor.current
SmallTopAppBar( AppBar(
title = { titleContent = {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Text( Text(
text = title.text, text = title.text,
@ -106,30 +118,28 @@ fun LibraryRegularToolbar(
Icon(Icons.Outlined.Refresh, contentDescription = "search") Icon(Icons.Outlined.Refresh, contentDescription = "search")
} }
}, },
incognitoMode = incognitoMode,
downloadedOnlyMode = downloadedOnlyMode,
scrollBehavior = scrollBehavior,
) )
} }
@Composable @Composable
fun LibrarySelectionToolbar( fun LibrarySelectionToolbar(
state: LibraryState, state: LibraryState,
incognitoMode: Boolean,
downloadedOnlyMode: Boolean,
onClickUnselectAll: () -> Unit, onClickUnselectAll: () -> Unit,
onClickSelectAll: () -> Unit, onClickSelectAll: () -> Unit,
onClickInvertSelection: () -> Unit, onClickInvertSelection: () -> Unit,
) { ) {
val backgroundColor by TopAppBarDefaults.smallTopAppBarColors().containerColor(1f) val backgroundColor by TopAppBarDefaults.smallTopAppBarColors().containerColor(1f)
SmallTopAppBar( AppBar(
modifier = Modifier modifier = Modifier
.drawBehind { .drawBehind {
drawRect(backgroundColor.copy(alpha = 1f)) drawRect(backgroundColor.copy(alpha = 1f))
}, },
navigationIcon = { titleContent = { Text(text = "${state.selection.size}") },
IconButton(onClick = onClickUnselectAll) {
Icon(Icons.Outlined.Close, contentDescription = "close")
}
},
title = {
Text(text = "${state.selection.size}")
},
actions = { actions = {
IconButton(onClick = onClickSelectAll) { IconButton(onClick = onClickSelectAll) {
Icon(Icons.Outlined.SelectAll, contentDescription = "search") Icon(Icons.Outlined.SelectAll, contentDescription = "search")
@ -138,27 +148,26 @@ fun LibrarySelectionToolbar(
Icon(Icons.Outlined.FlipToBack, contentDescription = "invert") Icon(Icons.Outlined.FlipToBack, contentDescription = "invert")
} }
}, },
colors = TopAppBarDefaults.smallTopAppBarColors( isActionMode = true,
containerColor = Color.Transparent, onCancelActionMode = onClickUnselectAll,
scrolledContainerColor = Color.Transparent, incognitoMode = incognitoMode,
), downloadedOnlyMode = downloadedOnlyMode,
) )
} }
@Composable @Composable
fun LibrarySearchToolbar( fun LibrarySearchToolbar(
searchQuery: String, searchQuery: String,
incognitoMode: Boolean,
downloadedOnlyMode: Boolean,
onChangeSearchQuery: (String) -> Unit, onChangeSearchQuery: (String) -> Unit,
onClickCloseSearch: () -> Unit, onClickCloseSearch: () -> Unit,
scrollBehavior: TopAppBarScrollBehavior?,
) { ) {
val focusRequester = remember { FocusRequester.Default } val focusRequester = remember { FocusRequester.Default }
SmallTopAppBar( AppBar(
navigationIcon = { navigateUp = onClickCloseSearch,
IconButton(onClick = onClickCloseSearch) { titleContent = {
Icon(Icons.Outlined.ArrowBack, contentDescription = "back")
}
},
title = {
BasicTextField( BasicTextField(
value = searchQuery, value = searchQuery,
onValueChange = onChangeSearchQuery, onValueChange = onChangeSearchQuery,
@ -175,6 +184,9 @@ fun LibrarySearchToolbar(
focusRequester.requestFocus() focusRequester.requestFocus()
} }
}, },
incognitoMode = incognitoMode,
downloadedOnlyMode = downloadedOnlyMode,
scrollBehavior = scrollBehavior,
) )
} }