Uploads run entirely in ShareUploadService.kt, an Android foreground
service with no channel back to Dart once started - by design, so
closing the app mid-upload doesn't interrupt it. That meant
FilesController had no way to know a batch had finished, so a newly
uploaded file only appeared after a manual pull-to-refresh.
Adds a one-shot completion signal instead of a full stream: the
service publishes into a new UploadEventBus (in-process pub/sub,
mirroring SyncStatusBus) once a batch finishes with at least one
success, MainActivity forwards it to Dart over a new
dev.ayushya.noo/upload_service/status EventChannel, and
FilesController (subscribed in its own constructor, same pattern
OfflineController already uses for sync completion) calls
refreshData() when the event's destination folder matches
currentFolderPath. Covers both upload entry points (share-to-Noo and
Files' own "+" -> Upload file), since they already share the same
ShareUploadView/UploadService path.
Move/Copy needed no fix - ItemOperations already calls
files.invalidateCache() + refreshData() on success.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Consolidates duplicated GET/PUT/notification-channel logic across
DownloadService/ShareUploadService/SyncEngine into shared Kotlin helpers,
gives upload/download real batch queueing instead of dropping a second
concurrent batch, and dedupes repeated Dart channel-argument boilerplate.
Replaces the 2300+ line ServerProvider god object with ten focused
ChangeNotifiers (SessionController, SettingsController, FilesController,
PhotosController, FavoritesController, TrashController, SharesController,
RecentController, SyncStatusController, PickController) plus ItemOperations,
a plain coordinator for cross-domain item mutations - fixing the coupling
where device-sync status, per-tab data, and global UI prefs all lived in
one object. Updates every view/widget call site accordingly and refreshes
the architecture/server/standards/styling docs to match.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sharing a large file to Noo used to black-screen and silently kick back
to the home screen: receive_sharing_intent copies the entire shared file
into the cache dir synchronously on the main thread before Flutter even
renders, which Android's watchdog eventually kills. Replaced with
hand-rolled handling in MainActivity.kt that only ever reads cheap Uri
metadata up front (ShareIntentService), so the destination picker always
appears instantly regardless of file size.
The destination picker (ShareUploadView) now mirrors the Files tab's own
controls/filters/listing instead of a bare folder list, and the actual
prepare+upload is handed off to ShareUploadService.kt, a real Android
foreground service with a single cancellable progress notification for
the whole batch - this survives the app being closed right after the
user confirms a destination, the same guarantee a file-manager app's own
upload notification gives.
Also fixes the "add another account" login page: it used to open in
url_launcher's bare inAppWebView, which has no close button and can hide
the status bar. LoginWebViewView is a real screen this app owns instead
(package:webview_flutter), with a normal AppBar/close button/safe area,
and can now auto-close itself on successful login.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>