169 lines
5.0 KiB
Kotlin
169 lines
5.0 KiB
Kotlin
package com.danilafe.fencelessgrazing.ui.activities
|
|
|
|
import androidx.appcompat.app.AppCompatActivity
|
|
import android.os.Bundle
|
|
import android.os.PersistableBundle
|
|
import android.view.View
|
|
import android.widget.Toast
|
|
import androidx.appcompat.app.AlertDialog
|
|
import com.android.volley.RequestQueue
|
|
import com.android.volley.Response
|
|
import com.android.volley.toolbox.Volley
|
|
import com.danilafe.fencelessgrazing.R
|
|
import com.danilafe.fencelessgrazing.model.CollarPos
|
|
import com.danilafe.fencelessgrazing.requests.authenticated.SetBoundaryRequest
|
|
import com.danilafe.fencelessgrazing.ui.components.GrazingPolygon
|
|
import org.osmdroid.util.GeoPoint
|
|
import org.osmdroid.views.MapView
|
|
import org.osmdroid.views.overlay.Marker
|
|
import org.osmdroid.views.overlay.Polygon
|
|
|
|
/**
|
|
* Activity used to update a grazing boundary for a particular collar.
|
|
*/
|
|
class BoundaryEditorActivity : AppCompatActivity(),
|
|
Marker.OnMarkerDragListener,
|
|
Marker.OnMarkerClickListener {
|
|
|
|
/**
|
|
* The map displaying the boundary vertices and polygon.
|
|
*/
|
|
private lateinit var map: MapView
|
|
|
|
/**
|
|
* The list of markers representing the new grazing boundary's edges.
|
|
*/
|
|
private val markers: MutableList<Marker> = mutableListOf()
|
|
|
|
/**
|
|
* The polygon used to display the grazing area on the [map].
|
|
*/
|
|
private lateinit var polygon: GrazingPolygon
|
|
|
|
/**
|
|
* The center around which the [map] was originally centered,
|
|
* used also for creating new vertices.
|
|
*/
|
|
private lateinit var center: GeoPoint
|
|
|
|
/**
|
|
* The identifier of the collar whose boundary is being changed.
|
|
*/
|
|
private var identifier: Int = -1
|
|
|
|
/**
|
|
* The Volley queue used for sending API requests.
|
|
*/
|
|
private lateinit var queue: RequestQueue
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
super.onCreate(savedInstanceState)
|
|
setContentView(R.layout.activity_boundary_editor)
|
|
|
|
val requestedCenter = intent.getParcelableExtra<CollarPos>("center")!!
|
|
center = requestedCenter.toGeoPoint()
|
|
identifier = intent.getIntExtra("identifier", -1)
|
|
queue = Volley.newRequestQueue(applicationContext)
|
|
|
|
map = findViewById(R.id.editorMap)
|
|
polygon = GrazingPolygon(map)
|
|
map.overlays.add(polygon)
|
|
map.controller.setZoom(9.5)
|
|
map.controller.setCenter(center)
|
|
}
|
|
|
|
/**
|
|
* Removes a marker from the [map].
|
|
*/
|
|
private fun removeMarker(m: Marker) {
|
|
markers.remove(m)
|
|
map.overlays.remove(m)
|
|
updatePolygon()
|
|
map.invalidate()
|
|
}
|
|
|
|
/**
|
|
* Sends the current list of points to the API endpoint, closing
|
|
* the activity if successful.
|
|
*/
|
|
fun sendBoundary(v: View) {
|
|
val request = SetBoundaryRequest(
|
|
getString(R.string.apiUrl),
|
|
getSharedPreferences("FencelessGrazing",0).getString("token",null)!!,
|
|
identifier, markers.map {
|
|
CollarPos(it.position.longitude.toString(), it.position.latitude.toString())
|
|
},
|
|
Response.Listener<String> {
|
|
finish()
|
|
},
|
|
Response.ErrorListener {
|
|
Toast.makeText(
|
|
this,
|
|
"Failed to update grazing boundaries",
|
|
Toast.LENGTH_SHORT).show()
|
|
}
|
|
)
|
|
queue.add(request)
|
|
}
|
|
|
|
/**
|
|
* Adds a new marker to the [map], starting it at the previously-configured
|
|
* [center].
|
|
*/
|
|
fun addMarker(v : View) {
|
|
if(markers.size >= 10) {
|
|
Toast.makeText(
|
|
this,
|
|
"Cannot add more than ten vertices to grazing boundary",
|
|
Toast.LENGTH_SHORT).show()
|
|
return
|
|
}
|
|
|
|
val newMarker = Marker(map)
|
|
newMarker.isDraggable = true
|
|
newMarker.setOnMarkerClickListener(this)
|
|
newMarker.setOnMarkerDragListener(this)
|
|
newMarker.position = center
|
|
markers.add(newMarker)
|
|
map.overlays.add(newMarker)
|
|
updatePolygon()
|
|
map.invalidate()
|
|
}
|
|
|
|
/**
|
|
* Ensures that the polygon's vertices are synchronized
|
|
* with the user-placed markers, making it so that the
|
|
* grazing area is visible to the user.
|
|
*/
|
|
private fun updatePolygon() {
|
|
polygon.points.clear()
|
|
if(markers.isEmpty()) return
|
|
val newPoints = markers.map { it.position }
|
|
polygon.points = newPoints
|
|
polygon.points.add(newPoints.first())
|
|
}
|
|
|
|
override fun onMarkerDragEnd(marker: Marker?) {
|
|
updatePolygon()
|
|
map.invalidate()
|
|
}
|
|
|
|
override fun onMarkerDragStart(marker: Marker?) {
|
|
|
|
}
|
|
|
|
override fun onMarkerDrag(marker: Marker?) {
|
|
|
|
}
|
|
|
|
override fun onMarkerClick(m: Marker, mv: MapView): Boolean {
|
|
AlertDialog.Builder(this)
|
|
.setTitle("Delete Marker")
|
|
.setMessage("Do you want to delete this marker?")
|
|
.setPositiveButton("Delete") { _, _ -> removeMarker(m) }
|
|
.setNegativeButton("Cancel") { d, _ -> d.dismiss() }
|
|
.show()
|
|
return true
|
|
}
|
|
}
|