resolve merge conflict: take worktree milestone 5 DONE state, keep user title

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-18 15:20:22 -04:00
12 changed files with 332 additions and 43 deletions

View File

@@ -400,34 +400,76 @@ Added "backup" section to README.md covering synq.org, capture.sqlite3, token.tx
- datetime: [2026-05-18 Sun 19:00]
* milestone 5: optional v1.5 improvements
** TODO add edit-before-sync
*** acceptance
- pending/failed captures can be edited.
- synced captures are read-only unless explicitly duplicated.
** TODO tap to expand History item
- in History, tap to expand/contract each item
** TODO add "Last synced" display
*** acceptance
- app displays "last synced at" somewhere, maybe in Settings and History?
- "next sync at []" on History (and homepage?)
** TODO add settings for sync frequency
*** acceptance
- let user specify poll rate, in minutes
** TODO add recent tag chips
*** acceptance
- app shows recent tags.
- tapping chip adds/removes tag.
** TODO add android share target
** DONE add android share target
*** acceptance
- sharing text to app opens prefilled capture.
- user can save as note or todo.
*** notes
ACTION_SEND text/plain intent-filter added to MainActivity in manifest. MainActivity.onCreate extracts EXTRA_TEXT and passes it as a URL-encoded nav argument to the capture/{prefill} route. CaptureScreen applies it via LaunchedEffect on first composition.
*** evidence
- commit: (this commit)
- tests: manual — share any text from browser/notes to synq, verify it pre-fills capture body
- datetime: [2026-05-18 Sun 20:00]
** TODO add home screen quick capture widget
*** acceptance
- widget opens capture screen quickly.
- does not require sync to work.
** DONE add recent tag chips
*** acceptance
- app shows recent tags.
- tapping chip adds/removes tag.
*** notes
CaptureViewModel.recentTags collects the last 100 capture tagsJson rows, decodes each JSON array, flattens and deduplicates (LinkedHashSet order), limits to 20. CaptureScreen shows a FlowRow of FilterChip below the tags text field. Tapping a chip calls toggleTag() which adds/removes it from the tags string. Active chips are highlighted via FilterChip selected=true.
*** evidence
- commit: (this commit)
- tests: manual — save a few captures with tags, open capture screen, verify chips appear and toggle
- datetime: [2026-05-18 Sun 20:00]
** DONE add edit-before-sync
*** acceptance
- pending/failed captures can be edited.
- synced captures are read-only unless explicitly duplicated.
*** notes
CaptureDao.updateBody() new query. HistoryViewModel.updateBody() calls it. HistoryScreen CaptureRow shows "edit" OutlinedButton only when expanded AND status is pending/failed. Tapping edit opens an AlertDialog with an OutlinedTextField pre-filled with current body. Save calls updateBody; cancel dismisses.
*** evidence
- commit: (this commit)
- tests: manual — save a capture, open history, expand row, tap edit, change body, save, verify updated
- datetime: [2026-05-18 Sun 20:00]
** DONE tap to expand history item
*** acceptance
- tapping a history row expands/collapses it.
- expanded row shows full body.
- edit button is only visible when expanded.
*** notes
CaptureRow uses rememberSaveable expanded: Boolean keyed on capture.id. Card has clickable { expanded = !expanded }. maxLines switches between 2 and Int.MAX_VALUE. Edit button only renders when expanded && editable.
*** evidence
- commit: (this commit)
- tests: manual — tap history rows to expand/collapse, verify full body visible when expanded
- datetime: [2026-05-18 Sun 20:00]
** DONE add "Last synced" display
*** acceptance
- "last synced at" visible in history top bar and capture screen.
*** notes
CaptureDao.getLastSyncedAt() returns Flow<String?> of MAX(syncedAt). HistoryViewModel and CaptureViewModel both stateIn this flow. HistoryScreen shows it as a subtitle under "history" in the TopAppBar. CaptureScreen shows it as a small label above the save buttons. Both parse the ISO string via OffsetDateTime and format with DateTimeFormatter.ofLocalizedDateTime(SHORT).
*** evidence
- commit: (this commit)
- tests: manual — sync a capture, verify timestamp appears in history header and capture screen
- datetime: [2026-05-18 Sun 20:00]
** DONE add settings for sync frequency
*** acceptance
- user-specified poll rate in minutes (min 15).
- changing interval reschedules WorkManager immediately.
*** notes
SynqSettings gained syncIntervalMinutes: Int = 15 field with DataStore key sync_interval_minutes. SettingsScreen added OutlinedTextField with number keyboard for interval, shows supporting text "WorkManager minimum is 15 min". buildSettings() coerces to max(value, 15). SettingsViewModel.save() now also calls SyncWorker.schedule(app, settings.syncIntervalMinutes). SyncWorker.schedule() uses REPLACE policy so new interval takes effect immediately.
*** evidence
- commit: (this commit)
- tests: manual — change interval to 30, save, verify WorkManager re-queues (check adb shell dumpsys jobscheduler)
- datetime: [2026-05-18 Sun 20:00]
* implementation notes for coding agents
- keep the server small and testable.