All screens in my app have access to the Uploading State Provider. When I upload an object from my uploads screen I am using FlutterFire Handling Tasks to get upload progress.
The upload task works just fine, but when I navigate away from the uploading screen to the home screen, where I am displaying the Uploading StateProvider's progress, it only displays the current progress and does not get the updates happening in the background.
How do I configure RiverPod to listen to the background snapshot still running or should I just avoid using RiverPod for this and just use Firebase storage listener?
Uploading StateProvider
final uploadingStateProvider = StateProvider<String?>((ref) => null);
Firebase storage upload task is sending progress string to my StateProvider
task.snapshotEvents.listen((TaskSnapshot snapshot) {
if (displayProgressNotification) {
final int percent =
((snapshot.bytesTransferred / snapshot.totalBytes) * 100).round();
if (percent >= 100) {
context.read(uploadingStateProvider).state = null;
} else {
context.read(uploadingStateProvider).state =
percent.toString();
}
} else {
context.read(uploadingStateProvider).state = null;
}
}, onDone: () async {
context.read(uploadingStateProvider).state = null;
if (deleteAfterUpload) {
await file.delete();
}
}, one rror: (e) {
context.read(uploadingStateProvider).state = null;
debugPrint(task.snapshot.toString());
debugPrint(e.toString());
});
Home screen displays progress spinner with percentage, but it only displays the initial % it reads and does not get updated percentages from the background task
Consumer(
builder: (context, watch, child) {
final uploadingPercent =
watch(uploadingStateProvider).state;
if (uploadingPercent != null) {
return Stack(
alignment: Alignment.center,
/// Note: First child is the bottom of the stack...
children: [
SpinKitDualRing(
color: Colors.white.withOpacity(0.5),
size: titleFontSize(shrinkOffset),
lineWidth: 2.0,
duration: const Duration(
milliseconds: 1500),
),
Text(
'$uploadingPercent%',
style: TextStyle(
color: Colors.white.withOpacity(0.5),
fontSize: uploadFontSize(shrinkOffset),
fontWeight: FontWeight.w200,
),
),
],
);
} else {
return const SizedBox.shrink();
}
},
),
CodePudding user response:
I would use the 1.0.0 version. No context
final uploadingStateProvider =
StateNotifierProvider.autoDispose<UploadingState, int?>((ref) {
return UploadingState(read: ref.read);
});
I would use a StateNotifier. The reader can be useful if you want the entire logic in the myUploadTask methode.
class UploadingState extends StateNotifier<int?> {
final Reader read;
StreamSubscription? mySubscription;
UploadingState({required this.read}) : super(null);
Future<void> myUploadTask(firebase_storage.UploadTask task) async {
mySubscription = task.snapshotEvents.listen((TaskSnapshot snapshot) {
final int percent =
((snapshot.bytesTransferred / snapshot.totalBytes) * 100).round();
state = percent;
}, onDone: () async {
state = null;
}, one rror: (e) {
state = null;
debugPrint(task.snapshot.toString());
debugPrint(e.toString());
});
}
@override
void dispose() {
mySubscription?.cancel();
super.dispose();
}
}
And your Consumer
Consumer(
builder: (context, ref,_) {
final uploadingPercent = ref.watch(uploadingStateProvider);
if (uploadingPercent != null) {
return Stack(
alignment: Alignment.center,
/// Note: First child is the bottom of the stack...
children: [
SpinKitDualRing(
color: Colors.white.withOpacity(0.5),
size: titleFontSize(shrinkOffset),
lineWidth: 2.0,
duration: const Duration(
milliseconds: 1500),
),
Text(
'$uploadingPercent%',
style: TextStyle(
color: Colors.white.withOpacity(0.5),
fontSize: uploadFontSize(shrinkOffset),
fontWeight: FontWeight.w200,
),
),
],
);
} else {
return const SizedBox.shrink();
}
},
),
Call that somewhere or put all the logic in UploadingState()
ref.read(uploadingStateProvider.notifier).myUploadTask(task);