Files
letro-ios/ElementX/Sources/Screens/MediaUploadPreviewScreen/MediaUploadPreviewScreenViewModel.swift
Stefan Ceriu 1ae6fc67c4 SDK update (#3891)
* Bump the RustSDK to v25.03.11

* Replace oidc login prompt with nil following the changes from https://github.com/matrix-org/matrix-rust-sdk/pull/4761

```
/// * `prompt` - The desired user experience in the web UI. No value means
///   that the user wishes to login into an existing account, and a value of
///   `Create` means that the user wishes to register a new account.
```

* Fix trailing closure warnings

* Update the client proxy after making `getNotificationSettings()` and  `cachedAvatarUrl()` async (they used to be blocking on the rust side).

* Move `Room.isEncrypted` to the info publisher and manually update the encryption state when creating the room.

* Bump the SDK again to v25.03.12 - This introduces a new way to configure the tokio runtime that we can use to have extensions use less memory
- introduce a new Target struct that takes care of setting up rust services (tracing and tokio) for our various targets
- cleanup MXLog and friends

* Address PR comments

* Bump the SDK again, switch back to using `.consent` as the OIDC login prompt (which was reintroduced in matrix-org/matrix-rust-sdk/pull/4791)
2025-03-13 11:17:37 +02:00

147 lines
6.5 KiB
Swift

//
// Copyright 2022-2024 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
// Please see LICENSE files in the repository root for full details.
//
import Combine
import MatrixRustSDK
import SwiftUI
typealias MediaUploadPreviewScreenViewModelType = StateStoreViewModel<MediaUploadPreviewScreenViewState, MediaUploadPreviewScreenViewAction>
class MediaUploadPreviewScreenViewModel: MediaUploadPreviewScreenViewModelType, MediaUploadPreviewScreenViewModelProtocol {
private let userIndicatorController: UserIndicatorControllerProtocol
private let roomProxy: JoinedRoomProxyProtocol
private let mediaUploadingPreprocessor: MediaUploadingPreprocessor
private let url: URL
private var processingTask: Task<Result<MediaInfo, MediaUploadingPreprocessorError>, Never>
private var requestHandle: SendAttachmentJoinHandleProtocol?
private var actionsSubject: PassthroughSubject<MediaUploadPreviewScreenViewModelAction, Never> = .init()
var actions: AnyPublisher<MediaUploadPreviewScreenViewModelAction, Never> {
actionsSubject.eraseToAnyPublisher()
}
init(userIndicatorController: UserIndicatorControllerProtocol,
roomProxy: JoinedRoomProxyProtocol,
mediaUploadingPreprocessor: MediaUploadingPreprocessor,
title: String?,
url: URL,
shouldShowCaptionWarning: Bool) {
self.userIndicatorController = userIndicatorController
self.roomProxy = roomProxy
self.mediaUploadingPreprocessor = mediaUploadingPreprocessor
self.url = url
// Start processing the media whilst the user is reviewing it/adding a caption.
processingTask = Task { await mediaUploadingPreprocessor.processMedia(at: url) }
super.init(initialViewState: MediaUploadPreviewScreenViewState(url: url,
title: title,
shouldShowCaptionWarning: shouldShowCaptionWarning,
isRoomEncrypted: roomProxy.infoPublisher.value.isEncrypted))
}
override func process(viewAction: MediaUploadPreviewScreenViewAction) {
// Get the current caption before all the processing starts.
let caption = state.bindings.caption.nonBlankString
switch viewAction {
case .send:
startLoading()
Task {
switch await processingTask.value {
case .success(let mediaInfo):
switch await sendAttachment(mediaInfo: mediaInfo, caption: caption) {
case .success:
actionsSubject.send(.dismiss)
case .failure(let error):
MXLog.error("Failed sending attachment with error: \(error)")
showError(label: L10n.screenMediaUploadPreviewErrorFailedSending)
}
stopLoading()
case .failure(let error):
MXLog.error("Failed processing media to upload with error: \(error)")
showError(label: L10n.screenMediaUploadPreviewErrorFailedProcessing)
stopLoading()
}
}
case .cancel:
requestHandle?.cancel()
actionsSubject.send(.dismiss)
}
}
func stopProcessing() {
processingTask.cancel()
}
// MARK: - Private
private func sendAttachment(mediaInfo: MediaInfo, caption: String?) async -> Result<Void, TimelineProxyError> {
let requestHandle: ((SendAttachmentJoinHandleProtocol) -> Void) = { [weak self] handle in
self?.requestHandle = handle
}
switch mediaInfo {
case let .image(imageURL, thumbnailURL, imageInfo):
return await roomProxy.timeline.sendImage(url: imageURL,
thumbnailURL: thumbnailURL,
imageInfo: imageInfo,
caption: caption,
requestHandle: requestHandle)
case let .video(videoURL, thumbnailURL, videoInfo):
return await roomProxy.timeline.sendVideo(url: videoURL,
thumbnailURL: thumbnailURL,
videoInfo: videoInfo,
caption: caption,
requestHandle: requestHandle)
case let .audio(audioURL, audioInfo):
return await roomProxy.timeline.sendAudio(url: audioURL,
audioInfo: audioInfo,
caption: caption,
requestHandle: requestHandle)
case let .file(fileURL, fileInfo):
return await roomProxy.timeline.sendFile(url: fileURL,
fileInfo: fileInfo,
caption: caption,
requestHandle: requestHandle)
}
}
private static let loadingIndicatorIdentifier = "\(MediaUploadPreviewScreenViewModel.self)-Loading"
private func startLoading() {
userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier,
type: .modal(progress: .indeterminate, interactiveDismissDisabled: false, allowsInteraction: true),
title: L10n.commonSending,
persistent: true))
state.shouldDisableInteraction = true
}
private func stopLoading() {
userIndicatorController.retractIndicatorWithId(Self.loadingIndicatorIdentifier)
state.shouldDisableInteraction = false
requestHandle = nil
}
private func showError(label: String) {
userIndicatorController.submitIndicator(UserIndicator(title: label))
}
}
extension NSAttributedString {
var nonBlankString: String? {
guard !string.isBlank else { return nil }
return string
}
}