mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 10:33:45 +00:00
Add experimental native calls behind a developer flag (#6159)
Add the element-call-ios dependency and a developer option for native calls The package carries the call UI and the matrix-rust-rtc media stack, pinned by exact version the way the SDK is, with the local path kept commented out for working against a checkout. Its media xcframework has no Intel simulator slice and a package cannot say so for the projects that consume it, hence the excluded architecture at the project level. The developer option is off by default and nothing reads it yet. It is placed next to the Element Call URL override, which only applies to the web view that native calls replace.
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
import AVKit
|
||||
import Combine
|
||||
import Compound
|
||||
import ElementCall
|
||||
import SwiftState
|
||||
import SwiftUI
|
||||
|
||||
@@ -227,7 +228,6 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable:next function_body_length
|
||||
private func setupObservers() {
|
||||
chatsTabFlowCoordinator.actionsPublisher
|
||||
.sink { [weak self] action in
|
||||
@@ -316,17 +316,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
flowParameters.elementCallService.actions
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] action in
|
||||
switch action {
|
||||
case .endCall:
|
||||
self?.dismissCallScreenIfNeeded()
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
setupCallObservers()
|
||||
|
||||
searchScreenCoordinator?.actionsPublisher
|
||||
.sink { [weak self] action in
|
||||
@@ -458,6 +448,10 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
private func presentCallScreen(roomID: String, isVoiceCall: Bool) async {
|
||||
guard case let .joined(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomID) else {
|
||||
// An answered call is left up for the native stack, so it has to be ended here rather
|
||||
// than leaving the system with a call this room can no longer serve.
|
||||
MXLog.error("Cannot present the call screen, \(roomID) isn't a joined room")
|
||||
flowParameters.elementCallService.tearDownCallSession(roomID: roomID)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -477,6 +471,12 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
private var callScreenPictureInPictureController: AVPictureInPictureController?
|
||||
private func presentCallScreen(configuration: ElementCallConfiguration) {
|
||||
// The service runs native calls and drives their screen through its own actions.
|
||||
if flowParameters.elementCallService.handleNativeCallRequest(roomProxy: configuration.roomProxy,
|
||||
isVoiceCall: configuration.voiceOnly) {
|
||||
return
|
||||
}
|
||||
|
||||
guard flowParameters.ongoingCallRoomIDPublisher.value != configuration.callRoomID else {
|
||||
MXLog.info("Returning to existing call.")
|
||||
callScreenPictureInPictureController?.stopPictureInPicture()
|
||||
@@ -514,6 +514,11 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
|
||||
private func hideCallScreenOverlay() {
|
||||
if navigationTabCoordinator.overlayCoordinator is NativeCallScreenCoordinator {
|
||||
flowParameters.elementCallService.minimizeNativeCall()
|
||||
return
|
||||
}
|
||||
|
||||
guard let callScreenPictureInPictureController else {
|
||||
MXLog.warning("Picture in picture isn't available, dismissing the call screen.")
|
||||
dismissCallScreenIfNeeded()
|
||||
@@ -525,8 +530,66 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
navigationTabCoordinator.setOverlayPresentationMode(.minimized)
|
||||
}
|
||||
|
||||
// MARK: - Native calls
|
||||
|
||||
private func setupCallObservers() {
|
||||
flowParameters.elementCallService.actions
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
switch action {
|
||||
case .endCall:
|
||||
// A native call comes down on `.nativeCall(.dismiss)` instead, once it has
|
||||
// actually left the room.
|
||||
if navigationTabCoordinator.overlayCoordinator is CallScreenCoordinator {
|
||||
dismissCallScreenIfNeeded()
|
||||
}
|
||||
case .nativeCall(let presentation):
|
||||
handleNativeCall(presentation)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
private func handleNativeCall(_ presentation: NativeCallPresentation) {
|
||||
switch presentation {
|
||||
case .present:
|
||||
presentNativeCallScreen()
|
||||
case .restore:
|
||||
restoreNativeCallScreen()
|
||||
case .minimize:
|
||||
navigationTabCoordinator.setOverlayPresentationMode(.minimized)
|
||||
case .dismiss:
|
||||
dismissCallScreenIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
private func presentNativeCallScreen() {
|
||||
guard let controller = flowParameters.elementCallService.nativeCallController else {
|
||||
MXLog.error("Cannot present a native call without a call stack")
|
||||
return
|
||||
}
|
||||
|
||||
guard !(navigationTabCoordinator.overlayCoordinator is NativeCallScreenCoordinator) else {
|
||||
restoreNativeCallScreen()
|
||||
return
|
||||
}
|
||||
|
||||
let coordinator = NativeCallScreenCoordinator(parameters: .init(controller: controller))
|
||||
navigationTabCoordinator.setOverlayCoordinator(coordinator, animated: true)
|
||||
flowParameters.analytics.track(screen: .RoomCall)
|
||||
}
|
||||
|
||||
private func restoreNativeCallScreen() {
|
||||
flowParameters.elementCallService.restoreNativeCall()
|
||||
navigationTabCoordinator.setOverlayPresentationMode(.fullScreen)
|
||||
}
|
||||
|
||||
private func dismissCallScreenIfNeeded() {
|
||||
guard navigationTabCoordinator.overlayCoordinator is CallScreenCoordinator else {
|
||||
guard navigationTabCoordinator.overlayCoordinator is CallScreenCoordinator
|
||||
|| navigationTabCoordinator.overlayCoordinator is NativeCallScreenCoordinator else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user