diff --git a/ElementX/Sources/Application/AppCoordinator.swift b/ElementX/Sources/Application/AppCoordinator.swift index 56acfa7fc..daf867484 100644 --- a/ElementX/Sources/Application/AppCoordinator.swift +++ b/ElementX/Sources/Application/AppCoordinator.swift @@ -175,8 +175,8 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg .receive(on: DispatchQueue.main) .sink { [weak self] action in switch action { - case .startCall(let roomID): - self?.handleAppRoute(.call(roomID: roomID)) + case .startCall(let roomID, let isVoiceCall): + self?.handleAppRoute(.call(roomID: roomID, isVoiceCall: isVoiceCall)) case .receivedIncomingCallRequest: // When reporting a VoIP call through the CXProvider's `reportNewIncomingVoIPPushPayload` // the UIApplication states don't change and syncing is neither started nor ran on @@ -309,7 +309,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg } MXLog.info("Starting call in room: \(roomIdentifier)") - handleAppRoute(AppRoute.call(roomID: roomIdentifier)) + handleAppRoute(AppRoute.call(roomID: roomIdentifier, isVoiceCall: false)) } // MARK: - AuthenticationFlowCoordinatorDelegate diff --git a/ElementX/Sources/Application/Navigation/AppRoutes.swift b/ElementX/Sources/Application/Navigation/AppRoutes.swift index 4d12c0293..c32caf347 100644 --- a/ElementX/Sources/Application/Navigation/AppRoutes.swift +++ b/ElementX/Sources/Application/Navigation/AppRoutes.swift @@ -40,7 +40,7 @@ enum AppRoute: Hashable { /// The profile of a matrix user (outside of a room). case userProfile(userID: String) /// An Element Call running in a particular room - case call(roomID: String) + case call(roomID: String, isVoiceCall: Bool) /// An Element Call link generated outside of a chat room. case genericCallLink(url: URL) /// The settings screen. diff --git a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift index 3d77809f4..e8b9c925d 100644 --- a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift @@ -126,8 +126,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { stateMachine.tryEvent(.showSettingsScreen) } settingsFlowCoordinator?.handleAppRoute(appRoute, animated: animated) - case .call(let roomID): - Task { await presentCallScreen(roomID: roomID) } + case .call(let roomID, let isVoiceCall): + Task { await presentCallScreen(roomID: roomID, isVoiceCall: isVoiceCall) } case .genericCallLink(let url): presentCallScreen(genericCallLink: url) case .roomList, .room, .roomAlias, .childRoom, .childRoomAlias, @@ -204,7 +204,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { case .sessionVerification(let flow): presentSessionVerificationScreen(flow: flow) case .showCallScreen(let roomProxy): - presentCallScreen(roomProxy: roomProxy) + presentCallScreen(roomProxy: roomProxy, voiceOnly: false) case .hideCallScreenOverlay: hideCallScreenOverlay() case .logout: @@ -218,7 +218,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { guard let self else { return } switch action { case .presentCallScreen(let roomProxy): - presentCallScreen(roomProxy: roomProxy) + presentCallScreen(roomProxy: roomProxy, voiceOnly: false) case .verifyUser(let userID): presentSessionVerificationScreen(flow: .userInitiator(userID: userID)) case .showSettings: @@ -394,21 +394,22 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { presentCallScreen(configuration: .init(genericCallLink: url)) } - private func presentCallScreen(roomID: String) async { + private func presentCallScreen(roomID: String, isVoiceCall: Bool) async { guard case let .joined(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomID) else { return } - presentCallScreen(roomProxy: roomProxy) + presentCallScreen(roomProxy: roomProxy, voiceOnly: isVoiceCall) } - private func presentCallScreen(roomProxy: JoinedRoomProxyProtocol) { + private func presentCallScreen(roomProxy: JoinedRoomProxyProtocol, voiceOnly: Bool) { let colorScheme: ColorScheme = flowParameters.windowManager.mainWindow.traitCollection.userInterfaceStyle == .light ? .light : .dark presentCallScreen(configuration: .init(roomProxy: roomProxy, clientProxy: userSession.clientProxy, clientID: InfoPlistReader.main.bundleIdentifier, elementCallBaseURL: flowParameters.appSettings.elementCallBaseURL, elementCallBaseURLOverride: flowParameters.appSettings.elementCallBaseURLOverride, + voiceOnly: voiceOnly, colorScheme: colorScheme)) } diff --git a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift index 84a3af535..19c08ed8d 100644 --- a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift @@ -6453,15 +6453,15 @@ class ElementCallWidgetDriverMock: ElementCallWidgetDriverProtocol, @unchecked S //MARK: - start - var startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationUnderlyingCallsCount = 0 - var startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationCallsCount: Int { + var startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationUnderlyingCallsCount = 0 + var startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationCallsCount: Int { get { if Thread.isMainThread { - return startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationUnderlyingCallsCount + return startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationUnderlyingCallsCount } else { var returnValue: Int? = nil DispatchQueue.main.sync { - returnValue = startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationUnderlyingCallsCount + returnValue = startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationUnderlyingCallsCount } return returnValue! @@ -6469,29 +6469,29 @@ class ElementCallWidgetDriverMock: ElementCallWidgetDriverProtocol, @unchecked S } set { if Thread.isMainThread { - startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationUnderlyingCallsCount = newValue + startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationUnderlyingCallsCount = newValue } else { DispatchQueue.main.sync { - startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationUnderlyingCallsCount = newValue + startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationUnderlyingCallsCount = newValue } } } } - var startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationCalled: Bool { - return startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationCallsCount > 0 + var startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationCalled: Bool { + return startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationCallsCount > 0 } - var startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationReceivedArguments: (baseURL: URL, clientID: String, colorScheme: ColorScheme, rageshakeURL: String?, analyticsConfiguration: ElementCallAnalyticsConfiguration?)? - var startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationReceivedInvocations: [(baseURL: URL, clientID: String, colorScheme: ColorScheme, rageshakeURL: String?, analyticsConfiguration: ElementCallAnalyticsConfiguration?)] = [] + var startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationReceivedArguments: (baseURL: URL, clientID: String, colorScheme: ColorScheme, voiceOnly: Bool, rageshakeURL: String?, analyticsConfiguration: ElementCallAnalyticsConfiguration?)? + var startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationReceivedInvocations: [(baseURL: URL, clientID: String, colorScheme: ColorScheme, voiceOnly: Bool, rageshakeURL: String?, analyticsConfiguration: ElementCallAnalyticsConfiguration?)] = [] - var startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationUnderlyingReturnValue: Result! - var startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationReturnValue: Result! { + var startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationUnderlyingReturnValue: Result! + var startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationReturnValue: Result! { get { if Thread.isMainThread { - return startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationUnderlyingReturnValue + return startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationUnderlyingReturnValue } else { var returnValue: Result? = nil DispatchQueue.main.sync { - returnValue = startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationUnderlyingReturnValue + returnValue = startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationUnderlyingReturnValue } return returnValue! @@ -6499,26 +6499,26 @@ class ElementCallWidgetDriverMock: ElementCallWidgetDriverProtocol, @unchecked S } set { if Thread.isMainThread { - startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationUnderlyingReturnValue = newValue + startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationUnderlyingReturnValue = newValue } else { DispatchQueue.main.sync { - startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationUnderlyingReturnValue = newValue + startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationUnderlyingReturnValue = newValue } } } } - var startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationClosure: ((URL, String, ColorScheme, String?, ElementCallAnalyticsConfiguration?) async -> Result)? + var startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationClosure: ((URL, String, ColorScheme, Bool, String?, ElementCallAnalyticsConfiguration?) async -> Result)? - func start(baseURL: URL, clientID: String, colorScheme: ColorScheme, rageshakeURL: String?, analyticsConfiguration: ElementCallAnalyticsConfiguration?) async -> Result { - startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationCallsCount += 1 - startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationReceivedArguments = (baseURL: baseURL, clientID: clientID, colorScheme: colorScheme, rageshakeURL: rageshakeURL, analyticsConfiguration: analyticsConfiguration) + func start(baseURL: URL, clientID: String, colorScheme: ColorScheme, voiceOnly: Bool, rageshakeURL: String?, analyticsConfiguration: ElementCallAnalyticsConfiguration?) async -> Result { + startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationCallsCount += 1 + startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationReceivedArguments = (baseURL: baseURL, clientID: clientID, colorScheme: colorScheme, voiceOnly: voiceOnly, rageshakeURL: rageshakeURL, analyticsConfiguration: analyticsConfiguration) DispatchQueue.main.async { - self.startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationReceivedInvocations.append((baseURL: baseURL, clientID: clientID, colorScheme: colorScheme, rageshakeURL: rageshakeURL, analyticsConfiguration: analyticsConfiguration)) + self.startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationReceivedInvocations.append((baseURL: baseURL, clientID: clientID, colorScheme: colorScheme, voiceOnly: voiceOnly, rageshakeURL: rageshakeURL, analyticsConfiguration: analyticsConfiguration)) } - if let startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationClosure = startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationClosure { - return await startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationClosure(baseURL, clientID, colorScheme, rageshakeURL, analyticsConfiguration) + if let startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationClosure = startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationClosure { + return await startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationClosure(baseURL, clientID, colorScheme, voiceOnly, rageshakeURL, analyticsConfiguration) } else { - return startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationReturnValue + return startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationReturnValue } } //MARK: - handleMessage diff --git a/ElementX/Sources/Mocks/JoinedRoomProxyMock.swift b/ElementX/Sources/Mocks/JoinedRoomProxyMock.swift index 2d01d7a67..a8e23d390 100644 --- a/ElementX/Sources/Mocks/JoinedRoomProxyMock.swift +++ b/ElementX/Sources/Mocks/JoinedRoomProxyMock.swift @@ -137,7 +137,7 @@ extension JoinedRoomProxyMock { fatalError() } - widgetDriver.startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationReturnValue = .success(url) + widgetDriver.startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationUnderlyingReturnValue = .success(url) elementCallWidgetDriverDeviceIDReturnValue = widgetDriver diff --git a/ElementX/Sources/Screens/CallScreen/CallScreenViewModel.swift b/ElementX/Sources/Screens/CallScreen/CallScreenViewModel.swift index e7c16472b..19bfbdb39 100644 --- a/ElementX/Sources/Screens/CallScreen/CallScreenViewModel.swift +++ b/ElementX/Sources/Screens/CallScreen/CallScreenViewModel.swift @@ -53,7 +53,7 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol case .genericCallLink(let url): widgetDriver = GenericCallLinkWidgetDriver(url: url) isGenericCallLink = true - case .roomCall(let roomProxy, let clientProxy, _, _, _, _): + case .roomCall(let roomProxy, let clientProxy, _, _, _, _, _): guard let deviceID = clientProxy.deviceID else { fatalError("Missing device ID for the call.") } widgetDriver = roomProxy.elementCallWidgetDriver(deviceID: deviceID) } @@ -167,7 +167,7 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol state.url = url // We need widget messaging to work before enabling CallKit, otherwise mute, hangup etc do nothing. - case .roomCall(let roomProxy, _, let clientID, let elementCallBaseURL, let elementCallBaseURLOverride, let colorScheme): + case .roomCall(let roomProxy, _, let clientID, let voiceOnly, let elementCallBaseURL, let elementCallBaseURLOverride, let colorScheme): Task { [weak self] in guard let self else { return } @@ -194,6 +194,7 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol switch await widgetDriver.start(baseURL: baseURL, clientID: clientID, colorScheme: colorScheme, + voiceOnly: voiceOnly, rageshakeURL: rageshakeURL, analyticsConfiguration: analyticsConfiguration) { case .success(let url): diff --git a/ElementX/Sources/Screens/CallScreen/View/CallScreen.swift b/ElementX/Sources/Screens/CallScreen/View/CallScreen.swift index e5c0d8bc4..a7222a76b 100644 --- a/ElementX/Sources/Screens/CallScreen/View/CallScreen.swift +++ b/ElementX/Sources/Screens/CallScreen/View/CallScreen.swift @@ -360,7 +360,7 @@ struct CallScreen_Previews: PreviewProvider { let widgetDriver = ElementCallWidgetDriverMock() widgetDriver.underlyingMessagePublisher = .init() widgetDriver.underlyingActions = PassthroughSubject().eraseToAnyPublisher() - widgetDriver.startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationReturnValue = .success(URL.userDirectory) + widgetDriver.startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationReturnValue = .success(URL.userDirectory) roomProxy.elementCallWidgetDriverDeviceIDReturnValue = widgetDriver @@ -370,6 +370,7 @@ struct CallScreen_Previews: PreviewProvider { clientID: "io.element.elementx", elementCallBaseURL: "https://call.element.io", elementCallBaseURLOverride: nil, + voiceOnly: false, colorScheme: .light), allowPictureInPicture: false, appHooks: AppHooks(), diff --git a/ElementX/Sources/Services/ElementCall/ElementCallConfiguration.swift b/ElementX/Sources/Services/ElementCall/ElementCallConfiguration.swift index 3127f45b4..a33cfdcd3 100644 --- a/ElementX/Sources/Services/ElementCall/ElementCallConfiguration.swift +++ b/ElementX/Sources/Services/ElementCall/ElementCallConfiguration.swift @@ -20,6 +20,7 @@ struct ElementCallConfiguration { case roomCall(roomProxy: JoinedRoomProxyProtocol, clientProxy: ClientProxyProtocol, clientID: String, + voiceOnly: Bool, elementCallBaseURL: URL, elementCallBaseURLOverride: URL?, colorScheme: ColorScheme) @@ -59,10 +60,12 @@ struct ElementCallConfiguration { clientID: String, elementCallBaseURL: URL, elementCallBaseURLOverride: URL?, + voiceOnly: Bool, colorScheme: ColorScheme) { kind = .roomCall(roomProxy: roomProxy, clientProxy: clientProxy, clientID: clientID, + voiceOnly: voiceOnly, elementCallBaseURL: elementCallBaseURL, elementCallBaseURLOverride: elementCallBaseURLOverride, colorScheme: colorScheme) @@ -73,7 +76,7 @@ struct ElementCallConfiguration { switch kind { case .genericCallLink(let url): url.absoluteString - case .roomCall(let roomProxy, _, _, _, _, _): + case .roomCall(let roomProxy, _, _, _, _, _, _): roomProxy.id } } diff --git a/ElementX/Sources/Services/ElementCall/ElementCallService.swift b/ElementX/Sources/Services/ElementCall/ElementCallService.swift index b273dcb22..2512e1674 100644 --- a/ElementX/Sources/Services/ElementCall/ElementCallService.swift +++ b/ElementX/Sources/Services/ElementCall/ElementCallService.swift @@ -25,6 +25,7 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe let callKitID: UUID let roomID: String let rtcNotificationID: String? + let isVoiceCall: Bool } private let pushRegistry: PKPushRegistry @@ -111,7 +112,7 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe let callID = if let incomingCallID, incomingCallID.roomID == roomID { incomingCallID } else { - CallID(callKitID: UUID(), roomID: roomID, rtcNotificationID: nil) + CallID(callKitID: UUID(), roomID: roomID, rtcNotificationID: nil, isVoiceCall: false) } incomingCallID = nil @@ -177,7 +178,9 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe return } - let callID = CallID(callKitID: UUID(), roomID: roomID, rtcNotificationID: rtcNotificationID) + let isVoiceCall = payload.dictionaryPayload[ElementCallServiceNotificationKey.isVoiceCall.rawValue] as? Bool ?? false + + let callID = CallID(callKitID: UUID(), roomID: roomID, rtcNotificationID: rtcNotificationID, isVoiceCall: isVoiceCall) incomingCallID = callID guard let expirationDate = (payload.dictionaryPayload[ElementCallServiceNotificationKey.expirationDate.rawValue] as? Date) else { @@ -199,7 +202,7 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe let roomDisplayName = payload.dictionaryPayload[ElementCallServiceNotificationKey.roomDisplayName.rawValue] as? String let update = CXCallUpdate() - update.hasVideo = true + update.hasVideo = !isVoiceCall update.localizedCallerName = roomDisplayName // https://stackoverflow.com/a/41230020/730924 update.remoteHandle = .init(type: .generic, value: roomID) @@ -271,7 +274,7 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe // Then end the and call rely on `setupCallSession` to create a new one provider.reportCall(with: incomingCallID.callKitID, endedAt: nil, reason: .remoteEnded) - self.actionsSubject.send(.startCall(roomID: incomingCallID.roomID)) + self.actionsSubject.send(.startCall(roomID: incomingCallID.roomID, isVoiceCall: incomingCallID.isVoiceCall)) self.endUnansweredCallTask?.cancel() } } diff --git a/ElementX/Sources/Services/ElementCall/ElementCallServiceConstants.swift b/ElementX/Sources/Services/ElementCall/ElementCallServiceConstants.swift index a518f95a9..231aa9c97 100644 --- a/ElementX/Sources/Services/ElementCall/ElementCallServiceConstants.swift +++ b/ElementX/Sources/Services/ElementCall/ElementCallServiceConstants.swift @@ -16,6 +16,7 @@ enum ElementCallServiceNotificationKey: String { case rtcNotifyEventID /// The Date at which the incoming call should stop ringing. case expirationDate + case isVoiceCall } let ElementCallServiceNotificationDiscardDelta = 15.0 diff --git a/ElementX/Sources/Services/ElementCall/ElementCallServiceProtocol.swift b/ElementX/Sources/Services/ElementCall/ElementCallServiceProtocol.swift index 606accfcd..f691e8284 100644 --- a/ElementX/Sources/Services/ElementCall/ElementCallServiceProtocol.swift +++ b/ElementX/Sources/Services/ElementCall/ElementCallServiceProtocol.swift @@ -10,7 +10,7 @@ import Combine enum ElementCallServiceAction { case receivedIncomingCallRequest - case startCall(roomID: String) + case startCall(roomID: String, isVoiceCall: Bool) case endCall(roomID: String) case setAudioEnabled(_ enabled: Bool, roomID: String) } diff --git a/ElementX/Sources/Services/ElementCall/ElementCallWidgetDriver.swift b/ElementX/Sources/Services/ElementCall/ElementCallWidgetDriver.swift index b03e61aeb..26ae34549 100644 --- a/ElementX/Sources/Services/ElementCall/ElementCallWidgetDriver.swift +++ b/ElementX/Sources/Services/ElementCall/ElementCallWidgetDriver.swift @@ -70,6 +70,7 @@ final class ElementCallWidgetDriver: WidgetCapabilitiesProvider, ElementCallWidg func start(baseURL: URL, clientID: String, colorScheme: ColorScheme, + voiceOnly: Bool, rageshakeURL: String?, analyticsConfiguration: ElementCallAnalyticsConfiguration?) async -> Result { guard let room = room as? Room else { @@ -77,7 +78,7 @@ final class ElementCallWidgetDriver: WidgetCapabilitiesProvider, ElementCallWidg } async let useEncryption = (try? room.latestEncryptionState() == .encrypted) ?? false - async let intent = room.joinCallIntent + async let intent = room.joinCallIntent(voiceOnly: voiceOnly) let widgetSettings: WidgetSettings do { @@ -92,6 +93,7 @@ final class ElementCallWidgetDriver: WidgetCapabilitiesProvider, ElementCallWidg posthogApiKey: analyticsConfiguration?.posthogAPIKey, rageshakeSubmitUrl: rageshakeURL, sentryDsn: analyticsConfiguration?.sentryDSN, + sentryEnvironment: nil), config: .init(intent: intent)) } catch { diff --git a/ElementX/Sources/Services/ElementCall/ElementCallWidgetDriverProtocol.swift b/ElementX/Sources/Services/ElementCall/ElementCallWidgetDriverProtocol.swift index aa46305ae..53b9f6a19 100644 --- a/ElementX/Sources/Services/ElementCall/ElementCallWidgetDriverProtocol.swift +++ b/ElementX/Sources/Services/ElementCall/ElementCallWidgetDriverProtocol.swift @@ -33,6 +33,7 @@ protocol ElementCallWidgetDriverProtocol { func start(baseURL: URL, clientID: String, colorScheme: ColorScheme, + voiceOnly: Bool, rageshakeURL: String?, analyticsConfiguration: ElementCallAnalyticsConfiguration?) async -> Result diff --git a/ElementX/Sources/Services/ElementCall/GenericCallLinkWidgetDriver.swift b/ElementX/Sources/Services/ElementCall/GenericCallLinkWidgetDriver.swift index 8af501675..52a65aaf0 100644 --- a/ElementX/Sources/Services/ElementCall/GenericCallLinkWidgetDriver.swift +++ b/ElementX/Sources/Services/ElementCall/GenericCallLinkWidgetDriver.swift @@ -27,6 +27,7 @@ class GenericCallLinkWidgetDriver: ElementCallWidgetDriverProtocol { func start(baseURL: URL, clientID: String, colorScheme: ColorScheme, + voiceOnly: Bool, rageshakeURL: String?, analyticsConfiguration: ElementCallAnalyticsConfiguration?) async -> Result { MXLog.error("Nothing to start, use the configuration's URL directly instead.") diff --git a/ElementX/Sources/Services/Room/Room.swift b/ElementX/Sources/Services/Room/Room.swift index a1da5a53b..d24bb4f75 100644 --- a/ElementX/Sources/Services/Room/Room.swift +++ b/ElementX/Sources/Services/Room/Room.swift @@ -9,14 +9,12 @@ import MatrixRustSDK extension RoomProtocol { - var joinCallIntent: Intent { - get async { - switch await (hasActiveRoomCall(), isDirect()) { - case (true, true): .joinExistingDm - case (true, false): .joinExisting - case (false, true): .startCallDm - case (false, false): .startCall - } + func joinCallIntent(voiceOnly: Bool) async -> Intent { + switch await (hasActiveRoomCall(), isDirect()) { + case (true, true): voiceOnly ? .joinExistingDmVoice : .joinExistingDm + case (true, false): .joinExisting + case (false, true): voiceOnly ? .startCallDmVoice : .startCallDm + case (false, false): .startCall } - } + } } diff --git a/NSE/Sources/NotificationHandler.swift b/NSE/Sources/NotificationHandler.swift index 8fc640370..29b22fe6a 100644 --- a/NSE/Sources/NotificationHandler.swift +++ b/NSE/Sources/NotificationHandler.swift @@ -126,13 +126,14 @@ class NotificationHandler { } return .processedShouldDiscard - case .rtcNotification(let notificationType, let expirationTimestamp, _): + case .rtcNotification(let notificationType, let expirationTimestamp, let callIntent): return await handleCallNotification(notificationType: notificationType, rtcNotifyEventID: event.eventId(), timestamp: event.timestamp(), expirationTimestamp: expirationTimestamp, roomID: itemProxy.roomID, - roomDisplayName: itemProxy.roomDisplayName) + roomDisplayName: itemProxy.roomDisplayName, + callIntent: callIntent) case .callAnswer, .callInvite, .callHangup, @@ -161,7 +162,7 @@ class NotificationHandler { timestamp: Timestamp, expirationTimestamp: Timestamp, roomID: String, - roomDisplayName: String) async -> NotificationProcessingResult { + roomDisplayName: String, callIntent: RtcCallIntent?) async -> NotificationProcessingResult { // Handle incoming VoIP calls, show the native OS call screen // https://developer.apple.com/documentation/callkit/sending-end-to-end-encrypted-voip-calls // @@ -215,7 +216,8 @@ class NotificationHandler { let payload = [ElementCallServiceNotificationKey.roomID.rawValue: roomID, ElementCallServiceNotificationKey.roomDisplayName.rawValue: roomDisplayName, ElementCallServiceNotificationKey.expirationDate.rawValue: expirationDate, - ElementCallServiceNotificationKey.rtcNotifyEventID.rawValue: rtcNotifyEventID] as [String: Any] + ElementCallServiceNotificationKey.rtcNotifyEventID.rawValue: rtcNotifyEventID, + ElementCallServiceNotificationKey.isVoiceCall.rawValue: callIntent == RtcCallIntent.audio] as [String: Any] do { try await CXProvider.reportNewIncomingVoIPPushPayload(payload)