mirror of
https://github.com/krille-chan/fluffychat
synced 2024-09-10 05:05:10 +00:00
fix: Some links not clickable in messages
This commit is contained in:
parent
6a75d07dea
commit
6b53d27c4c
3 changed files with 111 additions and 96 deletions
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -872,7 +872,7 @@ packages:
|
|||
source: hosted
|
||||
version: "1.1.0"
|
||||
html:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: html
|
||||
sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue