Files
MHDrunPathfinder/app/src/main/java/org/pupes/mhdrunpathfinder/HaukUtils.kt
T

138 lines
4.9 KiB
Kotlin

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<List<Double?>>,
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<HaukResponse>(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;
}