diff --git a/lib/src/room.dart b/lib/src/room.dart index ce1403d2..830aaca7 100644 --- a/lib/src/room.dart +++ b/lib/src/room.dart @@ -17,6 +17,7 @@ */ import 'dart:async'; +import 'dart:convert'; import 'package:html_unescape/html_unescape.dart'; import 'package:matrix_file_e2ee/matrix_file_e2ee.dart'; @@ -583,7 +584,8 @@ class Room { if (parseMarkdown) { final html = markdown(event['body'], emotePacks ?? this.emotePacks); // if the decoded html is the same as the body, there is no need in sending a formatted message - if (HtmlUnescape().convert(html) != event['body']) { + if (HtmlUnescape().convert(html.replaceAll(RegExp(r'
\n?'), '\n')) != + event['body']) { event['format'] = 'org.matrix.custom.html'; event['formatted_body'] = html; } @@ -754,9 +756,22 @@ class Room { } replyText = replyTextLines.join('\n'); content['format'] = 'org.matrix.custom.html'; + // be sure that we strip any previous reply fallbacks + final replyHtml = (inReplyTo.formattedText.isNotEmpty + ? inReplyTo.formattedText + : htmlEscape.convert(inReplyTo.body).replaceAll('\n', '
')) + .replaceAll( + RegExp(r'.*<\/mx-reply>', + caseSensitive: false, multiLine: false, dotAll: true), + ''); + final repliedHtml = content.tryGet( + 'formatted_body', + htmlEscape + .convert(content.tryGet('body', '')) + .replaceAll('\n', '
')); content['formatted_body'] = - '
In reply to ${inReplyTo.senderId}
${inReplyTo.body}
${content["formatted_body"] ?? content["body"]}'; - content['body'] = replyText + "\n\n${content["body"] ?? ""}"; + '
In reply to ${inReplyTo.senderId}
$replyHtml
$repliedHtml'; + content['body'] = replyText + "\n\n${content.tryGet('body', '')}"; content['m.relates_to'] = { 'm.in_reply_to': { 'event_id': inReplyTo.eventId, diff --git a/test/room_test.dart b/test/room_test.dart index 191128f3..23c30dcf 100644 --- a/test/room_test.dart +++ b/test/room_test.dart @@ -420,12 +420,12 @@ void main() { 'sender': '@alice:example.org', }, room); FakeMatrixApi.calledEndpoints.clear(); - final dynamic resp = await room.sendTextEvent('Hello world', + var resp = await room.sendTextEvent('Hello world', txid: 'testtxid', inReplyTo: event); expect(resp.startsWith('\$event'), true); - final entry = FakeMatrixApi.calledEndpoints.entries + var entry = FakeMatrixApi.calledEndpoints.entries .firstWhere((p) => p.key.contains('/send/m.room.message/')); - final content = json.decode(entry.value.first); + var content = json.decode(entry.value.first); expect(content, { 'body': '> <@alice:example.org> Blah\n\nHello world', 'msgtype': 'm.text', @@ -438,6 +438,67 @@ void main() { }, }, }); + + event = Event.fromJson({ + 'event_id': '\$replyEvent', + 'content': { + 'body': 'Blah\nbeep', + 'msgtype': 'm.text', + }, + 'type': 'm.room.message', + 'sender': '@alice:example.org', + }, room); + FakeMatrixApi.calledEndpoints.clear(); + resp = await room.sendTextEvent('Hello world\nfox', + txid: 'testtxid', inReplyTo: event); + expect(resp.startsWith('\$event'), true); + entry = FakeMatrixApi.calledEndpoints.entries + .firstWhere((p) => p.key.contains('/send/m.room.message/')); + content = json.decode(entry.value.first); + expect(content, { + 'body': + '> <@alice:example.org> Blah\n> beep\n\nHello world\nfox', + 'msgtype': 'm.text', + 'format': 'org.matrix.custom.html', + 'formatted_body': + '
In reply to @alice:example.org
<b>Blah</b>
beep
Hello world
fox', + 'm.relates_to': { + 'm.in_reply_to': { + 'event_id': '\$replyEvent', + }, + }, + }); + + event = Event.fromJson({ + 'event_id': '\$replyEvent', + 'content': { + 'format': 'org.matrix.custom.html', + 'formatted_body': 'heyameow', + 'body': 'plaintext meow', + 'msgtype': 'm.text', + }, + 'type': 'm.room.message', + 'sender': '@alice:example.org', + }, room); + FakeMatrixApi.calledEndpoints.clear(); + resp = await room.sendTextEvent('Hello world', + txid: 'testtxid', inReplyTo: event); + expect(resp.startsWith('\$event'), true); + entry = FakeMatrixApi.calledEndpoints.entries + .firstWhere((p) => p.key.contains('/send/m.room.message/')); + content = json.decode(entry.value.first); + expect(content, { + 'body': '> <@alice:example.org> plaintext meow\n\nHello world', + 'msgtype': 'm.text', + 'format': 'org.matrix.custom.html', + 'formatted_body': + '
In reply to @alice:example.org
meow
Hello world', + 'm.relates_to': { + 'm.in_reply_to': { + 'event_id': '\$replyEvent', + }, + }, + }); }); test('send reaction', () async {