fix: Some links not clickable in messages

This commit is contained in:
Krille 2023-12-27 15:26:22 +01:00
parent 6a75d07dea
commit 6b53d27c4c
No known key found for this signature in database
GPG key ID: E067ECD60F1A0652
3 changed files with 111 additions and 96 deletions

View file

@ -6,6 +6,7 @@ import 'package:flutter_highlighter/themes/shades-of-purple.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_html_table/flutter_html_table.dart';
import 'package:flutter_math_fork/flutter_math.dart';
import 'package:html/dom.dart' as dom;
import 'package:linkify/linkify.dart';
import 'package:matrix/matrix.dart';
@ -26,6 +27,35 @@ class HtmlMessage extends StatelessWidget {
this.textColor = Colors.black,
});
dom.Node _linkifyHtml(dom.Node element) {
for (final node in element.nodes) {
if (node is! dom.Text) {
node.replaceWith(_linkifyHtml(node));
continue;
}
final parts = linkify(
node.text,
options: const LinkifyOptions(humanize: false),
);
if (!parts.any((part) => part is UrlElement)) {
continue;
}
final newHtml = parts
.map(
(linkifyElement) => linkifyElement is! UrlElement
? linkifyElement.text
: '<a href="${linkifyElement.text}">${linkifyElement.text}</a>',
)
.join(' ');
node.replaceWith(dom.Element.html(newHtml));
}
return element;
}
@override
Widget build(BuildContext context) {
// riot-web is notorious for creating bad reply fallback events from invalid messages which, if
@ -46,21 +76,6 @@ class HtmlMessage extends StatelessWidget {
final fontSize = AppConfig.messageFontSize * AppConfig.fontSizeFactor;
final linkifiedRenderHtml = linkify(
renderHtml,
options: const LinkifyOptions(humanize: false),
).map(
(element) {
if (element is! UrlElement ||
element.text.contains('<') ||
element.text.contains('>') ||
element.text.contains('"')) {
return element.text;
}
return '<a href="${element.url}">${element.text}</a>';
},
).join('');
final linkColor = textColor.withAlpha(150);
final blockquoteStyle = Style(
@ -73,87 +88,86 @@ class HtmlMessage extends StatelessWidget {
padding: HtmlPaddings.only(left: 6, bottom: 0),
);
final element = _linkifyHtml(HtmlParser.parseHTML(renderHtml));
// there is no need to pre-validate the html, as we validate it while rendering
return MouseRegion(
cursor: SystemMouseCursors.text,
child: Html(
data: linkifiedRenderHtml,
style: {
'*': Style(
color: textColor,
margin: Margins.all(0),
fontSize: FontSize(fontSize),
),
'a': Style(color: linkColor, textDecorationColor: linkColor),
'h1': Style(
fontSize: FontSize(fontSize * 2),
lineHeight: LineHeight.number(1.5),
fontWeight: FontWeight.w600,
),
'h2': Style(
fontSize: FontSize(fontSize * 1.75),
lineHeight: LineHeight.number(1.5),
fontWeight: FontWeight.w500,
),
'h3': Style(
fontSize: FontSize(fontSize * 1.5),
lineHeight: LineHeight.number(1.5),
),
'h4': Style(
fontSize: FontSize(fontSize * 1.25),
lineHeight: LineHeight.number(1.5),
),
'h5': Style(
fontSize: FontSize(fontSize * 1.25),
lineHeight: LineHeight.number(1.5),
),
'h6': Style(
fontSize: FontSize(fontSize),
lineHeight: LineHeight.number(1.5),
),
'blockquote': blockquoteStyle,
'tg-forward': blockquoteStyle,
'hr': Style(
border: Border.all(color: textColor, width: 0.5),
),
'table': Style(
border: Border.all(color: textColor, width: 0.5),
),
'tr': Style(
border: Border.all(color: textColor, width: 0.5),
),
'td': Style(
border: Border.all(color: textColor, width: 0.5),
padding: HtmlPaddings.all(2),
),
'th': Style(
border: Border.all(color: textColor, width: 0.5),
),
},
extensions: [
RoomPillExtension(context, room),
CodeExtension(fontSize: fontSize),
MatrixMathExtension(
style: TextStyle(fontSize: fontSize, color: textColor),
),
const TableHtmlExtension(),
SpoilerExtension(textColor: textColor),
const ImageExtension(),
FontColorExtension(),
],
onLinkTap: (url, _, element) => UrlLauncher(
context,
url,
element?.text,
).launchUrl(),
onlyRenderTheseTags: const {
...allowedHtmlTags,
// Needed to make it work properly
'body',
'html',
},
shrinkWrap: true,
),
return Html.fromElement(
documentElement: element as dom.Element,
style: {
'*': Style(
color: textColor,
margin: Margins.all(0),
fontSize: FontSize(fontSize),
),
'a': Style(color: linkColor, textDecorationColor: linkColor),
'h1': Style(
fontSize: FontSize(fontSize * 2),
lineHeight: LineHeight.number(1.5),
fontWeight: FontWeight.w600,
),
'h2': Style(
fontSize: FontSize(fontSize * 1.75),
lineHeight: LineHeight.number(1.5),
fontWeight: FontWeight.w500,
),
'h3': Style(
fontSize: FontSize(fontSize * 1.5),
lineHeight: LineHeight.number(1.5),
),
'h4': Style(
fontSize: FontSize(fontSize * 1.25),
lineHeight: LineHeight.number(1.5),
),
'h5': Style(
fontSize: FontSize(fontSize * 1.25),
lineHeight: LineHeight.number(1.5),
),
'h6': Style(
fontSize: FontSize(fontSize),
lineHeight: LineHeight.number(1.5),
),
'blockquote': blockquoteStyle,
'tg-forward': blockquoteStyle,
'hr': Style(
border: Border.all(color: textColor, width: 0.5),
),
'table': Style(
border: Border.all(color: textColor, width: 0.5),
),
'tr': Style(
border: Border.all(color: textColor, width: 0.5),
),
'td': Style(
border: Border.all(color: textColor, width: 0.5),
padding: HtmlPaddings.all(2),
),
'th': Style(
border: Border.all(color: textColor, width: 0.5),
),
},
extensions: [
RoomPillExtension(context, room),
CodeExtension(fontSize: fontSize),
MatrixMathExtension(
style: TextStyle(fontSize: fontSize, color: textColor),
),
const TableHtmlExtension(),
SpoilerExtension(textColor: textColor),
const ImageExtension(),
FontColorExtension(),
],
onLinkTap: (url, _, element) => UrlLauncher(
context,
url,
element?.text,
).launchUrl(),
onlyRenderTheseTags: const {
...allowedHtmlTags,
// Needed to make it work properly
'body',
'html',
},
shrinkWrap: true,
);
}

View file

@ -872,7 +872,7 @@ packages:
source: hosted
version: "1.1.0"
html:
dependency: transitive
dependency: "direct main"
description:
name: html
sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"

View file

@ -54,6 +54,7 @@ dependencies:
go_router: ^12.1.1
hive: ^2.2.3
hive_flutter: ^1.1.0
html: ^0.15.4
http: ^0.13.6
image_picker: ^1.0.0
intl: any