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'; |
part of '../neon.dart'; |
||||||
|
|
||||||
final _cacheManager = DefaultCacheManager(); |
class CachedURLImage extends CachedImage { |
||||||
|
CachedURLImage({ |
||||||
class CachedURLImage extends StatelessWidget { |
required final String url, |
||||||
const CachedURLImage({ |
super.height, |
||||||
required this.url, |
super.width, |
||||||
this.height, |
super.fit, |
||||||
this.width, |
super.svgColor, |
||||||
this.fit, |
super.iconColor, |
||||||
this.svgColor, |
|
||||||
this.iconColor, |
|
||||||
super.key, |
super.key, |
||||||
}); |
}) : super( |
||||||
|
future: _cacheManager.getSingleFile(url), |
||||||
final String url; |
isSvgHint: Uri.parse(url).path.endsWith('.svg'), |
||||||
|
); |
||||||
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, |
|
||||||
), |
|
||||||
); |
|
||||||
}, |
|
||||||
); |
|
||||||
} |
} |
||||||
|
Loading…
Reference in new issue