From 413398b332a4b2e932e6696b9395faac607543dd Mon Sep 17 00:00:00 2001 From: Justus Fluegel Date: Wed, 5 Jun 2024 05:51:23 +0200 Subject: [PATCH 1/3] Refactor for await in web runtime to streamcontroller Signed-off-by: Justus Fluegel --- .../lib/cached_network_image_web.dart | 61 +++++++++++-------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/cached_network_image_web/lib/cached_network_image_web.dart b/cached_network_image_web/lib/cached_network_image_web.dart index 7922eb1e..43d66839 100644 --- a/cached_network_image_web/lib/cached_network_image_web.dart +++ b/cached_network_image_web/lib/cached_network_image_web.dart @@ -115,39 +115,46 @@ class ImageLoader implements platform.ImageLoader { int? maxWidth, Map? headers, VoidCallback evictImage, - ) async* { - try { - await for (final result in cacheManager.getFileStream( - url, - key: cacheKey, - withProgress: true, - headers: headers, - )) { - if (result is DownloadProgress) { + ) { + var streamController = StreamController(); + + final stream = cacheManager.getFileStream( + url, + withProgress: true, + headers: headers, + key: cacheKey, + ); + + stream.listen( + (event) { + if (event is DownloadProgress) { chunkEvents.add( ImageChunkEvent( - cumulativeBytesLoaded: result.downloaded, - expectedTotalBytes: result.totalSize, + cumulativeBytesLoaded: event.downloaded, + expectedTotalBytes: event.totalSize, ), ); } - if (result is FileInfo) { - final file = result.file; - final bytes = await file.readAsBytes(); - final decoded = await decode(bytes); - yield decoded; + if (event is FileInfo) { + event.file + .readAsBytes() + .then((value) => decode(value).then(streamController.add)); } - } - } on Object { - // Depending on where the exception was thrown, the image cache may not - // have had a chance to track the key in the cache at all. - // Schedule a microtask to give the cache a chance to add the key. - scheduleMicrotask(() { - evictImage(); - }); - rethrow; - } - await chunkEvents.close(); + }, + onError: (e, st) { + scheduleMicrotask(() { + evictImage(); + }); + streamController.addError(e, st); + }, + onDone: () async { + streamController.close(); + chunkEvents.close(); + }, + cancelOnError: true, + ); + + return streamController.stream; } Future _loadAsyncHtmlImage( From 1e3196d39c9177561731e243e731704f21531f05 Mon Sep 17 00:00:00 2001 From: Justus Fluegel Date: Wed, 5 Jun 2024 06:37:45 +0200 Subject: [PATCH 2/3] Don't prematurely close the stream Signed-off-by: Justus Fluegel --- .../lib/cached_network_image_web.dart | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/cached_network_image_web/lib/cached_network_image_web.dart b/cached_network_image_web/lib/cached_network_image_web.dart index 43d66839..42f63b67 100644 --- a/cached_network_image_web/lib/cached_network_image_web.dart +++ b/cached_network_image_web/lib/cached_network_image_web.dart @@ -12,6 +12,8 @@ import 'package:cached_network_image_platform_interface' import 'package:flutter/material.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; +enum _State { open, waitingForData, closing } + /// ImageLoader class to load images on the web platform. class ImageLoader implements platform.ImageLoader { @Deprecated('Use loadImageAsync instead') @@ -125,6 +127,8 @@ class ImageLoader implements platform.ImageLoader { key: cacheKey, ); + var state = _State.open; + stream.listen( (event) { if (event is DownloadProgress) { @@ -136,9 +140,17 @@ class ImageLoader implements platform.ImageLoader { ); } if (event is FileInfo) { - event.file - .readAsBytes() - .then((value) => decode(value).then(streamController.add)); + if (state == _State.open) { + state = _State.waitingForData; + } + + event.file.readAsBytes().then((value) => decode(value)).then((data) { + streamController.add(data); + if (state == _State.closing) { + streamController.close(); + chunkEvents.close(); + } + }); } }, onError: (e, st) { @@ -148,8 +160,12 @@ class ImageLoader implements platform.ImageLoader { streamController.addError(e, st); }, onDone: () async { - streamController.close(); - chunkEvents.close(); + if (state == _State.open) { + streamController.close(); + chunkEvents.close(); + } else if (state == _State.waitingForData) { + state = _State.closing; + } }, cancelOnError: true, ); From 19744365cac7b3fd05970e0af383a571935806d9 Mon Sep 17 00:00:00 2001 From: Justus Fluegel Date: Sun, 4 Aug 2024 01:21:55 +0200 Subject: [PATCH 3/3] Put initialization code in try-catch to mirror old behaviour of sending errors on stream Signed-off-by: Justus Fluegel --- .../lib/cached_network_image_web.dart | 98 ++++++++++--------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/cached_network_image_web/lib/cached_network_image_web.dart b/cached_network_image_web/lib/cached_network_image_web.dart index 42f63b67..9b7449c6 100644 --- a/cached_network_image_web/lib/cached_network_image_web.dart +++ b/cached_network_image_web/lib/cached_network_image_web.dart @@ -120,55 +120,65 @@ class ImageLoader implements platform.ImageLoader { ) { var streamController = StreamController(); - final stream = cacheManager.getFileStream( - url, - withProgress: true, - headers: headers, - key: cacheKey, - ); + try { + final stream = cacheManager.getFileStream( + url, + withProgress: true, + headers: headers, + key: cacheKey, + ); - var state = _State.open; + var state = _State.open; - stream.listen( - (event) { - if (event is DownloadProgress) { - chunkEvents.add( - ImageChunkEvent( - cumulativeBytesLoaded: event.downloaded, - expectedTotalBytes: event.totalSize, - ), - ); - } - if (event is FileInfo) { - if (state == _State.open) { - state = _State.waitingForData; + stream.listen( + (event) { + if (event is DownloadProgress) { + chunkEvents.add( + ImageChunkEvent( + cumulativeBytesLoaded: event.downloaded, + expectedTotalBytes: event.totalSize, + ), + ); } - - event.file.readAsBytes().then((value) => decode(value)).then((data) { - streamController.add(data); - if (state == _State.closing) { - streamController.close(); - chunkEvents.close(); + if (event is FileInfo) { + if (state == _State.open) { + state = _State.waitingForData; } + + event.file + .readAsBytes() + .then((value) => decode(value)) + .then((data) { + streamController.add(data); + if (state == _State.closing) { + streamController.close(); + chunkEvents.close(); + } + }); + } + }, + onError: (e, st) { + scheduleMicrotask(() { + evictImage(); }); - } - }, - onError: (e, st) { - scheduleMicrotask(() { - evictImage(); - }); - streamController.addError(e, st); - }, - onDone: () async { - if (state == _State.open) { - streamController.close(); - chunkEvents.close(); - } else if (state == _State.waitingForData) { - state = _State.closing; - } - }, - cancelOnError: true, - ); + streamController.addError(e, st); + }, + onDone: () async { + if (state == _State.open) { + streamController.close(); + chunkEvents.close(); + } else if (state == _State.waitingForData) { + state = _State.closing; + } + }, + cancelOnError: true, + ); + } on Object catch (e, st) { + scheduleMicrotask(() { + evictImage(); + }); + streamController.addError(e, st); + } return streamController.stream; }