diff --git a/ElementX/Sources/Screens/CallScreen/CallScreenViewModel.swift b/ElementX/Sources/Screens/CallScreen/CallScreenViewModel.swift index e563f2f3f..a33536e72 100644 --- a/ElementX/Sources/Screens/CallScreen/CallScreenViewModel.swift +++ b/ElementX/Sources/Screens/CallScreen/CallScreenViewModel.swift @@ -31,6 +31,8 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol actionsSubject.eraseToAnyPublisher() } + private var syncUpdateCancellable: AnyCancellable? + /// Designated initialiser /// - Parameters: /// - elementCallService: service responsible for setting up CallKit @@ -113,31 +115,42 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol } .store(in: &cancellables) - Task { - let baseURL = if let elementCallBaseURLOverride { - elementCallBaseURLOverride - } else if case .success(let wellKnown) = await clientProxy.getElementWellKnown(), let wellKnownCall = wellKnown?.call { - wellKnownCall.widgetURL - } else { - elementCallBaseURL - } - - switch await widgetDriver.start(baseURL: baseURL, clientID: clientID, colorScheme: colorScheme) { - case .success(let url): - state.url = url - case .failure(let error): - 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 - self?.actionsSubject.send(.dismiss) - })) - - return - } - - await elementCallService.setupCallSession(roomID: roomProxy.id, roomDisplayName: roomProxy.roomTitle) - - let _ = await roomProxy.sendCallNotificationIfNeeeded() - } + // Wait for room states to be up to date before starting the call and notifying others + syncUpdateCancellable = clientProxy.actionsPublisher + .filter(\.isSyncUpdate) + .timeout(.seconds(5), scheduler: DispatchQueue.main) + .first() // Timeout will make the publisher complete, use first to handle both branches in the same place + .sink(receiveCompletion: { [weak self] _ in + Task { [weak self] in + guard let self else { return } + + let baseURL = if let elementCallBaseURLOverride { + elementCallBaseURLOverride + } else if case .success(let wellKnown) = await clientProxy.getElementWellKnown(), let wellKnownCall = wellKnown?.call { + wellKnownCall.widgetURL + } else { + elementCallBaseURL + } + + switch await widgetDriver.start(baseURL: baseURL, clientID: clientID, colorScheme: colorScheme) { + case .success(let url): + state.url = url + case .failure(let error): + 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 + 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) { diff --git a/ElementX/Sources/Screens/CallScreen/View/CallScreen.swift b/ElementX/Sources/Screens/CallScreen/View/CallScreen.swift index d0a809999..2ddd46436 100644 --- a/ElementX/Sources/Screens/CallScreen/View/CallScreen.swift +++ b/ElementX/Sources/Screens/CallScreen/View/CallScreen.swift @@ -22,12 +22,16 @@ struct CallScreen: View { @ObservedObject var context: CallScreenViewModel.Context var body: some View { - WebView(url: context.viewState.url, viewModelContext: context) - // This URL is stable, forces view reloads if this representable is ever reused for another url - .id(context.viewState.url) - .ignoresSafeArea(edges: .bottom) - .presentationDragIndicator(.visible) - .alert(item: $context.alertInfo) + if context.viewState.url == nil { + ProgressView() + } else { + WebView(url: context.viewState.url, viewModelContext: context) + // This URL is stable, forces view reloads if this representable is ever reused for another url + .id(context.viewState.url) + .ignoresSafeArea(edges: .bottom) + .presentationDragIndicator(.visible) + .alert(item: $context.alertInfo) + } } }