parseLinks method

TextSpan parseLinks(
  1. List<TapGestureRecognizer> recognizers, [
  2. TextStyle? style
])

Returns TextSpans containing plain text along with links and e-mails detected and parsed.

recognizers are TapGestureRecognizers constructed, so ensure to dispose them properly.

Implementation

TextSpan parseLinks(
  List<TapGestureRecognizer> recognizers, [
  TextStyle? style,
]) {
  final Iterable<RegExpMatch> matches = _regex.allMatches(this);
  if (matches.isEmpty) {
    return TextSpan(text: this);
  }

  String text = this;
  final List<TextSpan> spans = [];
  final List<String> links = [];

  for (RegExpMatch match in matches) {
    links.add(text.substring(match.start, match.end));
  }

  for (int i = 0; i < links.length; i++) {
    final String link = links[i];

    final int index = text.indexOf(link);
    final List<String> parts = [
      text.substring(0, index),
      text.substring(index + link.length),
    ];

    if (parts[0].isNotEmpty) {
      spans.add(TextSpan(text: parts[0]));
    }

    final TapGestureRecognizer recognizer = TapGestureRecognizer();
    recognizers.add(recognizer);

    spans.add(
      TextSpan(
        text: link,
        style: style,
        recognizer: recognizer
          ..onTap = () async {
            final Uri uri;

            if (link.isEmail) {
              uri = Uri(scheme: 'mailto', path: link);
            } else {
              uri = Uri.parse(
                !link.startsWith('http') ? 'https://$link' : link,
              );

              final String url = uri.toString();
              final List<String> origins = [Config.origin, Config.link];

              for (var e in origins) {
                if (url.startsWith(e)) {
                  router.push(url.replaceFirst(e, ''));
                  return;
                }
              }
            }

            if (await canLaunchUrl(uri)) {
              await launchUrl(uri);
            }
          },
      ),
    );

    if (parts[1].isNotEmpty) {
      if (i == links.length - 1) {
        spans.add(TextSpan(text: parts[1]));
      } else {
        text = parts[1];
      }
    }
  }

  return TextSpan(children: spans);
}