Move stuff into more granular packages.

This commit is contained in:
Danila Fedorin 2020-05-13 19:11:24 -07:00
parent 1cb22bf4a0
commit e13572ae67
19 changed files with 122 additions and 92 deletions

View File

@ -13,10 +13,10 @@
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=".StatisticsActivity"/> <activity android:name=".ui.activities.StatisticsActivity"/>
<activity android:name=".CollarDetailActivity" /> <activity android:name=".ui.activities.CollarDetailActivity" />
<activity android:name=".CollarListActivity" /> <activity android:name=".ui.activities.CollarListActivity" />
<activity android:name=".MainActivity"> <activity android:name=".ui.activities.MainActivity">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View File

@ -1,4 +1,4 @@
package com.danilafe.fencelessgrazing.requests package com.danilafe.fencelessgrazing.requests.authenticated
import com.android.volley.Response import com.android.volley.Response
import com.android.volley.toolbox.StringRequest import com.android.volley.toolbox.StringRequest

View File

@ -1,11 +1,8 @@
package com.danilafe.fencelessgrazing.requests package com.danilafe.fencelessgrazing.requests.authenticated
import com.android.volley.Response import com.android.volley.Response
import com.android.volley.toolbox.StringRequest
import com.danilafe.fencelessgrazing.model.CollarDetails import com.danilafe.fencelessgrazing.model.CollarDetails
import com.danilafe.fencelessgrazing.model.CollarPos import com.danilafe.fencelessgrazing.requests.toGsonListener
import com.danilafe.fencelessgrazing.model.CollarSummary
import com.google.gson.reflect.TypeToken
/** /**
* Request to the `/collars/<id>/details` API endpoint. Retrieves detailed information * Request to the `/collars/<id>/details` API endpoint. Retrieves detailed information

View File

@ -1,10 +1,8 @@
package com.danilafe.fencelessgrazing.requests package com.danilafe.fencelessgrazing.requests.authenticated
import com.android.volley.Response import com.android.volley.Response
import com.android.volley.toolbox.StringRequest
import com.danilafe.fencelessgrazing.model.CollarPos import com.danilafe.fencelessgrazing.model.CollarPos
import com.danilafe.fencelessgrazing.model.CollarSummary import com.danilafe.fencelessgrazing.requests.toGsonListener
import com.google.gson.reflect.TypeToken
/** /**
* A request to the `/collars/<id>/history` API endpoint. Retrieves the entire list * A request to the `/collars/<id>/history` API endpoint. Retrieves the entire list

View File

@ -1,9 +1,8 @@
package com.danilafe.fencelessgrazing.requests package com.danilafe.fencelessgrazing.requests.authenticated
import com.android.volley.Response import com.android.volley.Response
import com.android.volley.toolbox.StringRequest
import com.danilafe.fencelessgrazing.model.CollarSummary import com.danilafe.fencelessgrazing.model.CollarSummary
import com.google.gson.reflect.TypeToken import com.danilafe.fencelessgrazing.requests.toGsonListener
/** /**
* A request to the `/collars` API endpoint. Retrieves a list of collar summaries, represented * A request to the `/collars` API endpoint. Retrieves a list of collar summaries, represented

View File

@ -1,9 +1,8 @@
package com.danilafe.fencelessgrazing.requests package com.danilafe.fencelessgrazing.requests.authenticated
import com.danilafe.fencelessgrazing.model.CollarDistance import com.danilafe.fencelessgrazing.model.CollarDistance
import com.android.volley.Response import com.android.volley.Response
import com.android.volley.toolbox.StringRequest import com.danilafe.fencelessgrazing.requests.toGsonListener
import com.google.gson.reflect.TypeToken
/** /**
* A request to the `/collars/stats/distance` API endpoint. Retrieves * A request to the `/collars/stats/distance` API endpoint. Retrieves

View File

@ -1,4 +1,4 @@
package com.danilafe.fencelessgrazing package com.danilafe.fencelessgrazing.ui.activities
import android.graphics.Color import android.graphics.Color
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
@ -8,9 +8,10 @@ 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.model.Polygon import com.danilafe.fencelessgrazing.model.Polygon
import com.danilafe.fencelessgrazing.requests.CollarDetailRequest import com.danilafe.fencelessgrazing.requests.authenticated.CollarDetailRequest
import com.danilafe.fencelessgrazing.requests.CollarHistoryRequest import com.danilafe.fencelessgrazing.requests.authenticated.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 org.osmdroid.views.overlay.Marker
@ -166,23 +167,32 @@ class CollarDetailActivity : AppCompatActivity() {
* Sends API requests that retrieve updated information about the collar. * Sends API requests that retrieve updated information about the collar.
*/ */
private fun triggerRefresh() { private fun triggerRefresh() {
val historyRequest = CollarHistoryRequest(getString(R.string.apiUrl), collarId, token, val historyRequest =
Response.Listener { CollarHistoryRequest(getString(R.string.apiUrl),
dataPoints = it.map { p -> GeoPoint(p.longitude.toDouble(), p.latitude.toDouble()) } collarId,
}, token,
Response.ErrorListener { Response.Listener {
Toast.makeText(this, "Failed to retrieve history of collar", Toast.LENGTH_SHORT).show() dataPoints =
} it.map { p -> GeoPoint(p.longitude.toDouble(), p.latitude.toDouble()) }
) },
val detailRequest = CollarDetailRequest(getString(R.string.apiUrl), collarId, token, Response.ErrorListener {
Response.Listener { Toast.makeText(this, "Failed to retrieve history of collar", Toast.LENGTH_SHORT)
collarName.text = it.name .show()
collarStimulus.text = getString(R.string.collarSummaryStimulus, it.stimulus) }
}, )
Response.ErrorListener { val detailRequest =
Toast.makeText(this, "Failed to retrieve details of collar", Toast.LENGTH_SHORT).show() CollarDetailRequest(getString(R.string.apiUrl),
} collarId,
) token,
Response.Listener {
collarName.text = it.name
collarStimulus.text = getString(R.string.collarSummaryStimulus, it.stimulus)
},
Response.ErrorListener {
Toast.makeText(this, "Failed to retrieve details of collar", Toast.LENGTH_SHORT)
.show()
}
)
queue.add(historyRequest) queue.add(historyRequest)
queue.add(detailRequest) queue.add(detailRequest)
} }

View File

@ -1,4 +1,4 @@
package com.danilafe.fencelessgrazing package com.danilafe.fencelessgrazing.ui.activities
import android.content.Intent import android.content.Intent
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
@ -12,8 +12,11 @@ import androidx.recyclerview.widget.RecyclerView
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.ui.components.CollarClickListener
import com.danilafe.fencelessgrazing.ui.components.CollarSummaryAdapter
import com.danilafe.fencelessgrazing.R
import com.danilafe.fencelessgrazing.model.CollarSummary import com.danilafe.fencelessgrazing.model.CollarSummary
import com.danilafe.fencelessgrazing.requests.CollarRequest import com.danilafe.fencelessgrazing.requests.authenticated.CollarRequest
import org.osmdroid.config.Configuration import org.osmdroid.config.Configuration
import org.osmdroid.tileprovider.tilesource.TileSourceFactory import org.osmdroid.tileprovider.tilesource.TileSourceFactory
import org.osmdroid.util.GeoPoint import org.osmdroid.util.GeoPoint
@ -116,17 +119,20 @@ class CollarListActivity : AppCompatActivity() {
* Sends the request to the API to retrieve an updated list of active collars. * Sends the request to the API to retrieve an updated list of active collars.
*/ */
private fun triggerRefresh() { private fun triggerRefresh() {
val request = CollarRequest(getString(R.string.apiUrl), token, val request =
Response.Listener { CollarRequest(getString(R.string.apiUrl),
summaries.clear() token,
summaries.addAll(it) Response.Listener {
summaryAdapter.notifyDataSetChanged() summaries.clear()
updateMap() summaries.addAll(it)
}, summaryAdapter.notifyDataSetChanged()
Response.ErrorListener { updateMap()
Toast.makeText(this, "Failed to retrieve collar list!", Toast.LENGTH_SHORT).show() },
} Response.ErrorListener {
) Toast.makeText(this, "Failed to retrieve collar list!", Toast.LENGTH_SHORT)
.show()
}
)
queue.add(request) queue.add(request)
} }
@ -158,12 +164,16 @@ class CollarListActivity : AppCompatActivity() {
*/ */
private fun setupCollarList() { private fun setupCollarList() {
val layoutManager = LinearLayoutManager(collarList.context) val layoutManager = LinearLayoutManager(collarList.context)
summaryAdapter = CollarSummaryAdapter(summaries, object : CollarClickListener { summaryAdapter =
override fun onCollarClick(collar: CollarSummary?) { CollarSummaryAdapter(
if (collar == null) return summaries,
startCollarDetailActivity(collar) object :
} CollarClickListener {
}) override fun onCollarClick(collar: CollarSummary?) {
if (collar == null) return
startCollarDetailActivity(collar)
}
})
collarList.adapter = summaryAdapter collarList.adapter = summaryAdapter
collarList.layoutManager = layoutManager collarList.layoutManager = layoutManager
collarList.addItemDecoration(DividerItemDecoration(collarList.context, layoutManager.orientation)) collarList.addItemDecoration(DividerItemDecoration(collarList.context, layoutManager.orientation))

View File

@ -1,4 +1,4 @@
package com.danilafe.fencelessgrazing package com.danilafe.fencelessgrazing.ui.activities
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
@ -9,8 +9,9 @@ import androidx.fragment.app.Fragment
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.model.CollarDistance import com.danilafe.fencelessgrazing.model.CollarDistance
import com.danilafe.fencelessgrazing.requests.DistanceTraveledRequest import com.danilafe.fencelessgrazing.requests.authenticated.DistanceTraveledRequest
import com.github.mikephil.charting.charts.BarChart import com.github.mikephil.charting.charts.BarChart
import com.github.mikephil.charting.components.XAxis import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.data.BarData import com.github.mikephil.charting.data.BarData
@ -61,14 +62,20 @@ class DistanceTraveledGraph() : Fragment() {
val activity = requireActivity() val activity = requireActivity()
val sharedPrefs = activity.getSharedPreferences("FencelessGrazing", 0) val sharedPrefs = activity.getSharedPreferences("FencelessGrazing", 0)
val token = sharedPrefs.getString("token", null)!! val token = sharedPrefs.getString("token", null)!!
val request = DistanceTraveledRequest(activity.getString(R.string.apiUrl), token, val request =
Response.Listener { DistanceTraveledRequest(activity.getString(R.string.apiUrl),
updateChartData(it) token,
}, Response.Listener {
Response.ErrorListener { updateChartData(it)
Toast.makeText(activity, "Failed to retrieve distance traveled!", Toast.LENGTH_SHORT).show() },
} Response.ErrorListener {
) Toast.makeText(
activity,
"Failed to retrieve distance traveled!",
Toast.LENGTH_SHORT
).show()
}
)
queue.add(request) queue.add(request)
} }

View File

@ -1,4 +1,4 @@
package com.danilafe.fencelessgrazing package com.danilafe.fencelessgrazing.ui.activities
import android.content.Intent import android.content.Intent
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
@ -8,6 +8,7 @@ import android.widget.TextView
import android.widget.Toast import android.widget.Toast
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.requests.LoginRequest import com.danilafe.fencelessgrazing.requests.LoginRequest
/** /**

View File

@ -1,10 +1,10 @@
package com.danilafe.fencelessgrazing package com.danilafe.fencelessgrazing.ui.activities
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.FragmentActivity
import androidx.viewpager.widget.ViewPager
import androidx.viewpager2.widget.ViewPager2 import androidx.viewpager2.widget.ViewPager2
import com.danilafe.fencelessgrazing.R
import com.danilafe.fencelessgrazing.ui.components.StatisticsGraphAdapter
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
@ -37,7 +37,10 @@ class StatisticsActivity : AppCompatActivity() {
tabLayout = findViewById(R.id.statisticsTabs) tabLayout = findViewById(R.id.statisticsTabs)
viewPager = findViewById(R.id.statisticsPager) viewPager = findViewById(R.id.statisticsPager)
viewPager.adapter = StatisticsGraphAdapter(this) viewPager.adapter =
StatisticsGraphAdapter(
this
)
TabLayoutMediator(tabLayout, viewPager) { tab, position -> TabLayoutMediator(tabLayout, viewPager) { tab, position ->
tab.text = tabNames[position] tab.text = tabNames[position]
}.attach() }.attach()

View File

@ -1,4 +1,4 @@
package com.danilafe.fencelessgrazing package com.danilafe.fencelessgrazing.ui.components
import com.danilafe.fencelessgrazing.model.CollarSummary import com.danilafe.fencelessgrazing.model.CollarSummary

View File

@ -1,15 +1,12 @@
package com.danilafe.fencelessgrazing package com.danilafe.fencelessgrazing.ui.components
import android.content.Context
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast
import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import com.android.volley.Response import com.danilafe.fencelessgrazing.R
import com.android.volley.toolbox.Volley
import com.danilafe.fencelessgrazing.model.CollarSummary import com.danilafe.fencelessgrazing.model.CollarSummary
import com.danilafe.fencelessgrazing.requests.CollarRequest import com.danilafe.fencelessgrazing.requests.authenticated.CollarRequest
/** /**
* A [ListAdapter] subclass to display and manage a list of [CollarSummary] items * A [ListAdapter] subclass to display and manage a list of [CollarSummary] items
@ -21,7 +18,9 @@ import com.danilafe.fencelessgrazing.requests.CollarRequest
class CollarSummaryAdapter( class CollarSummaryAdapter(
private val items: List<CollarSummary>, private val items: List<CollarSummary>,
private val collarClickListener: CollarClickListener private val collarClickListener: CollarClickListener
) : ListAdapter<CollarSummary, CollarViewHolder>(DiffCallback()) { ) : ListAdapter<CollarSummary, CollarViewHolder>(
DiffCallback()
) {
/** /**
* [DiffUtil.ItemCallback] used for the [ListAdapter]. Compares items using * [DiffUtil.ItemCallback] used for the [ListAdapter]. Compares items using
@ -37,14 +36,17 @@ class CollarSummaryAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CollarViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CollarViewHolder {
val layout = LayoutInflater.from(parent.context).inflate(viewType, parent, false) val layout = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
return CollarViewHolder(layout) return CollarViewHolder(
layout
)
} }
override fun onBindViewHolder(holder: CollarViewHolder, position: Int) { override fun onBindViewHolder(holder: CollarViewHolder, position: Int) {
holder.bindData(getItem(position), collarClickListener) holder.bindData(getItem(position), collarClickListener)
} }
override fun getItemViewType(position: Int): Int = R.layout.collar_summary_layout override fun getItemViewType(position: Int): Int =
R.layout.collar_summary_layout
override fun getItem(position: Int): CollarSummary = items[position] override fun getItem(position: Int): CollarSummary = items[position]

View File

@ -1,8 +1,9 @@
package com.danilafe.fencelessgrazing package com.danilafe.fencelessgrazing.ui.components
import android.view.View import android.view.View
import android.widget.TextView import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.danilafe.fencelessgrazing.R
import com.danilafe.fencelessgrazing.model.CollarSummary import com.danilafe.fencelessgrazing.model.CollarSummary
/** /**
@ -28,7 +29,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
positionView.text = itemView.resources.getString(R.string.collarSummaryLocation, positionView.text = itemView.resources.getString(
R.string.collarSummaryLocation,
summary.pos.longitude.toDouble(), summary.pos.latitude.toDouble()) summary.pos.longitude.toDouble(), summary.pos.latitude.toDouble())
itemView.setOnClickListener { itemView.setOnClickListener {
collarClickListener.onCollarClick(summary) collarClickListener.onCollarClick(summary)

View File

@ -1,13 +1,15 @@
package com.danilafe.fencelessgrazing package com.danilafe.fencelessgrazing.ui.components
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.adapter.FragmentStateAdapter
import com.danilafe.fencelessgrazing.ui.activities.DistanceTraveledGraph
/** /**
* Adapter for the [ViewPager2][androidx.viewpager2.widget.ViewPager2] class. * Adapter for the [ViewPager2][androidx.viewpager2.widget.ViewPager2] class.
*/ */
class StatisticsGraphAdapter(activity : FragmentActivity) : FragmentStateAdapter(activity) { class StatisticsGraphAdapter(activity : FragmentActivity) : FragmentStateAdapter(activity) {
override fun getItemCount(): Int = 1 override fun getItemCount(): Int = 1
override fun createFragment(position: Int): Fragment = DistanceTraveledGraph() override fun createFragment(position: Int): Fragment =
DistanceTraveledGraph()
} }

View File

@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".CollarDetailActivity"> tools:context=".ui.activities.CollarDetailActivity">
<org.osmdroid.views.MapView <org.osmdroid.views.MapView
android:id="@+id/detailMap" android:id="@+id/detailMap"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".CollarListActivity"> tools:context=".ui.activities.CollarListActivity">
<org.osmdroid.views.MapView <org.osmdroid.views.MapView
android:id="@+id/map" android:id="@+id/map"

View File

@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".MainActivity"> tools:context=".ui.activities.MainActivity">
<EditText <EditText
android:id="@+id/username" android:id="@+id/username"

View File

@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".StatisticsActivity"> tools:context=".ui.activities.StatisticsActivity">
<com.google.android.material.tabs.TabLayout <com.google.android.material.tabs.TabLayout
android:id="@+id/statisticsTabs" android:id="@+id/statisticsTabs"