diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/location/LocationSearchBarScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/location/LocationSearchBarScreen.kt index 7c265995a..968898393 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/location/LocationSearchBarScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/location/LocationSearchBarScreen.kt @@ -8,11 +8,14 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment.Companion.TopCenter import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import org.hisp.dhis.common.screens.components.GroupComponentDropDown import org.hisp.dhis.mobile.ui.designsystem.component.DropdownItem import org.hisp.dhis.mobile.ui.designsystem.component.LocationBar @@ -37,6 +40,8 @@ fun LocationSearchBarScreen( screenDropdownItemList.add(DropdownItem(it.label)) } + val scope = rememberCoroutineScope() + GroupComponentDropDown( dropdownItems = screenDropdownItemList.toList(), onItemSelected = { @@ -52,6 +57,8 @@ fun LocationSearchBarScreen( when (currentScreen.value) { LocationSearchBarOptions.DEFAULT_BEHAVIOUR -> { + var searching by remember { mutableStateOf(false) } + Box( modifier = Modifier.fillMaxSize() .background(Color.White) @@ -63,18 +70,26 @@ fun LocationSearchBarScreen( onBackClicked = {}, onClearLocation = {}, onSearchLocation = { locationQuery -> - onSearchLocation(locationQuery) { - itemList = - it.takeIf { locationQuery.isNotBlank() } ?: defaultLocationItems + searching = true + scope.launch { + delay(3000) + onSearchLocation(locationQuery) { + itemList = + it.takeIf { locationQuery.isNotBlank() } ?: defaultLocationItems + searching = false + } } }, onLocationSelected = { locationItemModel -> }, + searching = searching, ) } } LocationSearchBarOptions.AUTOSELECT_ON_ONE_ITEM_FOUND -> { + var searching by remember { mutableStateOf(false) } + Box( modifier = Modifier.fillMaxSize() .background(Color.White) @@ -87,14 +102,19 @@ fun LocationSearchBarScreen( onBackClicked = {}, onClearLocation = {}, onSearchLocation = { locationQuery -> - onSearchLocation(locationQuery) { - itemList = - it.take(1).takeIf { locationQuery.isNotBlank() } - ?: defaultLocationItems + searching = true + scope.launch { + onSearchLocation(locationQuery) { + itemList = + it.take(1).takeIf { locationQuery.isNotBlank() } + ?: defaultLocationItems + searching = false + } } }, onLocationSelected = { locationItemModel -> }, + searching = searching, ) } } diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/LocationSearchBar.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/LocationSearchBar.kt index b070ab29b..a696d588f 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/LocationSearchBar.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/LocationSearchBar.kt @@ -66,6 +66,11 @@ enum class SearchBarMode { SEARCH, } +/** + * DHIS2 Location Bar search actions + * Default: The user will need to select a result to mark it as selected + * OnOneItemSelect: If only one item is available, it will be selected automatically + * */ enum class OnSearchAction { Default, OnOneItemSelect, @@ -75,6 +80,8 @@ enum class OnSearchAction { * DHIS2 Location Bar. * @param currentResults: the available location items to display before/after search. * @param mode: the initial mode for the composable. + * @param searchAction: How the search result selection is carried out. + * @param searching: whether the search is currently in progress. * @param onBackClicked: callback for when the back button is clicked. * @param onClearLocation: callback for when the clear location button is clicked. * @param onSearchLocation: callback for when the search location button is clicked. @@ -86,6 +93,7 @@ fun LocationBar( currentResults: List, mode: SearchBarMode = SearchBarMode.BUTTON, searchAction: OnSearchAction = OnSearchAction.Default, + searching: Boolean, onBackClicked: () -> Unit, onClearLocation: () -> Unit, onSearchLocation: (query: String) -> Unit, @@ -129,6 +137,7 @@ fun LocationBar( SearchBarMode.SEARCH -> LocationSearchBar( currentSearch = currentSearch, currentResults = currentResults, + activeSearching = searching, onSearchChanged = { currentSearch = it onSearchLocation(currentSearch) @@ -212,6 +221,7 @@ private fun LocationSearchBarButton( private fun LocationSearchBar( currentSearch: String = "", currentResults: List, + activeSearching: Boolean, onSearchChanged: (String) -> Unit, onSearch: (String) -> Unit, onBackClicked: () -> Unit, @@ -221,6 +231,7 @@ private fun LocationSearchBar( val focusRequester = remember { FocusRequester() } val keyboardController = LocalSoftwareKeyboardController.current var needsToFocus by remember { mutableStateOf(true) } + var searching by remember(currentSearch) { mutableStateOf(false) } Column( modifier = Modifier.fillMaxSize(), @@ -259,6 +270,11 @@ private fun LocationSearchBar( LazyColumn(modifier = Modifier.fillMaxWidth(), state = scrollState) { when { + activeSearching -> + item { + SearchProgressMessage() + } + currentResults.isNotEmpty() -> itemsIndexed(items = currentResults) { index, locationItemModel -> SearchResultLocationItem( @@ -431,3 +447,24 @@ private fun NoResultsMessage(isSearching: Boolean) { ) } } + +@Composable +private fun SearchProgressMessage() { + val message = provideStringResource("searching_location") + + Column( + modifier = Modifier + .testTag("SEARCHING_LOCATION") + .fillMaxWidth() + .padding(vertical = 64.dp), + verticalArrangement = spacedBy(16.dp), + horizontalAlignment = CenterHorizontally, + ) { + ProgressIndicator(type = ProgressIndicatorType.CIRCULAR) + Text( + text = message, + style = MaterialTheme.typography.bodyLarge, + color = TextColor.OnSurfaceVariant, + ) + } +} diff --git a/designsystem/src/commonMain/resources/values-es/strings.xml b/designsystem/src/commonMain/resources/values-es/strings.xml index a0b90142e..e347b3ed5 100644 --- a/designsystem/src/commonMain/resources/values-es/strings.xml +++ b/designsystem/src/commonMain/resources/values-es/strings.xml @@ -46,4 +46,5 @@ Seleccionar en el mapa No hay resultados recientes No hay resultados + Buscando... diff --git a/designsystem/src/commonMain/resources/values/strings.xml b/designsystem/src/commonMain/resources/values/strings.xml index b012b6a6b..523a10f8c 100644 --- a/designsystem/src/commonMain/resources/values/strings.xml +++ b/designsystem/src/commonMain/resources/values/strings.xml @@ -46,4 +46,5 @@ Select in map No recent results No results + Searching...