package org.pupes.mhdrunpathfinder import android.app.Activity import android.os.Handler import android.os.Looper import android.widget.Toast import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import okhttp3.OkHttpClient import ovh.plrapps.mapcompose.api.addPath import ovh.plrapps.mapcompose.api.moveMarker import ovh.plrapps.mapcompose.api.removePath import ovh.plrapps.mapcompose.api.updatePath import java.net.URL @Serializable data class HaukResponse( val type: Int, val expire: Long, val serverTime: Double, val interval: Int, val points: List>, val encrypted: Boolean, val salt: String? = null ) // OkHttpClient for making HTTP requests val haukhttpClient = OkHttpClient.Builder() .build() private val HaukMainHandler = Handler(Looper.getMainLooper()) private var HaukTrackingThread: Thread? = null var HaukIsTracking = false private var PathCreated = false private fun fetchHaukPosition(haukUrl: String, callee: Activity) { try { val url = URL(haukUrl) val targetId = url.toString().substringAfter("?") val request = okhttp3.Request.Builder() .url("${url.protocol}://${url.host}/api/fetch.php?id=$targetId") .header("User-Agent", "${BuildConfig.APPLICATION_ID}/${BuildConfig.VERSION_NAME} (Android)") .build() haukhttpClient.newCall(request).execute().use { response -> var message = if (response.isSuccessful) { response.body?.string() ?: "Empty response" } else { "Error: ${response.code} ${response.message}" } message = "{" + message.substringAfter("{"); val hauk_response = json.decodeFromString(message) val lat = hauk_response.points.last().getOrNull(0) val lon = hauk_response.points.last().getOrNull(1) if (lat != null && lon != null) { val lastlat = hauk_response.points.getOrNull(hauk_response.points.size - 2)?.getOrNull(0) val lastlon = hauk_response.points.getOrNull(hauk_response.points.size - 2)?.getOrNull(1) val newspeed = if (lastlat != null && lastlon != null) { var fulldistance: Double = 0.0 for (i in 1 until hauk_response.points.size -1) { try{ fulldistance += haversineDistance(hauk_response.points[i-1][0]!!, hauk_response.points[i-1][1]!!, hauk_response.points[i][0]!!, hauk_response.points[i][1]!!) } catch (e: Exception) { // Ignore } } (fulldistance / (hauk_response.interval * hauk_response.points.size)*3600) } else { 0.0 } HaukMainHandler.post { try { mapState.moveMarker("target_position", x = longitudeToXNormalized(lon), y = latitudeToYNormalized(lat)) target_speed = "${"%.1f".format(newspeed)}km/h" } catch (e: Exception) { // Marker might not exist yet, ignore } pathDataBuilder.addPoint(longitudeToXNormalized(lon), latitudeToYNormalized(lat)); if (!PathCreated) { mapState.addPath( "target_path", color = Color(0xFF0000FF), pathData = pathDataBuilder.build()?: return@post, width = 1.dp ); PathCreated = true } mapState.updatePath("target_path", pathData = pathDataBuilder.build()) } } else { HaukMainHandler.post { Toast.makeText(callee, "TARGET LOCATION NOT AVAILABLE", Toast.LENGTH_SHORT).show() } }} } catch (e: Exception) { // Post UI update to main thread HaukMainHandler.post { Toast.makeText(callee, e.message ?: "Unknown error", Toast.LENGTH_SHORT).show() } } } // Start the timer with a URL: fun startHaukTracking(url: String, callee: Activity) { if (HaukIsTracking) return HaukIsTracking = true HaukTrackingThread = Thread { while (HaukIsTracking) { fetchHaukPosition(url, callee) try { Thread.sleep(1000) // Wait 1 second between requests } catch (e: InterruptedException) { break } } }.apply { start() } } fun stopHaukTracking() { HaukIsTracking = false HaukTrackingThread?.interrupt() HaukTrackingThread = null mapState.removePath("target_path"); PathCreated = false; }