package org.pupes.mhdrunpathfinder import android.Manifest import android.app.Activity import android.content.Context import android.content.pm.PackageManager import android.location.Location import android.location.LocationListener import android.location.LocationManager import android.os.Handler import android.os.Looper import android.widget.Toast import androidx.core.app.ActivityCompat import ovh.plrapps.mapcompose.api.moveMarker // Handler for main thread operations private val LocationMainHandler = Handler(Looper.getMainLooper()) private var locationManager: LocationManager? = null private var locationListener: LocationListener? = null private var isLocationTracking = false // Location update configuration private const val MIN_TIME_BETWEEN_UPDATES = 1000L // 1 second in milliseconds private const val MIN_DISTANCE_CHANGE = 0f // 0 meters - update on any movement // LocationListener callback private val createLocationListener: (Activity) -> LocationListener = { callee -> LocationListener { location -> handleLocationUpdate(location, callee) } } private fun handleLocationUpdate(location: Location, callee: Activity) { try { val normalizedX = longitudeToXNormalized(location.longitude) val normalizedY = latitudeToYNormalized(location.latitude) // Update marker on main thread LocationMainHandler.post { try { mapState.moveMarker( "current_position", x = normalizedX, y = normalizedY ) } catch (e: Exception) { // Marker might not exist yet, silently ignore } } } catch (e: Exception) { LocationMainHandler.post { Toast.makeText(callee, "Location error: ${e.message}", Toast.LENGTH_SHORT).show() } } } // Check if location permissions are granted private fun hasLocationPermissions(context: Context): Boolean { return ActivityCompat.checkSelfPermission( context, Manifest.permission.ACCESS_FINE_LOCATION ) == PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission( context, Manifest.permission.ACCESS_COARSE_LOCATION ) == PackageManager.PERMISSION_GRANTED } // Start continuous location tracking fun startLocationTracking(callee: Activity) { if (isLocationTracking) { Toast.makeText(callee, "Location tracking already active", Toast.LENGTH_SHORT).show() return } if (!hasLocationPermissions(callee)) { Toast.makeText(callee, "Location permissions not granted", Toast.LENGTH_LONG).show() // Request permissions ActivityCompat.requestPermissions( callee, arrayOf( Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION ), LOCATION_PERMISSION_REQUEST_CODE ) return } try { locationManager = callee.getSystemService(Context.LOCATION_SERVICE) as LocationManager locationListener = createLocationListener(callee) // Try GPS first, then network provider val providers = listOf( LocationManager.GPS_PROVIDER, LocationManager.NETWORK_PROVIDER ) var providerFound = false for (provider in providers) { if (locationManager?.isProviderEnabled(provider) == true) { try { locationManager?.requestLocationUpdates( provider, MIN_TIME_BETWEEN_UPDATES, MIN_DISTANCE_CHANGE, locationListener!!, Looper.getMainLooper() ) providerFound = true // Get last known location and update immediately locationManager?.getLastKnownLocation(provider)?.let { location -> handleLocationUpdate(location, callee) } break } catch (e: SecurityException) { // Permission denied Toast.makeText(callee, "Location permission denied", Toast.LENGTH_LONG).show() return } } } if (!providerFound) { Toast.makeText(callee, "No location provider available. Please enable GPS or network location", Toast.LENGTH_LONG).show() return } isLocationTracking = true Toast.makeText(callee, "Location tracking started", Toast.LENGTH_SHORT).show() } catch (e: Exception) { Toast.makeText(callee, "Failed to start location tracking: ${e.message}", Toast.LENGTH_LONG).show() } } // Stop location tracking fun stopLocationTracking() { if (!isLocationTracking) return try { locationListener?.let { listener -> locationManager?.removeUpdates(listener) } locationListener = null locationManager = null isLocationTracking = false } catch (e: Exception) { // Silently handle cleanup errors } } // Get current tracking status fun isLocationTrackingActive(): Boolean { return isLocationTracking } // Permission request code const val LOCATION_PERMISSION_REQUEST_CODE = 1001