Collapsable top bar for SecondScreen.kt

This commit is contained in:
Sad Ellie 2022-05-28 23:46:56 +03:00
parent 90780d66ef
commit a37babb63d
2 changed files with 186 additions and 171 deletions

View File

@ -1,15 +1,17 @@
package com.sadellie.unitto.screens.second package com.sadellie.unitto.screens.second
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.Scaffold
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.sadellie.unitto.R import com.sadellie.unitto.R
import com.sadellie.unitto.data.units.ALL_UNIT_GROUPS import com.sadellie.unitto.data.units.ALL_UNIT_GROUPS
@ -38,12 +40,15 @@ fun SecondScreen(
val chipsRowLazyListState = rememberLazyListState() val chipsRowLazyListState = rememberLazyListState()
val currentUnit = if (leftSide) viewModel.unitFrom else viewModel.unitTo val currentUnit = if (leftSide) viewModel.unitFrom else viewModel.unitTo
var chosenUnitGroup: UnitGroup? by rememberSaveable { mutableStateOf(currentUnit.group) } var chosenUnitGroup: UnitGroup? by rememberSaveable { mutableStateOf(currentUnit.group) }
val scrollBehavior: TopAppBarScrollBehavior = remember {
TopAppBarDefaults.enterAlwaysScrollBehavior()
}
Column { Scaffold(
SearchBar(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .nestedScroll(scrollBehavior.nestedScrollConnection),
.padding(8.dp), topBar = {
SearchBar(
title = stringResource(id = if (leftSide) R.string.units_screen_from else R.string.units_screen_to), title = stringResource(id = if (leftSide) R.string.units_screen_from else R.string.units_screen_to),
value = searchQuery, value = searchQuery,
onValueChange = { onValueChange = {
@ -56,9 +61,12 @@ fun SecondScreen(
viewModel.loadUnitsToShow(searchQuery, chosenUnitGroup, leftSide) viewModel.loadUnitsToShow(searchQuery, chosenUnitGroup, leftSide)
}, },
navigateUpAction = navigateUp, navigateUpAction = navigateUp,
focusManager = focusManager focusManager = focusManager,
scrollBehavior = scrollBehavior
) )
}
) { paddingValues ->
Column(modifier = Modifier.padding(paddingValues)) {
if (leftSide) { if (leftSide) {
ChipsRow( ChipsRow(
lazyListState = chipsRowLazyListState, lazyListState = chipsRowLazyListState,
@ -86,6 +94,7 @@ fun SecondScreen(
) )
} }
} }
}
// This block is called only once on initial composition // This block is called only once on initial composition
LaunchedEffect(Unit) { LaunchedEffect(Unit) {

View File

@ -8,15 +8,12 @@ import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.FavoriteBorder import androidx.compose.material.icons.filled.FavoriteBorder
import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.outlined.ArrowBack
import androidx.compose.material.icons.outlined.Clear import androidx.compose.material.icons.outlined.Clear
import androidx.compose.material3.Icon import androidx.compose.material3.*
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -33,7 +30,6 @@ import com.sadellie.unitto.R
/** /**
* Search bar on the Second screen. Controls what will be shown in the list above this component * Search bar on the Second screen. Controls what will be shown in the list above this component
* *
* @param modifier Modifier to be applied to the Row that contains search bar elements
* @param title Search bar title * @param title Search bar title
* @param value Current query * @param value Current query
* @param onValueChange Action to perform when search query changes * @param onValueChange Action to perform when search query changes
@ -41,35 +37,43 @@ import com.sadellie.unitto.R
* @param favoriteAction Function to toggle favorite filter * @param favoriteAction Function to toggle favorite filter
* @param navigateUpAction Function to navigate to previous screen * @param navigateUpAction Function to navigate to previous screen
* @param focusManager Used to hide keyboard when leaving unit selection screen * @param focusManager Used to hide keyboard when leaving unit selection screen
* @param scrollBehavior [TopAppBarScrollBehavior] that is used for collapsing and container color
*/ */
@Composable @Composable
fun SearchBar( fun SearchBar(
modifier: Modifier = Modifier,
title: String = String(), title: String = String(),
value: String = String(), value: String = String(),
onValueChange: (String) -> Unit = {}, onValueChange: (String) -> Unit = {},
favoritesOnly: Boolean, favoritesOnly: Boolean,
favoriteAction: () -> Unit, favoriteAction: () -> Unit,
navigateUpAction: () -> Unit = {}, navigateUpAction: () -> Unit = {},
focusManager: FocusManager focusManager: FocusManager,
scrollBehavior: TopAppBarScrollBehavior
) { ) {
var showSearch by rememberSaveable { mutableStateOf(false) } var showSearch by rememberSaveable { mutableStateOf(false) }
val focusRequester = remember { FocusRequester() } val focusRequester = remember { FocusRequester() }
fun stagedNavigateUp() {
if (showSearch) {
// Search text field is open, need to close it and clear search query
onValueChange("")
focusManager.clearFocus()
showSearch = false
} else {
// No search text field is shown, can go back as usual
navigateUpAction()
}
}
SmallTopAppBar(
title = {
Crossfade(targetState = showSearch) { textFieldShown -> Crossfade(targetState = showSearch) { textFieldShown ->
Row( Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
when (textFieldShown) { when (textFieldShown) {
// No search text field // No search text field
false -> { false -> {
IconButton(onClick = navigateUpAction) {
Icon(
Icons.Default.ArrowBack,
contentDescription = stringResource(id = R.string.navigate_up_description)
)
}
Text( Text(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -77,43 +81,9 @@ fun SearchBar(
text = title, text = title,
style = MaterialTheme.typography.titleLarge style = MaterialTheme.typography.titleLarge
) )
// Search button
IconButton(onClick = { onValueChange(""); showSearch = true }) {
Icon(
Icons.Default.Search,
contentDescription = stringResource(id = R.string.search_button_description)
)
}
// Favorites button
IconButton(onClick = favoriteAction) {
AnimatedContent(
targetState = favoritesOnly,
transitionSpec = {
(scaleIn() with scaleOut()).using(SizeTransform(clip = false))
}
) {
Icon(
if (favoritesOnly) Icons.Filled.Favorite else Icons.Filled.FavoriteBorder,
contentDescription = stringResource(id = R.string.favorite_button_description)
)
}
}
} }
// With text field // With text field
true -> { true -> {
IconButton(
onClick = {
// Resetting query
onValueChange("")
focusManager.clearFocus()
showSearch = false
}
) {
Icon(
Icons.Default.ArrowBack,
contentDescription = stringResource(id = R.string.navigate_up_description)
)
}
BasicTextField( BasicTextField(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -149,31 +119,67 @@ fun SearchBar(
} }
} }
) )
// Clear button
IconButton(
modifier = Modifier.alpha(if (value != String()) 1f else 0f),
onClick = { onValueChange("") }
) {
Icon(
Icons.Outlined.Clear,
contentDescription = stringResource(id = R.string.clear_input_description)
)
}
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
focusRequester.requestFocus() focusRequester.requestFocus()
} }
} }
} }
} }
BackHandler { }
if (textFieldShown) { },
// Search text field is open, need to close it and clear search query actions = {
onValueChange("") Crossfade(targetState = showSearch) {
showSearch = false Row(
} else { verticalAlignment = Alignment.CenterVertically
// No MyTextField shown, can go back as usual ) {
navigateUpAction() when (it) {
false -> {
// Search button
IconButton(onClick = { onValueChange(""); showSearch = true }) {
Icon(
Icons.Default.Search,
contentDescription = stringResource(id = R.string.search_button_description)
)
}
// Favorites button
IconButton(onClick = favoriteAction) {
AnimatedContent(
targetState = favoritesOnly,
transitionSpec = {
(scaleIn() with scaleOut()).using(SizeTransform(clip = false))
}
) {
Icon(
if (favoritesOnly) Icons.Filled.Favorite else Icons.Filled.FavoriteBorder,
contentDescription = stringResource(id = R.string.favorite_button_description)
)
}
}
}
true -> {
// Clear button
IconButton(onClick = { onValueChange("") }) {
Icon(
modifier = Modifier.alpha(if (value.isBlank()) 0f else 1f),
imageVector = Icons.Outlined.Clear,
contentDescription = stringResource(id = R.string.clear_input_description)
)
} }
} }
} }
} }
}
},
navigationIcon = {
IconButton(onClick = { stagedNavigateUp() }) {
Icon(
Icons.Outlined.ArrowBack,
contentDescription = stringResource(id = R.string.navigate_up_description)
)
}
},
scrollBehavior = scrollBehavior
)
BackHandler { stagedNavigateUp() }
}