Upload cheat
final manager = UploadTaskManager(
storage: FirebaseStorage.instance,
randomizer: DefaultRandomizer(),
uid: currentUserId,
container: providerContainer, // optional
);
String taskId = manager.uploadSync(file, location: 'photos/');
// Returns immediately, upload in background
UploadResult result = await manager.uploadAsync(file, location: 'docs/');
if (result.isSuccess) { /* success */ }
manager.notifier.stream.listen((state) {
print('Active: ${state.inProgressCount}');
print('Done: ${state.completedCount}');
print('Failed: ${state.failedCount}');
});
final state = manager.notifier.state;
print('Queue size: ${state.totalCount}');
print('Has errors: ${state.hasErrors}');
await manager.cancelTask(taskId); // Cancel one
await manager.cancelAll(); // Cancel all
manager.notifier.clearErrors(); // Remove failed tasks
manager.notifier.reset(); // Clear everything
await manager.setUser(newUserId); // Cancels old user's uploads
await manager.dispose(); // Always call when done!
manager.uploadAsync(
file,
location: 'photos/',
onProgress: (snapshot) {
double percent = snapshot.bytesTransferred / snapshot.totalBytes * 100;
print('${percent.toStringAsFixed(1)}%');
},
);
for (final file in files) {
manager.uploadSync(file, location: 'batch/');
}
// Wait for critical
await manager.uploadAsync(profilePhoto, location: 'profile/');
// Fire-and-forget background
for (final photo in gallery) {
manager.uploadSync(photo, location: 'gallery/');
}
try {
final result = await manager.uploadAsync(file, location: 'docs/');
// handle result
} on UploadException catch (e) {
print('Upload failed: ${e.message}');
}
state.waitingCount // Tasks queued
state.inProgressCount // Currently uploading
state.completedCount // Successfully done
state.failedCount // Failed uploads
state.totalCount // All tasks
state.isFull // Queue at capacity
state.hasErrors // Any failures
state.errorCount // Number of errors
StreamBuilder(
stream: uploadManager.notifier.stream,
builder: (context, snapshot) {
if (!snapshot.hasData) return Loading();
final state = snapshot.data!;
return Column(
children: [
Text('${state.inProgressCount} uploading'),
LinearProgressIndicator(
value: state.completedCount / state.totalCount,
),
],
);
},
)
test('sync upload returns task ID', () {
final taskId = manager.uploadSync(file, location: 'test/');
expect(taskId, isNotEmpty);
});
test('async upload returns result', () async {
final result = await manager.uploadAsync(file, location: 'test/');
expect(result.status, isNotNull);
});
✅ Do:
- Call
dispose()when done - Use sync for background uploads
- Use async for critical uploads
- Monitor stream for UI updates
- Handle errors gracefully
❌ Don’t:
- Forget to dispose
- Block UI with sync uploads (they’re non-blocking)
- Ignore error state
- Upload without user authentication
- Create multiple managers (use singleton)
print('Ready: ${manager.isReady}');
print('Authenticated: ${manager.isAuthenticated}');
manager.notifier.stream.listen(
(state) => print('Update: $state'),
onError: (e) => print('Error: $e'),
onDone: () => print('Stream closed'),
);
// Always dispose in lifecycle
@override
void dispose() {
manager.dispose();
super.dispose();
}
- Full Guide:
UPLOAD_TASK_MANAGER_GUIDE.md - Integration Details:
INTEGRATION_SUMMARY.md - Tests:
upload_task_manager_integration_test.dart