jld3103
2 years ago
7 changed files with 198 additions and 236 deletions
@ -0,0 +1,33 @@
|
||||
part of '../neon.dart'; |
||||
|
||||
typedef APIImageDownloader = Future<Uint8List> Function(); |
||||
|
||||
class CachedAPIImage extends CachedImage { |
||||
CachedAPIImage({ |
||||
required final Account account, |
||||
required final String cacheKey, |
||||
required final APIImageDownloader download, |
||||
final String? etag, |
||||
super.height, |
||||
super.width, |
||||
super.fit, |
||||
super.svgColor, |
||||
super.iconColor, |
||||
super.key, |
||||
}) : super( |
||||
future: () async { |
||||
final realKey = '${account.id}-$cacheKey'; |
||||
final cacheFile = await _cacheManager.getFileFromCache(realKey); |
||||
if (cacheFile != null && cacheFile.validTill.isAfter(DateTime.now())) { |
||||
return cacheFile.file; |
||||
} |
||||
|
||||
return _cacheManager.putFile( |
||||
realKey, |
||||
await download(), |
||||
maxAge: const Duration(days: 7), |
||||
eTag: etag, |
||||
); |
||||
}(), |
||||
); |
||||
} |
@ -0,0 +1,72 @@
|
||||
part of '../neon.dart'; |
||||
|
||||
final _cacheManager = DefaultCacheManager(); |
||||
|
||||
abstract class CachedImage extends StatelessWidget { |
||||
const CachedImage({ |
||||
required this.future, |
||||
this.isSvgHint = false, |
||||
this.height, |
||||
this.width, |
||||
this.fit, |
||||
this.svgColor, |
||||
this.iconColor, |
||||
super.key, |
||||
}); |
||||
|
||||
final Future<File> future; |
||||
final bool isSvgHint; |
||||
|
||||
final double? height; |
||||
final double? width; |
||||
final BoxFit? fit; |
||||
|
||||
final Color? svgColor; |
||||
final Color? iconColor; |
||||
|
||||
@override |
||||
Widget build(final BuildContext context) => FutureBuilder<File>( |
||||
future: future, |
||||
builder: (final context, final fileSnapshot) { |
||||
if (fileSnapshot.hasData) { |
||||
final content = fileSnapshot.data!.readAsBytesSync(); |
||||
|
||||
try { |
||||
// TODO: Is this safe enough? |
||||
if (isSvgHint || utf8.decode(content).contains('<svg')) { |
||||
return SvgPicture.memory( |
||||
content, |
||||
height: height, |
||||
width: width, |
||||
fit: fit ?? BoxFit.contain, |
||||
color: svgColor, |
||||
); |
||||
} |
||||
} catch (_) { |
||||
// If the data is not UTF-8 |
||||
} |
||||
|
||||
return Image.memory( |
||||
content, |
||||
height: height, |
||||
width: width, |
||||
fit: fit, |
||||
gaplessPlayback: true, |
||||
); |
||||
} |
||||
if (fileSnapshot.hasError) { |
||||
return Icon( |
||||
Icons.error_outline, |
||||
size: height != null && width != null ? min(height!, width!) : height ?? width, |
||||
color: iconColor, |
||||
); |
||||
} |
||||
return SizedBox( |
||||
width: width, |
||||
child: CustomLinearProgressIndicator( |
||||
color: iconColor, |
||||
), |
||||
); |
||||
}, |
||||
); |
||||
} |
@ -1,82 +1,16 @@
|
||||
part of '../neon.dart'; |
||||
|
||||
final _cacheManager = DefaultCacheManager(); |
||||
|
||||
class CachedURLImage extends StatelessWidget { |
||||
const CachedURLImage({ |
||||
required this.url, |
||||
this.height, |
||||
this.width, |
||||
this.fit, |
||||
this.svgColor, |
||||
this.iconColor, |
||||
class CachedURLImage extends CachedImage { |
||||
CachedURLImage({ |
||||
required final String url, |
||||
super.height, |
||||
super.width, |
||||
super.fit, |
||||
super.svgColor, |
||||
super.iconColor, |
||||
super.key, |
||||
}); |
||||
|
||||
final String url; |
||||
|
||||
final double? height; |
||||
final double? width; |
||||
final BoxFit? fit; |
||||
|
||||
final Color? svgColor; |
||||
final Color? iconColor; |
||||
|
||||
@override |
||||
Widget build(final BuildContext context) => FutureBuilder<File>( |
||||
// Really weird false positive |
||||
// ignore: discarded_futures |
||||
future: _cacheManager.getSingleFile(url), |
||||
builder: (final context, final fileSnapshot) { |
||||
if (fileSnapshot.hasData) { |
||||
final content = fileSnapshot.data!.readAsBytesSync(); |
||||
|
||||
var isSvg = false; |
||||
if (Uri.parse(url).path.endsWith('.svg')) { |
||||
isSvg = true; |
||||
} |
||||
if (!isSvg) { |
||||
try { |
||||
// TODO: Is this safe enough? |
||||
if (utf8.decode(content).contains('<svg')) { |
||||
isSvg = true; |
||||
} |
||||
} catch (_) { |
||||
// If the data is not UTF-8 |
||||
} |
||||
} |
||||
|
||||
if (isSvg) { |
||||
return SvgPicture.memory( |
||||
content, |
||||
height: height, |
||||
width: width, |
||||
fit: fit ?? BoxFit.contain, |
||||
color: svgColor, |
||||
); |
||||
} |
||||
|
||||
return Image.memory( |
||||
content, |
||||
height: height, |
||||
width: width, |
||||
fit: fit, |
||||
gaplessPlayback: true, |
||||
); |
||||
} |
||||
if (fileSnapshot.hasError) { |
||||
return Icon( |
||||
Icons.error_outline, |
||||
size: height != null && width != null ? min(height!, width!) : height ?? width, |
||||
color: iconColor, |
||||
); |
||||
} |
||||
return SizedBox( |
||||
width: width, |
||||
child: CustomLinearProgressIndicator( |
||||
color: iconColor, |
||||
), |
||||
); |
||||
}, |
||||
); |
||||
}) : super( |
||||
future: _cacheManager.getSingleFile(url), |
||||
isSvgHint: Uri.parse(url).path.endsWith('.svg'), |
||||
); |
||||
} |
||||
|
Loading…
Reference in new issue