From 6a8def0cf148aab1000df04f7920c1d448196024 Mon Sep 17 00:00:00 2001 From: Severiano Jaramillo Date: Thu, 24 Jan 2019 13:37:06 -0600 Subject: [PATCH] Make some changes to the Merchant's map Cluster logic, so that both Merchants and Tellers clusters work at the same time and automatically as the map camera moves. --- .../fragments/MerchantsFragment.kt | 93 +++++++++---------- .../repositories/MerchantRepository.kt | 7 ++ .../repositories/TellerRepository.kt | 7 ++ .../bitsybitshareswallet/utils/Constants.kt | 2 +- ...Renderer.kt => MerchantClusterRenderer.kt} | 2 +- ...erRenderer.kt => TellerClusterRenderer.kt} | 2 +- 6 files changed, 61 insertions(+), 52 deletions(-) rename app/src/main/java/cy/agorise/bitsybitshareswallet/utils/{MerchantMarkerRenderer.kt => MerchantClusterRenderer.kt} (96%) rename app/src/main/java/cy/agorise/bitsybitshareswallet/utils/{TellerMarkerRenderer.kt => TellerClusterRenderer.kt} (96%) diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/MerchantsFragment.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/MerchantsFragment.kt index 998866e..b244140 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/MerchantsFragment.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/MerchantsFragment.kt @@ -20,22 +20,21 @@ 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.MarkerManager import com.google.maps.android.clustering.Cluster +import com.google.maps.android.clustering.ClusterItem import com.google.maps.android.clustering.ClusterManager import cy.agorise.bitsybitshareswallet.database.entities.Merchant import cy.agorise.bitsybitshareswallet.database.entities.Teller import cy.agorise.bitsybitshareswallet.utils.Constants -import cy.agorise.bitsybitshareswallet.utils.MerchantMarkerRenderer -import cy.agorise.bitsybitshareswallet.utils.TellerMarkerRenderer +import cy.agorise.bitsybitshareswallet.utils.MerchantClusterRenderer +import cy.agorise.bitsybitshareswallet.utils.TellerClusterRenderer import cy.agorise.bitsybitshareswallet.utils.toast import cy.agorise.bitsybitshareswallet.viewmodels.MerchantViewModel import java.lang.Exception -class MerchantsFragment : Fragment(), OnMapReadyCallback, - ClusterManager.OnClusterClickListener, - ClusterManager.OnClusterItemClickListener, - ClusterManager.OnClusterItemInfoWindowClickListener{ +class MerchantsFragment : Fragment(), OnMapReadyCallback { companion object { private const val TAG = "MerchantsFragment" @@ -48,13 +47,12 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, private lateinit var mMerchantViewModel: MerchantViewModel + private var mMarkerManager: MarkerManager? = null + private var mMerchantClusterManager: ClusterManager? = null private var mTellerClusterManager: ClusterManager? = null - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_merchants, container, false) } @@ -68,17 +66,6 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, mMerchantViewModel = ViewModelProviders.of(this).get(MerchantViewModel::class.java) } - private fun verifyLocationPermission() { - if (ContextCompat.checkSelfPermission(activity!!, Manifest.permission.ACCESS_FINE_LOCATION) - != PackageManager.PERMISSION_GRANTED) { - // Permission is not already granted - requestPermissions(arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_LOCATION_PERMISSION) - } else { - // Permission is already granted - mMap.isMyLocationEnabled = true - } - } - /** Handles the result from the location permission request */ @SuppressLint("MissingPermission") override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { @@ -110,9 +97,19 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, verifyLocationPermission() + mMarkerManager = MarkerManager(mMap) + initMerchantsCluster() initTellersCluster() + + // Point the map's listeners at the listeners implemented by the cluster manager. + mMap.setOnMarkerClickListener(mMarkerManager) + + mMap.setOnCameraIdleListener { + mMerchantClusterManager?.onCameraIdle() + mTellerClusterManager?.onCameraIdle() + } } private fun applyMapTheme() { @@ -134,22 +131,25 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, } } + private fun verifyLocationPermission() { + if (ContextCompat.checkSelfPermission(activity!!, Manifest.permission.ACCESS_FINE_LOCATION) + != PackageManager.PERMISSION_GRANTED) { + // Permission is not already granted + requestPermissions(arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_LOCATION_PERMISSION) + } else { + // Permission is already granted + mMap.isMyLocationEnabled = true + } + } + private fun initMerchantsCluster() { // Setup clusters to group markers when possible - mMerchantClusterManager = ClusterManager(context, mMap) - val merchantRenderer = MerchantMarkerRenderer(context, mMap, mMerchantClusterManager) + mMerchantClusterManager = ClusterManager(context, mMap, mMarkerManager) + val merchantRenderer = MerchantClusterRenderer(context, mMap, mMerchantClusterManager) mMerchantClusterManager?.renderer = merchantRenderer - // Point the map's listeners at the listeners implemented by the cluster manager. - mMap.setOnCameraIdleListener(mMerchantClusterManager) - mMap.setOnMarkerClickListener(mMerchantClusterManager) - - mMap.setOnMarkerClickListener(mMerchantClusterManager) - mMap.setInfoWindowAdapter(mMerchantClusterManager?.markerManager) - mMap.setOnInfoWindowClickListener(mMerchantClusterManager) - mMerchantClusterManager?.setOnClusterClickListener(this) - mMerchantClusterManager?.setOnClusterItemClickListener(this) - mMerchantClusterManager?.setOnClusterItemInfoWindowClickListener(this) + mMerchantClusterManager?.setOnClusterClickListener { onClusterClick(it as Cluster) } + mMerchantClusterManager?.setOnClusterItemClickListener { false } mMerchantViewModel.getAllMerchants().observe(this, Observer> {merchants -> mMerchantClusterManager?.clearItems() @@ -160,10 +160,13 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, private fun initTellersCluster() { // Setup clusters to group markers when possible - mTellerClusterManager = ClusterManager(context, mMap) - val tellerRenderer = TellerMarkerRenderer(context, mMap, mTellerClusterManager) + mTellerClusterManager = ClusterManager(context, mMap, mMarkerManager) + val tellerRenderer = TellerClusterRenderer(context, mMap, mTellerClusterManager) mTellerClusterManager?.renderer = tellerRenderer + mTellerClusterManager?.setOnClusterClickListener { onClusterClick(it as Cluster) } + mTellerClusterManager?.setOnClusterItemClickListener { false } + mMerchantViewModel.getAllTellers().observe(this, Observer> {tellers -> mTellerClusterManager?.clearItems() mTellerClusterManager?.addItems(tellers) @@ -172,14 +175,14 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, } /** Animates the camera update to focus on an area that shows all the items from the cluster that was tapped. */ - override fun onClusterClick(cluster: Cluster?): Boolean { + private fun onClusterClick(cluster: Cluster?): Boolean { val builder = LatLngBounds.builder() - val merchantMarkers = cluster?.items + val items = cluster?.items - if (merchantMarkers != null) { - for (item in merchantMarkers) { - val merchantPosition = item.position - builder.include(merchantPosition) + if (items != null) { + for (item in items) { + val position = item.position + builder.include(position) } val bounds = builder.build() @@ -190,14 +193,6 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, Log.d(TAG, e.message) } } - return true } - - override fun onClusterItemClick(p0: Merchant?): Boolean { - return false - } - - override fun onClusterItemInfoWindowClick(p0: Merchant?) { - } } diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/MerchantRepository.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/MerchantRepository.kt index a70966b..615fde6 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/MerchantRepository.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/MerchantRepository.kt @@ -3,6 +3,7 @@ package cy.agorise.bitsybitshareswallet.repositories import android.content.Context import android.os.AsyncTask import android.preference.PreferenceManager +import android.util.Log import androidx.lifecycle.LiveData import cy.agorise.bitsybitshareswallet.database.BitsyDatabase import cy.agorise.bitsybitshareswallet.database.daos.MerchantDao @@ -17,6 +18,10 @@ import retrofit2.converter.gson.GsonConverterFactory class MerchantRepository internal constructor(val context: Context) : retrofit2.Callback> { + companion object { + private const val TAG = "MerchantRepository" + } + private val mMerchantDao: MerchantDao init { @@ -38,6 +43,8 @@ class MerchantRepository internal constructor(val context: Context) : retrofit2. val now = System.currentTimeMillis() if (lastMerchantUpdate + Constants.MERCHANTS_UPDATE_PERIOD < now) { + Log.d(TAG, "Updating merchants from webservice") + // TODO make sure it works when there are more merchants than those sent back in the first response val retrofit = Retrofit.Builder() .baseUrl(Constants.MERCHANTS_WEBSERVICE_URL) .addConverterFactory(GsonConverterFactory.create()) diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/TellerRepository.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/TellerRepository.kt index 21404ad..e96f818 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/TellerRepository.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/TellerRepository.kt @@ -3,6 +3,7 @@ package cy.agorise.bitsybitshareswallet.repositories import android.content.Context import android.os.AsyncTask import android.preference.PreferenceManager +import android.util.Log import androidx.lifecycle.LiveData import cy.agorise.bitsybitshareswallet.database.BitsyDatabase import cy.agorise.bitsybitshareswallet.database.daos.TellerDao @@ -17,6 +18,10 @@ import retrofit2.converter.gson.GsonConverterFactory class TellerRepository internal constructor(val context: Context) : retrofit2.Callback> { + companion object { + private const val TAG = "TellerRepository" + } + private val mTellerDao: TellerDao init { @@ -38,6 +43,8 @@ class TellerRepository internal constructor(val context: Context) : retrofit2.Ca val now = System.currentTimeMillis() if (lastTellerUpdate + Constants.MERCHANTS_UPDATE_PERIOD < now) { + Log.d(TAG, "Updating tellers from webservice") + // TODO make sure it works when there are more tellers than those sent back in the first response val retrofit = Retrofit.Builder() .baseUrl(Constants.MERCHANTS_WEBSERVICE_URL) .addConverterFactory(GsonConverterFactory.create()) diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/Constants.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/Constants.kt index 4137f35..592b280 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/Constants.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/Constants.kt @@ -1,6 +1,5 @@ package cy.agorise.bitsybitshareswallet.utils -import cy.agorise.graphenej.Asset import cy.agorise.graphenej.UserAccount object Constants { @@ -94,5 +93,6 @@ object Constants { /** Key used to store the last time in millis that the tellers info was refreshed */ const val KEY_TELLERS_LAST_UPDATE = "key_tellers_last_update" + /** Constant used to decide whether or not to update the tellers and merchants info from the webservice */ const val MERCHANTS_UPDATE_PERIOD = 1000L * 60 * 60 + 24 // 1 day } diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/MerchantMarkerRenderer.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/MerchantClusterRenderer.kt similarity index 96% rename from app/src/main/java/cy/agorise/bitsybitshareswallet/utils/MerchantMarkerRenderer.kt rename to app/src/main/java/cy/agorise/bitsybitshareswallet/utils/MerchantClusterRenderer.kt index b8d1096..36039a6 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/MerchantMarkerRenderer.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/MerchantClusterRenderer.kt @@ -21,7 +21,7 @@ import cy.agorise.bitsybitshareswallet.database.entities.Merchant /** * This class is used to create custom merchant and merchant cluster icons to show on the map. */ -class MerchantMarkerRenderer(val context: Context?, map: GoogleMap?, clusterManager: ClusterManager?) : +class MerchantClusterRenderer(val context: Context?, map: GoogleMap?, clusterManager: ClusterManager?) : DefaultClusterRenderer(context, map, clusterManager) { // Icons used to display merchants and merchants' clusters on the map diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/TellerMarkerRenderer.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/TellerClusterRenderer.kt similarity index 96% rename from app/src/main/java/cy/agorise/bitsybitshareswallet/utils/TellerMarkerRenderer.kt rename to app/src/main/java/cy/agorise/bitsybitshareswallet/utils/TellerClusterRenderer.kt index b8f6620..1cc2ad5 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/TellerMarkerRenderer.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/TellerClusterRenderer.kt @@ -21,7 +21,7 @@ import cy.agorise.bitsybitshareswallet.database.entities.Teller /** * This class is used to create custom merchant and merchant cluster icons to show on the map. */ -class TellerMarkerRenderer(val context: Context?, map: GoogleMap?, clusterManager: ClusterManager?) : +class TellerClusterRenderer(val context: Context?, map: GoogleMap?, clusterManager: ClusterManager?) : DefaultClusterRenderer(context, map, clusterManager) { // Icons used to display merchants and merchants' clusters on the map