NearbyParentFragment.kt: fix bug where multiple user location overlays would appear

Before this commit, the user could see multiple user location overlays if they paused the app and reopened it when
there are no Places/pins on the map. This was caused by a linear search failing to identify the target overlay
because it compared Drawables between two Overlays, which was unreliable.

This commit contains a better solution for replacing existing user location overlays by adding 2 instance variables
to keep track of the overlays. The position of these overlays in the overlay list can then be found by using indexOf()
with these instance variables rather than the linear search that was implemented before. Some refactoring was also done.
This commit is contained in:
Jason Whitmore 2025-06-25 18:36:59 -07:00
parent 01b0d5251b
commit c684008803

View file

@ -123,6 +123,7 @@ import org.osmdroid.views.CustomZoomButtonsController
import org.osmdroid.views.MapView
import org.osmdroid.views.overlay.MapEventsOverlay
import org.osmdroid.views.overlay.Marker
import org.osmdroid.views.overlay.Overlay
import org.osmdroid.views.overlay.ScaleBarOverlay
import org.osmdroid.views.overlay.ScaleDiskOverlay
import org.osmdroid.views.overlay.TilesOverlay
@ -267,6 +268,9 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
private var dataList: MutableList<BottomSheetItem>? = null
private var bottomSheetAdapter: BottomSheetAdapter? = null
private var userLocationOverlay: Overlay? = null
private var userLocationErrorOverlay: Overlay? = null
private val galleryPickLauncherForResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
controller?.handleActivityResultWithCallback(
@ -2690,47 +2694,8 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
*/
private fun updateUserLocationOverlays(geoPoint: GeoPoint?, invalidate: Boolean) {
geoPoint?.let{
val overlays = binding?.map?.overlays ?: return@let
// Multiply accuracy by 2 to get 95% confidence interval
val accuracy = getCurrentLocationAccuracy() * 2
// Create disk overlay
val errorOverlay = createCurrentLocationErrorOverlay(this.context, geoPoint,
(accuracy).toInt(), UnitOfMeasure.meter)
// Create current location overlay
val locationOverlay = createCurrentLocationOverlay(geoPoint)
var locationOverlayFound = false
var errorOverlayFound = false
// Find and replace overlays
for (i in overlays.indices) {
val overlay = overlays[i]
if (overlay is ScaleDiskOverlay) {
overlays[i] = errorOverlay
errorOverlayFound = true
}
if (overlay is Marker && overlay.icon.equals(locationOverlay.icon)) {
overlays[i] = locationOverlay
locationOverlayFound = true
}
if (errorOverlayFound && locationOverlayFound) {
break
}
}
// If the user location overlays were not found, add them
if (!errorOverlayFound) {
overlays.add(errorOverlay)
}
if (!locationOverlayFound) {
overlays.add(locationOverlay)
}
updateUserLocationOverlay(geoPoint)
updateUserLocationErrorOverlay(geoPoint)
}
if (invalidate) {
@ -2738,6 +2703,57 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
}
}
/**
* Updates the user location error overlay by either replacing it with or adding a new one.
*
* If the user location error overlay is null, the new overlay is added. If the
* overlay is not null, it is replaced by the new overlay.
*
* @param geoPoint The GeoPoint representing the user's location
*/
private fun updateUserLocationErrorOverlay(geoPoint: GeoPoint) {
val overlays = binding?.map?.overlays ?: return
// Multiply accuracy by 2 to get 95% confidence interval
val accuracy = getCurrentLocationAccuracy() * 2
val overlay = createCurrentLocationErrorOverlay(this.context, geoPoint,
(accuracy).toInt(), UnitOfMeasure.meter)
val index = overlays.indexOf(userLocationErrorOverlay)
if (userLocationErrorOverlay == null || index == -1) {
overlays.add(overlay)
} else {
overlays[index] = overlay
}
userLocationErrorOverlay = overlay
}
/**
* Updates the user location overlay by either replacing it with or adding a new one.
*
* If the user location overlay is null, the new overlay is added. If the
* overlay is not null, it is replaced by the new overlay.
*
* @param geoPoint The GeoPoint representing the user's location
*/
private fun updateUserLocationOverlay(geoPoint: GeoPoint) {
val overlays = binding?.map?.overlays ?: return
val overlay = createCurrentLocationOverlay(geoPoint)
val index = overlays.indexOf(userLocationOverlay)
if (userLocationOverlay == null || index == -1) {
overlays.add(overlay)
} else {
overlays[index] = overlay
}
userLocationOverlay = overlay
}
/**
* @return The accuracy of the current location with a confidence at the 68th percentile.
* Units are in meters. Returning 0 may indicate failure.