diff options
| author | Claude <noreply@anthropic.com> | 2026-05-26 04:57:28 +0000 |
|---|---|---|
| committer | Claude <noreply@anthropic.com> | 2026-05-26 04:57:28 +0000 |
| commit | d35410c707900075bf4207bab518ead44d43c6e7 (patch) | |
| tree | 53f8f63c41fe86104b4875df4a3e157e20f7bce4 | |
| parent | 70c1698ebc9e9661724e5326ae1c93f2b74c2b09 (diff) | |
Fix camera to open system camera app; harden logbook storage; add backlog
Camera:
- Replace ActivityResultContracts.TakePicture() with explicit
StartActivityForResult + Intent(ACTION_IMAGE_CAPTURE) + EXTRA_OUTPUT
so the full system camera app always opens (not a sub-view preview)
- FLAG_GRANT_WRITE_URI_PERMISSION added for camera app FileProvider access
LogbookStorage:
- getExternalFilesDir() can return null when external storage is
unavailable; fall back to filesDir for both storageFile and photoDir
so saves never silently fail on devices without external storage
Backlog (worklog.md):
- Add notes/photos to finished tracks + include in trip report
- Trip report voice: replace generic style picker with single Nav voice
- Fix tack detection false positives at low SOG
- Investigate/fix speed coloring in MapLibre Android 11.x
https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn
3 files changed, 23 insertions, 8 deletions
diff --git a/.agent/worklog.md b/.agent/worklog.md index 55fd5a7..cfae053 100644 --- a/.agent/worklog.md +++ b/.agent/worklog.md @@ -1,5 +1,15 @@ # SESSION_STATE.md +## Backlog (fix later) + +- **Add notes/photos to a finished track** — UI to attach logbook entries to a past track by timestamp/geo proximity. Must flow into the trip report (currently only live-session entries are scoped). + +- **Trip report voice** — The current narrative styles (Professional / Adventurous / Journal / Pirate) are generic and not right for Nav. Nav is an opinionated sailing app; the report should have a single voice that reflects that — concise, knowledgeable, seamanlike. Rip out the style picker and write one good template. + +- **Tack detection is buggy, especially at low speed** — False positives at low SOG (GPS heading noise looks like tacks). Need minimum-SOG gate (e.g. skip detection when SOG < 1.5 kt) and review the stability window / MIN_DELTA thresholds against real tracks. + +- **Speed coloring on the map doesn't work** — `Expression.get("color")` on a FeatureCollection of 2-point LineStrings fails silently in MapLibre Android 11.x. The focused-track layer in MapHandler still uses this broken approach. Needs investigation: either find a working data-driven expression syntax for this MapLibre version, or pre-segment the GeoJSON differently. + ## Current Task Goal Instrument Sheet Visual Redesign — IN PROGRESS (2026-04-06) 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 6b90542..51f1f09 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 @@ -16,10 +16,10 @@ class LogbookStorage(private val context: Context) { private val adapter = moshi.adapter(LogEntryList::class.java) private val storageFile: File - get() = File(context.getExternalFilesDir(null), "nav_logbook.json") + get() = File(context.getExternalFilesDir(null) ?: context.filesDir, "nav_logbook.json") val photoDir: File - get() = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "Nav") + get() = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) ?: context.filesDir, "Nav") .also { it.mkdirs() } fun loadAll(): List<LogEntry> = runCatching { 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 3638f8f..2557eb4 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 @@ -1,12 +1,14 @@ package org.terst.nav.ui.voicelog import android.Manifest +import android.app.Activity import android.content.Intent import android.content.pm.PackageManager import android.graphics.BitmapFactory import android.net.Uri import android.os.Build import android.os.Bundle +import android.provider.MediaStore import android.speech.RecognitionListener import android.speech.RecognizerIntent import android.speech.SpeechRecognizer @@ -73,9 +75,9 @@ class VoiceLogFragment : Fragment() { private var pendingCameraUri: Uri? = null private val cameraLauncher = registerForActivityResult( - ActivityResultContracts.TakePicture() - ) { success: Boolean -> - if (success) { + ActivityResultContracts.StartActivityForResult() + ) { result -> + if (result.resultCode == Activity.RESULT_OK) { val path = pendingPhotoPath ?: return@registerForActivityResult setPhoto(path) { val bm = BitmapFactory.decodeFile(path) @@ -140,13 +142,16 @@ class VoiceLogFragment : Fragment() { fabMic.setOnClickListener { startListening() } btnCamera.setOnClickListener { - val dir = NavApplication.logbookRepository.photoDir - val file = File(dir, "log_${System.currentTimeMillis()}.jpg") + val file = File(NavApplication.logbookRepository.photoDir, "log_${System.currentTimeMillis()}.jpg") pendingPhotoPath = file.absolutePath pendingCameraUri = FileProvider.getUriForFile( requireContext(), "${requireContext().packageName}.fileprovider", file ) - cameraLauncher.launch(pendingCameraUri!!) + val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE).apply { + putExtra(MediaStore.EXTRA_OUTPUT, pendingCameraUri) + addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) + } + cameraLauncher.launch(intent) } btnGallery.setOnClickListener { galleryLauncher.launch("image/*") } |
