Implement emotes (/me) (#1841)

* implement emotes (/me)

requires matthew/emotes branch of matrix-rust-sdk

* changelog + whitespace

* remove apparently superfluous swiftlint

* fix constness

* remove inout params and incorporate review

* switch to new api based on sdk PR feedback

* Bump the RustSDK to v1.1.21

* Address PR comments

---------

Co-authored-by: Stefan Ceriu <stefan.ceriu@gmail.com>
This commit is contained in:
Matthew Hodgson 2023-10-03 14:17:03 +01:00 committed by GitHub
parent e6fa1bac2e
commit 68ec7bbc9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 52 additions and 22 deletions

View File

@ -5801,7 +5801,7 @@
repositoryURL = "https://github.com/matrix-org/matrix-rust-components-swift";
requirement = {
kind = exactVersion;
version = 1.1.20;
version = 1.1.21;
};
};
821C67C9A7F8CC3FD41B28B4 /* XCRemoteSwiftPackageReference "emojibase-bindings" */ = {

View File

@ -129,8 +129,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/matrix-org/matrix-rust-components-swift",
"state" : {
"revision" : "5f3a195f6a461b4d40a8a705a3af8235711f12f5",
"version" : "1.1.20"
"revision" : "22461632db17a6dc1193dcdcfa3231614649c517",
"version" : "1.1.21"
}
},
{

View File

@ -615,6 +615,12 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
} else {
text = messageTimelineItem.body
}
case .emote(let emoteItem):
if ServiceLocator.shared.settings.richTextEditorEnabled, let formattedBodyHTMLString = emoteItem.formattedBodyHTMLString {
text = "/me " + formattedBodyHTMLString
} else {
text = "/me " + messageTimelineItem.body
}
default:
text = messageTimelineItem.body
}

View File

@ -259,12 +259,8 @@ class RoomProxy: RoomProxyProtocol {
sendMessageBackgroundTask?.stop()
}
let messageContent: RoomMessageEventContentWithoutRelation
if let html {
messageContent = messageEventContentFromHtml(body: message, htmlBody: html)
} else {
messageContent = messageEventContentFromMarkdown(md: message)
}
let messageContent = buildMessageContentFor(message, html: html)
return await Task.dispatch(on: messageSendingDispatchQueue) {
do {
if let eventID {
@ -435,23 +431,18 @@ class RoomProxy: RoomProxyProtocol {
}
}
func editMessage(_ newMessage: String, html: String?, original eventID: String) async -> Result<Void, RoomProxyError> {
func editMessage(_ message: String, html: String?, original eventID: String) async -> Result<Void, RoomProxyError> {
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
defer {
sendMessageBackgroundTask?.stop()
}
let newMessageContent: RoomMessageEventContentWithoutRelation
if let html {
newMessageContent = messageEventContentFromHtml(body: newMessage, htmlBody: html)
} else {
newMessageContent = messageEventContentFromMarkdown(md: newMessage)
}
let messageContent = buildMessageContentFor(message, html: html)
return await Task.dispatch(on: messageSendingDispatchQueue) {
do {
let originalEvent = try self.room.getEventTimelineItemByEventId(eventId: eventID)
try self.room.edit(newContent: newMessageContent, editItem: originalEvent)
try self.room.edit(newContent: messageContent, editItem: originalEvent)
return .success(())
} catch {
return .failure(.failedEditingMessage)
@ -708,6 +699,36 @@ class RoomProxy: RoomProxyProtocol {
// MARK: - Private
private func buildMessageContentFor(_ message: String, html: String?) -> RoomMessageEventContentWithoutRelation {
let emoteSlashCommand = "/me "
let isEmote: Bool = message.starts(with: emoteSlashCommand)
guard isEmote else {
if let html {
return messageEventContentFromHtml(body: message, htmlBody: html)
} else {
return messageEventContentFromMarkdown(md: message)
}
}
let emoteMessage = String(message.dropFirst(emoteSlashCommand.count))
var emoteHtml: String?
if let html {
emoteHtml = String(html.dropFirst(emoteSlashCommand.count))
}
return buildEmoteMessageContentFor(emoteMessage, html: emoteHtml)
}
private func buildEmoteMessageContentFor(_ message: String, html: String?) -> RoomMessageEventContentWithoutRelation {
if let html {
return messageEventContentFromHtmlAsEmote(body: message, htmlBody: html)
} else {
return messageEventContentFromMarkdownAsEmote(md: message)
}
}
/// Force the timeline to load member details so it can populate sender profiles whenever we add a timeline listener
/// This should become automatic on the RustSDK side at some point
private func fetchMembers() async {

View File

@ -19,4 +19,6 @@ import UIKit
struct EmoteRoomTimelineItemContent: Hashable {
let body: String
var formattedBody: AttributedString?
/// The original textual representation of the formatted body directly from the event (usually HTML code)
var formattedBodyHTMLString: String?
}

View File

@ -558,7 +558,7 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
formattedBody = attributedStringBuilder.fromPlain(L10n.commonEmote(name, messageContent.body))
}
return .init(body: messageContent.body, formattedBody: formattedBody)
return .init(body: messageContent.body, formattedBody: formattedBody, formattedBodyHTMLString: htmlBody)
}
// MARK: - State Events

1
changelog.d/1841.feature Normal file
View File

@ -0,0 +1 @@
Implement /me

View File

@ -46,7 +46,7 @@ packages:
# Element/Matrix dependencies
MatrixRustSDK:
url: https://github.com/matrix-org/matrix-rust-components-swift
exactVersion: 1.1.20
exactVersion: 1.1.21
# path: ../matrix-rust-sdk
DesignKit:
path: DesignKit