diff --git a/ElementX/Sources/Screens/Timeline/TimelineModels.swift b/ElementX/Sources/Screens/Timeline/TimelineModels.swift index 19abe2233..805c24ded 100644 --- a/ElementX/Sources/Screens/Timeline/TimelineModels.swift +++ b/ElementX/Sources/Screens/Timeline/TimelineModels.swift @@ -222,7 +222,7 @@ struct ReadReceiptSummaryInfo: Identifiable { enum TimelineAlertInfoType: Hashable { case audioRecodingPermissionError case pollEndConfirmation(String) - case sendingFailed(reason: String?, sendHandle: SendHandleProxy) + case sendingFailed(reason: String?, sendHandle: SendHandleProxy?) case encryptionAuthenticity(String) case encryptionForwarder(String) case inviteAgain diff --git a/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift b/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift index 898068470..de6b4e9fd 100644 --- a/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift +++ b/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift @@ -739,12 +739,8 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol { } if case let .sendingFailed(.unknown(reason)) = eventTimelineItem.properties.deliveryStatus { - guard let sendHandle = timelineController.sendHandle(for: itemID) else { - MXLog.error("Cannot find send handle for \(itemID).") - return - } - - displayAlert(.sendingFailed(reason: reason, sendHandle: sendHandle)) + // A missing send handle only costs the retry/remove actions, the reason is still worth showing. + displayAlert(.sendingFailed(reason: reason, sendHandle: timelineController.sendHandle(for: itemID))) } else if case let .sendingFailed(.verifiedUser(failure)) = eventTimelineItem.properties.deliveryStatus { guard let sendHandle = timelineController.sendHandle(for: itemID) else { MXLog.error("Cannot find send handle for \(itemID).") @@ -1121,11 +1117,13 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol { state.bindings.alertInfo = .init(id: type, title: L10n.commonSendingFailed, message: reason, - primaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil), - verticalButtons: [.init(title: L10n.actionRetry) { [weak self] in self?.retrySending(sendHandle) }, - .init(title: L10n.actionRemoveMessage, role: .destructive) { [weak self] in - self?.timelineInteractionHandler.handleTimelineItemMenuAction(.redact(isMedia: false), itemID: sendHandle.itemID) - }]) + primaryButton: .init(title: sendHandle == nil ? L10n.actionOk : L10n.actionCancel, role: .cancel, action: nil), + verticalButtons: sendHandle.map { sendHandle in + [.init(title: L10n.actionRetry) { [weak self] in self?.retrySending(sendHandle) }, + .init(title: L10n.actionRemoveMessage, role: .destructive) { [weak self] in + self?.timelineInteractionHandler.handleTimelineItemMenuAction(.redact(isMedia: false), itemID: sendHandle.itemID) + }] + }) case .encryptionAuthenticity(let message): state.bindings.alertInfo = .init(id: type, title: message,