feat: Check markdown checkboxes in messages
This commit is contained in:
parent
7cc341ac91
commit
a2e5a940bd
5 changed files with 109 additions and 10 deletions
|
|
@ -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<Event>? 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<dom.Element>().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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
27
lib/utils/event_checkbox_extension.dart
Normal file
27
lib/utils/event_checkbox_extension.dart
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import 'package:matrix/matrix.dart';
|
||||
|
||||
extension EventCheckboxRoomExtension on Room {
|
||||
static const String relationshipType = 'im.fluffychat.checkboxes';
|
||||
Future<String?> 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<String, Object?>('m.relates_to')
|
||||
?.tryGet<int>('checkbox_id');
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Loading…
Add table
Reference in a new issue