diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 7f0b0179f..ea9662726 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -220,6 +220,7 @@ 27FEF0F40750465195C9D6D6 /* RoomSelectionScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B9D191A81FFB0C72CE73E77 /* RoomSelectionScreenModels.swift */; }; 281BED345D59A9A6A99E9D98 /* UNNotificationContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE148A4FFEE853C5A281500C /* UNNotificationContent.swift */; }; 2835FD52F3F618D07F799B3D /* Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7310D8DFE01AF45F0689C3AA /* Publisher.swift */; }; + 288408E6151D7BD3EBAA073A /* RoomScreenHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = B343C5255FB408DDE853CFDF /* RoomScreenHook.swift */; }; 28AB1614E749D1147A2AC6C2 /* CreateRoomScreenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2214C32EA81FA9168D923D4C /* CreateRoomScreenTests.swift */; }; 292827744227DF61C930BDDB /* CreateRoomScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB0D6CB491777E7FC6B5BA12 /* CreateRoomScreen.swift */; }; 29491EE7AE37E239E839C5A3 /* LocationSharingScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BEBF0E59F25E842EDB6FD11 /* LocationSharingScreenModels.swift */; }; @@ -2265,6 +2266,7 @@ B2E7C987AE5DC9087BB19F7D /* MediaUploadPreviewScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaUploadPreviewScreenModels.swift; sourceTree = ""; }; B2EAFFD44F81F86012D6EC27 /* AudioRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRoomTimelineView.swift; sourceTree = ""; }; B3005886F00029F058DB62BE /* StartChatScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatScreenCoordinator.swift; sourceTree = ""; }; + B343C5255FB408DDE853CFDF /* RoomScreenHook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenHook.swift; sourceTree = ""; }; B383DCD3DCB19E00FD478A5F /* ConfirmationDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationDialog.swift; sourceTree = ""; }; B4005D82E9D27BAF006A8FE1 /* AppLockScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockScreenViewModel.swift; sourceTree = ""; }; B40233F2989AD49906BB310D /* RoomPollsHistoryScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomPollsHistoryScreenViewModelTests.swift; sourceTree = ""; }; @@ -3233,6 +3235,7 @@ 3865AD7B7249C939D7C69C33 /* CertificateValidatorHook.swift */, 7AC0CD1CAFD3F8B057F9AEA5 /* ClientBuilderHook.swift */, 8B89D6C760E8CAE29CA28FB1 /* CompoundHook.swift */, + B343C5255FB408DDE853CFDF /* RoomScreenHook.swift */, ); path = Hooks; sourceTree = ""; @@ -7607,6 +7610,7 @@ C55A44C99F64A479ABA85B46 /* RoomScreen.swift in Sources */, A851635B3255C6DC07034A12 /* RoomScreenCoordinator.swift in Sources */, E8C65C19F7C40EE545172DD6 /* RoomScreenFooterView.swift in Sources */, + 288408E6151D7BD3EBAA073A /* RoomScreenHook.swift in Sources */, 352C439BE0F75E101EF11FB1 /* RoomScreenModels.swift in Sources */, 7BB31E67648CF32D2AB5E502 /* RoomScreenViewModel.swift in Sources */, 617624A97BDBB75ED3DD8156 /* RoomScreenViewModelProtocol.swift in Sources */, diff --git a/ElementX/Sources/AppHooks/AppHooks.swift b/ElementX/Sources/AppHooks/AppHooks.swift index 004f69182..576787224 100644 --- a/ElementX/Sources/AppHooks/AppHooks.swift +++ b/ElementX/Sources/AppHooks/AppHooks.swift @@ -9,6 +9,10 @@ import Foundation class AppHooks: AppHooksProtocol { #if IS_MAIN_APP + func configure(with userSession: UserSessionProtocol?) async { + await roomScreenHook.configure(with: userSession) + } + private(set) var appSettingsHook: AppSettingsHookProtocol = DefaultAppSettingsHook() func registerAppSettingsHook(_ hook: AppSettingsHookProtocol) { appSettingsHook = hook @@ -28,6 +32,11 @@ class AppHooks: AppHooksProtocol { func registerCertificateValidatorHook(_ hook: CertificateValidatorHookProtocol) { certificateValidatorHook = hook } + + private(set) var roomScreenHook: RoomScreenHookProtocol = DefaultRoomScreenHook() + func registerRoomScreenHook(_ hook: RoomScreenHookProtocol) { + roomScreenHook = hook + } #endif private(set) var clientBuilderHook: ClientBuilderHookProtocol = DefaultClientBuilderHook() @@ -38,6 +47,10 @@ class AppHooks: AppHooksProtocol { protocol AppHooksProtocol { func setUp() + + #if IS_MAIN_APP + func configure(with userSession: UserSessionProtocol?) async + #endif } extension AppHooksProtocol { diff --git a/ElementX/Sources/AppHooks/Hooks/RoomScreenHook.swift b/ElementX/Sources/AppHooks/Hooks/RoomScreenHook.swift new file mode 100644 index 000000000..6d329c204 --- /dev/null +++ b/ElementX/Sources/AppHooks/Hooks/RoomScreenHook.swift @@ -0,0 +1,18 @@ +// +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. +// + +import Foundation + +protocol RoomScreenHookProtocol { + func configure(with userSession: UserSessionProtocol?) async + func update(_ viewState: RoomScreenViewState) -> RoomScreenViewState +} + +struct DefaultRoomScreenHook: RoomScreenHookProtocol { + func configure(with userSession: UserSessionProtocol?) async { } + func update(_ viewState: RoomScreenViewState) -> RoomScreenViewState { viewState } +} diff --git a/ElementX/Sources/Application/AppCoordinator.swift b/ElementX/Sources/Application/AppCoordinator.swift index d1dfb9be7..4f67f71e7 100644 --- a/ElementX/Sources/Application/AppCoordinator.swift +++ b/ElementX/Sources/Application/AppCoordinator.swift @@ -36,6 +36,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg observeUserSessionChanges() startSync() performSettingsToAccountDataMigration(userSession: userSession) + Task { await appHooks.configure(with: userSession) } } } } diff --git a/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift index 8ff89cd22..7dcc7c0fd 100644 --- a/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift @@ -62,6 +62,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { private let ongoingCallRoomIDPublisher: CurrentValuePublisher private let appMediator: AppMediatorProtocol private let appSettings: AppSettings + private let appHooks: AppHooks private let analytics: AnalyticsService private let userIndicatorController: UserIndicatorControllerProtocol @@ -99,6 +100,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { ongoingCallRoomIDPublisher: CurrentValuePublisher, appMediator: AppMediatorProtocol, appSettings: AppSettings, + appHooks: AppHooks, analytics: AnalyticsService, userIndicatorController: UserIndicatorControllerProtocol) async { self.roomID = roomID @@ -110,6 +112,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { self.ongoingCallRoomIDPublisher = ongoingCallRoomIDPublisher self.appMediator = appMediator self.appSettings = appSettings + self.appHooks = appHooks self.analytics = analytics self.userIndicatorController = userIndicatorController @@ -510,6 +513,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { ongoingCallRoomIDPublisher: ongoingCallRoomIDPublisher, appMediator: appMediator, appSettings: appSettings, + appHooks: appHooks, composerDraftService: composerDraftService, timelineControllerFactory: timelineControllerFactory) @@ -1451,6 +1455,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { ongoingCallRoomIDPublisher: ongoingCallRoomIDPublisher, appMediator: appMediator, appSettings: appSettings, + appHooks: appHooks, analytics: analytics, userIndicatorController: userIndicatorController) coordinator.actions.sink { [weak self] action in diff --git a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift index d0dda9bd9..4c0794fd9 100644 --- a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift @@ -675,6 +675,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { ongoingCallRoomIDPublisher: elementCallService.ongoingCallRoomIDPublisher, appMediator: appMediator, appSettings: appSettings, + appHooks: appHooks, analytics: analytics, userIndicatorController: ServiceLocator.shared.userIndicatorController) diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenCoordinator.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenCoordinator.swift index a4e54ce58..b8ef390b5 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenCoordinator.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenCoordinator.swift @@ -25,6 +25,7 @@ struct RoomScreenCoordinatorParameters { let ongoingCallRoomIDPublisher: CurrentValuePublisher let appMediator: AppMediatorProtocol let appSettings: AppSettings + let appHooks: AppHooks let composerDraftService: ComposerDraftServiceProtocol let timelineControllerFactory: TimelineControllerFactoryProtocol } @@ -73,6 +74,7 @@ final class RoomScreenCoordinator: CoordinatorProtocol { ongoingCallRoomIDPublisher: parameters.ongoingCallRoomIDPublisher, appMediator: parameters.appMediator, appSettings: parameters.appSettings, + appHooks: parameters.appHooks, analyticsService: ServiceLocator.shared.analytics, userIndicatorController: ServiceLocator.shared.userIndicatorController) diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift index 86cdfa77b..942cc799f 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift @@ -43,9 +43,18 @@ struct RoomScreenViewState: BindableState { } var canSendMessage = true + + /// Whether or not starting a call is supported. + var isCallingEnabled = true + /// 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. var hasOngoingCall: Bool - var shouldShowCallButton = true + /// Whether or not the user is already part of a call in another room. + var isParticipatingInOngoingCall = false + var shouldShowCallButton: Bool { + isCallingEnabled && !isParticipatingInOngoingCall // Hide the join call button when already in the call + } var isKnockingEnabled = false var isKnockableRoom = false @@ -70,7 +79,7 @@ struct RoomScreenViewState: BindableState { var footerDetails: RoomScreenFooterViewDetails? - var bindings: RoomScreenViewStateBindings + var bindings = RoomScreenViewStateBindings() } struct RoomScreenViewStateBindings { diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift index 04e8c4fc2..275ba96d0 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift @@ -57,6 +57,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol ongoingCallRoomIDPublisher: CurrentValuePublisher, appMediator: AppMediatorProtocol, appSettings: AppSettings, + appHooks: AppHooks, analyticsService: AnalyticsService, userIndicatorController: UserIndicatorControllerProtocol) { self.clientProxy = clientProxy @@ -69,16 +70,15 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol self.initialSelectedPinnedEventID = initialSelectedPinnedEventID pinnedEventStringBuilder = .pinnedEventStringBuilder(userID: roomProxy.ownUserID) - super.init(initialViewState: .init(roomTitle: roomProxy.infoPublisher.value.displayName ?? roomProxy.id, - roomAvatar: roomProxy.infoPublisher.value.avatar, - hasOngoingCall: roomProxy.infoPublisher.value.hasRoomCall, - hasSuccessor: roomProxy.infoPublisher.value.successor != nil, - bindings: .init()), + let viewState = RoomScreenViewState(roomTitle: roomProxy.infoPublisher.value.displayName ?? roomProxy.id, + roomAvatar: roomProxy.infoPublisher.value.avatar, + hasOngoingCall: roomProxy.infoPublisher.value.hasRoomCall, + hasSuccessor: roomProxy.infoPublisher.value.successor != nil) + super.init(initialViewState: appHooks.roomScreenHook.update(viewState), mediaProvider: mediaProvider) Task { await handleRoomInfoUpdate(roomProxy.infoPublisher.value) - await updateVerificationBadge() } @@ -205,7 +205,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol .receive(on: DispatchQueue.main) .sink { [weak self] ongoingCallRoomID in guard let self else { return } - state.shouldShowCallButton = ongoingCallRoomID != roomProxy.id + state.isParticipatingInOngoingCall = ongoingCallRoomID == roomProxy.id } .store(in: &cancellables) @@ -430,6 +430,7 @@ extension RoomScreenViewModel { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), analyticsService: ServiceLocator.shared.analytics, userIndicatorController: ServiceLocator.shared.userIndicatorController) } diff --git a/ElementX/Sources/UITests/UITestsAppCoordinator.swift b/ElementX/Sources/UITests/UITestsAppCoordinator.swift index eee69feb4..4d93004d2 100644 --- a/ElementX/Sources/UITests/UITestsAppCoordinator.swift +++ b/ElementX/Sources/UITests/UITestsAppCoordinator.swift @@ -271,6 +271,7 @@ class MockScreen: Identifiable { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -291,6 +292,7 @@ class MockScreen: Identifiable { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -311,6 +313,7 @@ class MockScreen: Identifiable { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -331,6 +334,7 @@ class MockScreen: Identifiable { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -354,6 +358,7 @@ class MockScreen: Identifiable { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -377,6 +382,7 @@ class MockScreen: Identifiable { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -400,6 +406,7 @@ class MockScreen: Identifiable { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -424,6 +431,7 @@ class MockScreen: Identifiable { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -447,6 +455,7 @@ class MockScreen: Identifiable { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -469,6 +478,7 @@ class MockScreen: Identifiable { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -505,6 +515,7 @@ class MockScreen: Identifiable { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -528,6 +539,7 @@ class MockScreen: Identifiable { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -551,6 +563,7 @@ class MockScreen: Identifiable { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let coordinator = RoomScreenCoordinator(parameters: parameters) diff --git a/Enterprise b/Enterprise index 3ed7e1c29..3faf64f71 160000 --- a/Enterprise +++ b/Enterprise @@ -1 +1 @@ -Subproject commit 3ed7e1c29a51059150f4449bf0d14fdaffa16d88 +Subproject commit 3faf64f71c03de03be1b0b69cacbb97ba69cc6fc diff --git a/UnitTests/Sources/RoomFlowCoordinatorTests.swift b/UnitTests/Sources/RoomFlowCoordinatorTests.swift index 6140b0cda..584dea42a 100644 --- a/UnitTests/Sources/RoomFlowCoordinatorTests.swift +++ b/UnitTests/Sources/RoomFlowCoordinatorTests.swift @@ -367,6 +367,7 @@ class RoomFlowCoordinatorTests: XCTestCase { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), analytics: ServiceLocator.shared.analytics, userIndicatorController: ServiceLocator.shared.userIndicatorController) } diff --git a/UnitTests/Sources/RoomScreenViewModelTests.swift b/UnitTests/Sources/RoomScreenViewModelTests.swift index b97ecc9dd..b9199c98d 100644 --- a/UnitTests/Sources/RoomScreenViewModelTests.swift +++ b/UnitTests/Sources/RoomScreenViewModelTests.swift @@ -45,6 +45,7 @@ class RoomScreenViewModelTests: XCTestCase { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), analyticsService: ServiceLocator.shared.analytics, userIndicatorController: ServiceLocator.shared.userIndicatorController) self.viewModel = viewModel @@ -125,6 +126,7 @@ class RoomScreenViewModelTests: XCTestCase { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), analyticsService: ServiceLocator.shared.analytics, userIndicatorController: ServiceLocator.shared.userIndicatorController) self.viewModel = viewModel @@ -175,6 +177,7 @@ class RoomScreenViewModelTests: XCTestCase { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), analyticsService: ServiceLocator.shared.analytics, userIndicatorController: ServiceLocator.shared.userIndicatorController) self.viewModel = viewModel @@ -214,6 +217,7 @@ class RoomScreenViewModelTests: XCTestCase { ongoingCallRoomIDPublisher: ongoingCallRoomIDSubject.asCurrentValuePublisher(), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), analyticsService: ServiceLocator.shared.analytics, userIndicatorController: ServiceLocator.shared.userIndicatorController) self.viewModel = viewModel @@ -259,6 +263,7 @@ class RoomScreenViewModelTests: XCTestCase { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), analyticsService: ServiceLocator.shared.analytics, userIndicatorController: ServiceLocator.shared.userIndicatorController) self.viewModel = viewModel @@ -294,6 +299,7 @@ class RoomScreenViewModelTests: XCTestCase { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), analyticsService: ServiceLocator.shared.analytics, userIndicatorController: ServiceLocator.shared.userIndicatorController) self.viewModel = viewModel @@ -324,6 +330,7 @@ class RoomScreenViewModelTests: XCTestCase { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), analyticsService: ServiceLocator.shared.analytics, userIndicatorController: ServiceLocator.shared.userIndicatorController) self.viewModel = viewModel @@ -345,6 +352,7 @@ class RoomScreenViewModelTests: XCTestCase { ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), analyticsService: ServiceLocator.shared.analytics, userIndicatorController: ServiceLocator.shared.userIndicatorController) self.viewModel = viewModel