Skip to content

Commit 1169d15

Browse files
Merge pull request Sub6Resources#66 from The-Redhat/master
use preCacheImage to catch errors while image loading
2 parents f8cb452 + fa50be5 commit 1169d15

File tree

5 files changed

+68
-25
lines changed

5 files changed

+68
-25
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## [0.9.7] - March 26, 2019:
2+
3+
* Added onImageError callback
4+
15
## [0.9.6] - March 11, 2019:
26

37
* Fix whitespace issue. ([#59](https://github.com/Sub6Resources/flutter_html/issues/59))

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ A Flutter widget for rendering static html tags as Flutter widgets. (Will render
99
Add the following to your `pubspec.yaml` file:
1010

1111
dependencies:
12-
flutter_html: ^0.9.6
12+
flutter_html: ^0.9.7
1313

1414
## Currently Supported HTML Tags:
1515
`a`, `abbr`, `acronym`, `address`, `article`, `aside`, `b`, `bdi`, `bdo`, `big`, `blockquote`, `body`, `br`, `caption`, `cite`, `code`, `data`, `dd`, `del`, `dfn`, `div`, `dl`, `dt`, `em`, `figcaption`, `figure`, `footer`, `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `header`, `hr`, `i`, `img`, `ins`, `kbd`, `li`, `main`, `mark`, `nav`, `noscript`, `ol`, `p`, `pre`, `q`, `rp`, `rt`, `ruby`, `s`, `samp`, `section`, `small`, `span`, `strike`, `strong`, `sub`, `sup`, `table`, `tbody`, `td`, `template`, `tfoot`, `th`, `thead`, `time`, `tr`, `tt`, `u`, `ul`, `var`

lib/flutter_html.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class Html extends StatelessWidget {
1515
this.customRender,
1616
this.blockSpacing = 14.0,
1717
this.useRichText = false,
18+
this.onImageError,
1819
this.linkStyle = const TextStyle(
1920
decoration: TextDecoration.underline,
2021
color: Colors.blueAccent,
@@ -29,6 +30,7 @@ class Html extends StatelessWidget {
2930
final bool renderNewlines;
3031
final double blockSpacing;
3132
final bool useRichText;
33+
final ImageErrorListener onImageError;
3234
final TextStyle linkStyle;
3335

3436
/// Either return a custom widget for specific node types or return null to
@@ -51,6 +53,7 @@ class Html extends StatelessWidget {
5153
onLinkTap: onLinkTap,
5254
renderNewlines: renderNewlines,
5355
html: data,
56+
onImageError: onImageError,
5457
linkStyle: linkStyle,
5558
)
5659
: HtmlOldParser(
@@ -60,6 +63,7 @@ class Html extends StatelessWidget {
6063
customRender: customRender,
6164
html: data,
6265
blockSpacing: blockSpacing,
66+
onImageError: onImageError,
6367
linkStyle: linkStyle,
6468
),
6569
),

lib/html_parser.dart

Lines changed: 58 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import 'dart:convert';
22

3-
import 'package:flutter/material.dart';
43
import 'package:flutter/gestures.dart';
5-
import 'package:html/parser.dart' as parser;
4+
import 'package:flutter/material.dart';
65
import 'package:html/dom.dart' as dom;
6+
import 'package:html/parser.dart' as parser;
77

88
typedef CustomRender = Widget Function(dom.Node node, List<Widget> children);
99
typedef OnLinkTap = void Function(String url);
@@ -144,6 +144,7 @@ class HtmlRichTextParser extends StatelessWidget {
144144
this.onLinkTap,
145145
this.renderNewlines = false,
146146
this.html,
147+
this.onImageError,
147148
this.linkStyle = const TextStyle(
148149
decoration: TextDecoration.underline,
149150
color: Colors.blueAccent,
@@ -156,6 +157,7 @@ class HtmlRichTextParser extends StatelessWidget {
156157
final onLinkTap;
157158
final bool renderNewlines;
158159
final String html;
160+
final ImageErrorListener onImageError;
159161
final TextStyle linkStyle;
160162

161163
// style elements set a default style
@@ -266,7 +268,8 @@ class HtmlRichTextParser extends StatelessWidget {
266268
);
267269

268270
// ignore the top level "body"
269-
body.nodes.forEach((dom.Node node) => _parseNode(node, parseContext));
271+
body.nodes
272+
.forEach((dom.Node node) => _parseNode(node, parseContext, context));
270273
// _parseNode(body, parseContext);
271274

272275
// filter out empty widgets
@@ -303,7 +306,8 @@ class HtmlRichTextParser extends StatelessWidget {
303306
// function can add child nodes to the parent if it should
304307
//
305308
// each iteration creates a new parseContext as a copy of the previous one if it needs to
306-
void _parseNode(dom.Node node, ParseContext parseContext) {
309+
void _parseNode(
310+
dom.Node node, ParseContext parseContext, BuildContext buildContext) {
307311
// TEXT ONLY NODES
308312
// a text only node is a child of a tag with no inner html
309313
if (node is dom.Text) {
@@ -624,9 +628,23 @@ class HtmlRichTextParser extends StatelessWidget {
624628
if (node.attributes['src'] != null) {
625629
if (node.attributes['src'].startsWith("data:image") &&
626630
node.attributes['src'].contains("base64,")) {
631+
precacheImage(
632+
MemoryImage(
633+
base64.decode(
634+
node.attributes['src'].split("base64,")[1].trim(),
635+
),
636+
),
637+
buildContext,
638+
onError: onImageError,
639+
);
627640
parseContext.rootWidgetList.add(Image.memory(base64.decode(
628641
node.attributes['src'].split("base64,")[1].trim())));
629642
} else {
643+
precacheImage(
644+
NetworkImage(node.attributes['src']),
645+
buildContext,
646+
onError: onImageError,
647+
);
630648
parseContext.rootWidgetList
631649
.add(Image.network(node.attributes['src']));
632650
}
@@ -743,7 +761,7 @@ class HtmlRichTextParser extends StatelessWidget {
743761
}
744762

745763
node.nodes.forEach((dom.Node childNode) {
746-
_parseNode(childNode, nextContext);
764+
_parseNode(childNode, nextContext, buildContext);
747765
});
748766
}
749767
}
@@ -817,6 +835,7 @@ class HtmlOldParser extends StatelessWidget {
817835
this.customRender,
818836
this.blockSpacing,
819837
this.html,
838+
this.onImageError,
820839
this.linkStyle = const TextStyle(
821840
decoration: TextDecoration.underline,
822841
color: Colors.blueAccent,
@@ -829,6 +848,7 @@ class HtmlOldParser extends StatelessWidget {
829848
final CustomRender customRender;
830849
final double blockSpacing;
831850
final String html;
851+
final ImageErrorListener onImageError;
832852
final TextStyle linkStyle;
833853

834854
static const _supportedElements = [
@@ -1291,24 +1311,39 @@ class HtmlOldParser extends StatelessWidget {
12911311
),
12921312
);
12931313
case "img":
1294-
if (node.attributes['src'] != null) {
1295-
if (node.attributes['src'].startsWith("data:image") &&
1296-
node.attributes['src'].contains("base64,")) {
1297-
return Image.memory(base64
1298-
.decode(node.attributes['src'].split("base64,")[1].trim()));
1299-
}
1300-
return Image.network(node.attributes['src']);
1301-
} else if (node.attributes['alt'] != null) {
1302-
//Temp fix for https://github.com/flutter/flutter/issues/736
1303-
if (node.attributes['alt'].endsWith(" ")) {
1304-
return Container(
1305-
padding: EdgeInsets.only(right: 2.0),
1306-
child: Text(node.attributes['alt']));
1307-
} else {
1308-
return Text(node.attributes['alt']);
1309-
}
1310-
}
1311-
return Container();
1314+
return Builder(
1315+
builder: (BuildContext context) {
1316+
if (node.attributes['src'] != null) {
1317+
if (node.attributes['src'].startsWith("data:image") &&
1318+
node.attributes['src'].contains("base64,")) {
1319+
precacheImage(
1320+
MemoryImage(base64.decode(
1321+
node.attributes['src'].split("base64,")[1].trim())),
1322+
context,
1323+
onError: onImageError,
1324+
);
1325+
return Image.memory(base64.decode(
1326+
node.attributes['src'].split("base64,")[1].trim()));
1327+
}
1328+
precacheImage(
1329+
NetworkImage(node.attributes['src']),
1330+
context,
1331+
onError: onImageError,
1332+
);
1333+
return Image.network(node.attributes['src']);
1334+
} else if (node.attributes['alt'] != null) {
1335+
//Temp fix for https://github.com/flutter/flutter/issues/736
1336+
if (node.attributes['alt'].endsWith(" ")) {
1337+
return Container(
1338+
padding: EdgeInsets.only(right: 2.0),
1339+
child: Text(node.attributes['alt']));
1340+
} else {
1341+
return Text(node.attributes['alt']);
1342+
}
1343+
}
1344+
return Container();
1345+
},
1346+
);
13121347
case "ins":
13131348
return DefaultTextStyle.merge(
13141349
child: Wrap(

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: flutter_html
22
description: A Flutter widget for rendering static html tags as Flutter widgets. (Will render over 70 different html tags!)
3-
version: 0.9.6
3+
version: 0.9.7
44
author: Matthew Whitaker <sub6resources@gmail.com>
55
homepage: https://github.com/Sub6Resources/flutter_html
66

0 commit comments

Comments
 (0)