Refresh Files list automatically when an upload finishes
Build APK / build (push) Successful in 5m32s

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>
This commit is contained in:
2026-09-29 13:09:08 -04:00
co-authored by Claude Sonnet 5
parent b73f451fff
commit c18fc98dc3
6 changed files with 146 additions and 8 deletions
+18
View File
@@ -3,6 +3,7 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../models/nextcloud_item.dart';
import '../services/upload_service.dart';
import 'folder_browser.dart';
import 'session_controller.dart';
@@ -107,6 +108,22 @@ class FilesController extends ChangeNotifier
session.addAccountClearedListener(_onAccountCleared);
session.addAccountActivatedListener(_onAccountActivated);
session.addAccountReadyListener(_restoreDisplayPrefs);
// Refreshes automatically once an upload finishes, so a file shared/
// uploaded into the folder currently on screen shows up without a
// manual pull-to-refresh - uploads run in an Android foreground
// service (see UploadService's doc comment) with no other way back to
// this controller.
_uploadSub = UploadService.completions.listen(_onUploadCompleted);
}
StreamSubscription<UploadCompletion>? _uploadSub;
void _onUploadCompleted(UploadCompletion completion) {
// refreshData() always hits the network regardless of cache freshness
// (see its own doc comment), so there's nothing to invalidate first -
// it overwrites this folder's cache entry once the fetch lands.
if (completion.remoteFolder != _currentFolderPath) return;
refreshData();
}
// Getters
@@ -711,6 +728,7 @@ class FilesController extends ChangeNotifier
void dispose() {
WidgetsBinding.instance.removeObserver(this);
_cacheRefreshTimer?.cancel();
_uploadSub?.cancel();
super.dispose();
}
}