Skip to content

Commit 3d94841

Browse files
authored
Merge pull request #8 from PieterAelse/master
Added support for mailto: links.
2 parents c53da06 + 437bc30 commit 3d94841

File tree

5 files changed

+96
-31
lines changed

5 files changed

+96
-31
lines changed

example/lib/main.dart

+17-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_linkify/flutter_linkify.dart';
3+
import 'dart:async';
4+
35
import 'package:url_launcher/url_launcher.dart';
46

57
void main() => runApp(new LinkifyExample());
@@ -15,17 +17,25 @@ class LinkifyExample extends StatelessWidget {
1517
),
1618
body: Center(
1719
child: Linkify(
18-
onOpen: (url) async {
19-
if (await canLaunch(url)) {
20-
await launch(url);
21-
} else {
22-
throw 'Could not launch $url';
23-
}
20+
onLinkOpen: (url) {
21+
_launchLink(url);
22+
},
23+
onEmailOpen: (emailAddress) {
24+
final emailAddressLink = "mailto:$emailAddress";
25+
_launchLink(emailAddressLink);
2426
},
25-
text: "Made by https://cretezy.com",
27+
text: "Made by https://cretezy.com\n\nMail: example@gmail.com",
2628
),
2729
),
2830
),
2931
);
3032
}
33+
34+
Future _launchLink(String link) async {
35+
if (await canLaunch(link)) {
36+
await launch(link);
37+
} else {
38+
throw 'Could not launch $link';
39+
}
40+
}
3141
}

example/pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ environment:
99
dependencies:
1010
flutter:
1111
sdk: flutter
12-
url_launcher: ^3.0.3
12+
url_launcher: ^5.0.1
1313
flutter_linkify:
1414
path: ..
1515

lib/flutter_linkify.dart

+31-8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import 'package:flutter_linkify/linkify.dart';
55
/// Callback with URL to open
66
typedef LinkCallback(String url);
77

8+
/// Callback with Email address
9+
typedef EmailCallback(String emailAddress);
10+
811
/// Turns URLs into links
912
class Linkify extends StatelessWidget {
1013
/// Text to be linkified
@@ -17,8 +20,12 @@ class Linkify extends StatelessWidget {
1720
final TextStyle linkStyle;
1821

1922
/// Callback for tapping a link
20-
final LinkCallback onOpen;
23+
final LinkCallback onLinkOpen;
24+
25+
/// Callback for tapping an email
26+
final EmailCallback onEmailOpen;
2127

28+
/// Text direction of the text
2229
final TextDirection textDirection;
2330

2431
/// Removes http/https from shown URLS
@@ -29,7 +36,8 @@ class Linkify extends StatelessWidget {
2936
this.text,
3037
this.style,
3138
this.linkStyle,
32-
this.onOpen,
39+
this.onLinkOpen,
40+
this.onEmailOpen,
3341
this.textDirection,
3442
this.humanize = false,
3543
}) : super(key: key);
@@ -51,7 +59,8 @@ class Linkify extends StatelessWidget {
5159
decoration: TextDecoration.underline,
5260
)
5361
.merge(linkStyle),
54-
onOpen: onOpen,
62+
onLinkOpen: onLinkOpen,
63+
onEmailOpen: onEmailOpen,
5564
humanize: humanize,
5665
),
5766
);
@@ -63,12 +72,19 @@ TextSpan buildTextSpan({
6372
String text,
6473
TextStyle style,
6574
TextStyle linkStyle,
66-
LinkCallback onOpen,
75+
LinkCallback onLinkOpen,
76+
EmailCallback onEmailOpen,
6777
bool humanize = false,
6878
}) {
69-
void _onOpen(String url) {
70-
if (onOpen != null) {
71-
onOpen(url);
79+
void _onLinkOpen(String url) {
80+
if (onLinkOpen != null) {
81+
onLinkOpen(url);
82+
}
83+
}
84+
85+
void _onEmailOpen(String emailAddress) {
86+
if (onEmailOpen != null) {
87+
onEmailOpen(emailAddress); // TODO: discussable; add "mailto:" here for immediate use with url_launcher or expect developers to do it themselves
7288
}
7389
}
7490

@@ -90,7 +106,14 @@ TextSpan buildTextSpan({
90106
text: element.text,
91107
style: linkStyle,
92108
recognizer: TapGestureRecognizer()
93-
..onTap = () => _onOpen(element.url),
109+
..onTap = () => _onLinkOpen(element.url),
110+
);
111+
} else if (element is EmailElement) {
112+
return TextSpan(
113+
text: element.text,
114+
style: linkStyle,
115+
recognizer: TapGestureRecognizer()
116+
..onTap = () => _onEmailOpen(element.emailAddress),
94117
);
95118
}
96119
},

lib/linkify.dart

+45-13
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@ class LinkElement extends LinkifyElement {
1313
}
1414
}
1515

16+
/// Represents an element containing an email address
17+
class EmailElement extends LinkifyElement {
18+
final String emailAddress;
19+
final String text;
20+
21+
EmailElement(this.emailAddress, [String text]) : this.text = text ?? emailAddress;
22+
23+
@override
24+
String toString() {
25+
return "EmailElement: $emailAddress ($text)";
26+
}
27+
}
28+
1629
/// Represents an element containing text
1730
class TextElement extends LinkifyElement {
1831
final String text;
@@ -25,11 +38,16 @@ class TextElement extends LinkifyElement {
2538
}
2639
}
2740

28-
final _linkifyRegex = RegExp(
41+
final _linkifyUrlRegex = RegExp(
2942
r"(\n*?.*?\s*?)((?:https?):\/\/[^\s/$.?#].[^\s]*)",
3043
caseSensitive: false,
3144
);
3245

46+
final _linkifyEmailRegex = RegExp(
47+
r"(\n*?.*?\s*?)((mailto:)?[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4})",
48+
caseSensitive: false
49+
);
50+
3351
/// Turns [text] into a list of [LinkifyElement]
3452
///
3553
/// Use [humanize] to remove http/https from the start of the URL shown.
@@ -40,29 +58,43 @@ List<LinkifyElement> linkify(String text, {bool humanize = false}) {
4058
return list;
4159
}
4260

43-
final match = _linkifyRegex.firstMatch(text);
44-
if (match == null) {
61+
final urlMatch = _linkifyUrlRegex.firstMatch(text);
62+
final emailMatch = _linkifyEmailRegex.firstMatch(text);
63+
if (urlMatch == null && emailMatch == null) {
4564
list.add(TextElement(text));
46-
} else {
47-
text = text.replaceFirst(_linkifyRegex, "");
65+
} else if (urlMatch != null){
66+
text = text.replaceFirst(_linkifyUrlRegex, "");
4867

49-
if (match.group(1).isNotEmpty) {
50-
list.add(TextElement(match.group(1)));
68+
if (urlMatch.group(1).isNotEmpty) {
69+
list.add(TextElement(urlMatch.group(1)));
5170
}
5271

53-
if (match.group(2).isNotEmpty) {
72+
if (urlMatch.group(2).isNotEmpty) {
5473
if (humanize ?? false) {
55-
print("humanizing ${match.group(2)}");
5674
list.add(LinkElement(
57-
match.group(2),
58-
match.group(2).replaceFirst(RegExp(r"https?://"), ""),
75+
urlMatch.group(2),
76+
urlMatch.group(2).replaceFirst(RegExp(r"https?://"), ""),
5977
));
6078
} else {
61-
print("not humanizing ${match.group(2)}");
62-
list.add(LinkElement(match.group(2)));
79+
list.add(LinkElement(urlMatch.group(2)));
6380
}
6481
}
6582

83+
list.addAll(linkify(text, humanize: humanize));
84+
} else if (emailMatch != null) {
85+
text = text.replaceFirst(_linkifyEmailRegex, "");
86+
87+
if (emailMatch.group(1).isNotEmpty) {
88+
list.add(TextElement(emailMatch.group(1)));
89+
}
90+
91+
if (emailMatch.group(2).isNotEmpty) {
92+
// Always humanize emails
93+
list.add(EmailElement(
94+
emailMatch.group(2).replaceFirst(RegExp(r"mailto:"), "")
95+
));
96+
}
97+
6698
list.addAll(linkify(text, humanize: humanize));
6799
}
68100

pubspec.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: flutter_linkify
2-
description: Turns text URLs into clickable inline links in text for Flutter.
3-
version: 1.1.1
2+
description: Turns text URLs and Mailto links into clickable inline links in text for Flutter.
3+
version: 1.2.0
44
author: Charles Crete <charles@cretezy.com>
55
homepage: https://github.com/Cretezy/flutter_linkify
66

0 commit comments

Comments
 (0)