Fix editing items not in the timeline failing (#3075)

This commit is contained in:
Mauro 2024-07-22 13:15:57 +02:00 committed by GitHub
parent ab49274015
commit ff33c07596
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 307 additions and 72 deletions

View File

@ -7471,7 +7471,7 @@
repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift";
requirement = {
kind = exactVersion;
version = 1.0.26;
version = 1.0.27;
};
};
701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = {

View File

@ -149,8 +149,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/element-hq/matrix-rust-components-swift",
"state" : {
"revision" : "29a19a07df68a5fe97431d08c944ced27e791ae3",
"version" : "1.0.26"
"revision" : "3a1f56a8dc2b14c93e562ece82fbf780d2f79704",
"version" : "1.0.27"
}
},
{

View File

@ -9297,6 +9297,76 @@ class RoomProxyMock: RoomProxyProtocol {
return markAsReadReceiptTypeReturnValue
}
}
//MARK: - edit
var editEventIDNewContentUnderlyingCallsCount = 0
var editEventIDNewContentCallsCount: Int {
get {
if Thread.isMainThread {
return editEventIDNewContentUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = editEventIDNewContentUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
editEventIDNewContentUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
editEventIDNewContentUnderlyingCallsCount = newValue
}
}
}
}
var editEventIDNewContentCalled: Bool {
return editEventIDNewContentCallsCount > 0
}
var editEventIDNewContentReceivedArguments: (eventID: String, newContent: RoomMessageEventContentWithoutRelation)?
var editEventIDNewContentReceivedInvocations: [(eventID: String, newContent: RoomMessageEventContentWithoutRelation)] = []
var editEventIDNewContentUnderlyingReturnValue: Result<Void, RoomProxyError>!
var editEventIDNewContentReturnValue: Result<Void, RoomProxyError>! {
get {
if Thread.isMainThread {
return editEventIDNewContentUnderlyingReturnValue
} else {
var returnValue: Result<Void, RoomProxyError>? = nil
DispatchQueue.main.sync {
returnValue = editEventIDNewContentUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
editEventIDNewContentUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
editEventIDNewContentUnderlyingReturnValue = newValue
}
}
}
}
var editEventIDNewContentClosure: ((String, RoomMessageEventContentWithoutRelation) async -> Result<Void, RoomProxyError>)?
func edit(eventID: String, newContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, RoomProxyError> {
editEventIDNewContentCallsCount += 1
editEventIDNewContentReceivedArguments = (eventID: eventID, newContent: newContent)
DispatchQueue.main.async {
self.editEventIDNewContentReceivedInvocations.append((eventID: eventID, newContent: newContent))
}
if let editEventIDNewContentClosure = editEventIDNewContentClosure {
return await editEventIDNewContentClosure(eventID, newContent)
} else {
return editEventIDNewContentReturnValue
}
}
//MARK: - sendTypingNotification
var sendTypingNotificationIsTypingUnderlyingCallsCount = 0
@ -12319,15 +12389,15 @@ class TimelineProxyMock: TimelineProxyProtocol {
}
//MARK: - edit
var editMessageHtmlIntentionalMentionsUnderlyingCallsCount = 0
var editMessageHtmlIntentionalMentionsCallsCount: Int {
var editNewContentUnderlyingCallsCount = 0
var editNewContentCallsCount: Int {
get {
if Thread.isMainThread {
return editMessageHtmlIntentionalMentionsUnderlyingCallsCount
return editNewContentUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = editMessageHtmlIntentionalMentionsUnderlyingCallsCount
returnValue = editNewContentUnderlyingCallsCount
}
return returnValue!
@ -12335,29 +12405,29 @@ class TimelineProxyMock: TimelineProxyProtocol {
}
set {
if Thread.isMainThread {
editMessageHtmlIntentionalMentionsUnderlyingCallsCount = newValue
editNewContentUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
editMessageHtmlIntentionalMentionsUnderlyingCallsCount = newValue
editNewContentUnderlyingCallsCount = newValue
}
}
}
}
var editMessageHtmlIntentionalMentionsCalled: Bool {
return editMessageHtmlIntentionalMentionsCallsCount > 0
var editNewContentCalled: Bool {
return editNewContentCallsCount > 0
}
var editMessageHtmlIntentionalMentionsReceivedArguments: (timelineItemID: TimelineItemIdentifier, message: String, html: String?, intentionalMentions: IntentionalMentions)?
var editMessageHtmlIntentionalMentionsReceivedInvocations: [(timelineItemID: TimelineItemIdentifier, message: String, html: String?, intentionalMentions: IntentionalMentions)] = []
var editNewContentReceivedArguments: (timelineItem: EventTimelineItem, newContent: RoomMessageEventContentWithoutRelation)?
var editNewContentReceivedInvocations: [(timelineItem: EventTimelineItem, newContent: RoomMessageEventContentWithoutRelation)] = []
var editMessageHtmlIntentionalMentionsUnderlyingReturnValue: Result<Void, TimelineProxyError>!
var editMessageHtmlIntentionalMentionsReturnValue: Result<Void, TimelineProxyError>! {
var editNewContentUnderlyingReturnValue: Result<Void, TimelineProxyError>!
var editNewContentReturnValue: Result<Void, TimelineProxyError>! {
get {
if Thread.isMainThread {
return editMessageHtmlIntentionalMentionsUnderlyingReturnValue
return editNewContentUnderlyingReturnValue
} else {
var returnValue: Result<Void, TimelineProxyError>? = nil
DispatchQueue.main.sync {
returnValue = editMessageHtmlIntentionalMentionsUnderlyingReturnValue
returnValue = editNewContentUnderlyingReturnValue
}
return returnValue!
@ -12365,26 +12435,26 @@ class TimelineProxyMock: TimelineProxyProtocol {
}
set {
if Thread.isMainThread {
editMessageHtmlIntentionalMentionsUnderlyingReturnValue = newValue
editNewContentUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
editMessageHtmlIntentionalMentionsUnderlyingReturnValue = newValue
editNewContentUnderlyingReturnValue = newValue
}
}
}
}
var editMessageHtmlIntentionalMentionsClosure: ((TimelineItemIdentifier, String, String?, IntentionalMentions) async -> Result<Void, TimelineProxyError>)?
var editNewContentClosure: ((EventTimelineItem, RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError>)?
func edit(_ timelineItemID: TimelineItemIdentifier, message: String, html: String?, intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError> {
editMessageHtmlIntentionalMentionsCallsCount += 1
editMessageHtmlIntentionalMentionsReceivedArguments = (timelineItemID: timelineItemID, message: message, html: html, intentionalMentions: intentionalMentions)
func edit(_ timelineItem: EventTimelineItem, newContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError> {
editNewContentCallsCount += 1
editNewContentReceivedArguments = (timelineItem: timelineItem, newContent: newContent)
DispatchQueue.main.async {
self.editMessageHtmlIntentionalMentionsReceivedInvocations.append((timelineItemID: timelineItemID, message: message, html: html, intentionalMentions: intentionalMentions))
self.editNewContentReceivedInvocations.append((timelineItem: timelineItem, newContent: newContent))
}
if let editMessageHtmlIntentionalMentionsClosure = editMessageHtmlIntentionalMentionsClosure {
return await editMessageHtmlIntentionalMentionsClosure(timelineItemID, message, html, intentionalMentions)
if let editNewContentClosure = editNewContentClosure {
return await editNewContentClosure(timelineItem, newContent)
} else {
return editMessageHtmlIntentionalMentionsReturnValue
return editNewContentReturnValue
}
}
//MARK: - redact
@ -13477,6 +13547,76 @@ class TimelineProxyMock: TimelineProxyProtocol {
return getLoadedReplyDetailsEventIDReturnValue
}
}
//MARK: - buildMessageContentFor
var buildMessageContentForHtmlIntentionalMentionsUnderlyingCallsCount = 0
var buildMessageContentForHtmlIntentionalMentionsCallsCount: Int {
get {
if Thread.isMainThread {
return buildMessageContentForHtmlIntentionalMentionsUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = buildMessageContentForHtmlIntentionalMentionsUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
buildMessageContentForHtmlIntentionalMentionsUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
buildMessageContentForHtmlIntentionalMentionsUnderlyingCallsCount = newValue
}
}
}
}
var buildMessageContentForHtmlIntentionalMentionsCalled: Bool {
return buildMessageContentForHtmlIntentionalMentionsCallsCount > 0
}
var buildMessageContentForHtmlIntentionalMentionsReceivedArguments: (message: String, html: String?, intentionalMentions: Mentions)?
var buildMessageContentForHtmlIntentionalMentionsReceivedInvocations: [(message: String, html: String?, intentionalMentions: Mentions)] = []
var buildMessageContentForHtmlIntentionalMentionsUnderlyingReturnValue: RoomMessageEventContentWithoutRelation!
var buildMessageContentForHtmlIntentionalMentionsReturnValue: RoomMessageEventContentWithoutRelation! {
get {
if Thread.isMainThread {
return buildMessageContentForHtmlIntentionalMentionsUnderlyingReturnValue
} else {
var returnValue: RoomMessageEventContentWithoutRelation? = nil
DispatchQueue.main.sync {
returnValue = buildMessageContentForHtmlIntentionalMentionsUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
buildMessageContentForHtmlIntentionalMentionsUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
buildMessageContentForHtmlIntentionalMentionsUnderlyingReturnValue = newValue
}
}
}
}
var buildMessageContentForHtmlIntentionalMentionsClosure: ((String, String?, Mentions) -> RoomMessageEventContentWithoutRelation)?
func buildMessageContentFor(_ message: String, html: String?, intentionalMentions: Mentions) -> RoomMessageEventContentWithoutRelation {
buildMessageContentForHtmlIntentionalMentionsCallsCount += 1
buildMessageContentForHtmlIntentionalMentionsReceivedArguments = (message: message, html: html, intentionalMentions: intentionalMentions)
DispatchQueue.main.async {
self.buildMessageContentForHtmlIntentionalMentionsReceivedInvocations.append((message: message, html: html, intentionalMentions: intentionalMentions))
}
if let buildMessageContentForHtmlIntentionalMentionsClosure = buildMessageContentForHtmlIntentionalMentionsClosure {
return buildMessageContentForHtmlIntentionalMentionsClosure(message, html, intentionalMentions)
} else {
return buildMessageContentForHtmlIntentionalMentionsReturnValue
}
}
}
class UserDiscoveryServiceMock: UserDiscoveryServiceProtocol {

View File

@ -9565,6 +9565,82 @@ open class NotificationSettingsSDKMock: MatrixRustSDK.NotificationSettings {
try await unmuteRoomRoomIdIsEncryptedIsOneToOneClosure?(roomId, isEncrypted, isOneToOne)
}
}
open class OidcAuthorizationDataSDKMock: MatrixRustSDK.OidcAuthorizationData {
init() {
super.init(noPointer: .init())
}
public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) {
fatalError("init(unsafeFromRawPointer:) has not been implemented")
}
fileprivate var pointer: UnsafeMutableRawPointer!
//MARK: - loginUrl
var loginUrlUnderlyingCallsCount = 0
open var loginUrlCallsCount: Int {
get {
if Thread.isMainThread {
return loginUrlUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = loginUrlUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
loginUrlUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
loginUrlUnderlyingCallsCount = newValue
}
}
}
}
open var loginUrlCalled: Bool {
return loginUrlCallsCount > 0
}
var loginUrlUnderlyingReturnValue: String!
open var loginUrlReturnValue: String! {
get {
if Thread.isMainThread {
return loginUrlUnderlyingReturnValue
} else {
var returnValue: String? = nil
DispatchQueue.main.sync {
returnValue = loginUrlUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
loginUrlUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
loginUrlUnderlyingReturnValue = newValue
}
}
}
}
open var loginUrlClosure: (() -> String)?
open override func loginUrl() -> String {
loginUrlCallsCount += 1
if let loginUrlClosure = loginUrlClosure {
return loginUrlClosure()
} else {
return loginUrlReturnValue
}
}
}
open class QrCodeDataSDKMock: MatrixRustSDK.QrCodeData {
init() {
super.init(noPointer: .init())

View File

@ -336,6 +336,16 @@ class RoomProxy: RoomProxyProtocol {
}
}
func edit(eventID: String, newContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, RoomProxyError> {
do {
try await room.edit(eventId: eventID, newContent: newContent)
return .success(())
} catch {
MXLog.error("Failed editing event id \(eventID), in room \(id) with error: \(error)")
return .failure(.sdkError(error))
}
}
func sendTypingNotification(isTyping: Bool) async -> Result<Void, RoomProxyError> {
MXLog.info("Sending typing notification isTyping: \(isTyping)")

View File

@ -96,6 +96,8 @@ protocol RoomProxyProtocol {
func markAsRead(receiptType: ReceiptType) async -> Result<Void, RoomProxyError>
func edit(eventID: String, newContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, RoomProxyError>
/// https://spec.matrix.org/v1.9/client-server-api/#typing-notifications
@discardableResult func sendTypingNotification(isTyping: Bool) async -> Result<Void, RoomProxyError>

View File

@ -191,15 +191,38 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
html: String?,
intentionalMentions: IntentionalMentions) async {
MXLog.info("Edit message in \(roomID)")
MXLog.info("Editing timeline item: \(timelineItemID)")
switch await activeTimeline.edit(timelineItemID,
message: message,
html: html,
intentionalMentions: intentionalMentions) {
case .success:
MXLog.info("Finished editing message")
case .failure(let error):
MXLog.error("Failed editing message with error: \(error)")
let editMode: EditMode
if !timelineItemID.timelineID.isEmpty,
let timelineItem = liveTimelineProvider.itemProxies.firstEventTimelineItemUsingStableID(timelineItemID) {
editMode = .byEvent(timelineItem)
} else if let eventID = timelineItemID.eventID {
editMode = .byID(eventID)
} else {
MXLog.error("Unknown timeline item: \(timelineItemID)")
return
}
let messageContent = activeTimeline.buildMessageContentFor(message,
html: html,
intentionalMentions: intentionalMentions.toRustMentions())
switch editMode {
case let .byEvent(item):
switch await activeTimeline.edit(item, newContent: messageContent) {
case .success:
MXLog.info("Finished editing message by event")
case let .failure(error):
MXLog.error("Failed editing message by event with error: \(error)")
}
case let .byID(eventID):
switch await roomProxy.edit(eventID: eventID, newContent: messageContent) {
case .success:
MXLog.info("Finished editing message by event ID")
case let .failure(error):
MXLog.error("Failed editing message by event ID with error: \(error)")
}
}
}
@ -408,3 +431,8 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
return nil
}
}
private enum EditMode {
case byEvent(EventTimelineItem)
case byID(String)
}

View File

@ -153,39 +153,17 @@ final class TimelineProxy: TimelineProxyProtocol {
}
}
func edit(_ timelineItemID: TimelineItemIdentifier,
message: String, html: String?,
intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError> {
MXLog.info("Editing timeline item: \(timelineItemID)")
let timelineItem: EventTimelineItem? = if !timelineItemID.timelineID.isEmpty,
let timelineItem = await timelineProvider.itemProxies.firstEventTimelineItemUsingStableID(timelineItemID) {
timelineItem
} else if let eventID = timelineItemID.eventID {
nil // We need to edit by event ID which was removed.
} else {
nil
}
guard let timelineItem else {
MXLog.error("Unknown timeline item: \(timelineItemID)")
return .failure(.failedEditing)
}
let messageContent = buildMessageContentFor(message,
html: html,
intentionalMentions: intentionalMentions.toRustMentions())
func edit(_ timelineItem: EventTimelineItem, newContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError> {
do {
guard try await timeline.edit(item: timelineItem, newContent: messageContent) == true else {
guard try await timeline.edit(item: timelineItem, newContent: newContent) == true else {
return .failure(.failedEditing)
}
MXLog.info("Finished editing timeline item: \(timelineItemID)")
MXLog.info("Finished editing timeline item: \(timelineItem.eventId() ?? timelineItem.transactionId() ?? "unknown")")
return .success(())
} catch {
MXLog.error("Failed editing timeline item: \(timelineItemID) with error: \(error)")
MXLog.error("Failed editing timeline item: \(timelineItem.eventId() ?? timelineItem.transactionId() ?? "unknown") with error: \(error)")
return .failure(.sdkError(error))
}
}
@ -505,12 +483,10 @@ final class TimelineProxy: TimelineProxyProtocol {
return .failure(.sdkError(error))
}
}
// MARK: - Private
private func buildMessageContentFor(_ message: String,
html: String?,
intentionalMentions: Mentions) -> RoomMessageEventContentWithoutRelation {
func buildMessageContentFor(_ message: String,
html: String?,
intentionalMentions: Mentions) -> RoomMessageEventContentWithoutRelation {
let emoteSlashCommand = "/me "
let isEmote: Bool = message.starts(with: emoteSlashCommand)
@ -533,6 +509,8 @@ final class TimelineProxy: TimelineProxyProtocol {
return content.withMentions(mentions: intentionalMentions)
}
// MARK: - Private
private func buildEmoteMessageContentFor(_ message: String, html: String?) -> RoomMessageEventContentWithoutRelation {
if let html {
return messageEventContentFromHtmlAsEmote(body: message, htmlBody: html)

View File

@ -41,10 +41,7 @@ protocol TimelineProxyProtocol {
func paginateBackwards(requestSize: UInt16) async -> Result<Void, TimelineProxyError>
func paginateForwards(requestSize: UInt16) async -> Result<Void, TimelineProxyError>
func edit(_ timelineItemID: TimelineItemIdentifier,
message: String,
html: String?,
intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError>
func edit(_ timelineItem: EventTimelineItem, newContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError>
func redact(_ timelineItemID: TimelineItemIdentifier,
reason: String?) async -> Result<Void, TimelineProxyError>
@ -109,6 +106,10 @@ protocol TimelineProxyProtocol {
func sendPollResponse(pollStartID: String, answers: [String]) async -> Result<Void, TimelineProxyError>
func getLoadedReplyDetails(eventID: String) async -> Result<InReplyToDetails, TimelineProxyError>
func buildMessageContentFor(_ message: String,
html: String?,
intentionalMentions: Mentions) -> RoomMessageEventContentWithoutRelation
}
extension TimelineProxyProtocol {

View File

@ -60,7 +60,7 @@ packages:
# Element/Matrix dependencies
MatrixRustSDK:
url: https://github.com/element-hq/matrix-rust-components-swift
exactVersion: 1.0.26
exactVersion: 1.0.27
# path: ../matrix-rust-sdk
Compound:
url: https://github.com/element-hq/compound-ios