androidMain.tech.skot.libraries.map.MapBoxInteractionHelper.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of viewlegacy_mapbox Show documentation
Show all versions of viewlegacy_mapbox Show documentation
viewlegacy_mapbox module for SK-Map skot library
The newest version!
package tech.skot.libraries.map
import android.annotation.SuppressLint
import android.content.Context
import android.content.res.Resources
import android.graphics.Bitmap
import androidx.collection.LruCache
import com.mapbox.geojson.Point
import com.mapbox.maps.CoordinateBounds
import com.mapbox.maps.MapView
import com.mapbox.maps.plugin.annotation.AnnotationConfig
import com.mapbox.maps.plugin.annotation.annotations
import com.mapbox.maps.plugin.annotation.generated.*
import com.mapbox.maps.toCameraOptions
import tech.skot.core.toColor
import tech.skot.core.view.Dimen
import tech.skot.core.view.DimenDP
import tech.skot.core.view.DimenRef
@SuppressLint("PotentialBehaviorOverride")
open class MapBoxInteractionHelper(
context: Context,
mapView: MapView,
memoryCache: LruCache
) : MapInteractionHelper(context, mapView, memoryCache) {
private var clickListener: OnPointAnnotationClickListener? = null
val annotationApi = mapView.annotations
val pointAnnotationManager =
annotationApi.createPointAnnotationManager(AnnotationConfig(layerId = "marker"))
val lineManager = annotationApi.createPolylineAnnotationManager(
AnnotationConfig(
layerId = "line",
belowLayerId = "marker"
)
)
val polygonManager = annotationApi.createPolygonAnnotationManager(
AnnotationConfig(
layerId = "polygon",
belowLayerId = "line"
)
)
private var items: List> = emptyList()
private var polylineItems: List> = emptyList()
private var polygonItems: List> = emptyList()
private var lastSelectedMarker: Pair? = null
override var onMarkerSelected: ((SKMapVC.Marker?) -> Unit)? = null
override var onMarkerClick: ((SKMapVC.Marker) -> Unit)? = null
override fun onDestroy() {
clickListener?.let {
pointAnnotationManager.removeClickListener(it)
}
}
private fun oldPolygonStillAvailable(
polyline: SKMapVC.Polygon,
polylines: List
): Boolean {
return if (polyline.id != null) {
polylines.any {
polyline.id == it.id
}
} else {
false
}
}
private fun newPolygonAlreadyExist(polyline: SKMapVC.Polygon): Boolean {
return if (polyline.id != null) {
this.polygonItems.any {
polyline.id == it.first.id
}
} else {
false
}
}
private fun oldLineStillAvailable(
polyline: SKMapVC.Polyline,
polylines: List
): Boolean {
return if (polyline.id != null) {
polylines.any {
polyline.id == it.id
}
} else {
false
}
}
private fun newLineAlreadyExist(polyline: SKMapVC.Polyline): Boolean {
return if (polyline.id != null) {
this.polylineItems.any {
polyline.id == it.first.id
}
} else {
false
}
}
private fun oldMarkerStillAvailable(
marker: SKMapVC.Marker,
markers: List
): Boolean {
return if (marker.id != null) {
markers.any {
marker.id == it.id
}
} else {
false
}
}
private fun newMarkerAlreadyExist(marker: SKMapVC.Marker): Boolean {
return if (marker.id != null) {
this.items.any {
marker.id == it.first.id
}
} else {
false
}
}
override fun addLines(polylines: List) {
mapView.getMapboxMap { map ->
//first parts -> items in map still exist in new markers list
//second parts -> items in maps no longer exist in new markers list
val (oldItemsToUpdate, oldItemsToRemove) = this.polylineItems.partition { currentItem ->
oldLineStillAvailable(currentItem.first, polylines)
}
//first parts -> update
//second parts -> add
val (newValueForItemsToUpdate, newItemsToAdd) = polylines.partition { marker ->
newLineAlreadyExist(marker)
}
//items to remove from map
oldItemsToRemove.forEach { pair ->
if (pair.first.id == lastSelectedMarker?.first?.id) {
lastSelectedMarker = null
}
lineManager.delete(pair.second)
}
//items to update on map
val updatedMarker = oldItemsToUpdate.mapNotNull { currentPair ->
newValueForItemsToUpdate.find {
it.id == currentPair.first.id
}?.let {
Pair(it, currentPair.second.apply {
this.points = it.points.map {
Point.fromLngLat(
it.second,
it.first,
)
}
lineColorInt = it.color.toColor(context)
lineWidth = convertLineWidth(it.lineWidth)
})
}
}
//items to add to map
val optionsToAdd = newItemsToAdd.map { line ->
PolylineAnnotationOptions()
.withPoints(line.points.map {
Point.fromLngLat(it.second, it.first)
})
.withLineWidth(
convertLineWidth(line.lineWidth)
)
.withLineColor(line.color.toColor(context))
}
val annotations = lineManager.create(options = optionsToAdd)
val addedLines = polylines.zip(annotations)
this.polylineItems = updatedMarker + addedLines
}
}
override fun addPolygons(polygons: List) {
mapView.getMapboxMap { map ->
//first parts -> items in map still exist in new markers list
//second parts -> items in maps no longer exist in new markers list
val (oldItemsToUpdate, oldItemsToRemove) = this.polygonItems.partition { currentItem ->
oldPolygonStillAvailable(currentItem.first, polygons)
}
//first parts -> update
//second parts -> add
val (newValueForItemsToUpdate, newItemsToAdd) = polygons.partition { marker ->
newPolygonAlreadyExist(marker)
}
//items to remove from map
oldItemsToRemove.forEach { pair ->
if (pair.first.id == lastSelectedMarker?.first?.id) {
lastSelectedMarker = null
}
polygonManager.delete(pair.second)
}
//items to update on map
val updatedMarker = oldItemsToUpdate.mapNotNull { currentPair ->
newValueForItemsToUpdate.find {
it.id == currentPair.first.id
}?.let {
Pair(it, currentPair.second.apply {
this.points = listOf(it.points.map {
Point.fromLngLat(
it.second,
it.first,
)
})
fillColorInt = it.fillColor.toColor(context)
// lineWidth = convertLineWidth(it.lineWidth)
})
}
}
//items to add to map
val optionsToAdd = newItemsToAdd.map { line ->
PolygonAnnotationOptions()
.withPoints(listOf(line.points.map {
Point.fromLngLat(it.second, it.first)
}))
.withFillColor(line.fillColor.toColor(context))
// .withLineColor(line.strokeColor.toColor(context))
}
val annotations = polygonManager.create(options = optionsToAdd)
val addedLines = polygons.zip(annotations)
this.polygonItems = updatedMarker + addedLines
}
}
private fun convertLineWidth(dimen: Dimen): Double {
return when (dimen) {
is DimenDP -> dimen.dp.toDouble()
is DimenRef -> (context.resources.getDimension(dimen.res) / Resources.getSystem().displayMetrics.density).toDouble()
else -> 1.0
}
}
override fun addMarkers(markers: List) {
mapView.getMapboxMap { map ->
//first parts -> items in map still exist in new markers list
//second parts -> items in maps no longer exist in new markers list
val (oldItemsToUpdate, oldItemsToRemove) = this.items.partition { currentItem ->
oldMarkerStillAvailable(currentItem.first, markers)
}
//first parts -> update
//second parts -> add
val (newValueForItemsToUpdate, newItemsToAdd) = markers.partition { marker ->
newMarkerAlreadyExist(marker)
}
//items to remove from map
if(oldItemsToRemove.any { it.first.id == lastSelectedMarker?.first?.id}) {
lastSelectedMarker = null
}
pointAnnotationManager.delete(oldItemsToRemove.map { it.second })
//items to update on map
val updatedMarker = oldItemsToUpdate.mapNotNull { currentPair ->
newValueForItemsToUpdate.find {
it.id == currentPair.first.id
}?.let {
Pair(it, currentPair.second.apply {
this.geometry = Point.fromLngLat(
it.position.second,
it.position.first,
)
getIcon(it, lastSelectedMarker?.first?.id == it.id)?.let {
this.iconImageBitmap = it
}
})
}
}
val optionsToAdd = mutableListOf()
//items to add to map
val markers = newItemsToAdd.map { skMarker ->
val options = PointAnnotationOptions()
.withGeometry(
Point.fromLngLat(
skMarker.position.second,
skMarker.position.first
)
)
getIcon(skMarker, false)?.let {
options.withIconImage(it)
}
optionsToAdd.add(options)
skMarker
}
val annotations = pointAnnotationManager.create(optionsToAdd)
val addedMarkers = markers.zip(annotations)
this.items = updatedMarker + addedMarkers
}
}
init {
mapView.getMapboxMap {
clickListener = OnPointAnnotationClickListener { annotation ->
val item = items.find { (_, marker) ->
marker == annotation
}
item?.let {
onMarkerClick?.invoke(item.first)
}
true
}.apply {
pointAnnotationManager.addClickListener(this)
}
}
}
override fun onOnMapBoundsChange(onMapBoundsChange: ((SKMapVC.LatLngBounds) -> Unit)?) {
mapView.getMapboxMap { mapBox ->
mapBox.addOnCameraChangeListener {
val cameraState = mapBox.cameraState
val bounds = mapBox.coordinateBoundsForCamera(cameraState.toCameraOptions())
onMapBoundsChange?.invoke(getMapBounds(bounds))
}
}
}
protected fun getMapBounds(bounds: CoordinateBounds): SKMapVC.LatLngBounds {
return SKMapVC.LatLngBounds(
bounds.north() to bounds.east(),
bounds.south() to bounds.west()
)
}
override fun onSelectedMarker(selectedMarker: SKMapVC.Marker?) {
onMarkerSelected?.invoke(selectedMarker)
mapView.getMapboxMap { mapBoxMap ->
lastSelectedMarker?.let { current ->
getIcon(current.first, false)?.let {
current.second.iconImage = null
current.second.iconImageBitmap = it
current.second.iconOpacity = 1.0
pointAnnotationManager.update(current.second)
}
}
lastSelectedMarker = items.find {
it.first.id == selectedMarker?.id
}?.also { newSelectedMarker ->
getIcon(newSelectedMarker.first, true)?.let {
newSelectedMarker.second.iconImage = null
newSelectedMarker.second.iconImageBitmap = it
newSelectedMarker.second.iconOpacity = 1.0
pointAnnotationManager.update(newSelectedMarker.second)
}
}
}
}
}