mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-10-31 08:15:24 +00:00
Adopt the new send queue interfaces
This commit is contained in:
@@ -12506,6 +12506,110 @@ nonisolated class TimelineControllerMock: TimelineControllerProtocol, @unchecked
|
||||
return sendHandleForReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - pendingSendTarget
|
||||
|
||||
private let pendingSendTargetForCallsCountLock = NSLock()
|
||||
private nonisolated(unsafe) var pendingSendTargetForUnderlyingCallsCount = 0
|
||||
var pendingSendTargetForCallsCount: Int {
|
||||
get { pendingSendTargetForCallsCountLock.withLock { pendingSendTargetForUnderlyingCallsCount } }
|
||||
set { pendingSendTargetForCallsCountLock.withLock { pendingSendTargetForUnderlyingCallsCount = newValue } }
|
||||
}
|
||||
var pendingSendTargetForCalled: Bool {
|
||||
return pendingSendTargetForCallsCount > 0
|
||||
}
|
||||
private let pendingSendTargetForReceivedItemIDLock = NSLock()
|
||||
private nonisolated(unsafe) var pendingSendTargetForUnderlyingReceivedItemID: TimelineItemIdentifier?
|
||||
var pendingSendTargetForReceivedItemID: TimelineItemIdentifier? {
|
||||
get { pendingSendTargetForReceivedItemIDLock.withLock { pendingSendTargetForUnderlyingReceivedItemID } }
|
||||
set { pendingSendTargetForReceivedItemIDLock.withLock { pendingSendTargetForUnderlyingReceivedItemID = newValue } }
|
||||
}
|
||||
private let pendingSendTargetForReceivedInvocationsLock = NSLock()
|
||||
private nonisolated(unsafe) var pendingSendTargetForUnderlyingReceivedInvocations: [TimelineItemIdentifier] = []
|
||||
var pendingSendTargetForReceivedInvocations: [TimelineItemIdentifier] {
|
||||
get { pendingSendTargetForReceivedInvocationsLock.withLock { pendingSendTargetForUnderlyingReceivedInvocations } }
|
||||
set { pendingSendTargetForReceivedInvocationsLock.withLock { pendingSendTargetForUnderlyingReceivedInvocations = newValue } }
|
||||
}
|
||||
|
||||
private let pendingSendTargetForReturnValueLock = NSLock()
|
||||
private nonisolated(unsafe) var pendingSendTargetForUnderlyingReturnValue: SendTarget?
|
||||
var pendingSendTargetForReturnValue: SendTarget? {
|
||||
get { pendingSendTargetForReturnValueLock.withLock { pendingSendTargetForUnderlyingReturnValue } }
|
||||
set { pendingSendTargetForReturnValueLock.withLock { pendingSendTargetForUnderlyingReturnValue = newValue } }
|
||||
}
|
||||
nonisolated(unsafe) var pendingSendTargetForClosure: ((TimelineItemIdentifier) -> SendTarget?)?
|
||||
|
||||
func pendingSendTarget(for itemID: TimelineItemIdentifier) -> SendTarget? {
|
||||
pendingSendTargetForCallsCountLock.withLock { pendingSendTargetForUnderlyingCallsCount += 1 }
|
||||
pendingSendTargetForReceivedItemID = itemID
|
||||
pendingSendTargetForReceivedInvocationsLock.withLock { pendingSendTargetForUnderlyingReceivedInvocations.append(itemID) }
|
||||
if let pendingSendTargetForClosure = pendingSendTargetForClosure {
|
||||
return pendingSendTargetForClosure(itemID)
|
||||
} else {
|
||||
return pendingSendTargetForReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - retrySend
|
||||
|
||||
private let retrySendTargetCallsCountLock = NSLock()
|
||||
private nonisolated(unsafe) var retrySendTargetUnderlyingCallsCount = 0
|
||||
var retrySendTargetCallsCount: Int {
|
||||
get { retrySendTargetCallsCountLock.withLock { retrySendTargetUnderlyingCallsCount } }
|
||||
set { retrySendTargetCallsCountLock.withLock { retrySendTargetUnderlyingCallsCount = newValue } }
|
||||
}
|
||||
var retrySendTargetCalled: Bool {
|
||||
return retrySendTargetCallsCount > 0
|
||||
}
|
||||
private let retrySendTargetReceivedArgumentsLock = NSLock()
|
||||
private nonisolated(unsafe) var retrySendTargetUnderlyingReceivedArguments: (itemID: TimelineItemIdentifier, target: SendTarget)?
|
||||
var retrySendTargetReceivedArguments: (itemID: TimelineItemIdentifier, target: SendTarget)? {
|
||||
get { retrySendTargetReceivedArgumentsLock.withLock { retrySendTargetUnderlyingReceivedArguments } }
|
||||
set { retrySendTargetReceivedArgumentsLock.withLock { retrySendTargetUnderlyingReceivedArguments = newValue } }
|
||||
}
|
||||
private let retrySendTargetReceivedInvocationsLock = NSLock()
|
||||
private nonisolated(unsafe) var retrySendTargetUnderlyingReceivedInvocations: [(itemID: TimelineItemIdentifier, target: SendTarget)] = []
|
||||
var retrySendTargetReceivedInvocations: [(itemID: TimelineItemIdentifier, target: SendTarget)] {
|
||||
get { retrySendTargetReceivedInvocationsLock.withLock { retrySendTargetUnderlyingReceivedInvocations } }
|
||||
set { retrySendTargetReceivedInvocationsLock.withLock { retrySendTargetUnderlyingReceivedInvocations = newValue } }
|
||||
}
|
||||
nonisolated(unsafe) var retrySendTargetClosure: ((TimelineItemIdentifier, SendTarget) async -> Void)?
|
||||
|
||||
@concurrent func retrySend(_ itemID: TimelineItemIdentifier, target: SendTarget) async {
|
||||
retrySendTargetCallsCountLock.withLock { retrySendTargetUnderlyingCallsCount += 1 }
|
||||
retrySendTargetReceivedArguments = (itemID: itemID, target: target)
|
||||
retrySendTargetReceivedInvocationsLock.withLock { retrySendTargetUnderlyingReceivedInvocations.append((itemID: itemID, target: target)) }
|
||||
await retrySendTargetClosure?(itemID, target)
|
||||
}
|
||||
//MARK: - abortSend
|
||||
|
||||
private let abortSendTargetCallsCountLock = NSLock()
|
||||
private nonisolated(unsafe) var abortSendTargetUnderlyingCallsCount = 0
|
||||
var abortSendTargetCallsCount: Int {
|
||||
get { abortSendTargetCallsCountLock.withLock { abortSendTargetUnderlyingCallsCount } }
|
||||
set { abortSendTargetCallsCountLock.withLock { abortSendTargetUnderlyingCallsCount = newValue } }
|
||||
}
|
||||
var abortSendTargetCalled: Bool {
|
||||
return abortSendTargetCallsCount > 0
|
||||
}
|
||||
private let abortSendTargetReceivedArgumentsLock = NSLock()
|
||||
private nonisolated(unsafe) var abortSendTargetUnderlyingReceivedArguments: (itemID: TimelineItemIdentifier, target: SendTarget)?
|
||||
var abortSendTargetReceivedArguments: (itemID: TimelineItemIdentifier, target: SendTarget)? {
|
||||
get { abortSendTargetReceivedArgumentsLock.withLock { abortSendTargetUnderlyingReceivedArguments } }
|
||||
set { abortSendTargetReceivedArgumentsLock.withLock { abortSendTargetUnderlyingReceivedArguments = newValue } }
|
||||
}
|
||||
private let abortSendTargetReceivedInvocationsLock = NSLock()
|
||||
private nonisolated(unsafe) var abortSendTargetUnderlyingReceivedInvocations: [(itemID: TimelineItemIdentifier, target: SendTarget)] = []
|
||||
var abortSendTargetReceivedInvocations: [(itemID: TimelineItemIdentifier, target: SendTarget)] {
|
||||
get { abortSendTargetReceivedInvocationsLock.withLock { abortSendTargetUnderlyingReceivedInvocations } }
|
||||
set { abortSendTargetReceivedInvocationsLock.withLock { abortSendTargetUnderlyingReceivedInvocations = newValue } }
|
||||
}
|
||||
nonisolated(unsafe) var abortSendTargetClosure: ((TimelineItemIdentifier, SendTarget) async -> Void)?
|
||||
|
||||
@concurrent func abortSend(_ itemID: TimelineItemIdentifier, target: SendTarget) async {
|
||||
abortSendTargetCallsCountLock.withLock { abortSendTargetUnderlyingCallsCount += 1 }
|
||||
abortSendTargetReceivedArguments = (itemID: itemID, target: target)
|
||||
abortSendTargetReceivedInvocationsLock.withLock { abortSendTargetUnderlyingReceivedInvocations.append((itemID: itemID, target: target)) }
|
||||
await abortSendTargetClosure?(itemID, target)
|
||||
}
|
||||
//MARK: - eventTimestamp
|
||||
|
||||
private let eventTimestampForCallsCountLock = NSLock()
|
||||
@@ -13292,6 +13396,90 @@ nonisolated class TimelineProxyMock: TimelineProxyProtocol, @unchecked Sendable
|
||||
return redactReasonReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - retrySend
|
||||
|
||||
private let retrySendTargetCallsCountLock = NSLock()
|
||||
private nonisolated(unsafe) var retrySendTargetUnderlyingCallsCount = 0
|
||||
var retrySendTargetCallsCount: Int {
|
||||
get { retrySendTargetCallsCountLock.withLock { retrySendTargetUnderlyingCallsCount } }
|
||||
set { retrySendTargetCallsCountLock.withLock { retrySendTargetUnderlyingCallsCount = newValue } }
|
||||
}
|
||||
var retrySendTargetCalled: Bool {
|
||||
return retrySendTargetCallsCount > 0
|
||||
}
|
||||
private let retrySendTargetReceivedArgumentsLock = NSLock()
|
||||
private nonisolated(unsafe) var retrySendTargetUnderlyingReceivedArguments: (eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, target: SendTarget)?
|
||||
var retrySendTargetReceivedArguments: (eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, target: SendTarget)? {
|
||||
get { retrySendTargetReceivedArgumentsLock.withLock { retrySendTargetUnderlyingReceivedArguments } }
|
||||
set { retrySendTargetReceivedArgumentsLock.withLock { retrySendTargetUnderlyingReceivedArguments = newValue } }
|
||||
}
|
||||
private let retrySendTargetReceivedInvocationsLock = NSLock()
|
||||
private nonisolated(unsafe) var retrySendTargetUnderlyingReceivedInvocations: [(eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, target: SendTarget)] = []
|
||||
var retrySendTargetReceivedInvocations: [(eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, target: SendTarget)] {
|
||||
get { retrySendTargetReceivedInvocationsLock.withLock { retrySendTargetUnderlyingReceivedInvocations } }
|
||||
set { retrySendTargetReceivedInvocationsLock.withLock { retrySendTargetUnderlyingReceivedInvocations = newValue } }
|
||||
}
|
||||
|
||||
private let retrySendTargetReturnValueLock = NSLock()
|
||||
private nonisolated(unsafe) var retrySendTargetUnderlyingReturnValue: Result<Bool, TimelineProxyError>!
|
||||
var retrySendTargetReturnValue: Result<Bool, TimelineProxyError>! {
|
||||
get { retrySendTargetReturnValueLock.withLock { retrySendTargetUnderlyingReturnValue } }
|
||||
set { retrySendTargetReturnValueLock.withLock { retrySendTargetUnderlyingReturnValue = newValue } }
|
||||
}
|
||||
nonisolated(unsafe) var retrySendTargetClosure: ((TimelineItemIdentifier.EventOrTransactionID, SendTarget) async -> Result<Bool, TimelineProxyError>)?
|
||||
|
||||
@concurrent func retrySend(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, target: SendTarget) async -> Result<Bool, TimelineProxyError> {
|
||||
retrySendTargetCallsCountLock.withLock { retrySendTargetUnderlyingCallsCount += 1 }
|
||||
retrySendTargetReceivedArguments = (eventOrTransactionID: eventOrTransactionID, target: target)
|
||||
retrySendTargetReceivedInvocationsLock.withLock { retrySendTargetUnderlyingReceivedInvocations.append((eventOrTransactionID: eventOrTransactionID, target: target)) }
|
||||
if let retrySendTargetClosure = retrySendTargetClosure {
|
||||
return await retrySendTargetClosure(eventOrTransactionID, target)
|
||||
} else {
|
||||
return retrySendTargetReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - abortSend
|
||||
|
||||
private let abortSendTargetCallsCountLock = NSLock()
|
||||
private nonisolated(unsafe) var abortSendTargetUnderlyingCallsCount = 0
|
||||
var abortSendTargetCallsCount: Int {
|
||||
get { abortSendTargetCallsCountLock.withLock { abortSendTargetUnderlyingCallsCount } }
|
||||
set { abortSendTargetCallsCountLock.withLock { abortSendTargetUnderlyingCallsCount = newValue } }
|
||||
}
|
||||
var abortSendTargetCalled: Bool {
|
||||
return abortSendTargetCallsCount > 0
|
||||
}
|
||||
private let abortSendTargetReceivedArgumentsLock = NSLock()
|
||||
private nonisolated(unsafe) var abortSendTargetUnderlyingReceivedArguments: (eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, target: SendTarget)?
|
||||
var abortSendTargetReceivedArguments: (eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, target: SendTarget)? {
|
||||
get { abortSendTargetReceivedArgumentsLock.withLock { abortSendTargetUnderlyingReceivedArguments } }
|
||||
set { abortSendTargetReceivedArgumentsLock.withLock { abortSendTargetUnderlyingReceivedArguments = newValue } }
|
||||
}
|
||||
private let abortSendTargetReceivedInvocationsLock = NSLock()
|
||||
private nonisolated(unsafe) var abortSendTargetUnderlyingReceivedInvocations: [(eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, target: SendTarget)] = []
|
||||
var abortSendTargetReceivedInvocations: [(eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, target: SendTarget)] {
|
||||
get { abortSendTargetReceivedInvocationsLock.withLock { abortSendTargetUnderlyingReceivedInvocations } }
|
||||
set { abortSendTargetReceivedInvocationsLock.withLock { abortSendTargetUnderlyingReceivedInvocations = newValue } }
|
||||
}
|
||||
|
||||
private let abortSendTargetReturnValueLock = NSLock()
|
||||
private nonisolated(unsafe) var abortSendTargetUnderlyingReturnValue: Result<Bool, TimelineProxyError>!
|
||||
var abortSendTargetReturnValue: Result<Bool, TimelineProxyError>! {
|
||||
get { abortSendTargetReturnValueLock.withLock { abortSendTargetUnderlyingReturnValue } }
|
||||
set { abortSendTargetReturnValueLock.withLock { abortSendTargetUnderlyingReturnValue = newValue } }
|
||||
}
|
||||
nonisolated(unsafe) var abortSendTargetClosure: ((TimelineItemIdentifier.EventOrTransactionID, SendTarget) async -> Result<Bool, TimelineProxyError>)?
|
||||
|
||||
@concurrent func abortSend(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, target: SendTarget) async -> Result<Bool, TimelineProxyError> {
|
||||
abortSendTargetCallsCountLock.withLock { abortSendTargetUnderlyingCallsCount += 1 }
|
||||
abortSendTargetReceivedArguments = (eventOrTransactionID: eventOrTransactionID, target: target)
|
||||
abortSendTargetReceivedInvocationsLock.withLock { abortSendTargetUnderlyingReceivedInvocations.append((eventOrTransactionID: eventOrTransactionID, target: target)) }
|
||||
if let abortSendTargetClosure = abortSendTargetClosure {
|
||||
return await abortSendTargetClosure(eventOrTransactionID, target)
|
||||
} else {
|
||||
return abortSendTargetReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - pin
|
||||
|
||||
private let pinEventIDCallsCountLock = NSLock()
|
||||
|
||||
@@ -264,7 +264,7 @@ struct TimelineRedactConfirmationInfo: Identifiable {
|
||||
enum TimelineAlertInfoType: Hashable {
|
||||
case audioRecodingPermissionError
|
||||
case pollEndConfirmation(String)
|
||||
case sendingFailed(reason: String?, sendHandle: SendHandleProxy?)
|
||||
case sendingFailed(reason: String?, itemID: TimelineItemIdentifier, target: SendTarget?)
|
||||
case encryptionAuthenticity(String)
|
||||
case encryptionForwarder(String)
|
||||
case inviteAgain
|
||||
|
||||
@@ -758,8 +758,8 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
||||
}
|
||||
|
||||
if case let .sendingFailed(.unknown(reason)) = eventTimelineItem.properties.deliveryStatus {
|
||||
// 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)))
|
||||
// A missing target only costs the retry/remove actions, the reason is still worth showing.
|
||||
displayAlert(.sendingFailed(reason: reason, itemID: itemID, target: timelineController.pendingSendTarget(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).")
|
||||
@@ -776,13 +776,12 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
private func retrySending(_ sendHandle: SendHandleProxy) {
|
||||
Task {
|
||||
if case .failure(let error) = await sendHandle.resend() {
|
||||
MXLog.error("Failed retrying to send \(sendHandle.itemID): \(error)")
|
||||
displayErrorToast(L10n.errorUnknown)
|
||||
}
|
||||
}
|
||||
private func retrySending(_ itemID: TimelineItemIdentifier, target: SendTarget) {
|
||||
Task { await timelineController.retrySend(itemID, target: target) }
|
||||
}
|
||||
|
||||
private func abortSending(_ itemID: TimelineItemIdentifier, target: SendTarget) {
|
||||
Task { await timelineController.abortSend(itemID, target: target) }
|
||||
}
|
||||
|
||||
private func slashCommand(message: String) -> SlashCommand? {
|
||||
@@ -1125,15 +1124,15 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
||||
message: L10n.commonPollEndConfirmation,
|
||||
primaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil),
|
||||
secondaryButton: .init(title: L10n.actionOk) { self.timelineInteractionHandler.endPoll(pollStartID: pollStartID) })
|
||||
case .sendingFailed(let reason, let sendHandle):
|
||||
case .sendingFailed(let reason, let itemID, let target):
|
||||
state.bindings.alertInfo = .init(id: type,
|
||||
title: L10n.commonSendingFailed,
|
||||
message: reason,
|
||||
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.redact(sendHandle.itemID, reason: nil)
|
||||
primaryButton: .init(title: target == nil ? L10n.actionOk : L10n.actionCancel, role: .cancel, action: nil),
|
||||
verticalButtons: target.map { target in
|
||||
[.init(title: L10n.actionRetry) { [weak self] in self?.retrySending(itemID, target: target) },
|
||||
.init(title: target == .event ? L10n.actionRemoveMessage : L10n.actionDiscard, role: .destructive) { [weak self] in
|
||||
self?.abortSending(itemID, target: target)
|
||||
}]
|
||||
})
|
||||
case .encryptionAuthenticity(let message):
|
||||
|
||||
@@ -288,6 +288,53 @@ class TimelineController: TimelineControllerProtocol {
|
||||
return nil
|
||||
}
|
||||
|
||||
func pendingSendTarget(for itemID: TimelineItemIdentifier) -> SendTarget? {
|
||||
for timelineItemProxy in activeTimelineItemProvider.itemProxies {
|
||||
switch timelineItemProxy {
|
||||
case .event(let item):
|
||||
if item.id == itemID {
|
||||
return item.pendingSend?.target
|
||||
}
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func retrySend(_ itemID: TimelineItemIdentifier, target: SendTarget) async {
|
||||
guard let eventOrTransactionID = itemID.eventOrTransactionID else {
|
||||
MXLog.error("Cannot retry sending on \(itemID).")
|
||||
return
|
||||
}
|
||||
|
||||
MXLog.info("Retry \(target) send in \(roomID)")
|
||||
|
||||
switch await activeTimeline.retrySend(eventOrTransactionID, target: target) {
|
||||
case .success(let hadPendingSend):
|
||||
MXLog.info("Finished retrying send, had one pending: \(hadPendingSend)")
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed retrying send with error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func abortSend(_ itemID: TimelineItemIdentifier, target: SendTarget) async {
|
||||
guard let eventOrTransactionID = itemID.eventOrTransactionID else {
|
||||
MXLog.error("Cannot abort sending on \(itemID).")
|
||||
return
|
||||
}
|
||||
|
||||
MXLog.info("Abort \(target) send in \(roomID)")
|
||||
|
||||
switch await activeTimeline.abortSend(eventOrTransactionID, target: target) {
|
||||
case .success(let hadPendingSend):
|
||||
MXLog.info("Finished aborting send, had one pending: \(hadPendingSend)")
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed aborting send with error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Sending
|
||||
|
||||
func sendMessage(_ message: String,
|
||||
|
||||
@@ -96,6 +96,12 @@ protocol TimelineControllerProtocol: Sendable {
|
||||
|
||||
func sendHandle(for itemID: TimelineItemIdentifier) -> SendHandleProxy?
|
||||
|
||||
func pendingSendTarget(for itemID: TimelineItemIdentifier) -> SendTarget?
|
||||
|
||||
func retrySend(_ itemID: TimelineItemIdentifier, target: SendTarget) async
|
||||
|
||||
func abortSend(_ itemID: TimelineItemIdentifier, target: SendTarget) async
|
||||
|
||||
func eventTimestamp(for itemID: TimelineItemIdentifier) -> Date?
|
||||
|
||||
// MARK: - Sending
|
||||
|
||||
@@ -84,11 +84,11 @@ final nonisolated class EventTimelineItemProxy: Sendable {
|
||||
}
|
||||
|
||||
var deliveryStatus: TimelineItemDeliveryStatus? {
|
||||
guard let localSendState = item.localSendState else {
|
||||
guard let pendingSend else {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch localSendState {
|
||||
switch pendingSend.state {
|
||||
case .sendingFailed(let error, _):
|
||||
switch error {
|
||||
case .identityViolations(let users):
|
||||
@@ -107,6 +107,19 @@ final nonisolated class EventTimelineItemProxy: Sendable {
|
||||
}
|
||||
}
|
||||
|
||||
/// The item's own pending send or, when it has already gone out, our pending edit or redaction of it.
|
||||
var pendingSend: (target: SendTarget, state: EventSendState)? {
|
||||
if let state = item.localSendState {
|
||||
(.event, state)
|
||||
} else if let state = item.editSendState {
|
||||
(.edit, state)
|
||||
} else if let state = item.redactionSendState {
|
||||
(.redaction, state)
|
||||
} else {
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
var canBeRepliedTo: Bool {
|
||||
item.canBeRepliedTo
|
||||
}
|
||||
|
||||
@@ -213,6 +213,36 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func retrySend(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, target: SendTarget) async -> Result<Bool, TimelineProxyError> {
|
||||
MXLog.info("Retrying \(target) send on timeline item: \(eventOrTransactionID)")
|
||||
|
||||
do {
|
||||
let hadPendingSend = try await timeline.retrySend(itemId: eventOrTransactionID.rustValue, target: target)
|
||||
|
||||
MXLog.info("Retried \(target) send on timeline item: \(eventOrTransactionID), had one pending: \(hadPendingSend)")
|
||||
|
||||
return .success(hadPendingSend)
|
||||
} catch {
|
||||
MXLog.error("Failed retrying \(target) send on timeline item: \(eventOrTransactionID) with error: \(error)")
|
||||
return .failure(.sdkError(error))
|
||||
}
|
||||
}
|
||||
|
||||
func abortSend(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, target: SendTarget) async -> Result<Bool, TimelineProxyError> {
|
||||
MXLog.info("Aborting \(target) send on timeline item: \(eventOrTransactionID)")
|
||||
|
||||
do {
|
||||
let hadPendingSend = try await timeline.abortSend(itemId: eventOrTransactionID.rustValue, target: target)
|
||||
|
||||
MXLog.info("Aborted \(target) send on timeline item: \(eventOrTransactionID), had one pending: \(hadPendingSend)")
|
||||
|
||||
return .success(hadPendingSend)
|
||||
} catch {
|
||||
MXLog.error("Failed aborting \(target) send on timeline item: \(eventOrTransactionID) with error: \(error)")
|
||||
return .failure(.sdkError(error))
|
||||
}
|
||||
}
|
||||
|
||||
func getLoadedReplyDetails(eventID: String) async -> Result<InReplyToDetails, TimelineProxyError> {
|
||||
do {
|
||||
return try await .success(timeline.loadReplyDetails(eventIdStr: eventID))
|
||||
|
||||
@@ -99,6 +99,12 @@ protocol TimelineProxyProtocol: Sendable {
|
||||
func redact(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID,
|
||||
reason: String?) async -> Result<Void, TimelineProxyError>
|
||||
|
||||
func retrySend(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID,
|
||||
target: SendTarget) async -> Result<Bool, TimelineProxyError>
|
||||
|
||||
func abortSend(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID,
|
||||
target: SendTarget) async -> Result<Bool, TimelineProxyError>
|
||||
|
||||
func pin(eventID: String) async -> Result<Bool, TimelineProxyError>
|
||||
|
||||
func unpin(eventID: String) async -> Result<Bool, TimelineProxyError>
|
||||
|
||||
@@ -549,7 +549,7 @@ final class TimelineViewModelTests {
|
||||
// Given a room with a message that failed to send for a known reason
|
||||
let items = [TextRoomTimelineItem(eventID: "t1", sendFailure: .unknown(reason: "M_TOO_LARGE"))]
|
||||
let timelineController = TimelineControllerMock(.init(timelineItems: items))
|
||||
timelineController.sendHandleForReturnValue = .mock
|
||||
timelineController.pendingSendTargetForReturnValue = .event
|
||||
let viewModel = makeViewModel(timelineController: timelineController)
|
||||
|
||||
viewModel.process(viewAction: .itemSendInfoTapped(itemID: items[0].id))
|
||||
|
||||
Reference in New Issue
Block a user