From 3d8e0b5f54f3e4951b1201c5aff33ce4cfb06796 Mon Sep 17 00:00:00 2001 From: acclorite Date: Sat, 3 Aug 2024 12:50:45 +0300 Subject: [PATCH 1/3] Fix: BookInfoTopBar's Container color does not change into Scrolled container color, even when overlapping. --- .../components/AnimatedTopAppBar.kt | 39 +++++++++---------- .../screens/book_info/BookInfoScreen.kt | 10 +---- .../book_info/components/BookInfoTopBar.kt | 10 ++--- 3 files changed, 23 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/components/AnimatedTopAppBar.kt b/app/src/main/java/ua/acclorite/book_story/presentation/components/AnimatedTopAppBar.kt index 87835a8a..70da23f8 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/components/AnimatedTopAppBar.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/components/AnimatedTopAppBar.kt @@ -1,6 +1,6 @@ package ua.acclorite.book_story.presentation.components -import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.FastOutLinearInEasing import androidx.compose.animation.core.Spring import androidx.compose.animation.core.spring import androidx.compose.animation.fadeIn @@ -18,19 +18,20 @@ import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.lerp import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import ua.acclorite.book_story.R /** - * Animated top app bar. Has up to 3 different top bars inside it. Follow [TopAppBar] for more info. + * Animated top app bar. + * Has up to 3 different top bars inside it. Follow [TopAppBar] for more info. * + * @param containerColor Container color of the TopBar. + * @param scrolledContainerColor Scrolled container color of the TopBar. + * @param scrollBehavior [TopAppBarScrollBehavior]. * @param isTopBarScrolled Whether isScrolled state should be forced or not. * @param content1Visibility Whether first top app bar should be shown. * @param content2Visibility Whether second top app bar should be shown. @@ -66,7 +67,7 @@ fun AnimatedTopAppBar( WindowInsets.statusBars.getTop(density).toDp() } - if (containerColor != Color.Transparent) { + if (containerColor.alpha != 0f) { Box( modifier = Modifier .fillMaxWidth() @@ -78,22 +79,18 @@ fun AnimatedTopAppBar( ) } - val scrollableContainerColor by remember(isTopBarScrolled) { - derivedStateOf { - if (isTopBarScrolled == true) { - scrolledContainerColor - } else { - containerColor - } - } + val animatedContainerColor = remember( + containerColor, + scrolledContainerColor, + isTopBarScrolled + ) { + lerp( + containerColor, + scrolledContainerColor, + FastOutLinearInEasing.transform(if (isTopBarScrolled == true) 1f else 0f) + ) } - val animatedContainerColor by animateColorAsState( - targetValue = scrollableContainerColor, - animationSpec = spring(stiffness = Spring.StiffnessMediumLow), - label = stringResource(id = R.string.top_app_bar_anim_content_desc) - ) - CustomAnimatedVisibility( visible = content1Visibility ?: true, enter = fadeIn(spring(stiffness = Spring.StiffnessMediumLow)), diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/book_info/BookInfoScreen.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/book_info/BookInfoScreen.kt index ab021289..ca0792f1 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/book_info/BookInfoScreen.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/book_info/BookInfoScreen.kt @@ -27,7 +27,6 @@ import androidx.compose.material.icons.filled.PlayArrow import androidx.compose.material.pullrefresh.PullRefreshIndicator import androidx.compose.material.pullrefresh.pullRefresh import androidx.compose.material.pullrefresh.rememberPullRefreshState -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.FloatingActionButtonDefaults import androidx.compose.material3.Icon @@ -35,7 +34,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect @@ -44,7 +42,6 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp @@ -109,7 +106,7 @@ fun BookInfoScreenRoot(screen: Screen.BookInfo) { ) } -@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class) +@OptIn(ExperimentalMaterialApi::class) @Composable private fun BookInfoScreen( state: State, @@ -120,7 +117,6 @@ private fun BookInfoScreen( onHistoryEvent: (HistoryEvent) -> Unit ) { val context = LocalContext.current - val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() val listState = rememberLazyListState() val snackbarState = remember { SnackbarHostState() } val refreshState = rememberPullRefreshState( @@ -179,8 +175,7 @@ private fun BookInfoScreen( .fillMaxSize() .imePadding() .windowInsetsPadding(WindowInsets.navigationBars) - .pullRefresh(refreshState) - .nestedScroll(scrollBehavior.nestedScrollConnection), + .pullRefresh(refreshState), containerColor = MaterialTheme.colorScheme.surface, topBar = { BookInfoTopBar( @@ -189,7 +184,6 @@ private fun BookInfoScreen( onLibraryEvent = onLibraryEvent, onHistoryEvent = onHistoryEvent, onNavigate = onNavigate, - scrollBehavior = scrollBehavior, listState = listState, snackbarState = snackbarState ) diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/book_info/components/BookInfoTopBar.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/book_info/components/BookInfoTopBar.kt index 300a531d..bcf394e8 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/book_info/components/BookInfoTopBar.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/book_info/components/BookInfoTopBar.kt @@ -12,13 +12,11 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember -import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.style.TextOverflow import ua.acclorite.book_story.R @@ -42,7 +40,6 @@ import ua.acclorite.book_story.presentation.ui.Transitions * @param onLibraryEvent [LibraryEvent] callback. * @param onHistoryEvent [HistoryEvent] callback. * @param onNavigate Navigator callback. - * @param scrollBehavior [TopAppBarScrollBehavior]. * @param listState [LazyListState]. * @param snackbarState [SnackbarHostState]. */ @@ -54,7 +51,6 @@ fun BookInfoTopBar( onLibraryEvent: (LibraryEvent) -> Unit, onHistoryEvent: (HistoryEvent) -> Unit, onNavigate: OnNavigate, - scrollBehavior: TopAppBarScrollBehavior, listState: LazyListState, snackbarState: SnackbarHostState ) { @@ -62,9 +58,9 @@ fun BookInfoTopBar( val firstVisibleItemIndex by remember { derivedStateOf { listState.firstVisibleItemIndex } } AnimatedTopAppBar( - containerColor = Color.Transparent, - scrollBehavior = scrollBehavior, - isTopBarScrolled = null, + containerColor = MaterialTheme.colorScheme.surface.copy(0f), + scrollBehavior = null, + isTopBarScrolled = listState.canScrollBackward, content1NavigationIcon = { if ( From b1ebe72cc31c6c870eea52a72d2fda1f61641eff Mon Sep 17 00:00:00 2001 From: acclorite Date: Sun, 4 Aug 2024 18:53:28 +0300 Subject: [PATCH 2/3] AnimatedTopAppBar: New custom content option, to also change scrollable color for content below. --- .../components/AnimatedTopAppBar.kt | 152 +++++++++--------- .../library/components/LibraryTabRow.kt | 4 +- .../library/components/LibraryTopBar.kt | 21 ++- 3 files changed, 93 insertions(+), 84 deletions(-) diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/components/AnimatedTopAppBar.kt b/app/src/main/java/ua/acclorite/book_story/presentation/components/AnimatedTopAppBar.kt index 70da23f8..08e54bfe 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/components/AnimatedTopAppBar.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/components/AnimatedTopAppBar.kt @@ -1,16 +1,17 @@ package ua.acclorite.book_story.presentation.components -import androidx.compose.animation.core.FastOutLinearInEasing import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.spring import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.statusBars import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme @@ -18,12 +19,11 @@ import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.lerp -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.unit.dp +import androidx.compose.ui.res.stringResource +import ua.acclorite.book_story.R /** * Animated top app bar. @@ -36,6 +36,7 @@ import androidx.compose.ui.unit.dp * @param content1Visibility Whether first top app bar should be shown. * @param content2Visibility Whether second top app bar should be shown. * @param content3Visibility Whether third top app bar should be shown. + * @param customContent Custom content below [TopAppBar]. */ @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -59,98 +60,93 @@ fun AnimatedTopAppBar( content3Visibility: Boolean? = null, content3NavigationIcon: @Composable () -> Unit = {}, content3Title: @Composable () -> Unit = {}, - content3Actions: @Composable RowScope.() -> Unit = {} + content3Actions: @Composable RowScope.() -> Unit = {}, + + customContent: @Composable ColumnScope.() -> Unit = {} ) { - Box(modifier = Modifier.fillMaxWidth()) { - val density = LocalDensity.current - val statusBarPadding = with(density) { - WindowInsets.statusBars.getTop(density).toDp() - } + val animatedContainerColor = lerp( + containerColor, + scrolledContainerColor, + animateFloatAsState( + if (isTopBarScrolled == true) 1f else 0f, + animationSpec = spring( + stiffness = Spring.StiffnessMediumLow + ), + label = stringResource(id = R.string.top_app_bar_anim_content_desc) + ).value + ) - if (containerColor.alpha != 0f) { - Box( - modifier = Modifier - .fillMaxWidth() - .height(64.dp + statusBarPadding) - .background( - if (isTopBarScrolled == true) scrolledContainerColor - else containerColor - ) - ) - } - - val animatedContainerColor = remember( - containerColor, - scrolledContainerColor, - isTopBarScrolled - ) { - lerp( - containerColor, - scrolledContainerColor, - FastOutLinearInEasing.transform(if (isTopBarScrolled == true) 1f else 0f) - ) - } - - CustomAnimatedVisibility( - visible = content1Visibility ?: true, - enter = fadeIn(spring(stiffness = Spring.StiffnessMediumLow)), - exit = fadeOut(spring(stiffness = Spring.StiffnessMediumLow)) - ) { - TopAppBar( - windowInsets = WindowInsets.statusBars, - navigationIcon = content1NavigationIcon, - title = content1Title, - actions = content1Actions, - scrollBehavior = scrollBehavior, - modifier = Modifier.fillMaxWidth(), - colors = TopAppBarDefaults.topAppBarColors( - containerColor = animatedContainerColor, - scrolledContainerColor = scrolledContainerColor - ) - ) - } - - if (content2Visibility != null) { + Column( + Modifier + .fillMaxWidth() + .background(animatedContainerColor) + ) { + Box(modifier = Modifier.fillMaxWidth()) { CustomAnimatedVisibility( - visible = content2Visibility, + visible = content1Visibility ?: true, enter = fadeIn(spring(stiffness = Spring.StiffnessMediumLow)), exit = fadeOut(spring(stiffness = Spring.StiffnessMediumLow)) ) { TopAppBar( windowInsets = WindowInsets.statusBars, - navigationIcon = content2NavigationIcon, - title = content2Title, - actions = content2Actions, + navigationIcon = content1NavigationIcon, + title = content1Title, + actions = content1Actions, scrollBehavior = scrollBehavior, modifier = Modifier.fillMaxWidth(), colors = TopAppBarDefaults.topAppBarColors( - containerColor = animatedContainerColor, + containerColor = if (isTopBarScrolled != null) Color.Transparent + else containerColor, scrolledContainerColor = scrolledContainerColor ) ) } - } - if (content3Visibility != null) { - CustomAnimatedVisibility( - visible = content3Visibility, - enter = fadeIn(spring(stiffness = Spring.StiffnessMediumLow)), - exit = fadeOut(spring(stiffness = Spring.StiffnessMediumLow)) - ) { - TopAppBar( - windowInsets = WindowInsets.statusBars, - navigationIcon = content3NavigationIcon, - title = content3Title, - actions = content3Actions, - scrollBehavior = scrollBehavior, - modifier = Modifier.fillMaxWidth(), - colors = TopAppBarDefaults.topAppBarColors( - containerColor = animatedContainerColor, - scrolledContainerColor = scrolledContainerColor + if (content2Visibility != null) { + CustomAnimatedVisibility( + visible = content2Visibility, + enter = fadeIn(spring(stiffness = Spring.StiffnessMediumLow)), + exit = fadeOut(spring(stiffness = Spring.StiffnessMediumLow)) + ) { + TopAppBar( + windowInsets = WindowInsets.statusBars, + navigationIcon = content2NavigationIcon, + title = content2Title, + actions = content2Actions, + scrollBehavior = scrollBehavior, + modifier = Modifier.fillMaxWidth(), + colors = TopAppBarDefaults.topAppBarColors( + containerColor = if (isTopBarScrolled != null) Color.Transparent + else containerColor, + scrolledContainerColor = scrolledContainerColor + ) ) - ) + } + } + + if (content3Visibility != null) { + CustomAnimatedVisibility( + visible = content3Visibility, + enter = fadeIn(spring(stiffness = Spring.StiffnessMediumLow)), + exit = fadeOut(spring(stiffness = Spring.StiffnessMediumLow)) + ) { + TopAppBar( + windowInsets = WindowInsets.statusBars, + navigationIcon = content3NavigationIcon, + title = content3Title, + actions = content3Actions, + scrollBehavior = scrollBehavior, + modifier = Modifier.fillMaxWidth(), + colors = TopAppBarDefaults.topAppBarColors( + containerColor = if (isTopBarScrolled != null) Color.Transparent + else containerColor, + scrolledContainerColor = scrolledContainerColor + ) + ) + } } } + customContent() } } diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/library/components/LibraryTabRow.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/library/components/LibraryTabRow.kt index 7671ab3e..886b4793 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/library/components/LibraryTabRow.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/library/components/LibraryTabRow.kt @@ -33,12 +33,14 @@ import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent * Tab row, either scrollable or static, depends on screen width. * * @param onEvent Event used to Scroll to Page. + * @param itemCountBackgroundColor Item count background color. * @param books The list of all books. * @param pagerState [PagerState]. */ @Composable fun LibraryTabRow( onEvent: (LibraryEvent) -> Unit, + itemCountBackgroundColor: Color, books: List, pagerState: PagerState ) { @@ -113,7 +115,7 @@ fun LibraryTabRow( text = tabItem.second.toString(), modifier = Modifier .background( - MaterialTheme.colorScheme.surfaceContainer, + itemCountBackgroundColor, MaterialTheme.shapes.medium ) .padding(horizontal = 8.dp, vertical = 4.dp), diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/library/components/LibraryTopBar.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/library/components/LibraryTopBar.kt index 5251e7c5..dd0113e9 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/library/components/LibraryTopBar.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/library/components/LibraryTopBar.kt @@ -1,5 +1,8 @@ package ua.acclorite.book_story.presentation.screens.library.components +import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.spring import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -168,12 +171,20 @@ fun LibraryTopBar( }, content3Actions = { MoreDropDown() + }, + customContent = { + LibraryTabRow( + onEvent = onEvent, + books = state.value.categorizedBooks, + itemCountBackgroundColor = animateColorAsState( + if (state.value.hasSelectedItems) MaterialTheme.colorScheme.surfaceContainerHighest + else MaterialTheme.colorScheme.surfaceContainer, + animationSpec = spring(stiffness = Spring.StiffnessMediumLow), + label = stringResource(id = R.string.top_app_bar_anim_content_desc) + ).value, + pagerState = pagerState + ) } ) - LibraryTabRow( - onEvent = onEvent, - books = state.value.categorizedBooks, - pagerState = pagerState - ) } } \ No newline at end of file From 8100902cbace18216906f1e64df0e89d51da5f95 Mon Sep 17 00:00:00 2001 From: acclorite Date: Sun, 4 Aug 2024 19:11:31 +0300 Subject: [PATCH 3/3] Removed unused Column(LibraryTopBar) --- .../library/components/LibraryTopBar.kt | 248 +++++++++--------- 1 file changed, 122 insertions(+), 126 deletions(-) diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/library/components/LibraryTopBar.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/library/components/LibraryTopBar.kt index dd0113e9..3067a3b2 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/library/components/LibraryTopBar.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/library/components/LibraryTopBar.kt @@ -4,10 +4,8 @@ import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.Spring import androidx.compose.animation.core.spring import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.pager.PagerState @@ -58,133 +56,131 @@ fun LibraryTopBar( ) { val focusRequester = remember { FocusRequester() } - Column(Modifier.fillMaxWidth()) { - AnimatedTopAppBar( - scrollBehavior = null, - isTopBarScrolled = state.value.hasSelectedItems, + AnimatedTopAppBar( + scrollBehavior = null, + isTopBarScrolled = state.value.hasSelectedItems, - content1Visibility = !state.value.hasSelectedItems && !state.value.showSearch, - content1NavigationIcon = {}, - content1Title = { - Row(verticalAlignment = Alignment.CenterVertically) { - Text(stringResource(id = R.string.library_screen)) - Spacer(modifier = Modifier.width(6.dp)) - Text( - text = state.value.books.size.toString(), - modifier = Modifier - .background( - MaterialTheme.colorScheme.surfaceContainer, - RoundedCornerShape(14.dp) - ) - .padding(horizontal = 8.dp, vertical = 3.dp), - color = MaterialTheme.colorScheme.onSurfaceVariant, - fontSize = 16.sp - ) - } - }, - content1Actions = { - CustomIconButton( - icon = Icons.Default.Search, - contentDescription = R.string.search_content_desc, - disableOnClick = true, - ) { - onEvent(LibraryEvent.OnSearchShowHide) - } - MoreDropDown() - }, - - content2Visibility = state.value.hasSelectedItems, - content2NavigationIcon = { - CustomIconButton( - icon = Icons.Default.Clear, - contentDescription = R.string.clear_selected_items_content_desc, - disableOnClick = true - ) { - onEvent(LibraryEvent.OnClearSelectedBooks) - } - }, - content2Title = { + content1Visibility = !state.value.hasSelectedItems && !state.value.showSearch, + content1NavigationIcon = {}, + content1Title = { + Row(verticalAlignment = Alignment.CenterVertically) { + Text(stringResource(id = R.string.library_screen)) + Spacer(modifier = Modifier.width(6.dp)) Text( - stringResource( - id = R.string.selected_items_count_query, - state.value.selectedItemsCount.coerceAtLeast(1) - ), - overflow = TextOverflow.Ellipsis, - maxLines = 1 - ) - }, - content2Actions = { - CustomIconButton( - icon = Icons.AutoMirrored.Outlined.DriveFileMove, - contentDescription = R.string.move_books_content_desc, - enabled = !state.value.isLoading - && !state.value.isRefreshing - && !state.value.showMoveDialog, - disableOnClick = false, - - ) { - onEvent(LibraryEvent.OnShowHideMoveDialog) - } - CustomIconButton( - icon = Icons.Outlined.Delete, - contentDescription = R.string.delete_books_content_desc, - enabled = !state.value.isLoading - && !state.value.isRefreshing - && !state.value.showDeleteDialog, - disableOnClick = false - ) { - onEvent(LibraryEvent.OnShowHideDeleteDialog) - } - }, - - content3Visibility = state.value.showSearch && !state.value.hasSelectedItems, - content3NavigationIcon = { - CustomIconButton( - icon = Icons.AutoMirrored.Default.ArrowBack, - contentDescription = R.string.exit_search_content_desc, - disableOnClick = true - ) { - onEvent( - LibraryEvent.OnSearchShowHide - ) - } - }, - content3Title = { - CustomSearchTextField( + text = state.value.books.size.toString(), 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) - ) - ) - }, - content3Actions = { - MoreDropDown() - }, - customContent = { - LibraryTabRow( - onEvent = onEvent, - books = state.value.categorizedBooks, - itemCountBackgroundColor = animateColorAsState( - if (state.value.hasSelectedItems) MaterialTheme.colorScheme.surfaceContainerHighest - else MaterialTheme.colorScheme.surfaceContainer, - animationSpec = spring(stiffness = Spring.StiffnessMediumLow), - label = stringResource(id = R.string.top_app_bar_anim_content_desc) - ).value, - pagerState = pagerState + .background( + MaterialTheme.colorScheme.surfaceContainer, + RoundedCornerShape(14.dp) + ) + .padding(horizontal = 8.dp, vertical = 3.dp), + color = MaterialTheme.colorScheme.onSurfaceVariant, + fontSize = 16.sp ) } - ) - } + }, + content1Actions = { + CustomIconButton( + icon = Icons.Default.Search, + contentDescription = R.string.search_content_desc, + disableOnClick = true, + ) { + onEvent(LibraryEvent.OnSearchShowHide) + } + MoreDropDown() + }, + + content2Visibility = state.value.hasSelectedItems, + content2NavigationIcon = { + CustomIconButton( + icon = Icons.Default.Clear, + contentDescription = R.string.clear_selected_items_content_desc, + disableOnClick = true + ) { + onEvent(LibraryEvent.OnClearSelectedBooks) + } + }, + content2Title = { + Text( + stringResource( + id = R.string.selected_items_count_query, + state.value.selectedItemsCount.coerceAtLeast(1) + ), + overflow = TextOverflow.Ellipsis, + maxLines = 1 + ) + }, + content2Actions = { + CustomIconButton( + icon = Icons.AutoMirrored.Outlined.DriveFileMove, + contentDescription = R.string.move_books_content_desc, + enabled = !state.value.isLoading + && !state.value.isRefreshing + && !state.value.showMoveDialog, + disableOnClick = false, + + ) { + onEvent(LibraryEvent.OnShowHideMoveDialog) + } + CustomIconButton( + icon = Icons.Outlined.Delete, + contentDescription = R.string.delete_books_content_desc, + enabled = !state.value.isLoading + && !state.value.isRefreshing + && !state.value.showDeleteDialog, + disableOnClick = false + ) { + onEvent(LibraryEvent.OnShowHideDeleteDialog) + } + }, + + content3Visibility = state.value.showSearch && !state.value.hasSelectedItems, + content3NavigationIcon = { + CustomIconButton( + icon = Icons.AutoMirrored.Default.ArrowBack, + contentDescription = R.string.exit_search_content_desc, + disableOnClick = true + ) { + onEvent( + LibraryEvent.OnSearchShowHide + ) + } + }, + content3Title = { + 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) + ) + ) + }, + content3Actions = { + MoreDropDown() + }, + customContent = { + LibraryTabRow( + onEvent = onEvent, + books = state.value.categorizedBooks, + itemCountBackgroundColor = animateColorAsState( + if (state.value.hasSelectedItems) MaterialTheme.colorScheme.surfaceContainerHighest + else MaterialTheme.colorScheme.surfaceContainer, + animationSpec = spring(stiffness = Spring.StiffnessMediumLow), + label = stringResource(id = R.string.top_app_bar_anim_content_desc) + ).value, + pagerState = pagerState + ) + } + ) } \ No newline at end of file