summaryrefslogtreecommitdiff
path: root/android-app/app/src/main
diff options
context:
space:
mode:
authorClaude <noreply@anthropic.com>2026-05-25 19:02:33 +0000
committerClaude <noreply@anthropic.com>2026-05-25 19:02:33 +0000
commit04b5b7f6aa469a368bcf8f1d75046770d3f83d63 (patch)
tree42bd875500262561e3402cc7e2cadb61452ea221 /android-app/app/src/main
parent620aa6c7419a611639be5f005c34a27e19bfee89 (diff)
Fix bugs from static analysis; add test coverage for new code
Bugs fixed: - LogbookStorage.copyFromUri: return null when ContentResolver returns null stream instead of returning a path to an unwritten file - VoiceLogFragment adapter: decode photos as downsampled thumbnails (128x96 target) using BitmapFactory inSampleSize instead of loading full-resolution bitmaps on the main thread Tests added: - LogbookRepositoryTest: ID sequencing, insertion order, storage delegation, reload from persisted state, lat/lon preservation - TripReportGeneratorTest: log entry time-range filtering, distance calculation, empty-points edge case, all narrative styles smoke-tested https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn
Diffstat (limited to 'android-app/app/src/main')
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/logbook/LogbookStorage.kt5
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/ui/voicelog/VoiceLogFragment.kt13
2 files changed, 14 insertions, 4 deletions
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/logbook/LogbookStorage.kt b/android-app/app/src/main/kotlin/org/terst/nav/logbook/LogbookStorage.kt
index 35349f0..6b90542 100644
--- a/android-app/app/src/main/kotlin/org/terst/nav/logbook/LogbookStorage.kt
+++ b/android-app/app/src/main/kotlin/org/terst/nav/logbook/LogbookStorage.kt
@@ -44,9 +44,8 @@ class LogbookStorage(private val context: Context) {
fun copyFromUri(uri: Uri): String? = runCatching {
val dest = File(photoDir, "log_${System.currentTimeMillis()}.jpg")
- context.contentResolver.openInputStream(uri)?.use { input ->
- FileOutputStream(dest).use { output -> input.copyTo(output) }
- }
+ val stream = context.contentResolver.openInputStream(uri) ?: return null
+ stream.use { input -> FileOutputStream(dest).use { output -> input.copyTo(output) } }
dest.absolutePath
}.getOrElse { null }
}
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/ui/voicelog/VoiceLogFragment.kt b/android-app/app/src/main/kotlin/org/terst/nav/ui/voicelog/VoiceLogFragment.kt
index 31d9715..3638f8f 100644
--- a/android-app/app/src/main/kotlin/org/terst/nav/ui/voicelog/VoiceLogFragment.kt
+++ b/android-app/app/src/main/kotlin/org/terst/nav/ui/voicelog/VoiceLogFragment.kt
@@ -368,6 +368,16 @@ class VoiceLogFragment : Fragment() {
}
}
+// ── Helpers ────────────────────────────────────────────────────────────────────
+
+private fun decodeThumbnail(path: String, targetW: Int, targetH: Int): android.graphics.Bitmap? {
+ val opts = BitmapFactory.Options().apply { inJustDecodeBounds = true }
+ BitmapFactory.decodeFile(path, opts)
+ if (opts.outWidth <= 0) return null
+ val scale = maxOf(opts.outWidth / targetW, opts.outHeight / targetH).coerceAtLeast(1)
+ return BitmapFactory.decodeFile(path, BitmapFactory.Options().apply { inSampleSize = scale })
+}
+
// ── Logbook entries adapter ────────────────────────────────────────────────────
private val TIME_FMT: DateTimeFormatter =
@@ -409,11 +419,12 @@ private class LogbookEntryAdapter : RecyclerView.Adapter<LogbookEntryAdapter.VH>
val photoPath = e.photoPath
if (photoPath != null && File(photoPath).exists()) {
- val bm = BitmapFactory.decodeFile(photoPath)
+ val bm = decodeThumbnail(photoPath, 128, 96)
if (bm != null) {
holder.ivPhoto.setImageBitmap(bm)
holder.ivPhoto.visibility = View.VISIBLE
} else {
+ holder.ivPhoto.setImageDrawable(null)
holder.ivPhoto.visibility = View.GONE
}
} else {