-
-
Save Gperez88/f8f360abb50c58377aa4cb5927a72ddf to your computer and use it in GitHub Desktop.
A Flutter widget that handles and shows an image downloaded from a Firebase Storage document.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:cached_network_image/cached_network_image.dart'; | |
import 'package:firebase_storage/firebase_storage.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:meta/meta.dart'; | |
import '../../../injection_container.dart' as di; | |
enum ImageDownloadState { | |
Idle, | |
GettingReference, | |
GettingURL, | |
Downloading, | |
Done, | |
Error | |
} | |
class FirebaseStorageImage extends StatefulWidget { | |
/// The reference url of the image that has to be loaded. | |
final String referenceUrl; | |
/// The widget that will be displayed when loading if no [placeholderImage] is set. | |
final Widget fallbackWidget; | |
/// The widget that will be displayed if an error occurs. | |
final Widget errorWidget; | |
/// The image that will be displayed when loading if no [fallbackWidget] is set. | |
final ImageProvider placeholderImage; | |
final BoxFit fit; | |
final double width; | |
final double height; | |
FirebaseStorageImage({ | |
Key key, | |
@required this.referenceUrl, | |
@required this.errorWidget, | |
this.fallbackWidget, | |
this.placeholderImage, | |
this.fit = BoxFit.cover, | |
this.width, | |
this.height, | |
}) { | |
assert( | |
(this.fallbackWidget == null && this.placeholderImage != null) || | |
(this.fallbackWidget != null && this.placeholderImage == null), | |
"Either [fallbackWidget] or [placeholderImage] must not be null."); | |
} | |
@override | |
_FirebaseStorageImageState createState() => _FirebaseStorageImageState( | |
referenceUrl, | |
fallbackWidget, | |
errorWidget, | |
placeholderImage, | |
fit, | |
width, | |
height, | |
); | |
} | |
class _FirebaseStorageImageState extends State<FirebaseStorageImage> | |
with SingleTickerProviderStateMixin { | |
_FirebaseStorageImageState( | |
String referenceUrl, | |
this.fallbackWidget, | |
this.errorWidget, | |
this.placeholderImage, | |
this.fit, | |
this.width, | |
this.height, | |
) { | |
final reference = _storage.getReferenceFromUrl(referenceUrl); | |
this._imageDownloadState = ImageDownloadState.GettingReference; | |
reference.then(this._getReferenceByUrl).catchError((err) { | |
this._setError(); | |
}); | |
} | |
final BoxFit fit; | |
final double width; | |
final double height; | |
// Storage firebase. | |
final _storage = di.sl<FirebaseStorage>(); | |
/// The widget that will be displayed when loading if no [placeholderImage] is set. | |
final Widget fallbackWidget; | |
/// The widget that will be displayed if an error occurs. | |
final Widget errorWidget; | |
/// The image that will be displayed when loading if no [fallbackWidget] is set. | |
final ImageProvider placeholderImage; | |
/// The image that will be/has been downloaded from the [reference]. | |
Image _networkImage; | |
/// The state of the [_networkImage]. | |
ImageDownloadState _imageDownloadState = ImageDownloadState.Idle; | |
/// Gets reference from reference url. | |
void _getReferenceByUrl(StorageReference reference) { | |
final url = reference.getDownloadURL(); | |
this._imageDownloadState = ImageDownloadState.GettingURL; | |
url.then(this._setImageData).catchError((err) { | |
this._setError(); | |
}); | |
} | |
/// Sets the [_networkImage] to the image downloaded from [url]. | |
void _setImageData(dynamic url) { | |
this._networkImage = Image.network(url, fit: fit); | |
this._networkImage.image.resolve(ImageConfiguration()).addListener( | |
ImageStreamListener((ImageInfo image, bool synchronousCall) { | |
if (mounted) | |
setState(() => this._imageDownloadState = ImageDownloadState.Done); | |
})); | |
if (this._imageDownloadState != ImageDownloadState.Done) | |
this._imageDownloadState = ImageDownloadState.Downloading; | |
} | |
/// Sets the [_imageDownloadState] to [ImageDownloadState.Error] and redraws the UI. | |
void _setError() { | |
if (mounted) | |
setState(() => this._imageDownloadState = ImageDownloadState.Error); | |
} | |
@override | |
Widget build(BuildContext context) { | |
Widget widget = SizedBox.shrink(); | |
switch (this._imageDownloadState) { | |
case ImageDownloadState.Idle: | |
case ImageDownloadState.GettingReference: | |
case ImageDownloadState.GettingURL: | |
case ImageDownloadState.Downloading: | |
widget = this.placeholderImage != null | |
? Image(image: this.placeholderImage) | |
: Center(child: this.fallbackWidget); | |
break; | |
case ImageDownloadState.Error: | |
widget = this.errorWidget; | |
break; | |
case ImageDownloadState.Done: | |
widget = this._networkImage; | |
break; | |
default: | |
widget = this.errorWidget; | |
} | |
return SizedBox( | |
height: height, | |
width: width, | |
child: widget, | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment