mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 21:39:12 +00:00
Add support for media uploading progress
- replace the ProgressTracker with a combination of currentValueSubjects and currentValuePublishers
This commit is contained in:
parent
9cf2aba16d
commit
8b11a0a5ec
@ -663,7 +663,6 @@
|
||||
F508683B76EF7B23BB2CBD6D /* TimelineItemPlainStylerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94BCC8A9C73C1F838122C645 /* TimelineItemPlainStylerView.swift */; };
|
||||
F519DE17A3A0F760307B2E6D /* InviteUsersScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02D155E09BF961BBA8F85263 /* InviteUsersScreenViewModel.swift */; };
|
||||
F54E2D6CAD96E1AC15BC526F /* MessageForwardingScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8E60332509665C00179ACF6 /* MessageForwardingScreenViewModel.swift */; };
|
||||
F587A9AF25A262DE5A7B0369 /* ProgressTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = F28551E81CE3700E5F1EC9B5 /* ProgressTracker.swift */; };
|
||||
F5D2270B5021D521C0D22E11 /* FlowCoordinatorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B9FCA1CFD07B8CF9BD21266 /* FlowCoordinatorProtocol.swift */; };
|
||||
F656F92A63D3DC1978D79427 /* Compound in Frameworks */ = {isa = PBXBuildFile; productRef = 07FEEEDB11543A7DED420F04 /* Compound */; };
|
||||
F6F49E37272AD7397CD29A01 /* HomeScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505208F28007C0FEC14E1FF0 /* HomeScreenViewModelTests.swift */; };
|
||||
@ -1337,7 +1336,6 @@
|
||||
F17EFA1D3D09FC2F9C5E1CB2 /* MediaProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProvider.swift; sourceTree = "<group>"; };
|
||||
F1964EE08550BEDBD0B0F5FD /* FilePreviewScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePreviewScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
F1B8500C152BC59445647DA8 /* UnsupportedRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsupportedRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||
F28551E81CE3700E5F1EC9B5 /* ProgressTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressTracker.swift; sourceTree = "<group>"; };
|
||||
F31F59030205A6F65B057E1A /* MatrixEntityRegexTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixEntityRegexTests.swift; sourceTree = "<group>"; };
|
||||
F348B5F2C12F9D4F4B4D3884 /* VideoRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||
F36C0A6D59717193F49EA986 /* UserSessionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionTests.swift; sourceTree = "<group>"; };
|
||||
@ -2983,7 +2981,6 @@
|
||||
6AD1A853D605C2146B0DC028 /* MatrixEntityRegex.swift */,
|
||||
C789E7BFC066CF39B8AE0974 /* NetworkMonitor.swift */,
|
||||
F754E66A8970963B15B2A41E /* PermalinkBuilder.swift */,
|
||||
F28551E81CE3700E5F1EC9B5 /* ProgressTracker.swift */,
|
||||
53482ECA4B6633961EC224F5 /* ScrollViewAdapter.swift */,
|
||||
DBA8DC95C079805B0B56E8A9 /* SharedUserDefaultsKeys.swift */,
|
||||
BB3073CCD77D906B330BC1D6 /* Tests.swift */,
|
||||
@ -4153,7 +4150,6 @@
|
||||
962A4F8AD6312804E2C6BB6E /* PhotoLibraryPicker.swift in Sources */,
|
||||
9D79B94493FB32249F7E472F /* PlaceholderAvatarImage.swift in Sources */,
|
||||
DF504B10A4918F971A57BEF2 /* PostHogAnalyticsClient.swift in Sources */,
|
||||
F587A9AF25A262DE5A7B0369 /* ProgressTracker.swift in Sources */,
|
||||
2835FD52F3F618D07F799B3D /* Publisher.swift in Sources */,
|
||||
743790BF6A5B0577EA74AF14 /* ReadMarkerRoomTimelineItem.swift in Sources */,
|
||||
8EF63DDDC1B54F122070B04D /* ReadMarkerRoomTimelineView.swift in Sources */,
|
||||
|
@ -177,12 +177,12 @@ class BugReportServiceMock: BugReportServiceProtocol {
|
||||
var submitBugReportProgressListenerCalled: Bool {
|
||||
return submitBugReportProgressListenerCallsCount > 0
|
||||
}
|
||||
var submitBugReportProgressListenerReceivedArguments: (bugReport: BugReport, progressListener: ProgressListener?)?
|
||||
var submitBugReportProgressListenerReceivedInvocations: [(bugReport: BugReport, progressListener: ProgressListener?)] = []
|
||||
var submitBugReportProgressListenerReceivedArguments: (bugReport: BugReport, progressListener: CurrentValueSubject<Double, Never>)?
|
||||
var submitBugReportProgressListenerReceivedInvocations: [(bugReport: BugReport, progressListener: CurrentValueSubject<Double, Never>)] = []
|
||||
var submitBugReportProgressListenerReturnValue: Result<SubmitBugReportResponse, BugReportServiceError>!
|
||||
var submitBugReportProgressListenerClosure: ((BugReport, ProgressListener?) async -> Result<SubmitBugReportResponse, BugReportServiceError>)?
|
||||
var submitBugReportProgressListenerClosure: ((BugReport, CurrentValueSubject<Double, Never>) async -> Result<SubmitBugReportResponse, BugReportServiceError>)?
|
||||
|
||||
func submitBugReport(_ bugReport: BugReport, progressListener: ProgressListener?) async -> Result<SubmitBugReportResponse, BugReportServiceError> {
|
||||
func submitBugReport(_ bugReport: BugReport, progressListener: CurrentValueSubject<Double, Never>) async -> Result<SubmitBugReportResponse, BugReportServiceError> {
|
||||
submitBugReportProgressListenerCallsCount += 1
|
||||
submitBugReportProgressListenerReceivedArguments = (bugReport: bugReport, progressListener: progressListener)
|
||||
submitBugReportProgressListenerReceivedInvocations.append((bugReport: bugReport, progressListener: progressListener))
|
||||
@ -633,86 +633,86 @@ class RoomProxyMock: RoomProxyProtocol {
|
||||
}
|
||||
//MARK: - sendImage
|
||||
|
||||
var sendImageUrlThumbnailURLImageInfoCallsCount = 0
|
||||
var sendImageUrlThumbnailURLImageInfoCalled: Bool {
|
||||
return sendImageUrlThumbnailURLImageInfoCallsCount > 0
|
||||
var sendImageUrlThumbnailURLImageInfoProgressSubjectCallsCount = 0
|
||||
var sendImageUrlThumbnailURLImageInfoProgressSubjectCalled: Bool {
|
||||
return sendImageUrlThumbnailURLImageInfoProgressSubjectCallsCount > 0
|
||||
}
|
||||
var sendImageUrlThumbnailURLImageInfoReceivedArguments: (url: URL, thumbnailURL: URL, imageInfo: ImageInfo)?
|
||||
var sendImageUrlThumbnailURLImageInfoReceivedInvocations: [(url: URL, thumbnailURL: URL, imageInfo: ImageInfo)] = []
|
||||
var sendImageUrlThumbnailURLImageInfoReturnValue: Result<Void, RoomProxyError>!
|
||||
var sendImageUrlThumbnailURLImageInfoClosure: ((URL, URL, ImageInfo) async -> Result<Void, RoomProxyError>)?
|
||||
var sendImageUrlThumbnailURLImageInfoProgressSubjectReceivedArguments: (url: URL, thumbnailURL: URL, imageInfo: ImageInfo, progressSubject: CurrentValueSubject<Double, Never>?)?
|
||||
var sendImageUrlThumbnailURLImageInfoProgressSubjectReceivedInvocations: [(url: URL, thumbnailURL: URL, imageInfo: ImageInfo, progressSubject: CurrentValueSubject<Double, Never>?)] = []
|
||||
var sendImageUrlThumbnailURLImageInfoProgressSubjectReturnValue: Result<Void, RoomProxyError>!
|
||||
var sendImageUrlThumbnailURLImageInfoProgressSubjectClosure: ((URL, URL, ImageInfo, CurrentValueSubject<Double, Never>?) async -> Result<Void, RoomProxyError>)?
|
||||
|
||||
func sendImage(url: URL, thumbnailURL: URL, imageInfo: ImageInfo) async -> Result<Void, RoomProxyError> {
|
||||
sendImageUrlThumbnailURLImageInfoCallsCount += 1
|
||||
sendImageUrlThumbnailURLImageInfoReceivedArguments = (url: url, thumbnailURL: thumbnailURL, imageInfo: imageInfo)
|
||||
sendImageUrlThumbnailURLImageInfoReceivedInvocations.append((url: url, thumbnailURL: thumbnailURL, imageInfo: imageInfo))
|
||||
if let sendImageUrlThumbnailURLImageInfoClosure = sendImageUrlThumbnailURLImageInfoClosure {
|
||||
return await sendImageUrlThumbnailURLImageInfoClosure(url, thumbnailURL, imageInfo)
|
||||
func sendImage(url: URL, thumbnailURL: URL, imageInfo: ImageInfo, progressSubject: CurrentValueSubject<Double, Never>?) async -> Result<Void, RoomProxyError> {
|
||||
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)
|
||||
} else {
|
||||
return sendImageUrlThumbnailURLImageInfoReturnValue
|
||||
return sendImageUrlThumbnailURLImageInfoProgressSubjectReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - sendVideo
|
||||
|
||||
var sendVideoUrlThumbnailURLVideoInfoCallsCount = 0
|
||||
var sendVideoUrlThumbnailURLVideoInfoCalled: Bool {
|
||||
return sendVideoUrlThumbnailURLVideoInfoCallsCount > 0
|
||||
var sendVideoUrlThumbnailURLVideoInfoProgressSubjectCallsCount = 0
|
||||
var sendVideoUrlThumbnailURLVideoInfoProgressSubjectCalled: Bool {
|
||||
return sendVideoUrlThumbnailURLVideoInfoProgressSubjectCallsCount > 0
|
||||
}
|
||||
var sendVideoUrlThumbnailURLVideoInfoReceivedArguments: (url: URL, thumbnailURL: URL, videoInfo: VideoInfo)?
|
||||
var sendVideoUrlThumbnailURLVideoInfoReceivedInvocations: [(url: URL, thumbnailURL: URL, videoInfo: VideoInfo)] = []
|
||||
var sendVideoUrlThumbnailURLVideoInfoReturnValue: Result<Void, RoomProxyError>!
|
||||
var sendVideoUrlThumbnailURLVideoInfoClosure: ((URL, URL, VideoInfo) async -> Result<Void, RoomProxyError>)?
|
||||
var sendVideoUrlThumbnailURLVideoInfoProgressSubjectReceivedArguments: (url: URL, thumbnailURL: URL, videoInfo: VideoInfo, progressSubject: CurrentValueSubject<Double, Never>?)?
|
||||
var sendVideoUrlThumbnailURLVideoInfoProgressSubjectReceivedInvocations: [(url: URL, thumbnailURL: URL, videoInfo: VideoInfo, progressSubject: CurrentValueSubject<Double, Never>?)] = []
|
||||
var sendVideoUrlThumbnailURLVideoInfoProgressSubjectReturnValue: Result<Void, RoomProxyError>!
|
||||
var sendVideoUrlThumbnailURLVideoInfoProgressSubjectClosure: ((URL, URL, VideoInfo, CurrentValueSubject<Double, Never>?) async -> Result<Void, RoomProxyError>)?
|
||||
|
||||
func sendVideo(url: URL, thumbnailURL: URL, videoInfo: VideoInfo) async -> Result<Void, RoomProxyError> {
|
||||
sendVideoUrlThumbnailURLVideoInfoCallsCount += 1
|
||||
sendVideoUrlThumbnailURLVideoInfoReceivedArguments = (url: url, thumbnailURL: thumbnailURL, videoInfo: videoInfo)
|
||||
sendVideoUrlThumbnailURLVideoInfoReceivedInvocations.append((url: url, thumbnailURL: thumbnailURL, videoInfo: videoInfo))
|
||||
if let sendVideoUrlThumbnailURLVideoInfoClosure = sendVideoUrlThumbnailURLVideoInfoClosure {
|
||||
return await sendVideoUrlThumbnailURLVideoInfoClosure(url, thumbnailURL, videoInfo)
|
||||
func sendVideo(url: URL, thumbnailURL: URL, videoInfo: VideoInfo, progressSubject: CurrentValueSubject<Double, Never>?) async -> Result<Void, RoomProxyError> {
|
||||
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)
|
||||
} else {
|
||||
return sendVideoUrlThumbnailURLVideoInfoReturnValue
|
||||
return sendVideoUrlThumbnailURLVideoInfoProgressSubjectReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - sendAudio
|
||||
|
||||
var sendAudioUrlAudioInfoCallsCount = 0
|
||||
var sendAudioUrlAudioInfoCalled: Bool {
|
||||
return sendAudioUrlAudioInfoCallsCount > 0
|
||||
var sendAudioUrlAudioInfoProgressSubjectCallsCount = 0
|
||||
var sendAudioUrlAudioInfoProgressSubjectCalled: Bool {
|
||||
return sendAudioUrlAudioInfoProgressSubjectCallsCount > 0
|
||||
}
|
||||
var sendAudioUrlAudioInfoReceivedArguments: (url: URL, audioInfo: AudioInfo)?
|
||||
var sendAudioUrlAudioInfoReceivedInvocations: [(url: URL, audioInfo: AudioInfo)] = []
|
||||
var sendAudioUrlAudioInfoReturnValue: Result<Void, RoomProxyError>!
|
||||
var sendAudioUrlAudioInfoClosure: ((URL, AudioInfo) async -> Result<Void, RoomProxyError>)?
|
||||
var sendAudioUrlAudioInfoProgressSubjectReceivedArguments: (url: URL, audioInfo: AudioInfo, progressSubject: CurrentValueSubject<Double, Never>?)?
|
||||
var sendAudioUrlAudioInfoProgressSubjectReceivedInvocations: [(url: URL, audioInfo: AudioInfo, progressSubject: CurrentValueSubject<Double, Never>?)] = []
|
||||
var sendAudioUrlAudioInfoProgressSubjectReturnValue: Result<Void, RoomProxyError>!
|
||||
var sendAudioUrlAudioInfoProgressSubjectClosure: ((URL, AudioInfo, CurrentValueSubject<Double, Never>?) async -> Result<Void, RoomProxyError>)?
|
||||
|
||||
func sendAudio(url: URL, audioInfo: AudioInfo) async -> Result<Void, RoomProxyError> {
|
||||
sendAudioUrlAudioInfoCallsCount += 1
|
||||
sendAudioUrlAudioInfoReceivedArguments = (url: url, audioInfo: audioInfo)
|
||||
sendAudioUrlAudioInfoReceivedInvocations.append((url: url, audioInfo: audioInfo))
|
||||
if let sendAudioUrlAudioInfoClosure = sendAudioUrlAudioInfoClosure {
|
||||
return await sendAudioUrlAudioInfoClosure(url, audioInfo)
|
||||
func sendAudio(url: URL, audioInfo: AudioInfo, progressSubject: CurrentValueSubject<Double, Never>?) async -> Result<Void, RoomProxyError> {
|
||||
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)
|
||||
} else {
|
||||
return sendAudioUrlAudioInfoReturnValue
|
||||
return sendAudioUrlAudioInfoProgressSubjectReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - sendFile
|
||||
|
||||
var sendFileUrlFileInfoCallsCount = 0
|
||||
var sendFileUrlFileInfoCalled: Bool {
|
||||
return sendFileUrlFileInfoCallsCount > 0
|
||||
var sendFileUrlFileInfoProgressSubjectCallsCount = 0
|
||||
var sendFileUrlFileInfoProgressSubjectCalled: Bool {
|
||||
return sendFileUrlFileInfoProgressSubjectCallsCount > 0
|
||||
}
|
||||
var sendFileUrlFileInfoReceivedArguments: (url: URL, fileInfo: FileInfo)?
|
||||
var sendFileUrlFileInfoReceivedInvocations: [(url: URL, fileInfo: FileInfo)] = []
|
||||
var sendFileUrlFileInfoReturnValue: Result<Void, RoomProxyError>!
|
||||
var sendFileUrlFileInfoClosure: ((URL, FileInfo) async -> Result<Void, RoomProxyError>)?
|
||||
var sendFileUrlFileInfoProgressSubjectReceivedArguments: (url: URL, fileInfo: FileInfo, progressSubject: CurrentValueSubject<Double, Never>?)?
|
||||
var sendFileUrlFileInfoProgressSubjectReceivedInvocations: [(url: URL, fileInfo: FileInfo, progressSubject: CurrentValueSubject<Double, Never>?)] = []
|
||||
var sendFileUrlFileInfoProgressSubjectReturnValue: Result<Void, RoomProxyError>!
|
||||
var sendFileUrlFileInfoProgressSubjectClosure: ((URL, FileInfo, CurrentValueSubject<Double, Never>?) async -> Result<Void, RoomProxyError>)?
|
||||
|
||||
func sendFile(url: URL, fileInfo: FileInfo) async -> Result<Void, RoomProxyError> {
|
||||
sendFileUrlFileInfoCallsCount += 1
|
||||
sendFileUrlFileInfoReceivedArguments = (url: url, fileInfo: fileInfo)
|
||||
sendFileUrlFileInfoReceivedInvocations.append((url: url, fileInfo: fileInfo))
|
||||
if let sendFileUrlFileInfoClosure = sendFileUrlFileInfoClosure {
|
||||
return await sendFileUrlFileInfoClosure(url, fileInfo)
|
||||
func sendFile(url: URL, fileInfo: FileInfo, progressSubject: CurrentValueSubject<Double, Never>?) async -> Result<Void, RoomProxyError> {
|
||||
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)
|
||||
} else {
|
||||
return sendFileUrlFileInfoReturnValue
|
||||
return sendFileUrlFileInfoProgressSubjectReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - retrySend
|
||||
|
@ -1,39 +0,0 @@
|
||||
//
|
||||
// Copyright 2023 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
protocol ProgressListener {
|
||||
var progressSubject: CurrentValueSubject<Double, Never> { get }
|
||||
}
|
||||
|
||||
protocol ProgressPublisher: AnyObject {
|
||||
var publisher: AnyPublisher<Double, Never> { get }
|
||||
}
|
||||
|
||||
final class ProgressTracker: ProgressListener, ProgressPublisher {
|
||||
let progressSubject: CurrentValueSubject<Double, Never>
|
||||
|
||||
var publisher: AnyPublisher<Double, Never> {
|
||||
progressSubject
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(initialValue: Double = 0.0) {
|
||||
progressSubject = .init(initialValue)
|
||||
}
|
||||
}
|
@ -30,13 +30,13 @@ struct UserIndicator: Equatable, Identifiable {
|
||||
static func == (lhs: UserIndicator.Progress, rhs: UserIndicator.Progress) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case (.indeterminate, .indeterminate): return true
|
||||
case (.published(let lhsPublisher), .published(let rhsPublisher)): return lhsPublisher === rhsPublisher
|
||||
case (.published(let lhsPublisher), .published(let rhsPublisher)): return lhsPublisher.value == rhsPublisher.value
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
|
||||
case indeterminate
|
||||
case published(ProgressPublisher)
|
||||
case published(CurrentValuePublisher<Double, Never>)
|
||||
}
|
||||
|
||||
var id: String = UUID().uuidString
|
||||
@ -54,14 +54,14 @@ struct UserIndicator: Equatable, Identifiable {
|
||||
}
|
||||
}
|
||||
|
||||
var progressPublisher: AnyPublisher<Double, Never> {
|
||||
var progressPublisher: CurrentValuePublisher<Double, Never> {
|
||||
switch type {
|
||||
case .toast(let progress), .modal(let progress, _):
|
||||
switch progress {
|
||||
case .none, .indeterminate:
|
||||
return Empty().eraseToAnyPublisher()
|
||||
case .some(.published(let progress)):
|
||||
return progress.publisher.eraseToAnyPublisher()
|
||||
return CurrentValueSubject<Double, Never>(0.0).asCurrentValuePublisher()
|
||||
case .some(.published(let publisher)):
|
||||
return publisher
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ struct UserIndicatorModalView_Previews: PreviewProvider {
|
||||
)
|
||||
.previewDisplayName("Spinner")
|
||||
|
||||
UserIndicatorModalView(indicator: UserIndicator(type: .modal(progress: .published(ProgressTracker(initialValue: 0.5)),
|
||||
UserIndicatorModalView(indicator: UserIndicator(type: .modal(progress: .published(CurrentValueSubject<Double, Never>(0.5).asCurrentValuePublisher()),
|
||||
interactiveDismissDisabled: false),
|
||||
title: "Successfully logged in",
|
||||
iconName: "checkmark")
|
||||
|
@ -60,8 +60,8 @@ final class BugReportScreenCoordinator: CoordinatorProtocol {
|
||||
switch result {
|
||||
case .cancel:
|
||||
self.completion?(.cancel)
|
||||
case let .submitStarted(progressTracker):
|
||||
self.startLoading(label: L10n.commonSending, progressPublisher: progressTracker)
|
||||
case let .submitStarted(progressPublisher):
|
||||
self.startLoading(label: L10n.commonSending, progressPublisher: progressPublisher)
|
||||
case .submitFinished:
|
||||
self.stopLoading()
|
||||
self.completion?(.finish)
|
||||
@ -85,7 +85,7 @@ final class BugReportScreenCoordinator: CoordinatorProtocol {
|
||||
|
||||
private static let loadingIndicatorIdentifier = "BugReportLoading"
|
||||
|
||||
private func startLoading(label: String = L10n.commonLoading, progressPublisher: ProgressPublisher) {
|
||||
private func startLoading(label: String = L10n.commonLoading, progressPublisher: CurrentValuePublisher<Double, Never>) {
|
||||
parameters.userIndicatorController?.submitIndicator(
|
||||
UserIndicator(id: Self.loadingIndicatorIdentifier,
|
||||
type: .modal(progress: .published(progressPublisher), interactiveDismissDisabled: false),
|
||||
|
@ -19,7 +19,7 @@ import UIKit
|
||||
|
||||
enum BugReportScreenViewModelAction {
|
||||
case cancel
|
||||
case submitStarted(progressTracker: ProgressTracker)
|
||||
case submitStarted(progressPublisher: CurrentValuePublisher<Double, Never>)
|
||||
case submitFinished
|
||||
case submitFailed(error: Error)
|
||||
}
|
||||
|
@ -62,8 +62,9 @@ class BugReportScreenViewModel: BugReportScreenViewModelType, BugReportScreenVie
|
||||
// MARK: Private
|
||||
|
||||
private func submitBugReport() async {
|
||||
let progressTracker = ProgressTracker()
|
||||
actionsSubject.send(.submitStarted(progressTracker: progressTracker))
|
||||
let progressSubject = CurrentValueSubject<Double, Never>(0.0)
|
||||
|
||||
actionsSubject.send(.submitStarted(progressPublisher: progressSubject.asCurrentValuePublisher()))
|
||||
|
||||
var files: [URL] = []
|
||||
if let screenshot = context.viewState.screenshot,
|
||||
@ -87,7 +88,7 @@ class BugReportScreenViewModel: BugReportScreenViewModelType, BugReportScreenVie
|
||||
files: files)
|
||||
|
||||
switch await bugReportService.submitBugReport(bugReport,
|
||||
progressListener: progressTracker) {
|
||||
progressListener: progressSubject) {
|
||||
case .success(let response):
|
||||
MXLog.info("Submission uploaded to: \(response.reportUrl)")
|
||||
actionsSubject.send(.submitFinished)
|
||||
|
@ -14,6 +14,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
typealias MediaUploadPreviewScreenViewModelType = StateStoreViewModel<MediaUploadPreviewScreenViewState, MediaUploadPreviewScreenViewAction>
|
||||
@ -43,11 +44,13 @@ class MediaUploadPreviewScreenViewModel: MediaUploadPreviewScreenViewModelType,
|
||||
switch viewAction {
|
||||
case .send:
|
||||
Task {
|
||||
startLoading()
|
||||
let progressSubject = CurrentValueSubject<Double, Never>(0.0)
|
||||
|
||||
startLoading(progressPublisher: progressSubject.asCurrentValuePublisher())
|
||||
|
||||
switch await mediaUploadingPreprocessor.processMedia(at: url) {
|
||||
case .success(let mediaInfo):
|
||||
switch await sendAttachment(mediaInfo: mediaInfo) {
|
||||
switch await sendAttachment(mediaInfo: mediaInfo, progressSubject: progressSubject) {
|
||||
case .success:
|
||||
callback?(.dismiss)
|
||||
case .failure(let error):
|
||||
@ -70,26 +73,26 @@ class MediaUploadPreviewScreenViewModel: MediaUploadPreviewScreenViewModelType,
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func sendAttachment(mediaInfo: MediaInfo) async -> Result<Void, RoomProxyError> {
|
||||
private func sendAttachment(mediaInfo: MediaInfo, progressSubject: CurrentValueSubject<Double, Never>) async -> Result<Void, RoomProxyError> {
|
||||
switch mediaInfo {
|
||||
case let .image(imageURL, thumbnailURL, imageInfo):
|
||||
return await roomProxy.sendImage(url: imageURL, thumbnailURL: thumbnailURL, imageInfo: imageInfo)
|
||||
return await roomProxy.sendImage(url: imageURL, thumbnailURL: thumbnailURL, imageInfo: imageInfo, progressSubject: progressSubject)
|
||||
case let .video(videoURL, thumbnailURL, videoInfo):
|
||||
return await roomProxy.sendVideo(url: videoURL, thumbnailURL: thumbnailURL, videoInfo: videoInfo)
|
||||
return await roomProxy.sendVideo(url: videoURL, thumbnailURL: thumbnailURL, videoInfo: videoInfo, progressSubject: progressSubject)
|
||||
case let .audio(audioURL, audioInfo):
|
||||
return await roomProxy.sendAudio(url: audioURL, audioInfo: audioInfo)
|
||||
return await roomProxy.sendAudio(url: audioURL, audioInfo: audioInfo, progressSubject: progressSubject)
|
||||
case let .file(fileURL, fileInfo):
|
||||
return await roomProxy.sendFile(url: fileURL, fileInfo: fileInfo)
|
||||
return await roomProxy.sendFile(url: fileURL, fileInfo: fileInfo, progressSubject: progressSubject)
|
||||
}
|
||||
}
|
||||
|
||||
private static let loadingIndicatorIdentifier = "MediaUploadPreviewLoading"
|
||||
|
||||
private func startLoading() {
|
||||
private func startLoading(progressPublisher: CurrentValuePublisher<Double, Never>) {
|
||||
userIndicatorController?.submitIndicator(
|
||||
UserIndicator(id: Self.loadingIndicatorIdentifier,
|
||||
type: .modal,
|
||||
title: L10n.commonLoading,
|
||||
type: .modal(progress: .published(progressPublisher), interactiveDismissDisabled: false),
|
||||
title: L10n.commonSending,
|
||||
persistent: true)
|
||||
)
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ class BugReportService: NSObject, BugReportServiceProtocol {
|
||||
|
||||
// swiftlint:disable:next function_body_length cyclomatic_complexity
|
||||
func submitBugReport(_ bugReport: BugReport,
|
||||
progressListener: ProgressListener?) async -> Result<SubmitBugReportResponse, BugReportServiceError> {
|
||||
progressListener: CurrentValueSubject<Double, Never>) async -> Result<SubmitBugReportResponse, BugReportServiceError> {
|
||||
var params = [
|
||||
MultipartFormData(key: "user_id", type: .text(value: bugReport.userID)),
|
||||
MultipartFormData(key: "text", type: .text(value: bugReport.text))
|
||||
@ -148,17 +148,13 @@ class BugReportService: NSObject, BugReportServiceProtocol {
|
||||
request.httpMethod = "POST"
|
||||
request.httpBody = body as Data
|
||||
|
||||
var delegate: URLSessionTaskDelegate?
|
||||
if let progressListener {
|
||||
progressSubject
|
||||
.receive(on: DispatchQueue.main)
|
||||
.weakAssign(to: \.value, on: progressListener.progressSubject)
|
||||
.store(in: &cancellables)
|
||||
delegate = self
|
||||
}
|
||||
progressSubject
|
||||
.receive(on: DispatchQueue.main)
|
||||
.weakAssign(to: \.value, on: progressListener)
|
||||
.store(in: &cancellables)
|
||||
|
||||
do {
|
||||
let (data, response) = try await session.dataWithRetry(for: request, delegate: delegate)
|
||||
let (data, response) = try await session.dataWithRetry(for: request, delegate: self)
|
||||
|
||||
guard let httpResponse = response as? HTTPURLResponse else {
|
||||
let errorDescription = String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "Unknown"
|
||||
|
@ -14,6 +14,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
@ -63,5 +64,5 @@ protocol BugReportServiceProtocol {
|
||||
func crash()
|
||||
|
||||
func submitBugReport(_ bugReport: BugReport,
|
||||
progressListener: ProgressListener?) async -> Result<SubmitBugReportResponse, BugReportServiceError>
|
||||
progressListener: CurrentValueSubject<Double, Never>) async -> Result<SubmitBugReportResponse, BugReportServiceError>
|
||||
}
|
||||
|
@ -276,7 +276,7 @@ class RoomProxy: RoomProxyProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func sendImage(url: URL, thumbnailURL: URL, imageInfo: ImageInfo) async -> Result<Void, RoomProxyError> {
|
||||
func sendImage(url: URL, thumbnailURL: URL, imageInfo: ImageInfo, progressSubject: CurrentValueSubject<Double, Never>?) async -> Result<Void, RoomProxyError> {
|
||||
sendMessageBackgroundTask = backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
@ -284,7 +284,9 @@ class RoomProxy: RoomProxyProtocol {
|
||||
|
||||
return await Task.dispatch(on: userInitiatedDispatchQueue) {
|
||||
do {
|
||||
try self.room.sendImage(url: url.path(), thumbnailUrl: thumbnailURL.path(), imageInfo: imageInfo, progressWatcher: nil)
|
||||
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)
|
||||
@ -292,7 +294,7 @@ class RoomProxy: RoomProxyProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func sendVideo(url: URL, thumbnailURL: URL, videoInfo: VideoInfo) async -> Result<Void, RoomProxyError> {
|
||||
func sendVideo(url: URL, thumbnailURL: URL, videoInfo: VideoInfo, progressSubject: CurrentValueSubject<Double, Never>?) async -> Result<Void, RoomProxyError> {
|
||||
sendMessageBackgroundTask = backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
@ -300,7 +302,9 @@ class RoomProxy: RoomProxyProtocol {
|
||||
|
||||
return await Task.dispatch(on: userInitiatedDispatchQueue) {
|
||||
do {
|
||||
try self.room.sendVideo(url: url.path(), thumbnailUrl: thumbnailURL.path(), videoInfo: videoInfo, progressWatcher: nil)
|
||||
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)
|
||||
@ -308,7 +312,7 @@ class RoomProxy: RoomProxyProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func sendAudio(url: URL, audioInfo: AudioInfo) async -> Result<Void, RoomProxyError> {
|
||||
func sendAudio(url: URL, audioInfo: AudioInfo, progressSubject: CurrentValueSubject<Double, Never>?) async -> Result<Void, RoomProxyError> {
|
||||
sendMessageBackgroundTask = backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
@ -316,7 +320,9 @@ class RoomProxy: RoomProxyProtocol {
|
||||
|
||||
return await Task.dispatch(on: userInitiatedDispatchQueue) {
|
||||
do {
|
||||
try self.room.sendAudio(url: url.path(), audioInfo: audioInfo, progressWatcher: nil)
|
||||
try self.room.sendAudio(url: url.path(), audioInfo: audioInfo, progressWatcher: UploadProgressListener { progress in
|
||||
progressSubject?.send(progress)
|
||||
})
|
||||
return .success(())
|
||||
} catch {
|
||||
return .failure(.failedSendingMedia)
|
||||
@ -324,7 +330,7 @@ class RoomProxy: RoomProxyProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func sendFile(url: URL, fileInfo: FileInfo) async -> Result<Void, RoomProxyError> {
|
||||
func sendFile(url: URL, fileInfo: FileInfo, progressSubject: CurrentValueSubject<Double, Never>?) async -> Result<Void, RoomProxyError> {
|
||||
sendMessageBackgroundTask = backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
@ -332,7 +338,9 @@ class RoomProxy: RoomProxyProtocol {
|
||||
|
||||
return await Task.dispatch(on: userInitiatedDispatchQueue) {
|
||||
do {
|
||||
try self.room.sendFile(url: url.path(), fileInfo: fileInfo, progressWatcher: nil)
|
||||
try self.room.sendFile(url: url.path(), fileInfo: fileInfo, progressWatcher: UploadProgressListener { progress in
|
||||
progressSubject?.send(progress)
|
||||
})
|
||||
return .success(())
|
||||
} catch {
|
||||
return .failure(.failedSendingMedia)
|
||||
@ -611,3 +619,17 @@ private class RoomTimelineListener: TimelineListener {
|
||||
onUpdateClosure(diff)
|
||||
}
|
||||
}
|
||||
|
||||
private class UploadProgressListener: ProgressWatcher {
|
||||
private let onUpdateClosure: (Double) -> Void
|
||||
|
||||
init(_ onUpdateClosure: @escaping (Double) -> Void) {
|
||||
self.onUpdateClosure = onUpdateClosure
|
||||
}
|
||||
|
||||
func transmissionProgress(progress: TransmissionProgress) {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.onUpdateClosure(Double(progress.current) / Double(progress.total))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,13 +93,13 @@ protocol RoomProxyProtocol {
|
||||
|
||||
func sendReaction(_ reaction: String, to eventID: String) async -> Result<Void, RoomProxyError>
|
||||
|
||||
func sendImage(url: URL, thumbnailURL: URL, imageInfo: ImageInfo) async -> Result<Void, RoomProxyError>
|
||||
func sendImage(url: URL, thumbnailURL: URL, imageInfo: ImageInfo, progressSubject: CurrentValueSubject<Double, Never>?) async -> Result<Void, RoomProxyError>
|
||||
|
||||
func sendVideo(url: URL, thumbnailURL: URL, videoInfo: VideoInfo) async -> Result<Void, RoomProxyError>
|
||||
func sendVideo(url: URL, thumbnailURL: URL, videoInfo: VideoInfo, progressSubject: CurrentValueSubject<Double, Never>?) async -> Result<Void, RoomProxyError>
|
||||
|
||||
func sendAudio(url: URL, audioInfo: AudioInfo) async -> Result<Void, RoomProxyError>
|
||||
func sendAudio(url: URL, audioInfo: AudioInfo, progressSubject: CurrentValueSubject<Double, Never>?) async -> Result<Void, RoomProxyError>
|
||||
|
||||
func sendFile(url: URL, fileInfo: FileInfo) async -> Result<Void, RoomProxyError>
|
||||
func sendFile(url: URL, fileInfo: FileInfo, progressSubject: CurrentValueSubject<Double, Never>?) async -> Result<Void, RoomProxyError>
|
||||
|
||||
/// Retries sending a failed message given its transaction ID
|
||||
func retrySend(transactionID: String) async
|
||||
|
Loading…
x
Reference in New Issue
Block a user