Icon: two thick tube-style arcs with 3D glossy highlights.
Arc 1 (left side): coral #E8665A to orange #E8A040
Arc 2 (right side): steel blue #4A7FD4 to deep purple #7B5EA7
Arrowheads: orange and purple. Background: dark purple-black.
Inspired by the braided knot color palette.
Fix "media not found" when opening photos:
- Intent now sets ClipData alongside FLAG_GRANT_READ_URI_PERMISSION
so the permission correctly propagates through the system chooser
to whichever app the user picks.
- openFile() and downloadToCache() both call MediaScannerConnection
so newly synced/downloaded files appear in gallery MediaStore index
before the viewer launches.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix multi-selection: selectedKeys exposed as StateFlow, collected in
FilesScreen so checkboxes and highlights update correctly on every tap.
fileKey() made public so UI can check membership without ViewModel calls.
Icon: white cloud body with two cyan/teal circular sync arcs (AutoSync
style), deep blue-to-teal gradient background.
Security review clean: no hardcoded credentials, cleartext blocked by
network_security_config, allowBackup=false, path traversal guards in
place on both server responses and local resolution.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Icon: three identical parallel arcing arrows (same bezier curve, same blue-to-teal
gradient #64C8FF→#32EDBB, same arrowhead geometry) — visually cohesive and clearly
visible against the near-black background.
FileWatchService: FileObserver is now recursive — watchDirRecursive() creates an
observer for each subdirectory at startup, and adds new watchers when CREATE events
produce new directories. Fixes files added to subdirectories not being detected.
FilesViewModel: openFile/shareFile now fall back to download-then-open when the file
is absent locally. AccountRepository + ProviderFactory injected; downloads to
context.cacheDir/syncflow_open/ with isDownloading state. Path traversal guard added
(reject relativePath containing ".."). file_paths.xml gains cache-path entry.
WebDavProvider: path-traversal guard in parsePropfind — skip any server-returned
filename containing "..", "/" or "\". Replace android.util.Log with Timber so debug
logs are stripped from release builds.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- FilesScreen: per-file context menu (Open, Share, Rename, Delete), rename dialog,
delete confirmation, FileProvider-based open/share intents, Snackbar error feedback
- FilesViewModel: FileAction sealed class + SharedFlow; openFile, shareFile,
deleteFile, renameFile with DB cleanup; resolveFile handles SAF primary: URIs
- FileWatchService: stopWithTask=false keeps watcher alive after app swipe-away;
catchupScan on startup detects changes missed while service was not running;
SyncFileStateDao injected; FileObserver used for real-path SAF URIs
- BootReceiver: handles MY_PACKAGE_REPLACED to restart service after app update
- file_paths.xml: added external-path so FileProvider can serve /storage/emulated/0 files
- ic_launcher_foreground: three curved stroke-based arrows (quadratic bezier, round caps)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix SYNC_COMPLETED showing ↑0 ↓0 ✗0 when only deletions occurred: add ✕N
for deleted files to the summary message (↑N ↓N ✕N ✗N format)
- Fix PairDetail Activity section showing raw "SYNC_STARTED" enum names and
"remote" as a plain subtitle: replace dot-based EventRow with the same
polished icon-bubble rows as the global Log tab
- Extract shared SyncEventRow composable + iconAndTint/label helpers to
ui/shared/SyncEventRow.kt; both LogScreen and PairDetailScreen now use it
- Add Files tab (4th tab between Log and Accounts): folder browser showing
all synced files per pair, grouped by subdirectory, with file-type icons,
size, last-synced date, and a summary header (N files, total size)
- Add SyncFileStateDao.observeForPair() reactive Flow query for Files tab
- Completely redesign app icon: near-black radial gradient background with
three bold directional arrows in an S-pattern (coral → silver → teal),
each with gradient fills and tip-glow dots — entirely different from the
typical circular sync-arrow style
- Bump version to 1.0.22 (build 23)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Request POST_NOTIFICATIONS permission at runtime in MainActivity (primary fix
for notifications never appearing on Android 13+ phones including Android 16)
- Register all 4 notification channels eagerly in SyncFlowApp.onCreate() instead
of lazily inside workers
- Add FOREGROUND_SERVICE_SHORT_SERVICE permission + shortService foreground type
for Android 16 foreground service compatibility
- Add global activity Log tab (new tab 2 in main nav) showing all sync events
across all pairs, grouped by date with pair name, event icon, and file detail
- Fix FileWatchService ON_CHANGE detection: ContentObserver on SAF tree URIs only
fires for SAF-API writes, not raw filesystem writes. Now resolves primary:/*
tree URIs to /storage/emulated/0/* and uses FileObserver for reliable detection
- Bump version to 1.0.21 (build 22)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CRITICAL
- SftpProvider: replace PromiscuousVerifier with TofuHostKeyVerifier
(trust-on-first-use; stores SHA-256 fingerprints in EncryptedSharedPreferences;
rejects key changes on subsequent connections)
HIGH
- GoogleDriveProvider: replace raw string interpolation with buildJsonObject
in uploadFile, createDirectory, and moveFile to prevent JSON injection
- DropboxProvider: replace all raw JSON strings and Dropbox-API-Arg headers
with buildJsonObject for the same reason
- OAuthHelper: add cryptographically random state parameter to Dropbox and
OneDrive authorization URLs (stored alongside the PKCE verifier)
- OAuthRedirectActivity: validate returned state against stored value before
exchanging the authorization code (CSRF protection)
MEDIUM
- WebDavProvider: block cross-host redirects in the manual redirect interceptor
so Authorization headers are never forwarded to a different server
- AccountSetupScreen: set FLAG_SECURE on the window while credential fields
are visible to prevent screenshots and screen-recording capture
- libs.versions.toml: security-crypto alpha06 → stable 1.0.0;
biometric-ktx alpha05 → biometric 1.1.0 (stable, non-ktx artifact matches
the BiometricManager/BiometricPrompt API actually used in MainActivity)
- CredentialStore: migrate to security-crypto 1.0.0 API (MasterKeys.getOrCreate
+ positional create() args); add saveHostKey/getHostFingerprint for SFTP TOFU
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Start FileWatchService from SyncFlowApp.onCreate() for any existing
enabled ON_CHANGE pairs — previously the watcher only started on
device boot or explicit pair toggle, so existing pairs after an
app update never got watched
- About screen now shows "Version X.Y.Z (build N)" updating
automatically from BuildConfig on every release
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Sync icon now rotates (CSS-style spin) in StatusPill, StatusBanner,
and card sync button whenever status is SYNCING
- Launcher icon redesigned: indigo→violet→cyan gradient background,
upload arrow fades white→sky-blue, download arrow fades white→violet,
soft glow ring behind arrows
- Fix ON_CHANGE not triggering: FileWatchService.start() now called
from AddPairViewModel.save() so pairs created with ON_CHANGE
immediately begin watching without needing a toggle or reboot
- Fix FileWatch notification hidden: IMPORTANCE_MIN → IMPORTANCE_LOW
so the "Watching N folders" notification shows in the shade
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add FileWatchService for real-time ON_CHANGE sync (FileObserver for
direct paths, ContentObserver for SAF content:// URIs), 5s debounce
- Fix remote browser stuck spinner: cancel in-flight jobs on navigation,
reset entries immediately, add Retry button on error
- Fix browser reuse bug: LaunchedEffect key now includes initialPath
- Fix WebDavProvider: rethrow XML parse errors (no more silent Empty
folder) and URL-decode file names from href
- Notifications now use BigTextStyle showing per-file-type counts
(Uploaded/Downloaded/Deleted) matching Autosync notification style
- Wire FileWatchService into BootReceiver and HomeViewModel toggle
- Register FileWatchService in AndroidManifest
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
App icon: deep indigo-to-violet gradient background with white sync arrows;
replaced flat #2196F3 with layered adaptive icon.
Theme: disabled dynamic color; rich indigo/teal/amber Material3 palette;
edge-to-edge with transparent status bar; tighter typography letterSpacing.
HomeScreen: colored left accent bar per status; URL-decoded SAF paths;
relative timestamps (Just now / N min ago / N hr ago); indigo status pills;
FilledTonalButton empty state.
PairDetailScreen: hero StatusBanner with large icon and relative time;
InfoCard as bordered grid with icon backgrounds; colored dot event timeline;
URL-decoded local path display.
SettingsScreen: section headers with primary left bar; AccountCard with
primaryContainer icon backgrounds; Security/About in bordered cards.
Bump version to 1.0.13 (code 14).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add Edit icon to PairDetailScreen top bar
- Wire onEdit callback through NavGraph to AddPairScreen with pairId
- Manual "Sync now" (home card + detail screen) now ignores wifiOnly
and chargingOnly constraints so it runs immediately on tap
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without calling takePersistableUriPermission, the content:// URI
permission granted by ACTION_OPEN_DOCUMENT_TREE is revoked on
app reinstall, causing Permission Denial errors during sync.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Single source of truth: bump VERSION_NAME/VERSION_CODE in version.properties
to release a new version. BuildConfig.VERSION_NAME exposed to the app.
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>