From 3404cffada7e82b55328bcdafa57a237db34ec5e Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Tue, 11 Feb 2020 11:06:54 +0000 Subject: [PATCH] =?UTF-8?q?[Event]=C2=A0Add=20support=20for=20replies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/event.dart | 18 ++++++++++++++++++ lib/src/room.dart | 43 ++++++++++++++++++++++++++++++++----------- test/event_test.dart | 3 ++- 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/lib/src/event.dart b/lib/src/event.dart index 06518894..26ceb3c2 100644 --- a/lib/src/event.dart +++ b/lib/src/event.dart @@ -23,6 +23,7 @@ import 'dart:convert'; import 'package:famedlysdk/famedlysdk.dart'; +import 'package:famedlysdk/src/utils/matrix_id_string_extension.dart'; import 'package:famedlysdk/src/utils/receipt.dart'; import './room.dart'; @@ -366,6 +367,23 @@ class Event { /// Redacts this event. Returns [ErrorResponse] on error. Future redact({String reason, String txid}) => room.redactEvent(eventId, reason: reason, txid: txid); + + /// Whether this event is in reply to another event. + bool get isReply => + content['m.relates_to'] is Map && + content['m.relates_to']['m.in_reply_to'] is Map && + content['m.relates_to']['m.in_reply_to']['event_id'] is String && + (content['m.relates_to']['m.in_reply_to']['event_id'] as String) + .isValidMatrixId && + (content['m.relates_to']['m.in_reply_to']['event_id'] as String).sigil == + "\$"; + + /// Searches for the reply event in the given timeline. + Future getReplyEvent(Timeline timeline) async { + if (!isReply) return null; + final String replyEventId = content['m.relates_to']['m.in_reply_to']; + return await timeline.getEventById(replyEventId); + } } enum MessageTypes { diff --git a/lib/src/room.dart b/lib/src/room.dart index ed6f6aeb..041a53ca 100644 --- a/lib/src/room.dart +++ b/lib/src/room.dart @@ -290,13 +290,15 @@ class Room { return res["event_id"]; } - Future sendTextEvent(String message, {String txid}) => - sendEvent({"msgtype": "m.text", "body": message}, txid: txid); + Future sendTextEvent(String message, + {String txid, Event inReplyTo}) => + sendEvent({"msgtype": "m.text", "body": message}, + txid: txid, inReplyTo: inReplyTo); /// Sends a [file] to this room after uploading it. The [msgType] is optional /// and will be detected by the mimetype of the file. Future sendFileEvent(MatrixFile file, - {String msgType = "m.file", String txid}) async { + {String msgType = "m.file", String txid, Event inReplyTo}) async { if (msgType == "m.image") return sendImageEvent(file); if (msgType == "m.audio") return sendVideoEvent(file); if (msgType == "m.video") return sendAudioEvent(file); @@ -315,11 +317,11 @@ class Room { "size": file.size, } }; - return await sendEvent(content, txid: txid); + return await sendEvent(content, txid: txid, inReplyTo: inReplyTo); } Future sendAudioEvent(MatrixFile file, - {String txid, int width, int height}) async { + {String txid, int width, int height, Event inReplyTo}) async { String fileName = file.path.split("/").last; final String uploadResp = await client.upload(file); Map content = { @@ -332,11 +334,11 @@ class Room { "size": file.size, } }; - return await sendEvent(content, txid: txid); + return await sendEvent(content, txid: txid, inReplyTo: inReplyTo); } Future sendImageEvent(MatrixFile file, - {String txid, int width, int height}) async { + {String txid, int width, int height, Event inReplyTo}) async { String fileName = file.path.split("/").last; final String uploadResp = await client.upload(file); Map content = { @@ -350,7 +352,7 @@ class Room { "h": height, }, }; - return await sendEvent(content, txid: txid); + return await sendEvent(content, txid: txid, inReplyTo: inReplyTo); } Future sendVideoEvent(MatrixFile file, @@ -360,7 +362,8 @@ class Room { int duration, MatrixFile thumbnail, int thumbnailWidth, - int thumbnailHeight}) async { + int thumbnailHeight, + Event inReplyTo}) async { String fileName = file.path.split("/").last; final String uploadResp = await client.upload(file); Map content = { @@ -396,10 +399,11 @@ class Room { content["info"]["thumbnail_info"]["h"] = thumbnailHeight; } } - return await sendEvent(content, txid: txid); + return await sendEvent(content, txid: txid, inReplyTo: inReplyTo); } - Future sendEvent(Map content, {String txid}) async { + Future sendEvent(Map content, + {String txid, Event inReplyTo}) async { final String type = "m.room.message"; // Create new transaction id @@ -411,6 +415,23 @@ class Room { messageID = txid; } + if (inReplyTo != null) { + String replyText = "<${inReplyTo.senderId}> " + inReplyTo.body; + List replyTextLines = replyText.split("\n"); + for (int i = 0; i < replyTextLines.length; i++) { + replyTextLines[i] = "> " + replyTextLines[i]; + } + replyText = replyTextLines.join("\n"); + content["format"] = "org.matrix.custom.html"; + content["formatted_body"] = '
In reply to ${inReplyTo.senderId}
${inReplyTo.body}
${content["formatted_body"] ?? content["body"]}'; + content["body"] = replyText + "\n\n${content["body"] ?? ""}"; + content["m.relates_to"] = { + "m.in_reply_to": { + "event_id": inReplyTo.eventId, + }, + }; + } + // Display a *sending* event and store it. EventUpdate eventUpdate = EventUpdate(type: "timeline", roomID: id, eventType: type, content: { diff --git a/test/event_test.dart b/test/event_test.dart index 82846710..6886e877 100644 --- a/test/event_test.dart +++ b/test/event_test.dart @@ -41,7 +41,7 @@ void main() { final String formatted_body = "Hello World"; final String contentJson = - '{"msgtype":"$msgtype","body":"$body","formatted_body":"$formatted_body"}'; + '{"msgtype":"$msgtype","body":"$body","formatted_body":"$formatted_body","m.relates_to":{"m.in_reply_to":{"event_id":"\$1234:example.com"}}}'; Map jsonObj = { "event_id": id, @@ -67,6 +67,7 @@ void main() { expect(event.formattedText, formatted_body); expect(event.body, body); expect(event.type, EventTypes.Message); + expect(event.isReply, true); jsonObj["state_key"] = ""; Event state = Event.fromJson(jsonObj, null); expect(state.eventId, id);