Added properties and functions to the event bloc for showing the upload status snackbar

This commit is contained in:
Mariano Uvalle 2019-04-11 01:05:36 -05:00
parent f503cce0e3
commit aa1d9b9edf
6 changed files with 52 additions and 14 deletions

View file

@ -28,6 +28,9 @@ class EventBloc {
/// An instace of the auth service. /// An instace of the auth service.
final AuthService _auth = authService; final AuthService _auth = authService;
/// An instance of the upload status service.
final UploadStatusService _uploadStatus = uploadStatusService;
/// A subject of list of task model. /// A subject of list of task model.
final _tasks = BehaviorSubject<List<TaskModel>>(); final _tasks = BehaviorSubject<List<TaskModel>>();
@ -46,6 +49,9 @@ class EventBloc {
/// A subject of a cache that contains the image files. /// A subject of a cache that contains the image files.
final _images = BehaviorSubject<Map<String, Future<File>>>(); final _images = BehaviorSubject<Map<String, Future<File>>>();
/// A subject of a flag that indicates if there is a snack bar showing.
final _snackBarStatus = BehaviorSubject<bool>(seedValue: false);
/// The event being managed by this bloc. /// The event being managed by this bloc.
EventModel _event; EventModel _event;
@ -68,6 +74,13 @@ class EventBloc {
/// An observable of a cache of the images files. /// An observable of a cache of the images files.
Observable<Map<String, Future<File>>> get images => _images.stream; Observable<Map<String, Future<File>>> get images => _images.stream;
/// An observable of a flag that indicates whether or not a snackBar is
/// currently showing.
ValueObservable<bool> get snackBarStatus => _snackBarStatus.stream;
/// An observable of the status of files being uploaded.
Observable<UploadStatus> get uploadStatus => _uploadStatus.status;
// Sinks getters. // Sinks getters.
/// Starts the fetching process for an image given its path. /// Starts the fetching process for an image given its path.
Function(String) get fetchImage => _imagesFetcher.sink.add; Function(String) get fetchImage => _imagesFetcher.sink.add;
@ -75,6 +88,9 @@ class EventBloc {
/// Starts the fetching process for an image thumbail given its path. /// Starts the fetching process for an image thumbail given its path.
Function(String) get fetchThumbnail => _imagesThumbnailsFetcher.sink.add; Function(String) get fetchThumbnail => _imagesThumbnailsFetcher.sink.add;
/// Updates the snack bar status.
Function(bool) get updateSnackBarStatus => _snackBarStatus.sink.add;
EventBloc({ EventBloc({
@required this.eventName, @required this.eventName,
}) { }) {
@ -143,6 +159,8 @@ class EventBloc {
} }
void dispose() async { void dispose() async {
await _snackBarStatus.drain();
_snackBarStatus.close();
await _imagesThumbnailsFetcher.drain(); await _imagesThumbnailsFetcher.drain();
_imagesThumbnailsFetcher.close(); _imagesThumbnailsFetcher.close();
await _imagesFetcher.drain(); await _imagesFetcher.drain();

View file

@ -9,8 +9,6 @@ import '../services/auth_service.dart';
export '../services/auth_service.dart' show FirebaseUser; export '../services/auth_service.dart' show FirebaseUser;
// TODO: Add the text search functionality.
/// A business logic component that manages the state of the home screen. /// A business logic component that manages the state of the home screen.
class HomeBloc { class HomeBloc {
/// An instance of the auth service. /// An instance of the auth service.

View file

@ -6,11 +6,16 @@ import 'package:firebase_storage/firebase_storage.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
import '../services/upload_status_service.dart';
export 'package:firebase_storage/firebase_storage.dart' export 'package:firebase_storage/firebase_storage.dart'
show StorageUploadTask, StorageTaskSnapshot; show StorageUploadTask, StorageTaskSnapshot;
/// A connection to the firebase sotrage bucket. /// A connection to the firebase sotrage bucket.
class FirebaseStorageProvider { class FirebaseStorageProvider {
/// An instance of the upload status service.
final UploadStatusService _uploadStatus = uploadStatusService;
/// The reference to the root path of the storage bucket. /// The reference to the root path of the storage bucket.
final StorageReference _storage; final StorageReference _storage;
@ -35,10 +40,12 @@ class FirebaseStorageProvider {
final String fileId = _uuid.v1(); final String fileId = _uuid.v1();
final StorageReference fileReference = final StorageReference fileReference =
_storage.child('$folder$fileId.$type'); _storage.child('$folder$fileId.$type');
return fileReference.putFile( final uploadTask = fileReference.putFile(
file, file,
StorageMetadata(contentType: 'image/png'), StorageMetadata(contentType: 'image/png'),
); );
_uploadStatus.addNewUpload(uploadTask);
return uploadTask;
} }
/// Deletes a file from the firebase storage bucket given its path. /// Deletes a file from the firebase storage bucket given its path.

View file

@ -41,9 +41,6 @@ class _EventScreenState extends State<EventScreen>
/// Needed for showing snackbars. /// Needed for showing snackbars.
BuildContext _scaffoldContext; BuildContext _scaffoldContext;
/// Flag that indicates if there is a snackbar currently being shown.
bool _hasSnackBar = false;
initState() { initState() {
super.initState(); super.initState();
bloc = EventBloc(eventName: widget.eventName); bloc = EventBloc(eventName: widget.eventName);

View file

@ -5,24 +5,32 @@ import 'package:rxdart/rxdart.dart';
/// A service that maintains a record of the upload operations made to /// A service that maintains a record of the upload operations made to
/// the firebase storage bucket. /// the firebase storage bucket.
class _UploadStatusService { class UploadStatusService {
/// A subject of the current status of uploads. /// A subject of the current status of uploads.
final _status = BehaviorSubject<UploadStatus>(); final _status = BehaviorSubject<UploadStatus>();
/// A map that contains the information about all the current upload tasks. /// A map that contains the information about all the current upload tasks.
Map<StorageUploadTask, List<int>> tasksData = Map<StorageUploadTask, List<int>> _tasksData =
<StorageUploadTask, List<int>>{}; <StorageUploadTask, List<int>>{};
/// An observable of the status for all current upload tasks. /// An observable of the status for all current upload tasks.
Observable<UploadStatus> get status => _status.stream; Observable<UploadStatus> get status => _status.stream;
/// Creates a new service that maintains a record of the upload operations
/// made to the firebase storage bucket.
///
/// Avoid multiple instantiaion of this service. Either use the
/// [uploadStatusService] singleton or instantiate once, the state will be
/// lost otherwise.
UploadStatusService();
/// Adds a new upload task to be tracked. /// Adds a new upload task to be tracked.
/// ///
/// The task gets automatically removed when done. /// The task gets automatically removed when done.
void addNewUpload(StorageUploadTask task) async { void addNewUpload(StorageUploadTask task) async {
final initialSnap = task.lastSnapshot; final initialSnap = task.lastSnapshot;
// Initialize the map entry with the initial values. // Initialize the map entry with the initial values.
tasksData[task] = [ _tasksData[task] = [
initialSnap.bytesTransferred, initialSnap.bytesTransferred,
initialSnap.totalByteCount, initialSnap.totalByteCount,
]; ];
@ -30,7 +38,7 @@ class _UploadStatusService {
(StorageTaskEvent event) { (StorageTaskEvent event) {
// Update the map with the current values. // Update the map with the current values.
final snap = event.snapshot; final snap = event.snapshot;
tasksData[task] = [ _tasksData[task] = [
snap.bytesTransferred, snap.bytesTransferred,
snap.totalByteCount, snap.totalByteCount,
]; ];
@ -38,14 +46,14 @@ class _UploadStatusService {
}, },
); );
await task.onComplete; await task.onComplete;
tasksData.remove(task); _tasksData.remove(task);
} }
/// Updates the _status subject with the most current data. /// Updates the _status subject with the most current data.
void _sendUpdate() { void _sendUpdate() {
int totalBytes = 0, bytestTransferred = 0; int totalBytes = 0, bytestTransferred = 0;
double percentage = 0.0; double percentage = 0.0;
tasksData.forEach( _tasksData.forEach(
(_, data) { (_, data) {
bytestTransferred += data[0]; bytestTransferred += data[0];
totalBytes += data[1]; totalBytes += data[1];
@ -56,7 +64,7 @@ class _UploadStatusService {
} }
_status.sink.add(UploadStatus( _status.sink.add(UploadStatus(
percentage: percentage, percentage: percentage,
numberOfFiles: tasksData.length, numberOfFiles: _tasksData.length,
)); ));
} }
@ -83,4 +91,4 @@ class UploadStatus {
}); });
} }
final uploadStatusService = _UploadStatusService(); final uploadStatusService = UploadStatusService();

View file

@ -1,7 +1,10 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';
import './models/task_model.dart'; import './models/task_model.dart';
import './services/upload_status_service.dart';
const kLowPriorityColor = Color(0xFF06AD12); const kLowPriorityColor = Color(0xFF06AD12);
const kMediumPriorityColor = Color(0xFFF6A93B); const kMediumPriorityColor = Color(0xFFF6A93B);
@ -67,3 +70,10 @@ String getImageThumbnailPath(String path) {
tokens.last = 'thumb@' + tokens.last; tokens.last = 'thumb@' + tokens.last;
return tokens.join('/'); return tokens.join('/');
} }
///
void showUploadStatusSnackBar(
BuildContext context,
Observable<UploadStatus> uploadStatus,
ValueObservable<bool> snackBarStatus,
) {}