summaryrefslogtreecommitdiff
path: root/android-app/app/src/main/kotlin/com/example/androidapp
diff options
context:
space:
mode:
Diffstat (limited to 'android-app/app/src/main/kotlin/com/example/androidapp')
-rw-r--r--android-app/app/src/main/kotlin/com/example/androidapp/data/storage/GribFileManager.kt24
-rw-r--r--android-app/app/src/main/kotlin/com/example/androidapp/data/weather/GribStalenessChecker.kt36
2 files changed, 60 insertions, 0 deletions
diff --git a/android-app/app/src/main/kotlin/com/example/androidapp/data/storage/GribFileManager.kt b/android-app/app/src/main/kotlin/com/example/androidapp/data/storage/GribFileManager.kt
new file mode 100644
index 0000000..b336818
--- /dev/null
+++ b/android-app/app/src/main/kotlin/com/example/androidapp/data/storage/GribFileManager.kt
@@ -0,0 +1,24 @@
+package com.example.androidapp.data.storage
+
+import com.example.androidapp.data.model.GribFile
+import com.example.androidapp.data.model.GribRegion
+import java.time.Instant
+
+interface GribFileManager {
+ fun saveMetadata(file: GribFile)
+ fun listFiles(region: GribRegion): List<GribFile>
+ fun latestFile(region: GribRegion): GribFile?
+ fun delete(file: GribFile): Boolean
+ fun purgeOlderThan(before: Instant): Int
+ fun totalSizeBytes(): Long
+}
+
+class InMemoryGribFileManager : GribFileManager {
+ private val files = mutableListOf<GribFile>()
+ override fun saveMetadata(file: GribFile) { files.add(file) }
+ override fun listFiles(region: GribRegion): List<GribFile> = files.filter { it.region.name == region.name }.sortedByDescending { it.downloadedAt }
+ override fun latestFile(region: GribRegion): GribFile? = listFiles(region).firstOrNull()
+ override fun delete(file: GribFile): Boolean = files.remove(file)
+ override fun purgeOlderThan(before: Instant): Int { val toRemove = files.filter { it.downloadedAt.isBefore(before) }; files.removeAll(toRemove); return toRemove.size }
+ override fun totalSizeBytes(): Long = files.sumOf { it.sizeBytes }
+}
diff --git a/android-app/app/src/main/kotlin/com/example/androidapp/data/weather/GribStalenessChecker.kt b/android-app/app/src/main/kotlin/com/example/androidapp/data/weather/GribStalenessChecker.kt
new file mode 100644
index 0000000..63466b2
--- /dev/null
+++ b/android-app/app/src/main/kotlin/com/example/androidapp/data/weather/GribStalenessChecker.kt
@@ -0,0 +1,36 @@
+package com.example.androidapp.data.weather
+
+import com.example.androidapp.data.model.GribFile
+import com.example.androidapp.data.storage.GribFileManager
+import com.example.androidapp.data.model.GribRegion
+import java.time.Instant
+
+/** Outcome of a freshness check. */
+sealed class FreshnessResult {
+ /** Data is current; no user action needed. */
+ object Fresh : FreshnessResult()
+ /** Data is stale; user should re-download. [message] is shown in the UI badge. */
+ data class Stale(val file: GribFile, val message: String) : FreshnessResult()
+ /** No local GRIB data exists for this region. */
+ object NoData : FreshnessResult()
+}
+
+/**
+ * Checks whether locally-stored GRIB data for a region is fresh or stale.
+ * Per design doc ยง6.3: GRIB weather valid until model run + forecast hour; stale after.
+ */
+class GribStalenessChecker(private val manager: GribFileManager) {
+
+ /**
+ * Check freshness of the most-recent GRIB file for [region] relative to [now].
+ */
+ fun check(region: GribRegion, now: Instant = Instant.now()): FreshnessResult {
+ val latest = manager.latestFile(region) ?: return FreshnessResult.NoData
+ return if (latest.isStale(now)) {
+ val hoursAgo = (now.epochSecond - latest.validUntil().epochSecond) / 3600
+ FreshnessResult.Stale(latest, "Weather data outdated by ${hoursAgo}h โ€” tap to refresh")
+ } else {
+ FreshnessResult.Fresh
+ }
+ }
+}