mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-19 00:35:26 +02:00
Update search UX/UI
This commit is contained in:
parent
6ab8477701
commit
7c53768c01
@ -20,44 +20,60 @@ package com.sadellie.unitto.core.ui.common
|
|||||||
|
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.Crossfade
|
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.animation.fadeOut
|
import androidx.compose.animation.fadeOut
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.RowScope
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.requiredHeight
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.statusBarsPadding
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.text.BasicTextField
|
import androidx.compose.foundation.text.BasicTextField
|
||||||
import androidx.compose.foundation.text.KeyboardActionScope
|
import androidx.compose.foundation.text.KeyboardActionScope
|
||||||
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.automirrored.outlined.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.Search
|
import androidx.compose.material.icons.filled.Search
|
||||||
import androidx.compose.material.icons.outlined.Clear
|
import androidx.compose.material.icons.outlined.Clear
|
||||||
|
import androidx.compose.material.ripple.rememberRipple
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
|
||||||
import androidx.compose.material3.TopAppBarColors
|
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||||
|
import androidx.compose.material3.surfaceColorAtElevation
|
||||||
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.SideEffect
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.focus.FocusManager
|
||||||
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.SolidColor
|
import androidx.compose.ui.graphics.SolidColor
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.semantics.Role
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.text.input.TextFieldValue
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.IntOffset
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import com.sadellie.unitto.core.base.R
|
import com.sadellie.unitto.core.base.R
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UnittoSearchBar(
|
fun UnittoSearchBar(
|
||||||
@ -65,73 +81,67 @@ fun UnittoSearchBar(
|
|||||||
query: TextFieldValue,
|
query: TextFieldValue,
|
||||||
onQueryChange: (TextFieldValue) -> Unit,
|
onQueryChange: (TextFieldValue) -> Unit,
|
||||||
navigateUp: () -> Unit,
|
navigateUp: () -> Unit,
|
||||||
title: String,
|
focusManager: FocusManager = LocalFocusManager.current,
|
||||||
searchActions: @Composable (RowScope.() -> Unit) = {},
|
onSearch: KeyboardActionScope.() -> Unit = { focusManager.clearFocus() },
|
||||||
noSearchActions: @Composable (RowScope.() -> Unit) = {},
|
focusRequester: FocusRequester = remember { FocusRequester() },
|
||||||
placeholder: String = stringResource(R.string.search_text_field_placeholder),
|
trailingIcon: @Composable () -> Unit = { SearchButton { focusManager.clearFocus() } },
|
||||||
scrollBehavior: TopAppBarScrollBehavior? = null,
|
scrollBehavior: TopAppBarScrollBehavior,
|
||||||
colors: TopAppBarColors = TopAppBarDefaults.topAppBarColors()
|
|
||||||
) {
|
) {
|
||||||
var showSearchInput by remember { mutableStateOf(false) }
|
val notEmpty = remember(query) { query.text.isNotEmpty() }
|
||||||
val focusRequester = remember { FocusRequester() }
|
fun clear() = onQueryChange(TextFieldValue())
|
||||||
|
LaunchedEffect(Unit) { focusRequester.requestFocus() }
|
||||||
|
LaunchedEffect(scrollBehavior.state.overlappedFraction) {
|
||||||
|
if (scrollBehavior.state.collapsedFraction > 0.5f) focusManager.clearFocus()
|
||||||
|
}
|
||||||
|
BackHandler(notEmpty, ::clear)
|
||||||
|
|
||||||
LaunchedEffect(showSearchInput) {
|
val heightOffsetLimit = with(LocalDensity.current) { -(UnittoSearchBarTokens.UnittoSearchBarFullHeight).toPx() }
|
||||||
if (showSearchInput) focusRequester.requestFocus() else onQueryChange(TextFieldValue())
|
SideEffect {
|
||||||
}
|
if (scrollBehavior.state.heightOffsetLimit != heightOffsetLimit) {
|
||||||
|
scrollBehavior.state.heightOffsetLimit = heightOffsetLimit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val height = LocalDensity.current.run {
|
||||||
|
UnittoSearchBarTokens.UnittoSearchBarFullHeight + scrollBehavior.state.heightOffset.toDp()
|
||||||
|
}
|
||||||
|
|
||||||
BackHandler(showSearchInput) { showSearchInput = false }
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
.statusBarsPadding()
|
||||||
|
.height(height),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.offset { IntOffset(x = 0, y = scrollBehavior.state.heightOffset.roundToInt()) }
|
||||||
|
.padding(horizontal = UnittoSearchBarTokens.UnittoSearchBarPadding)
|
||||||
|
.requiredHeight(UnittoSearchBarTokens.UnittoSearchBarHeight)
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(6.dp))
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
|
) {
|
||||||
|
ProvideColor(MaterialTheme.colorScheme.onSurface) {
|
||||||
|
|
||||||
Crossfade(
|
NavigateButton { if (notEmpty) clear() else navigateUp() }
|
||||||
modifier = modifier,
|
|
||||||
targetState = showSearchInput,
|
SearchTextField(
|
||||||
label = "Search input"
|
modifier = Modifier
|
||||||
) { showSearch ->
|
.focusRequester(focusRequester)
|
||||||
if (showSearch) {
|
.fillMaxWidth()
|
||||||
TopAppBar(
|
.weight(1f),
|
||||||
title = {
|
value = query,
|
||||||
SearchTextField(
|
placeholder = stringResource(R.string.search_text_field_placeholder),
|
||||||
modifier = Modifier
|
onValueChange = onQueryChange,
|
||||||
.focusRequester(focusRequester)
|
onSearch = onSearch
|
||||||
.fillMaxWidth(),
|
)
|
||||||
value = query,
|
|
||||||
placeholder = placeholder,
|
ClearButton(notEmpty, ::clear)
|
||||||
onValueChange = onQueryChange,
|
|
||||||
onSearch = {}
|
trailingIcon()
|
||||||
)
|
}
|
||||||
},
|
|
||||||
navigationIcon = {
|
|
||||||
NavigateUpButton { showSearchInput = false }
|
|
||||||
},
|
|
||||||
actions = {
|
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
|
||||||
ClearButton(visible = query.text.isNotEmpty()) { onQueryChange(TextFieldValue()) }
|
|
||||||
searchActions()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
colors = colors,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
TopAppBar(
|
|
||||||
title = {
|
|
||||||
Text(
|
|
||||||
text = title,
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
style = MaterialTheme.typography.titleLarge
|
|
||||||
)
|
|
||||||
},
|
|
||||||
navigationIcon = {
|
|
||||||
NavigateUpButton { navigateUp() }
|
|
||||||
},
|
|
||||||
actions = {
|
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
|
||||||
SearchButton { showSearchInput = true }
|
|
||||||
noSearchActions()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
colors = colors,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,7 +159,7 @@ private fun SearchTextField(
|
|||||||
value = value,
|
value = value,
|
||||||
onValueChange = onValueChange,
|
onValueChange = onValueChange,
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
textStyle = MaterialTheme.typography.titleLarge.copy(color = MaterialTheme.colorScheme.onSurface),
|
textStyle = MaterialTheme.typography.bodyLarge.copy(color = MaterialTheme.colorScheme.onSurface),
|
||||||
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurface),
|
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurface),
|
||||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
|
||||||
keyboardActions = KeyboardActions(onSearch = onSearch),
|
keyboardActions = KeyboardActions(onSearch = onSearch),
|
||||||
@ -160,7 +170,7 @@ private fun SearchTextField(
|
|||||||
Text(
|
Text(
|
||||||
modifier = Modifier.alpha(0.7f),
|
modifier = Modifier.alpha(0.7f),
|
||||||
text = placeholder,
|
text = placeholder,
|
||||||
style = MaterialTheme.typography.titleLarge,
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
color = MaterialTheme.colorScheme.onSurface
|
color = MaterialTheme.colorScheme.onSurface
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -172,25 +182,37 @@ private fun SearchTextField(
|
|||||||
private fun SearchButton(
|
private fun SearchButton(
|
||||||
onClick: () -> Unit
|
onClick: () -> Unit
|
||||||
) {
|
) {
|
||||||
IconButton(onClick) {
|
SearchBarIconButton(onClick) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Default.Search,
|
imageVector = Icons.Default.Search,
|
||||||
contentDescription = stringResource(R.string.search_button_description)
|
contentDescription = stringResource(R.string.search_button_description)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun NavigateButton(
|
||||||
|
onClick: () -> Unit
|
||||||
|
) {
|
||||||
|
SearchBarIconButton(onClick) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.AutoMirrored.Outlined.ArrowBack,
|
||||||
|
contentDescription = stringResource(R.string.navigate_up_description)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ClearButton(
|
private fun ClearButton(
|
||||||
visible: Boolean,
|
visible: Boolean,
|
||||||
onClick: () -> Unit
|
onClick: () -> Unit
|
||||||
) {
|
) {
|
||||||
IconButton(onClick = onClick) {
|
AnimatedVisibility(
|
||||||
AnimatedVisibility(
|
visible = visible,
|
||||||
visible = visible,
|
enter = fadeIn(),
|
||||||
enter = fadeIn(),
|
exit = fadeOut()
|
||||||
exit = fadeOut()
|
) {
|
||||||
) {
|
SearchBarIconButton(onClick) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Outlined.Clear,
|
imageVector = Icons.Outlined.Clear,
|
||||||
contentDescription = stringResource(R.string.clear_input_description)
|
contentDescription = stringResource(R.string.clear_input_description)
|
||||||
@ -199,6 +221,36 @@ private fun ClearButton(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SearchBarIconButton(
|
||||||
|
onClick: () -> Unit,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(24.dp)
|
||||||
|
.clickable(
|
||||||
|
onClick = onClick,
|
||||||
|
enabled = true,
|
||||||
|
role = Role.Button,
|
||||||
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
|
indication = rememberRipple(
|
||||||
|
bounded = false,
|
||||||
|
radius = 20.dp
|
||||||
|
)
|
||||||
|
),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private object UnittoSearchBarTokens {
|
||||||
|
val UnittoSearchBarHeight = 56.dp
|
||||||
|
val UnittoSearchBarPadding = 8.dp
|
||||||
|
val UnittoSearchBarFullHeight = UnittoSearchBarHeight + UnittoSearchBarPadding * 2
|
||||||
|
}
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun UnittoSearchBarPreview() {
|
fun UnittoSearchBarPreview() {
|
||||||
@ -206,7 +258,6 @@ fun UnittoSearchBarPreview() {
|
|||||||
query = TextFieldValue("test"),
|
query = TextFieldValue("test"),
|
||||||
onQueryChange = {},
|
onQueryChange = {},
|
||||||
navigateUp = {},
|
navigateUp = {},
|
||||||
title = "Title",
|
scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||||
placeholder = "placeholder"
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,6 @@
|
|||||||
package com.sadellie.unitto.feature.converter
|
package com.sadellie.unitto.feature.converter
|
||||||
|
|
||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.animation.animateColorAsState
|
|
||||||
import androidx.compose.animation.core.LinearOutSlowInEasing
|
|
||||||
import androidx.compose.animation.core.tween
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
@ -32,19 +29,13 @@ import androidx.compose.foundation.lazy.rememberLazyListState
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.rememberTopAppBarState
|
|
||||||
import androidx.compose.material3.surfaceColorAtElevation
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.derivedStateOf
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.input.TextFieldValue
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.sadellie.unitto.core.base.R
|
import com.sadellie.unitto.core.base.R
|
||||||
import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen
|
import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen
|
||||||
@ -96,16 +87,7 @@ private fun LeftSideScreen(
|
|||||||
navigateUp: () -> Unit,
|
navigateUp: () -> Unit,
|
||||||
navigateToUnitGroups: () -> Unit,
|
navigateToUnitGroups: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
||||||
val elevatedColor = MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp)
|
|
||||||
val needToTint by remember {
|
|
||||||
derivedStateOf { scrollBehavior.state.overlappedFraction > 0.01f }
|
|
||||||
}
|
|
||||||
val chipsBackground = animateColorAsState(
|
|
||||||
targetValue = if (needToTint) elevatedColor else MaterialTheme.colorScheme.surface,
|
|
||||||
animationSpec = tween(durationMillis = 500, easing = LinearOutSlowInEasing),
|
|
||||||
label = "Chips background",
|
|
||||||
)
|
|
||||||
|
|
||||||
val chipsRowLazyListState = rememberLazyListState()
|
val chipsRowLazyListState = rememberLazyListState()
|
||||||
|
|
||||||
@ -124,19 +106,18 @@ private fun LeftSideScreen(
|
|||||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
topBar = {
|
topBar = {
|
||||||
Column(
|
Column(
|
||||||
Modifier.background(chipsBackground.value)
|
Modifier.background(MaterialTheme.colorScheme.surface)
|
||||||
) {
|
) {
|
||||||
UnittoSearchBar(
|
UnittoSearchBar(
|
||||||
query = uiState.query,
|
query = uiState.query,
|
||||||
onQueryChange = onQueryChange,
|
onQueryChange = onQueryChange,
|
||||||
navigateUp = navigateUp,
|
navigateUp = navigateUp,
|
||||||
title = stringResource(R.string.converter_left_side_title),
|
trailingIcon = {
|
||||||
placeholder = stringResource(R.string.converter_search_bar_placeholder),
|
|
||||||
noSearchActions = {
|
|
||||||
FavoritesButton(uiState.favorites) {
|
FavoritesButton(uiState.favorites) {
|
||||||
toggleFavoritesOnly(!uiState.favorites)
|
toggleFavoritesOnly(!uiState.favorites)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
scrollBehavior = scrollBehavior
|
||||||
)
|
)
|
||||||
|
|
||||||
if (uiState.verticalList) {
|
if (uiState.verticalList) {
|
||||||
@ -213,7 +194,7 @@ private fun LeftSideScreenPreview() {
|
|||||||
uiState = LeftSideUIState.Ready(
|
uiState = LeftSideUIState.Ready(
|
||||||
unitFrom = units.values.first().first(),
|
unitFrom = units.values.first().first(),
|
||||||
units = units,
|
units = units,
|
||||||
query = TextFieldValue(),
|
query = TextFieldValue("test"),
|
||||||
favorites = false,
|
favorites = false,
|
||||||
shownUnitGroups = listOf(UnitGroup.LENGTH, UnitGroup.TEMPERATURE, UnitGroup.CURRENCY),
|
shownUnitGroups = listOf(UnitGroup.LENGTH, UnitGroup.TEMPERATURE, UnitGroup.CURRENCY),
|
||||||
unitGroup = units.keys.toList().first(),
|
unitGroup = units.keys.toList().first(),
|
||||||
|
@ -25,7 +25,6 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.rememberTopAppBarState
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
@ -86,7 +85,7 @@ private fun RightSideScreen(
|
|||||||
navigateUp: () -> Unit,
|
navigateUp: () -> Unit,
|
||||||
navigateToUnitGroups: () -> Unit,
|
navigateToUnitGroups: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
@ -95,9 +94,7 @@ private fun RightSideScreen(
|
|||||||
query = uiState.query,
|
query = uiState.query,
|
||||||
onQueryChange = onQueryChange,
|
onQueryChange = onQueryChange,
|
||||||
navigateUp = navigateUp,
|
navigateUp = navigateUp,
|
||||||
title = stringResource(R.string.converter_right_side_title),
|
trailingIcon = {
|
||||||
placeholder = stringResource(R.string.converter_search_bar_placeholder),
|
|
||||||
noSearchActions = {
|
|
||||||
FavoritesButton(uiState.favorites) {
|
FavoritesButton(uiState.favorites) {
|
||||||
toggleFavoritesOnly(!uiState.favorites)
|
toggleFavoritesOnly(!uiState.favorites)
|
||||||
}
|
}
|
||||||
@ -229,4 +226,3 @@ private fun RightSideScreenPreview() {
|
|||||||
navigateToUnitGroups = {}
|
navigateToUnitGroups = {}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,17 +27,17 @@ import androidx.compose.material.icons.Icons
|
|||||||
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.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import com.sadellie.unitto.core.base.R
|
import com.sadellie.unitto.core.base.R
|
||||||
|
import com.sadellie.unitto.core.ui.common.SearchBarIconButton
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun FavoritesButton(
|
internal fun FavoritesButton(
|
||||||
state: Boolean,
|
state: Boolean,
|
||||||
onClick: () -> Unit
|
onClick: () -> Unit
|
||||||
) {
|
) {
|
||||||
IconButton(onClick = onClick) {
|
SearchBarIconButton(onClick = onClick) {
|
||||||
AnimatedContent(
|
AnimatedContent(
|
||||||
targetState = state,
|
targetState = state,
|
||||||
transitionSpec = {
|
transitionSpec = {
|
||||||
|
@ -27,24 +27,23 @@ import android.text.format.DateFormat.is24HourFormat
|
|||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.rememberTopAppBarState
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.text.input.TextFieldValue
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.sadellie.unitto.core.base.R
|
|
||||||
import com.sadellie.unitto.core.ui.LocalLocale
|
import com.sadellie.unitto.core.ui.LocalLocale
|
||||||
import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen
|
import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen
|
||||||
import com.sadellie.unitto.core.ui.common.UnittoListItem
|
import com.sadellie.unitto.core.ui.common.UnittoListItem
|
||||||
@ -84,7 +83,7 @@ fun AddTimeZoneScreen(
|
|||||||
addToFavorites: (TimeZone) -> Unit,
|
addToFavorites: (TimeZone) -> Unit,
|
||||||
userTime: ZonedDateTime,
|
userTime: ZonedDateTime,
|
||||||
) {
|
) {
|
||||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
||||||
val locale = LocalLocale.current
|
val locale = LocalLocale.current
|
||||||
val is24Hour = is24HourFormat(LocalContext.current)
|
val is24Hour = is24HourFormat(LocalContext.current)
|
||||||
|
|
||||||
@ -95,19 +94,19 @@ fun AddTimeZoneScreen(
|
|||||||
query = uiState.query,
|
query = uiState.query,
|
||||||
onQueryChange = onQueryChange,
|
onQueryChange = onQueryChange,
|
||||||
navigateUp = navigateUp,
|
navigateUp = navigateUp,
|
||||||
title = stringResource(R.string.time_zone_add_title),
|
scrollBehavior = scrollBehavior,
|
||||||
scrollBehavior = scrollBehavior
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
Crossfade(
|
Crossfade(
|
||||||
|
modifier = Modifier.padding(paddingValues),
|
||||||
targetState = uiState.list.isEmpty(),
|
targetState = uiState.list.isEmpty(),
|
||||||
label = "Placeholder"
|
label = "Placeholder"
|
||||||
) { empty ->
|
) { empty ->
|
||||||
if (empty) {
|
if (empty) {
|
||||||
UnittoEmptyScreen()
|
UnittoEmptyScreen()
|
||||||
} else {
|
} else {
|
||||||
LazyColumn(contentPadding = paddingValues) {
|
LazyColumn(Modifier.fillMaxSize()) {
|
||||||
items(uiState.list, { it.timeZone.id }) {
|
items(uiState.list, { it.timeZone.id }) {
|
||||||
UnittoListItem(
|
UnittoListItem(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
Loading…
x
Reference in New Issue
Block a user