diff --git a/feature/timezone/src/main/java/com/sadellie/unitto/timezone/components/UnittoSearchBar.kt b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoSearchBar.kt
similarity index 92%
rename from feature/timezone/src/main/java/com/sadellie/unitto/timezone/components/UnittoSearchBar.kt
rename to core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoSearchBar.kt
index 9b4a44b3..ef4a6de4 100644
--- a/feature/timezone/src/main/java/com/sadellie/unitto/timezone/components/UnittoSearchBar.kt
+++ b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoSearchBar.kt
@@ -16,13 +16,14 @@
* along with this program. If not, see .
*/
-package com.sadellie.unitto.timezone.components
+package com.sadellie.unitto.core.ui.common
import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.Crossfade
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
+import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.text.BasicTextField
@@ -46,6 +47,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.focus.FocusRequester
@@ -54,7 +56,6 @@ import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import com.sadellie.unitto.core.base.R
-import com.sadellie.unitto.core.ui.common.NavigateUpButton
@Composable
fun UnittoSearchBar(
@@ -113,12 +114,14 @@ fun UnittoSearchBar(
},
actions = {
Crossfade(showSearch) { _showSearch ->
- if (_showSearch) {
- ClearButton(visible = query.isNotEmpty()) { onQueryChange("") }
- searchActions()
- } else {
- SearchButton { showSearch = true }
- noSearchActions()
+ Row(verticalAlignment = Alignment.CenterVertically) {
+ if (_showSearch) {
+ ClearButton(visible = query.isNotEmpty()) { onQueryChange("") }
+ searchActions()
+ } else {
+ SearchButton { showSearch = true }
+ noSearchActions()
+ }
}
}
},
diff --git a/feature/timezone/src/main/java/com/sadellie/unitto/timezone/AddTimeZoneScreen.kt b/feature/timezone/src/main/java/com/sadellie/unitto/timezone/AddTimeZoneScreen.kt
index a9f08764..ff852e96 100644
--- a/feature/timezone/src/main/java/com/sadellie/unitto/timezone/AddTimeZoneScreen.kt
+++ b/feature/timezone/src/main/java/com/sadellie/unitto/timezone/AddTimeZoneScreen.kt
@@ -48,7 +48,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.data.model.UnittoTimeZone
import com.sadellie.unitto.timezone.components.SelectableTimeZone
-import com.sadellie.unitto.timezone.components.UnittoSearchBar
+import com.sadellie.unitto.core.ui.common.UnittoSearchBar
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import java.time.ZonedDateTime
diff --git a/feature/unitslist/src/main/java/com/sadellie/unitto/feature/unitslist/LeftSideScreen.kt b/feature/unitslist/src/main/java/com/sadellie/unitto/feature/unitslist/LeftSideScreen.kt
index 44531ac2..4befc26d 100644
--- a/feature/unitslist/src/main/java/com/sadellie/unitto/feature/unitslist/LeftSideScreen.kt
+++ b/feature/unitslist/src/main/java/com/sadellie/unitto/feature/unitslist/LeftSideScreen.kt
@@ -46,9 +46,10 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.sadellie.unitto.core.base.R
+import com.sadellie.unitto.core.ui.common.UnittoSearchBar
import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.feature.unitslist.components.ChipsRow
-import com.sadellie.unitto.feature.unitslist.components.SearchBar
+import com.sadellie.unitto.feature.unitslist.components.FavoritesButton
import com.sadellie.unitto.feature.unitslist.components.SearchPlaceholder
import com.sadellie.unitto.feature.unitslist.components.UnitGroupHeader
import com.sadellie.unitto.feature.unitslist.components.UnitListItem
@@ -91,15 +92,18 @@ internal fun LeftSideScreen(
Column(
Modifier.background(chipsBackground.value)
) {
- SearchBar(
+ UnittoSearchBar(
+ query = uiState.value.searchQuery,
+ onQueryChange = { viewModel.onSearchQueryChange(it, false) },
+ navigateUp = navigateUp,
title = stringResource(R.string.units_screen_from),
- value = uiState.value.searchQuery,
- onValueChange = { viewModel.onSearchQueryChange(it, false) },
- favoritesOnly = uiState.value.favoritesOnly,
- favoriteAction = { viewModel.toggleFavoritesOnly(false) },
- navigateUpAction = navigateUp,
- focusManager = focusManager,
- scrollBehavior = scrollBehavior
+ placeholder = stringResource(R.string.search_bar_placeholder),
+ noSearchActions = {
+ FavoritesButton(
+ favoritesOnly = uiState.value.favoritesOnly,
+ favoriteAction = { viewModel.toggleFavoritesOnly(false) }
+ )
+ }
)
ChipsRow(
chosenUnitGroup = uiState.value.chosenUnitGroup,
diff --git a/feature/unitslist/src/main/java/com/sadellie/unitto/feature/unitslist/RightSideScreen.kt b/feature/unitslist/src/main/java/com/sadellie/unitto/feature/unitslist/RightSideScreen.kt
index d334d101..396d1a2d 100644
--- a/feature/unitslist/src/main/java/com/sadellie/unitto/feature/unitslist/RightSideScreen.kt
+++ b/feature/unitslist/src/main/java/com/sadellie/unitto/feature/unitslist/RightSideScreen.kt
@@ -33,12 +33,13 @@ import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.sadellie.unitto.core.base.R
+import com.sadellie.unitto.core.ui.common.UnittoSearchBar
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.ui.common.textfield.formatExpression
import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.model.NumberBaseUnit
import com.sadellie.unitto.data.model.UnitGroup
-import com.sadellie.unitto.feature.unitslist.components.SearchBar
+import com.sadellie.unitto.feature.unitslist.components.FavoritesButton
import com.sadellie.unitto.feature.unitslist.components.SearchPlaceholder
import com.sadellie.unitto.feature.unitslist.components.UnitGroupHeader
import com.sadellie.unitto.feature.unitslist.components.UnitListItem
@@ -92,19 +93,18 @@ internal fun RightSideScreen(
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
- SearchBar(
+ UnittoSearchBar(
+ query = uiState.value.searchQuery,
+ onQueryChange = { viewModel.onSearchQueryChange(it, true) },
+ navigateUp = navigateUp,
title = stringResource(R.string.units_screen_to),
- value = uiState.value.searchQuery,
- onValueChange = {
- viewModel.onSearchQueryChange(it, true)
- },
- favoritesOnly = uiState.value.favoritesOnly,
- favoriteAction = {
- viewModel.toggleFavoritesOnly(true)
- },
- navigateUpAction = navigateUp,
- focusManager = focusManager,
- scrollBehavior = scrollBehavior
+ placeholder = stringResource(R.string.search_bar_placeholder),
+ noSearchActions = {
+ FavoritesButton(
+ favoritesOnly = uiState.value.favoritesOnly,
+ favoriteAction = { viewModel.toggleFavoritesOnly(true) }
+ )
+ }
)
}
) { paddingValues ->
diff --git a/feature/unitslist/src/main/java/com/sadellie/unitto/feature/unitslist/components/FavoritesButton.kt b/feature/unitslist/src/main/java/com/sadellie/unitto/feature/unitslist/components/FavoritesButton.kt
new file mode 100644
index 00000000..daab4773
--- /dev/null
+++ b/feature/unitslist/src/main/java/com/sadellie/unitto/feature/unitslist/components/FavoritesButton.kt
@@ -0,0 +1,53 @@
+/*
+ * Unitto is a unit converter for Android
+ * Copyright (c) 2022-2023 Elshan Agaev
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sadellie.unitto.feature.unitslist.components
+
+import androidx.compose.animation.AnimatedContent
+import androidx.compose.animation.SizeTransform
+import androidx.compose.animation.scaleIn
+import androidx.compose.animation.scaleOut
+import androidx.compose.animation.togetherWith
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Favorite
+import androidx.compose.material.icons.filled.FavoriteBorder
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.res.stringResource
+import com.sadellie.unitto.core.base.R
+
+@Composable
+internal fun FavoritesButton(
+ favoritesOnly: Boolean,
+ favoriteAction: () -> Unit
+) {
+ IconButton(onClick = favoriteAction) {
+ AnimatedContent(
+ targetState = favoritesOnly,
+ transitionSpec = {
+ (scaleIn() togetherWith scaleOut()).using(SizeTransform(clip = false))
+ }
+ ) {
+ Icon(
+ if (it) Icons.Filled.Favorite else Icons.Filled.FavoriteBorder,
+ contentDescription = stringResource(R.string.favorite_button_description)
+ )
+ }
+ }
+}
diff --git a/feature/unitslist/src/main/java/com/sadellie/unitto/feature/unitslist/components/SearchBar.kt b/feature/unitslist/src/main/java/com/sadellie/unitto/feature/unitslist/components/SearchBar.kt
deleted file mode 100644
index 6e78872c..00000000
--- a/feature/unitslist/src/main/java/com/sadellie/unitto/feature/unitslist/components/SearchBar.kt
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Unitto is a unit converter for Android
- * Copyright (c) 2022-2023 Elshan Agaev
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package com.sadellie.unitto.feature.unitslist.components
-
-import android.annotation.SuppressLint
-import androidx.activity.compose.BackHandler
-import androidx.compose.animation.AnimatedContent
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.Crossfade
-import androidx.compose.animation.SizeTransform
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.animation.scaleIn
-import androidx.compose.animation.scaleOut
-import androidx.compose.animation.togetherWith
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.text.BasicTextField
-import androidx.compose.foundation.text.KeyboardActionScope
-import androidx.compose.foundation.text.KeyboardActions
-import androidx.compose.foundation.text.KeyboardOptions
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Favorite
-import androidx.compose.material.icons.filled.FavoriteBorder
-import androidx.compose.material.icons.filled.Search
-import androidx.compose.material.icons.outlined.Clear
-import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
-import androidx.compose.material3.TopAppBar
-import androidx.compose.material3.TopAppBarScrollBehavior
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.alpha
-import androidx.compose.ui.focus.FocusManager
-import androidx.compose.ui.focus.FocusRequester
-import androidx.compose.ui.focus.focusRequester
-import androidx.compose.ui.graphics.SolidColor
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.input.ImeAction
-import com.sadellie.unitto.core.base.R
-import com.sadellie.unitto.core.ui.common.NavigateUpButton
-
-/**
- * Search bar on the Second screen. Controls what will be shown in the list above this component
- *
- * @param title Search bar title
- * @param value Current query
- * @param onValueChange Action to perform when search query changes
- * @param favoritesOnly Current filter state: On or Off
- * @param favoriteAction Function to toggle favorite filter
- * @param navigateUpAction Function to navigate to previous screen
- * @param focusManager Used to hide keyboard when leaving unit selection screen
- * @param scrollBehavior [TopAppBarScrollBehavior] that is used for collapsing and container color
- */
-@Composable
-internal fun SearchBar(
- title: String,
- value: String,
- onValueChange: (String) -> Unit,
- favoritesOnly: Boolean,
- favoriteAction: () -> Unit,
- navigateUpAction: () -> Unit,
- focusManager: FocusManager,
- scrollBehavior: TopAppBarScrollBehavior
-) {
- var showSearch by rememberSaveable { mutableStateOf(false) }
- 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()
- }
- }
-
- TopAppBar(
- title = {
- Crossfade(targetState = showSearch) { textFieldShown ->
- Row(verticalAlignment = Alignment.CenterVertically) {
- if (textFieldShown) {
- SearchTextField(
- modifier = Modifier
- .fillMaxWidth()
- .weight(1f)
- .focusRequester(focusRequester),
- value = value,
- onValueChange = onValueChange,
- onSearch = {
- // Close searchbar if there is nothing in search query and user
- // clicks search button on his keyboard
- if (value.isEmpty()) {
- showSearch = false
- } else {
- focusManager.clearFocus()
- }
- }
- )
- LaunchedEffect(Unit) {
- focusRequester.requestFocus()
- }
- } else {
- Text(
- modifier = Modifier
- .fillMaxWidth()
- .weight(1f),
- text = title,
- style = MaterialTheme.typography.titleLarge
- )
- }
- }
- }
- },
- actions = {
- Crossfade(targetState = showSearch) {
- Row(
- verticalAlignment = Alignment.CenterVertically
- ) {
- when (it) {
- false -> {
- // Search button
- SearchButton {
- onValueChange("")
- showSearch = true
- }
- // Favorites button
- FavoritesButton(favoritesOnly, favoriteAction)
- }
- true -> {
- // Clear button
- ClearButton(value.isNotBlank()) { onValueChange("") }
- }
- }
- }
- }
- },
- navigationIcon = {
- NavigateUpButton { stagedNavigateUp() }
- },
- scrollBehavior = scrollBehavior
- )
-
- BackHandler { stagedNavigateUp() }
-}
-
-@Composable
-private fun SearchTextField(
- modifier: Modifier,
- value: String,
- onValueChange: (String) -> Unit,
- onSearch: KeyboardActionScope.() -> Unit
-) {
- BasicTextField(
- modifier = modifier,
- value = value,
- onValueChange = onValueChange,
- singleLine = true,
- textStyle = MaterialTheme.typography.titleLarge.copy(color = MaterialTheme.colorScheme.onSurface),
- cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurface),
- keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
- keyboardActions = KeyboardActions(onSearch = onSearch),
- decorationBox = { innerTextField ->
- innerTextField()
- // Showing placeholder only when there is query is empty
- value.ifEmpty {
- Text(
- modifier = Modifier.alpha(0.7f),
- text = stringResource(R.string.search_bar_placeholder),
- style = MaterialTheme.typography.titleLarge,
- color = MaterialTheme.colorScheme.onSurface
- )
- }
- }
- )
-}
-
-@Composable
-private fun SearchButton(
- onClick: () -> Unit
-) {
- IconButton(onClick) {
- Icon(
- Icons.Default.Search,
- contentDescription = stringResource(R.string.search_button_description)
- )
- }
-}
-
-@SuppressLint("UnusedContentLambdaTargetStateParameter")
-@Composable
-private fun FavoritesButton(
- favoritesOnly: Boolean,
- favoriteAction: () -> Unit
-) {
- IconButton(onClick = favoriteAction) {
- AnimatedContent(
- targetState = favoritesOnly,
- transitionSpec = {
- (scaleIn() togetherWith scaleOut()).using(SizeTransform(clip = false))
- }
- ) {
- Icon(
- if (favoritesOnly) Icons.Filled.Favorite else Icons.Filled.FavoriteBorder,
- contentDescription = stringResource(R.string.favorite_button_description)
- )
- }
- }
-}
-
-@Composable
-private fun ClearButton(
- visible: Boolean,
- onClick: () -> Unit
-) {
- IconButton(onClick = onClick) {
- AnimatedVisibility(
- visible = visible,
- enter = fadeIn(),
- exit = fadeOut()
- ) {
- Icon(
- imageVector = Icons.Outlined.Clear,
- contentDescription = stringResource(R.string.clear_input_description)
- )
- }
- }
-}