Skip to content

Commit

Permalink
fix: [ANDROAPP-6622] Add progress to search location (#3875)
Browse files Browse the repository at this point in the history
* fix: [ANDROAPP-6622] Add progress to search location

* fix test

* fix code smell
  • Loading branch information
Balcan authored Nov 12, 2024
1 parent 6106696 commit f732d99
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 45 deletions.
2 changes: 1 addition & 1 deletion commons/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ android {
}

configurations.all {
resolutionStrategy.cacheDynamicVersionsFor(0, TimeUnit.SECONDS)
resolutionStrategy.cacheChangingModulesFor(0, TimeUnit.SECONDS)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ data class MapSelectorScreenState(
val selectedLocation: SelectedLocation,
val captureMode: MapSelectorViewModel.CaptureMode,
val accuracyRange: AccuracyRange,
val searching: Boolean,
val searchOnAreaVisible: Boolean,
val displayPolygonInfo: Boolean,
val locationState: LocationState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,15 @@ import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.recyclerview.widget.RecyclerView
import androidx.window.core.layout.WindowSizeClass
import androidx.window.core.layout.WindowWidthSizeClass
import com.mapbox.geojson.FeatureCollection
import com.mapbox.mapboxsdk.maps.MapView
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
Expand All @@ -63,6 +67,7 @@ import org.dhis2.maps.R
import org.dhis2.maps.location.AccuracyIndicator
import org.dhis2.maps.location.LocationState
import org.dhis2.maps.model.AccuracyRange
import org.dhis2.maps.model.MapData
import org.dhis2.maps.model.MapSelectorScreenActions
import org.dhis2.maps.model.MapSelectorScreenState
import org.hisp.dhis.mobile.ui.designsystem.component.Button
Expand Down Expand Up @@ -124,13 +129,16 @@ fun SinglePaneMapSelector(
) {
if (screenState.isManualCaptureEnabled && !screenState.displayPolygonInfo) {
SearchBar(
searching = screenState.searching,
locationItems = screenState.locationItems,
onBackClicked = screenActions.onBackClicked,
onClearLocation = screenActions.onClearLocation,
onSearchLocation = screenActions.onSearchLocation,
onLocationSelected = screenActions.onLocationSelected,
onSearchCaptureMode = screenActions.onSearchCaptureMode,
onButtonMode = screenActions.onButtonMode,
searchBarActions = SearchBarActions(
onBackClicked = screenActions.onBackClicked,
onClearLocation = screenActions.onClearLocation,
onSearchLocation = screenActions.onSearchLocation,
onLocationSelected = screenActions.onLocationSelected,
onSearchCaptureMode = screenActions.onSearchCaptureMode,
onButtonMode = screenActions.onButtonMode,
),
)
}

Expand Down Expand Up @@ -179,34 +187,49 @@ private fun TwoPaneMapSelector(
modifier = Modifier
.weight(0.3f)
.fillMaxHeight()
.fillMaxSize()
.padding(top = 56.dp),
.fillMaxSize(),
verticalArrangement = spacedBy(16.dp),
) {
SearchBar(
locationItems = screenState.locationItems,
onBackClicked = screenActions.onBackClicked,
onClearLocation = screenActions.onClearLocation,
onSearchLocation = screenActions.onSearchLocation,
onLocationSelected = screenActions.onLocationSelected,
onSearchCaptureMode = screenActions.onSearchCaptureMode,
onButtonMode = {
// no-op
},
)
if (!screenState.isManualCaptureEnabled || screenState.displayPolygonInfo) {
MapTopBar(screenActions.onBackClicked)
}

LocationInfoContent(
selectedLocation = screenState.selectedLocation,
captureMode = screenState.captureMode,
displayPolygonInfo = screenState.displayPolygonInfo,
accuracyRange = screenState.accuracyRange,
configurePolygonInfoRecycler = screenActions.configurePolygonInfoRecycler,
)
if (screenState.isManualCaptureEnabled && !screenState.displayPolygonInfo) {
SearchBar(
searching = screenState.searching,
locationItems = screenState.locationItems,
searchBarActions = SearchBarActions(
onBackClicked = screenActions.onBackClicked,
onClearLocation = screenActions.onClearLocation,
onSearchLocation = screenActions.onSearchLocation,
onLocationSelected = screenActions.onLocationSelected,
onSearchCaptureMode = screenActions.onSearchCaptureMode,
onButtonMode = {
// no-op
},
),
)
}

DoneButton(
enabled = screenState.doneButtonEnabled,
onDoneButtonClicked = screenActions.onDoneButtonClick,
)
Box(
modifier = Modifier.weight(1f),
contentAlignment = Alignment.BottomCenter,
) {
Column {
LocationInfoContent(
selectedLocation = screenState.selectedLocation,
captureMode = screenState.captureMode,
displayPolygonInfo = screenState.displayPolygonInfo,
accuracyRange = screenState.accuracyRange,
configurePolygonInfoRecycler = screenActions.configurePolygonInfoRecycler,
)

DoneButton(
enabled = screenState.doneButtonEnabled,
onDoneButtonClicked = screenActions.onDoneButtonClick,
)
}
}
}

Column(Modifier.weight(0.7f)) {
Expand All @@ -227,15 +250,20 @@ private fun TwoPaneMapSelector(
}
}

private data class SearchBarActions(
val onBackClicked: () -> Unit,
val onClearLocation: () -> Unit,
val onSearchLocation: (String) -> Unit,
val onLocationSelected: (LocationItemModel) -> Unit,
val onSearchCaptureMode: () -> Unit,
val onButtonMode: () -> Unit,
)

@Composable
private fun SearchBar(
searching: Boolean,
locationItems: List<LocationItemModel>,
onBackClicked: () -> Unit,
onClearLocation: () -> Unit,
onSearchLocation: (String) -> Unit,
onLocationSelected: (LocationItemModel) -> Unit,
onSearchCaptureMode: () -> Unit,
onButtonMode: () -> Unit,
searchBarActions: SearchBarActions,
) {
val scope = rememberCoroutineScope()

Expand All @@ -250,24 +278,25 @@ private fun SearchBar(
LocationBar(
currentResults = locationItems,
searchAction = OnSearchAction.OnOneItemSelect,
onBackClicked = onBackClicked,
onClearLocation = onClearLocation,
onBackClicked = searchBarActions.onBackClicked,
onClearLocation = searchBarActions.onClearLocation,
onSearchLocation = {
timeLeft = 1000
onSearchLocation(it)
searchBarActions.onSearchLocation(it)
},
searching = searching,
onLocationSelected = {
scope.launch {
delay(1000)
if (timeLeft == 0) {
onLocationSelected(it)
searchBarActions.onLocationSelected(it)
}
}
},
onModeChanged = {
when (it) {
SearchBarMode.BUTTON -> onButtonMode()
SearchBarMode.SEARCH -> onSearchCaptureMode()
SearchBarMode.BUTTON -> searchBarActions.onButtonMode()
SearchBarMode.SEARCH -> searchBarActions.onSearchCaptureMode()
}
},
)
Expand Down Expand Up @@ -417,7 +446,8 @@ private fun Map(
) {
Box(
modifier = modifier
.clip(RoundedCornerShape(8.dp)),
.clip(RoundedCornerShape(8.dp))
.background(SurfaceColor.ContainerLow),
contentAlignment = Alignment.Center,
) {
MapScreen(
Expand Down Expand Up @@ -606,3 +636,100 @@ private fun MapTopBar(onBackClicked: () -> Unit) {
),
)
}

@Preview(device = "id:pixel_8a", showBackground = true)
@Composable
fun TestPortraitMap(
@PreviewParameter(ScreenStateParamProvider::class) screenState: MapSelectorScreenState,
) {
MapSelectorScreen(
screenState = screenState,
mapSelectorScreenActions = previewActions,
)
}

@Preview(device = "id:pixel_tablet", showBackground = true)
@Composable
fun TestLandscapeMap(
@PreviewParameter(ScreenStateParamProvider::class) screenState: MapSelectorScreenState,
) {
TwoPaneMapSelector(
screenState = screenState,
screenActions = previewActions,
)
}

private class ScreenStateParamProvider : PreviewParameterProvider<MapSelectorScreenState> {
override val values: Sequence<MapSelectorScreenState>
get() = sequenceOf(
searchScreenState,
gpsScreenState,
)
}

private val searchScreenState = MapSelectorScreenState(
mapData = MapData(
featureCollection = FeatureCollection.fromFeatures(emptyList()),
boundingBox = null,
),
locationItems = listOf(
LocationItemModel.StoredResult(
storedTitle = "title",
storedSubtitle = "subtitle",
storedLatitude = 0.0,
storedLongitude = 0.0,
),
LocationItemModel.SearchResult(
searchedTitle = "title",
searchedSubtitle = "subtitle",
searchedLatitude = 0.0,
searchedLongitude = 0.0,
),
),
selectedLocation = SelectedLocation.None(),
captureMode = MapSelectorViewModel.CaptureMode.SEARCH,
accuracyRange = AccuracyRange.None(),
searchOnAreaVisible = true,
displayPolygonInfo = false,
locationState = LocationState.OFF,
isManualCaptureEnabled = true,
forcedLocationAccuracy = 10,
lastGPSLocation = null,
searching = false,
)

private val gpsScreenState = MapSelectorScreenState(
mapData = MapData(
featureCollection = FeatureCollection.fromFeatures(emptyList()),
boundingBox = null,
),
locationItems = emptyList(),
selectedLocation = SelectedLocation.GPSResult(
selectedLatitude = 0.0,
selectedLongitude = 0.0,
accuracy = 5f,
),
captureMode = MapSelectorViewModel.CaptureMode.GPS,
accuracyRange = AccuracyRange.VeryGood(5),
searchOnAreaVisible = true,
displayPolygonInfo = false,
locationState = LocationState.FIXED,
isManualCaptureEnabled = true,
forcedLocationAccuracy = 10,
lastGPSLocation = null,
searching = false,
)

private val previewActions = MapSelectorScreenActions(
onBackClicked = { },
loadMap = {},
configurePolygonInfoRecycler = {},
onClearLocation = {},
onSearchLocation = {},
onLocationSelected = {},
onSearchCaptureMode = {},
onButtonMode = {},
onSearchOnAreaClick = {},
onMyLocationButtonClick = {},
onDoneButtonClick = {},
)
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ class MapSelectorViewModel(
isManualCaptureEnabled = mapStyleConfig.isManualCaptureEnabled(),
forcedLocationAccuracy = mapStyleConfig.getForcedLocationAccuracy(),
lastGPSLocation = null,
searching = false,
),
)

Expand Down Expand Up @@ -129,6 +130,7 @@ class MapSelectorViewModel(
displayPolygonInfo: Boolean = _screenState.value.displayPolygonInfo,
locationState: LocationState = _screenState.value.locationState,
lastGPSLocation: SelectedLocation.GPSResult? = _screenState.value.lastGPSLocation,
searching: Boolean = _screenState.value.searching,
) {
_screenState.update {
it.copy(
Expand All @@ -141,6 +143,7 @@ class MapSelectorViewModel(
displayPolygonInfo = displayPolygonInfo,
locationState = locationState,
lastGPSLocation = lastGPSLocation,
searching = searching,
)
}
}
Expand Down Expand Up @@ -258,6 +261,7 @@ class MapSelectorViewModel(
regionToSearch: AvailableLatLngBounds? = _currentVisibleRegion,
) {
if (_screenState.value.captureMode.isSearch()) {
updateScreenState(searching = true)
val filteredPreviousLocation =
searchLocationManager.getAvailableLocations(query)
val searchItems = geocoder.getLocationFromName(query, regionToSearch)
Expand All @@ -273,6 +277,7 @@ class MapSelectorViewModel(
locationItems = locationItems,
selectedLocation = SelectedLocation.None(),
searchOnAreaVisible = false,
searching = false,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@ class MapSelectorViewModelTest {
assertTrue(state1.captureMode == MapSelectorViewModel.CaptureMode.SEARCH)
assertTrue(state1.locationItems.isEmpty())
mapSelectorViewModel.onSearchLocation("Address")
val searchingItem = awaitItem()
assertTrue(searchingItem.searching)
assertTrue(searchingItem.locationItems.isEmpty())
val item2 = awaitItem()
assertTrue(item2.locationItems == mockedLocationItemSearchResults)
assertTrue(!item2.searchOnAreaVisible)
Expand Down Expand Up @@ -336,7 +339,7 @@ class MapSelectorViewModelTest {
) doReturn mockedOtherRegionLocationItemSearchResults

mapSelectorViewModel.onSearchOnAreaClick()
1
2
},
then = { screenState ->
assertEquals(false, screenState.searchOnAreaVisible)
Expand Down Expand Up @@ -377,6 +380,7 @@ class MapSelectorViewModelTest {
viewModel.initSearchMode()
awaitItem()
viewModel.onSearchLocation("Address")
assertTrue(awaitItem().searching)
with(awaitItem()) {
assertTrue(locationItems.isNotEmpty())
assertTrue(captureMode == MapSelectorViewModel.CaptureMode.SEARCH)
Expand Down

0 comments on commit f732d99

Please sign in to comment.