Compare commits
3 Commits
8bf4f513b7
...
55f0bec0b4
Author | SHA1 | Date |
---|---|---|
Danila Fedorin | 55f0bec0b4 | |
Danila Fedorin | f6098e9ed4 | |
Danila Fedorin | f343b97704 |
|
@ -25,20 +25,24 @@ android {
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
google()
|
||||||
|
maven { url 'https://jitpack.io' }
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
implementation 'androidx.appcompat:appcompat:1.0.2'
|
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||||
implementation 'androidx.core:core-ktx:1.0.2'
|
implementation 'androidx.core:core-ktx:1.2.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||||
implementation 'com.android.volley:volley:1.1.1'
|
implementation 'com.android.volley:volley:1.1.1'
|
||||||
implementation 'com.google.code.gson:gson:2.8.6'
|
implementation 'com.google.code.gson:gson:2.8.6'
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||||
implementation 'org.osmdroid:osmdroid-android:6.1.5'
|
implementation 'org.osmdroid:osmdroid-android:6.1.5'
|
||||||
implementation "androidx.preference:preference-ktx:1.1.0"
|
implementation "androidx.preference:preference-ktx:1.1.1"
|
||||||
|
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
|
||||||
|
implementation 'com.google.android.material:material:1.1.0'
|
||||||
}
|
}
|
||||||
|
|
|
@ -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=".CollarDetailActivity"></activity>
|
<activity android:name=".StatisticsActivity"/>
|
||||||
|
<activity android:name=".CollarDetailActivity" />
|
||||||
<activity android:name=".CollarListActivity" />
|
<activity android:name=".CollarListActivity" />
|
||||||
<activity android:name=".MainActivity">
|
<activity android:name=".MainActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
|
|
@ -23,6 +23,7 @@ class CollarDetailActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private lateinit var collarName: TextView
|
private lateinit var collarName: TextView
|
||||||
private lateinit var collarPos: TextView
|
private lateinit var collarPos: TextView
|
||||||
|
private lateinit var collarStimulus: TextView
|
||||||
|
|
||||||
private lateinit var token: String
|
private lateinit var token: String
|
||||||
private lateinit var queue: RequestQueue
|
private lateinit var queue: RequestQueue
|
||||||
|
@ -56,10 +57,11 @@ class CollarDetailActivity : AppCompatActivity() {
|
||||||
|
|
||||||
collarName = findViewById(R.id.collarName)
|
collarName = findViewById(R.id.collarName)
|
||||||
collarPos = findViewById(R.id.collarPos)
|
collarPos = findViewById(R.id.collarPos)
|
||||||
|
collarStimulus = findViewById(R.id.collarStimulus)
|
||||||
|
|
||||||
token = intent.getStringExtra("token")!!
|
token = getSharedPreferences("FencelessGrazing", 0).getString("token", null)!!
|
||||||
collarId = intent.getIntExtra("identifier", -1)
|
collarId = intent.getIntExtra("identifier", -1)
|
||||||
queue = Volley.newRequestQueue(this)
|
queue = Volley.newRequestQueue(applicationContext)
|
||||||
|
|
||||||
map = findViewById(R.id.detailMap)
|
map = findViewById(R.id.detailMap)
|
||||||
map.controller.setZoom(9.5)
|
map.controller.setZoom(9.5)
|
||||||
|
@ -104,6 +106,7 @@ class CollarDetailActivity : AppCompatActivity() {
|
||||||
val detailRequest = CollarDetailRequest(getString(R.string.apiUrl), collarId, token,
|
val detailRequest = CollarDetailRequest(getString(R.string.apiUrl), collarId, token,
|
||||||
Response.Listener {
|
Response.Listener {
|
||||||
collarName.text = it.name
|
collarName.text = it.name
|
||||||
|
collarStimulus.text = getString(R.string.collarSummaryStimulus, it.stimulus)
|
||||||
},
|
},
|
||||||
Response.ErrorListener {
|
Response.ErrorListener {
|
||||||
Toast.makeText(this, "Failed to retrieve details of collar", Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, "Failed to retrieve details of collar", Toast.LENGTH_SHORT).show()
|
||||||
|
|
|
@ -3,6 +3,8 @@ package com.danilafe.fencelessgrazing
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Button
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration
|
import androidx.recyclerview.widget.DividerItemDecoration
|
||||||
|
@ -22,7 +24,6 @@ import java.util.*
|
||||||
import kotlin.concurrent.timerTask
|
import kotlin.concurrent.timerTask
|
||||||
|
|
||||||
class CollarListActivity : AppCompatActivity() {
|
class CollarListActivity : AppCompatActivity() {
|
||||||
|
|
||||||
// The list of collar summaries and its list adapter.
|
// The list of collar summaries and its list adapter.
|
||||||
private val summaries : MutableList<CollarSummary> = mutableListOf()
|
private val summaries : MutableList<CollarSummary> = mutableListOf()
|
||||||
private lateinit var summaryAdapter: CollarSummaryAdapter
|
private lateinit var summaryAdapter: CollarSummaryAdapter
|
||||||
|
@ -49,10 +50,10 @@ class CollarListActivity : AppCompatActivity() {
|
||||||
setContentView(R.layout.activity_collar_list)
|
setContentView(R.layout.activity_collar_list)
|
||||||
findViews()
|
findViews()
|
||||||
|
|
||||||
token = intent.getStringExtra("token")!!
|
token = getSharedPreferences("FencelessGrazing", 0).getString("token", null)!!
|
||||||
map.setTileSource(TileSourceFactory.MAPNIK)
|
map.setTileSource(TileSourceFactory.MAPNIK)
|
||||||
map.controller.setZoom(9.5)
|
map.controller.setZoom(9.5)
|
||||||
queue = Volley.newRequestQueue(this)
|
queue = Volley.newRequestQueue(applicationContext)
|
||||||
|
|
||||||
setupCollarList()
|
setupCollarList()
|
||||||
}
|
}
|
||||||
|
@ -71,6 +72,10 @@ class CollarListActivity : AppCompatActivity() {
|
||||||
refreshTimer.purge()
|
refreshTimer.purge()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun openStatistics(view: View) {
|
||||||
|
startActivity(Intent(this, StatisticsActivity::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
private fun triggerRefresh() {
|
private fun triggerRefresh() {
|
||||||
val request = CollarRequest(getString(R.string.apiUrl), token,
|
val request = CollarRequest(getString(R.string.apiUrl), token,
|
||||||
Response.Listener {
|
Response.Listener {
|
||||||
|
@ -93,7 +98,6 @@ class CollarListActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private fun startCollarDetailActivity(collar: CollarSummary) {
|
private fun startCollarDetailActivity(collar: CollarSummary) {
|
||||||
val newIntent = Intent(this, CollarDetailActivity::class.java).apply {
|
val newIntent = Intent(this, CollarDetailActivity::class.java).apply {
|
||||||
putExtra("token", token)
|
|
||||||
putExtra("identifier", collar.id)
|
putExtra("identifier", collar.id)
|
||||||
}
|
}
|
||||||
startActivity(newIntent)
|
startActivity(newIntent)
|
||||||
|
@ -150,4 +154,5 @@ class CollarListActivity : AppCompatActivity() {
|
||||||
|
|
||||||
map.invalidate()
|
map.invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
package com.danilafe.fencelessgrazing
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import com.android.volley.RequestQueue
|
||||||
|
import com.android.volley.Response
|
||||||
|
import com.android.volley.toolbox.Volley
|
||||||
|
import com.danilafe.fencelessgrazing.requests.DistanceTraveledRequest
|
||||||
|
import com.github.mikephil.charting.charts.BarChart
|
||||||
|
import com.github.mikephil.charting.data.BarData
|
||||||
|
import com.github.mikephil.charting.data.BarDataSet
|
||||||
|
import com.github.mikephil.charting.data.BarEntry
|
||||||
|
import com.github.mikephil.charting.formatter.IndexAxisValueFormatter
|
||||||
|
import com.github.mikephil.charting.utils.ColorTemplate
|
||||||
|
|
||||||
|
class DistanceTraveledGraph() : Fragment() {
|
||||||
|
|
||||||
|
private lateinit var distanceTraveledChart: BarChart
|
||||||
|
|
||||||
|
private lateinit var queue : RequestQueue
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
val view = inflater.inflate(R.layout.distance_traveled_layoyt, container, false)
|
||||||
|
distanceTraveledChart = view.findViewById(R.id.distanceTraveledChart)
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
queue = Volley.newRequestQueue(requireActivity().applicationContext)
|
||||||
|
|
||||||
|
triggerRefresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun triggerRefresh() {
|
||||||
|
val activity = requireActivity()
|
||||||
|
val sharedPrefs = activity.getSharedPreferences("FencelessGrazing", 0)
|
||||||
|
val token = sharedPrefs.getString("token", null)!!
|
||||||
|
val request = DistanceTraveledRequest(activity.getString(R.string.apiUrl), token,
|
||||||
|
Response.Listener {
|
||||||
|
val entries = mutableListOf<BarEntry>()
|
||||||
|
val labels = it.map { c -> c.name }
|
||||||
|
it.forEachIndexed { i, v ->
|
||||||
|
entries.add(BarEntry(i.toFloat(), v.distance))
|
||||||
|
}
|
||||||
|
val dataSet = BarDataSet(entries, "Distance Traveled")
|
||||||
|
dataSet.colors = ColorTemplate.VORDIPLOM_COLORS.toList()
|
||||||
|
val data = BarData(dataSet)
|
||||||
|
data.barWidth = 0.9f
|
||||||
|
distanceTraveledChart.legend.textSize = 20.0f
|
||||||
|
distanceTraveledChart.data = data
|
||||||
|
distanceTraveledChart.setFitBars(true)
|
||||||
|
distanceTraveledChart.xAxis.valueFormatter = IndexAxisValueFormatter(labels)
|
||||||
|
distanceTraveledChart.xAxis.granularity = 1.0f
|
||||||
|
distanceTraveledChart.xAxis.isGranularityEnabled = true
|
||||||
|
distanceTraveledChart.invalidate()
|
||||||
|
},
|
||||||
|
Response.ErrorListener {
|
||||||
|
Toast.makeText(activity, "Failed to retrieve distance traveled!", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
queue.add(request)
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,9 +26,11 @@ class MainActivity : AppCompatActivity() {
|
||||||
LoginRequest(getString(R.string.apiUrl),
|
LoginRequest(getString(R.string.apiUrl),
|
||||||
usernameField.text.toString(), passwordField.text.toString(),
|
usernameField.text.toString(), passwordField.text.toString(),
|
||||||
Response.Listener {
|
Response.Listener {
|
||||||
val newIntent = Intent(this, CollarListActivity::class.java).apply {
|
val editor = getSharedPreferences("FencelessGrazing", 0).edit()
|
||||||
putExtra("token", it?.token)
|
editor.putString("token", it.token)
|
||||||
}
|
editor.apply()
|
||||||
|
|
||||||
|
val newIntent = Intent(this, CollarListActivity::class.java)
|
||||||
startActivity(newIntent)
|
startActivity(newIntent)
|
||||||
},
|
},
|
||||||
Response.ErrorListener {
|
Response.ErrorListener {
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.danilafe.fencelessgrazing
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import androidx.viewpager.widget.ViewPager
|
||||||
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
|
import com.google.android.material.tabs.TabLayout
|
||||||
|
import com.google.android.material.tabs.TabLayoutMediator
|
||||||
|
|
||||||
|
class StatisticsActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var tabLayout: TabLayout
|
||||||
|
private lateinit var viewPager: ViewPager2
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val tabNames = arrayOf("Distance Traveled")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_statistics)
|
||||||
|
|
||||||
|
tabLayout = findViewById(R.id.statisticsTabs)
|
||||||
|
viewPager = findViewById(R.id.statisticsPager)
|
||||||
|
|
||||||
|
viewPager.adapter = StatisticsGraphAdapter(this)
|
||||||
|
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
|
||||||
|
tab.text = tabNames[position]
|
||||||
|
}.attach()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.danilafe.fencelessgrazing
|
||||||
|
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||||
|
|
||||||
|
class StatisticsGraphAdapter(activity : FragmentActivity) : FragmentStateAdapter(activity) {
|
||||||
|
override fun getItemCount(): Int = 1
|
||||||
|
override fun createFragment(position: Int): Fragment = DistanceTraveledGraph()
|
||||||
|
}
|
|
@ -1,3 +1,3 @@
|
||||||
package com.danilafe.fencelessgrazing.model
|
package com.danilafe.fencelessgrazing.model
|
||||||
|
|
||||||
data class CollarDetails(val id: Int, val name: String)
|
data class CollarDetails(val id: Int, val name: String, val stimulus: Int)
|
|
@ -0,0 +1,3 @@
|
||||||
|
package com.danilafe.fencelessgrazing.model
|
||||||
|
|
||||||
|
data class CollarDistance(val name: String, val id: Int, val distance: Float)
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.danilafe.fencelessgrazing.requests
|
||||||
|
|
||||||
|
import com.danilafe.fencelessgrazing.model.CollarDistance
|
||||||
|
import com.android.volley.Response
|
||||||
|
import com.android.volley.toolbox.StringRequest
|
||||||
|
import com.google.gson.reflect.TypeToken
|
||||||
|
|
||||||
|
class DistanceTraveledRequest(
|
||||||
|
baseUrl: String,
|
||||||
|
private val token : String,
|
||||||
|
listener: Response.Listener<List<CollarDistance>>,
|
||||||
|
error: Response.ErrorListener
|
||||||
|
) : StringRequest(
|
||||||
|
Method.GET, "${baseUrl}/collars/stats/distance",
|
||||||
|
GsonListener(
|
||||||
|
object : TypeToken<List<CollarDistance>>() {}.type,
|
||||||
|
listener
|
||||||
|
), error
|
||||||
|
) {
|
||||||
|
|
||||||
|
override fun getHeaders(): MutableMap<String, String> {
|
||||||
|
return mutableMapOf("Authorization" to "Bearer $token")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -10,7 +10,6 @@ class GsonListener<T : Any>(private val targetType : Type, private val stringLis
|
||||||
private val gson = Gson()
|
private val gson = Gson()
|
||||||
|
|
||||||
override fun onResponse(response: String?) {
|
override fun onResponse(response: String?) {
|
||||||
Log.i("Response", response)
|
|
||||||
if(response == null) { return stringListener.onResponse(null) }
|
if(response == null) { return stringListener.onResponse(null) }
|
||||||
stringListener.onResponse(gson.fromJson<T>(response, targetType))
|
stringListener.onResponse(gson.fromJson<T>(response, targetType))
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,4 +33,13 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/collarName" />
|
app:layout_constraintTop_toBottomOf="@+id/collarName" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/collarStimulus"
|
||||||
|
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/collarPos" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -20,6 +20,25 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/map"
|
app:layout_constraintTop_toBottomOf="@+id/linearLayout"
|
||||||
tools:layout_editor_absoluteX="0dp" />
|
tools:layout_editor_absoluteX="0dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/linearLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHeight_max="wrap"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/map">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/statisticsButton"
|
||||||
|
style="@android:style/Widget.Material.Button.Colored"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:onClick="openStatistics"
|
||||||
|
android:text="@string/viewStatistics" />
|
||||||
|
</LinearLayout>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?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=".StatisticsActivity">
|
||||||
|
|
||||||
|
<com.google.android.material.tabs.TabLayout
|
||||||
|
android:id="@+id/statisticsTabs"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
<androidx.viewpager2.widget.ViewPager2
|
||||||
|
android:id="@+id/statisticsPager"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/statisticsTabs" />
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?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">
|
||||||
|
|
||||||
|
<com.github.mikephil.charting.charts.BarChart
|
||||||
|
android:id="@+id/distanceTraveledChart"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -5,4 +5,7 @@
|
||||||
<string name="login">Log In</string>
|
<string name="login">Log In</string>
|
||||||
<string name="apiUrl">http://dev.danilafe.com:8090</string>
|
<string name="apiUrl">http://dev.danilafe.com:8090</string>
|
||||||
<string name="collarSummaryLocation">Currently at %1f, %2f</string>
|
<string name="collarSummaryLocation">Currently at %1f, %2f</string>
|
||||||
|
<string name="collarSummaryStimulus">Required %1d stimuli in the last 24 hours</string>
|
||||||
|
<string name="distanceTraveled">Distance Traveled</string>
|
||||||
|
<string name="viewStatistics">View Statistics</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue