summaryrefslogtreecommitdiff
path: root/android-app/app/src
diff options
context:
space:
mode:
Diffstat (limited to 'android-app/app/src')
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/ui/aton/AtonData.kt29
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/ui/aton/AtonRepository.kt24
2 files changed, 26 insertions, 27 deletions
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/ui/aton/AtonData.kt b/android-app/app/src/main/kotlin/org/terst/nav/ui/aton/AtonData.kt
index 2ff59cd..d3a6b6b 100644
--- a/android-app/app/src/main/kotlin/org/terst/nav/ui/aton/AtonData.kt
+++ b/android-app/app/src/main/kotlin/org/terst/nav/ui/aton/AtonData.kt
@@ -1,9 +1,8 @@
package org.terst.nav.ui.aton
-import com.google.gson.JsonObject
-import com.google.gson.JsonParser
import org.maplibre.geojson.Feature
import org.maplibre.geojson.Point
+import org.json.JSONObject
object AtonData {
fun colorFor(type: String): String = when (type) {
@@ -14,24 +13,20 @@ object AtonData {
}
fun parseStation(json: String): Feature? = try {
- val obj = JsonParser.parseString(json).asJsonObject
- val lat = obj.get("lat").asDouble
- val lng = obj.get("lng").asDouble
- val type = obj.get("type")?.asString ?: ""
- val id = obj.get("id")?.asString ?: ""
- val name = obj.get("name")?.asString ?: ""
- val props = JsonObject().apply {
- addProperty("id", id)
- addProperty("name", name)
- addProperty("type", type)
- addProperty("color", colorFor(type))
+ val obj = JSONObject(json)
+ val lat = obj.getDouble("lat")
+ val lng = obj.getDouble("lng")
+ val type = obj.optString("type", "")
+ Feature.fromGeometry(Point.fromLngLat(lng, lat)).apply {
+ addStringProperty("id", obj.optString("id"))
+ addStringProperty("name", obj.optString("name"))
+ addStringProperty("type", type)
+ addStringProperty("color", colorFor(type))
}
- Feature.fromGeometry(Point.fromLngLat(lng, lat), props)
} catch (_: Exception) { null }
fun parseResponse(json: String): List<Feature> = try {
- val arr = JsonParser.parseString(json).asJsonObject
- .getAsJsonArray("stations")
- arr.mapNotNull { parseStation(it.toString()) }
+ val arr = JSONObject(json).getJSONArray("stations")
+ (0 until arr.length()).mapNotNull { parseStation(arr.get(it).toString()) }
} catch (_: Exception) { emptyList() }
}
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/ui/aton/AtonRepository.kt b/android-app/app/src/main/kotlin/org/terst/nav/ui/aton/AtonRepository.kt
index b5472b3..249fdac 100644
--- a/android-app/app/src/main/kotlin/org/terst/nav/ui/aton/AtonRepository.kt
+++ b/android-app/app/src/main/kotlin/org/terst/nav/ui/aton/AtonRepository.kt
@@ -16,18 +16,22 @@ class AtonRepository(private val context: Context) {
"https://api.tidesandcurrents.noaa.gov/mdapi/prod/webapi/stations.json?type=aton&units=english"
suspend fun getFeatures(): List<Feature> = withContext(Dispatchers.IO) {
- val cached = readCache()
- if (cached != null) return@withContext AtonData.parseResponse(cached)
- val fresh = fetchFromApi() ?: return@withContext emptyList()
- cacheFile.writeText(fresh)
- AtonData.parseResponse(fresh)
+ val staleJson = readCacheRaw()
+ if (staleJson != null && isCacheFresh()) return@withContext AtonData.parseResponse(staleJson)
+ val fresh = fetchFromApi()
+ if (fresh != null) {
+ cacheFile.writeText(fresh)
+ return@withContext AtonData.parseResponse(fresh)
+ }
+ // Network unavailable — serve stale data if any, otherwise empty
+ if (staleJson != null) AtonData.parseResponse(staleJson) else emptyList()
}
- private fun readCache(): String? {
- if (!cacheFile.exists()) return null
- if (System.currentTimeMillis() - cacheFile.lastModified() > maxAgeMs) return null
- return cacheFile.readText()
- }
+ private fun isCacheFresh(): Boolean =
+ cacheFile.exists() && System.currentTimeMillis() - cacheFile.lastModified() <= maxAgeMs
+
+ private fun readCacheRaw(): String? =
+ if (cacheFile.exists()) runCatching { cacheFile.readText() }.getOrNull() else null
private fun fetchFromApi(): String? = try {
URL(apiUrl).openStream().bufferedReader().readText()