mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 21:39:12 +00:00
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:
parent
e6fa1bac2e
commit
68ec7bbc9e
@ -5801,7 +5801,7 @@
|
|||||||
repositoryURL = "https://github.com/matrix-org/matrix-rust-components-swift";
|
repositoryURL = "https://github.com/matrix-org/matrix-rust-components-swift";
|
||||||
requirement = {
|
requirement = {
|
||||||
kind = exactVersion;
|
kind = exactVersion;
|
||||||
version = 1.1.20;
|
version = 1.1.21;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
821C67C9A7F8CC3FD41B28B4 /* XCRemoteSwiftPackageReference "emojibase-bindings" */ = {
|
821C67C9A7F8CC3FD41B28B4 /* XCRemoteSwiftPackageReference "emojibase-bindings" */ = {
|
||||||
|
@ -129,8 +129,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/matrix-org/matrix-rust-components-swift",
|
"location" : "https://github.com/matrix-org/matrix-rust-components-swift",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "5f3a195f6a461b4d40a8a705a3af8235711f12f5",
|
"revision" : "22461632db17a6dc1193dcdcfa3231614649c517",
|
||||||
"version" : "1.1.20"
|
"version" : "1.1.21"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -615,10 +615,16 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
|||||||
} else {
|
} else {
|
||||||
text = messageTimelineItem.body
|
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:
|
default:
|
||||||
text = messageTimelineItem.body
|
text = messageTimelineItem.body
|
||||||
}
|
}
|
||||||
|
|
||||||
actionsSubject.send(.composer(action: .setText(text: text)))
|
actionsSubject.send(.composer(action: .setText(text: text)))
|
||||||
actionsSubject.send(.composer(action: .setMode(mode: .edit(originalItemId: messageTimelineItem.id))))
|
actionsSubject.send(.composer(action: .setMode(mode: .edit(originalItemId: messageTimelineItem.id))))
|
||||||
case .copyPermalink:
|
case .copyPermalink:
|
||||||
|
@ -252,19 +252,15 @@ class RoomProxy: RoomProxyProtocol {
|
|||||||
return .success(())
|
return .success(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendMessage(_ message: String, html: String?, inReplyTo eventID: String? = nil) async -> Result<Void, RoomProxyError> {
|
func sendMessage(_ message: String, html: String?, inReplyTo eventID: String? = nil) async -> Result<Void, RoomProxyError> {
|
||||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||||
defer {
|
defer {
|
||||||
sendMessageBackgroundTask?.stop()
|
sendMessageBackgroundTask?.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
let messageContent: RoomMessageEventContentWithoutRelation
|
let messageContent = buildMessageContentFor(message, html: html)
|
||||||
if let html {
|
|
||||||
messageContent = messageEventContentFromHtml(body: message, htmlBody: html)
|
|
||||||
} else {
|
|
||||||
messageContent = messageEventContentFromMarkdown(md: message)
|
|
||||||
}
|
|
||||||
return await Task.dispatch(on: messageSendingDispatchQueue) {
|
return await Task.dispatch(on: messageSendingDispatchQueue) {
|
||||||
do {
|
do {
|
||||||
if let eventID {
|
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)
|
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||||
defer {
|
defer {
|
||||||
sendMessageBackgroundTask?.stop()
|
sendMessageBackgroundTask?.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
let newMessageContent: RoomMessageEventContentWithoutRelation
|
let messageContent = buildMessageContentFor(message, html: html)
|
||||||
if let html {
|
|
||||||
newMessageContent = messageEventContentFromHtml(body: newMessage, htmlBody: html)
|
|
||||||
} else {
|
|
||||||
newMessageContent = messageEventContentFromMarkdown(md: newMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
return await Task.dispatch(on: messageSendingDispatchQueue) {
|
return await Task.dispatch(on: messageSendingDispatchQueue) {
|
||||||
do {
|
do {
|
||||||
let originalEvent = try self.room.getEventTimelineItemByEventId(eventId: eventID)
|
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(())
|
return .success(())
|
||||||
} catch {
|
} catch {
|
||||||
return .failure(.failedEditingMessage)
|
return .failure(.failedEditingMessage)
|
||||||
@ -707,7 +698,37 @@ class RoomProxy: RoomProxyProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Private
|
// 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
|
/// 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
|
/// This should become automatic on the RustSDK side at some point
|
||||||
private func fetchMembers() async {
|
private func fetchMembers() async {
|
||||||
|
@ -19,4 +19,6 @@ import UIKit
|
|||||||
struct EmoteRoomTimelineItemContent: Hashable {
|
struct EmoteRoomTimelineItemContent: Hashable {
|
||||||
let body: String
|
let body: String
|
||||||
var formattedBody: AttributedString?
|
var formattedBody: AttributedString?
|
||||||
|
/// The original textual representation of the formatted body directly from the event (usually HTML code)
|
||||||
|
var formattedBodyHTMLString: String?
|
||||||
}
|
}
|
||||||
|
@ -558,7 +558,7 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
|||||||
formattedBody = attributedStringBuilder.fromPlain(L10n.commonEmote(name, messageContent.body))
|
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
|
// MARK: - State Events
|
||||||
|
1
changelog.d/1841.feature
Normal file
1
changelog.d/1841.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
Implement /me
|
@ -46,7 +46,7 @@ packages:
|
|||||||
# Element/Matrix dependencies
|
# Element/Matrix dependencies
|
||||||
MatrixRustSDK:
|
MatrixRustSDK:
|
||||||
url: https://github.com/matrix-org/matrix-rust-components-swift
|
url: https://github.com/matrix-org/matrix-rust-components-swift
|
||||||
exactVersion: 1.1.20
|
exactVersion: 1.1.21
|
||||||
# path: ../matrix-rust-sdk
|
# path: ../matrix-rust-sdk
|
||||||
DesignKit:
|
DesignKit:
|
||||||
path: DesignKit
|
path: DesignKit
|
||||||
|
Loading…
x
Reference in New Issue
Block a user