Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libnavui-androidauto/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Mapbox welcomes participation and contributions from everyone.
## Unreleased
#### Features
#### Bug fixes and improvements
- Removed `MapboxNavigation` from `PlaceListOnMapScreen`. [#6371](https://github.com/mapbox/mapbox-navigation-android/pull/6371)

## androidauto-v0.12.0 - Sep 26, 2022
### Changelog
Expand Down
11 changes: 10 additions & 1 deletion libnavui-androidauto/api/current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -604,13 +604,22 @@ package com.mapbox.androidauto.car.placeslistonmap {
public static final class PlacesListOnMapLayerUtil.Companion {
}

public final class PlacesListOnMapManager implements com.mapbox.maps.extension.androidauto.MapboxCarMapObserver {
ctor public PlacesListOnMapManager(com.mapbox.androidauto.car.placeslistonmap.PlacesListOnMapProvider placesListOnMapProvider);
method public androidx.car.app.model.ItemList? currentItemList();
method public kotlinx.coroutines.flow.StateFlow<java.util.List<com.mapbox.androidauto.car.search.PlaceRecord>> getPlaceRecords();
method public kotlinx.coroutines.flow.StateFlow<com.mapbox.androidauto.car.search.PlaceRecord> getPlaceSelected();
property public final kotlinx.coroutines.flow.StateFlow<java.util.List<com.mapbox.androidauto.car.search.PlaceRecord>> placeRecords;
property public final kotlinx.coroutines.flow.StateFlow<com.mapbox.androidauto.car.search.PlaceRecord> placeSelected;
}

public interface PlacesListOnMapProvider {
method public void cancel();
method public suspend Object? getPlaces(kotlin.coroutines.Continuation<? super com.mapbox.bindgen.Expected<com.mapbox.androidauto.car.search.GetPlacesError,java.util.List<? extends com.mapbox.androidauto.car.search.PlaceRecord>>>);
}

@com.mapbox.maps.MapboxExperimental public final class PlacesListOnMapScreen extends androidx.car.app.Screen {
ctor @UiThread public PlacesListOnMapScreen(com.mapbox.androidauto.car.search.SearchCarContext searchCarContext, com.mapbox.androidauto.car.placeslistonmap.PlacesListOnMapProvider placesProvider, com.mapbox.androidauto.car.placeslistonmap.PlacesListItemMapper placesListItemMapper, java.util.List<? extends com.mapbox.androidauto.car.action.MapboxActionProvider> actionProviders, com.mapbox.androidauto.car.placeslistonmap.PlacesListOnMapLayerUtil placesLayerUtil = com.mapbox.androidauto.car.placeslistonmap.PlacesListOnMapLayerUtil());
ctor @UiThread public PlacesListOnMapScreen(com.mapbox.androidauto.car.search.SearchCarContext searchCarContext, com.mapbox.androidauto.car.placeslistonmap.PlacesListOnMapProvider placesProvider, java.util.List<? extends com.mapbox.androidauto.car.action.MapboxActionProvider> actionProviders);
method public androidx.car.app.model.ItemList getItemList();
method public androidx.car.app.model.Template onGetTemplate();
method public void setItemList(androidx.car.app.model.ItemList);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import androidx.core.graphics.drawable.IconCompat
import com.mapbox.androidauto.R
import com.mapbox.androidauto.car.feedback.core.CarFeedbackSender
import com.mapbox.androidauto.car.feedback.ui.CarFeedbackAction
import com.mapbox.androidauto.car.placeslistonmap.PlaceMarkerRenderer
import com.mapbox.androidauto.car.placeslistonmap.PlacesListItemMapper
import com.mapbox.androidauto.car.placeslistonmap.PlacesListOnMapScreen
import com.mapbox.androidauto.car.search.FavoritesApi
import com.mapbox.androidauto.car.search.PlaceSearchScreen
Expand Down Expand Up @@ -94,14 +92,6 @@ class MainActionStrip(
return PlacesListOnMapScreen(
SearchCarContext(mainCarContext),
placesProvider,
PlacesListItemMapper(
PlaceMarkerRenderer(mainCarContext.carContext),
mainCarContext
.mapboxNavigation
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's this dependency that needs to be moved, getting the unit type to become observable is a bit complicated

.navigationOptions
.distanceFormatterOptions
.unitType
),
listOf(
CarFeedbackAction(
mainCarContext.mapboxCarMap,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package com.mapbox.androidauto.car.placeslistonmap

import androidx.car.app.model.ItemList
import com.mapbox.androidauto.car.search.PlaceRecord
import com.mapbox.androidauto.internal.car.extensions.handleStyleOnAttached
import com.mapbox.androidauto.internal.car.extensions.handleStyleOnDetached
import com.mapbox.androidauto.internal.car.extensions.mapboxNavigationForward
import com.mapbox.androidauto.internal.logAndroidAuto
import com.mapbox.androidauto.navigation.location.CarAppLocation
import com.mapbox.geojson.Feature
import com.mapbox.geojson.FeatureCollection
import com.mapbox.geojson.Point
import com.mapbox.maps.MapboxExperimental
import com.mapbox.maps.extension.androidauto.MapboxCarMapObserver
import com.mapbox.maps.extension.androidauto.MapboxCarMapSurface
import com.mapbox.maps.plugin.delegates.listeners.OnStyleLoadedListener
import com.mapbox.navigation.core.MapboxNavigation
import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

@OptIn(MapboxExperimental::class)
class PlacesListOnMapManager(
private val placesListOnMapProvider: PlacesListOnMapProvider,
) : MapboxCarMapObserver {

private var carMapSurface: MapboxCarMapSurface? = null
private var coroutineScope: CoroutineScope? = null
private var styleLoadedListener: OnStyleLoadedListener? = null
private var placesListItemMapper: PlacesListItemMapper? = null
private val placesLayerUtil: PlacesListOnMapLayerUtil = PlacesListOnMapLayerUtil()
private val navigationObserver = mapboxNavigationForward(this::onAttached) { onDetached() }

private val _placeRecords = MutableStateFlow(listOf<PlaceRecord>())
val placeRecords: StateFlow<List<PlaceRecord>> = _placeRecords.asStateFlow()

private val _placeSelected = MutableStateFlow<PlaceRecord?>(null)
val placeSelected: StateFlow<PlaceRecord?> = _placeSelected.asStateFlow()

private val placeClickListener = object : PlacesListItemClickListener {
override fun onItemClick(placeRecord: PlaceRecord) {
logAndroidAuto("PlacesListOnMapScreen request $placeRecord")
_placeSelected.value = placeRecord
}
}

fun currentItemList(): ItemList? {
val carAppLocation = MapboxNavigationApp.getObserver(CarAppLocation::class)
val currentLocation = carAppLocation.navigationLocationProvider.lastLocation
?: return null
return placesListItemMapper?.mapToItemList(
currentLocation,
placeRecords.value,
placeClickListener
)
}

override fun onAttached(mapboxCarMapSurface: MapboxCarMapSurface) {
super.onAttached(mapboxCarMapSurface)
carMapSurface = mapboxCarMapSurface
coroutineScope = MainScope()
MapboxNavigationApp.registerObserver(navigationObserver)

styleLoadedListener = mapboxCarMapSurface.handleStyleOnAttached {
placesLayerUtil.initializePlacesListOnMapLayer(
it,
mapboxCarMapSurface.carContext.resources
)
loadPlaceRecords()
}
}

override fun onDetached(mapboxCarMapSurface: MapboxCarMapSurface) {
super.onDetached(mapboxCarMapSurface)
mapboxCarMapSurface.handleStyleOnDetached(styleLoadedListener)?.let {
placesLayerUtil.removePlacesListOnMapLayer(it)
}
styleLoadedListener = null
MapboxNavigationApp.unregisterObserver(navigationObserver)
carMapSurface = null
}

private fun onAttached(mapboxNavigation: MapboxNavigation) {
placesListItemMapper = PlacesListItemMapper(
PlaceMarkerRenderer(carMapSurface?.carContext!!),
mapboxNavigation
.navigationOptions
.distanceFormatterOptions
.unitType
)
}

private fun onDetached() {
placesListItemMapper = null
coroutineScope?.cancel()
coroutineScope = null
}

private fun loadPlaceRecords() {
coroutineScope?.launch {
val expectedPlaceRecords = withContext(Dispatchers.IO) {
placesListOnMapProvider.getPlaces()
}
_placeRecords.value = emptyList()
expectedPlaceRecords.fold(
{
logAndroidAuto(
"PlacesListOnMapScreen ${it.errorMessage}, ${it.throwable?.stackTrace}"
)
},
{
_placeRecords.value = it
addPlaceIconsToMap(it)
}
)
}
}

private fun addPlaceIconsToMap(places: List<PlaceRecord>) {
logAndroidAuto("PlacesListOnMapScreen addPlaceIconsToMap with ${places.size} places.")
carMapSurface?.mapSurface?.getMapboxMap()?.let { mapboxMap ->
val features = places.filter { it.coordinate != null }.map {
Feature.fromGeometry(
Point.fromLngLat(it.coordinate!!.longitude(), it.coordinate.latitude())
)
}
val featureCollection = FeatureCollection.fromFeatures(features)
mapboxMap.getStyle()?.let {
placesLayerUtil.updatePlacesListOnMapLayer(it, featureCollection)
}
}
}
}
Loading