🛠️ Improve AnimatedTopAppBar
* Corrected shown state of the top bar (always one at a time)
This commit is contained in:
parent
e04bb0aca7
commit
4e5b5bcb26
5 changed files with 111 additions and 94 deletions
|
|
@ -22,9 +22,10 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.lerp
|
import androidx.compose.ui.graphics.lerp
|
||||||
|
import ua.acclorite.book_story.domain.util.ID
|
||||||
|
|
||||||
data class AnimatedTopAppBarData(
|
data class AnimatedTopAppBarData(
|
||||||
val contentVisibility: Boolean? = null,
|
val contentID: ID,
|
||||||
val contentNavigationIcon: @Composable () -> Unit,
|
val contentNavigationIcon: @Composable () -> Unit,
|
||||||
val contentTitle: @Composable () -> Unit,
|
val contentTitle: @Composable () -> Unit,
|
||||||
val contentActions: @Composable RowScope.() -> Unit
|
val contentActions: @Composable RowScope.() -> Unit
|
||||||
|
|
@ -38,7 +39,8 @@ data class AnimatedTopAppBarData(
|
||||||
* @param scrolledContainerColor Scrolled container color of the TopBar.
|
* @param scrolledContainerColor Scrolled container color of the TopBar.
|
||||||
* @param scrollBehavior [TopAppBarScrollBehavior].
|
* @param scrollBehavior [TopAppBarScrollBehavior].
|
||||||
* @param isTopBarScrolled Whether isScrolled state should be forced or not.
|
* @param isTopBarScrolled Whether isScrolled state should be forced or not.
|
||||||
* @param animatedTopBars Pass a list of all [AnimatedTopAppBarData] to show.
|
* @param shownTopBar [ID] of the top bar to show.
|
||||||
|
* @param topBars Pass a list of all [AnimatedTopAppBarData] to show.
|
||||||
* @param customContent Custom content below [TopAppBar].
|
* @param customContent Custom content below [TopAppBar].
|
||||||
*/
|
*/
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
|
@ -50,7 +52,8 @@ fun AnimatedTopAppBar(
|
||||||
scrollBehavior: TopAppBarScrollBehavior?,
|
scrollBehavior: TopAppBarScrollBehavior?,
|
||||||
isTopBarScrolled: Boolean?,
|
isTopBarScrolled: Boolean?,
|
||||||
|
|
||||||
animatedTopBars: List<AnimatedTopAppBarData>,
|
shownTopBar: ID,
|
||||||
|
topBars: List<AnimatedTopAppBarData>,
|
||||||
customContent: @Composable ColumnScope.() -> Unit = {}
|
customContent: @Composable ColumnScope.() -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val animatedContainerColor = lerp(
|
val animatedContainerColor = lerp(
|
||||||
|
|
@ -70,9 +73,9 @@ fun AnimatedTopAppBar(
|
||||||
.background(animatedContainerColor)
|
.background(animatedContainerColor)
|
||||||
) {
|
) {
|
||||||
Box(modifier = Modifier.fillMaxWidth()) {
|
Box(modifier = Modifier.fillMaxWidth()) {
|
||||||
animatedTopBars.forEach { data ->
|
topBars.forEach { data ->
|
||||||
CustomAnimatedVisibility(
|
CustomAnimatedVisibility(
|
||||||
visible = data.contentVisibility == true,
|
visible = data.contentID == shownTopBar,
|
||||||
enter = fadeIn(spring(stiffness = Spring.StiffnessMediumLow)),
|
enter = fadeIn(spring(stiffness = Spring.StiffnessMediumLow)),
|
||||||
exit = fadeOut(spring(stiffness = Spring.StiffnessMediumLow))
|
exit = fadeOut(spring(stiffness = Spring.StiffnessMediumLow))
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -60,9 +60,10 @@ fun BookInfoTopBar(
|
||||||
scrollBehavior = null,
|
scrollBehavior = null,
|
||||||
isTopBarScrolled = listState.canScrollBackward,
|
isTopBarScrolled = listState.canScrollBackward,
|
||||||
|
|
||||||
animatedTopBars = listOf(
|
shownTopBar = 0,
|
||||||
|
topBars = listOf(
|
||||||
AnimatedTopAppBarData(
|
AnimatedTopAppBarData(
|
||||||
contentVisibility = true,
|
contentID = 0,
|
||||||
contentNavigationIcon = {
|
contentNavigationIcon = {
|
||||||
if (
|
if (
|
||||||
state.value.editTitle ||
|
state.value.editTitle ||
|
||||||
|
|
|
||||||
|
|
@ -78,13 +78,17 @@ fun BrowseTopBar(filteredFiles: List<SelectableFile>) {
|
||||||
|
|
||||||
AnimatedTopAppBar(
|
AnimatedTopAppBar(
|
||||||
scrollBehavior = null,
|
scrollBehavior = null,
|
||||||
isTopBarScrolled = isScrolled.value || inNestedDirectory.value,
|
isTopBarScrolled = isScrolled.value || state.value.hasSelectedItems,
|
||||||
|
|
||||||
animatedTopBars = listOf(
|
shownTopBar = when {
|
||||||
|
state.value.hasSelectedItems -> 3
|
||||||
|
state.value.showSearch -> 2
|
||||||
|
state.value.inNestedDirectory -> 1
|
||||||
|
else -> 0
|
||||||
|
},
|
||||||
|
topBars = listOf(
|
||||||
AnimatedTopAppBarData(
|
AnimatedTopAppBarData(
|
||||||
contentVisibility = !state.value.hasSelectedItems &&
|
contentID = 0,
|
||||||
!state.value.showSearch &&
|
|
||||||
!inNestedDirectory.value,
|
|
||||||
contentNavigationIcon = {},
|
contentNavigationIcon = {},
|
||||||
contentTitle = {
|
contentTitle = {
|
||||||
Text(
|
Text(
|
||||||
|
|
@ -120,7 +124,7 @@ fun BrowseTopBar(filteredFiles: List<SelectableFile>) {
|
||||||
),
|
),
|
||||||
|
|
||||||
AnimatedTopAppBarData(
|
AnimatedTopAppBarData(
|
||||||
contentVisibility = inNestedDirectory.value,
|
contentID = 1,
|
||||||
contentNavigationIcon = {
|
contentNavigationIcon = {
|
||||||
CustomIconButton(
|
CustomIconButton(
|
||||||
icon = Icons.AutoMirrored.Default.ArrowBack,
|
icon = Icons.AutoMirrored.Default.ArrowBack,
|
||||||
|
|
@ -165,7 +169,43 @@ fun BrowseTopBar(filteredFiles: List<SelectableFile>) {
|
||||||
),
|
),
|
||||||
|
|
||||||
AnimatedTopAppBarData(
|
AnimatedTopAppBarData(
|
||||||
contentVisibility = state.value.hasSelectedItems,
|
contentID = 2,
|
||||||
|
contentNavigationIcon = {
|
||||||
|
CustomIconButton(
|
||||||
|
icon = Icons.AutoMirrored.Default.ArrowBack,
|
||||||
|
contentDescription = R.string.exit_search_content_desc,
|
||||||
|
disableOnClick = true
|
||||||
|
) {
|
||||||
|
onEvent(BrowseEvent.OnSearchShowHide)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
contentTitle = {
|
||||||
|
CustomSearchTextField(
|
||||||
|
modifier = Modifier
|
||||||
|
.focusRequester(focusRequester)
|
||||||
|
.onGloballyPositioned {
|
||||||
|
onEvent(BrowseEvent.OnRequestFocus(focusRequester))
|
||||||
|
},
|
||||||
|
query = state.value.searchQuery,
|
||||||
|
onQueryChange = {
|
||||||
|
onEvent(BrowseEvent.OnSearchQueryChange(it))
|
||||||
|
},
|
||||||
|
onSearch = {
|
||||||
|
onEvent(BrowseEvent.OnSearch)
|
||||||
|
},
|
||||||
|
placeholder = stringResource(
|
||||||
|
id = R.string.search_query,
|
||||||
|
stringResource(id = R.string.files)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
contentActions = {
|
||||||
|
MoreDropDown()
|
||||||
|
}
|
||||||
|
),
|
||||||
|
|
||||||
|
AnimatedTopAppBarData(
|
||||||
|
contentID = 3,
|
||||||
contentNavigationIcon = {
|
contentNavigationIcon = {
|
||||||
CustomIconButton(
|
CustomIconButton(
|
||||||
icon = Icons.Default.Clear,
|
icon = Icons.Default.Clear,
|
||||||
|
|
@ -207,42 +247,6 @@ fun BrowseTopBar(filteredFiles: List<SelectableFile>) {
|
||||||
onEvent(BrowseEvent.OnAddingDialogRequest)
|
onEvent(BrowseEvent.OnAddingDialogRequest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
),
|
|
||||||
|
|
||||||
AnimatedTopAppBarData(
|
|
||||||
contentVisibility = state.value.showSearch && !state.value.hasSelectedItems,
|
|
||||||
contentNavigationIcon = {
|
|
||||||
CustomIconButton(
|
|
||||||
icon = Icons.AutoMirrored.Default.ArrowBack,
|
|
||||||
contentDescription = R.string.exit_search_content_desc,
|
|
||||||
disableOnClick = true
|
|
||||||
) {
|
|
||||||
onEvent(BrowseEvent.OnSearchShowHide)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
contentTitle = {
|
|
||||||
CustomSearchTextField(
|
|
||||||
modifier = Modifier
|
|
||||||
.focusRequester(focusRequester)
|
|
||||||
.onGloballyPositioned {
|
|
||||||
onEvent(BrowseEvent.OnRequestFocus(focusRequester))
|
|
||||||
},
|
|
||||||
query = state.value.searchQuery,
|
|
||||||
onQueryChange = {
|
|
||||||
onEvent(BrowseEvent.OnSearchQueryChange(it))
|
|
||||||
},
|
|
||||||
onSearch = {
|
|
||||||
onEvent(BrowseEvent.OnSearch)
|
|
||||||
},
|
|
||||||
placeholder = stringResource(
|
|
||||||
id = R.string.search_query,
|
|
||||||
stringResource(id = R.string.files)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
contentActions = {
|
|
||||||
MoreDropDown()
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
customContent = {
|
customContent = {
|
||||||
|
|
|
||||||
|
|
@ -102,9 +102,13 @@ private fun HistoryScreen() {
|
||||||
scrollBehavior = null,
|
scrollBehavior = null,
|
||||||
isTopBarScrolled = state.value.listState.canScrollBackward,
|
isTopBarScrolled = state.value.listState.canScrollBackward,
|
||||||
|
|
||||||
animatedTopBars = listOf(
|
shownTopBar = when {
|
||||||
|
state.value.showSearch -> 1
|
||||||
|
else -> 0
|
||||||
|
},
|
||||||
|
topBars = listOf(
|
||||||
AnimatedTopAppBarData(
|
AnimatedTopAppBarData(
|
||||||
contentVisibility = !state.value.showSearch,
|
contentID = 0,
|
||||||
contentNavigationIcon = {},
|
contentNavigationIcon = {},
|
||||||
contentTitle = {
|
contentTitle = {
|
||||||
Text(stringResource(id = R.string.history_screen))
|
Text(stringResource(id = R.string.history_screen))
|
||||||
|
|
@ -133,7 +137,7 @@ private fun HistoryScreen() {
|
||||||
),
|
),
|
||||||
|
|
||||||
AnimatedTopAppBarData(
|
AnimatedTopAppBarData(
|
||||||
contentVisibility = state.value.showSearch,
|
contentID = 1,
|
||||||
contentNavigationIcon = {
|
contentNavigationIcon = {
|
||||||
CustomIconButton(
|
CustomIconButton(
|
||||||
icon = Icons.AutoMirrored.Default.ArrowBack,
|
icon = Icons.AutoMirrored.Default.ArrowBack,
|
||||||
|
|
|
||||||
|
|
@ -56,9 +56,14 @@ fun LibraryTopBar(pagerState: PagerState) {
|
||||||
scrollBehavior = null,
|
scrollBehavior = null,
|
||||||
isTopBarScrolled = state.value.hasSelectedItems,
|
isTopBarScrolled = state.value.hasSelectedItems,
|
||||||
|
|
||||||
animatedTopBars = listOf(
|
shownTopBar = when {
|
||||||
|
state.value.hasSelectedItems -> 2
|
||||||
|
state.value.showSearch -> 1
|
||||||
|
else -> 0
|
||||||
|
},
|
||||||
|
topBars = listOf(
|
||||||
AnimatedTopAppBarData(
|
AnimatedTopAppBarData(
|
||||||
contentVisibility = !state.value.hasSelectedItems && !state.value.showSearch,
|
contentID = 0,
|
||||||
contentNavigationIcon = {},
|
contentNavigationIcon = {},
|
||||||
contentTitle = {
|
contentTitle = {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
|
@ -90,7 +95,45 @@ fun LibraryTopBar(pagerState: PagerState) {
|
||||||
),
|
),
|
||||||
|
|
||||||
AnimatedTopAppBarData(
|
AnimatedTopAppBarData(
|
||||||
contentVisibility = state.value.hasSelectedItems,
|
contentID = 1,
|
||||||
|
contentNavigationIcon = {
|
||||||
|
CustomIconButton(
|
||||||
|
icon = Icons.AutoMirrored.Default.ArrowBack,
|
||||||
|
contentDescription = R.string.exit_search_content_desc,
|
||||||
|
disableOnClick = true
|
||||||
|
) {
|
||||||
|
onEvent(
|
||||||
|
LibraryEvent.OnSearchShowHide
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
contentTitle = {
|
||||||
|
CustomSearchTextField(
|
||||||
|
modifier = Modifier
|
||||||
|
.focusRequester(focusRequester)
|
||||||
|
.onGloballyPositioned {
|
||||||
|
onEvent(LibraryEvent.OnRequestFocus(focusRequester))
|
||||||
|
},
|
||||||
|
query = state.value.searchQuery,
|
||||||
|
onQueryChange = {
|
||||||
|
onEvent(LibraryEvent.OnSearchQueryChange(it))
|
||||||
|
},
|
||||||
|
onSearch = {
|
||||||
|
onEvent(LibraryEvent.OnSearch)
|
||||||
|
},
|
||||||
|
placeholder = stringResource(
|
||||||
|
id = R.string.search_query,
|
||||||
|
stringResource(id = R.string.books)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
contentActions = {
|
||||||
|
MoreDropDown()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
AnimatedTopAppBarData(
|
||||||
|
contentID = 2,
|
||||||
contentNavigationIcon = {
|
contentNavigationIcon = {
|
||||||
CustomIconButton(
|
CustomIconButton(
|
||||||
icon = Icons.Default.Clear,
|
icon = Icons.Default.Clear,
|
||||||
|
|
@ -134,44 +177,6 @@ fun LibraryTopBar(pagerState: PagerState) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|
||||||
AnimatedTopAppBarData(
|
|
||||||
contentVisibility = state.value.showSearch && !state.value.hasSelectedItems,
|
|
||||||
contentNavigationIcon = {
|
|
||||||
CustomIconButton(
|
|
||||||
icon = Icons.AutoMirrored.Default.ArrowBack,
|
|
||||||
contentDescription = R.string.exit_search_content_desc,
|
|
||||||
disableOnClick = true
|
|
||||||
) {
|
|
||||||
onEvent(
|
|
||||||
LibraryEvent.OnSearchShowHide
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
contentTitle = {
|
|
||||||
CustomSearchTextField(
|
|
||||||
modifier = Modifier
|
|
||||||
.focusRequester(focusRequester)
|
|
||||||
.onGloballyPositioned {
|
|
||||||
onEvent(LibraryEvent.OnRequestFocus(focusRequester))
|
|
||||||
},
|
|
||||||
query = state.value.searchQuery,
|
|
||||||
onQueryChange = {
|
|
||||||
onEvent(LibraryEvent.OnSearchQueryChange(it))
|
|
||||||
},
|
|
||||||
onSearch = {
|
|
||||||
onEvent(LibraryEvent.OnSearch)
|
|
||||||
},
|
|
||||||
placeholder = stringResource(
|
|
||||||
id = R.string.search_query,
|
|
||||||
stringResource(id = R.string.books)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
contentActions = {
|
|
||||||
MoreDropDown()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
customContent = {
|
customContent = {
|
||||||
LibraryTabRow(
|
LibraryTabRow(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue