diff --git a/tasks.org b/tasks.org index e1933da..b48e70c 100644 --- a/tasks.org +++ b/tasks.org @@ -250,30 +250,57 @@ HistoryScreen.kt observes captureDao.observeAll() as Flow. Status colored green/ - datetime: [2026-05-18 Sun 17:00] * milestone 3: android sync -** TODO implement api client +** DONE implement api client *** acceptance - base url configurable in app settings or build config. - bearer token configurable in app settings or build config. - client can call `/health`. - client can post capture payload. -** TODO implement manual sync +*** notes +SynqApiClient in data/api/. OkHttp with 10s timeouts. checkHealth() does GET /health, returns false on any exception so callers never crash. postCapture() maps 401 → failed, non-2xx → failed, already_seen → AlreadySeen, else → Accepted. Uses org.json for request building, kotlinx-serialization for tag decoding. +*** evidence +- commit: 2a963d9 +- tests: manual — sync now button, check history screen status +- datetime: [2026-05-18 Sun 18:00] + +** DONE implement manual sync *** acceptance - sync now posts all pending captures. - successful posts mark rows synced. - already-seen response marks row synced. - failures retain pending/failed status and last error. -** TODO implement opportunistic workmanager sync +*** notes +syncPending() top-level function in data/sync/SyncService.kt — shared by manual sync and WorkManager. CaptureViewModel.syncNow() calls it on Dispatchers.IO, guards with isSyncing flag. Sync icon in top bar shows CircularProgressIndicator while running. +*** evidence +- commit: 2a963d9 +- tests: manual — tap sync, verify captures move to synced in history; test with wrong token, verify failed + error message +- datetime: [2026-05-18 Sun 18:00] + +** DONE implement opportunistic workmanager sync *** acceptance - periodic sync is registered. - sync only runs when network is available. - worker first checks `/health`. - worker does not block capture speed. -** TODO add simple server reachability settings +*** notes +SyncWorker (CoroutineWorker) in data/sync/. Registered in SynqApp.onCreate() as KEEP unique periodic work (15-min interval, NETWORK_CONNECTED constraint). Health check before sync — exits quietly if server unreachable. Does not touch UI thread. +*** evidence +- commit: 2a963d9 +- tests: manual — let app sit on WiFi, verify pending captures eventually sync without manual trigger +- datetime: [2026-05-18 Sun 18:00] + +** DONE add simple server reachability settings *** acceptance - default url can be set to `http://jeeves.mother:8765`. - user can change server url. - user can change token. - invalid settings do not crash app. +*** notes +SettingsScreen + SettingsViewModel from milestone 2. DataStore-backed. Default serverUrl is http://jeeves.mother:8765. All network calls wrap exceptions so invalid URL/token never crashes — they just produce PostResult.Failed with the error message. +*** evidence +- commit: 19b05a8 (screen), 2a963d9 (wired to sync) +- tests: manual — set bad URL, tap sync, verify captures stay pending/failed with error; set correct URL + token, sync succeeds +- datetime: [2026-05-18 Sun 18:00] * milestone 4: polish and hardening ** TODO make launch path fast