Files
Qlyra/lib/frontend/widgets/link_text.dart
T

73 lines
1.9 KiB
Dart

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import '../../core/utils/link_opener.dart';
final RegExp linkPattern = RegExp(
r'((?:https?|komet|max)://[^\s<>]+'
r'|www\.[^\s<>]+'
r'|(?<![\w.@/-])max\.ru(?![\w.-])(?:/[^\s<>]*)?)',
caseSensitive: false,
);
String linkTarget(String raw) => raw.contains('://') ? raw : 'https://$raw';
class LinkText extends StatefulWidget {
final String text;
final TextStyle style;
const LinkText({super.key, required this.text, required this.style});
static bool hasLinks(String? text) =>
text != null && linkPattern.hasMatch(text);
@override
State<LinkText> createState() => _LinkTextState();
}
class _LinkTextState extends State<LinkText> {
final List<TapGestureRecognizer> _recognizers = [];
@override
void dispose() {
for (final r in _recognizers) {
r.dispose();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
for (final r in _recognizers) {
r.dispose();
}
_recognizers.clear();
final spans = <InlineSpan>[];
var cursor = 0;
for (final match in linkPattern.allMatches(widget.text)) {
if (match.start > cursor) {
spans.add(TextSpan(text: widget.text.substring(cursor, match.start)));
}
final url = match.group(0)!;
final target = linkTarget(url);
final recognizer = TapGestureRecognizer()
..onTap = () => openExternalUrl(context, target);
_recognizers.add(recognizer);
spans.add(
TextSpan(
text: url,
style: const TextStyle(decoration: TextDecoration.underline),
recognizer: recognizer,
),
);
cursor = match.end;
}
if (cursor < widget.text.length) {
spans.add(TextSpan(text: widget.text.substring(cursor)));
}
return Text.rich(TextSpan(style: widget.style, children: spans));
}
}