Compare commits
2 Commits
efb3921dc2
...
9a75af4045
Author | SHA1 | Date |
---|---|---|
Danila Fedorin | 9a75af4045 | |
Danila Fedorin | 03c55f370e |
|
@ -13,7 +13,8 @@
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme">
|
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.CollarDetailActivity" />
|
||||||
<activity android:name=".ui.activities.CollarListActivity" />
|
<activity android:name=".ui.activities.CollarListActivity" />
|
||||||
<activity android:name=".ui.activities.MainActivity">
|
<activity android:name=".ui.activities.MainActivity">
|
||||||
|
|
|
@ -6,5 +6,6 @@ package com.danilafe.fencelessgrazing.model
|
||||||
* @param id the collar's internal unique identifier.
|
* @param id the collar's internal unique identifier.
|
||||||
* @param name the collar's current designation in the system.
|
* @param name the collar's current designation in the system.
|
||||||
* @param stimulus the number of stimulus activation reports in the last 24 hours.
|
* @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>)
|
|
@ -2,6 +2,7 @@ package com.danilafe.fencelessgrazing.model
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
|
import org.osmdroid.util.GeoPoint
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GPS coordinate returned by many of the project's API endpoints.
|
* 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.
|
* @param latitude the latitude of the GPS point.
|
||||||
*/
|
*/
|
||||||
@Parcelize
|
@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())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,9 +34,7 @@ class BoundaryEditorActivity : AppCompatActivity(),
|
||||||
setContentView(R.layout.activity_boundary_editor)
|
setContentView(R.layout.activity_boundary_editor)
|
||||||
|
|
||||||
val requestedCenter = intent.getParcelableExtra<CollarPos>("center")!!
|
val requestedCenter = intent.getParcelableExtra<CollarPos>("center")!!
|
||||||
center = GeoPoint(
|
center = requestedCenter.toGeoPoint()
|
||||||
requestedCenter.longitude.toDouble(),
|
|
||||||
requestedCenter.latitude.toDouble())
|
|
||||||
identifier = intent.getIntExtra("identifier", -1)
|
identifier = intent.getIntExtra("identifier", -1)
|
||||||
queue = Volley.newRequestQueue(applicationContext)
|
queue = Volley.newRequestQueue(applicationContext)
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
package com.danilafe.fencelessgrazing.ui.activities
|
package com.danilafe.fencelessgrazing.ui.activities
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.view.View
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import com.android.volley.RequestQueue
|
import com.android.volley.RequestQueue
|
||||||
import com.android.volley.Response
|
import com.android.volley.Response
|
||||||
import com.android.volley.toolbox.Volley
|
import com.android.volley.toolbox.Volley
|
||||||
import com.danilafe.fencelessgrazing.R
|
import com.danilafe.fencelessgrazing.R
|
||||||
|
import com.danilafe.fencelessgrazing.model.CollarPos
|
||||||
import com.danilafe.fencelessgrazing.model.Polygon
|
import com.danilafe.fencelessgrazing.model.Polygon
|
||||||
import com.danilafe.fencelessgrazing.requests.authenticated.CollarDetailRequest
|
import com.danilafe.fencelessgrazing.requests.authenticated.CollarDetailRequest
|
||||||
import com.danilafe.fencelessgrazing.requests.authenticated.CollarHistoryRequest
|
import com.danilafe.fencelessgrazing.requests.authenticated.CollarHistoryRequest
|
||||||
|
@ -174,7 +177,7 @@ class CollarDetailActivity : AppCompatActivity() {
|
||||||
token,
|
token,
|
||||||
Response.Listener {
|
Response.Listener {
|
||||||
dataPoints =
|
dataPoints =
|
||||||
it.map { p -> GeoPoint(p.longitude.toDouble(), p.latitude.toDouble()) }
|
it.map { p -> p.toGeoPoint() }
|
||||||
},
|
},
|
||||||
Response.ErrorListener {
|
Response.ErrorListener {
|
||||||
Toast.makeText(this, "Failed to retrieve history of collar", Toast.LENGTH_SHORT)
|
Toast.makeText(this, "Failed to retrieve history of collar", Toast.LENGTH_SHORT)
|
||||||
|
@ -199,6 +202,16 @@ class CollarDetailActivity : AppCompatActivity() {
|
||||||
queue.add(detailRequest)
|
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
|
* Given a new location history of the animal, configures
|
||||||
* updates the [map] to include the relevant elements (such as the animal's
|
* 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) {
|
private fun updateBoundingBox(oldValue: Polygon?, polygon: Polygon) {
|
||||||
if(oldValue == null) map.overlays.add(mapPolygon)
|
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()
|
val polygonPoints = points.toMutableList()
|
||||||
polygonPoints.add(polygonPoints[0])
|
polygonPoints.add(polygonPoints[0])
|
||||||
mapPolygon.points = polygonPoints
|
mapPolygon.points = polygonPoints
|
||||||
|
|
|
@ -196,7 +196,7 @@ class CollarListActivity : AppCompatActivity() {
|
||||||
centerSet = true
|
centerSet = true
|
||||||
val averageLongitude = summaries.map { it.pos.longitude.toDouble() }.average()
|
val averageLongitude = summaries.map { it.pos.longitude.toDouble() }.average()
|
||||||
val averageLatitude = summaries.map { it.pos.latitude.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
|
// Create or update overlay
|
||||||
val overlay = collarOverlays[it.id] ?: Marker(map)
|
val overlay = collarOverlays[it.id] ?: Marker(map)
|
||||||
overlay.title = it.name
|
overlay.title = it.name
|
||||||
overlay.position = GeoPoint(it.pos.longitude.toDouble(), it.pos.latitude.toDouble())
|
overlay.position = it.pos.toGeoPoint()
|
||||||
|
|
||||||
// Store new / existing overlay.
|
// Store new / existing overlay.
|
||||||
if(!collarOverlays.containsKey(it.id)) map.overlays.add(overlay)
|
if(!collarOverlays.containsKey(it.id)) map.overlays.add(overlay)
|
||||||
|
|
|
@ -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>
|
|
@ -29,9 +29,8 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="10dp"
|
android:layout_marginStart="10dp"
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/collarName" />
|
app:layout_constraintTop_toBottomOf="@+id/changeBoundaryButton" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/collarStimulus"
|
android:id="@+id/collarStimulus"
|
||||||
|
@ -42,4 +41,14 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/collarPos" />
|
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>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -8,4 +8,7 @@
|
||||||
<string name="collarSummaryStimulus">Required %1d stimuli in the last 24 hours</string>
|
<string name="collarSummaryStimulus">Required %1d stimuli in the last 24 hours</string>
|
||||||
<string name="distanceTraveled">Distance Traveled</string>
|
<string name="distanceTraveled">Distance Traveled</string>
|
||||||
<string name="viewStatistics">View Statistics</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>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue