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: '[![alt](https://img#50x50)](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 ![alt](https://img#50x50) 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)[![alt](https://img#50x50)](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 {