Skip to content

Commit

Permalink
Show progress while loading relatively linked images
Browse files Browse the repository at this point in the history
  • Loading branch information
amake committed Sep 3, 2024
1 parent d4486ca commit e2dacb9
Showing 1 changed file with 36 additions and 12 deletions.
48 changes: 36 additions & 12 deletions lib/src/components/image.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:convert';
import 'dart:ui' as ui;

Expand Down Expand Up @@ -218,8 +219,11 @@ class _DataSourceImage extends ImageProvider<_DataSourceImage> {
@protected
ImageStreamCompleter loadImage(
_DataSourceImage key, ImageDecoderCallback decode) {
final chunkEvents = StreamController<ImageChunkEvent>();

return MultiFrameImageStreamCompleter(
codec: _loadAsync(key, decode: decode),
codec: _loadAsync(key, chunkEvents, decode: decode),
chunkEvents: chunkEvents.stream,
scale: key.scale,
debugLabel: key.dataSource.id,
informationCollector: () => <DiagnosticsNode>[
Expand All @@ -229,20 +233,40 @@ class _DataSourceImage extends ImageProvider<_DataSourceImage> {
}

Future<ui.Codec> _loadAsync(
_DataSourceImage key, {
_DataSourceImage key,
StreamController<ImageChunkEvent> chunkEvents, {
required ImageDecoderCallback decode,
}) async {
assert(key == this);

final relative = await key.dataSource.resolveRelative(key.relativePath);
final bytes = await relative.bytes;
if (bytes.isEmpty) {
// The file may become available later.
PaintingBinding.instance.imageCache.evict(key);
throw StateError(
'${key.dataSource.id} / $relativePath is empty and cannot be loaded as an image.');
try {
assert(key == this);

chunkEvents.add(const ImageChunkEvent(
cumulativeBytesLoaded: 0,
expectedTotalBytes: null,
));

final relative = await key.dataSource.resolveRelative(key.relativePath);
final bytes = await relative.bytes;

chunkEvents.add(ImageChunkEvent(
cumulativeBytesLoaded: bytes.length,
expectedTotalBytes: bytes.length,
));

if (bytes.isEmpty) {
// The file may become available later. Throw to evict from cash.
throw StateError(
'${key.dataSource.id} / $relativePath is empty and cannot be loaded as an image.');
}
return decode(await ui.ImmutableBuffer.fromUint8List(bytes));
} catch (e) {
scheduleMicrotask(() {
PaintingBinding.instance.imageCache.evict(key);
});
rethrow;
} finally {
chunkEvents.close();
}
return decode(await ui.ImmutableBuffer.fromUint8List(bytes));
}

@override
Expand Down

0 comments on commit e2dacb9

Please sign in to comment.