|
|
@ -11,6 +11,7 @@ import 'package:neon/src/widgets/linear_progress_indicator.dart'; |
|
|
|
typedef CacheReviver = FutureOr<Uint8List?> Function(CacheManager cacheManager); |
|
|
|
typedef CacheReviver = FutureOr<Uint8List?> Function(CacheManager cacheManager); |
|
|
|
typedef ImageDownloader = FutureOr<Uint8List> Function(); |
|
|
|
typedef ImageDownloader = FutureOr<Uint8List> Function(); |
|
|
|
typedef CacheWriter = Future<void> Function(CacheManager cacheManager, Uint8List image); |
|
|
|
typedef CacheWriter = Future<void> Function(CacheManager cacheManager, Uint8List image); |
|
|
|
|
|
|
|
typedef ErrorWidgetBuilder = Widget? Function(BuildContext, dynamic); |
|
|
|
|
|
|
|
|
|
|
|
class NeonCachedImage extends StatefulWidget { |
|
|
|
class NeonCachedImage extends StatefulWidget { |
|
|
|
const NeonCachedImage({ |
|
|
|
const NeonCachedImage({ |
|
|
@ -21,6 +22,7 @@ class NeonCachedImage extends StatefulWidget { |
|
|
|
this.fit, |
|
|
|
this.fit, |
|
|
|
this.svgColor, |
|
|
|
this.svgColor, |
|
|
|
this.iconColor, |
|
|
|
this.iconColor, |
|
|
|
|
|
|
|
this.errorBuilder, |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
NeonCachedImage.url({ |
|
|
|
NeonCachedImage.url({ |
|
|
@ -31,6 +33,7 @@ class NeonCachedImage extends StatefulWidget { |
|
|
|
this.fit, |
|
|
|
this.fit, |
|
|
|
this.svgColor, |
|
|
|
this.svgColor, |
|
|
|
this.iconColor, |
|
|
|
this.iconColor, |
|
|
|
|
|
|
|
this.errorBuilder, |
|
|
|
}) : image = _getImageFromUrl(url), |
|
|
|
}) : image = _getImageFromUrl(url), |
|
|
|
super(key: key ?? Key(url)); |
|
|
|
super(key: key ?? Key(url)); |
|
|
|
|
|
|
|
|
|
|
@ -44,6 +47,7 @@ class NeonCachedImage extends StatefulWidget { |
|
|
|
this.fit, |
|
|
|
this.fit, |
|
|
|
this.svgColor, |
|
|
|
this.svgColor, |
|
|
|
this.iconColor, |
|
|
|
this.iconColor, |
|
|
|
|
|
|
|
this.errorBuilder, |
|
|
|
}) : image = _customImageGetter( |
|
|
|
}) : image = _customImageGetter( |
|
|
|
reviver, |
|
|
|
reviver, |
|
|
|
getImage, |
|
|
|
getImage, |
|
|
@ -61,6 +65,8 @@ class NeonCachedImage extends StatefulWidget { |
|
|
|
final Color? svgColor; |
|
|
|
final Color? svgColor; |
|
|
|
final Color? iconColor; |
|
|
|
final Color? iconColor; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final ErrorWidgetBuilder? errorBuilder; |
|
|
|
|
|
|
|
|
|
|
|
static Future<Uint8List> _getImageFromUrl(final String url) async { |
|
|
|
static Future<Uint8List> _getImageFromUrl(final String url) async { |
|
|
|
final file = await _cacheManager.getSingleFile(url); |
|
|
|
final file = await _cacheManager.getSingleFile(url); |
|
|
|
return file.readAsBytes(); |
|
|
|
return file.readAsBytes(); |
|
|
@ -116,6 +122,10 @@ class _NeonCachedImageState extends State<NeonCachedImage> { |
|
|
|
child: FutureBuilder<Uint8List>( |
|
|
|
child: FutureBuilder<Uint8List>( |
|
|
|
future: widget.image, |
|
|
|
future: widget.image, |
|
|
|
builder: (final context, final fileSnapshot) { |
|
|
|
builder: (final context, final fileSnapshot) { |
|
|
|
|
|
|
|
if (fileSnapshot.hasError) { |
|
|
|
|
|
|
|
return _buildError(fileSnapshot.error); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (!fileSnapshot.hasData) { |
|
|
|
if (!fileSnapshot.hasData) { |
|
|
|
return SizedBox( |
|
|
|
return SizedBox( |
|
|
|
width: widget.size?.width, |
|
|
|
width: widget.size?.width, |
|
|
@ -125,18 +135,6 @@ class _NeonCachedImageState extends State<NeonCachedImage> { |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (fileSnapshot.hasError) { |
|
|
|
|
|
|
|
return NeonException( |
|
|
|
|
|
|
|
fileSnapshot.error, |
|
|
|
|
|
|
|
onRetry: () { |
|
|
|
|
|
|
|
setState(() {}); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
onlyIcon: true, |
|
|
|
|
|
|
|
iconSize: widget.size?.shortestSide, |
|
|
|
|
|
|
|
color: widget.iconColor ?? Theme.of(context).colorScheme.error, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final content = fileSnapshot.requireData; |
|
|
|
final content = fileSnapshot.requireData; |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
@ -160,8 +158,20 @@ class _NeonCachedImageState extends State<NeonCachedImage> { |
|
|
|
width: widget.size?.width, |
|
|
|
width: widget.size?.width, |
|
|
|
fit: widget.fit, |
|
|
|
fit: widget.fit, |
|
|
|
gaplessPlayback: true, |
|
|
|
gaplessPlayback: true, |
|
|
|
|
|
|
|
errorBuilder: (final context, final error, final stacktrace) => _buildError(error), |
|
|
|
); |
|
|
|
); |
|
|
|
}, |
|
|
|
}, |
|
|
|
), |
|
|
|
), |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Widget _buildError(final dynamic error) => |
|
|
|
|
|
|
|
widget.errorBuilder?.call(context, error) ?? |
|
|
|
|
|
|
|
NeonException( |
|
|
|
|
|
|
|
error, |
|
|
|
|
|
|
|
onRetry: () { |
|
|
|
|
|
|
|
setState(() {}); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
onlyIcon: true, |
|
|
|
|
|
|
|
iconSize: widget.size?.shortestSide, |
|
|
|
|
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|