diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-07-01 06:24:45 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-07-01 06:24:45 +0000 |
| commit | c92dcd0d6407e506c84ca8bb79ab395257d7c392 (patch) | |
| tree | 594ba09d274f094bd5aac967d72d46193b40048b /android-app/app/src/main | |
| parent | 36d94937a561300197ef53aa9096defadfda3e72 (diff) | |
fix(aton): switch to org.json, add stale-cache fallback
Replace Gson dependency in AtonData with org.json.JSONObject (Android SDK
built-in) and add testImplementation for org.json to support unit tests.
AtonRepository now falls back to stale cache data when the network is
unavailable rather than returning an empty list.
Diffstat (limited to 'android-app/app/src/main')
| -rw-r--r-- | android-app/app/src/main/kotlin/org/terst/nav/ui/aton/AtonData.kt | 29 | ||||
| -rw-r--r-- | android-app/app/src/main/kotlin/org/terst/nav/ui/aton/AtonRepository.kt | 24 |
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() |
