Merge branch 'main' into issue_6008

This commit is contained in:
Nicolas Raoul 2025-06-29 18:30:56 +09:00 committed by GitHub
commit e0ec3d1ef5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -123,6 +123,7 @@ import org.osmdroid.views.CustomZoomButtonsController
import org.osmdroid.views.MapView import org.osmdroid.views.MapView
import org.osmdroid.views.overlay.MapEventsOverlay import org.osmdroid.views.overlay.MapEventsOverlay
import org.osmdroid.views.overlay.Marker import org.osmdroid.views.overlay.Marker
import org.osmdroid.views.overlay.Overlay
import org.osmdroid.views.overlay.ScaleBarOverlay import org.osmdroid.views.overlay.ScaleBarOverlay
import org.osmdroid.views.overlay.ScaleDiskOverlay import org.osmdroid.views.overlay.ScaleDiskOverlay
import org.osmdroid.views.overlay.TilesOverlay import org.osmdroid.views.overlay.TilesOverlay
@ -267,6 +268,9 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
private var dataList: MutableList<BottomSheetItem>? = null private var dataList: MutableList<BottomSheetItem>? = null
private var bottomSheetAdapter: BottomSheetAdapter? = null private var bottomSheetAdapter: BottomSheetAdapter? = null
private var userLocationOverlay: Overlay? = null
private var userLocationErrorOverlay: Overlay? = null
private val galleryPickLauncherForResult = private val galleryPickLauncherForResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
controller?.handleActivityResultWithCallback( controller?.handleActivityResultWithCallback(
@ -724,7 +728,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
val targetP = GeoPoint(target.latitude, target.longitude) val targetP = GeoPoint(target.latitude, target.longitude)
mapCenter = targetP mapCenter = targetP
binding?.map?.controller?.setCenter(targetP) binding?.map?.controller?.setCenter(targetP)
recenterMarkerToPosition(targetP) updateUserLocationOverlays(targetP, true)
if (!isCameFromExploreMap()) { if (!isCameFromExploreMap()) {
moveCameraToPosition(targetP) moveCameraToPosition(targetP)
} }
@ -1863,6 +1867,8 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
lastKnownLocation = latLng lastKnownLocation = latLng
NearbyController.currentLocation = lastKnownLocation NearbyController.currentLocation = lastKnownLocation
presenter!!.updateMapAndList(locationChangeType) presenter!!.updateMapAndList(locationChangeType)
updateUserLocationOverlays(GeoPoint(latLng.latitude, latLng.longitude), true)
} }
override fun onLocationChangedSignificantly(latLng: LatLng) { override fun onLocationChangedSignificantly(latLng: LatLng) {
@ -2644,43 +2650,14 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
*/ */
override fun clearAllMarkers() { override fun clearAllMarkers() {
binding!!.map.overlayManager.clear() binding!!.map.overlayManager.clear()
binding!!.map.invalidate()
val geoPoint = mapCenter var geoPoint = mapCenter
if (geoPoint != null) { val lastLatLng = locationManager.getLastLocation()
val diskOverlay = if (lastLatLng != null) {
ScaleDiskOverlay( geoPoint = GeoPoint(lastLatLng.latitude, lastLatLng.longitude)
this.context,
geoPoint, 2000, UnitOfMeasure.foot
)
val circlePaint = Paint()
circlePaint.color = Color.rgb(128, 128, 128)
circlePaint.style = Paint.Style.STROKE
circlePaint.strokeWidth = 2f
diskOverlay.setCirclePaint2(circlePaint)
val diskPaint = Paint()
diskPaint.color = Color.argb(40, 128, 128, 128)
diskPaint.style = Paint.Style.FILL_AND_STROKE
diskOverlay.setCirclePaint1(diskPaint)
diskOverlay.setDisplaySizeMin(900)
diskOverlay.setDisplaySizeMax(1700)
binding!!.map.overlays.add(diskOverlay)
val startMarker = Marker(
binding!!.map
)
startMarker.position = geoPoint
startMarker.setAnchor(
Marker.ANCHOR_CENTER,
Marker.ANCHOR_BOTTOM
)
startMarker.icon =
getDrawable(
this.requireContext(),
fr.free.nrw.commons.R.drawable.current_location_marker
)
startMarker.title = "Your Location"
startMarker.textLabelFontSize = 24
binding!!.map.overlays.add(startMarker)
} }
updateUserLocationOverlays(geoPoint, false)
val scaleBarOverlay = ScaleBarOverlay(binding!!.map) val scaleBarOverlay = ScaleBarOverlay(binding!!.map)
scaleBarOverlay.setScaleBarOffset(15, 25) scaleBarOverlay.setScaleBarOffset(15, 25)
val barPaint = Paint() val barPaint = Paint()
@ -2690,6 +2667,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
binding!!.map.overlays.add(scaleBarOverlay) binding!!.map.overlays.add(scaleBarOverlay)
binding!!.map.overlays.add(mapEventsOverlay) binding!!.map.overlays.add(mapEventsOverlay)
binding!!.map.setMultiTouchControls(true) binding!!.map.setMultiTouchControls(true)
binding!!.map.invalidate()
} }
/** /**
@ -2700,45 +2678,149 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
private fun recenterMarkerToPosition(geoPoint: GeoPoint?) { private fun recenterMarkerToPosition(geoPoint: GeoPoint?) {
geoPoint?.let { geoPoint?.let {
binding?.map?.controller?.setCenter(it) binding?.map?.controller?.setCenter(it)
val overlays = binding?.map?.overlays ?: return@let
// Remove markers and disks using index-based removal updateUserLocationOverlays(it, true);
var i = 0
while (i < overlays.size) {
when (overlays[i]) {
is Marker, is ScaleDiskOverlay -> overlays.removeAt(i)
else -> i++
}
}
// Add disk overlay
ScaleDiskOverlay(context, it, 2000, UnitOfMeasure.foot).apply {
setCirclePaint2(Paint().apply {
color = Color.rgb(128, 128, 128)
style = Paint.Style.STROKE
strokeWidth = 2f
})
setCirclePaint1(Paint().apply {
color = Color.argb(40, 128, 128, 128)
style = Paint.Style.FILL_AND_STROKE
})
setDisplaySizeMin(900)
setDisplaySizeMax(1700)
overlays.add(this)
}
// Add marker
Marker(binding?.map).apply {
position = it
setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
icon = getDrawable(context, R.drawable.current_location_marker)
title = "Your Location"
textLabelFontSize = 24
overlays.add(this)
}
} }
} }
/**
* Updates the user current location overlays (both the location and error overlays) by
* replacing any existing location overlays with new overlays at the given GeoPoint. If there
* are no existing location and error overlays, then new overlays are added.
*
* @param geoPoint The GeoPoint representing the user's current location.
* @param invalidate If true, the map overlays will be invalidated after the user
* location overlays are updated/added. If false, the overlays will not be invalidated.
*/
private fun updateUserLocationOverlays(geoPoint: GeoPoint?, invalidate: Boolean) {
geoPoint?.let{
updateUserLocationOverlay(geoPoint)
updateUserLocationErrorOverlay(geoPoint)
}
if (invalidate) {
binding!!.map.invalidate()
}
}
/**
* 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.
*/
private fun getCurrentLocationAccuracy(): Float {
var accuracy = 0f
val lastLocation = locationManager.getLastLocation()
if (lastLocation != null) {
accuracy = lastLocation.accuracy
}
return accuracy
}
/**
* Creates the current location overlay
*
* @param geoPoint The GeoPoint where the current location overlay will be placed.
*
* @return The current location overlay as a Marker
*/
private fun createCurrentLocationOverlay(geoPoint: GeoPoint): Marker {
val currentLocationOverlay = Marker(
binding!!.map
)
currentLocationOverlay.position = geoPoint
currentLocationOverlay.icon =
getDrawable(
this.requireContext(),
fr.free.nrw.commons.R.drawable.current_location_marker
)
currentLocationOverlay.title = "Your Location"
currentLocationOverlay.textLabelFontSize = 24
currentLocationOverlay.setAnchor(0.5f, 0.5f)
return currentLocationOverlay
}
/**
* Creates the location error overlay to show the user how accurate the current location
* overlay is. The edge of the disk is the 95% confidence interval.
*
* @param context The Android context
* @param point The user's location as a GeoPoint
* @param value The radius of the disk
* @param unitOfMeasure The unit of measurement of the value/disk radius.
*
* @return The location error overlay as a ScaleDiskOverlay.
*/
private fun createCurrentLocationErrorOverlay(context: Context?, point: GeoPoint, value: Int,
unitOfMeasure: UnitOfMeasure): ScaleDiskOverlay {
val scaleDisk = ScaleDiskOverlay(context, point, value, unitOfMeasure)
scaleDisk.setCirclePaint2(Paint().apply {
color = Color.rgb(128, 128, 128)
style = Paint.Style.STROKE
strokeWidth = 2f
})
scaleDisk.setCirclePaint1(Paint().apply {
color = Color.argb(40, 128, 128, 128)
style = Paint.Style.FILL_AND_STROKE
})
return scaleDisk
}
private fun moveCameraToPosition(geoPoint: GeoPoint) { private fun moveCameraToPosition(geoPoint: GeoPoint) {
binding!!.map.controller.animateTo(geoPoint) binding!!.map.controller.animateTo(geoPoint)
} }