Start working on retrieving collar details.
This commit is contained in:
parent
246d43be80
commit
0f4f4ab8a9
|
@ -3,18 +3,37 @@ package com.danilafe.fencelessgrazing
|
||||||
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.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
|
import com.android.volley.Request
|
||||||
|
import com.android.volley.RequestQueue
|
||||||
|
import com.android.volley.Response
|
||||||
|
import com.android.volley.toolbox.Volley
|
||||||
import com.danilafe.fencelessgrazing.model.CollarPos
|
import com.danilafe.fencelessgrazing.model.CollarPos
|
||||||
|
import com.danilafe.fencelessgrazing.model.CollarSummary
|
||||||
import com.danilafe.fencelessgrazing.model.Polygon
|
import com.danilafe.fencelessgrazing.model.Polygon
|
||||||
|
import com.danilafe.fencelessgrazing.requests.CollarDetailRequest
|
||||||
|
import com.danilafe.fencelessgrazing.requests.CollarHistoryRequest
|
||||||
import org.osmdroid.util.GeoPoint
|
import org.osmdroid.util.GeoPoint
|
||||||
import org.osmdroid.views.MapView
|
import org.osmdroid.views.MapView
|
||||||
|
import org.osmdroid.views.overlay.Marker
|
||||||
|
import java.sql.Time
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.concurrent.timerTask
|
||||||
|
|
||||||
class CollarDetailActivity : AppCompatActivity() {
|
class CollarDetailActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var collarName: TextView
|
||||||
|
private lateinit var collarPos: TextView
|
||||||
|
|
||||||
private lateinit var token: String
|
private lateinit var token: String
|
||||||
|
private lateinit var queue: RequestQueue
|
||||||
private var collarId: Int = -1
|
private var collarId: Int = -1
|
||||||
|
|
||||||
private lateinit var map: MapView
|
private lateinit var map: MapView
|
||||||
|
|
||||||
|
private var refreshTimer = Timer()
|
||||||
|
|
||||||
private lateinit var mapPolygon: org.osmdroid.views.overlay.Polygon
|
private lateinit var mapPolygon: org.osmdroid.views.overlay.Polygon
|
||||||
private var boundingBox: Polygon? = null
|
private var boundingBox: Polygon? = null
|
||||||
set(newValue) {
|
set(newValue) {
|
||||||
|
@ -23,44 +42,108 @@ class CollarDetailActivity : AppCompatActivity() {
|
||||||
field = newValue
|
field = newValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private lateinit var mapMarker: Marker
|
||||||
|
private var dataPoints: List<GeoPoint> = listOf()
|
||||||
|
set(newValue) {
|
||||||
|
if(newValue.isNotEmpty()) updateAnimalHistory(newValue)
|
||||||
|
else clearAnimalHistory()
|
||||||
|
field = newValue
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_collar_detail)
|
setContentView(R.layout.activity_collar_detail)
|
||||||
|
|
||||||
|
collarName = findViewById(R.id.collarName)
|
||||||
|
collarPos = findViewById(R.id.collarPos)
|
||||||
|
|
||||||
token = intent.getStringExtra("token")!!
|
token = intent.getStringExtra("token")!!
|
||||||
collarId = intent.getIntExtra("identifier", -1)
|
collarId = intent.getIntExtra("identifier", -1)
|
||||||
|
queue = Volley.newRequestQueue(this)
|
||||||
|
|
||||||
map = findViewById(R.id.detailMap)
|
map = findViewById(R.id.detailMap)
|
||||||
mapPolygon = org.osmdroid.views.overlay.Polygon(map)
|
mapPolygon = org.osmdroid.views.overlay.Polygon(map)
|
||||||
|
mapMarker = Marker(map)
|
||||||
configureMapPolygon()
|
configureMapPolygon()
|
||||||
|
|
||||||
|
refreshTimer.schedule(timerTask { triggerRefresh() }, 0L, 5000L)
|
||||||
|
|
||||||
|
boundingBox = Polygon(
|
||||||
|
listOf(
|
||||||
|
CollarPos("20", "20"),
|
||||||
|
CollarPos("20", "21"),
|
||||||
|
CollarPos("21", "21"),
|
||||||
|
CollarPos("21", "20")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
map.onPause()
|
||||||
|
refreshTimer.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
map.onResume()
|
||||||
|
refreshTimer = Timer()
|
||||||
|
refreshTimer.schedule(timerTask { triggerRefresh() }, 0L, 5000L)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun triggerRefresh() {
|
||||||
|
val historyRequest = CollarHistoryRequest(getString(R.string.apiUrl), collarId, token,
|
||||||
|
Response.Listener {
|
||||||
|
dataPoints = it.map { p -> GeoPoint(p.longitude.toDouble(), p.latitude.toDouble()) }
|
||||||
|
},
|
||||||
|
Response.ErrorListener {
|
||||||
|
Toast.makeText(this, "Failed to retrieve history of collar", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
val detailRequest = CollarDetailRequest(getString(R.string.apiUrl), collarId, token,
|
||||||
|
Response.Listener {
|
||||||
|
collarName.text = it.name
|
||||||
|
},
|
||||||
|
Response.ErrorListener {
|
||||||
|
Toast.makeText(this, "Failed to retrieve details of collar", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
queue.add(historyRequest)
|
||||||
|
queue.add(detailRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun configureMapPolygon() {
|
private fun configureMapPolygon() {
|
||||||
mapPolygon.fillPaint.color = Color.CYAN
|
mapPolygon.fillPaint.color = Color.parseColor("#32a852")
|
||||||
mapPolygon.fillPaint.alpha = 127
|
mapPolygon.fillPaint.alpha = 127
|
||||||
|
mapPolygon.outlinePaint.color = Color.parseColor("#227539")
|
||||||
mapPolygon.outlinePaint.strokeWidth = 0.0f
|
mapPolygon.outlinePaint.strokeWidth = 0.0f
|
||||||
mapPolygon.title = "Valid Grazing Area"
|
mapPolygon.title = "Valid Grazing Area"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateAnimalHistory(points : List<GeoPoint>) {
|
||||||
|
val currentPoint = points.first()
|
||||||
|
mapMarker.position = currentPoint
|
||||||
|
collarPos.text = getString(R.string.collarSummaryLocation, currentPoint.longitude, currentPoint.latitude)
|
||||||
|
if(!map.overlays.contains(mapMarker)) map.overlays.add(mapMarker)
|
||||||
|
map.invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clearAnimalHistory() {
|
||||||
|
map.overlays.remove(mapMarker)
|
||||||
|
map.invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
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.longitude.toDouble(), it.latitude.toDouble()) }
|
val points = polygon.dataPoints.map { GeoPoint(it.longitude.toDouble(), it.latitude.toDouble()) }
|
||||||
val polygonPoints = points.toMutableList()
|
val polygonPoints = points.toMutableList()
|
||||||
polygonPoints.add(polygonPoints[0])
|
polygonPoints.add(polygonPoints[0])
|
||||||
mapPolygon.points = polygonPoints
|
mapPolygon.points = polygonPoints
|
||||||
|
map.invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun clearBoundingBox() {
|
private fun clearBoundingBox() {
|
||||||
map.overlays.remove(mapPolygon)
|
map.overlays.remove(mapPolygon)
|
||||||
}
|
map.invalidate()
|
||||||
|
|
||||||
override fun onPause() {
|
|
||||||
super.onPause()
|
|
||||||
map.onPause()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
map.onResume()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@ class CollarViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
|
||||||
fun bindData(summary: CollarSummary, collarClickListener: CollarClickListener) {
|
fun bindData(summary: CollarSummary, collarClickListener: CollarClickListener) {
|
||||||
nameView.text = summary.name
|
nameView.text = summary.name
|
||||||
// TODO figure out how to get getString here.
|
positionView.text = nameView.resources.getString(R.string.collarSummaryLocation,
|
||||||
positionView.text = "Currently at ${summary.pos.longitude}, ${summary.pos.latitude}"
|
summary.pos.longitude.toDouble(), summary.pos.latitude.toDouble())
|
||||||
itemView.setOnClickListener {
|
itemView.setOnClickListener {
|
||||||
collarClickListener.onCollarClick(summary)
|
collarClickListener.onCollarClick(summary)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
package com.danilafe.fencelessgrazing.model
|
||||||
|
|
||||||
|
data class CollarDetails(val id: Int, val name: String)
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.danilafe.fencelessgrazing.requests
|
||||||
|
|
||||||
|
import com.android.volley.Response
|
||||||
|
import com.android.volley.toolbox.StringRequest
|
||||||
|
import com.danilafe.fencelessgrazing.model.CollarDetails
|
||||||
|
import com.danilafe.fencelessgrazing.model.CollarPos
|
||||||
|
import com.danilafe.fencelessgrazing.model.CollarSummary
|
||||||
|
import com.google.gson.reflect.TypeToken
|
||||||
|
|
||||||
|
class CollarDetailRequest(
|
||||||
|
baseUrl: String,
|
||||||
|
collarId: Int,
|
||||||
|
private val token : String,
|
||||||
|
listener: Response.Listener<CollarDetails>,
|
||||||
|
error: Response.ErrorListener
|
||||||
|
) : StringRequest(
|
||||||
|
Method.GET, "${baseUrl}/collars/$collarId/details",
|
||||||
|
GsonListener(
|
||||||
|
object : TypeToken<CollarDetails>() {}.type,
|
||||||
|
listener
|
||||||
|
), error
|
||||||
|
) {
|
||||||
|
|
||||||
|
override fun getHeaders(): MutableMap<String, String> {
|
||||||
|
return mutableMapOf("Authorization" to "Bearer $token")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package com.danilafe.fencelessgrazing.requests
|
||||||
|
|
||||||
|
import com.android.volley.Response
|
||||||
|
import com.android.volley.toolbox.StringRequest
|
||||||
|
import com.danilafe.fencelessgrazing.model.CollarPos
|
||||||
|
import com.danilafe.fencelessgrazing.model.CollarSummary
|
||||||
|
import com.google.gson.reflect.TypeToken
|
||||||
|
|
||||||
|
class CollarHistoryRequest(
|
||||||
|
baseUrl: String,
|
||||||
|
collarId: Int,
|
||||||
|
private val token : String,
|
||||||
|
listener: Response.Listener<List<CollarPos>>,
|
||||||
|
error: Response.ErrorListener
|
||||||
|
) : StringRequest(
|
||||||
|
Method.GET, "${baseUrl}/collars/$collarId/history",
|
||||||
|
GsonListener(
|
||||||
|
object : TypeToken<List<CollarPos>>() {}.type,
|
||||||
|
listener
|
||||||
|
), error
|
||||||
|
) {
|
||||||
|
|
||||||
|
override fun getHeaders(): MutableMap<String, String> {
|
||||||
|
return mutableMapOf("Authorization" to "Bearer $token")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -14,4 +14,23 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/collarName"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Display1"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/detailMap" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/collarPos"
|
||||||
|
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" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -12,7 +12,6 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:text="TextView"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -20,6 +19,5 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp" />
|
||||||
android:text="TextView" />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user