- SyncEngine: accepts onProgress callback — emits uploaded/downloaded/
deleted/bytes counts atomically as each file completes
- SyncWorker: streams progress to WorkManager data so the UI can poll
it live; reports per-run counters in the completion notification;
adds pause/resume support
- HomeViewModel/PairDetailViewModel: subscribe to live WorkManager
progress and surface it via SyncProgress state
- SyncPairEntity/SyncPairDao/SyncDatabase: persist last-run counters
(uploaded, downloaded, deleted, bytesTransferred) in the DB with a
Room migration (v3→v4)
- AppModule: provides WorkManager as an injectable singleton
- .gitignore: add .kotlin/ to exclude compiler session files
Security: no new issues — all logging via Timber (debug-only), DB
queries use Room parameterized API, file sharing via FileProvider.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sync change detection:
- DbConverters was using epochSecond but comparisons used epochMilli —
every file appeared modified on every scan, causing full re-sync each time
- DB migration 2→3 clears sync_file_states (all stored timestamps wrong)
- First sync after upgrade re-learns state; subsequent syncs skip unchanged files
Biometric:
- Move prompt trigger from LaunchedEffect to onResume() — guarantees
the activity is in RESUMED state when authenticate() is called
- Add bestAuthenticators(): tries BIOMETRIC_STRONG|DEVICE_CREDENTIAL first,
falls back to BIOMETRIC_WEAK|DEVICE_CREDENTIAL for side-sensor phones
- canAuthenticate() now accepts either strong or weak+credential
- onAuthenticationError always shows Unlock button (no infinite retry loop)
- isLocked/showRetry are Activity-level state, no need for Compose remember
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Supports WebDAV, SFTP, SFTPGo, Nextcloud, ownCloud, Google Drive,
Dropbox, and OneDrive. Credentials encrypted with Android Keystore.
Biometric app-lock, conflict resolution, and auto-sync via WorkManager.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>