diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 0fcd73b94..e4d1bb39f 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -5099,7 +5099,7 @@ repositoryURL = "https://github.com/matrix-org/matrix-rust-components-swift"; requirement = { kind = exactVersion; - version = "1.0.89-alpha"; + version = "1.0.91-alpha"; }; }; 96495DD8554E2F39D3954354 /* XCRemoteSwiftPackageReference "posthog-ios" */ = { diff --git a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index ce478870e..878c4ca51 100644 --- a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -111,8 +111,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/matrix-org/matrix-rust-components-swift", "state" : { - "revision" : "2f649822e3ce6d2a6b502602c0ab10e67f820bb5", - "version" : "1.0.89-alpha" + "revision" : "51c57a8c6c0d05fcaa249226e8e2a9df6e21e7cf", + "version" : "1.0.91-alpha" } }, { diff --git a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift index 45ddc6943..3dedd21af 100644 --- a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift @@ -637,86 +637,70 @@ class RoomProxyMock: RoomProxyProtocol { } //MARK: - sendImage - var sendImageUrlThumbnailURLImageInfoProgressSubjectCallsCount = 0 - var sendImageUrlThumbnailURLImageInfoProgressSubjectCalled: Bool { - return sendImageUrlThumbnailURLImageInfoProgressSubjectCallsCount > 0 + var sendImageUrlThumbnailURLImageInfoProgressSubjectRequestHandleCallsCount = 0 + var sendImageUrlThumbnailURLImageInfoProgressSubjectRequestHandleCalled: Bool { + return sendImageUrlThumbnailURLImageInfoProgressSubjectRequestHandleCallsCount > 0 } - var sendImageUrlThumbnailURLImageInfoProgressSubjectReceivedArguments: (url: URL, thumbnailURL: URL, imageInfo: ImageInfo, progressSubject: CurrentValueSubject?)? - var sendImageUrlThumbnailURLImageInfoProgressSubjectReceivedInvocations: [(url: URL, thumbnailURL: URL, imageInfo: ImageInfo, progressSubject: CurrentValueSubject?)] = [] - var sendImageUrlThumbnailURLImageInfoProgressSubjectReturnValue: Result! - var sendImageUrlThumbnailURLImageInfoProgressSubjectClosure: ((URL, URL, ImageInfo, CurrentValueSubject?) async -> Result)? + var sendImageUrlThumbnailURLImageInfoProgressSubjectRequestHandleReturnValue: Result! + var sendImageUrlThumbnailURLImageInfoProgressSubjectRequestHandleClosure: ((URL, URL, ImageInfo, CurrentValueSubject?, (SendAttachmentJoinHandleProtocol) -> Void) async -> Result)? - func sendImage(url: URL, thumbnailURL: URL, imageInfo: ImageInfo, progressSubject: CurrentValueSubject?) async -> Result { - sendImageUrlThumbnailURLImageInfoProgressSubjectCallsCount += 1 - sendImageUrlThumbnailURLImageInfoProgressSubjectReceivedArguments = (url: url, thumbnailURL: thumbnailURL, imageInfo: imageInfo, progressSubject: progressSubject) - sendImageUrlThumbnailURLImageInfoProgressSubjectReceivedInvocations.append((url: url, thumbnailURL: thumbnailURL, imageInfo: imageInfo, progressSubject: progressSubject)) - if let sendImageUrlThumbnailURLImageInfoProgressSubjectClosure = sendImageUrlThumbnailURLImageInfoProgressSubjectClosure { - return await sendImageUrlThumbnailURLImageInfoProgressSubjectClosure(url, thumbnailURL, imageInfo, progressSubject) + func sendImage(url: URL, thumbnailURL: URL, imageInfo: ImageInfo, progressSubject: CurrentValueSubject?, requestHandle: (SendAttachmentJoinHandleProtocol) -> Void) async -> Result { + sendImageUrlThumbnailURLImageInfoProgressSubjectRequestHandleCallsCount += 1 + if let sendImageUrlThumbnailURLImageInfoProgressSubjectRequestHandleClosure = sendImageUrlThumbnailURLImageInfoProgressSubjectRequestHandleClosure { + return await sendImageUrlThumbnailURLImageInfoProgressSubjectRequestHandleClosure(url, thumbnailURL, imageInfo, progressSubject, requestHandle) } else { - return sendImageUrlThumbnailURLImageInfoProgressSubjectReturnValue + return sendImageUrlThumbnailURLImageInfoProgressSubjectRequestHandleReturnValue } } //MARK: - sendVideo - var sendVideoUrlThumbnailURLVideoInfoProgressSubjectCallsCount = 0 - var sendVideoUrlThumbnailURLVideoInfoProgressSubjectCalled: Bool { - return sendVideoUrlThumbnailURLVideoInfoProgressSubjectCallsCount > 0 + var sendVideoUrlThumbnailURLVideoInfoProgressSubjectRequestHandleCallsCount = 0 + var sendVideoUrlThumbnailURLVideoInfoProgressSubjectRequestHandleCalled: Bool { + return sendVideoUrlThumbnailURLVideoInfoProgressSubjectRequestHandleCallsCount > 0 } - var sendVideoUrlThumbnailURLVideoInfoProgressSubjectReceivedArguments: (url: URL, thumbnailURL: URL, videoInfo: VideoInfo, progressSubject: CurrentValueSubject?)? - var sendVideoUrlThumbnailURLVideoInfoProgressSubjectReceivedInvocations: [(url: URL, thumbnailURL: URL, videoInfo: VideoInfo, progressSubject: CurrentValueSubject?)] = [] - var sendVideoUrlThumbnailURLVideoInfoProgressSubjectReturnValue: Result! - var sendVideoUrlThumbnailURLVideoInfoProgressSubjectClosure: ((URL, URL, VideoInfo, CurrentValueSubject?) async -> Result)? + var sendVideoUrlThumbnailURLVideoInfoProgressSubjectRequestHandleReturnValue: Result! + var sendVideoUrlThumbnailURLVideoInfoProgressSubjectRequestHandleClosure: ((URL, URL, VideoInfo, CurrentValueSubject?, (SendAttachmentJoinHandleProtocol) -> Void) async -> Result)? - func sendVideo(url: URL, thumbnailURL: URL, videoInfo: VideoInfo, progressSubject: CurrentValueSubject?) async -> Result { - sendVideoUrlThumbnailURLVideoInfoProgressSubjectCallsCount += 1 - sendVideoUrlThumbnailURLVideoInfoProgressSubjectReceivedArguments = (url: url, thumbnailURL: thumbnailURL, videoInfo: videoInfo, progressSubject: progressSubject) - sendVideoUrlThumbnailURLVideoInfoProgressSubjectReceivedInvocations.append((url: url, thumbnailURL: thumbnailURL, videoInfo: videoInfo, progressSubject: progressSubject)) - if let sendVideoUrlThumbnailURLVideoInfoProgressSubjectClosure = sendVideoUrlThumbnailURLVideoInfoProgressSubjectClosure { - return await sendVideoUrlThumbnailURLVideoInfoProgressSubjectClosure(url, thumbnailURL, videoInfo, progressSubject) + func sendVideo(url: URL, thumbnailURL: URL, videoInfo: VideoInfo, progressSubject: CurrentValueSubject?, requestHandle: (SendAttachmentJoinHandleProtocol) -> Void) async -> Result { + sendVideoUrlThumbnailURLVideoInfoProgressSubjectRequestHandleCallsCount += 1 + if let sendVideoUrlThumbnailURLVideoInfoProgressSubjectRequestHandleClosure = sendVideoUrlThumbnailURLVideoInfoProgressSubjectRequestHandleClosure { + return await sendVideoUrlThumbnailURLVideoInfoProgressSubjectRequestHandleClosure(url, thumbnailURL, videoInfo, progressSubject, requestHandle) } else { - return sendVideoUrlThumbnailURLVideoInfoProgressSubjectReturnValue + return sendVideoUrlThumbnailURLVideoInfoProgressSubjectRequestHandleReturnValue } } //MARK: - sendAudio - var sendAudioUrlAudioInfoProgressSubjectCallsCount = 0 - var sendAudioUrlAudioInfoProgressSubjectCalled: Bool { - return sendAudioUrlAudioInfoProgressSubjectCallsCount > 0 + var sendAudioUrlAudioInfoProgressSubjectRequestHandleCallsCount = 0 + var sendAudioUrlAudioInfoProgressSubjectRequestHandleCalled: Bool { + return sendAudioUrlAudioInfoProgressSubjectRequestHandleCallsCount > 0 } - var sendAudioUrlAudioInfoProgressSubjectReceivedArguments: (url: URL, audioInfo: AudioInfo, progressSubject: CurrentValueSubject?)? - var sendAudioUrlAudioInfoProgressSubjectReceivedInvocations: [(url: URL, audioInfo: AudioInfo, progressSubject: CurrentValueSubject?)] = [] - var sendAudioUrlAudioInfoProgressSubjectReturnValue: Result! - var sendAudioUrlAudioInfoProgressSubjectClosure: ((URL, AudioInfo, CurrentValueSubject?) async -> Result)? + var sendAudioUrlAudioInfoProgressSubjectRequestHandleReturnValue: Result! + var sendAudioUrlAudioInfoProgressSubjectRequestHandleClosure: ((URL, AudioInfo, CurrentValueSubject?, (SendAttachmentJoinHandleProtocol) -> Void) async -> Result)? - func sendAudio(url: URL, audioInfo: AudioInfo, progressSubject: CurrentValueSubject?) async -> Result { - sendAudioUrlAudioInfoProgressSubjectCallsCount += 1 - sendAudioUrlAudioInfoProgressSubjectReceivedArguments = (url: url, audioInfo: audioInfo, progressSubject: progressSubject) - sendAudioUrlAudioInfoProgressSubjectReceivedInvocations.append((url: url, audioInfo: audioInfo, progressSubject: progressSubject)) - if let sendAudioUrlAudioInfoProgressSubjectClosure = sendAudioUrlAudioInfoProgressSubjectClosure { - return await sendAudioUrlAudioInfoProgressSubjectClosure(url, audioInfo, progressSubject) + func sendAudio(url: URL, audioInfo: AudioInfo, progressSubject: CurrentValueSubject?, requestHandle: (SendAttachmentJoinHandleProtocol) -> Void) async -> Result { + sendAudioUrlAudioInfoProgressSubjectRequestHandleCallsCount += 1 + if let sendAudioUrlAudioInfoProgressSubjectRequestHandleClosure = sendAudioUrlAudioInfoProgressSubjectRequestHandleClosure { + return await sendAudioUrlAudioInfoProgressSubjectRequestHandleClosure(url, audioInfo, progressSubject, requestHandle) } else { - return sendAudioUrlAudioInfoProgressSubjectReturnValue + return sendAudioUrlAudioInfoProgressSubjectRequestHandleReturnValue } } //MARK: - sendFile - var sendFileUrlFileInfoProgressSubjectCallsCount = 0 - var sendFileUrlFileInfoProgressSubjectCalled: Bool { - return sendFileUrlFileInfoProgressSubjectCallsCount > 0 + var sendFileUrlFileInfoProgressSubjectRequestHandleCallsCount = 0 + var sendFileUrlFileInfoProgressSubjectRequestHandleCalled: Bool { + return sendFileUrlFileInfoProgressSubjectRequestHandleCallsCount > 0 } - var sendFileUrlFileInfoProgressSubjectReceivedArguments: (url: URL, fileInfo: FileInfo, progressSubject: CurrentValueSubject?)? - var sendFileUrlFileInfoProgressSubjectReceivedInvocations: [(url: URL, fileInfo: FileInfo, progressSubject: CurrentValueSubject?)] = [] - var sendFileUrlFileInfoProgressSubjectReturnValue: Result! - var sendFileUrlFileInfoProgressSubjectClosure: ((URL, FileInfo, CurrentValueSubject?) async -> Result)? + var sendFileUrlFileInfoProgressSubjectRequestHandleReturnValue: Result! + var sendFileUrlFileInfoProgressSubjectRequestHandleClosure: ((URL, FileInfo, CurrentValueSubject?, (SendAttachmentJoinHandleProtocol) -> Void) async -> Result)? - func sendFile(url: URL, fileInfo: FileInfo, progressSubject: CurrentValueSubject?) async -> Result { - sendFileUrlFileInfoProgressSubjectCallsCount += 1 - sendFileUrlFileInfoProgressSubjectReceivedArguments = (url: url, fileInfo: fileInfo, progressSubject: progressSubject) - sendFileUrlFileInfoProgressSubjectReceivedInvocations.append((url: url, fileInfo: fileInfo, progressSubject: progressSubject)) - if let sendFileUrlFileInfoProgressSubjectClosure = sendFileUrlFileInfoProgressSubjectClosure { - return await sendFileUrlFileInfoProgressSubjectClosure(url, fileInfo, progressSubject) + func sendFile(url: URL, fileInfo: FileInfo, progressSubject: CurrentValueSubject?, requestHandle: (SendAttachmentJoinHandleProtocol) -> Void) async -> Result { + sendFileUrlFileInfoProgressSubjectRequestHandleCallsCount += 1 + if let sendFileUrlFileInfoProgressSubjectRequestHandleClosure = sendFileUrlFileInfoProgressSubjectRequestHandleClosure { + return await sendFileUrlFileInfoProgressSubjectRequestHandleClosure(url, fileInfo, progressSubject, requestHandle) } else { - return sendFileUrlFileInfoProgressSubjectReturnValue + return sendFileUrlFileInfoProgressSubjectRequestHandleReturnValue } } //MARK: - sendLocation diff --git a/ElementX/Sources/Other/UserIndicator/UserIndicator.swift b/ElementX/Sources/Other/UserIndicator/UserIndicator.swift index 3a66f2e4e..8a47c8ea2 100644 --- a/ElementX/Sources/Other/UserIndicator/UserIndicator.swift +++ b/ElementX/Sources/Other/UserIndicator/UserIndicator.swift @@ -19,10 +19,10 @@ import Foundation enum UserIndicatorType: Equatable { case toast(progress: UserIndicator.Progress?) - case modal(progress: UserIndicator.Progress?, interactiveDismissDisabled: Bool) + case modal(progress: UserIndicator.Progress?, interactiveDismissDisabled: Bool, allowsInteraction: Bool) static var toast: Self { .toast(progress: .none) } - static var modal: Self { .modal(progress: .indeterminate, interactiveDismissDisabled: false) } + static var modal: Self { .modal(progress: .indeterminate, interactiveDismissDisabled: false, allowsInteraction: false) } } struct UserIndicator: Equatable, Identifiable { @@ -50,13 +50,13 @@ struct UserIndicator: Equatable, Identifiable { var progress: Progress? { switch type { case .toast(let progress): return progress - case .modal(let progress, _): return progress + case .modal(let progress, _, _): return progress } } var progressPublisher: CurrentValuePublisher { switch type { - case .toast(let progress), .modal(let progress, _): + case .toast(let progress), .modal(let progress, _, _): switch progress { case .none, .indeterminate: return CurrentValueSubject(0.0).asCurrentValuePublisher() @@ -70,8 +70,17 @@ struct UserIndicator: Equatable, Identifiable { switch type { case .toast: return false - case .modal(_, let interactiveDismissDisabled): + case .modal(_, let interactiveDismissDisabled, _): return interactiveDismissDisabled } } + + var allowsInteraction: Bool { + switch type { + case .toast: + return true + case .modal(_, _, let allowsInteraction): + return allowsInteraction + } + } } diff --git a/ElementX/Sources/Other/UserIndicator/UserIndicatorModalView.swift b/ElementX/Sources/Other/UserIndicator/UserIndicatorModalView.swift index 2b9c6afa8..969ef1386 100644 --- a/ElementX/Sources/Other/UserIndicator/UserIndicatorModalView.swift +++ b/ElementX/Sources/Other/UserIndicator/UserIndicatorModalView.swift @@ -54,7 +54,11 @@ struct UserIndicatorModalView: View { } .id(indicator.id) .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(.black.opacity(0.1)) + .background { + if !indicator.allowsInteraction { + Color.black.opacity(0.1) + } + } .ignoresSafeArea() .interactiveDismissDisabled(indicator.interactiveDismissDisabled) } @@ -70,13 +74,16 @@ struct UserIndicatorModalView_Previews: PreviewProvider { .previewDisplayName("Spinner") UserIndicatorModalView(indicator: UserIndicator(type: .modal(progress: .published(CurrentValueSubject(0.5).asCurrentValuePublisher()), - interactiveDismissDisabled: false), + interactiveDismissDisabled: false, + allowsInteraction: false), title: "Successfully logged in", iconName: "checkmark") ) .previewDisplayName("Progress Bar") - UserIndicatorModalView(indicator: UserIndicator(type: .modal(progress: .none, interactiveDismissDisabled: false), + UserIndicatorModalView(indicator: UserIndicator(type: .modal(progress: .none, + interactiveDismissDisabled: false, + allowsInteraction: false), title: "Successfully logged in", iconName: "checkmark") ) diff --git a/ElementX/Sources/Screens/BugReportScreen/BugReportScreenCoordinator.swift b/ElementX/Sources/Screens/BugReportScreen/BugReportScreenCoordinator.swift index 8deed5a50..8e6be716a 100644 --- a/ElementX/Sources/Screens/BugReportScreen/BugReportScreenCoordinator.swift +++ b/ElementX/Sources/Screens/BugReportScreen/BugReportScreenCoordinator.swift @@ -88,7 +88,7 @@ final class BugReportScreenCoordinator: CoordinatorProtocol { private func startLoading(label: String = L10n.commonLoading, progressPublisher: CurrentValuePublisher) { parameters.userIndicatorController?.submitIndicator( UserIndicator(id: Self.loadingIndicatorIdentifier, - type: .modal(progress: .published(progressPublisher), interactiveDismissDisabled: false), + type: .modal(progress: .published(progressPublisher), interactiveDismissDisabled: false, allowsInteraction: false), title: label, persistent: true) ) diff --git a/ElementX/Sources/Screens/CreateRoom/CreateRoomViewModel.swift b/ElementX/Sources/Screens/CreateRoom/CreateRoomViewModel.swift index 425d74d8a..f1030bf4f 100644 --- a/ElementX/Sources/Screens/CreateRoom/CreateRoomViewModel.swift +++ b/ElementX/Sources/Screens/CreateRoom/CreateRoomViewModel.swift @@ -175,7 +175,7 @@ class CreateRoomViewModel: CreateRoomViewModelType, CreateRoomViewModelProtocol private func showLoadingIndicator() { userIndicatorController?.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, - type: .modal(progress: .indeterminate, interactiveDismissDisabled: true), + type: .modal(progress: .indeterminate, interactiveDismissDisabled: true, allowsInteraction: false), title: L10n.commonLoading, persistent: true)) } diff --git a/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift b/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift index 6db9aef4a..934400433 100644 --- a/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift +++ b/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift @@ -305,7 +305,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol state.bindings.alertInfo = AlertInfo(id: UUID(), title: L10n.errorUnknown) case .some(.success): userIndicatorController.submitIndicator(UserIndicator(id: UUID().uuidString, - type: .modal(progress: .none, interactiveDismissDisabled: false), + type: .modal(progress: .none, interactiveDismissDisabled: false, allowsInteraction: false), title: L10n.commonCurrentUserLeftRoom, iconName: "checkmark")) callback?(.roomLeft(roomIdentifier: roomId)) diff --git a/ElementX/Sources/Screens/MediaUploadPreviewScreen/MediaUploadPreviewScreenModels.swift b/ElementX/Sources/Screens/MediaUploadPreviewScreen/MediaUploadPreviewScreenModels.swift index 974dfb574..e919f1f5d 100644 --- a/ElementX/Sources/Screens/MediaUploadPreviewScreen/MediaUploadPreviewScreenModels.swift +++ b/ElementX/Sources/Screens/MediaUploadPreviewScreen/MediaUploadPreviewScreenModels.swift @@ -23,6 +23,7 @@ enum MediaUploadPreviewScreenViewModelAction { struct MediaUploadPreviewScreenViewState: BindableState { let url: URL let title: String? + var shouldDisableInteraction = false } enum MediaUploadPreviewScreenViewAction { diff --git a/ElementX/Sources/Screens/MediaUploadPreviewScreen/MediaUploadPreviewScreenViewModel.swift b/ElementX/Sources/Screens/MediaUploadPreviewScreen/MediaUploadPreviewScreenViewModel.swift index 2c2e7cf01..f91c5dda1 100644 --- a/ElementX/Sources/Screens/MediaUploadPreviewScreen/MediaUploadPreviewScreenViewModel.swift +++ b/ElementX/Sources/Screens/MediaUploadPreviewScreen/MediaUploadPreviewScreenViewModel.swift @@ -15,6 +15,7 @@ // import Combine +import MatrixRustSDK import SwiftUI typealias MediaUploadPreviewScreenViewModelType = StateStoreViewModel @@ -24,6 +25,11 @@ class MediaUploadPreviewScreenViewModel: MediaUploadPreviewScreenViewModelType, private let roomProxy: RoomProxyProtocol private let mediaUploadingPreprocessor: MediaUploadingPreprocessor private let url: URL + private var requestHandle: SendAttachmentJoinHandleProtocol? { + didSet { + state.shouldDisableInteraction = requestHandle != nil + } + } var callback: ((MediaUploadPreviewScreenViewModelAction) -> Void)? @@ -67,6 +73,7 @@ class MediaUploadPreviewScreenViewModel: MediaUploadPreviewScreenViewModelType, } case .cancel: + requestHandle?.cancel() callback?(.dismiss) } } @@ -74,15 +81,20 @@ class MediaUploadPreviewScreenViewModel: MediaUploadPreviewScreenViewModelType, // MARK: - Private private func sendAttachment(mediaInfo: MediaInfo, progressSubject: CurrentValueSubject) async -> Result { + let requestHandle: ((SendAttachmentJoinHandleProtocol) -> Void) = { [weak self] handle in + self?.requestHandle?.cancel() + self?.requestHandle = handle + } + switch mediaInfo { case let .image(imageURL, thumbnailURL, imageInfo): - return await roomProxy.sendImage(url: imageURL, thumbnailURL: thumbnailURL, imageInfo: imageInfo, progressSubject: progressSubject) + return await roomProxy.sendImage(url: imageURL, thumbnailURL: thumbnailURL, imageInfo: imageInfo, progressSubject: progressSubject, requestHandle: requestHandle) case let .video(videoURL, thumbnailURL, videoInfo): - return await roomProxy.sendVideo(url: videoURL, thumbnailURL: thumbnailURL, videoInfo: videoInfo, progressSubject: progressSubject) + return await roomProxy.sendVideo(url: videoURL, thumbnailURL: thumbnailURL, videoInfo: videoInfo, progressSubject: progressSubject, requestHandle: requestHandle) case let .audio(audioURL, audioInfo): - return await roomProxy.sendAudio(url: audioURL, audioInfo: audioInfo, progressSubject: progressSubject) + return await roomProxy.sendAudio(url: audioURL, audioInfo: audioInfo, progressSubject: progressSubject, requestHandle: requestHandle) case let .file(fileURL, fileInfo): - return await roomProxy.sendFile(url: fileURL, fileInfo: fileInfo, progressSubject: progressSubject) + return await roomProxy.sendFile(url: fileURL, fileInfo: fileInfo, progressSubject: progressSubject, requestHandle: requestHandle) } } @@ -91,7 +103,7 @@ class MediaUploadPreviewScreenViewModel: MediaUploadPreviewScreenViewModelType, private func startLoading(progressPublisher: CurrentValuePublisher) { userIndicatorController?.submitIndicator( UserIndicator(id: Self.loadingIndicatorIdentifier, - type: .modal(progress: .published(progressPublisher), interactiveDismissDisabled: false), + type: .modal(progress: .published(progressPublisher), interactiveDismissDisabled: false, allowsInteraction: true), title: L10n.commonSending, persistent: true) ) @@ -99,6 +111,7 @@ class MediaUploadPreviewScreenViewModel: MediaUploadPreviewScreenViewModelType, private func stopLoading() { userIndicatorController?.retractIndicatorWithId(Self.loadingIndicatorIdentifier) + requestHandle = nil } private func showError(label: String) { diff --git a/ElementX/Sources/Screens/MediaUploadPreviewScreen/View/MediaUploadPreviewScreen.swift b/ElementX/Sources/Screens/MediaUploadPreviewScreen/View/MediaUploadPreviewScreen.swift index 54936c229..08dab1b21 100644 --- a/ElementX/Sources/Screens/MediaUploadPreviewScreen/View/MediaUploadPreviewScreen.swift +++ b/ElementX/Sources/Screens/MediaUploadPreviewScreen/View/MediaUploadPreviewScreen.swift @@ -25,6 +25,7 @@ struct MediaUploadPreviewScreen: View { fileURL: context.viewState.url, title: context.viewState.title) .id(UUID()) + .disabled(context.viewState.shouldDisableInteraction) .ignoresSafeArea(edges: .bottom) .toolbar { toolbar } .interactiveDismissDisabled() @@ -41,6 +42,7 @@ struct MediaUploadPreviewScreen: View { Button { context.send(viewAction: .send) } label: { Text(L10n.actionSend) } + .disabled(context.viewState.shouldDisableInteraction) } } } diff --git a/ElementX/Sources/Screens/RoomDetailsEditScreen/RoomDetailsEditScreenViewModel.swift b/ElementX/Sources/Screens/RoomDetailsEditScreen/RoomDetailsEditScreenViewModel.swift index ee9cea3c5..ef88b925c 100644 --- a/ElementX/Sources/Screens/RoomDetailsEditScreen/RoomDetailsEditScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomDetailsEditScreen/RoomDetailsEditScreenViewModel.swift @@ -78,7 +78,7 @@ class RoomDetailsEditScreenViewModel: RoomDetailsEditScreenViewModelType, RoomDe userIndicatorController?.retractIndicatorWithId(userIndicatorID) } userIndicatorController?.submitIndicator(UserIndicator(id: userIndicatorID, - type: .modal(progress: .indeterminate, interactiveDismissDisabled: true), + type: .modal(progress: .indeterminate, interactiveDismissDisabled: true, allowsInteraction: false), title: L10n.commonLoading, persistent: true)) @@ -102,7 +102,7 @@ class RoomDetailsEditScreenViewModel: RoomDetailsEditScreenViewModelType, RoomDe userIndicatorController?.retractIndicatorWithId(userIndicatorID) } userIndicatorController?.submitIndicator(UserIndicator(id: userIndicatorID, - type: .modal(progress: .indeterminate, interactiveDismissDisabled: true), + type: .modal(progress: .indeterminate, interactiveDismissDisabled: true, allowsInteraction: false), title: L10n.screenRoomDetailsUpdatingRoom, persistent: true)) diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift index 129cbe532..9a628d0c4 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift @@ -568,7 +568,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol private func showLoadingIndicator(with delay: Duration) { userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, - type: .modal(progress: .indeterminate, interactiveDismissDisabled: true), + type: .modal(progress: .indeterminate, interactiveDismissDisabled: true, allowsInteraction: false), title: L10n.commonLoading, persistent: true), delay: delay) diff --git a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift index c719e61cf..9806639bb 100644 --- a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift +++ b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift @@ -163,7 +163,7 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie private func showLoadingIndicator() { userIndicatorController?.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, - type: .modal(progress: .indeterminate, interactiveDismissDisabled: true), + type: .modal(progress: .indeterminate, interactiveDismissDisabled: true, allowsInteraction: false), title: L10n.commonLoading, persistent: true)) } diff --git a/ElementX/Sources/Services/Room/RoomProxy.swift b/ElementX/Sources/Services/Room/RoomProxy.swift index 390188d24..a7e4122fb 100644 --- a/ElementX/Sources/Services/Room/RoomProxy.swift +++ b/ElementX/Sources/Services/Room/RoomProxy.swift @@ -274,76 +274,102 @@ class RoomProxy: RoomProxyProtocol { } } - func sendImage(url: URL, thumbnailURL: URL, imageInfo: ImageInfo, progressSubject: CurrentValueSubject?) async -> Result { + func sendImage(url: URL, + thumbnailURL: URL, + imageInfo: ImageInfo, + progressSubject: CurrentValueSubject?, + requestHandle: (SendAttachmentJoinHandleProtocol) -> Void) async -> Result { sendMessageBackgroundTask = backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true) defer { sendMessageBackgroundTask?.stop() } - - return await Task.dispatch(on: userInitiatedDispatchQueue) { - do { - try self.room.sendImage(url: url.path(), thumbnailUrl: thumbnailURL.path(), imageInfo: imageInfo, progressWatcher: UploadProgressListener { progress in - progressSubject?.send(progress) - }) - return .success(()) - } catch { - return .failure(.failedSendingMedia) - } + + let handle = room.sendImage(url: url.path(), thumbnailUrl: thumbnailURL.path(), imageInfo: imageInfo, progressWatcher: UploadProgressListener { progress in + progressSubject?.send(progress) + }) + + requestHandle(handle) + + do { + try await handle.join() + } catch { + return .failure(.failedSendingMedia) } + + return .success(()) } - func sendVideo(url: URL, thumbnailURL: URL, videoInfo: VideoInfo, progressSubject: CurrentValueSubject?) async -> Result { + func sendVideo(url: URL, + thumbnailURL: URL, + videoInfo: VideoInfo, + progressSubject: CurrentValueSubject?, + requestHandle: (SendAttachmentJoinHandleProtocol) -> Void) async -> Result { sendMessageBackgroundTask = backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true) defer { sendMessageBackgroundTask?.stop() } - - return await Task.dispatch(on: userInitiatedDispatchQueue) { - do { - try self.room.sendVideo(url: url.path(), thumbnailUrl: thumbnailURL.path(), videoInfo: videoInfo, progressWatcher: UploadProgressListener { progress in - progressSubject?.send(progress) - }) - return .success(()) - } catch { - return .failure(.failedSendingMedia) - } + + let handle = room.sendVideo(url: url.path(), thumbnailUrl: thumbnailURL.path(), videoInfo: videoInfo, progressWatcher: UploadProgressListener { progress in + progressSubject?.send(progress) + }) + + requestHandle(handle) + + do { + try await handle.join() + } catch { + return .failure(.failedSendingMedia) } + + return .success(()) } - func sendAudio(url: URL, audioInfo: AudioInfo, progressSubject: CurrentValueSubject?) async -> Result { + func sendAudio(url: URL, + audioInfo: AudioInfo, + progressSubject: CurrentValueSubject?, + requestHandle: (SendAttachmentJoinHandleProtocol) -> Void) async -> Result { sendMessageBackgroundTask = backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true) defer { sendMessageBackgroundTask?.stop() } - - return await Task.dispatch(on: userInitiatedDispatchQueue) { - do { - try self.room.sendAudio(url: url.path(), audioInfo: audioInfo, progressWatcher: UploadProgressListener { progress in - progressSubject?.send(progress) - }) - return .success(()) - } catch { - return .failure(.failedSendingMedia) - } + + let handle = room.sendAudio(url: url.path(), audioInfo: audioInfo, progressWatcher: UploadProgressListener { progress in + progressSubject?.send(progress) + }) + + requestHandle(handle) + + do { + try await handle.join() + } catch { + return .failure(.failedSendingMedia) } + + return .success(()) } - func sendFile(url: URL, fileInfo: FileInfo, progressSubject: CurrentValueSubject?) async -> Result { + func sendFile(url: URL, + fileInfo: FileInfo, + progressSubject: CurrentValueSubject?, + requestHandle: (SendAttachmentJoinHandleProtocol) -> Void) async -> Result { sendMessageBackgroundTask = backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true) defer { sendMessageBackgroundTask?.stop() } - - return await Task.dispatch(on: userInitiatedDispatchQueue) { - do { - try self.room.sendFile(url: url.path(), fileInfo: fileInfo, progressWatcher: UploadProgressListener { progress in - progressSubject?.send(progress) - }) - return .success(()) - } catch { - return .failure(.failedSendingMedia) - } + + let handle = room.sendFile(url: url.path(), fileInfo: fileInfo, progressWatcher: UploadProgressListener { progress in + progressSubject?.send(progress) + }) + + requestHandle(handle) + + do { + try await handle.join() + } catch { + return .failure(.failedSendingMedia) } + + return .success(()) } func sendLocation(body: String, geoURI: GeoURI) async -> Result { diff --git a/ElementX/Sources/Services/Room/RoomProxyProtocol.swift b/ElementX/Sources/Services/Room/RoomProxyProtocol.swift index 317171fa5..8bbd637cd 100644 --- a/ElementX/Sources/Services/Room/RoomProxyProtocol.swift +++ b/ElementX/Sources/Services/Room/RoomProxyProtocol.swift @@ -93,13 +93,27 @@ protocol RoomProxyProtocol { func toggleReaction(_ reaction: String, to eventID: String) async -> Result - func sendImage(url: URL, thumbnailURL: URL, imageInfo: ImageInfo, progressSubject: CurrentValueSubject?) async -> Result + func sendImage(url: URL, + thumbnailURL: URL, + imageInfo: ImageInfo, + progressSubject: CurrentValueSubject?, + requestHandle: (SendAttachmentJoinHandleProtocol) -> Void) async -> Result - func sendVideo(url: URL, thumbnailURL: URL, videoInfo: VideoInfo, progressSubject: CurrentValueSubject?) async -> Result + func sendVideo(url: URL, + thumbnailURL: URL, + videoInfo: VideoInfo, + progressSubject: CurrentValueSubject?, + requestHandle: (SendAttachmentJoinHandleProtocol) -> Void) async -> Result - func sendAudio(url: URL, audioInfo: AudioInfo, progressSubject: CurrentValueSubject?) async -> Result + func sendAudio(url: URL, + audioInfo: AudioInfo, + progressSubject: CurrentValueSubject?, + requestHandle: (SendAttachmentJoinHandleProtocol) -> Void) async -> Result - func sendFile(url: URL, fileInfo: FileInfo, progressSubject: CurrentValueSubject?) async -> Result + func sendFile(url: URL, + fileInfo: FileInfo, + progressSubject: CurrentValueSubject?, + requestHandle: (SendAttachmentJoinHandleProtocol) -> Void) async -> Result func sendLocation(body: String, geoURI: GeoURI) async -> Result diff --git a/project.yml b/project.yml index 8ef7926db..5e9d9f7a6 100644 --- a/project.yml +++ b/project.yml @@ -44,7 +44,7 @@ include: packages: MatrixRustSDK: url: https://github.com/matrix-org/matrix-rust-components-swift - exactVersion: 1.0.89-alpha + exactVersion: 1.0.91-alpha # path: ../matrix-rust-sdk DesignKit: path: DesignKit