diff --git a/lib/pages/chat/events/html_message.dart b/lib/pages/chat/events/html_message.dart
index ae4997e40..ddb1a394f 100644
--- a/lib/pages/chat/events/html_message.dart
+++ b/lib/pages/chat/events/html_message.dart
@@ -2,13 +2,13 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
-import 'package:flutter_highlighter/flutter_highlighter.dart';
-import 'package:flutter_highlighter/themes/shades-of-purple.dart';
import 'package:flutter_linkify/flutter_linkify.dart';
+import 'package:highlight/highlight.dart' show highlight;
import 'package:html/dom.dart' as dom;
import 'package:html/parser.dart' as parser;
import 'package:matrix/matrix.dart';
+import 'package:fluffychat/utils/code_highlight_theme.dart';
import 'package:fluffychat/utils/event_checkbox_extension.dart';
import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
@@ -137,6 +137,19 @@ class HtmlMessage extends StatelessWidget {
];
}
+ InlineSpan _renderCodeBlockNode(dom.Node node) {
+ if (node is! dom.Element) {
+ return TextSpan(text: node.text);
+ }
+ final style = atomOneDarkTheme[node.className.split('-').last] ??
+ atomOneDarkTheme['root'];
+
+ return TextSpan(
+ children: node.nodes.map(_renderCodeBlockNode).toList(),
+ style: style,
+ );
+ }
+
/// Transforms a Node to an InlineSpan.
InlineSpan _renderHtml(
dom.Node node,
@@ -334,33 +347,60 @@ class HtmlMessage extends StatelessWidget {
);
case 'code':
final isInline = node.parent?.localName != 'pre';
+ final lang = node.className
+ .split(' ')
+ .singleWhereOrNull(
+ (className) => className.startsWith('language-'),
+ )
+ ?.split('language-')
+ .last ??
+ 'md';
+ final highlightedHtml =
+ highlight.parse(node.text, language: lang).toHtml();
+ final element = parser.parse(highlightedHtml).body;
+ if (element == null) {
+ return const TextSpan(text: 'Unable to render code block!');
+ }
+ final controller = isInline ? null : ScrollController();
+
return WidgetSpan(
child: Material(
- clipBehavior: Clip.hardEdge,
- borderRadius: BorderRadius.circular(4),
- child: SingleChildScrollView(
- scrollDirection: Axis.horizontal,
- child: HighlightView(
- node.text,
- language: node.className
- .split(' ')
- .singleWhereOrNull(
- (className) => className.startsWith('language-'),
- )
- ?.split('language-')
- .last ??
- 'md',
- theme: shadesOfPurpleTheme,
- padding: EdgeInsets.symmetric(
- horizontal: 8,
- vertical: isInline ? 0 : 8,
- ),
- textStyle: TextStyle(
- fontSize: fontSize,
- fontFamily: 'RobotoMono',
- ),
- ),
+ color: atomOneBackgroundColor,
+ shape: RoundedRectangleBorder(
+ side: const BorderSide(color: hightlightTextColor),
+ borderRadius: BorderRadius.circular(4),
),
+ child: isInline
+ ? Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 4.0),
+ child: Text.rich(
+ TextSpan(
+ children: [_renderCodeBlockNode(element)],
+ ),
+ selectionColor: hightlightTextColor.withAlpha(128),
+ ),
+ )
+ : RawScrollbar(
+ thumbVisibility: true,
+ trackVisibility: true,
+ controller: controller,
+ thumbColor: hightlightTextColor,
+ trackColor: hightlightTextColor.withAlpha(128),
+ thickness: 8,
+ child: SingleChildScrollView(
+ controller: controller,
+ scrollDirection: Axis.horizontal,
+ child: Padding(
+ padding: const EdgeInsets.all(4.0),
+ child: Text.rich(
+ TextSpan(
+ children: [_renderCodeBlockNode(element)],
+ ),
+ selectionColor: hightlightTextColor.withAlpha(212),
+ ),
+ ),
+ ),
+ ),
),
);
case 'img':
diff --git a/lib/utils/code_highlight_theme.dart b/lib/utils/code_highlight_theme.dart
new file mode 100644
index 000000000..ac3a19144
--- /dev/null
+++ b/lib/utils/code_highlight_theme.dart
@@ -0,0 +1,40 @@
+import 'package:flutter/widgets.dart';
+
+const hightlightTextColor = Color(0xffabb2bf);
+const atomOneBackgroundColor = Color(0xff282c34);
+const atomOneDarkTheme = {
+ 'root': TextStyle(color: hightlightTextColor),
+ 'comment': TextStyle(color: Color(0xff5c6370), fontStyle: FontStyle.italic),
+ 'quote': TextStyle(color: Color(0xff5c6370), fontStyle: FontStyle.italic),
+ 'doctag': TextStyle(color: Color(0xffc678dd)),
+ 'keyword': TextStyle(color: Color(0xffc678dd)),
+ 'formula': TextStyle(color: Color(0xffc678dd)),
+ 'section': TextStyle(color: Color(0xffe06c75)),
+ 'name': TextStyle(color: Color(0xffe06c75)),
+ 'selector-tag': TextStyle(color: Color(0xffe06c75)),
+ 'deletion': TextStyle(color: Color(0xffe06c75)),
+ 'subst': TextStyle(color: Color(0xffe06c75)),
+ 'literal': TextStyle(color: Color(0xff56b6c2)),
+ 'string': TextStyle(color: Color(0xff98c379)),
+ 'regexp': TextStyle(color: Color(0xff98c379)),
+ 'addition': TextStyle(color: Color(0xff98c379)),
+ 'attribute': TextStyle(color: Color(0xff98c379)),
+ 'meta-string': TextStyle(color: Color(0xff98c379)),
+ 'built_in': TextStyle(color: Color(0xffe6c07b)),
+ 'attr': TextStyle(color: Color(0xffd19a66)),
+ 'variable': TextStyle(color: Color(0xffd19a66)),
+ 'template-variable': TextStyle(color: Color(0xffd19a66)),
+ 'type': TextStyle(color: Color(0xffd19a66)),
+ 'selector-class': TextStyle(color: Color(0xffd19a66)),
+ 'selector-attr': TextStyle(color: Color(0xffd19a66)),
+ 'selector-pseudo': TextStyle(color: Color(0xffd19a66)),
+ 'number': TextStyle(color: Color(0xffd19a66)),
+ 'symbol': TextStyle(color: Color(0xff61aeee)),
+ 'bullet': TextStyle(color: Color(0xff61aeee)),
+ 'link': TextStyle(color: Color(0xff61aeee)),
+ 'meta': TextStyle(color: Color(0xff61aeee)),
+ 'selector-id': TextStyle(color: Color(0xff61aeee)),
+ 'title': TextStyle(color: Color(0xff61aeee)),
+ 'emphasis': TextStyle(fontStyle: FontStyle.italic),
+ 'strong': TextStyle(fontWeight: FontWeight.bold),
+};
diff --git a/lib/utils/error_reporter.dart b/lib/utils/error_reporter.dart
index 9f3e7e86f..5e90afcb5 100644
--- a/lib/utils/error_reporter.dart
+++ b/lib/utils/error_reporter.dart
@@ -1,8 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
-import 'package:flutter_highlighter/flutter_highlighter.dart';
-import 'package:flutter_highlighter/themes/shades-of-purple.dart';
import 'package:matrix/matrix.dart';
import 'package:url_launcher/url_launcher.dart';
@@ -40,10 +38,12 @@ class ErrorReporter {
height: 256,
width: 256,
child: SingleChildScrollView(
- child: HighlightView(
+ child: Text(
text,
- language: 'sh',
- theme: shadesOfPurpleTheme,
+ style: const TextStyle(
+ fontSize: 14,
+ fontFamily: 'RobotoMono',
+ ),
),
),
),
diff --git a/pubspec.lock b/pubspec.lock
index 5ff83a837..965667782 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -483,14 +483,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "9.1.0"
- flutter_highlighter:
- dependency: "direct main"
- description:
- name: flutter_highlighter
- sha256: "93173afd47a9ada53f3176371755e7ea4a1065362763976d06d6adfb4d946e10"
- url: "https://pub.dev"
- source: hosted
- version: "0.1.1"
flutter_linkify:
dependency: "direct main"
description:
@@ -799,14 +791,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.4.0"
- highlighter:
- dependency: transitive
+ highlight:
+ dependency: "direct main"
description:
- name: highlighter
- sha256: "92180c72b9da8758e1acf39a45aa305a97dcfe2fdc8f3d1d2947c23f2772bfbc"
+ name: highlight
+ sha256: "5353a83ffe3e3eca7df0abfb72dcf3fa66cc56b953728e7113ad4ad88497cf21"
url: "https://pub.dev"
source: hosted
- version: "0.1.1"
+ version: "0.7.0"
html:
dependency: "direct main"
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index cc38297df..e133ad76e 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -30,7 +30,6 @@ dependencies:
flutter:
sdk: flutter
flutter_foreground_task: ^9.1.0
- flutter_highlighter: ^0.1.1
flutter_linkify: ^6.0.0
flutter_local_notifications: ^19.5.0
flutter_localizations:
@@ -45,6 +44,7 @@ dependencies:
geolocator: ^14.0.2
go_router: ^17.0.0
handy_window: ^0.4.0
+ highlight: ^0.7.0
html: ^0.15.4
http: ^1.6.0
image: ^4.1.7