diff --git a/lib/pages/chat/events/html_message.dart b/lib/pages/chat/events/html_message.dart
index 7aca3154b..5e57b128c 100644
--- a/lib/pages/chat/events/html_message.dart
+++ b/lib/pages/chat/events/html_message.dart
@@ -8,7 +8,9 @@ import 'package:html/dom.dart' as dom;
import 'package:html/parser.dart' as parser;
import 'package:matrix/matrix.dart';
+import 'package:fluffychat/utils/event_checkbox_extension.dart';
import 'package:fluffychat/widgets/avatar.dart';
+import 'package:fluffychat/widgets/future_loading_dialog.dart';
import 'package:fluffychat/widgets/mxc_image.dart';
import '../../../utils/url_launcher.dart';
@@ -19,6 +21,8 @@ class HtmlMessage extends StatelessWidget {
final double fontSize;
final TextStyle linkStyle;
final void Function(LinkableElement) onOpen;
+ final String? eventId;
+ final Set? checkboxCheckedEvents;
const HtmlMessage({
super.key,
@@ -28,6 +32,8 @@ class HtmlMessage extends StatelessWidget {
required this.linkStyle,
this.textColor = Colors.black,
required this.onOpen,
+ this.eventId,
+ this.checkboxCheckedEvents,
});
/// Keep in sync with: https://spec.matrix.org/latest/client-server-api/#mroommessage-msgtypes
@@ -218,6 +224,24 @@ class HtmlMessage extends StatelessWidget {
if (!{'ol', 'ul'}.contains(node.parent?.localName)) {
continue block;
}
+ final eventId = this.eventId;
+
+ final isCheckbox = node.className == 'task-list-item';
+ final checkboxIndex = isCheckbox
+ ? node.rootElement
+ .getElementsByClassName('task-list-item')
+ .indexOf(node) +
+ 1
+ : null;
+ final checkedByReaction = !isCheckbox
+ ? null
+ : checkboxCheckedEvents?.firstWhereOrNull(
+ (event) => event.checkedCheckboxId == checkboxIndex,
+ );
+ final staticallyChecked = !isCheckbox
+ ? false
+ : node.children.first.attributes['checked'] == 'true';
+
return WidgetSpan(
child: Padding(
padding: EdgeInsets.only(left: fontSize),
@@ -231,6 +255,42 @@ class HtmlMessage extends StatelessWidget {
text:
'${(node.parent?.nodes.whereType().toList().indexOf(node) ?? 0) + (int.tryParse(node.parent?.attributes['start'] ?? '1') ?? 1)}. ',
),
+ if (node.className == 'task-list-item')
+ WidgetSpan(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 8.0),
+ child: SizedBox.square(
+ dimension: fontSize,
+ child: Checkbox.adaptive(
+ checkColor: textColor,
+ side: BorderSide(color: textColor),
+ activeColor: textColor.withAlpha(64),
+ visualDensity: VisualDensity.compact,
+ value:
+ staticallyChecked || checkedByReaction != null,
+ onChanged: eventId == null ||
+ checkboxIndex == null ||
+ staticallyChecked ||
+ !room.canSendDefaultMessages ||
+ (checkedByReaction != null &&
+ checkedByReaction.senderId !=
+ room.client.userID)
+ ? null
+ : (_) => showFutureLoadingDialog(
+ context: context,
+ future: () => checkedByReaction != null
+ ? room.redactEvent(
+ checkedByReaction.eventId,
+ )
+ : room.checkCheckbox(
+ eventId,
+ checkboxIndex,
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
..._renderWithLineBreaks(
node.nodes,
context,
@@ -446,11 +506,9 @@ class HtmlMessage extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final element = parser.parse(html).body ?? dom.Element.html('');
return Text.rich(
- _renderHtml(
- parser.parse(html).body ?? dom.Element.html(''),
- context,
- ),
+ _renderHtml(element, context),
style: TextStyle(
fontSize: fontSize,
color: textColor,
@@ -516,3 +574,7 @@ extension on String {
return colorValue == null ? null : Color(colorValue);
}
}
+
+extension on dom.Element {
+ dom.Element get rootElement => parent?.rootElement ?? this;
+}
diff --git a/lib/pages/chat/events/message_content.dart b/lib/pages/chat/events/message_content.dart
index 116aaf4ef..8c72cae3b 100644
--- a/lib/pages/chat/events/message_content.dart
+++ b/lib/pages/chat/events/message_content.dart
@@ -13,6 +13,7 @@ import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/matrix.dart';
import '../../../config/app_config.dart';
+import '../../../utils/event_checkbox_extension.dart';
import '../../../utils/platform_infos.dart';
import '../../../utils/url_launcher.dart';
import '../../bootstrap/bootstrap_dialog.dart';
@@ -204,6 +205,11 @@ class MessageContent extends StatelessWidget {
decorationColor: linkColor,
),
onOpen: (url) => UrlLauncher(context, url.url).launchUrl(),
+ eventId: event.eventId,
+ checkboxCheckedEvents: event.aggregatedEvents(
+ timeline,
+ EventCheckboxRoomExtension.relationshipType,
+ ),
),
);
}
diff --git a/lib/utils/event_checkbox_extension.dart b/lib/utils/event_checkbox_extension.dart
new file mode 100644
index 000000000..cf3832ba6
--- /dev/null
+++ b/lib/utils/event_checkbox_extension.dart
@@ -0,0 +1,27 @@
+import 'package:matrix/matrix.dart';
+
+extension EventCheckboxRoomExtension on Room {
+ static const String relationshipType = 'im.fluffychat.checkboxes';
+ Future checkCheckbox(
+ String eventId,
+ int checkboxId, {
+ String? txid,
+ }) =>
+ sendEvent(
+ {
+ 'm.relates_to': {
+ 'rel_type': relationshipType,
+ 'event_id': eventId,
+ 'checkbox_id': checkboxId,
+ },
+ },
+ type: EventTypes.Reaction,
+ txid: txid,
+ );
+}
+
+extension EventCheckboxExtension on Event {
+ int? get checkedCheckboxId => content
+ .tryGetMap('m.relates_to')
+ ?.tryGet('checkbox_id');
+}
diff --git a/pubspec.lock b/pubspec.lock
index f1c892e49..084b31477 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -1150,10 +1150,11 @@ packages:
matrix:
dependency: "direct main"
description:
- name: matrix
- sha256: "7d15fdbc760be7e40c58bb65e03baa8241b1e31db2bc67dab61883aabc083a85"
- url: "https://pub.dev"
- source: hosted
+ path: "."
+ ref: "krille/add-markdown-checkboxes"
+ resolved-ref: f3bb654ac2cda19bdd8a35fb46846018acd01a89
+ url: "https://github.com/famedly/matrix-dart-sdk.git"
+ source: git
version: "0.40.0"
meta:
dependency: transitive
diff --git a/pubspec.yaml b/pubspec.yaml
index a3fc68d61..61efd69b9 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -61,7 +61,10 @@ dependencies:
just_audio: ^0.9.39
latlong2: ^0.9.1
linkify: ^5.0.0
- matrix: ^0.40.0
+ matrix:
+ git:
+ url: https://github.com/famedly/matrix-dart-sdk.git
+ ref: krille/add-markdown-checkboxes
mime: ^1.0.6
native_imaging: ^0.2.0
opus_caf_converter_dart: ^1.0.1
@@ -140,4 +143,4 @@ dependency_overrides:
url: https://github.com/ThexXTURBOXx/flutter_web_auth_2.git
ref: 3.x-without-v1
path: flutter_web_auth_2
- win32: 5.5.3
+ win32: 5.5.3
\ No newline at end of file