Fix the onTap callback for images (#24)
* Wrap linked images in a GestureDetector
* Add test
* Version bump and changelog
* Add test for image within a text link
* Add test for image links surrounded by different links
diff --git a/packages/flutter_markdown/CHANGELOG.md b/packages/flutter_markdown/CHANGELOG.md
index 0a3ba9f..955b872 100644
--- a/packages/flutter_markdown/CHANGELOG.md
+++ b/packages/flutter_markdown/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.1.2
+
+* Fix the `onTap` callback on images nested in hyperlinks
+
## 0.1.1
* Add support for local file paths in image links. Make sure to set the
diff --git a/packages/flutter_markdown/lib/src/builder.dart b/packages/flutter_markdown/lib/src/builder.dart
index 18bf8b7..42103d0 100644
--- a/packages/flutter_markdown/lib/src/builder.dart
+++ b/packages/flutter_markdown/lib/src/builder.dart
@@ -251,13 +251,21 @@
}
Uri uri = Uri.parse(path);
+ Widget child;
if (uri.scheme == 'http' || uri.scheme == 'https') {
- return new Image.network(uri.toString(), width: width, height: height);
+ child = new Image.network(uri.toString(), width: width, height: height);
} else {
String filePath = (imageDirectory == null
? uri.toFilePath()
: p.join(imageDirectory.path, uri.toFilePath()));
- return new Image.file(new File(filePath), width: width, height: height);
+ child = new Image.file(new File(filePath), width: width, height: height);
+ }
+
+ if (_linkHandlers.isNotEmpty) {
+ TapGestureRecognizer recognizer = _linkHandlers.last;
+ return new GestureDetector(child: child, onTap: recognizer.onTap);
+ } else {
+ return child;
}
}
diff --git a/packages/flutter_markdown/pubspec.yaml b/packages/flutter_markdown/pubspec.yaml
index 2df97d3..2a92df6 100644
--- a/packages/flutter_markdown/pubspec.yaml
+++ b/packages/flutter_markdown/pubspec.yaml
@@ -2,7 +2,7 @@
author: Flutter Authors <flutter-dev@googlegroups.com>
description: A markdown renderer for Flutter.
homepage: https://github.com/flutter/flutter_markdown
-version: 0.1.1
+version: 0.1.2
dependencies:
flutter:
diff --git a/packages/flutter_markdown/test/flutter_markdown_test.dart b/packages/flutter_markdown/test/flutter_markdown_test.dart
index b6ee532..7a6b3b6 100644
--- a/packages/flutter_markdown/test/flutter_markdown_test.dart
+++ b/packages/flutter_markdown/test/flutter_markdown_test.dart
@@ -228,6 +228,88 @@
expect(textSpan.text, 'Hello ');
expect(textSpan.style, isNotNull);
});
+
+ testWidgets('should work when nested in a link', (WidgetTester tester) async {
+ final List<String> tapResults = <String>[];
+ await tester.pumpWidget(_boilerplate(new Markdown(
+ data: '[](href)',
+ onTapLink: (value) => tapResults.add(value),
+ )));
+
+ final GestureDetector detector =
+ tester.allWidgets.firstWhere((Widget widget) => widget is GestureDetector);
+
+ detector.onTap();
+
+ expect(tapResults.length, 1);
+ expect(tapResults, everyElement('href'));
+ });
+
+ testWidgets('should work when nested in a link with text', (WidgetTester tester) async {
+ final List<String> tapResults = <String>[];
+ await tester.pumpWidget(_boilerplate(new Markdown(
+ data: '[Text before  text after](href)',
+ onTapLink: (value) => tapResults.add(value),
+ )));
+
+ final GestureDetector detector =
+ tester.allWidgets.firstWhere((Widget widget) => widget is GestureDetector);
+ detector.onTap();
+
+ final RichText firstTextWidget =
+ tester.allWidgets.firstWhere((Widget widget) => widget is RichText);
+ final TextSpan firstSpan = firstTextWidget.text;
+ (firstSpan.recognizer as TapGestureRecognizer).onTap();
+
+ final RichText lastTextWidget =
+ tester.allWidgets.lastWhere((Widget widget) => widget is RichText);
+ final TextSpan lastSpan = lastTextWidget.text;
+ (lastSpan.recognizer as TapGestureRecognizer).onTap();
+
+ expect(firstSpan.children, null);
+ expect(firstSpan.text, 'Text before ');
+ expect(firstSpan.recognizer.runtimeType, equals(TapGestureRecognizer));
+
+ expect(lastSpan.children, null);
+ expect(lastSpan.text, ' text after');
+ expect(lastSpan.recognizer.runtimeType, equals(TapGestureRecognizer));
+
+ expect(tapResults.length, 3);
+ expect(tapResults, everyElement('href'));
+ });
+
+ testWidgets('should work alongside different links', (WidgetTester tester) async {
+ final List<String> tapResults = <String>[];
+ await tester.pumpWidget(_boilerplate(new Markdown(
+ data: '[Link before](firstHref)[](imageHref)[link after](secondHref)',
+ onTapLink: (value) => tapResults.add(value),
+ )));
+
+ final RichText firstTextWidget =
+ tester.allWidgets.firstWhere((Widget widget) => widget is RichText);
+ final TextSpan firstSpan = firstTextWidget.text;
+ (firstSpan.recognizer as TapGestureRecognizer).onTap();
+
+ final GestureDetector detector =
+ tester.allWidgets.firstWhere((Widget widget) => widget is GestureDetector);
+ detector.onTap();
+
+ final RichText lastTextWidget =
+ tester.allWidgets.lastWhere((Widget widget) => widget is RichText);
+ final TextSpan lastSpan = lastTextWidget.text;
+ (lastSpan.recognizer as TapGestureRecognizer).onTap();
+
+ expect(firstSpan.children, null);
+ expect(firstSpan.text, 'Link before');
+ expect(firstSpan.recognizer.runtimeType, equals(TapGestureRecognizer));
+
+ expect(lastSpan.children, null);
+ expect(lastSpan.text, 'link after');
+ expect(lastSpan.recognizer.runtimeType, equals(TapGestureRecognizer));
+
+ expect(tapResults.length, 3);
+ expect(tapResults, ['firstHref', 'imageHref', 'secondHref']);
+ });
});
testWidgets('HTML tag ignored ', (WidgetTester tester) async {