From 18987c3b31c2b8fe1a911297e8b104d583dd5c83 Mon Sep 17 00:00:00 2001 From: Iván Ávalos Date: Thu, 10 Mar 2022 20:33:40 -0600 Subject: - Card on map now updates info when there is a change - Huge device list performance improvements on search and updates --- .../TrackerMap/android/devices/DevicesAdapter.kt | 11 +++++- .../android/devices/DevicesDiffCallback.kt | 20 ++++++++++ .../TrackerMap/android/devices/DevicesFragment.kt | 7 +--- .../TrackerMap/android/map/UnitMapFragment.kt | 19 ++++++---- .../TrackerMap/android/units/UnitsActivity.kt | 3 -- .../TrackerMap/android/units/UnitsViewModel.kt | 44 +++++++++++++++++----- 6 files changed, 78 insertions(+), 26 deletions(-) create mode 100644 androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesDiffCallback.kt (limited to 'androidApp') diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesAdapter.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesAdapter.kt index 4cfd6b5..0fbf597 100644 --- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesAdapter.kt +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesAdapter.kt @@ -20,6 +20,7 @@ package mx.trackermap.TrackerMap.android.devices import android.view.LayoutInflater import android.view.ViewGroup import androidx.core.view.updateLayoutParams +import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import mx.trackermap.TrackerMap.android.R import mx.trackermap.TrackerMap.android.databinding.UnitItemBinding @@ -28,10 +29,18 @@ import mx.trackermap.TrackerMap.android.shared.UnitRenderData import mx.trackermap.TrackerMap.client.models.UnitInformation class DevicesAdapter( - private val units: List, + private val units: MutableList, private val actionCallback: ActionCallback? ) : RecyclerView.Adapter() { + fun setData(units: List) { + val diffCallback = DevicesDiffCallback(this.units, units) + val diffResult = DiffUtil.calculateDiff(diffCallback) + this.units.clear() + this.units.addAll(units) + diffResult.dispatchUpdatesTo(this) + } + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val binding = UnitItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesDiffCallback.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesDiffCallback.kt new file mode 100644 index 0000000..40e6e9c --- /dev/null +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesDiffCallback.kt @@ -0,0 +1,20 @@ +package mx.trackermap.TrackerMap.android.devices + +import androidx.recyclerview.widget.DiffUtil +import mx.trackermap.TrackerMap.client.models.UnitInformation + +class DevicesDiffCallback( + private val oldList: List, + private val newList: List +): DiffUtil.Callback() { + override fun getOldListSize() = oldList.size + + override fun getNewListSize() = newList.size + + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) = + oldList[oldItemPosition].device.id == newList[newItemPosition].device.id + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) = + (oldList[oldItemPosition].position?.id == newList[newItemPosition].position?.id) && newItemPosition != 0 + +} \ No newline at end of file diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesFragment.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesFragment.kt index ad93429..e5143cb 100644 --- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesFragment.kt +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesFragment.kt @@ -83,7 +83,7 @@ class DevicesFragment : Fragment() { context, LinearLayoutManager.VERTICAL, false ) - binding.devicesList.adapter = DevicesAdapter(emptyList(), null) + binding.devicesList.adapter = DevicesAdapter(mutableListOf(), this::itemAction) binding.infoLoading.root.visibility = View.VISIBLE } @@ -93,10 +93,7 @@ class DevicesFragment : Fragment() { unitsViewModel.units.observe(viewLifecycleOwner) { units -> Log.d("DevicesFragment", "Success $units") binding.infoLoading.root.visibility = View.GONE - binding.devicesList.swapAdapter( - DevicesAdapter(units, this::itemAction), - false - ) + (binding.devicesList.adapter as DevicesAdapter).setData(units) } } diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/UnitMapFragment.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/UnitMapFragment.kt index e7e5ce0..5e2224b 100644 --- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/UnitMapFragment.kt +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/UnitMapFragment.kt @@ -85,7 +85,7 @@ class UnitMapFragment : Fragment() { childFragmentManager.commit { replace(R.id.unitsMap, mapFragment) } - mapFragment.setMarkerCallback(unitsViewModel::selectUnitWith) + mapFragment.setMarkerCallback(unitsViewModel::selectUnitWithPositionId) } private fun setupObservers() { @@ -132,14 +132,16 @@ class UnitMapFragment : Fragment() { ), binding.mapUnitCard.context, unit, this::itemAction ) - unitsViewModel.moveCamera( - UnitsViewModel.Camera( - point = Point2d( - unit.position!!.longitude!!, unit.position!!.latitude!! - ), - animated = true + if (selectedUnit.device.id != unitsViewModel.oldSelectedUnit.value?.device?.id) { + unitsViewModel.moveCamera( + UnitsViewModel.Camera( + point = Point2d( + unit.position!!.longitude!!, unit.position!!.latitude!! + ), + animated = true + ) ) - ) + } } } @@ -178,6 +180,7 @@ class UnitMapFragment : Fragment() { unitsViewModel.selectedUnit.removeObservers(viewLifecycleOwner) unitsViewModel.mapLayerType.removeObservers(viewLifecycleOwner) unitsViewModel.geofences.removeObservers(viewLifecycleOwner) + unitsViewModel.camera.removeObservers(viewLifecycleOwner) } private fun itemAction(unit: UnitInformation, action: UnitRenderData.Action) { diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/units/UnitsActivity.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/units/UnitsActivity.kt index 4371eed..09bedbb 100644 --- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/units/UnitsActivity.kt +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/units/UnitsActivity.kt @@ -128,9 +128,6 @@ class UnitsActivity : AppCompatActivity() { } private fun setupObservers() { - unitsViewModel.units.observe(this) { - Toast.makeText(this, getString(R.string.shared_loading), Toast.LENGTH_SHORT).show() - } unitsViewModel.unitsDisplayMode.observe(this) { displayMode -> binding.displayModeToggle.setImageResource( when (displayMode) { diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/units/UnitsViewModel.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/units/UnitsViewModel.kt index ba29090..174d55e 100644 --- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/units/UnitsViewModel.kt +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/units/UnitsViewModel.kt @@ -54,6 +54,7 @@ class UnitsViewModel( private var _searchQuery = savedStateHandle.getLiveData("searchQuery", "") private var _unitsDisplayMode = MutableLiveData(UnitsDisplayMode.MAP) private var _units = MutableLiveData>() + private var _oldSelectedUnit = MutableLiveData() private var _selectedUnit = MutableLiveData() private var _mapLayerType = MutableLiveData() private var _geofences = MutableLiveData>() @@ -62,6 +63,7 @@ class UnitsViewModel( val searchQuery: LiveData get() = _searchQuery val unitsDisplayMode: LiveData get() = _unitsDisplayMode val units: LiveData> get() = _units + val oldSelectedUnit: LiveData get() = _oldSelectedUnit val selectedUnit: LiveData get() = _selectedUnit val mapLayerType: LiveData get() = _mapLayerType val geofences: LiveData> get() = _geofences @@ -82,6 +84,7 @@ class UnitsViewModel( Log.d("UnitsViewModel", "Setup observers") unitsController.displayedUnitsFlow.collect { units -> this._units.value = units + updateSelectedUnit() } } @@ -91,22 +94,45 @@ class UnitsViewModel( } } - fun selectUnit(unit: UnitInformation) { - Log.d("UnitsViewModel", "Selecting unit ${unit.device.name}") + fun selectUnit(unit: UnitInformation?, switchToMap: Boolean = true) { + Log.d("UnitsViewModel", "Selecting unit ${unit?.device?.name}") + _oldSelectedUnit.postValue(_selectedUnit.value) _selectedUnit.postValue(unit) - setDisplayMode(UnitsDisplayMode.MAP) + if (unit != null && switchToMap) { + setDisplayMode(UnitsDisplayMode.MAP) + } } - fun selectUnitWith(positionId: Int?) { - if (positionId == null) { + fun selectUnitWithPositionId(id: Int?, switchToMap: Boolean = true) { + if (id == null) { Log.d("UnitsViewModel", "Deselecting unit") - _selectedUnit.postValue(null) + selectUnit(null, switchToMap = switchToMap) return } - Log.d("UnitsViewModel", "Selecting unit with position id: $positionId") - val unit = _units.value?.find { it.position?.id == positionId } - _selectedUnit.postValue(unit) + Log.d("UnitsViewModel", "Selecting unit with position id: $id") + val unit = _units.value?.find { it.position?.id == id } + selectUnit(unit, switchToMap = switchToMap) + } + + private fun selectUnitWithUnitId(id: Int?, switchToMap: Boolean = true) { + if (id == null) { + Log.d("UnitsViewModel", "Deselecting unit") + selectUnit(null, switchToMap = switchToMap) + return + } + + Log.d("UnitsViewModel", "Selecting unit with device id: $id") + val unit = _units.value?.find { it.device.id == id } + selectUnit(unit, switchToMap = switchToMap) + } + + private fun updateSelectedUnit() { + selectedUnit.value?.let { selected -> + Log.d("UnitsViewModel", "Updating selected unit with id: ${selected.device.id}") + selectUnitWithUnitId(selected.device.id, switchToMap = false) + } + } fun setDisplayMode(displayMode: UnitsDisplayMode) { -- cgit v1.2.3 From 620cd5b1e2782adfd57660017878013f2fb896bd Mon Sep 17 00:00:00 2001 From: Iván Ávalos Date: Thu, 10 Mar 2022 21:03:52 -0600 Subject: Updated Android libraries --- androidApp/build.gradle.kts | 8 ++++---- androidApp/libs/WhirlyGlobeMaply.aar | Bin 7091003 -> 7331207 bytes .../TrackerMap/android/session/LoginFragment.kt | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'androidApp') diff --git a/androidApp/build.gradle.kts b/androidApp/build.gradle.kts index 6920eb1..5bb488c 100644 --- a/androidApp/build.gradle.kts +++ b/androidApp/build.gradle.kts @@ -49,13 +49,13 @@ dependencies { implementation("androidx.constraintlayout:constraintlayout:2.1.3") implementation("com.squareup.okhttp3:okhttp:4.9.1") implementation("com.github.Zhuinden:live-event:1.2.0") - implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0") - implementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.4.0") - implementation("androidx.preference:preference-ktx:1.1.1") + implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1") + implementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.4.1") + implementation("androidx.preference:preference-ktx:1.2.0") implementation("io.insert-koin:koin-android:3.1.4") implementation("androidx.core:core-ktx:1.7.0") implementation("androidx.activity:activity-ktx:1.4.0") - implementation("androidx.fragment:fragment-ktx:1.4.0") + implementation("androidx.fragment:fragment-ktx:1.4.1") implementation("io.ktor:ktor-client-serialization:1.6.6") implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.3.1") implementation("com.github.zerobranch:SwipeLayout:1.3.1") diff --git a/androidApp/libs/WhirlyGlobeMaply.aar b/androidApp/libs/WhirlyGlobeMaply.aar index 644e8ad..46aa91d 100644 Binary files a/androidApp/libs/WhirlyGlobeMaply.aar and b/androidApp/libs/WhirlyGlobeMaply.aar differ diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/LoginFragment.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/LoginFragment.kt index c855f44..6a30789 100644 --- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/LoginFragment.kt +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/LoginFragment.kt @@ -58,10 +58,10 @@ class LoginFragment : Fragment() { setupEvents() setupObservers() - broadcastManager = LocalBroadcastManager.getInstance(activity!!) + broadcastManager = LocalBroadcastManager.getInstance(requireActivity()) binding.urlEditText.setText( PreferenceManager - .getDefaultSharedPreferences(activity) + .getDefaultSharedPreferences(requireActivity()) .getString( PREFERENCE_SERVER_URL, getString(R.string.default_server_url) @@ -93,7 +93,7 @@ class LoginFragment : Fragment() { binding.passwordEditText.text.toString(), binding.urlEditText.text.toString(), PreferenceManager - .getDefaultSharedPreferences(activity) + .getDefaultSharedPreferences(requireActivity()) .getString(PREFERENCE_TOKEN, null) ) } @@ -127,7 +127,7 @@ class LoginFragment : Fragment() { } SessionController.LoginState.Success -> { PreferenceManager - .getDefaultSharedPreferences(activity) + .getDefaultSharedPreferences(requireActivity()) .edit() .putString(PREFERENCE_SERVER_URL, binding.urlEditText.text.toString()) .apply() @@ -148,7 +148,7 @@ class LoginFragment : Fragment() { override fun onReceive(p0: Context?, p1: Intent?) { p1?.getStringExtra(KEY_TOKEN)?.let { token -> PreferenceManager - .getDefaultSharedPreferences(activity) + .getDefaultSharedPreferences(requireActivity()) .edit() .putString(PREFERENCE_TOKEN, token) .apply() -- cgit v1.2.3