Migrating to Mapbox API V10

This commit is contained in:
Jackson Rosenthal
2022-02-04 21:58:00 -05:00
parent 88a4825b28
commit ed98232263
5 changed files with 116 additions and 128 deletions

View File

@@ -6,6 +6,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Observer
import com.geeksville.android.GeeksvilleApplication
@@ -17,20 +18,17 @@ import com.geeksville.util.formatAgo
import com.mapbox.geojson.Feature
import com.mapbox.geojson.FeatureCollection
import com.mapbox.geojson.Point
import com.mapbox.mapboxsdk.camera.CameraPosition
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory
import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.geometry.LatLngBounds
import com.mapbox.mapboxsdk.maps.MapView
import com.mapbox.mapboxsdk.maps.MapboxMap
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.style.expressions.Expression
import com.mapbox.mapboxsdk.style.layers.Property
import com.mapbox.mapboxsdk.style.layers.Property.TEXT_ANCHOR_TOP
import com.mapbox.mapboxsdk.style.layers.Property.TEXT_JUSTIFY_AUTO
import com.mapbox.mapboxsdk.style.layers.PropertyFactory.*
import com.mapbox.mapboxsdk.style.layers.SymbolLayer
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource
import com.mapbox.mapboxsdk.style.layers.PropertyFactory.textAllowOverlap
import com.mapbox.maps.MapView
import com.mapbox.maps.CameraOptions
import com.mapbox.maps.MapboxMap
import com.mapbox.maps.Style
import com.mapbox.maps.extension.style.expressions.generated.Expression
import com.mapbox.maps.extension.style.layers.generated.SymbolLayer
import com.mapbox.maps.extension.style.layers.properties.generated.IconAnchor
import com.mapbox.maps.extension.style.layers.properties.generated.TextAnchor
import com.mapbox.maps.extension.style.layers.properties.generated.TextJustify
import com.mapbox.maps.extension.style.sources.generated.GeoJsonSource
class MapFragment : ScreenFragment("Map"), Logging {
@@ -42,22 +40,19 @@ class MapFragment : ScreenFragment("Map"), Logging {
private val labelLayerId = "label-layer"
private val markerImageId = "my-marker-image"
private val nodePositions = GeoJsonSource(nodeSourceId)
private val nodePositions = GeoJsonSource(GeoJsonSource.Builder(nodeSourceId))
private val nodeLayer = SymbolLayer(nodeLayerId, nodeSourceId).withProperties(
iconImage(markerImageId),
iconAnchor(Property.ICON_ANCHOR_BOTTOM),
iconAllowOverlap(true)
)
private val nodeLayer = SymbolLayer(nodeLayerId, nodeSourceId)
.iconImage(markerImageId)
.iconAnchor(IconAnchor.BOTTOM)
private val labelLayer = SymbolLayer(labelLayerId, nodeSourceId).withProperties(
textField(Expression.get("name")),
textSize(12f),
textColor(Color.RED),
textVariableAnchor(arrayOf(TEXT_ANCHOR_TOP)),
textJustify(TEXT_JUSTIFY_AUTO),
textAllowOverlap(true)
)
private val labelLayer = SymbolLayer(labelLayerId, nodeSourceId)
.textField(Expression.get("name"))
.textSize()
.textColor(Color.RED)
.textVariableAnchor(arrayListOf(TextAnchor.TOP.toString()))
.textJustify(TextJustify.AUTO)
.textAllowOverlap(true)
private fun onNodesChanged(map: MapboxMap, nodes: Collection<NodeInfo>) {
@@ -89,33 +84,34 @@ class MapFragment : ScreenFragment("Map"), Logging {
}
nodePositions.setGeoJson(getCurrentNodes()) // Update node positions
// nodePositions.setGeoJson(getCurrentNodes()) // Update node positions
}
fun zoomToNodes(map: MapboxMap) {
val nodesWithPosition =
model.nodeDB.nodes.value?.values?.filter { it.validPosition != null }
if (nodesWithPosition != null && nodesWithPosition.isNotEmpty()) {
val update = if (nodesWithPosition.size >= 2) {
// Multiple nodes, make them all fit on the map view
val bounds = LatLngBounds.Builder()
// Add all positions
bounds.includes(nodesWithPosition.map { it.position!! }
.map { LatLng(it.latitude, it.longitude) })
CameraUpdateFactory.newLatLngBounds(bounds.build(), 150)
} else {
// Only one node, just zoom in on it
val it = nodesWithPosition[0].position!!
val cameraPos = CameraPosition.Builder().target(
LatLng(it.latitude, it.longitude)
).zoom(9.0).build()
CameraUpdateFactory.newCameraPosition(cameraPos)
}
map.animateCamera(update, 1000)
// val update = if (nodesWithPosition.size >= 2) {
// // Multiple nodes, make them all fit on the map view
// val bounds = LatLngBounds.Builder()
//
// // Add all positions
// bounds.includes(nodesWithPosition.map { it.position!! }
// .map { LatLng(it.latitude, it.longitude) })
//
// CameraUpdateFactory.newLatLngBounds(bounds.build(), 150)
// } else {
// // Only one node, just zoom in on it
// val it = nodesWithPosition[0].position!!
//
// val cameraPos = CameraPosition.Builder().target(
// LatLng(it.latitude, it.longitude)
// ).zoom(9.0).build()
// CameraUpdateFactory.newCameraPosition(cameraPos)
// }
// map.animateCamera(update, 1000)
// }
// }
}
}
@@ -141,7 +137,7 @@ class MapFragment : ScreenFragment("Map"), Logging {
* Mapbox native code can crash painfully if you ever call a mapbox view function while the view is not actively being show
*/
private val isViewVisible: Boolean
get() = !(mapView?.isDestroyed ?: true)
get() = mapView?.isVisible == true
override fun onViewCreated(viewIn: View, savedInstanceState: Bundle?) {
super.onViewCreated(viewIn, savedInstanceState)
@@ -151,50 +147,44 @@ class MapFragment : ScreenFragment("Map"), Logging {
val vIn = viewIn.findViewById<MapView>(R.id.mapView)
mapView = vIn
mapView?.let { v ->
v.onCreate(savedInstanceState)
// Each time the pane is shown start fetching new map info (we do this here instead of
// onCreate because getMapAsync can die in native code if the view goes away)
v.getMapAsync { map ->
if (view != null) { // it might have gone away by now
// val markerIcon = BitmapFactory.decodeResource(context.resources, R.drawable.ic_twotone_person_pin_24)
val markerIcon =
ContextCompat.getDrawable(
requireActivity(),
R.drawable.ic_twotone_person_pin_24
)!!
val map = v.getMapboxMap()
if (view != null) { // it might have gone away by now
// val markerIcon = BitmapFactory.decodeResource(context.resources, R.drawable.ic_twotone_person_pin_24)
val markerIcon =
ContextCompat.getDrawable(
requireActivity(),
R.drawable.ic_twotone_person_pin_24
)!!
map.setStyle(Style.OUTDOORS) { style ->
style.addSource(nodePositions)
style.addImage(markerImageId, markerIcon)
style.addLayer(nodeLayer)
style.addLayer(labelLayer)
}
map.loadStyleUri(Style.OUTDOORS)
// style.addSource(nodePositions)
// style.addImage(markerImageId, markerIcon)
// style.addLayer(nodeLayer)
// style.addLayer(labelLayer)
map.uiSettings.isRotateGesturesEnabled = false
// Provide initial positions
model.nodeDB.nodes.value?.let { nodes ->
onNodesChanged(map, nodes.values)
}
// map.uiSettings.isRotateGesturesEnabled = false
// Provide initial positions
model.nodeDB.nodes.value?.let { nodes ->
onNodesChanged(map, nodes.values)
}
// Any times nodes change update our map
model.nodeDB.nodes.observe(viewLifecycleOwner, Observer { nodes ->
if (isViewVisible)
onNodesChanged(map, nodes.values)
})
zoomToNodes(map)
}
// Any times nodes change update our map
model.nodeDB.nodes.observe(viewLifecycleOwner, Observer { nodes ->
if (isViewVisible)
onNodesChanged(map, nodes.values)
})
zoomToNodes(map)
}
}
}
override fun onPause() {
mapView?.onPause()
super.onPause()
}
override fun onStart() {
super.onStart()
mapView?.onStart()
@@ -205,11 +195,6 @@ class MapFragment : ScreenFragment("Map"), Logging {
super.onStop()
}
override fun onResume() {
super.onResume()
mapView?.onResume()
}
override fun onDestroyView() {
super.onDestroyView()
mapView?.onDestroy()
@@ -217,18 +202,18 @@ class MapFragment : ScreenFragment("Map"), Logging {
override fun onSaveInstanceState(outState: Bundle) {
mapView?.let {
if (!it.isDestroyed)
it.onSaveInstanceState(outState)
super.onSaveInstanceState(outState)
}
super.onSaveInstanceState(outState)
}
override fun onLowMemory() {
mapView?.let {
if (!it.isDestroyed)
it.onLowMemory()
}
super.onLowMemory()
mapView?.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView?.onDestroy()
}
}