Fixes #3137 - Delay starting ElementCall until a sync response comes in (or a 5 second timeout)

- this will ensure that the room state is up to date before sending any call related events
This commit is contained in:
Stefan Ceriu
2024-08-08 14:11:33 +03:00
committed by Stefan Ceriu
parent 0b984cc3eb
commit 0ad8f3cae8
2 changed files with 48 additions and 31 deletions
@@ -31,6 +31,8 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
actionsSubject.eraseToAnyPublisher() actionsSubject.eraseToAnyPublisher()
} }
private var syncUpdateCancellable: AnyCancellable?
/// Designated initialiser /// Designated initialiser
/// - Parameters: /// - Parameters:
/// - elementCallService: service responsible for setting up CallKit /// - elementCallService: service responsible for setting up CallKit
@@ -113,31 +115,42 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
} }
.store(in: &cancellables) .store(in: &cancellables)
Task { // Wait for room states to be up to date before starting the call and notifying others
let baseURL = if let elementCallBaseURLOverride { syncUpdateCancellable = clientProxy.actionsPublisher
elementCallBaseURLOverride .filter(\.isSyncUpdate)
} else if case .success(let wellKnown) = await clientProxy.getElementWellKnown(), let wellKnownCall = wellKnown?.call { .timeout(.seconds(5), scheduler: DispatchQueue.main)
wellKnownCall.widgetURL .first() // Timeout will make the publisher complete, use first to handle both branches in the same place
} else { .sink(receiveCompletion: { [weak self] _ in
elementCallBaseURL Task { [weak self] in
} guard let self else { return }
switch await widgetDriver.start(baseURL: baseURL, clientID: clientID, colorScheme: colorScheme) { let baseURL = if let elementCallBaseURLOverride {
case .success(let url): elementCallBaseURLOverride
state.url = url } else if case .success(let wellKnown) = await clientProxy.getElementWellKnown(), let wellKnownCall = wellKnown?.call {
case .failure(let error): wellKnownCall.widgetURL
MXLog.error("Failed starting ElementCall Widget Driver with error: \(error)") } else {
state.bindings.alertInfo = .init(id: UUID(), title: L10n.errorUnknown, primaryButton: .init(title: L10n.actionOk, action: { [weak self] in elementCallBaseURL
self?.actionsSubject.send(.dismiss) }
}))
switch await widgetDriver.start(baseURL: baseURL, clientID: clientID, colorScheme: colorScheme) {
return case .success(let url):
} state.url = url
case .failure(let error):
await elementCallService.setupCallSession(roomID: roomProxy.id, roomDisplayName: roomProxy.roomTitle) MXLog.error("Failed starting ElementCall Widget Driver with error: \(error)")
state.bindings.alertInfo = .init(id: UUID(), title: L10n.errorUnknown, primaryButton: .init(title: L10n.actionOk, action: { [weak self] in
let _ = await roomProxy.sendCallNotificationIfNeeeded() self?.actionsSubject.send(.dismiss)
} }))
return
}
await elementCallService.setupCallSession(roomID: roomProxy.id, roomDisplayName: roomProxy.roomTitle)
_ = await roomProxy.sendCallNotificationIfNeeeded()
syncUpdateCancellable = nil
}
}, receiveValue: { _ in })
} }
override func process(viewAction: CallScreenViewAction) { override func process(viewAction: CallScreenViewAction) {
@@ -22,12 +22,16 @@ struct CallScreen: View {
@ObservedObject var context: CallScreenViewModel.Context @ObservedObject var context: CallScreenViewModel.Context
var body: some View { var body: some View {
WebView(url: context.viewState.url, viewModelContext: context) if context.viewState.url == nil {
// This URL is stable, forces view reloads if this representable is ever reused for another url ProgressView()
.id(context.viewState.url) } else {
.ignoresSafeArea(edges: .bottom) WebView(url: context.viewState.url, viewModelContext: context)
.presentationDragIndicator(.visible) // This URL is stable, forces view reloads if this representable is ever reused for another url
.alert(item: $context.alertInfo) .id(context.viewState.url)
.ignoresSafeArea(edges: .bottom)
.presentationDragIndicator(.visible)
.alert(item: $context.alertInfo)
}
} }
} }