Enable sending messages with pills

This commit is contained in:
aringenbach
2022-05-02 13:35:35 +02:00
parent 968c2e34c5
commit 8d65cd8a40
17 changed files with 555 additions and 175 deletions
@@ -0,0 +1,131 @@
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
extension RoomDataSource {
func sendAttributedTextMessage(_ attributedText: NSAttributedString,
completion: @escaping (MXResponse<String?>) -> Void) {
var localEcho: MXEvent?
// TODO: emote
let sanitized = sanitizedAttributedMessageText(attributedText)
let rawText: String
let html: String? = htmlMessageFromSanitizedAttributedText(sanitized)
if #available(iOS 15.0, *) {
rawText = StringPillsUtils.stringByReplacingPills(in: sanitized)
} else {
rawText = sanitized.string
}
room.sendTextMessage(rawText,
formattedText: html,
threadId: self.threadId,
localEcho: &localEcho,
completion: completion)
if localEcho != nil {
self.queueEvent(forProcessing: localEcho, with: self.roomState, direction: .forwards)
self.processQueuedEvents(nil)
}
}
func sendReply(to eventToReply: MXEvent,
withAttributedTextMessage attributedText: NSAttributedString,
completion: @escaping (MXResponse<String?>) -> Void) {
var localEcho: MXEvent?
let sanitized = sanitizedAttributedMessageText(attributedText)
let rawText: String
let html: String? = htmlMessageFromSanitizedAttributedText(sanitized)
if #available(iOS 15.0, *) {
rawText = StringPillsUtils.stringByReplacingPills(in: sanitized)
} else {
rawText = sanitized.string
}
let stringLocalizer: MXSendReplyEventStringLocalizerProtocol = MXKSendReplyEventStringLocalizer()
room.sendReply(to: eventToReply,
textMessage: rawText,
formattedTextMessage: html,
stringLocalizer: stringLocalizer,
threadId: self.threadId,
localEcho: &localEcho,
completion: completion)
if localEcho != nil {
self.queueEvent(forProcessing: localEcho, with: self.roomState, direction: .forwards)
self.processQueuedEvents(nil)
}
}
func replaceAttributedTextMessage(for event: MXEvent,
withAttributedTextMessage attributedText: NSAttributedString,
success: @escaping ((String?) -> Void),
failure: @escaping ((Error?) -> Void)) {
let sanitized = sanitizedAttributedMessageText(attributedText)
let rawText: String
let html: String? = htmlMessageFromSanitizedAttributedText(sanitized)
if #available(iOS 15.0, *) {
rawText = StringPillsUtils.stringByReplacingPills(in: sanitized)
} else {
rawText = sanitized.string
}
let eventBody = event.content[kMXMessageBodyKey] as? String
let eventFormattedBody = event.content["formatted_body"] as? String
if rawText != eventBody && (eventFormattedBody == nil || html != eventFormattedBody) {
self.mxSession.aggregations.replaceTextMessageEvent(
event,
withTextMessage: rawText,
formattedText: html,
localEcho: { localEcho in
// Apply the local echo to the timeline
self.updateEvent(withReplace: localEcho)
// Integrate the replace local event into the timeline like when sending a message
// This also allows to manage read receipt on this replace event
self.queueEvent(forProcessing: localEcho, with: self.roomState, direction: .forwards)
self.processQueuedEvents(nil)
},
success: success,
failure: failure)
} else {
failure(nil)
}
}
func sanitizedAttributedMessageText(_ attributedString: NSAttributedString) -> NSAttributedString {
let newAttr = NSMutableAttributedString(attributedString: attributedString)
newAttr.mutableString.replaceOccurrences(of: String(format: "%C", 0x00000000), with: "", range: .init(location: 0, length: newAttr.length))
return newAttr
}
func htmlMessageFromSanitizedAttributedText(_ sanitizedText: NSAttributedString) -> String? {
let rawText: String
if #available(iOS 15.0, *) {
rawText = StringPillsUtils.stringByReplacingPills(in: sanitizedText, asMarkdown: true)
} else {
rawText = sanitizedText.string
}
let html = eventFormatter.htmlString(fromMarkdownString: rawText)
return html == sanitizedText.string ? nil : html
}
}