Create MerchantViewModel and MerchantRepository, the first to hold the merchants data and deliver it to the MerchantsFragment and the second to serve as a single source to fetch the Merchants list. When it gets a request for the merchants it retrieves and serves the list from the database and meanwhile refreshes the list from the WebService.

master
Severiano Jaramillo 2019-01-23 15:37:13 -06:00
parent 6aad0ca624
commit 4bb53de009
5 changed files with 100 additions and 33 deletions

View File

@ -1,8 +1,10 @@
package cy.agorise.bitsybitshareswallet.database.daos
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import cy.agorise.bitsybitshareswallet.database.entities.Merchant
@Dao
@ -12,4 +14,7 @@ interface MerchantDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(merchants: List<Merchant>)
@Query("SELECT * FROM merchants")
fun getAll(): LiveData<List<Merchant>>
}

View File

@ -12,17 +12,12 @@ import android.view.ViewGroup
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.gson.GsonBuilder
import cy.agorise.bitsybitshareswallet.R
import cy.agorise.bitsybitshareswallet.network.MerchantsWebservice
import cy.agorise.bitsybitshareswallet.network.FeathersResponse
import retrofit2.Call
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import android.preference.PreferenceManager
import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.model.*
import com.google.maps.android.clustering.Cluster
@ -31,10 +26,11 @@ import cy.agorise.bitsybitshareswallet.database.entities.Merchant
import cy.agorise.bitsybitshareswallet.utils.Constants
import cy.agorise.bitsybitshareswallet.utils.MerchantMarkerRenderer
import cy.agorise.bitsybitshareswallet.utils.toast
import cy.agorise.bitsybitshareswallet.viewmodels.MerchantViewModel
import java.lang.Exception
class MerchantsFragment : Fragment(), OnMapReadyCallback, retrofit2.Callback<FeathersResponse<Merchant>>,
class MerchantsFragment : Fragment(), OnMapReadyCallback,
ClusterManager.OnClusterClickListener<Merchant>,
ClusterManager.OnClusterItemClickListener<Merchant>,
ClusterManager.OnClusterItemInfoWindowClickListener<Merchant>{
@ -48,6 +44,8 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, retrofit2.Callback<Fea
private lateinit var mMap: GoogleMap
private lateinit var mMerchantViewModel: MerchantViewModel
private var mClusterManager: ClusterManager<Merchant>? = null
override fun onCreateView(
@ -63,6 +61,8 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, retrofit2.Callback<Fea
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
mMerchantViewModel = ViewModelProviders.of(this).get(MerchantViewModel::class.java)
}
private fun verifyLocationPermission() {
@ -123,17 +123,11 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, retrofit2.Callback<Fea
mClusterManager?.setOnClusterItemClickListener(this)
mClusterManager?.setOnClusterItemInfoWindowClickListener(this)
val gson = GsonBuilder()
.setLenient()
.create()
val retrofit = Retrofit.Builder()
.baseUrl(Constants.MERCHANTS_WEBSERVICE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
val ambassadorService = retrofit.create<MerchantsWebservice>(MerchantsWebservice::class.java)
val call = ambassadorService.getMerchants(0)
call.enqueue(this)
mMerchantViewModel.getAllMerchants().observe(this, Observer<List<Merchant>> {merchants ->
mClusterManager?.clearItems()
mClusterManager?.addItems(merchants)
mClusterManager?.cluster()
})
}
private fun applyMapTheme() {
@ -155,19 +149,6 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, retrofit2.Callback<Fea
}
}
override fun onResponse(call: Call<FeathersResponse<Merchant>>, response: Response<FeathersResponse<Merchant>>) {
if (response.isSuccessful) {
val res: FeathersResponse<Merchant>? = response.body()
val merchants = res?.data ?: return
mClusterManager?.addItems(merchants)
mClusterManager?.cluster()
} else {
Log.e("error_bitsy", response.errorBody()?.string())
}
}
override fun onFailure(call: Call<FeathersResponse<Merchant>>, t: Throwable) { /* Do nothing */ }
/**
* Animates the camera update to focus on an area that shows all the items from the cluster that was tapped.
*/

View File

@ -9,7 +9,9 @@ import retrofit2.http.Query
interface MerchantsWebservice {
@GET("/api/v1/merchants")
fun getMerchants(@Query(value = "\$skip") skip: Int): Call<FeathersResponse<Merchant>>
fun getMerchants(@Query(value = "\$skip") skip: Int,
@Query(value = "\$limit") limit: Int = 50):
Call<FeathersResponse<Merchant>>
@GET("api/v2/tellers")
fun getTellers(@Query(value = "\$skip") skip: Int): Call<FeathersResponse<Teller>>

View File

@ -0,0 +1,64 @@
package cy.agorise.bitsybitshareswallet.repositories
import android.content.Context
import android.os.AsyncTask
import androidx.lifecycle.LiveData
import cy.agorise.bitsybitshareswallet.database.BitsyDatabase
import cy.agorise.bitsybitshareswallet.database.daos.MerchantDao
import cy.agorise.bitsybitshareswallet.database.entities.Merchant
import cy.agorise.bitsybitshareswallet.network.FeathersResponse
import cy.agorise.bitsybitshareswallet.network.MerchantsWebservice
import cy.agorise.bitsybitshareswallet.utils.Constants
import retrofit2.Call
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
class MerchantRepository internal constructor(context: Context) : retrofit2.Callback<FeathersResponse<Merchant>> {
private val mMerchantDao: MerchantDao
init {
val db = BitsyDatabase.getDatabase(context)
mMerchantDao = db!!.merchantDao()
}
/**
* Returns a LiveData object directly from the database while the response from the WebService is obtained.
*/
fun getAll(): LiveData<List<Merchant>> {
refreshMerchants()
return mMerchantDao.getAll()
}
private fun refreshMerchants() {
val retrofit = Retrofit.Builder()
.baseUrl(Constants.MERCHANTS_WEBSERVICE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
val ambassadorService = retrofit.create<MerchantsWebservice>(MerchantsWebservice::class.java)
val call = ambassadorService.getMerchants(0)
call.enqueue(this)
}
override fun onResponse(call: Call<FeathersResponse<Merchant>>, response: Response<FeathersResponse<Merchant>>) {
if (response.isSuccessful) {
val res: FeathersResponse<Merchant>? = response.body()
val merchants = res?.data ?: return
insertAllAsyncTask(mMerchantDao).execute(merchants)
}
}
override fun onFailure(call: Call<FeathersResponse<Merchant>>, t: Throwable) { /* Do nothing */ }
private class insertAllAsyncTask internal constructor(private val mAsyncTaskDao: MerchantDao) :
AsyncTask<List<Merchant>, Void, Void>() {
override fun doInBackground(vararg merchants: List<Merchant>): Void? {
// TODO Delete all first
mAsyncTaskDao.insertAll(merchants[0])
return null
}
}
}

View File

@ -0,0 +1,15 @@
package cy.agorise.bitsybitshareswallet.viewmodels
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import cy.agorise.bitsybitshareswallet.database.entities.Merchant
import cy.agorise.bitsybitshareswallet.repositories.MerchantRepository
class MerchantViewModel(application: Application) : AndroidViewModel(application) {
private var mMerchantRepository = MerchantRepository(application)
internal fun getAllMerchants(): LiveData<List<Merchant>> {
return mMerchantRepository.getAll()
}
}