Meshtastic-Android/app/src/main/java/com/geeksville/mesh/ui/MapFragment.kt

184 lines
5.9 KiB
Kotlin
Raw Normal View History

2020-03-11 14:45:49 -07:00
package com.geeksville.mesh.ui
2020-03-30 15:00:18 -07:00
import android.graphics.Color
2020-03-30 11:56:59 -07:00
import android.os.Bundle
2020-04-07 11:27:51 -07:00
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Observer
2020-03-30 10:26:16 -07:00
import com.geeksville.android.Logging
import com.geeksville.mesh.NodeInfo
2020-03-11 18:13:44 -07:00
import com.geeksville.mesh.R
import com.geeksville.mesh.model.UIViewModel
2020-03-30 12:47:01 -07:00
import com.mapbox.geojson.Feature
import com.mapbox.geojson.FeatureCollection
import com.mapbox.geojson.Point
import com.mapbox.mapboxsdk.camera.CameraPosition
2020-03-30 13:06:41 -07:00
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory
import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.geometry.LatLngBounds
2020-03-30 10:26:16 -07:00
import com.mapbox.mapboxsdk.maps.MapView
2020-04-07 12:13:50 -07:00
import com.mapbox.mapboxsdk.maps.MapboxMap
2020-03-30 11:56:59 -07:00
import com.mapbox.mapboxsdk.maps.Style
2020-03-30 15:00:18 -07:00
import com.mapbox.mapboxsdk.style.expressions.Expression
2020-03-30 12:47:01 -07:00
import com.mapbox.mapboxsdk.style.layers.Property
2020-03-30 15:00:18 -07:00
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.*
2020-03-30 12:47:01 -07:00
import com.mapbox.mapboxsdk.style.layers.SymbolLayer
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource
2020-03-11 14:45:49 -07:00
2020-04-07 11:27:51 -07:00
class MapFragment : ScreenFragment("Map"), Logging {
2020-04-07 12:13:50 -07:00
private val model: UIViewModel by activityViewModels()
2020-04-07 12:13:50 -07:00
private val nodeSourceId = "node-positions"
private val nodeLayerId = "node-layer"
private val labelLayerId = "label-layer"
private val markerImageId = "my-marker-image"
private val nodePositions = GeoJsonSource(nodeSourceId)
private val nodeLayer = SymbolLayer(nodeLayerId, nodeSourceId).withProperties(
iconImage(markerImageId),
iconAnchor(Property.ICON_ANCHOR_BOTTOM),
iconAllowOverlap(true)
)
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 fun onNodesChanged(map: MapboxMap, nodes: Collection<NodeInfo>) {
val nodesWithPosition = nodes.filter { it.validPosition != null }
/**
* Using the latest nodedb, generate geojson features
*/
fun getCurrentNodes(): FeatureCollection {
// Find all nodes with valid locations
2020-04-07 12:13:50 -07:00
val locations = nodesWithPosition.map { node ->
val p = node.position!!
debug("Showing on map: $node")
2020-04-07 12:13:50 -07:00
val f = Feature.fromGeometry(
Point.fromLngLat(
p.longitude,
p.latitude
)
2020-04-07 12:13:50 -07:00
)
node.user?.let {
f.addStringProperty("name", it.longName)
}
f
2020-04-07 12:13:50 -07:00
}
return FeatureCollection.fromFeatures(locations)
}
2020-04-07 12:13:50 -07:00
fun zoomToNodes(map: MapboxMap) {
if (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(nodes.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)
2020-04-07 12:13:50 -07:00
}
}
nodePositions.setGeoJson(getCurrentNodes()) // Update node positions
zoomToNodes(map)
2020-04-07 12:13:50 -07:00
}
2020-04-07 11:27:51 -07:00
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(R.layout.map_view, container, false)
2020-03-11 14:45:49 -07:00
2020-04-07 11:27:51 -07:00
lateinit var mapView: MapView
2020-03-30 11:56:59 -07:00
2020-04-07 11:27:51 -07:00
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
2020-03-30 11:56:59 -07:00
2020-04-07 11:27:51 -07:00
mapView = view.findViewById(R.id.mapView)
mapView.onCreate(savedInstanceState)
2020-03-30 11:56:59 -07:00
2020-04-07 11:27:51 -07:00
mapView.getMapAsync { map ->
2020-03-30 11:56:59 -07:00
2020-04-07 11:27:51 -07:00
// val markerIcon = BitmapFactory.decodeResource(context.resources, R.drawable.ic_twotone_person_pin_24)
val markerIcon = requireActivity().getDrawable(R.drawable.ic_twotone_person_pin_24)!!
2020-04-07 11:27:51 -07:00
2020-03-30 12:47:01 -07:00
map.setStyle(Style.OUTDOORS) { style ->
style.addSource(nodePositions)
2020-03-30 15:00:18 -07:00
style.addImage(markerImageId, markerIcon)
2020-03-30 12:47:01 -07:00
style.addLayer(nodeLayer)
2020-03-30 15:00:18 -07:00
style.addLayer(labelLayer)
2020-03-30 10:26:16 -07:00
}
2020-03-30 13:06:41 -07:00
model.nodeDB.nodes.observe(viewLifecycleOwner, Observer { nodes ->
onNodesChanged(map, nodes.values)
})
2020-03-30 15:00:18 -07:00
//map.uiSettings.isScrollGesturesEnabled = true
//map.uiSettings.isZoomGesturesEnabled = true
2020-03-30 10:26:16 -07:00
}
2020-03-11 14:45:49 -07:00
}
2020-04-07 11:27:51 -07:00
override fun onPause() {
mapView.onPause()
super.onPause()
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onStop() {
mapView.onStop()
super.onStop()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onDestroy() {
mapView.onDestroy()
super.onDestroy()
}
2020-03-11 14:45:49 -07:00
2020-04-07 11:27:51 -07:00
override fun onSaveInstanceState(outState: Bundle) {
mapView.onSaveInstanceState(outState)
super.onSaveInstanceState(outState)
2020-03-11 14:45:49 -07:00
}
}
2020-04-07 11:27:51 -07:00