Offline tab as Files view, automatic background sync, sync notifications
Build APK / build (push) Successful in 5m27s

- Offline tab is now FilesView(offline: true) over a FolderBrowser interface
  (FilesController / OfflineController) sharing controls, tiles, thumbnails
- Synced files follow the Files Cache rule (default: refresh every 15 min):
  per-account WorkManager jobs, in-app timer, resume and pull triggers;
  root-etag shortcut skips full walks when nothing changed
- Single sync at a time (shared lock); logging out stops that account's sync
- Sync safety: PROPFIND failures skip the path instead of deleting local files
- Mirror empty folders and remove deleted ones; drop synced paths deleted on
  the server; missing local files are re-downloaded
- Notifications: silent per-account sync notifications, "Background sync
  notifications" setting, audible upload/download completion
- Files refresh in place (no spinner flash); retry after network returns
- Fix sync badges not updating (shared native status stream), "Sync off" on
  launch (eager providers), Files Cache section moved under Device Sync

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-21 18:06:55 -04:00
co-authored by Claude Sonnet 5
parent 49ae712f5e
commit f2bba2914e
38 changed files with 3133 additions and 741 deletions
+12 -1
View File
@@ -14,7 +14,12 @@ import '../views/trash_view.dart';
Widget buildAppTabView(AppTab tab, ScrollController controller) {
switch (tab) {
case AppTab.files:
return FilesView(scrollController: controller);
// Keyed so the Files and Offline tabs (same widget type) never share
// State when the visible-tab list shifts positions in the IndexedStack.
return FilesView(
key: const ValueKey('files'),
scrollController: controller,
);
case AppTab.photos:
return PhotosView(scrollController: controller);
case AppTab.favorites:
@@ -27,5 +32,11 @@ Widget buildAppTabView(AppTab tab, ScrollController controller) {
return SharesView(scrollController: controller);
case AppTab.recent:
return RecentView(scrollController: controller);
case AppTab.offline:
return FilesView(
key: const ValueKey('offline'),
scrollController: controller,
offline: true,
);
}
}