Get the boundary setting activity working.

This commit is contained in:
Danila Fedorin 2020-05-13 23:53:08 -07:00
parent 7cd3706b7d
commit 48a6d1fff1
4 changed files with 179 additions and 1 deletions

View File

@ -1,9 +1,14 @@
package com.danilafe.fencelessgrazing.model
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
/**
* GPS coordinate returned by many of the project's API endpoints.
*
* @param longitude the longitude of the GPS point.
* @param latitude the latitude of the GPS point.
*/
data class CollarPos(val longitude: String, val latitude: String)
@Parcelize
data class CollarPos(val longitude: String, val latitude: String) : Parcelable

View File

@ -0,0 +1,30 @@
package com.danilafe.fencelessgrazing.requests.authenticated
import com.android.volley.Response
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.StringRequest
import com.google.gson.Gson
import com.google.gson.JsonObject
import org.json.JSONObject
open class AuthenticatedPostRequest<T>(
private val value: T,
baseUrl: String,
apiEndpoint: String,
private val token: String,
listener: Response.Listener<String>,
error: Response.ErrorListener
) : StringRequest(Method.POST, "${baseUrl}${apiEndpoint}",
listener, error
) {
override fun getBody(): ByteArray = Gson().toJson(value).toByteArray()
override fun getBodyContentType(): String = "application/json"
override fun getHeaders(): MutableMap<String, String> {
val newMap = HashMap(super.getHeaders())
newMap["Authorization"] = "Bearer $token"
return newMap
}
}

View File

@ -0,0 +1,16 @@
package com.danilafe.fencelessgrazing.requests.authenticated
import com.android.volley.Response
import com.danilafe.fencelessgrazing.model.CollarPos
class SetBoundaryRequest(
baseUrl: String,
token: String,
identifier: Int,
coordinates: List<CollarPos>,
listener: Response.Listener<String>,
error: Response.ErrorListener
) : AuthenticatedPostRequest<List<CollarPos>>(
coordinates, baseUrl, "/collars/${identifier}/boundary/set",
token, listener, error
)

View File

@ -0,0 +1,127 @@
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
class BoundaryEditorActivity : AppCompatActivity(),
Marker.OnMarkerDragListener,
Marker.OnMarkerClickListener {
private lateinit var map: MapView
private val markers: MutableList<Marker> = mutableListOf()
private lateinit var polygon: GrazingPolygon
private lateinit var center: GeoPoint
private var identifier: Int = -1
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 = GeoPoint(
requestedCenter.longitude.toDouble(),
requestedCenter.latitude.toDouble())
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)
}
private fun removeMarker(m: Marker) {
markers.remove(m)
map.overlays.remove(m)
updatePolygon()
map.invalidate()
}
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)
}
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()
}
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
}
}