dev
dart 65 lines 1.86 KB
Raw
1 import 'package:flutter/gestures.dart';
2 import 'package:flutter/material.dart';
3 import 'package:url_launcher/url_launcher.dart';
4
5 class ClickableLinksText extends StatelessWidget {
6 const ClickableLinksText({
7 required this.text,
8 required this.textStyle,
9 this.linkStyle,
10 });
11
12 final String text;
13 final TextStyle textStyle;
14 final TextStyle? linkStyle;
15
16 @override
17 Widget build(BuildContext context) {
18 List<InlineSpan> spans = [];
19 RegExp linkRegExp = RegExp(r'(https?://[^\s]+)');
20 Iterable<Match> matches = linkRegExp.allMatches(text);
21
22 int previousEnd = 0;
23 matches.forEach((match) {
24 if (match.start > previousEnd) {
25 spans.add(TextSpan(text: text.substring(previousEnd, match.start), style: textStyle));
26 }
27 String url = text.substring(match.start, match.end);
28 if (url.toLowerCase().endsWith('.md')) {
29 spans.add(
30 TextSpan(
31 text: url,
32 style: Theme.of(context).textTheme.bodyMedium?.copyWith(
33 color: Theme.of(context).colorScheme.primary,
34 fontSize: 18,
35 ),
36 recognizer: TapGestureRecognizer()
37 ..onTap = () async {
38 if (await canLaunchUrl(Uri.parse(url))) {
39 await launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication);
40 }
41 },
42 ),
43 );
44 } else {
45 spans.add(
46 TextSpan(
47 text: url,
48 style: linkStyle,
49 recognizer: TapGestureRecognizer()
50 ..onTap = () {
51 launchUrl(Uri.parse(url));
52 },
53 ),
54 );
55 }
56 previousEnd = match.end;
57 });
58
59 if (previousEnd < text.length) {
60 spans.add(TextSpan(text: text.substring(previousEnd), style: textStyle));
61 }
62
63 return RichText(text: TextSpan(children: spans));
64 }
65 }