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:
Valere Fedronic
2026-09-17 18:42:18 +02:00
committed by GitHub
parent fe18472556
commit fb49f5b83b
33 changed files with 1778 additions and 160 deletions
@@ -137,7 +137,7 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
await hangup()
}
elementCallService.tearDownCallSession()
elementCallService.tearDownCallSession(roomID: configuration.callRoomID)
UIDevice.current.isProximityMonitoringEnabled = false
}
@@ -196,7 +196,8 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
}
await elementCallService.setupCallSession(roomID: configuration.roomProxy.id,
roomDisplayName: configuration.roomProxy.infoPublisher.value.displayName ?? configuration.roomProxy.id)
roomDisplayName: configuration.roomProxy.infoPublisher.value.displayNameOrID,
isVideo: !configuration.voiceOnly)
}
timeoutTask = Task { [weak self] in
@@ -0,0 +1,26 @@
//
// Copyright 2026 Element Creations 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 ElementCall
import SwiftUI
struct NativeCallScreenCoordinatorParameters {
let controller: ElementCallController
}
final class NativeCallScreenCoordinator: CoordinatorProtocol {
private let viewModel: ElementCallScreenViewModel
init(parameters: NativeCallScreenCoordinatorParameters) {
viewModel = ElementCallScreenViewModel(controller: parameters.controller)
}
func toPresentable() -> AnyView {
AnyView(ElementCallScreen(viewModel: viewModel))
}
}
@@ -67,7 +67,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
self.initialSelectedPinnedEventID = initialSelectedPinnedEventID
pinnedEventStringBuilder = .pinnedEventStringBuilder(userID: roomProxy.ownUserID)
let viewState = RoomScreenViewState(roomTitle: roomProxy.infoPublisher.value.displayName ?? roomProxy.id,
let viewState = RoomScreenViewState(roomTitle: roomProxy.infoPublisher.value.displayNameOrID,
roomAvatar: roomProxy.infoPublisher.value.avatar,
hasOngoingCall: roomProxy.infoPublisher.value.hasRoomCall,
isDM: roomProxy.infoPublisher.value.isDM,
@@ -336,7 +336,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
}
private func updateRoomInfo(_ roomInfo: RoomInfoProxyProtocol) {
state.roomTitle = roomInfo.displayName ?? roomProxy.id
state.roomTitle = roomInfo.displayNameOrID
state.roomAvatar = roomInfo.avatar
state.dmRecipientDetails.statusEmoji = roomInfo.statusEmoji
state.hasOngoingCall = roomInfo.hasRoomCall
@@ -74,6 +74,8 @@ protocol DeveloperOptionsProtocol: AnyObject {
var linkNewDeviceEnabled: Bool { get set }
var globalSearchEnabled: Bool { get set }
var nativeCallEnabled: Bool { get set }
}
extension AppSettings: DeveloperOptionsProtocol { }
@@ -120,7 +120,7 @@ struct DeveloperOptionsScreen: View {
Text("This setting controls how end-to-end encryption (E2EE) keys are exchanged. Enabling it will prevent the inclusion of devices that have not been explicitly verified by their owners.")
}
Section("Element Call remote URL override") {
Section {
TextField("Leave empty to use EC locally", text: $elementCallURLOverrideString)
.autocorrectionDisabled(true)
.autocapitalization(.none)
@@ -133,6 +133,13 @@ struct DeveloperOptionsScreen: View {
context.elementCallBaseURLOverride = url
}
}
Toggle(isOn: $context.nativeCallEnabled) {
Text("Experimental native calls")
}
} header: {
Text("Calls")
} footer: {
Text("The URL override only applies to calls run in the Element Call web view, which native calls replace.")
}
Section("Notifications") {
@@ -66,7 +66,7 @@ extension SpaceAddRoomsScreenRoom {
init(roomProxy: JoinedRoomProxyProtocol) {
self.init(id: roomProxy.id,
title: roomProxy.infoPublisher.value.displayName ?? roomProxy.id,
title: roomProxy.infoPublisher.value.displayNameOrID,
description: roomProxy.infoPublisher.value.roomListDescription,
avatar: roomProxy.infoPublisher.value.avatar)
}
@@ -25,7 +25,7 @@ class ThreadTimelineScreenViewModel: ThreadTimelineScreenViewModelType, ThreadTi
self.roomProxy = roomProxy
self.userSession = userSession
super.init(initialViewState: ThreadTimelineScreenViewState(roomTitle: roomProxy.infoPublisher.value.displayName ?? roomProxy.id,
super.init(initialViewState: ThreadTimelineScreenViewState(roomTitle: roomProxy.infoPublisher.value.displayNameOrID,
roomAvatar: roomProxy.infoPublisher.value.avatar), mediaProvider: userSession.mediaProvider)
roomProxy.infoPublisher
@@ -101,7 +101,7 @@ class ThreadTimelineScreenViewModel: ThreadTimelineScreenViewModelType, ThreadTi
}
private func updateRoomInfo(_ roomInfo: RoomInfoProxyProtocol) {
state.roomTitle = roomInfo.displayName ?? roomProxy.id
state.roomTitle = roomInfo.displayNameOrID
state.roomAvatar = roomInfo.avatar
state.dmRecipientDetails.statusEmoji = roomInfo.statusEmoji