firebase_storage_upload_bloc 1.0.4
firebase_storage_upload_bloc: ^1.0.4 copied to clipboard
Bloc for resuming uploads to Firebase Storage after app restarts
import 'dart:async';
import 'dart:convert' show utf8;
import 'package:firebase_storage/firebase_storage.dart';
import 'package:firebase_storage_mocks/firebase_storage_mocks.dart';
import 'package:firebase_storage_upload_bloc/firebase_storage_upload_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:uuid/uuid.dart';
void main() {
final mockFirebaseStorage = MockFirebaseStorage();
runApp(MyApp(firebaseStorage: mockFirebaseStorage));
}
class MyApp extends StatelessWidget {
const MyApp({required this.firebaseStorage, super.key});
final FirebaseStorage firebaseStorage;
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
colorScheme: .fromSeed(seedColor: Colors.deepPurple),
),
home: RepositoryProvider.value(
value: firebaseStorage,
child: BlocProvider<FirebaseStorageUploadBloc>(
create: (context) => FirebaseStorageUploadBloc(
firebaseStorage: context.read(),
),
child: const MyHomePage(),
),
),
);
}
}
// Keep in one file to make the example easier to read.
// ignore: prefer-single-widget-per-file
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const .all(12),
child: Center(
child: Column(
mainAxisAlignment: .center,
children: [
Expanded(
child: BlocBuilder<FirebaseStorageUploadBloc, FirebaseStorageUploadState>(
builder: (context, state) => ListView.builder(
itemCount: state.tasks.length,
itemBuilder: (context, index) {
final task = state.tasks.keys.elementAtOrNull(index);
final description = state.tasks[task];
return ListTile(
leading: task is UploadTask
? StreamBuilder<TaskSnapshot>(
stream: task.snapshotEvents,
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Icon(Icons.error_outline);
} else if (snapshot.hasData) {
switch (snapshot.requireData.state) {
case .running:
if (snapshot.requireData.totalBytes > 0) {
return CircularProgressIndicator(
value:
snapshot.requireData.bytesTransferred / snapshot.requireData.totalBytes,
);
}
return const CircularProgressIndicator();
case .success:
return const Icon(Icons.check);
case .paused:
return const Icon(Icons.pause);
case .error:
case .canceled:
return const Icon(Icons.error_outline);
}
} else {
return const CircularProgressIndicator();
}
},
)
: FutureBuilder(
future: task,
builder: (context, snapshot) {
if (snapshot.connectionState == .done) {
return Icon(snapshot.hasError ? Icons.error_outline : Icons.check);
}
return const CircularProgressIndicator();
},
),
title: Text(
description ?? 'Unknown task',
style: Theme.of(context).textTheme.bodyMedium,
),
);
},
),
),
),
TextButton(
onPressed: () => _uploadFile(context),
child: const Text('Simulate File Upload'),
),
TextButton(
onPressed: () => _addTimerTask(context, 'Five second timer task'),
child: const Text('Add Timer Task'),
),
],
),
),
),
);
}
static void _uploadFile(BuildContext context) {
final firebaseStorage = context.read<FirebaseStorage>();
final bloc = context.read<FirebaseStorageUploadBloc>();
final id = const Uuid().v4();
final ref = firebaseStorage.ref().child('$id.txt');
final data = utf8.encode('Hello world!');
unawaited(bloc.uploadFile(ref, data, 'text/plain'));
_addTimerTask(context, 'Mock file uploads instantly, so this task just shows that it happened');
}
static void _addTimerTask(BuildContext context, String description) {
final bloc = context.read<FirebaseStorageUploadBloc>();
// Timer test task
final task = Future<void>.delayed(const Duration(seconds: 5));
bloc.addTask(task, description);
}
}