Compare commits

...

2 Commits

9 changed files with 86 additions and 12 deletions

View File

@ -13,7 +13,8 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".ui.activities.StatisticsActivity"/>
<activity android:name=".ui.activities.BoundaryEditorActivity"></activity>
<activity android:name=".ui.activities.StatisticsActivity" />
<activity android:name=".ui.activities.CollarDetailActivity" />
<activity android:name=".ui.activities.CollarListActivity" />
<activity android:name=".ui.activities.MainActivity">

View File

@ -6,5 +6,6 @@ package com.danilafe.fencelessgrazing.model
* @param id the collar's internal unique identifier.
* @param name the collar's current designation in the system.
* @param stimulus the number of stimulus activation reports in the last 24 hours.
* @param boundary the collar's current valid grazing boundary.
*/
data class CollarDetails(val id: Int, val name: String, val stimulus: Int)
data class CollarDetails(val id: Int, val name: String, val stimulus: Int, val boundary: List<CollarPos>)

View File

@ -2,6 +2,7 @@ package com.danilafe.fencelessgrazing.model
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
import org.osmdroid.util.GeoPoint
/**
* GPS coordinate returned by many of the project's API endpoints.
@ -10,5 +11,7 @@ import kotlinx.android.parcel.Parcelize
* @param latitude the latitude of the GPS point.
*/
@Parcelize
data class CollarPos(val longitude: String, val latitude: String) : Parcelable
data class CollarPos(val longitude: String, val latitude: String) : Parcelable {
fun toGeoPoint(): GeoPoint = GeoPoint(latitude.toDouble(), longitude.toDouble())
}

View File

@ -34,9 +34,7 @@ class BoundaryEditorActivity : AppCompatActivity(),
setContentView(R.layout.activity_boundary_editor)
val requestedCenter = intent.getParcelableExtra<CollarPos>("center")!!
center = GeoPoint(
requestedCenter.longitude.toDouble(),
requestedCenter.latitude.toDouble())
center = requestedCenter.toGeoPoint()
identifier = intent.getIntExtra("identifier", -1)
queue = Volley.newRequestQueue(applicationContext)

View File

@ -1,15 +1,18 @@
package com.danilafe.fencelessgrazing.ui.activities
import android.content.Intent
import android.graphics.Color
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.TextView
import android.widget.Toast
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.model.Polygon
import com.danilafe.fencelessgrazing.requests.authenticated.CollarDetailRequest
import com.danilafe.fencelessgrazing.requests.authenticated.CollarHistoryRequest
@ -174,7 +177,7 @@ class CollarDetailActivity : AppCompatActivity() {
token,
Response.Listener {
dataPoints =
it.map { p -> GeoPoint(p.longitude.toDouble(), p.latitude.toDouble()) }
it.map { p -> p.toGeoPoint() }
},
Response.ErrorListener {
Toast.makeText(this, "Failed to retrieve history of collar", Toast.LENGTH_SHORT)
@ -199,6 +202,16 @@ class CollarDetailActivity : AppCompatActivity() {
queue.add(detailRequest)
}
fun changeGrazingBoundary(v : View) {
startActivity(Intent(this, BoundaryEditorActivity::class.java).apply {
val center = dataPoints.lastOrNull()?.let {
CollarPos(it.longitude.toString(), it.latitude.toString())
} ?: CollarPos("0", "0")
putExtra("center", center)
putExtra("identifier", collarId)
})
}
/**
* Given a new location history of the animal, configures
* updates the [map] to include the relevant elements (such as the animal's
@ -235,7 +248,7 @@ class CollarDetailActivity : AppCompatActivity() {
*/
private fun updateBoundingBox(oldValue: Polygon?, polygon: Polygon) {
if(oldValue == null) map.overlays.add(mapPolygon)
val points = polygon.dataPoints.map { GeoPoint(it.latitude.toDouble(), it.longitude.toDouble()) }
val points = polygon.dataPoints.map { it.toGeoPoint() }
val polygonPoints = points.toMutableList()
polygonPoints.add(polygonPoints[0])
mapPolygon.points = polygonPoints

View File

@ -196,7 +196,7 @@ class CollarListActivity : AppCompatActivity() {
centerSet = true
val averageLongitude = summaries.map { it.pos.longitude.toDouble() }.average()
val averageLatitude = summaries.map { it.pos.latitude.toDouble() }.average()
map.controller.setCenter(GeoPoint(averageLongitude, averageLatitude))
map.controller.setCenter(GeoPoint(averageLatitude, averageLongitude))
}
/**
@ -208,7 +208,7 @@ class CollarListActivity : AppCompatActivity() {
// Create or update overlay
val overlay = collarOverlays[it.id] ?: Marker(map)
overlay.title = it.name
overlay.position = GeoPoint(it.pos.longitude.toDouble(), it.pos.latitude.toDouble())
overlay.position = it.pos.toGeoPoint()
// Store new / existing overlay.
if(!collarOverlays.containsKey(it.id)) map.overlays.add(overlay)

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.activities.BoundaryEditorActivity">
<org.osmdroid.views.MapView
android:id="@+id/editorMap"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/saveButtonLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</org.osmdroid.views.MapView>
<LinearLayout
android:id="@+id/saveButtonLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<Button
android:onClick="sendBoundary"
android:id="@+id/saveBoundaryButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/saveBoundary" />
<Button
android:onClick="addMarker"
android:id="@+id/addVertexButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/addVertex" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -29,9 +29,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/collarName" />
app:layout_constraintTop_toBottomOf="@+id/changeBoundaryButton" />
<TextView
android:id="@+id/collarStimulus"
@ -42,4 +41,14 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/collarPos" />
<Button
android:id="@+id/changeBoundaryButton"
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="changeGrazingBoundary"
android:text="@string/changeGrazingBoundary"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/collarName" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -8,4 +8,7 @@
<string name="collarSummaryStimulus">Required %1d stimuli in the last 24 hours</string>
<string name="distanceTraveled">Distance Traveled</string>
<string name="viewStatistics">View Statistics</string>
<string name="saveBoundary">Save Boundary</string>
<string name="addVertex">Add Vertex</string>
<string name="changeGrazingBoundary">Change Grazing Boundary</string>
</resources>