From 9f298ac64183bcf54d2531e0363b205a04e3366a Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 26 May 2026 09:13:38 +0000 Subject: Fix gallery photo timestamp and map pin not updating after note save MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gallery photos were always anchored to track.endMs with the final GPS position. Now reads EXIF DateTimeOriginal (parsed in device local time) after copying the file; if the timestamp falls within the track window the note is positioned at the correct time and nearest track point. Notes taken outside the window fall back to the previous behaviour. Map note layer was never refreshed after saving — drawNotes() ran once at style-load time and the GeoJsonSource was never updated. Added refreshNoteLayer() which updates the existing source or creates it if no notes existed before. https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD --- .../kotlin/org/terst/nav/track/TrackDetailSheet.kt | 48 +++++++++++++++++++--- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/android-app/app/src/main/kotlin/org/terst/nav/track/TrackDetailSheet.kt b/android-app/app/src/main/kotlin/org/terst/nav/track/TrackDetailSheet.kt index 7c26a01..f101779 100644 --- a/android-app/app/src/main/kotlin/org/terst/nav/track/TrackDetailSheet.kt +++ b/android-app/app/src/main/kotlin/org/terst/nav/track/TrackDetailSheet.kt @@ -1,5 +1,6 @@ package org.terst.nav.track +import android.media.ExifInterface import android.app.Activity import android.app.AlertDialog import android.content.Intent @@ -50,7 +51,9 @@ import java.io.FileOutputStream import java.time.Instant import java.time.ZoneId import java.time.format.DateTimeFormatter +import java.text.SimpleDateFormat import java.util.Locale +import java.util.TimeZone import kotlin.math.abs /** A notable event extracted from a track for display in the log step-through. */ @@ -72,6 +75,7 @@ class TrackDetailSheet : Fragment() { // Note-adding state private var pendingNotePhotoPath: String? = null + private var pendingNotePhotoTimestampMs: Long? = null private var noteDialogPhotoFrame: FrameLayout? = null private var noteDialogPhotoView: ImageView? = null private var logEventAdapter: LogEventAdapter? = null @@ -97,18 +101,20 @@ class TrackDetailSheet : Fragment() { ) { uri: Uri? -> if (uri != null) { lifecycleScope.launch { - val path = withContext(Dispatchers.IO) { + val result = withContext(Dispatchers.IO) { runCatching { val dir = NavApplication.logbookRepository.photoDir val dest = File(dir, "log_${System.currentTimeMillis()}.jpg") requireContext().contentResolver.openInputStream(uri)?.use { inp -> FileOutputStream(dest).use { out -> inp.copyTo(out) } } - dest.absolutePath + dest.absolutePath to readExifTimestamp(dest.absolutePath) }.getOrNull() } - if (path != null) { + if (result != null) { + val (path, ts) = result pendingNotePhotoPath = path + pendingNotePhotoTimestampMs = ts noteDialogPhotoView?.setImageURI(Uri.fromFile(File(path))) noteDialogPhotoFrame?.visibility = View.VISIBLE } @@ -182,6 +188,7 @@ class TrackDetailSheet : Fragment() { noteDialogPhotoFrame = dialogView.findViewById(R.id.frame_note_photo) noteDialogPhotoView = dialogView.findViewById(R.id.iv_note_photo) pendingNotePhotoPath = null + pendingNotePhotoTimestampMs = null noteDialogPhotoFrame?.visibility = View.GONE dialogView.findViewById