Show the call buttons on macOS when the experimental native calling feature is enabled. (#6183)

* Show the call buttons on macOS when the experimental native calling feature is enabled.

* Start native calls in their own window on macOS.

* Update the Enterprise submodule.
This commit is contained in:
Doug
2026-09-23 12:24:54 +01:00
committed by GitHub
parent 27ffd4f3d5
commit 7c758df208
14 changed files with 56 additions and 10 deletions
@@ -11,6 +11,7 @@ import SwiftUI
enum SecondaryWindowType: Hashable, Codable {
case room(roomID: String)
case settings
case call
}
protocol SecureWindowManagerDelegate: AnyObject {
@@ -940,6 +940,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
private func presentRoomDetails(isRoot: Bool, animated: Bool) async {
let params = RoomDetailsScreenCoordinatorParameters(roomProxy: roomProxy,
userSession: userSession,
appSettings: flowParameters.appSettings,
appHooks: flowParameters.appHooks,
analyticsService: flowParameters.analytics,
userIndicatorController: flowParameters.userIndicatorController,
@@ -211,6 +211,7 @@ final class SpaceSettingsFlowCoordinator: FlowCoordinatorProtocol {
private func presentSpaceSettings(animated: Bool) {
let coordinator = RoomDetailsScreenCoordinator(parameters: .init(roomProxy: roomProxy,
userSession: flowParameters.userSession,
appSettings: flowParameters.appSettings,
appHooks: flowParameters.appHooks,
analyticsService: flowParameters.analytics,
userIndicatorController: flowParameters.userIndicatorController,
@@ -578,8 +578,13 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
}
let coordinator = NativeCallScreenCoordinator(parameters: .init(controller: controller))
navigationTabCoordinator.setOverlayCoordinator(coordinator, animated: true)
flowParameters.analytics.track(screen: .RoomCall)
if ProcessInfo.processInfo.isiOSAppOnMac {
flowParameters.appMediator.windowManager.registerCoordinator(coordinator, flowCoordinator: nil, forWindowType: .call)
} else {
navigationTabCoordinator.setOverlayCoordinator(coordinator, animated: true)
flowParameters.analytics.track(screen: .RoomCall)
}
}
private func restoreNativeCallScreen() {
@@ -588,12 +593,16 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
}
private func dismissCallScreenIfNeeded() {
guard navigationTabCoordinator.overlayCoordinator is CallScreenCoordinator
|| navigationTabCoordinator.overlayCoordinator is NativeCallScreenCoordinator else {
return
if ProcessInfo.processInfo.isiOSAppOnMac {
flowParameters.appMediator.windowManager.closeSecondaryWindow(forType: .call)
} else {
guard navigationTabCoordinator.overlayCoordinator is CallScreenCoordinator
|| navigationTabCoordinator.overlayCoordinator is NativeCallScreenCoordinator else {
return
}
navigationTabCoordinator.setOverlayCoordinator(nil)
}
navigationTabCoordinator.setOverlayCoordinator(nil)
}
// MARK: - Logout
@@ -12,6 +12,7 @@ import SwiftUI
struct RoomDetailsScreenCoordinatorParameters {
let roomProxy: JoinedRoomProxyProtocol
let userSession: UserSessionProtocol
let appSettings: AppSettings
let appHooks: AppHooks
let analyticsService: AnalyticsServiceProtocol
let userIndicatorController: UserIndicatorControllerProtocol
@@ -53,6 +54,7 @@ final class RoomDetailsScreenCoordinator: CoordinatorProtocol {
isSpace = parameters.roomProxy.infoPublisher.value.isSpace
viewModel = RoomDetailsScreenViewModel(roomProxy: parameters.roomProxy,
userSession: parameters.userSession,
appSettings: parameters.appSettings,
appHooks: parameters.appHooks,
analyticsService: parameters.analyticsService,
userIndicatorController: parameters.userIndicatorController,
@@ -63,6 +63,7 @@ struct RoomDetailsScreenViewState: BindableState {
var canBanUsers = false
var notificationSettingsState: RoomDetailsNotificationSettingsState = .loading
var isCallingEnabled = true
var isNativeCallingEnabled = false
var canJoinCall = false
var pinnedEventsActionState = RoomDetailsScreenPinnedEventsActionState.loading
@@ -94,7 +95,7 @@ struct RoomDetailsScreenViewState: BindableState {
var shortcuts: [RoomDetailsScreenViewShortcut] {
var shortcuts: [RoomDetailsScreenViewShortcut] = [.mute]
if !ProcessInfo.processInfo.isiOSAppOnMac, isCallingEnabled, canJoinCall {
if !ProcessInfo.processInfo.isiOSAppOnMac || isNativeCallingEnabled, isCallingEnabled, canJoinCall {
if isDirect {
shortcuts.append(.voiceCall)
}
@@ -45,6 +45,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
init(roomProxy: JoinedRoomProxyProtocol,
userSession: UserSessionProtocol,
appSettings: AppSettings,
appHooks: AppHooks,
analyticsService: AnalyticsServiceProtocol,
userIndicatorController: UserIndicatorControllerProtocol,
@@ -66,6 +67,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
topicSummary: topic?.unattributedStringByReplacingNewlinesWithSpaces(),
joinedMembersCount: roomProxy.infoPublisher.value.joinedMembersCount,
notificationSettingsState: .loading,
isNativeCallingEnabled: appSettings.nativeCallEnabled,
bindings: .init())
super.init(initialViewState: appHooks.roomDetailsScreenHook.update(viewState),
mediaProvider: userSession.mediaProvider)
@@ -441,6 +441,7 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
return .init(roomProxy: roomProxy,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -469,6 +470,7 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
return .init(roomProxy: roomProxy,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -507,6 +509,7 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
return .init(roomProxy: roomProxy,
userSession: UserSessionMock(.init(clientProxy: clientProxyMock)),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -57,6 +57,8 @@ struct RoomScreenViewState: BindableState {
/// Whether or not starting a call is supported.
var isCallingEnabled = true
/// Whether or not calls are using the experimental native implementation.
var isNativeCallingEnabled = false
/// Whether or not the user is allowed to join calls in this room.
var canJoinCall = false
/// Whether or not this room currently has a call in progress.
@@ -69,6 +69,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
let viewState = RoomScreenViewState(roomTitle: roomProxy.infoPublisher.value.displayNameOrID,
roomAvatar: roomProxy.infoPublisher.value.avatar,
isNativeCallingEnabled: appSettings.nativeCallEnabled,
hasOngoingCall: roomProxy.infoPublisher.value.hasRoomCall,
isDM: roomProxy.infoPublisher.value.isDM,
hasSuccessor: roomProxy.infoPublisher.value.successor != nil,
@@ -316,7 +316,7 @@ struct RoomScreen: View {
}
}
if !ProcessInfo.processInfo.isiOSAppOnMac {
if !ProcessInfo.processInfo.isiOSAppOnMac || context.viewState.isNativeCallingEnabled {
if context.viewState.shouldShowCallButton {
RoomCallControlsToolbar(viewState: context.viewState) { isVoiceCall in
context.send(viewAction: .displayCall(isVoiceCall: isVoiceCall))
@@ -132,6 +132,7 @@ struct SpaceSettingsScreen_Previews: PreviewProvider, TestablePreview {
canonicalAlias: "#space:matrix.org",
members: members)),
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -30,6 +30,7 @@ struct RoomDetailsScreenViewModelTests {
notificationSettingsProxyMock = NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration())
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -43,6 +44,7 @@ struct RoomDetailsScreenViewModelTests {
roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", members: mockedMembers, joinRule: .public))
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -63,6 +65,7 @@ struct RoomDetailsScreenViewModelTests {
roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", members: mockedMembers))
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -84,6 +87,7 @@ struct RoomDetailsScreenViewModelTests {
roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", members: mockedMembers))
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -142,6 +146,7 @@ struct RoomDetailsScreenViewModelTests {
roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: true, isEncrypted: true, members: mockedMembers))
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -163,6 +168,7 @@ struct RoomDetailsScreenViewModelTests {
roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: true, isEncrypted: true, members: mockedMembers))
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -195,6 +201,7 @@ struct RoomDetailsScreenViewModelTests {
roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: true, isEncrypted: true, members: mockedMembers))
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init(clientProxy: clientProxy)),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -226,6 +233,7 @@ struct RoomDetailsScreenViewModelTests {
roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: true, isEncrypted: true, members: mockedMembers))
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -258,6 +266,7 @@ struct RoomDetailsScreenViewModelTests {
roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: true, isEncrypted: true, members: mockedMembers))
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init(clientProxy: clientProxy)),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -291,6 +300,7 @@ struct RoomDetailsScreenViewModelTests {
powerLevelsConfiguration: .init(canUserInvite: false)))
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -308,6 +318,7 @@ struct RoomDetailsScreenViewModelTests {
roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", members: mockedMembers, joinRule: .public))
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -356,6 +367,7 @@ struct RoomDetailsScreenViewModelTests {
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -391,6 +403,7 @@ struct RoomDetailsScreenViewModelTests {
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -426,6 +439,7 @@ struct RoomDetailsScreenViewModelTests {
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -446,6 +460,7 @@ struct RoomDetailsScreenViewModelTests {
roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: false, members: mockedMembers))
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -466,6 +481,7 @@ struct RoomDetailsScreenViewModelTests {
roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: true, members: mockedMembers))
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -484,6 +500,7 @@ struct RoomDetailsScreenViewModelTests {
notificationSettingsProxyMock.getNotificationSettingsRoomIdIsEncryptedIsOneToOneThrowableError = NotificationSettingsError.Generic(msg: "error")
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -692,6 +709,7 @@ struct RoomDetailsScreenViewModelTests {
roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: false, knockRequestsState: .loaded(mockedRequests), joinRule: .knock))
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -713,6 +731,7 @@ struct RoomDetailsScreenViewModelTests {
roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: false, knockRequestsState: .loading, joinRule: .knock))
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -736,6 +755,7 @@ struct RoomDetailsScreenViewModelTests {
powerLevelsConfiguration: .init(canUserInvite: false)))
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -759,6 +779,7 @@ struct RoomDetailsScreenViewModelTests {
roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: true, members: mockedMembers, knockRequestsState: .loaded(mockedRequests), joinRule: .knock))
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
@@ -786,6 +807,7 @@ struct RoomDetailsScreenViewModelTests {
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
userSession: UserSessionMock(.init()),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
analyticsService: AnalyticsServiceMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),