Compare commits

..

2 Commits

2 changed files with 63 additions and 7 deletions

View File

@@ -156,6 +156,62 @@ synq/
5. add history screen and resend handling. 5. add history screen and resend handling.
6. polish launch speed and widget/share-target only after core path works. 6. polish launch speed and widget/share-target only after core path works.
## build & deploy
### server (docker)
```bash
# build
docker build -t synq-server ./server
# run (replace paths and token as needed)
docker run -d --name synq --restart=unless-stopped \
-p 8765:8765 \
-v /mnt/user/synq/data:/data \
synq-server
```
the server generates a random token on first start and logs it prominently. copy it into the android app settings. to use a fixed token instead, pass `-e PHONE_CAPTURE_TOKEN=yourtoken`.
to rebuild after a `git pull`:
```bash
git pull
docker build -t synq-server ./server
docker stop synq && docker rm synq
# re-run the docker run command above
```
### android
open `android/` in Android Studio and hit **Sync**. then either:
- **run on device/emulator directly** from Android Studio (▶), or
- **build a release APK** from the terminal:
```bash
cd android
./gradlew assembleRelease
# output: app/build/outputs/apk/release/app-release-unsigned.apk
```
sideload to a connected device:
```bash
adb install app/build/outputs/apk/release/app-release-unsigned.apk
```
### releasing on gitea
tag the commit and push the tag:
```bash
git tag v1.0.0
git push gitea v1.0.0
```
then go to **Releases → New Release** in the Gitea UI, pick the tag, and drag the APK into the assets box. anyone on the LAN can download it from there.
## backup ## backup
### what to back up ### what to back up

View File

@@ -395,7 +395,7 @@ logger.info for accepted and duplicate (id only, no body). logger.warning for in
*** notes *** notes
Added "backup" section to README.md covering synq.org, capture.sqlite3, token.txt. Restore section documents behavior when each file is lost individually. Added "backup" section to README.md covering synq.org, capture.sqlite3, token.txt. Restore section documents behavior when each file is lost individually.
*** evidence *** evidence
- commit: (this commit) - commit: 66155f6
- tests: n/a - tests: n/a
- datetime: [2026-05-18 Sun 19:00] - datetime: [2026-05-18 Sun 19:00]
@@ -407,7 +407,7 @@ Added "backup" section to README.md covering synq.org, capture.sqlite3, token.tx
*** notes *** 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. 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 *** evidence
- commit: (this commit) - commit: 66155f6
- tests: manual — share any text from browser/notes to synq, verify it pre-fills capture body - tests: manual — share any text from browser/notes to synq, verify it pre-fills capture body
- datetime: [2026-05-18 Sun 20:00] - datetime: [2026-05-18 Sun 20:00]
@@ -423,7 +423,7 @@ ACTION_SEND text/plain intent-filter added to MainActivity in manifest. MainActi
*** notes *** 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. 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 *** evidence
- commit: (this commit) - commit: 66155f6
- tests: manual — save a few captures with tags, open capture screen, verify chips appear and toggle - tests: manual — save a few captures with tags, open capture screen, verify chips appear and toggle
- datetime: [2026-05-18 Sun 20:00] - datetime: [2026-05-18 Sun 20:00]
@@ -434,7 +434,7 @@ CaptureViewModel.recentTags collects the last 100 capture tagsJson rows, decodes
*** notes *** 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. 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 *** evidence
- commit: (this commit) - commit: 66155f6
- tests: manual — save a capture, open history, expand row, tap edit, change body, save, verify updated - tests: manual — save a capture, open history, expand row, tap edit, change body, save, verify updated
- datetime: [2026-05-18 Sun 20:00] - datetime: [2026-05-18 Sun 20:00]
@@ -446,7 +446,7 @@ CaptureDao.updateBody() new query. HistoryViewModel.updateBody() calls it. Histo
*** notes *** 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. 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 *** evidence
- commit: (this commit) - commit: 66155f6
- tests: manual — tap history rows to expand/collapse, verify full body visible when expanded - tests: manual — tap history rows to expand/collapse, verify full body visible when expanded
- datetime: [2026-05-18 Sun 20:00] - datetime: [2026-05-18 Sun 20:00]
@@ -456,7 +456,7 @@ CaptureRow uses rememberSaveable expanded: Boolean keyed on capture.id. Card has
*** notes *** 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). 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 *** evidence
- commit: (this commit) - commit: 66155f6
- tests: manual — sync a capture, verify timestamp appears in history header and capture screen - tests: manual — sync a capture, verify timestamp appears in history header and capture screen
- datetime: [2026-05-18 Sun 20:00] - datetime: [2026-05-18 Sun 20:00]
@@ -467,7 +467,7 @@ CaptureDao.getLastSyncedAt() returns Flow<String?> of MAX(syncedAt). HistoryView
*** notes *** 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. 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 *** evidence
- commit: (this commit) - commit: 66155f6
- tests: manual — change interval to 30, save, verify WorkManager re-queues (check adb shell dumpsys jobscheduler) - tests: manual — change interval to 30, save, verify WorkManager re-queues (check adb shell dumpsys jobscheduler)
- datetime: [2026-05-18 Sun 20:00] - datetime: [2026-05-18 Sun 20:00]