From ff5dcb040de8993456b768d30e637e6edc3a9b5a Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 14 May 2026 01:45:49 -0500 Subject: [PATCH] Replace the ServiceLocator with direct dependency injection (#5548) Removes the ServiceLocator singleton and instead directly injects the dependencies it was holding for more control over instantiation of the various component subtrees and better visibility over how they're being used. --- ElementX.xcodeproj/project.pbxproj | 8 +- .../AccessibilityTestsAppCoordinator.swift | 10 +- .../Sources/Application/AppCoordinator.swift | 80 ++++---- .../Sources/Application/ServiceLocator.swift | 33 ---- .../Sources/Mocks/AnalyticsService+Mock.swift | 21 ++ .../Analytics/ScreenTrackerViewModifier.swift | 2 +- .../Other/SwiftUI/Views/VisualListItem.swift | 2 +- .../LoginScreen/View/LoginScreen.swift | 7 +- .../View/ServerConfirmationScreen.swift | 4 +- .../View/ServerSelectionScreen.swift | 4 +- .../AuthenticationClassicAppAccountView.swift | 2 +- .../View/AuthenticationStartScreen.swift | 2 +- .../Screens/CallScreen/View/CallScreen.swift | 9 +- .../View/PollFormScreen.swift | 4 +- .../View/CreateRoomScreen.swift | 6 +- .../View/CreateRoomSpaceSelectionSheet.swift | 11 +- .../View/EmojiPickerScreen.swift | 4 +- .../RoomListFiltersEmptyStateView.swift | 4 +- .../View/Filters/RoomListFiltersView.swift | 6 +- .../Screens/HomeScreen/View/HomeScreen.swift | 11 +- .../View/HomeScreenEmptyStateView.swift | 10 +- .../View/HomeScreenInviteCell.swift | 11 +- .../View/HomeScreenKnockedCell.swift | 11 +- ...eScreenRecoveryKeyConfirmationBanner.swift | 11 +- .../HomeScreen/View/HomeScreenRoomCell.swift | 9 +- .../InviteUsersConfirmationSheetView.swift | 2 +- .../View/InviteUsersScreen.swift | 2 +- .../JoinRoomScreen/View/JoinRoomScreen.swift | 2 +- .../LocationSharingScreenViewModel.swift | 9 +- .../View/ManageRoomMemberSheetView.swift | 2 +- .../View/MediaEventsTimelineScreen.swift | 11 +- .../View/MediaUploadPreviewScreen.swift | 2 +- .../View/AnalyticsPromptScreen.swift | 2 +- .../View/IdentityConfirmationScreen.swift | 4 +- .../View/PinnedEventsTimelineScreen.swift | 12 +- .../View/RoomChangePermissionsScreen.swift | 2 +- .../View/RoomChangeRolesScreen.swift | 2 +- .../View/RoomDetailsEditScreen.swift | 2 +- .../View/RoomDetailsScreen.swift | 33 ++-- .../View/RoomMemberDetailsScreen.swift | 11 +- .../View/RoomMembersListScreen.swift | 4 +- .../RoomMembersListScreenMemberCell.swift | 4 +- .../View/RoomRolesAndPermissionsScreen.swift | 4 +- .../ComposerToolbarViewModel.swift | 9 +- .../View/RoomAttachmentPicker.swift | 22 ++- .../RoomScreen/RoomScreenViewModel.swift | 19 +- .../Screens/RoomScreen/View/RoomScreen.swift | 12 +- .../View/AdvancedSettingsScreen.swift | 7 +- .../View/AnalyticsSettingsScreen.swift | 3 +- .../View/DeveloperOptionsScreen.swift | 5 +- .../SettingsScreen/View/SettingsScreen.swift | 2 +- .../View/UserDetailsEditScreen.swift | 2 +- .../View/SpaceSettingsScreen.swift | 41 ++-- .../View/JoinRoomByAddressView.swift | 8 +- .../View/StartChatScreen.swift | 2 +- .../Screens/Timeline/TimelineViewModel.swift | 12 +- .../View/ItemMenu/TimelineItemMenu.swift | 2 +- .../ReadReceiptsSummaryView.swift | 10 +- .../Style/TimelineItemBubbledStylerView.swift | 12 +- .../TimelineReadReceiptsView.swift | 29 +-- .../HighlightedTimelineItemModifier.swift | 29 +-- .../Screens/Timeline/View/TimelineView.swift | 27 +-- .../View/UserProfileScreen.swift | 11 +- .../Analytics/Helpers/Analytics+SwiftUI.swift | 2 +- .../AuthenticationService.swift | 4 +- .../TimelineControllerFactory.swift | 10 +- .../UITests/UITestsAppCoordinator.swift | 180 ++++++++++-------- .../UnitTests/UnitTestsAppCoordinator.swift | 9 +- ...nalyticsSettingsScreenViewModelTests.swift | 13 +- UnitTests/Sources/AnalyticsTests.swift | 39 ++-- .../Sources/AuthenticationServiceTests.swift | 2 +- ...henticationStartScreenViewModelTests.swift | 2 - .../BlockedUsersScreenViewModelTests.swift | 4 +- .../ChatsTabFlowCoordinatorTests.swift | 9 +- .../ComposerToolbarViewModelTests.swift | 35 ++-- .../Sources/CreateRoomViewModelTests.swift | 24 ++- .../EmojiPickerScreenViewModelTests.swift | 4 +- UnitTests/Sources/EmojiProviderTests.swift | 8 +- .../Sources/HomeScreenViewModelTests.swift | 11 +- .../Sources/InviteUsersViewModelTests.swift | 5 +- .../JoinRoomScreenViewModelTests.swift | 6 +- .../LocationSharingScreenViewModelTests.swift | 21 +- .../Sources/LoginScreenViewModelTests.swift | 8 +- .../ManageRoomMemberSheetViewModelTests.swift | 6 +- ...diaUploadPreviewScreenViewModelTests.swift | 16 +- .../MediaUploadingPreprocessorTests.swift | 1 - .../NotificationManagerTests.swift | 6 +- UnitTests/Sources/PillContextTests.swift | 132 ++++++++----- .../PollFormScreenViewModelTests.swift | 2 +- ...hangePermissionsScreenViewModelTests.swift | 2 +- .../RoomChangeRolesScreenViewModelTests.swift | 2 +- .../RoomDetailsEditScreenViewModelTests.swift | 2 +- .../RoomDetailsScreenViewModelTests.swift | 176 ++++++++++------- .../Sources/RoomFlowCoordinatorTests.swift | 18 +- .../RoomMemberDetailsViewModelTests.swift | 10 +- .../RoomMembersFlowCoordinatorTests.swift | 9 +- .../RoomMembersListScreenViewModelTests.swift | 8 +- ...esAndPermissionsScreenViewModelTests.swift | 2 +- .../Sources/RoomScreenViewModelTests.swift | 71 +++---- ...rverConfirmationScreenViewModelTests.swift | 11 +- .../ServerSelectionScreenViewModelTests.swift | 6 +- .../SettingsScreenViewModelTests.swift | 3 +- .../SpaceListScreenViewModelTests.swift | 6 +- .../Sources/StartChatViewModelTests.swift | 6 +- .../Sources/TimelineViewModelTests.swift | 102 +++++----- .../UserDetailsEditScreenViewModelTests.swift | 8 +- .../UserProfileScreenViewModelTests.swift | 30 ++- .../UserSessionFlowCoordinatorTests.swift | 13 +- 108 files changed, 971 insertions(+), 729 deletions(-) delete mode 100644 ElementX/Sources/Application/ServiceLocator.swift create mode 100644 ElementX/Sources/Mocks/AnalyticsService+Mock.swift diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 5e03d6662..c24958669 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -426,6 +426,7 @@ 484202C5D50983442D24D061 /* AttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52BD6ED18E2EB61E28C340AD /* AttributedString.swift */; }; 4870F7F72CEBEFDAD1C973A6 /* VoiceMessageMediaEventsTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD3521DF92391551E02004D8 /* VoiceMessageMediaEventsTimelineView.swift */; }; 489BB6A733D3DA0FE7062650 /* IdentityConfirmationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C71B9802433F1B4252291BB /* IdentityConfirmationScreenViewModelProtocol.swift */; }; + 48F2D00593F6D73434D3F893 /* AnalyticsService+Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = A384A5A9F8472A0DA76FDB27 /* AnalyticsService+Mock.swift */; }; 491D62ACD19E6F134B1766AF /* RoomNotificationSettingsUserDefinedScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3203C6566DC17B7AECC1B7FD /* RoomNotificationSettingsUserDefinedScreen.swift */; }; 492274DA6691EE985C2FCCAA /* SnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 21C83087604B154AA30E9A8F /* SnapshotTesting */; }; 4940B439681767BE9D78CFDB /* AppLockSetupBiometricsScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F5EE5DE3B55D59299DB5BC /* AppLockSetupBiometricsScreenViewModelTests.swift */; }; @@ -1120,7 +1121,6 @@ BCC864190651B3A3CF51E4DF /* MediaFileHandleProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEC1D382565A4E9CAC2F14EA /* MediaFileHandleProxy.swift */; }; BD0BE20DBCE31253AE4490A1 /* RoomListFiltersEmptyStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC1DDB2293A51EA4C2739351 /* RoomListFiltersEmptyStateView.swift */; }; BD6685592716CA957D7BAAC4 /* RoomChangeRolesScreenSelectedItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D9B45D584D232CB9E5C7734 /* RoomChangeRolesScreenSelectedItem.swift */; }; - BD782053BE4C3D2F0BDE5699 /* ServiceLocator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57F95CADD0A5DBD76B990FCB /* ServiceLocator.swift */; }; BDA68E8D95B2B24B28825B8B /* LoginScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C368CAB3063EF275357ECD4 /* LoginScreenViewModel.swift */; }; BDC4EB54CC3036730475CB8B /* QRCodeLoginScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25E7E9B7FEAB6169D960C206 /* QRCodeLoginScreenViewModelTests.swift */; }; BDCF42966007770A33D90E15 /* PreviewScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB56ABD78E60920ACE43087 /* PreviewScrollView.swift */; }; @@ -2115,7 +2115,6 @@ 57916A1578D8043BB0795441 /* GeneratedMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneratedMocks.swift; sourceTree = ""; }; 57AD14D3ADADE8F6A10F9E88 /* EncryptionSettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionSettingsTests.swift; sourceTree = ""; }; 57EAAF82432B0B53881CF826 /* AudioRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRoomTimelineItem.swift; sourceTree = ""; }; - 57F95CADD0A5DBD76B990FCB /* ServiceLocator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceLocator.swift; sourceTree = ""; }; 580BDCD23DD02481AB5FFB47 /* LeaveSpaceHandleSDKMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeaveSpaceHandleSDKMock.swift; sourceTree = ""; }; 584A61D9C459FAFEF038A7C0 /* Section.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Section.swift; sourceTree = ""; }; 5875F7C0A2398E9F134B1284 /* EncryptionResetScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionResetScreenViewModel.swift; sourceTree = ""; }; @@ -2527,6 +2526,7 @@ A232D9156D225BD9FD1D0C43 /* PhotoLibraryPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoLibraryPicker.swift; sourceTree = ""; }; A243A6E6207297123E60DE48 /* TimelineItemMacContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemMacContextMenu.swift; sourceTree = ""; }; A2723A4AF3AB9F5E18D26E49 /* hr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hr; path = hr.lproj/InfoPlist.strings; sourceTree = ""; }; + A384A5A9F8472A0DA76FDB27 /* AnalyticsService+Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AnalyticsService+Mock.swift"; sourceTree = ""; }; A3A4F56855188DAD23E59031 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = ""; }; A3B4B58B79A6FA250B24A1EC /* HomeScreenContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenContent.swift; sourceTree = ""; }; A3E3DE6616DCA81AD5F4791B /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -3766,6 +3766,7 @@ isa = PBXGroup; children = ( 69CB8242D69B7E4D0B32E18D /* AggregatedReactionMock.swift */, + A384A5A9F8472A0DA76FDB27 /* AnalyticsService+Mock.swift */, 3BAC027034248429A438886B /* AppMediatorMock.swift */, 0554FEA301486A8CFA475D5A /* AuthenticationClientBuilderFactoryMock.swift */, 9FD7E851E2BA8C5A8D284B2A /* BannedRoomProxyMock.swift */, @@ -5911,7 +5912,6 @@ 05AF58372CA884A789EB9C5A /* AppMediatorProtocol.swift */, B251F5B4511D1CA0BA8361FE /* CoordinatorProtocol.swift */, 7B9FCA1CFD07B8CF9BD21266 /* FlowCoordinatorProtocol.swift */, - 57F95CADD0A5DBD76B990FCB /* ServiceLocator.swift */, B5D829FD8958376614504B18 /* TargetConfiguration.swift */, 780F74C73E826685A9DB289B /* Navigation */, D64E20C9E4C486D5C764D7F3 /* Settings */, @@ -8079,6 +8079,7 @@ 6DC8E43BA04AC2AC4EB2EB97 /* AnalyticsPromptScreenModels.swift in Sources */, DB65401349C143DFF883E2B0 /* AnalyticsPromptScreenViewModel.swift in Sources */, 05BAB510CBC2ED35C154ADD0 /* AnalyticsPromptScreenViewModelProtocol.swift in Sources */, + 48F2D00593F6D73434D3F893 /* AnalyticsService+Mock.swift in Sources */, 3C73442084BF8A6939F0F80B /* AnalyticsService.swift in Sources */, 020F7E70167FB2833266F2F0 /* AnalyticsSettingsScreen.swift in Sources */, 95690DDD9D547D3D842ACBE3 /* AnalyticsSettingsScreenCoordinator.swift in Sources */, @@ -8880,7 +8881,6 @@ 6530865EB9A8C0F0AF0216DA /* ServerSelectionScreenModels.swift in Sources */, 85F89F3F320F4FADCFFFE68B /* ServerSelectionScreenViewModel.swift in Sources */, 0C47AE2CA7929CB3B0E2D793 /* ServerSelectionScreenViewModelProtocol.swift in Sources */, - BD782053BE4C3D2F0BDE5699 /* ServiceLocator.swift in Sources */, 914BDF61447C723F104BCE33 /* SessionDirectories.swift in Sources */, 237FC70AA257B935F53316BA /* SessionVerificationControllerProxy.swift in Sources */, AE1A73B24D63DA3D63DC4EE3 /* SessionVerificationControllerProxyMock.swift in Sources */, diff --git a/ElementX/Sources/AccessibilityTests/AccessibilityTestsAppCoordinator.swift b/ElementX/Sources/AccessibilityTests/AccessibilityTestsAppCoordinator.swift index 5e8f0e71d..f29ca3c7d 100644 --- a/ElementX/Sources/AccessibilityTests/AccessibilityTestsAppCoordinator.swift +++ b/ElementX/Sources/AccessibilityTests/AccessibilityTestsAppCoordinator.swift @@ -40,17 +40,9 @@ class AccessibilityTestsAppCoordinator: AppCoordinatorProtocol { MXLog.configure(currentTarget: "accessibility-tests") - ServiceLocator.shared.register(userIndicatorController: UserIndicatorController()) - AppSettings.configureWithSuiteName("io.element.elementx.accessibilitytests") AppSettings.resetAllSettings() - ServiceLocator.shared.register(appSettings: AppSettings()) - - let analyticsClient = AnalyticsClientMock() - analyticsClient.isRunning = false - ServiceLocator.shared.register(analytics: AnalyticsService(client: analyticsClient, - appSettings: ServiceLocator.shared.settings)) - + guard let name = ProcessInfo.accessibilityViewID, let previewType = TestablePreviewsDictionary.dictionary[name] else { fatalError("Unable to launch with unknown screen.") diff --git a/ElementX/Sources/Application/AppCoordinator.swift b/ElementX/Sources/Application/AppCoordinator.swift index 6b4cdd720..3e12ee98c 100644 --- a/ElementX/Sources/Application/AppCoordinator.swift +++ b/ElementX/Sources/Application/AppCoordinator.swift @@ -22,6 +22,9 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg private let targetConfiguration: Target.ConfigurationResult private let appMediator: AppMediator private let appSettings: AppSettings + private let analyticsService: AnalyticsService + private let userIndicatorController: UserIndicatorControllerProtocol + private let appDelegate: AppDelegate private let appHooks: AppHooks private let bugReportService: BugReportServiceProtocol @@ -76,7 +79,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg appMediator = AppMediator(windowManager: windowManager, networkMonitor: networkMonitor) let appSettings = appHooks.appSettingsHook.configure(AppSettings()) - ServiceLocator.shared.register(appSettings: appSettings) + self.appSettings = appSettings targetConfiguration = Target.mainApp.configure(logLevel: appSettings.logLevel, traceLogPacks: appSettings.traceLogPacks, @@ -94,17 +97,15 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg } self.appDelegate = appDelegate - self.appSettings = appSettings self.appHooks = appHooks appRouteURLParser = AppRouteURLParser(appSettings: appSettings) - ServiceLocator.shared.register(userIndicatorController: UserIndicatorController()) - let posthogAnalyticsClient = PostHogAnalyticsClient() posthogAnalyticsClient.updateSuperProperties(AnalyticsEvent.SuperProperties(appPlatform: .EXI, cryptoSDK: .Rust, cryptoSDKVersion: sdkGitSha())) - let analyticsService = AnalyticsService(client: posthogAnalyticsClient, appSettings: appSettings) - ServiceLocator.shared.register(analytics: analyticsService) + analyticsService = AnalyticsService(client: posthogAnalyticsClient, appSettings: appSettings) + + userIndicatorController = UserIndicatorController() elementCallService = ElementCallService() @@ -136,7 +137,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg sdkGitSHA: sdkGitSha(), appHooks: appHooks) - Self.setupSentry(bugReportService: bugReportService, appSettings: appSettings) + Self.setupSentry(bugReportService: bugReportService, appSettings: appSettings, analytics: analyticsService) analyticsService.startIfEnabled() @@ -165,9 +166,9 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg registerBackgroundAppRefresh() appSettings.$analyticsConsentState - .dropFirst() // Called above before configuring the ServiceLocator - .sink { [bugReportService] _ in - Self.setupSentry(bugReportService: bugReportService, appSettings: appSettings) + .dropFirst() // Sentry is configured during init; only reconfigure when consent state actually changes + .sink { [bugReportService, analyticsService, appSettings] _ in + Self.setupSentry(bugReportService: bugReportService, appSettings: appSettings, analytics: analyticsService) } .store(in: &cancellables) @@ -216,7 +217,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg func toPresentable() -> AnyView { AnyView(navigationRootCoordinator.toPresentable() - .environment(\.analyticsService, ServiceLocator.shared.analytics) + .environment(\.analyticsService, analyticsService) .onReceive(appSettings.$appAppearance) { [weak self] appAppearance in guard let self else { return } @@ -370,7 +371,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg func windowManagerDidConfigureWindows(_ windowManager: SecureWindowManagerProtocol) { windowManager.alternateWindow.rootViewController = UIHostingController(rootView: appLockFlowCoordinator.toPresentable()) - ServiceLocator.shared.userIndicatorController.window = windowManager.overlayWindow + userIndicatorController.window = windowManager.overlayWindow } // MARK: - NotificationManagerDelegate @@ -414,7 +415,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg handleAppRoute(.thread(roomID: roomID, threadRootEventID: threadRootEventID, focusEventID: eventID), windowType: nil) } else if let eventID { // Only track main timeline event deeplinking - ServiceLocator.shared.analytics.signpost.startTransaction(.notificationToMessage) + analyticsService.signpost.startTransaction(.notificationToMessage) handleAppRoute(.event(eventID: eventID, roomID: roomID, via: []), windowType: nil) } else { handleAppRoute(.room(roomID: roomID, via: []), windowType: nil) @@ -665,8 +666,8 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg appMediator: appMediator, appSettings: appSettings, appHooks: appHooks, - analytics: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + analytics: analyticsService, + userIndicatorController: userIndicatorController) coordinator.delegate = self authenticationFlowCoordinator = coordinator @@ -721,7 +722,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg appMediator: appMediator, appSettings: appSettings, appHooks: appHooks, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + userIndicatorController: userIndicatorController) let coordinator = SoftLogoutScreenCoordinator(parameters: parameters) self.softLogoutCoordinator = coordinator coordinator.actions @@ -750,24 +751,24 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg } if let serverName = userSession.clientProxy.userIDServerName { - ServiceLocator.shared.analytics.signpost.addGlobalTag(.homeserver, value: serverName) + analyticsService.signpost.addGlobalTag(.homeserver, value: serverName) } if !isNewLogin { - ServiceLocator.shared.analytics.signpost.startTransaction(.cachedRoomList) + analyticsService.signpost.startTransaction(.cachedRoomList) } let flowParameters = CommonFlowParameters(userSession: userSession, bugReportService: bugReportService, elementCallService: elementCallService, - timelineControllerFactory: TimelineControllerFactory(), + timelineControllerFactory: TimelineControllerFactory(appSettings: appSettings), emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), appMediator: appMediator, appSettings: appSettings, appHooks: appHooks, - analytics: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analytics: analyticsService, + userIndicatorController: userIndicatorController, notificationManager: notificationManager, stateMachineFactory: StateMachineFactory()) @@ -837,8 +838,8 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg appHooks.remoteSettingsHook.reset(appSettings) // Reset analytics - ServiceLocator.shared.analytics.optOut() - ServiceLocator.shared.analytics.resetConsentState() + analyticsService.optOut() + analyticsService.resetConsentState() stateMachine.processEvent(.completedSigningOut) @@ -847,7 +848,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg } private func tearDownUserSession() { - ServiceLocator.shared.userIndicatorController.retractAllIndicators() + userIndicatorController.retractAllIndicators() userSession = nil @@ -949,7 +950,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg } } - private static func setupSentry(bugReportService: BugReportServiceProtocol, appSettings: AppSettings) { + private static func setupSentry(bugReportService: BugReportServiceProtocol, appSettings: AppSettings, analytics: AnalyticsService) { guard let bugReportSentryURL = appSettings.bugReportSentryURL else { return } let options: Options = .init() @@ -1008,7 +1009,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg // Any ongoing transactions will no longer be valid after calling SentrySDK.start so lets // remove them and start over, otherwise the app will crash if finishTransaction is used. - ServiceLocator.shared.analytics.signpost.resetTransactions() + analytics.signpost.resetTransactions() SentrySDK.start(options: options) // Swift enableSentryLogging(enabled: options.enabled) // Rust @@ -1043,18 +1044,18 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg private static let loadingIndicatorIdentifier = "\(AppCoordinator.self)-Loading" private func showLoadingIndicator() { - ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, - type: .modal, - title: L10n.commonLoading, - persistent: true)) + userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, + type: .modal, + title: L10n.commonLoading, + persistent: true)) } private func hideLoadingIndicator() { - ServiceLocator.shared.userIndicatorController.retractIndicatorWithId(Self.loadingIndicatorIdentifier) + userIndicatorController.retractIndicatorWithId(Self.loadingIndicatorIdentifier) } private func showLoginErrorToast() { - ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(title: "Failed logging in")) + userIndicatorController.submitIndicator(UserIndicator(title: "Failed logging in")) } // MARK: - Application State @@ -1074,8 +1075,8 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg private func startSync() { guard let userSession else { return } - ServiceLocator.shared.analytics.signpost.startTransaction(.upToDateRoomList) - + analyticsService.signpost.startTransaction(.upToDateRoomList) + userSession.clientProxy.startSync() guard clientProxyObserver == nil else { @@ -1089,16 +1090,17 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg .receive(on: DispatchQueue.main) .sink { [weak self] state in let toastIdentifier = "StaleDataIndicator" + guard let self else { return } switch state { case .loading: - if self?.userSession?.clientProxy.homeserverReachabilityPublisher.value == .reachable, - self?.appMediator.networkMonitor.reachabilityPublisher.value == .reachable { - ServiceLocator.shared.userIndicatorController.submitIndicator(.init(id: toastIdentifier, type: .toast(progress: .indeterminate), title: L10n.commonSyncing, persistent: true)) + if self.userSession?.clientProxy.homeserverReachabilityPublisher.value == .reachable, + self.appMediator.networkMonitor.reachabilityPublisher.value == .reachable { + self.userIndicatorController.submitIndicator(.init(id: toastIdentifier, type: .toast(progress: .indeterminate), title: L10n.commonSyncing, persistent: true)) } case .notLoading: - ServiceLocator.shared.analytics.signpost.finishTransaction(.upToDateRoomList) - ServiceLocator.shared.userIndicatorController.retractIndicatorWithId(toastIdentifier) + self.analyticsService.signpost.finishTransaction(.upToDateRoomList) + self.userIndicatorController.retractIndicatorWithId(toastIdentifier) } } } diff --git a/ElementX/Sources/Application/ServiceLocator.swift b/ElementX/Sources/Application/ServiceLocator.swift deleted file mode 100644 index fcc10ec1f..000000000 --- a/ElementX/Sources/Application/ServiceLocator.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// Copyright 2025 Element Creations Ltd. -// Copyright 2022-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 - -class ServiceLocator { - private(set) static var shared = ServiceLocator() - - private init() { } - - private(set) var userIndicatorController: UserIndicatorControllerProtocol! - - func register(userIndicatorController: UserIndicatorControllerProtocol) { - self.userIndicatorController = userIndicatorController - } - - private(set) var settings: AppSettings! - - func register(appSettings: AppSettings) { - settings = appSettings - } - - private(set) var analytics: AnalyticsService! - - func register(analytics: AnalyticsService) { - self.analytics = analytics - } -} diff --git a/ElementX/Sources/Mocks/AnalyticsService+Mock.swift b/ElementX/Sources/Mocks/AnalyticsService+Mock.swift new file mode 100644 index 000000000..5f31dcd7e --- /dev/null +++ b/ElementX/Sources/Mocks/AnalyticsService+Mock.swift @@ -0,0 +1,21 @@ +// +// 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. +// + +extension AnalyticsService { + static func mock(_ clientOverride: AnalyticsClientProtocol? = nil, settings: AppSettings? = nil) -> AnalyticsService { + let client: AnalyticsClientProtocol + if let clientOverride { + client = clientOverride + } else { + let mockClient = AnalyticsClientMock() + mockClient.isRunning = false + client = mockClient + } + + return .init(client: client, appSettings: settings ?? AppSettings()) + } +} diff --git a/ElementX/Sources/Other/Analytics/ScreenTrackerViewModifier.swift b/ElementX/Sources/Other/Analytics/ScreenTrackerViewModifier.swift index b8c3355ac..3621e41bf 100644 --- a/ElementX/Sources/Other/Analytics/ScreenTrackerViewModifier.swift +++ b/ElementX/Sources/Other/Analytics/ScreenTrackerViewModifier.swift @@ -18,7 +18,7 @@ struct ScreenTrackerViewModifier: ViewModifier { func body(content: Content) -> some View { content .onAppear { - analyticsService.track(screen: screen) + analyticsService?.track(screen: screen) } } } diff --git a/ElementX/Sources/Other/SwiftUI/Views/VisualListItem.swift b/ElementX/Sources/Other/SwiftUI/Views/VisualListItem.swift index 08d98abd6..397edb2ee 100644 --- a/ElementX/Sources/Other/SwiftUI/Views/VisualListItem.swift +++ b/ElementX/Sources/Other/SwiftUI/Views/VisualListItem.swift @@ -56,7 +56,7 @@ private struct VisualListItemLabelStyle: LabelStyle { // MARK: - Previews struct VisualListItem_Previews: PreviewProvider, TestablePreview { - static let strings = AnalyticsPromptScreenStrings(termsURL: ServiceLocator.shared.settings.analyticsTermsURL) + static let strings = AnalyticsPromptScreenStrings(termsURL: AppSettings().analyticsTermsURL) static var testImage1: some View { Image(systemName: "circle") diff --git a/ElementX/Sources/Screens/Authentication/LoginScreen/View/LoginScreen.swift b/ElementX/Sources/Screens/Authentication/LoginScreen/View/LoginScreen.swift index 47fc6171d..43146dbb4 100644 --- a/ElementX/Sources/Screens/Authentication/LoginScreen/View/LoginScreen.swift +++ b/ElementX/Sources/Screens/Authentication/LoginScreen/View/LoginScreen.swift @@ -158,11 +158,14 @@ struct LoginScreen_Previews: PreviewProvider, TestablePreview { Task { await authenticationService.configure(for: homeserverAddress, flow: .login) } + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + let viewModel = LoginScreenViewModel(authenticationService: authenticationService, loginHint: nil, userIndicatorController: UserIndicatorControllerMock(), - appSettings: ServiceLocator.shared.settings, - analytics: ServiceLocator.shared.analytics) + appSettings: appSettings, + analytics: analytics) if withCredentials { viewModel.context.username = "alice" diff --git a/ElementX/Sources/Screens/Authentication/ServerConfirmationScreen/View/ServerConfirmationScreen.swift b/ElementX/Sources/Screens/Authentication/ServerConfirmationScreen/View/ServerConfirmationScreen.swift index 8e1007af5..284bbe85e 100644 --- a/ElementX/Sources/Screens/Authentication/ServerConfirmationScreen/View/ServerConfirmationScreen.swift +++ b/ElementX/Sources/Screens/Authentication/ServerConfirmationScreen/View/ServerConfirmationScreen.swift @@ -163,7 +163,7 @@ struct ServerConfirmationScreen_Previews: PreviewProvider, TestablePreview { ServerConfirmationScreenViewModel(authenticationService: AuthenticationService.mock, mode: mode, authenticationFlow: flow, - appSettings: ServiceLocator.shared.settings, - userIndicatorController: UserIndicatorControllerMock()) + appSettings: AppSettings(), + userIndicatorController: UserIndicatorControllerMock.default) } } diff --git a/ElementX/Sources/Screens/Authentication/ServerSelectionScreen/View/ServerSelectionScreen.swift b/ElementX/Sources/Screens/Authentication/ServerSelectionScreen/View/ServerSelectionScreen.swift index c98d92244..af5f32227 100644 --- a/ElementX/Sources/Screens/Authentication/ServerSelectionScreen/View/ServerSelectionScreen.swift +++ b/ElementX/Sources/Screens/Authentication/ServerSelectionScreen/View/ServerSelectionScreen.swift @@ -116,8 +116,8 @@ struct ServerSelection_Previews: PreviewProvider, TestablePreview { let viewModel = ServerSelectionScreenViewModel(authenticationService: authenticationService, authenticationFlow: .login, - appSettings: ServiceLocator.shared.settings, - userIndicatorController: UserIndicatorControllerMock()) + appSettings: AppSettings(), + userIndicatorController: UserIndicatorControllerMock.default) viewModel.context.homeserverAddress = homeserverAddress if homeserverAddress == "thisisbad" { viewModel.context.send(viewAction: .confirm) diff --git a/ElementX/Sources/Screens/Authentication/StartScreen/View/AuthenticationClassicAppAccountView.swift b/ElementX/Sources/Screens/Authentication/StartScreen/View/AuthenticationClassicAppAccountView.swift index 52c7cbf98..b163e5196 100644 --- a/ElementX/Sources/Screens/Authentication/StartScreen/View/AuthenticationClassicAppAccountView.swift +++ b/ElementX/Sources/Screens/Authentication/StartScreen/View/AuthenticationClassicAppAccountView.swift @@ -151,7 +151,7 @@ struct AuthenticationClassicAppAccountView_Previews: PreviewProvider { // Not Te provisioningParameters: nil, isBugReportServiceEnabled: false, appMediator: AppMediatorMock(), - appSettings: ServiceLocator.shared.settings, + appSettings: AppSettings(), mediaProvider: MediaProviderMock(configuration: .init()), userIndicatorController: UserIndicatorControllerMock()) } diff --git a/ElementX/Sources/Screens/Authentication/StartScreen/View/AuthenticationStartScreen.swift b/ElementX/Sources/Screens/Authentication/StartScreen/View/AuthenticationStartScreen.swift index 0cdbdcae5..d85942bf1 100644 --- a/ElementX/Sources/Screens/Authentication/StartScreen/View/AuthenticationStartScreen.swift +++ b/ElementX/Sources/Screens/Authentication/StartScreen/View/AuthenticationStartScreen.swift @@ -195,7 +195,7 @@ struct AuthenticationStartScreen_Previews: PreviewProvider, TestablePreview { provisioningParameters: provisionedServerName.map { .init(accountProvider: $0, loginHint: nil) }, isBugReportServiceEnabled: true, appMediator: AppMediatorMock(), - appSettings: ServiceLocator.shared.settings, + appSettings: AppSettings(), mediaProvider: MediaProviderMock(configuration: .init()), userIndicatorController: UserIndicatorControllerMock()) } diff --git a/ElementX/Sources/Screens/CallScreen/View/CallScreen.swift b/ElementX/Sources/Screens/CallScreen/View/CallScreen.swift index 592b8dab0..6e2867d4a 100644 --- a/ElementX/Sources/Screens/CallScreen/View/CallScreen.swift +++ b/ElementX/Sources/Screens/CallScreen/View/CallScreen.swift @@ -363,7 +363,10 @@ struct CallScreen_Previews: PreviewProvider { widgetDriver.startBaseURLClientIDColorSchemeVoiceOnlyRageshakeURLAnalyticsConfigurationReturnValue = .success(URL.userDirectory) roomProxy.elementCallWidgetDriverDeviceIDReturnValue = widgetDriver - + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return CallScreenViewModel(elementCallService: ElementCallServiceMock(.init()), configuration: .init(roomProxy: roomProxy, clientProxy: clientProxy, @@ -374,8 +377,8 @@ struct CallScreen_Previews: PreviewProvider { colorScheme: .light), allowPictureInPicture: false, appHooks: AppHooks(), - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics) + appSettings: appSettings, + analyticsService: analytics) }() static var previews: some View { diff --git a/ElementX/Sources/Screens/CreatePollScreen/View/PollFormScreen.swift b/ElementX/Sources/Screens/CreatePollScreen/View/PollFormScreen.swift index 5fa819fe6..c5aab3e37 100644 --- a/ElementX/Sources/Screens/CreatePollScreen/View/PollFormScreen.swift +++ b/ElementX/Sources/Screens/CreatePollScreen/View/PollFormScreen.swift @@ -227,8 +227,8 @@ struct PollFormScreen_Previews: PreviewProvider, TestablePreview { static func makeViewModel(mode: PollFormMode) -> PollFormScreenViewModel { PollFormScreenViewModel(mode: mode, timelineController: MockTimelineController(), - analytics: ServiceLocator.shared.analytics, - userIndicatorController: UserIndicatorControllerMock()) + analytics: .mock(), + userIndicatorController: UserIndicatorControllerMock.default) } } diff --git a/ElementX/Sources/Screens/CreateRoomScreen/View/CreateRoomScreen.swift b/ElementX/Sources/Screens/CreateRoomScreen/View/CreateRoomScreen.swift index 134700f24..242f08beb 100644 --- a/ElementX/Sources/Screens/CreateRoomScreen/View/CreateRoomScreen.swift +++ b/ElementX/Sources/Screens/CreateRoomScreen/View/CreateRoomScreen.swift @@ -456,13 +456,13 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview { let spaces = [SpaceServiceRoom].mockJoinedSpaces2 clientProxy.spaceService = SpaceServiceProxyMock(.init(editableSpaces: spaces)) let userSession = UserSessionMock(.init(clientProxy: clientProxy)) - + return CreateRoomScreenViewModel(isSpace: isSpace, spaceSelectionMode: selectionMode, shouldShowCancelButton: isSpace, userSession: userSession, - analytics: ServiceLocator.shared.analytics, - userIndicatorController: UserIndicatorControllerMock(), + analytics: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, appSettings: appSettings) } } diff --git a/ElementX/Sources/Screens/CreateRoomScreen/View/CreateRoomSpaceSelectionSheet.swift b/ElementX/Sources/Screens/CreateRoomScreen/View/CreateRoomSpaceSelectionSheet.swift index b53445b64..2a72f87bf 100644 --- a/ElementX/Sources/Screens/CreateRoomScreen/View/CreateRoomSpaceSelectionSheet.swift +++ b/ElementX/Sources/Screens/CreateRoomScreen/View/CreateRoomSpaceSelectionSheet.swift @@ -66,14 +66,17 @@ struct CreateRoomSpaceSelectionSheet_Previews: PreviewProvider, TestablePreview let clientProxy = ClientProxyMock(.init(userID: "@userid:example.com")) clientProxy.spaceService = SpaceServiceProxyMock(.init(editableSpaces: .mockJoinedSpaces2)) let userSession = UserSessionMock(.init(clientProxy: clientProxy)) - + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return CreateRoomScreenViewModel(isSpace: false, spaceSelectionMode: .editableSpacesList(preSelectedSpace: nil), shouldShowCancelButton: false, userSession: userSession, - analytics: ServiceLocator.shared.analytics, - userIndicatorController: UserIndicatorControllerMock(), - appSettings: ServiceLocator.shared.settings) + analytics: analytics, + userIndicatorController: UserIndicatorControllerMock.default, + appSettings: appSettings) }() static var previews: some View { diff --git a/ElementX/Sources/Screens/EmojiPickerScreen/View/EmojiPickerScreen.swift b/ElementX/Sources/Screens/EmojiPickerScreen/View/EmojiPickerScreen.swift index 2240c81f0..df466bed1 100644 --- a/ElementX/Sources/Screens/EmojiPickerScreen/View/EmojiPickerScreen.swift +++ b/ElementX/Sources/Screens/EmojiPickerScreen/View/EmojiPickerScreen.swift @@ -103,7 +103,7 @@ struct EmojiPickerScreen: View { struct EmojiPickerScreen_Previews: PreviewProvider, TestablePreview { static let viewModel = EmojiPickerScreenViewModel(itemID: .randomEvent, selectedEmojis: ["😀", "😄"], - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: AppSettings()), timelineController: MockTimelineController()) static var previews: some View { @@ -116,7 +116,7 @@ struct EmojiPickerScreen_Previews: PreviewProvider, TestablePreview { struct EmojiPickerScreenSheet_Previews: PreviewProvider { static let viewModel = EmojiPickerScreenViewModel(itemID: .randomEvent, selectedEmojis: ["😀", "😄"], - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: AppSettings()), timelineController: MockTimelineController()) static var previews: some View { diff --git a/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFiltersEmptyStateView.swift b/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFiltersEmptyStateView.swift index 60b0ae372..8bfaf2278 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFiltersEmptyStateView.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFiltersEmptyStateView.swift @@ -59,10 +59,10 @@ struct RoomListFiltersEmptyStateView_Previews: PreviewProvider, TestablePreview VStack(spacing: 24) { ForEach(RoomListFilter.allCases) { filter in RoomListFiltersEmptyStateView(state: .init(activeFilters: [filter], - appSettings: ServiceLocator.shared.settings)) + appSettings: AppSettings())) } RoomListFiltersEmptyStateView(state: .init(activeFilters: [.people, .favourites], - appSettings: ServiceLocator.shared.settings)) + appSettings: AppSettings())) } .padding(.bottom) .previewLayout(.sizeThatFits) diff --git a/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFiltersView.swift b/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFiltersView.swift index 0c1e52d99..87f4a8fe5 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFiltersView.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFiltersView.swift @@ -90,10 +90,10 @@ struct RoomListFiltersView: View { struct RoomListFiltersView_Previews: PreviewProvider, TestablePreview { static var previews: some View { - RoomListFiltersView(state: .constant(.init(appSettings: ServiceLocator.shared.settings))) + RoomListFiltersView(state: .constant(.init(appSettings: AppSettings()))) RoomListFiltersView(state: .constant(.init(activeFilters: [.rooms, .favourites], - appSettings: ServiceLocator.shared.settings))) + appSettings: AppSettings()))) RoomListFiltersView(state: .constant(.init(activeFilters: [.lowPriority], - appSettings: ServiceLocator.shared.settings))) + appSettings: AppSettings()))) } } diff --git a/ElementX/Sources/Screens/HomeScreen/View/HomeScreen.swift b/ElementX/Sources/Screens/HomeScreen/View/HomeScreen.swift index 86e0d9e9a..61c973208 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/HomeScreen.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/HomeScreen.swift @@ -221,12 +221,15 @@ struct HomeScreen_Previews: PreviewProvider, TestablePreview { roomSummaryProvider: RoomSummaryProviderMock(.init(state: roomSummaryProviderState)))) let userSession = UserSessionMock(.init(clientProxy: clientProxy)) - + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return HomeScreenViewModel(userSession: userSession, selectedRoomPublisher: CurrentValueSubject(nil).asCurrentValuePublisher(), - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, + appSettings: appSettings, + analyticsService: analytics, notificationManager: NotificationManagerMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController) + userIndicatorController: UserIndicatorControllerMock.default) } } diff --git a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenEmptyStateView.swift b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenEmptyStateView.swift index 671ac5b89..a559ad6cc 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenEmptyStateView.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenEmptyStateView.swift @@ -143,12 +143,14 @@ struct HomeScreenEmptyStateView_Previews: PreviewProvider, TestablePreview { static let viewModel = { let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@user:example.com", roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loaded([]))))))) - + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return HomeScreenViewModel(userSession: userSession, selectedRoomPublisher: CurrentValueSubject(nil).asCurrentValuePublisher(), - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, + appSettings: appSettings, + analyticsService: analytics, notificationManager: NotificationManagerMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController) + userIndicatorController: UserIndicatorControllerMock.default) }() } diff --git a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenInviteCell.swift b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenInviteCell.swift index f4c042e7e..c90288e90 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenInviteCell.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenInviteCell.swift @@ -199,13 +199,16 @@ struct HomeScreenInviteCell_Previews: PreviewProvider, TestablePreview { let clientProxy = ClientProxyMock(.init()) let userSession = UserSessionMock(.init(clientProxy: clientProxy)) - + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return HomeScreenViewModel(userSession: userSession, selectedRoomPublisher: CurrentValueSubject(nil).asCurrentValuePublisher(), - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, + appSettings: appSettings, + analyticsService: analytics, notificationManager: NotificationManagerMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController) + userIndicatorController: UserIndicatorControllerMock.default) } } diff --git a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenKnockedCell.swift b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenKnockedCell.swift index dcad63ae9..024733917 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenKnockedCell.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenKnockedCell.swift @@ -131,13 +131,16 @@ struct HomeScreenKnockedCell_Previews: PreviewProvider, TestablePreview { let clientProxy = ClientProxyMock(.init()) let userSession = UserSessionMock(.init(clientProxy: clientProxy)) - + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return HomeScreenViewModel(userSession: userSession, selectedRoomPublisher: CurrentValueSubject(nil).asCurrentValuePublisher(), - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, + appSettings: appSettings, + analyticsService: analytics, notificationManager: NotificationManagerMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController) + userIndicatorController: UserIndicatorControllerMock.default) } } diff --git a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRecoveryKeyConfirmationBanner.swift b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRecoveryKeyConfirmationBanner.swift index 4e2b2e987..bf81d5f2d 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRecoveryKeyConfirmationBanner.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRecoveryKeyConfirmationBanner.swift @@ -120,12 +120,15 @@ struct HomeScreenRecoveryKeyConfirmationBanner_Previews: PreviewProvider, Testab roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loading)))) let userSession = UserSessionMock(.init(clientProxy: clientProxy)) - + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return HomeScreenViewModel(userSession: userSession, selectedRoomPublisher: CurrentValueSubject(nil).asCurrentValuePublisher(), - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, + appSettings: appSettings, + analyticsService: analytics, notificationManager: NotificationManagerMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController) + userIndicatorController: UserIndicatorControllerMock.default) } } diff --git a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRoomCell.swift b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRoomCell.swift index 401fa4c49..df75027f4 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRoomCell.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRoomCell.swift @@ -253,12 +253,15 @@ struct HomeScreenRoomCell_Previews: PreviewProvider, TestablePreview { static func makeViewModel(roomSummaryProvider: RoomSummaryProviderProtocol) -> HomeScreenViewModel { let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "John Doe", roomSummaryProvider: roomSummaryProvider)))) + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return HomeScreenViewModel(userSession: userSession, selectedRoomPublisher: CurrentValueSubject(nil).asCurrentValuePublisher(), - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, + appSettings: appSettings, + analyticsService: analytics, notificationManager: NotificationManagerMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController) + userIndicatorController: UserIndicatorControllerMock.default) } static func makeRoom(lastMessageState: RoomSummary.LastMessageState) -> HomeScreenRoom { diff --git a/ElementX/Sources/Screens/InviteUsersScreen/View/InviteUsersConfirmationSheetView.swift b/ElementX/Sources/Screens/InviteUsersScreen/View/InviteUsersConfirmationSheetView.swift index 9c8d4c7f3..f082fc1b0 100644 --- a/ElementX/Sources/Screens/InviteUsersScreen/View/InviteUsersConfirmationSheetView.swift +++ b/ElementX/Sources/Screens/InviteUsersScreen/View/InviteUsersConfirmationSheetView.swift @@ -65,7 +65,7 @@ struct InviteUsersConfirmationSheetView_Previews: PreviewProvider, TestablePrevi isSkippable: true, userDiscoveryService: UserDiscoveryServiceMock(), userIndicatorController: UserIndicatorControllerMock(), - appSettings: ServiceLocator.shared.settings) + appSettings: AppSettings()) viewModel.state.usersToConfirm = [.mockAlice, .mockCharlie, .mockBob, .mockDan] diff --git a/ElementX/Sources/Screens/InviteUsersScreen/View/InviteUsersScreen.swift b/ElementX/Sources/Screens/InviteUsersScreen/View/InviteUsersScreen.swift index 7457e9326..989e62786 100644 --- a/ElementX/Sources/Screens/InviteUsersScreen/View/InviteUsersScreen.swift +++ b/ElementX/Sources/Screens/InviteUsersScreen/View/InviteUsersScreen.swift @@ -193,7 +193,7 @@ struct InviteUsersScreen_Previews: PreviewProvider, TestablePreview { isSkippable: true, userDiscoveryService: userDiscoveryService, userIndicatorController: UserIndicatorControllerMock(), - appSettings: ServiceLocator.shared.settings) + appSettings: AppSettings()) if let searchQuery { viewModel.context.searchQuery = searchQuery diff --git a/ElementX/Sources/Screens/JoinRoomScreen/View/JoinRoomScreen.swift b/ElementX/Sources/Screens/JoinRoomScreen/View/JoinRoomScreen.swift index 4ade900cb..de95f59f0 100644 --- a/ElementX/Sources/Screens/JoinRoomScreen/View/JoinRoomScreen.swift +++ b/ElementX/Sources/Screens/JoinRoomScreen/View/JoinRoomScreen.swift @@ -458,7 +458,7 @@ struct JoinRoomScreenPreviewWrapper: Identifiable { viewModel = JoinRoomScreenViewModel(source: source, appSettings: appSettings, userSession: UserSessionMock(.init(clientProxy: clientProxy)), - userIndicatorController: ServiceLocator.shared.userIndicatorController) + userIndicatorController: UserIndicatorControllerMock.default) } var previewDisplayName: String { diff --git a/ElementX/Sources/Screens/LocationSharing/LocationSharingScreenViewModel.swift b/ElementX/Sources/Screens/LocationSharing/LocationSharingScreenViewModel.swift index 6e8eec4e9..b5c17be7d 100644 --- a/ElementX/Sources/Screens/LocationSharing/LocationSharingScreenViewModel.swift +++ b/ElementX/Sources/Screens/LocationSharing/LocationSharingScreenViewModel.swift @@ -388,13 +388,16 @@ extension LocationSharingScreenViewModel { let liveLocationServiceMock = RoomLiveLocationServiceMock(.init(shares: liveLocationShares)) let roomProxy = JoinedRoomProxyMock(.init(members: .allMembers, ownUserID: RoomMemberProxyMock.mockMe.userID)) roomProxy.makeLiveLocationServiceReturnValue = liveLocationServiceMock - + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return LocationSharingScreenViewModel(interactionMode: interactionMode, - mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration, + mapURLBuilder: appSettings.mapTilerConfiguration, roomProxy: roomProxy, timelineController: MockTimelineController(), liveLocationManager: LiveLocationManagerMock(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, userIndicatorController: UserIndicatorControllerMock(), mediaProvider: MediaProviderMock(configuration: .init())) } diff --git a/ElementX/Sources/Screens/ManageRoomMemberSheet/View/ManageRoomMemberSheetView.swift b/ElementX/Sources/Screens/ManageRoomMemberSheet/View/ManageRoomMemberSheetView.swift index e1594e17f..b1205d78e 100644 --- a/ElementX/Sources/Screens/ManageRoomMemberSheet/View/ManageRoomMemberSheetView.swift +++ b/ElementX/Sources/Screens/ManageRoomMemberSheet/View/ManageRoomMemberSheetView.swift @@ -120,7 +120,7 @@ private extension ManageRoomMemberSheetViewModel { ownPowerLevel: powerLevel), roomProxy: JoinedRoomProxyMock(.init()), userIndicatorController: UserIndicatorControllerMock(), - analyticsService: ServiceLocator.shared.analytics, + analyticsService: .mock(), mediaProvider: MediaProviderMock(configuration: .init())) } } diff --git a/ElementX/Sources/Screens/MediaEventsTimelineScreen/View/MediaEventsTimelineScreen.swift b/ElementX/Sources/Screens/MediaEventsTimelineScreen/View/MediaEventsTimelineScreen.swift index 33cc95710..d227c7a9b 100644 --- a/ElementX/Sources/Screens/MediaEventsTimelineScreen/View/MediaEventsTimelineScreen.swift +++ b/ElementX/Sources/Screens/MediaEventsTimelineScreen/View/MediaEventsTimelineScreen.swift @@ -309,16 +309,19 @@ struct MediaEventsTimelineScreen_Previews: PreviewProvider, TestablePreview { } else { MockTimelineController.mediaGallery } - + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return TimelineViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Preview room")), timelineController: timelineController, userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), userIndicatorController: UserIndicatorControllerMock(), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) } diff --git a/ElementX/Sources/Screens/MediaUploadPreviewScreen/View/MediaUploadPreviewScreen.swift b/ElementX/Sources/Screens/MediaUploadPreviewScreen/View/MediaUploadPreviewScreen.swift index 10f857e31..d2b63518e 100644 --- a/ElementX/Sources/Screens/MediaUploadPreviewScreen/View/MediaUploadPreviewScreen.swift +++ b/ElementX/Sources/Screens/MediaUploadPreviewScreen/View/MediaUploadPreviewScreen.swift @@ -370,7 +370,7 @@ struct MediaUploadPreviewScreen_Previews: PreviewProvider, TestablePreview { title: "App Icon.png", isRoomEncrypted: true, shouldShowCaptionWarning: true, - mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: ServiceLocator.shared.settings), + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: AppSettings()), timelineController: MockTimelineController(), clientProxy: ClientProxyMock(.init()), userIndicatorController: UserIndicatorControllerMock.default) diff --git a/ElementX/Sources/Screens/Onboarding/AnalyticsPromptScreen/View/AnalyticsPromptScreen.swift b/ElementX/Sources/Screens/Onboarding/AnalyticsPromptScreen/View/AnalyticsPromptScreen.swift index aef362555..f3f7390e5 100644 --- a/ElementX/Sources/Screens/Onboarding/AnalyticsPromptScreen/View/AnalyticsPromptScreen.swift +++ b/ElementX/Sources/Screens/Onboarding/AnalyticsPromptScreen/View/AnalyticsPromptScreen.swift @@ -102,6 +102,6 @@ struct AnalyticsPromptScreen_Previews: PreviewProvider, TestablePreview { } static func makeViewModel(showTerms: Bool = true) -> AnalyticsPromptScreenViewModel { - AnalyticsPromptScreenViewModel(termsURL: showTerms ? ServiceLocator.shared.settings.analyticsTermsURL : nil) + AnalyticsPromptScreenViewModel(termsURL: showTerms ? AppSettings().analyticsTermsURL : nil) } } diff --git a/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/View/IdentityConfirmationScreen.swift b/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/View/IdentityConfirmationScreen.swift index 378b960ca..3e49707d4 100644 --- a/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/View/IdentityConfirmationScreen.swift +++ b/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/View/IdentityConfirmationScreen.swift @@ -140,7 +140,7 @@ struct IdentityConfirmationScreen_Previews: PreviewProvider, TestablePreview { userSession.sessionSecurityStatePublisher = CurrentValuePublisher(.init(verificationState: .unverified, recoveryState: recoveryState)) return IdentityConfirmationScreenViewModel(userSession: userSession, - appSettings: ServiceLocator.shared.settings, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + appSettings: AppSettings(), + userIndicatorController: UserIndicatorControllerMock.default) } } diff --git a/ElementX/Sources/Screens/PinnedEventsTimelineScreen/View/PinnedEventsTimelineScreen.swift b/ElementX/Sources/Screens/PinnedEventsTimelineScreen/View/PinnedEventsTimelineScreen.swift index 069328bb5..d2c73c65a 100644 --- a/ElementX/Sources/Screens/PinnedEventsTimelineScreen/View/PinnedEventsTimelineScreen.swift +++ b/ElementX/Sources/Screens/PinnedEventsTimelineScreen/View/PinnedEventsTimelineScreen.swift @@ -69,20 +69,24 @@ struct PinnedEventsTimelineScreen_Previews: PreviewProvider, TestablePreview { static let viewModel = PinnedEventsTimelineScreenViewModel(roomProxy: JoinedRoomProxyMock(.init()), userIndicatorController: UserIndicatorControllerMock(), appSettings: AppSettings(), - analyticsService: ServiceLocator.shared.analytics) + analyticsService: .mock()) static let emptyTimelineViewModel: TimelineViewModel = { let timelineController = MockTimelineController(timelineKind: .pinned) timelineController.timelineItems = [] + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return TimelineViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Preview room")), timelineController: timelineController, userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), userIndicatorController: UserIndicatorControllerMock(), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) }() diff --git a/ElementX/Sources/Screens/RoomChangePermissionsScreen/View/RoomChangePermissionsScreen.swift b/ElementX/Sources/Screens/RoomChangePermissionsScreen/View/RoomChangePermissionsScreen.swift index 030099b53..bedfa48ee 100644 --- a/ElementX/Sources/Screens/RoomChangePermissionsScreen/View/RoomChangePermissionsScreen.swift +++ b/ElementX/Sources/Screens/RoomChangePermissionsScreen/View/RoomChangePermissionsScreen.swift @@ -91,6 +91,6 @@ struct RoomChangePermissionsScreen_Previews: PreviewProvider, TestablePreview { ownPowerLevel: ownPowerLevel, roomProxy: JoinedRoomProxyMock(.init(isSpace: isSpace)), userIndicatorController: UserIndicatorControllerMock(), - analytics: ServiceLocator.shared.analytics) + analytics: .mock()) } } diff --git a/ElementX/Sources/Screens/RoomChangeRolesScreen/View/RoomChangeRolesScreen.swift b/ElementX/Sources/Screens/RoomChangeRolesScreen/View/RoomChangeRolesScreen.swift index 740756113..e1598d29e 100644 --- a/ElementX/Sources/Screens/RoomChangeRolesScreen/View/RoomChangeRolesScreen.swift +++ b/ElementX/Sources/Screens/RoomChangeRolesScreen/View/RoomChangeRolesScreen.swift @@ -151,6 +151,6 @@ struct RoomChangeRolesScreen_Previews: PreviewProvider, TestablePreview { roomProxy: JoinedRoomProxyMock(.init(members: members)), mediaProvider: MediaProviderMock(configuration: .init()), userIndicatorController: UserIndicatorControllerMock(), - analytics: ServiceLocator.shared.analytics) + analytics: .mock()) } } diff --git a/ElementX/Sources/Screens/RoomDetailsEditScreen/View/RoomDetailsEditScreen.swift b/ElementX/Sources/Screens/RoomDetailsEditScreen/View/RoomDetailsEditScreen.swift index 6bca24ecb..be35983a7 100644 --- a/ElementX/Sources/Screens/RoomDetailsEditScreen/View/RoomDetailsEditScreen.swift +++ b/ElementX/Sources/Screens/RoomDetailsEditScreen/View/RoomDetailsEditScreen.swift @@ -177,7 +177,7 @@ struct RoomDetailsEditScreen_Previews: PreviewProvider, TestablePreview { return RoomDetailsEditScreenViewModel(roomProxy: roomProxy, userSession: UserSessionMock(.init()), - mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: ServiceLocator.shared.settings), + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: AppSettings()), userIndicatorController: UserIndicatorControllerMock.default) } } diff --git a/ElementX/Sources/Screens/RoomDetailsScreen/View/RoomDetailsScreen.swift b/ElementX/Sources/Screens/RoomDetailsScreen/View/RoomDetailsScreen.swift index 0650c6050..c553e0c8c 100644 --- a/ElementX/Sources/Screens/RoomDetailsScreen/View/RoomDetailsScreen.swift +++ b/ElementX/Sources/Screens/RoomDetailsScreen/View/RoomDetailsScreen.swift @@ -405,14 +405,17 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview { notificationSettingsProxyMockConfiguration.roomMode.isDefault = false let notificationSettingsProxy = NotificationSettingsProxyMock(with: notificationSettingsProxyMockConfiguration) - + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return .init(roomProxy: roomProxy, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: analytics, + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: notificationSettingsProxy, attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) } private static func makeSimpleRoomViewModel() -> RoomDetailsScreenViewModel { @@ -433,14 +436,17 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview { joinRule: .knock)) let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init()) - + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return .init(roomProxy: roomProxy, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: analytics, + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: notificationSettingsProxy, attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) } private static func makeDMViewModel(verificationState: UserIdentityVerificationState) -> RoomDetailsScreenViewModel { @@ -471,13 +477,16 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview { } let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init()) - + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return .init(roomProxy: roomProxy, userSession: UserSessionMock(.init(clientProxy: clientProxyMock)), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: analytics, + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: notificationSettingsProxy, attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) } } diff --git a/ElementX/Sources/Screens/RoomMemberDetailsScreen/View/RoomMemberDetailsScreen.swift b/ElementX/Sources/Screens/RoomMemberDetailsScreen/View/RoomMemberDetailsScreen.swift index e4398d1b8..11302ec8a 100644 --- a/ElementX/Sources/Screens/RoomMemberDetailsScreen/View/RoomMemberDetailsScreen.swift +++ b/ElementX/Sources/Screens/RoomMemberDetailsScreen/View/RoomMemberDetailsScreen.swift @@ -235,12 +235,15 @@ struct RoomMemberDetailsScreen_Previews: PreviewProvider, TestablePreview { if member.userID != RoomMemberProxyMock.mockMe.userID { clientProxyMock.directRoomForUserIDReturnValue = .success("roomID") } - + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return RoomMemberDetailsScreenViewModel(userID: member.userID, roomProxy: roomProxyMock, userSession: UserSessionMock(.init(clientProxy: clientProxyMock)), - userIndicatorController: ServiceLocator.shared.userIndicatorController, - analytics: ServiceLocator.shared.analytics, - appSettings: ServiceLocator.shared.settings) + userIndicatorController: UserIndicatorControllerMock.default, + analytics: analytics, + appSettings: appSettings) } } diff --git a/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListScreen.swift b/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListScreen.swift index e1a17a58d..e6e2e21cd 100644 --- a/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListScreen.swift +++ b/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListScreen.swift @@ -261,7 +261,7 @@ struct RoomMembersListScreen_Previews: PreviewProvider, TestablePreview { members: members, ownUserID: ownUserID, powerLevelsConfiguration: .init(canUserInvite: false))), - userIndicatorController: ServiceLocator.shared.userIndicatorController, - analytics: ServiceLocator.shared.analytics) + userIndicatorController: UserIndicatorControllerMock.default, + analytics: .mock()) } } diff --git a/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListScreenMemberCell.swift b/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListScreenMemberCell.swift index e57dfd1c5..840543f70 100644 --- a/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListScreenMemberCell.swift +++ b/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListScreenMemberCell.swift @@ -131,8 +131,8 @@ struct RoomMembersListMemberCell_Previews: PreviewProvider, TestablePreview { static let viewModel = RoomMembersListScreenViewModel(userSession: UserSessionMock(.init()), roomProxy: JoinedRoomProxyMock(.init(name: "Some room", members: [])), - userIndicatorController: ServiceLocator.shared.userIndicatorController, - analytics: ServiceLocator.shared.analytics) + userIndicatorController: UserIndicatorControllerMock.default, + analytics: .mock()) static var previews: some View { VStack(spacing: 0) { Section("Invited/Joined") { diff --git a/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/View/RoomRolesAndPermissionsScreen.swift b/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/View/RoomRolesAndPermissionsScreen.swift index 76e5a4ac0..7b1e7d5ed 100644 --- a/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/View/RoomRolesAndPermissionsScreen.swift +++ b/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/View/RoomRolesAndPermissionsScreen.swift @@ -121,12 +121,12 @@ struct RoomRolesAndPermissionsScreen_Previews: PreviewProvider, TestablePreview static let viewModel = RoomRolesAndPermissionsScreenViewModel(initialPermissions: RoomPermissions(powerLevels: .mock), roomProxy: JoinedRoomProxyMock(.init(members: .allMembersAsAdmin)), userIndicatorController: UserIndicatorControllerMock(), - analytics: ServiceLocator.shared.analytics) + analytics: .mock()) static let creatorViewModel = RoomRolesAndPermissionsScreenViewModel(initialPermissions: RoomPermissions(powerLevels: .mock), roomProxy: JoinedRoomProxyMock(.init(members: .allMembersAsCreator)), userIndicatorController: UserIndicatorControllerMock(), - analytics: ServiceLocator.shared.analytics) + analytics: .mock()) static var previews: some View { ElementNavigationStack { RoomRolesAndPermissionsScreen(context: viewModel.context) diff --git a/ElementX/Sources/Screens/RoomScreen/ComposerToolbar/ComposerToolbarViewModel.swift b/ElementX/Sources/Screens/RoomScreen/ComposerToolbar/ComposerToolbarViewModel.swift index b0756b97d..545e8fdbc 100644 --- a/ElementX/Sources/Screens/RoomScreen/ComposerToolbar/ComposerToolbarViewModel.swift +++ b/ElementX/Sources/Screens/RoomScreen/ComposerToolbar/ComposerToolbarViewModel.swift @@ -819,15 +819,18 @@ extension ComposerToolbarViewModel { if !canSend { roomProxy.identityStatusChangesPublisher = .init([.init(userId: RoomMemberProxyMock.mockAlice.userID, changedTo: .verificationViolation)]) } - + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + let wysiwygViewModel = WysiwygComposerViewModel() let viewModel = ComposerToolbarViewModel(roomProxy: roomProxy, wysiwygViewModel: wysiwygViewModel, completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init(suggestions: suggestions)), mediaProvider: MediaProviderMock(configuration: .init()), mentionDisplayHelper: ComposerMentionDisplayHelper.mock, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, + appSettings: appSettings, + analyticsService: analytics, composerDraftService: ComposerDraftServiceMock(.init())) viewModel.state.bindings.composerFocused = focused viewModel.state.bindings.plainComposerText = NSAttributedString(string: message) diff --git a/ElementX/Sources/Screens/RoomScreen/ComposerToolbar/View/RoomAttachmentPicker.swift b/ElementX/Sources/Screens/RoomScreen/ComposerToolbar/View/RoomAttachmentPicker.swift index e78b01fbe..65a8d0c8e 100644 --- a/ElementX/Sources/Screens/RoomScreen/ComposerToolbar/View/RoomAttachmentPicker.swift +++ b/ElementX/Sources/Screens/RoomScreen/ComposerToolbar/View/RoomAttachmentPicker.swift @@ -78,14 +78,20 @@ struct RoomAttachmentPicker: View { } struct RoomAttachmentPicker_Previews: PreviewProvider, TestablePreview { - static let viewModel = ComposerToolbarViewModel(roomProxy: JoinedRoomProxyMock(.init()), - wysiwygViewModel: WysiwygComposerViewModel(), - completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()), - mediaProvider: MediaProviderMock(configuration: .init()), - mentionDisplayHelper: ComposerMentionDisplayHelper.mock, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - composerDraftService: ComposerDraftServiceMock(.init())) + static let viewModel = makeViewModel() + + static func makeViewModel() -> ComposerToolbarViewModel { + let appSettings = AppSettings() + + return ComposerToolbarViewModel(roomProxy: JoinedRoomProxyMock(.init()), + wysiwygViewModel: WysiwygComposerViewModel(), + completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()), + mediaProvider: MediaProviderMock(configuration: .init()), + mentionDisplayHelper: ComposerMentionDisplayHelper.mock, + appSettings: appSettings, + analyticsService: .mock(settings: appSettings), + composerDraftService: ComposerDraftServiceMock(.init())) + } static var previews: some View { RoomAttachmentPicker(context: viewModel.context) diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift index bd2e07017..aef76cd64 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift @@ -456,14 +456,17 @@ extension RoomScreenViewModel { static func mock(roomProxyMock: JoinedRoomProxyMock, clientProxyMock: ClientProxyMock = ClientProxyMock(.init()), appHooks: AppHooks = AppHooks()) -> RoomScreenViewModel { - RoomScreenViewModel(userSession: UserSessionMock(.init(clientProxy: clientProxyMock)), - roomProxy: roomProxyMock, - initialSelectedPinnedEventID: nil, - ongoingCallRoomIDPublisher: .init(.init(nil)), - appSettings: ServiceLocator.shared.settings, - appHooks: appHooks, - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + + return RoomScreenViewModel(userSession: UserSessionMock(.init(clientProxy: clientProxyMock)), + roomProxy: roomProxyMock, + initialSelectedPinnedEventID: nil, + ongoingCallRoomIDPublisher: .init(.init(nil)), + appSettings: appSettings, + appHooks: appHooks, + analyticsService: analytics, + userIndicatorController: UserIndicatorControllerMock.default) } } diff --git a/ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift b/ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift index c97918480..b82c5a650 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift @@ -256,15 +256,19 @@ struct RoomScreen_Previews: PreviewProvider, TestablePreview { successor: hasSuccessor ? .init(roomId: UUID().uuidString, reason: nil) : nil, powerLevelsConfiguration: .init(canUserSendMessage: canSendMessage))) let roomViewModel = RoomScreenViewModel.mock(roomProxyMock: roomProxyMock) + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + let timelineViewModel = TimelineViewModel(roomProxy: roomProxyMock, timelineController: MockTimelineController(), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: UserIndicatorControllerMock.default, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) diff --git a/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/View/AdvancedSettingsScreen.swift b/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/View/AdvancedSettingsScreen.swift index e0ab2ba19..a72ae10de 100644 --- a/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/View/AdvancedSettingsScreen.swift +++ b/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/View/AdvancedSettingsScreen.swift @@ -162,10 +162,11 @@ private extension AppAppearance { struct AdvancedSettingsScreen_Previews: PreviewProvider, TestablePreview { static let viewModel = { AppSettings.resetAllSettings() - return AdvancedSettingsScreenViewModel(advancedSettings: AppSettings(), - analytics: ServiceLocator.shared.analytics, + let appSettings = AppSettings() + return AdvancedSettingsScreenViewModel(advancedSettings: appSettings, + analytics: .mock(settings: appSettings), clientProxy: ClientProxyMock(.init()), - userIndicatorController: UserIndicatorControllerMock()) + userIndicatorController: UserIndicatorControllerMock.default) }() static var previews: some View { diff --git a/ElementX/Sources/Screens/Settings/AnalyticsSettingsScreen/View/AnalyticsSettingsScreen.swift b/ElementX/Sources/Screens/Settings/AnalyticsSettingsScreen/View/AnalyticsSettingsScreen.swift index d356a9b8a..a39e70762 100644 --- a/ElementX/Sources/Screens/Settings/AnalyticsSettingsScreen/View/AnalyticsSettingsScreen.swift +++ b/ElementX/Sources/Screens/Settings/AnalyticsSettingsScreen/View/AnalyticsSettingsScreen.swift @@ -40,8 +40,9 @@ struct AnalyticsSettingsScreen: View { struct AnalyticsSettingsScreen_Previews: PreviewProvider, TestablePreview { static var previews: some View { let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) let viewModel = AnalyticsSettingsScreenViewModel(appSettings: appSettings, - analytics: ServiceLocator.shared.analytics) + analytics: analytics) AnalyticsSettingsScreen(context: viewModel.context) } } diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift index 4c84345b3..4ef9990fe 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift @@ -244,10 +244,11 @@ private extension Set { // MARK: - Previews struct DeveloperOptionsScreen_Previews: PreviewProvider { - static let viewModel = DeveloperOptionsScreenViewModel(developerOptions: ServiceLocator.shared.settings, - elementCallBaseURL: ServiceLocator.shared.settings.elementCallBaseURL, + static let viewModel = DeveloperOptionsScreenViewModel(developerOptions: AppSettings(), + elementCallBaseURL: AppSettings().elementCallBaseURL, appHooks: AppHooks(), clientProxy: ClientProxyMock(.init())) + static var previews: some View { ElementNavigationStack { DeveloperOptionsScreen(context: viewModel.context) diff --git a/ElementX/Sources/Screens/Settings/SettingsScreen/View/SettingsScreen.swift b/ElementX/Sources/Screens/Settings/SettingsScreen/View/SettingsScreen.swift index 1767576b0..db2f31494 100644 --- a/ElementX/Sources/Screens/Settings/SettingsScreen/View/SettingsScreen.swift +++ b/ElementX/Sources/Screens/Settings/SettingsScreen/View/SettingsScreen.swift @@ -277,7 +277,7 @@ struct SettingsScreen_Previews: PreviewProvider, TestablePreview { let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@userid:example.com", deviceID: "AAAAAAAAAAA")))) return SettingsScreenViewModel(userSession: userSession, - appSettings: ServiceLocator.shared.settings, + appSettings: AppSettings(), isBugReportServiceEnabled: isBugReportServiceEnabled, isInSecondaryWindow: false) } diff --git a/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/View/UserDetailsEditScreen.swift b/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/View/UserDetailsEditScreen.swift index b79fb74bf..cb0717838 100644 --- a/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/View/UserDetailsEditScreen.swift +++ b/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/View/UserDetailsEditScreen.swift @@ -141,7 +141,7 @@ struct UserDetailsEditScreen_Previews: PreviewProvider, TestablePreview { UserDetailsEditScreenViewModel(userSession: UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@stefan:matrix.org", canChangeAvatar: canChangeProfile, canChangeDisplayName: canChangeProfile)))), - mediaUploadingPreprocessor: .init(appSettings: ServiceLocator.shared.settings), + mediaUploadingPreprocessor: .init(appSettings: AppSettings()), userIndicatorController: UserIndicatorControllerMock.default) } } diff --git a/ElementX/Sources/Screens/Spaces/SpaceSettingsScreen/View/SpaceSettingsScreen.swift b/ElementX/Sources/Screens/Spaces/SpaceSettingsScreen/View/SpaceSettingsScreen.swift index 66cc708ec..b57f9d9a5 100644 --- a/ElementX/Sources/Screens/Spaces/SpaceSettingsScreen/View/SpaceSettingsScreen.swift +++ b/ElementX/Sources/Screens/Spaces/SpaceSettingsScreen/View/SpaceSettingsScreen.swift @@ -121,30 +121,27 @@ struct SpaceSettingsScreen: View { // MARK: - Previews struct SpaceSettingsScreen_Previews: PreviewProvider, TestablePreview { - static let ownerViewModel = RoomDetailsScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Space", - avatarURL: .mockMXCAvatar, - isSpace: true, - canonicalAlias: "#space:matrix.org", - members: .allMembersAsCreator)), - userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, - notificationSettingsProxy: NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()), - attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + static let ownerViewModel = makeViewModel(members: .allMembersAsCreator) - static let userViewModel = RoomDetailsScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Space", - avatarURL: .mockMXCAvatar, - isSpace: true, - canonicalAlias: "#space:matrix.org", - members: .allMembers)), - userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, - notificationSettingsProxy: NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()), - attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + static let userViewModel = makeViewModel(members: .allMembers) + static func makeViewModel(members: [RoomMemberProxyMock]) -> RoomDetailsScreenViewModel { + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + + return RoomDetailsScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Space", + avatarURL: .mockMXCAvatar, + isSpace: true, + canonicalAlias: "#space:matrix.org", + members: members)), + userSession: UserSessionMock(.init()), + analyticsService: analytics, + userIndicatorController: UserIndicatorControllerMock.default, + notificationSettingsProxy: NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()), + attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), + appSettings: appSettings) + } + static var previews: some View { ElementNavigationStack { SpaceSettingsScreen(context: ownerViewModel.context) diff --git a/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift b/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift index 9579e72d2..72675e2d3 100644 --- a/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift +++ b/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift @@ -82,11 +82,15 @@ struct JoinRoomByAddressView_Previews: PreviewProvider, TestablePreview { let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@userid:example.com")))) let userDiscoveryService = UserDiscoveryServiceMock() userDiscoveryService.searchProfilesWithReturnValue = .success([.mockAlice]) + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return StartChatScreenViewModel(userSession: userSession, - analytics: ServiceLocator.shared.analytics, + analytics: analytics, userIndicatorController: UserIndicatorControllerMock(), userDiscoveryService: userDiscoveryService, - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) }() static var previews: some View { diff --git a/ElementX/Sources/Screens/StartChatScreen/View/StartChatScreen.swift b/ElementX/Sources/Screens/StartChatScreen/View/StartChatScreen.swift index 7f5492b3f..8ca3d8a33 100644 --- a/ElementX/Sources/Screens/StartChatScreen/View/StartChatScreen.swift +++ b/ElementX/Sources/Screens/StartChatScreen/View/StartChatScreen.swift @@ -159,7 +159,7 @@ struct StartChatScreen_Previews: PreviewProvider, TestablePreview { let userDiscoveryService = UserDiscoveryServiceMock() userDiscoveryService.searchProfilesWithReturnValue = .success([.mockAlice]) return StartChatScreenViewModel(userSession: userSession, - analytics: ServiceLocator.shared.analytics, + analytics: .mock(settings: appSettings), userIndicatorController: UserIndicatorControllerMock(), userDiscoveryService: userDiscoveryService, appSettings: appSettings) diff --git a/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift b/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift index f803249a8..ce37d99d1 100644 --- a/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift +++ b/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift @@ -1056,16 +1056,20 @@ extension TimelineViewModel { clientProxyMock.roomSummaryForAliasReturnValue = .mock(id: "!room:matrix.org", name: "Room") clientProxyMock.roomSummaryForIdentifierReturnValue = .mock(id: "!room:matrix.org", name: "Room", canonicalAlias: "#room:matrix.org") let roomProxy = JoinedRoomProxyMock(.init(name: "Preview room", predecessor: hasPredecessor ? .init(roomId: UUID().uuidString) : nil)) + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return TimelineViewModel(roomProxy: roomProxy, focussedEventID: nil, timelineController: timelineController ?? MockTimelineController(timelineKind: timelineKind), userSession: UserSessionMock(.init(clientProxy: clientProxyMock)), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: UserIndicatorControllerMock.default, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) } diff --git a/ElementX/Sources/Screens/Timeline/View/ItemMenu/TimelineItemMenu.swift b/ElementX/Sources/Screens/Timeline/View/ItemMenu/TimelineItemMenu.swift index fcec60475..aebd6a080 100644 --- a/ElementX/Sources/Screens/Timeline/View/ItemMenu/TimelineItemMenu.swift +++ b/ElementX/Sources/Screens/Timeline/View/ItemMenu/TimelineItemMenu.swift @@ -342,7 +342,7 @@ struct TimelineItemMenu_Previews: PreviewProvider, TestablePreview { isViewSourceEnabled: true, areThreadsEnabled: true, timelineKind: .live, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings)) + emojiProvider: EmojiProvider(appSettings: AppSettings())) guard let actions = provider.makeActions() else { return nil } if var textItem = item as? TextRoomTimelineItem { diff --git a/ElementX/Sources/Screens/Timeline/View/ReadReceipts/ReadReceiptsSummaryView.swift b/ElementX/Sources/Screens/Timeline/View/ReadReceipts/ReadReceiptsSummaryView.swift index 7e55c9591..a37445af5 100644 --- a/ElementX/Sources/Screens/Timeline/View/ReadReceipts/ReadReceiptsSummaryView.swift +++ b/ElementX/Sources/Screens/Timeline/View/ReadReceipts/ReadReceiptsSummaryView.swift @@ -44,15 +44,19 @@ struct ReadReceiptsSummaryView_Previews: PreviewProvider, TestablePreview { .mockDan ] let roomProxyMock = JoinedRoomProxyMock(.init(name: "Room", members: members)) + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return TimelineViewModel(roomProxy: roomProxyMock, timelineController: MockTimelineController(), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), userIndicatorController: UserIndicatorControllerMock(), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) }() diff --git a/ElementX/Sources/Screens/Timeline/View/Style/TimelineItemBubbledStylerView.swift b/ElementX/Sources/Screens/Timeline/View/Style/TimelineItemBubbledStylerView.swift index 65e6b4914..f40b19278 100644 --- a/ElementX/Sources/Screens/Timeline/View/Style/TimelineItemBubbledStylerView.swift +++ b/ElementX/Sources/Screens/Timeline/View/Style/TimelineItemBubbledStylerView.swift @@ -343,11 +343,11 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview timelineController: MockTimelineController(), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: UserIndicatorControllerMock.default, appMediator: AppMediatorMock.default, appSettings: appSettings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + analyticsService: .mock(settings: appSettings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) }() @@ -362,11 +362,11 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview timelineController: MockTimelineController(), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: UserIndicatorControllerMock.default, appMediator: AppMediatorMock.default, appSettings: appSettings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + analyticsService: .mock(settings: appSettings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) }() diff --git a/ElementX/Sources/Screens/Timeline/View/Supplementary/TimelineReadReceiptsView.swift b/ElementX/Sources/Screens/Timeline/View/Supplementary/TimelineReadReceiptsView.swift index 682b66f54..a66402afd 100644 --- a/ElementX/Sources/Screens/Timeline/View/Supplementary/TimelineReadReceiptsView.swift +++ b/ElementX/Sources/Screens/Timeline/View/Supplementary/TimelineReadReceiptsView.swift @@ -79,18 +79,23 @@ struct TimelineReadReceiptsView_Previews: PreviewProvider, TestablePreview { .mockMe ] - static let viewModel = TimelineViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Test", members: members)), - timelineController: MockTimelineController(), - userSession: UserSessionMock(.init()), - mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController, - appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), - linkMetadataProvider: LinkMetadataProvider(), - timelineControllerFactory: TimelineControllerFactoryMock(.init())) - + static let viewModel = { + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + + return TimelineViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Test", members: members)), + timelineController: MockTimelineController(), + userSession: UserSessionMock(.init()), + mediaPlayerProvider: MediaPlayerProviderMock(), + userIndicatorController: UserIndicatorControllerMock.default, + appMediator: AppMediatorMock.default, + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), + linkMetadataProvider: LinkMetadataProvider(), + timelineControllerFactory: TimelineControllerFactoryMock(.init())) + }() + static let singleReceipt = [ReadReceipt(userID: RoomMemberProxyMock.mockAlice.userID, formattedTimestamp: "Now")] static let doubleReceipt = [ReadReceipt(userID: RoomMemberProxyMock.mockAlice.userID, formattedTimestamp: "Now"), ReadReceipt(userID: RoomMemberProxyMock.mockBob.userID, formattedTimestamp: "Before")] diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/HighlightedTimelineItemModifier.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/HighlightedTimelineItemModifier.swift index 1a96d6846..80b3cc3fe 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/HighlightedTimelineItemModifier.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/HighlightedTimelineItemModifier.swift @@ -89,18 +89,23 @@ struct HighlightedTimelineItemTimeline_Previews: PreviewProvider { static let roomViewModel = RoomScreenViewModel.mock(roomProxyMock: roomProxyMock) static let focussedEventID = "RoomTimelineItemFixtures.default.5" static let composerViewModel = ComposerToolbarViewModel.mock() - static let timelineViewModel = TimelineViewModel(roomProxy: roomProxyMock, - focussedEventID: focussedEventID, - timelineController: MockTimelineController(), - userSession: UserSessionMock(.init()), - mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController, - appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), - linkMetadataProvider: LinkMetadataProvider(), - timelineControllerFactory: TimelineControllerFactoryMock(.init())) + static let timelineViewModel = { + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + + return TimelineViewModel(roomProxy: roomProxyMock, + focussedEventID: focussedEventID, + timelineController: MockTimelineController(), + userSession: UserSessionMock(.init()), + mediaPlayerProvider: MediaPlayerProviderMock(), + userIndicatorController: UserIndicatorControllerMock.default, + appMediator: AppMediatorMock.default, + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), + linkMetadataProvider: LinkMetadataProvider(), + timelineControllerFactory: TimelineControllerFactoryMock(.init())) + }() static var previews: some View { ElementNavigationStack { diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineView.swift index 7deffb181..6f5f7a8ab 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineView.swift @@ -146,17 +146,22 @@ struct TimelineView_Previews: PreviewProvider { // Not testable as this preview name: "Preview room")) static let roomViewModel = RoomScreenViewModel.mock(roomProxyMock: roomProxyMock) static let composerViewModel = ComposerToolbarViewModel.mock() - static let timelineViewModel = TimelineViewModel(roomProxy: roomProxyMock, - timelineController: MockTimelineController(), - userSession: UserSessionMock(.init()), - mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController, - appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), - linkMetadataProvider: LinkMetadataProvider(), - timelineControllerFactory: TimelineControllerFactoryMock(.init())) + static let timelineViewModel = { + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + + return TimelineViewModel(roomProxy: roomProxyMock, + timelineController: MockTimelineController(), + userSession: UserSessionMock(.init()), + mediaPlayerProvider: MediaPlayerProviderMock(), + userIndicatorController: UserIndicatorControllerMock.default, + appMediator: AppMediatorMock.default, + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), + linkMetadataProvider: LinkMetadataProvider(), + timelineControllerFactory: TimelineControllerFactoryMock(.init())) + }() static var previews: some View { ElementNavigationStack { diff --git a/ElementX/Sources/Screens/UserProfileScreen/View/UserProfileScreen.swift b/ElementX/Sources/Screens/UserProfileScreen/View/UserProfileScreen.swift index ce17b2f4b..2880b3a73 100644 --- a/ElementX/Sources/Screens/UserProfileScreen/View/UserProfileScreen.swift +++ b/ElementX/Sources/Screens/UserProfileScreen/View/UserProfileScreen.swift @@ -142,12 +142,15 @@ struct UserProfileScreen_Previews: PreviewProvider, TestablePreview { if userID != RoomMemberProxyMock.mockMe.userID { clientProxyMock.directRoomForUserIDReturnValue = .success("roomID") } - + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + return UserProfileScreenViewModel(userID: userID, isPresentedModally: false, userSession: UserSessionMock(.init(clientProxy: clientProxyMock)), - userIndicatorController: ServiceLocator.shared.userIndicatorController, - analytics: ServiceLocator.shared.analytics, - appSettings: ServiceLocator.shared.settings) + userIndicatorController: UserIndicatorControllerMock.default, + analytics: analytics, + appSettings: appSettings) } } diff --git a/ElementX/Sources/Services/Analytics/Helpers/Analytics+SwiftUI.swift b/ElementX/Sources/Services/Analytics/Helpers/Analytics+SwiftUI.swift index 98d3abfe6..96b9b4beb 100644 --- a/ElementX/Sources/Services/Analytics/Helpers/Analytics+SwiftUI.swift +++ b/ElementX/Sources/Services/Analytics/Helpers/Analytics+SwiftUI.swift @@ -9,5 +9,5 @@ import SwiftUI extension EnvironmentValues { - @Entry var analyticsService: AnalyticsService = ServiceLocator.shared.analytics + @Entry var analyticsService: AnalyticsService? } diff --git a/ElementX/Sources/Services/Authentication/AuthenticationService.swift b/ElementX/Sources/Services/Authentication/AuthenticationService.swift index 9be44dde3..3209b7321 100644 --- a/ElementX/Sources/Services/Authentication/AuthenticationService.swift +++ b/ElementX/Sources/Services/Authentication/AuthenticationService.swift @@ -382,13 +382,13 @@ extension AuthenticationService { static var mock: AuthenticationService { mock(classicAppManager: nil) } - + static func mock(classicAppManager: ClassicAppManagerProtocol?) -> AuthenticationService { AuthenticationService(userSessionStore: UserSessionStoreMock(configuration: .init()), encryptionKeyProvider: EncryptionKeyProvider(), classicAppManager: classicAppManager, clientFactory: AuthenticationClientFactoryMock(configuration: .init()), - appSettings: ServiceLocator.shared.settings, + appSettings: AppSettings(), appHooks: AppHooks()) } } diff --git a/ElementX/Sources/Services/Timeline/TimelineController/TimelineControllerFactory.swift b/ElementX/Sources/Services/Timeline/TimelineController/TimelineControllerFactory.swift index a6c520e8c..f2181ea59 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/TimelineControllerFactory.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/TimelineControllerFactory.swift @@ -10,6 +10,8 @@ import Foundation import MatrixRustSDK struct TimelineControllerFactory: TimelineControllerFactoryProtocol { + let appSettings: AppSettings + func buildTimelineController(roomProxy: JoinedRoomProxyProtocol, initialFocussedEventID: String?, timelineItemFactory: RoomTimelineItemFactoryProtocol, @@ -19,7 +21,7 @@ struct TimelineControllerFactory: TimelineControllerFactoryProtocol { initialFocussedEventID: initialFocussedEventID, timelineItemFactory: timelineItemFactory, mediaProvider: mediaProvider, - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) } func buildThreadTimelineController(threadRootEventID: String, @@ -34,7 +36,7 @@ struct TimelineControllerFactory: TimelineControllerFactoryProtocol { initialFocussedEventID: initialFocussedEventID, timelineItemFactory: timelineItemFactory, mediaProvider: mediaProvider, - appSettings: ServiceLocator.shared.settings)) + appSettings: appSettings)) case .failure(let error): return .failure(.roomProxyError(error)) } @@ -50,7 +52,7 @@ struct TimelineControllerFactory: TimelineControllerFactoryProtocol { initialFocussedEventID: nil, timelineItemFactory: timelineItemFactory, mediaProvider: mediaProvider, - appSettings: ServiceLocator.shared.settings)) + appSettings: appSettings)) case .failure(let error): return .failure(.roomProxyError(error)) } @@ -69,7 +71,7 @@ struct TimelineControllerFactory: TimelineControllerFactoryProtocol { initialFocussedEventID: nil, timelineItemFactory: timelineItemFactory, mediaProvider: mediaProvider, - appSettings: ServiceLocator.shared.settings)) + appSettings: appSettings)) case .failure(let error): return .failure(.roomProxyError(error)) } diff --git a/ElementX/Sources/UITests/UITestsAppCoordinator.swift b/ElementX/Sources/UITests/UITestsAppCoordinator.swift index fefb6ba0c..456fa43b4 100644 --- a/ElementX/Sources/UITests/UITestsAppCoordinator.swift +++ b/ElementX/Sources/UITests/UITestsAppCoordinator.swift @@ -12,6 +12,10 @@ import SwiftUI import UIKit class UITestsAppCoordinator: AppCoordinatorProtocol, SecureWindowManagerDelegate { + private let appSettings: AppSettings + private let analytics: AnalyticsService + private let userIndicatorController: UserIndicatorControllerProtocol + private let navigationRootCoordinator: NavigationRootCoordinator // periphery:ignore - retaining purpose @@ -29,26 +33,30 @@ class UITestsAppCoordinator: AppCoordinatorProtocol, SecureWindowManagerDelegate navigationRootCoordinator = NavigationRootCoordinator() - windowManager.delegate = self - MXLog.configure(currentTarget: "uitests") - ServiceLocator.shared.register(userIndicatorController: UserIndicatorController()) - AppSettings.configureWithSuiteName("io.element.elementx.uitests") AppSettings.resetAllSettings() - ServiceLocator.shared.register(appSettings: AppSettings()) + appSettings = AppSettings() let analyticsClient = AnalyticsClientMock() analyticsClient.isRunning = false - ServiceLocator.shared.register(analytics: AnalyticsService(client: analyticsClient, - appSettings: ServiceLocator.shared.settings)) + + analytics = .mock(analyticsClient, settings: appSettings) + userIndicatorController = UserIndicatorController() + + windowManager.delegate = self } func start() { guard let screenID = ProcessInfo.testScreenID else { fatalError("Unable to launch with unknown screen.") } - let mockScreen = MockScreen(id: screenID, windowManager: windowManager, navigationRootCoordinator: navigationRootCoordinator) + let mockScreen = MockScreen(id: screenID, + windowManager: windowManager, + navigationRootCoordinator: navigationRootCoordinator, + appSettings: appSettings, + analytics: analytics, + userIndicatorController: userIndicatorController) if let coordinator = mockScreen.coordinator { navigationRootCoordinator.setRootCoordinator(coordinator) @@ -58,7 +66,8 @@ class UITestsAppCoordinator: AppCoordinatorProtocol, SecureWindowManagerDelegate } func toPresentable() -> AnyView { - navigationRootCoordinator.toPresentable() + AnyView(navigationRootCoordinator.toPresentable() + .environment(\.analyticsService, analytics)) } func handlePotentialPhishingAttempt(url: URL, openURLAction: @escaping (URL) -> Void) -> Bool { @@ -78,13 +87,16 @@ class UITestsAppCoordinator: AppCoordinatorProtocol, SecureWindowManagerDelegate } func windowManagerDidConfigureWindows(_ windowManager: SecureWindowManagerProtocol) { - ServiceLocator.shared.userIndicatorController.window = windowManager.overlayWindow + userIndicatorController.window = windowManager.overlayWindow // Set up the alternate window for the App Lock flow coordinator tests. guard let screenID = ProcessInfo.testScreenID, screenID == .appLockFlow || screenID == .appLockFlowDisabled else { return } let screen = MockScreen(id: screenID == .appLockFlow ? .appLockFlowAlternateWindow : .appLockFlowDisabledAlternateWindow, windowManager: windowManager, - navigationRootCoordinator: navigationRootCoordinator) + navigationRootCoordinator: navigationRootCoordinator, + appSettings: appSettings, + analytics: analytics, + userIndicatorController: userIndicatorController) guard let coordinator = screen.coordinator else { fatalError() @@ -102,6 +114,10 @@ class MockScreen: Identifiable { let windowManager: SecureWindowManagerProtocol let navigationRootCoordinator: NavigationRootCoordinator + private let appSettings: AppSettings + private let analytics: AnalyticsService + private let userIndicatorController: UserIndicatorControllerProtocol + private var client: UITestsSignalling.Client? private var retainedState = [Any]() @@ -109,10 +125,16 @@ class MockScreen: Identifiable { init(id: UITestsScreenIdentifier, windowManager: SecureWindowManagerProtocol, - navigationRootCoordinator: NavigationRootCoordinator) { + navigationRootCoordinator: NavigationRootCoordinator, + appSettings: AppSettings, + analytics: AnalyticsService, + userIndicatorController: UserIndicatorControllerProtocol) { self.id = id self.windowManager = windowManager self.navigationRootCoordinator = navigationRootCoordinator + self.appSettings = appSettings + self.analytics = analytics + self.userIndicatorController = userIndicatorController } lazy var coordinator: CoordinatorProtocol? = { @@ -121,12 +143,12 @@ class MockScreen: Identifiable { let navigationStackCoordinator = NavigationStackCoordinator() let coordinator = ServerSelectionScreenCoordinator(parameters: .init(authenticationService: AuthenticationService.mock, authenticationFlow: .login, - appSettings: ServiceLocator.shared.settings, - userIndicatorController: ServiceLocator.shared.userIndicatorController)) + appSettings: appSettings, + userIndicatorController: userIndicatorController)) navigationStackCoordinator.setRootCoordinator(coordinator) return navigationStackCoordinator case .authenticationFlow, .provisionedAuthenticationFlow, .singleProviderAuthenticationFlow, .multipleProvidersAuthenticationFlow: - let appSettings: AppSettings! = ServiceLocator.shared.settings + let appSettings: AppSettings! = appSettings if id == .singleProviderAuthenticationFlow || id == .multipleProvidersAuthenticationFlow { let accountProviders = id == .singleProviderAuthenticationFlow ? ["example.com"] : ["guest.example.com", "example.com"] @@ -158,8 +180,8 @@ class MockScreen: Identifiable { appMediator: AppMediatorMock.default, appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + analytics: analytics, + userIndicatorController: userIndicatorController) flowCoordinator.start() retainedState.append(flowCoordinator) @@ -184,7 +206,7 @@ class MockScreen: Identifiable { context.evaluatedPolicyDomainStateValue = Data("😎".utf8) let appLockService = AppLockService(keychainController: keychainController, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, context: context) if id == .appLockFlowAlternateWindow { @@ -206,7 +228,7 @@ class MockScreen: Identifiable { appLockService: appLockService, navigationCoordinator: navigationCoordinator, notificationCenter: notificationCenter, - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) flowCoordinator.actions .sink { [weak self] action in @@ -240,7 +262,7 @@ class MockScreen: Identifiable { context.evaluatedPolicyDomainStateValue = Data("😎".utf8) let appLockService = AppLockService(keychainController: keychainController, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, context: context) if id == .appLockSetupFlowUnlock, case .failure = appLockService.setupPINCode("2023") { fatalError("Failed to pre-set the PIN code") @@ -272,14 +294,14 @@ class MockScreen: Identifiable { roomProxy: JoinedRoomProxyMock(.init(name: "Some room name", avatarURL: nil)), timelineController: MockTimelineController(), mediaPlayerProvider: MediaPlayerProviderMock(), - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()), ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init()), userIndicatorController: UserIndicatorControllerMock()) @@ -294,14 +316,14 @@ class MockScreen: Identifiable { roomProxy: JoinedRoomProxyMock(.init(name: "New room", avatarURL: .mockMXCAvatar)), timelineController: timelineController, mediaPlayerProvider: MediaPlayerProviderMock(), - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()), ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init()), userIndicatorController: UserIndicatorControllerMock()) @@ -316,14 +338,14 @@ class MockScreen: Identifiable { roomProxy: JoinedRoomProxyMock(.init(name: "New room", avatarURL: .mockMXCAvatar)), timelineController: timelineController, mediaPlayerProvider: MediaPlayerProviderMock(), - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()), ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init()), userIndicatorController: UserIndicatorControllerMock()) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -337,14 +359,14 @@ class MockScreen: Identifiable { roomProxy: JoinedRoomProxyMock(.init(name: "New room", avatarURL: .mockMXCAvatar)), timelineController: timelineController, mediaPlayerProvider: MediaPlayerProviderMock(), - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()), ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init()), userIndicatorController: UserIndicatorControllerMock()) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -361,14 +383,14 @@ class MockScreen: Identifiable { roomProxy: JoinedRoomProxyMock(.init(name: "Small timeline", avatarURL: .mockMXCAvatar)), timelineController: timelineController, mediaPlayerProvider: MediaPlayerProviderMock(), - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()), ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init()), userIndicatorController: UserIndicatorControllerMock()) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -385,14 +407,14 @@ class MockScreen: Identifiable { roomProxy: JoinedRoomProxyMock(.init(name: "Small timeline, paginating", avatarURL: .mockMXCAvatar)), timelineController: timelineController, mediaPlayerProvider: MediaPlayerProviderMock(), - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()), ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init()), userIndicatorController: UserIndicatorControllerMock()) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -408,14 +430,14 @@ class MockScreen: Identifiable { roomProxy: JoinedRoomProxyMock(.init(name: "Large timeline", avatarURL: .mockMXCAvatar)), timelineController: timelineController, mediaPlayerProvider: MediaPlayerProviderMock(), - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()), ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init()), userIndicatorController: UserIndicatorControllerMock()) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -433,14 +455,14 @@ class MockScreen: Identifiable { roomProxy: JoinedRoomProxyMock(.init(name: "Large timeline", avatarURL: .mockMXCAvatar)), timelineController: timelineController, mediaPlayerProvider: MediaPlayerProviderMock(), - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()), ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init()), userIndicatorController: UserIndicatorControllerMock()) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -457,14 +479,14 @@ class MockScreen: Identifiable { roomProxy: JoinedRoomProxyMock(.init(name: "Large timeline", avatarURL: .mockMXCAvatar)), timelineController: timelineController, mediaPlayerProvider: MediaPlayerProviderMock(), - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()), ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init()), userIndicatorController: UserIndicatorControllerMock()) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -480,14 +502,14 @@ class MockScreen: Identifiable { roomProxy: JoinedRoomProxyMock(.init(name: "Timeline highlight", avatarURL: .mockMXCAvatar)), timelineController: timelineController, mediaPlayerProvider: MediaPlayerProviderMock(), - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()), ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init()), userIndicatorController: UserIndicatorControllerMock()) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -517,14 +539,14 @@ class MockScreen: Identifiable { roomProxy: JoinedRoomProxyMock(.init(name: "Polls timeline", avatarURL: .mockMXCAvatar)), timelineController: timelineController, mediaPlayerProvider: MediaPlayerProviderMock(), - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()), ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init()), userIndicatorController: UserIndicatorControllerMock()) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -541,14 +563,14 @@ class MockScreen: Identifiable { roomProxy: JoinedRoomProxyMock(.init(name: "Polls timeline", avatarURL: .mockMXCAvatar)), timelineController: timelineController, mediaPlayerProvider: MediaPlayerProviderMock(), - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()), ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init()), userIndicatorController: UserIndicatorControllerMock()) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -565,14 +587,14 @@ class MockScreen: Identifiable { roomProxy: JoinedRoomProxyMock(.init(name: "Polls timeline", avatarURL: .mockMXCAvatar)), timelineController: timelineController, mediaPlayerProvider: MediaPlayerProviderMock(), - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()), ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, composerDraftService: ComposerDraftServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init()), userIndicatorController: UserIndicatorControllerMock()) let coordinator = RoomScreenCoordinator(parameters: parameters) @@ -584,11 +606,11 @@ class MockScreen: Identifiable { requestDelay: .seconds(5)) let parameters = SessionVerificationScreenCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationControllerProxy, flow: .deviceInitiator, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, mediaProvider: MediaProviderMock(configuration: .init())) return SessionVerificationScreenCoordinator(parameters: parameters) case .userSessionScreen, .userSessionScreenReply, .userSessionSpacesFlow: - let appSettings: AppSettings = ServiceLocator.shared.settings + let appSettings: AppSettings = appSettings appSettings.hasRunIdentityConfirmationOnboarding = true appSettings.hasRunNotificationPermissionsOnboarding = true appSettings.analyticsConsentState = .optedOut @@ -616,7 +638,7 @@ class MockScreen: Identifiable { let flowCoordinator = UserSessionFlowCoordinator(isNewLogin: false, navigationRootCoordinator: navigationRootCoordinator, appLockService: AppLockService(keychainController: KeychainControllerMock(), - appSettings: ServiceLocator.shared.settings), + appSettings: appSettings), flowParameters: CommonFlowParameters(userSession: UserSessionMock(.init(clientProxy: clientProxy)), bugReportService: BugReportServiceMock(.init()), elementCallService: ElementCallServiceMock(.init()), @@ -626,7 +648,7 @@ class MockScreen: Identifiable { appMediator: appMediator, appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, userIndicatorController: UserIndicatorControllerMock(), notificationManager: NotificationManagerMock(), stateMachineFactory: StateMachineFactory())) @@ -641,8 +663,8 @@ class MockScreen: Identifiable { let members: [RoomMemberProxyMock] = [.mockInvitedAlice, .mockBob, .mockCharlie] let coordinator = RoomMembersListScreenCoordinator(parameters: .init(userSession: UserSessionMock(.init()), roomProxy: JoinedRoomProxyMock(.init(name: "test", members: members)), - userIndicatorController: ServiceLocator.shared.userIndicatorController, - analytics: ServiceLocator.shared.analytics)) + userIndicatorController: userIndicatorController, + analytics: analytics)) navigationStackCoordinator.setRootCoordinator(coordinator) return navigationStackCoordinator case .roomRolesAndPermissionsFlow: @@ -651,8 +673,8 @@ class MockScreen: Identifiable { let coordinator = RoomRolesAndPermissionsFlowCoordinator(parameters: .init(roomProxy: JoinedRoomProxyMock(.init(members: .allMembersAsAdmin)), mediaProvider: MediaProviderMock(configuration: .init()), navigationStackCoordinator: navigationStackCoordinator, - userIndicatorController: ServiceLocator.shared.userIndicatorController, - analytics: ServiceLocator.shared.analytics)) + userIndicatorController: userIndicatorController, + analytics: analytics)) retainedState.append(coordinator) coordinator.start() return navigationStackCoordinator @@ -673,12 +695,12 @@ class MockScreen: Identifiable { bugReportService: BugReportServiceMock(.init()), elementCallService: ElementCallServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init()), - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, userIndicatorController: UserIndicatorControllerMock(), notificationManager: NotificationManagerMock(), stateMachineFactory: StateMachineFactory())) @@ -705,7 +727,7 @@ class MockScreen: Identifiable { let coordinator = PollFormScreenCoordinator(parameters: .init(mode: .new, maxNumberOfOptions: 10, timelineController: MockTimelineController(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, userIndicatorController: UserIndicatorControllerMock())) navigationStackCoordinator.setRootCoordinator(coordinator) return navigationStackCoordinator @@ -718,7 +740,7 @@ class MockScreen: Identifiable { navigationStackCoordinator.setRootCoordinator(BlankFormCoordinator()) let coordinator = EncryptionSettingsFlowCoordinator(parameters: .init(userSession: userSession, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, userIndicatorController: UserIndicatorControllerMock(), navigationStackCoordinator: navigationStackCoordinator)) retainedState.append(coordinator) @@ -736,7 +758,7 @@ class MockScreen: Identifiable { let coordinator = EncryptionResetFlowCoordinator(parameters: .init(userSession: userSession, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), userIndicatorController: userIndicatorController, navigationStackCoordinator: navigationStackCoordinator, @@ -759,12 +781,12 @@ class MockScreen: Identifiable { bugReportService: BugReportServiceMock(.init()), elementCallService: ElementCallServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init()), - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, userIndicatorController: UserIndicatorControllerMock(), notificationManager: NotificationManagerMock(), stateMachineFactory: StateMachineFactory())) @@ -787,7 +809,7 @@ class MockScreen: Identifiable { navigationRootCoordinator.setSheetCoordinator(navigationStackCoordinator) return PlaceholderScreenCoordinator(hideBrandChrome: false) case .autoUpdatingTimeline: - let appSettings: AppSettings = ServiceLocator.shared.settings + let appSettings: AppSettings = appSettings appSettings.hasRunIdentityConfirmationOnboarding = true appSettings.hasRunNotificationPermissionsOnboarding = true appSettings.analyticsConsentState = .optedOut @@ -807,7 +829,7 @@ class MockScreen: Identifiable { attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), stateEventStringBuilder: RoomStateEventStringBuilder(userID: "@alice:matrix.org")), mediaProvider: MediaProviderMock(configuration: .init()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) let flowCoordinator = ChatsTabFlowCoordinator(isNewLogin: false, navigationSplitCoordinator: navigationSplitCoordinator, @@ -820,7 +842,7 @@ class MockScreen: Identifiable { appMediator: AppMediatorMock.default, appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, userIndicatorController: UserIndicatorControllerMock(), notificationManager: NotificationManagerMock(), stateMachineFactory: StateMachineFactory())) diff --git a/ElementX/Sources/UnitTests/UnitTestsAppCoordinator.swift b/ElementX/Sources/UnitTests/UnitTestsAppCoordinator.swift index d2ed1bd1e..ac04a6905 100644 --- a/ElementX/Sources/UnitTests/UnitTestsAppCoordinator.swift +++ b/ElementX/Sources/UnitTests/UnitTestsAppCoordinator.swift @@ -17,17 +17,10 @@ class UnitTestsAppCoordinator: AppCoordinatorProtocol { init(appDelegate: AppDelegate) { windowManager = WindowManager(appDelegate: appDelegate) - ServiceLocator.shared.register(userIndicatorController: UserIndicatorControllerMock.default) AppSettings.configureWithSuiteName("io.element.elementx.unittests") AppSettings.resetAllSettings() - ServiceLocator.shared.register(appSettings: AppSettings()) - - let analyticsClient = AnalyticsClientMock() - analyticsClient.isRunning = false - ServiceLocator.shared.register(analytics: AnalyticsService(client: analyticsClient, - appSettings: ServiceLocator.shared.settings)) - + // As the tests take advantage of Rust's ability to redirect the log files, there is // often some debris left from the previous run, so we wipe the entire directory. // This is an NOT an advised way to delete logs in production, `Tracing.deleteLogFiles` diff --git a/UnitTests/Sources/AnalyticsSettingsScreenViewModelTests.swift b/UnitTests/Sources/AnalyticsSettingsScreenViewModelTests.swift index 054e8c371..970c8cd86 100644 --- a/UnitTests/Sources/AnalyticsSettingsScreenViewModelTests.swift +++ b/UnitTests/Sources/AnalyticsSettingsScreenViewModelTests.swift @@ -11,20 +11,19 @@ import Testing @MainActor final class AnalyticsSettingsScreenViewModelTests { - private var appSettings: AppSettings! + private let appSettings: AppSettings + private let analytics: AnalyticsService + private var viewModel: AnalyticsSettingsScreenViewModelProtocol! private var context: AnalyticsSettingsScreenViewModelType.Context! init() { AppSettings.resetAllSettings() appSettings = AppSettings() - let analyticsClient = AnalyticsClientMock() - analyticsClient.isRunning = false - ServiceLocator.shared.register(analytics: AnalyticsService(client: analyticsClient, - appSettings: appSettings)) - + analytics = .mock(settings: appSettings) + viewModel = AnalyticsSettingsScreenViewModel(appSettings: appSettings, - analytics: ServiceLocator.shared.analytics) + analytics: analytics) context = viewModel.context } diff --git a/UnitTests/Sources/AnalyticsTests.swift b/UnitTests/Sources/AnalyticsTests.swift index f740d7106..a79c169a5 100644 --- a/UnitTests/Sources/AnalyticsTests.swift +++ b/UnitTests/Sources/AnalyticsTests.swift @@ -12,18 +12,19 @@ import PostHog import Testing final class AnalyticsTests { - private var appSettings: AppSettings - private var analyticsClient: AnalyticsClientMock + private let appSettings: AppSettings + private let analytics: AnalyticsService + private let analyticsClient: AnalyticsClientMock private var posthogMock: PHGPostHogMock + @MainActor init() { AppSettings.resetAllSettings() appSettings = AppSettings() analyticsClient = AnalyticsClientMock() analyticsClient.isRunning = false - ServiceLocator.shared.register(analytics: AnalyticsService(client: analyticsClient, - appSettings: appSettings)) + analytics = .mock(analyticsClient, settings: appSettings) posthogMock = PHGPostHogMock() posthogMock.configureMockBehavior() @@ -37,7 +38,7 @@ final class AnalyticsTests { func analyticsPromptNewUser() { // Given a fresh install of the app (without PostHog analytics having been set). // When the user is prompted for analytics. - let showPrompt = ServiceLocator.shared.analytics.shouldShowAnalyticsPrompt + let showPrompt = analytics.shouldShowAnalyticsPrompt // Then the prompt should be shown. #expect(showPrompt, "A prompt should be shown for a new user.") @@ -49,7 +50,7 @@ final class AnalyticsTests { appSettings.analyticsConsentState = .optedOut // When the user is prompted for analytics - let showPrompt = ServiceLocator.shared.analytics.shouldShowAnalyticsPrompt + let showPrompt = analytics.shouldShowAnalyticsPrompt // Then no prompt should be shown. #expect(!showPrompt, "A prompt should not be shown any more.") @@ -61,7 +62,7 @@ final class AnalyticsTests { appSettings.analyticsConsentState = .optedIn // When the user is prompted for analytics - let showPrompt = ServiceLocator.shared.analytics.shouldShowAnalyticsPrompt + let showPrompt = analytics.shouldShowAnalyticsPrompt // Then no prompt should be shown. #expect(!showPrompt, "A prompt should not be shown any more.") @@ -71,7 +72,7 @@ final class AnalyticsTests { func analyticsPromptNotDisplayed() { // Given a fresh install of the app Analytics should be disabled #expect(appSettings.analyticsConsentState == .unknown) - #expect(!ServiceLocator.shared.analytics.isEnabled) + #expect(!analytics.isEnabled) #expect(!analyticsClient.startAnalyticsConfigurationCalled) } @@ -79,10 +80,10 @@ final class AnalyticsTests { func analyticsOptOut() { // Given a fresh install of the app (without PostHog analytics having been set). // When analytics is opt-out - ServiceLocator.shared.analytics.optOut() + analytics.optOut() // Then analytics should be disabled #expect(appSettings.analyticsConsentState == .optedOut) - #expect(!ServiceLocator.shared.analytics.isEnabled) + #expect(!analytics.isEnabled) #expect(!analyticsClient.isRunning) // Analytics client should have been stopped #expect(analyticsClient.stopCalled) @@ -92,10 +93,10 @@ final class AnalyticsTests { func analyticsOptIn() { // Given a fresh install of the app (without PostHog analytics having been set). // When analytics is opt-in - ServiceLocator.shared.analytics.optIn() + analytics.optIn() // The analytics should be enabled #expect(appSettings.analyticsConsentState == .optedIn) - #expect(ServiceLocator.shared.analytics.isEnabled) + #expect(analytics.isEnabled) // Analytics client should have been started #expect(analyticsClient.startAnalyticsConfigurationCalled) } @@ -105,8 +106,8 @@ final class AnalyticsTests { // Given an existing install of the app where the user previously declined the tracking appSettings.analyticsConsentState = .optedOut // Analytics should not start - #expect(!ServiceLocator.shared.analytics.isEnabled) - ServiceLocator.shared.analytics.startIfEnabled() + #expect(!analytics.isEnabled) + analytics.startIfEnabled() #expect(!analyticsClient.startAnalyticsConfigurationCalled) } @@ -115,8 +116,8 @@ final class AnalyticsTests { // Given an existing install of the app where the user previously accepted the tracking appSettings.analyticsConsentState = .optedIn // Analytics should start - #expect(ServiceLocator.shared.analytics.isEnabled) - ServiceLocator.shared.analytics.startIfEnabled() + #expect(analytics.isEnabled) + analytics.startIfEnabled() #expect(analyticsClient.startAnalyticsConfigurationCalled) } @@ -214,14 +215,14 @@ final class AnalyticsTests { func resetConsentState() { // Given an existing install of the app where the user previously accpeted the tracking appSettings.analyticsConsentState = .optedIn - #expect(!ServiceLocator.shared.analytics.shouldShowAnalyticsPrompt) + #expect(!analytics.shouldShowAnalyticsPrompt) // When forgetting analytics consents - ServiceLocator.shared.analytics.resetConsentState() + analytics.resetConsentState() // Then the analytics prompt should be presented again #expect(appSettings.analyticsConsentState == .unknown) - #expect(ServiceLocator.shared.analytics.shouldShowAnalyticsPrompt) + #expect(analytics.shouldShowAnalyticsPrompt) } @Test diff --git a/UnitTests/Sources/AuthenticationServiceTests.swift b/UnitTests/Sources/AuthenticationServiceTests.swift index 38a6f6a36..05b0e0702 100644 --- a/UnitTests/Sources/AuthenticationServiceTests.swift +++ b/UnitTests/Sources/AuthenticationServiceTests.swift @@ -153,7 +153,7 @@ struct AuthenticationServiceTests { encryptionKeyProvider: encryptionKeyProvider, classicAppManager: classicAppManager, clientFactory: clientFactory, - appSettings: ServiceLocator.shared.settings, + appSettings: AppSettings(), appHooks: AppHooks()) if let classicAppAccount = service.classicAppAccount { diff --git a/UnitTests/Sources/AuthenticationStartScreenViewModelTests.swift b/UnitTests/Sources/AuthenticationStartScreenViewModelTests.swift index 11c6c8767..3ea882e34 100644 --- a/UnitTests/Sources/AuthenticationStartScreenViewModelTests.swift +++ b/UnitTests/Sources/AuthenticationStartScreenViewModelTests.swift @@ -28,8 +28,6 @@ final class AuthenticationStartScreenViewModelTests { init() { AppSettings.resetAllSettings() appSettings = AppSettings() - // These app settings are kept local to the tests on purpose as if they are registered in the - // ServiceLocator, the providers override that we apply will break other tests in the suite. } deinit { diff --git a/UnitTests/Sources/BlockedUsersScreenViewModelTests.swift b/UnitTests/Sources/BlockedUsersScreenViewModelTests.swift index b411a4747..1f19065f6 100644 --- a/UnitTests/Sources/BlockedUsersScreenViewModelTests.swift +++ b/UnitTests/Sources/BlockedUsersScreenViewModelTests.swift @@ -19,7 +19,7 @@ struct BlockedUsersScreenViewModelTests { let viewModel = BlockedUsersScreenViewModel(hideProfiles: true, userSession: UserSessionMock(.init(clientProxy: clientProxy)), - userIndicatorController: ServiceLocator.shared.userIndicatorController) + userIndicatorController: UserIndicatorControllerMock.default) let deferred = deferFailure(viewModel.context.observe(\.viewState.blockedUsers), timeout: .seconds(1)) { $0.contains { $0.displayName != nil } } try await deferred.fulfill() @@ -34,7 +34,7 @@ struct BlockedUsersScreenViewModelTests { let viewModel = BlockedUsersScreenViewModel(hideProfiles: false, userSession: UserSessionMock(.init(clientProxy: clientProxy)), - userIndicatorController: ServiceLocator.shared.userIndicatorController) + userIndicatorController: UserIndicatorControllerMock.default) let deferred = deferFulfillment(viewModel.context.observe(\.viewState.blockedUsers)) { $0.contains { $0.displayName != nil } } try await deferred.fulfill() diff --git a/UnitTests/Sources/ChatsTabFlowCoordinatorTests.swift b/UnitTests/Sources/ChatsTabFlowCoordinatorTests.swift index 55aa72776..96bc0aafb 100644 --- a/UnitTests/Sources/ChatsTabFlowCoordinatorTests.swift +++ b/UnitTests/Sources/ChatsTabFlowCoordinatorTests.swift @@ -31,6 +31,9 @@ struct ChatsTabFlowCoordinatorTests { } init() async throws { + let appSettings = AppSettings() + let analytics: AnalyticsService = .mock(settings: appSettings) + clientProxy = ClientProxyMock(.init(userID: "hi@bob", roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loaded(.mockRooms))))) timelineControllerFactory = TimelineControllerFactoryMock(.init()) @@ -42,12 +45,12 @@ struct ChatsTabFlowCoordinatorTests { bugReportService: BugReportServiceMock(.init()), elementCallService: ElementCallServiceMock(.init()), timelineControllerFactory: timelineControllerFactory, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, userIndicatorController: UserIndicatorControllerMock(), notificationManager: notificationManager, stateMachineFactory: stateMachineFactory) diff --git a/UnitTests/Sources/ComposerToolbarViewModelTests.swift b/UnitTests/Sources/ComposerToolbarViewModelTests.swift index 001f275c3..0e7003ba8 100644 --- a/UnitTests/Sources/ComposerToolbarViewModelTests.swift +++ b/UnitTests/Sources/ComposerToolbarViewModelTests.swift @@ -15,16 +15,14 @@ import WysiwygComposer @MainActor final class ComposerToolbarViewModelTests { - private var appSettings: AppSettings! private var wysiwygViewModel: WysiwygComposerViewModel! private var viewModel: ComposerToolbarViewModel! private var completionSuggestionServiceMock: CompletionSuggestionServiceMock! private var draftServiceMock: ComposerDraftServiceMock! - + init() { AppSettings.resetAllSettings() - appSettings = AppSettings() - ServiceLocator.shared.register(appSettings: appSettings) + setUpViewModel() } @@ -91,13 +89,15 @@ final class ComposerToolbarViewModelTests { .init(suggestionType: .user(.init(id: "@user_mention_2:matrix.org", displayName: "User 2", avatarURL: nil)), range: .init(), rawSuggestionText: "")] let mockCompletionSuggestionService = CompletionSuggestionServiceMock(configuration: .init(suggestions: suggestions)) + let appSettings = AppSettings() + viewModel = ComposerToolbarViewModel(roomProxy: JoinedRoomProxyMock(.init()), wysiwygViewModel: wysiwygViewModel, completionSuggestionService: mockCompletionSuggestionService, mediaProvider: MediaProviderMock(configuration: .init()), mentionDisplayHelper: ComposerMentionDisplayHelper.mock, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, + appSettings: appSettings, + analyticsService: .mock(settings: appSettings), composerDraftService: draftServiceMock) #expect(viewModel.state.suggestions == suggestions) @@ -708,13 +708,15 @@ final class ComposerToolbarViewModelTests { let mockSubject = CurrentValueSubject<[IdentityStatusChange], Never>([]) roomProxyMock.underlyingIdentityStatusChangesPublisher = mockSubject.asCurrentValuePublisher() + let appSettings = AppSettings() + viewModel = ComposerToolbarViewModel(roomProxy: roomProxyMock, wysiwygViewModel: wysiwygViewModel, completionSuggestionService: mockCompletionSuggestionService, mediaProvider: MediaProviderMock(configuration: .init()), mentionDisplayHelper: ComposerMentionDisplayHelper.mock, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, + appSettings: appSettings, + analyticsService: .mock(settings: appSettings), composerDraftService: draftServiceMock) var fulfillment = deferFulfillment(viewModel.context.$viewState, message: "Composer is disabled") { $0.canSend == false } @@ -753,13 +755,15 @@ final class ComposerToolbarViewModelTests { roomProxyMock.underlyingIdentityStatusChangesPublisher = mockSubject.asCurrentValuePublisher() + let appSettings = AppSettings() + viewModel = ComposerToolbarViewModel(roomProxy: roomProxyMock, wysiwygViewModel: wysiwygViewModel, completionSuggestionService: mockCompletionSuggestionService, mediaProvider: MediaProviderMock(configuration: .init()), mentionDisplayHelper: ComposerMentionDisplayHelper.mock, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, + appSettings: appSettings, + analyticsService: .mock(settings: appSettings), composerDraftService: draftServiceMock) var fulfillment = deferFulfillment(viewModel.context.$viewState, message: "Composer is disabled") { $0.canSend == false } @@ -787,14 +791,15 @@ final class ComposerToolbarViewModelTests { } roomProxyMock.underlyingIdentityStatusChangesPublisher = CurrentValueSubject([IdentityStatusChange(userId: "@alice:localhost", changedTo: .pinViolation)]).asCurrentValuePublisher() + let appSettings = AppSettings() viewModel = ComposerToolbarViewModel(roomProxy: roomProxyMock, wysiwygViewModel: wysiwygViewModel, completionSuggestionService: mockCompletionSuggestionService, mediaProvider: MediaProviderMock(configuration: .init()), mentionDisplayHelper: ComposerMentionDisplayHelper.mock, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, + appSettings: appSettings, + analyticsService: .mock(settings: appSettings), composerDraftService: draftServiceMock) let deferred = deferFulfillment(viewModel.context.$viewState, message: "Composer should be enabled") { $0.canSend == true } @@ -811,14 +816,16 @@ final class ComposerToolbarViewModelTests { draftServiceMock.loadDraftClosure = loadDraftClosure } + let appSettings = AppSettings() + viewModel = ComposerToolbarViewModel(initialText: initialText, roomProxy: JoinedRoomProxyMock(.init()), wysiwygViewModel: wysiwygViewModel, completionSuggestionService: completionSuggestionServiceMock, mediaProvider: MediaProviderMock(configuration: .init()), mentionDisplayHelper: ComposerMentionDisplayHelper.mock, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, + appSettings: appSettings, + analyticsService: .mock(settings: appSettings), composerDraftService: draftServiceMock) viewModel.context.composerFormattingEnabled = true } diff --git a/UnitTests/Sources/CreateRoomViewModelTests.swift b/UnitTests/Sources/CreateRoomViewModelTests.swift index 97332a717..0fad48c2c 100644 --- a/UnitTests/Sources/CreateRoomViewModelTests.swift +++ b/UnitTests/Sources/CreateRoomViewModelTests.swift @@ -16,13 +16,21 @@ final class CreateRoomScreenViewModelTests { var clientProxy: ClientProxyMock! var spaceService: SpaceServiceProxyMock! var userSession: UserSessionMock! - + + private let appSettings: AppSettings + private let analytics: AnalyticsService + private let usersSubject = CurrentValueSubject<[UserProfileProxy], Never>([]) var context: CreateRoomScreenViewModel.Context { viewModel.context } - + + init() { + appSettings = AppSettings() + analytics = .mock(settings: appSettings) + } + deinit { AppSettings.resetAllSettings() viewModel = nil @@ -82,14 +90,14 @@ final class CreateRoomScreenViewModelTests { spaceServiceConfiguration: .init(spaceRoomLists: ["1": .init()]))) clientProxy.roomForIdentifierClosure = { roomID in .joined(JoinedRoomProxyMock(.init(id: roomID))) } userSession = UserSessionMock(.init(clientProxy: clientProxy)) - ServiceLocator.shared.settings.knockingEnabled = true + appSettings.knockingEnabled = true let viewModel = CreateRoomScreenViewModel(isSpace: true, spaceSelectionMode: .none, shouldShowCancelButton: false, userSession: userSession, - analytics: ServiceLocator.shared.analytics, + analytics: analytics, userIndicatorController: UserIndicatorControllerMock(), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) self.viewModel = viewModel // Given a form with a blank topic. @@ -332,14 +340,14 @@ final class CreateRoomScreenViewModelTests { clientProxy.spaceService = spaceService clientProxy.roomForIdentifierClosure = { roomID in .joined(JoinedRoomProxyMock(.init(id: roomID))) } userSession = UserSessionMock(.init(clientProxy: clientProxy)) - ServiceLocator.shared.settings.knockingEnabled = true + appSettings.knockingEnabled = true let viewModel = CreateRoomScreenViewModel(isSpace: isSpace, spaceSelectionMode: spacesSelectionMode, shouldShowCancelButton: false, userSession: userSession, - analytics: ServiceLocator.shared.analytics, + analytics: analytics, userIndicatorController: UserIndicatorControllerMock(), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) self.viewModel = viewModel } } diff --git a/UnitTests/Sources/EmojiPickerScreenViewModelTests.swift b/UnitTests/Sources/EmojiPickerScreenViewModelTests.swift index 2c014ca0d..bc0c2bb38 100644 --- a/UnitTests/Sources/EmojiPickerScreenViewModelTests.swift +++ b/UnitTests/Sources/EmojiPickerScreenViewModelTests.swift @@ -17,7 +17,7 @@ struct EmojiPickerScreenViewModelTests { var context: EmojiPickerScreenViewModel.Context { viewModel.context } - + @Test mutating func toggleReaction() async throws { setupViewModel() @@ -45,7 +45,7 @@ struct EmojiPickerScreenViewModelTests { viewModel = EmojiPickerScreenViewModel(itemID: .randomEvent, selectedEmojis: selectedEmojis, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: AppSettings()), timelineController: MockTimelineController(timelineProxy: timelineProxy)) } } diff --git a/UnitTests/Sources/EmojiProviderTests.swift b/UnitTests/Sources/EmojiProviderTests.swift index 094952593..7c599cbf7 100644 --- a/UnitTests/Sources/EmojiProviderTests.swift +++ b/UnitTests/Sources/EmojiProviderTests.swift @@ -19,7 +19,7 @@ struct EmojiProviderTests { let emojiLoaderMock = EmojiLoaderMock() emojiLoaderMock.categories = [category] - let emojiProvider = EmojiProvider(loader: emojiLoaderMock, appSettings: ServiceLocator.shared.settings) + let emojiProvider = EmojiProvider(loader: emojiLoaderMock, appSettings: AppSettings()) let categories = await emojiProvider.categories() #expect(emojiLoaderMock.categories == categories) @@ -33,7 +33,7 @@ struct EmojiProviderTests { let emojiLoaderMock = EmojiLoaderMock() emojiLoaderMock.categories = [category] - let emojiProvider = EmojiProvider(loader: emojiLoaderMock, appSettings: ServiceLocator.shared.settings) + let emojiProvider = EmojiProvider(loader: emojiLoaderMock, appSettings: AppSettings()) let categories = await emojiProvider.categories(searchString: "") #expect(emojiLoaderMock.categories == categories) @@ -51,7 +51,7 @@ struct EmojiProviderTests { let emojiLoaderMock = EmojiLoaderMock() emojiLoaderMock.categories = categoriesForFirstLoad - let emojiProvider = EmojiProvider(loader: emojiLoaderMock, appSettings: ServiceLocator.shared.settings) + let emojiProvider = EmojiProvider(loader: emojiLoaderMock, appSettings: AppSettings()) _ = await emojiProvider.categories() emojiLoaderMock.categories = categoriesForSecondLoad @@ -82,7 +82,7 @@ struct EmojiProviderTests { let emojiLoaderMock = EmojiLoaderMock() emojiLoaderMock.categories = categories - let emojiProvider = EmojiProvider(loader: emojiLoaderMock, appSettings: ServiceLocator.shared.settings) + let emojiProvider = EmojiProvider(loader: emojiLoaderMock, appSettings: AppSettings()) _ = await emojiProvider.categories() let result = await emojiProvider.categories(searchString: searchString) diff --git a/UnitTests/Sources/HomeScreenViewModelTests.swift b/UnitTests/Sources/HomeScreenViewModelTests.swift index 098bfef53..5e8cf2508 100644 --- a/UnitTests/Sources/HomeScreenViewModelTests.swift +++ b/UnitTests/Sources/HomeScreenViewModelTests.swift @@ -19,15 +19,18 @@ final class HomeScreenViewModelTests { var clientProxy: ClientProxyMock! var roomSummaryProvider: RoomSummaryProviderMock! - var appSettings: AppSettings! var notificationManager: NotificationManagerMock! + private let appSettings: AppSettings + private let analytics: AnalyticsService + private let userIndicatorController: UserIndicatorControllerProtocol var cancellables = Set() init() { AppSettings.resetAllSettings() appSettings = AppSettings() - ServiceLocator.shared.register(appSettings: appSettings) + analytics = .mock(settings: appSettings) + userIndicatorController = UserIndicatorControllerMock.default } deinit { @@ -441,9 +444,9 @@ final class HomeScreenViewModelTests { viewModel = HomeScreenViewModel(userSession: userSession, selectedRoomPublisher: CurrentValueSubject(nil).asCurrentValuePublisher(), appSettings: appSettings, - analyticsService: ServiceLocator.shared.analytics, + analyticsService: analytics, notificationManager: notificationManager, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + userIndicatorController: userIndicatorController) } } diff --git a/UnitTests/Sources/InviteUsersViewModelTests.swift b/UnitTests/Sources/InviteUsersViewModelTests.swift index 6241fdac1..80de7f375 100644 --- a/UnitTests/Sources/InviteUsersViewModelTests.swift +++ b/UnitTests/Sources/InviteUsersViewModelTests.swift @@ -15,12 +15,9 @@ final class InviteUsersScreenViewModelTests { var viewModel: InviteUsersScreenViewModelProtocol! var userDiscoveryService: UserDiscoveryServiceMock! var clientProxy: ClientProxyMock! - var appSettings: AppSettings! init() { AppSettings.resetAllSettings() - appSettings = AppSettings() - ServiceLocator.shared.register(appSettings: appSettings) } deinit { @@ -175,7 +172,7 @@ final class InviteUsersScreenViewModelTests { isSkippable: isSkippable, userDiscoveryService: userDiscoveryService, userIndicatorController: UserIndicatorControllerMock(), - appSettings: ServiceLocator.shared.settings) + appSettings: AppSettings()) viewModel.state.usersSection = .init(type: .suggestions, users: [.mockAlice, .mockBob, .mockCharlie]) self.viewModel = viewModel } diff --git a/UnitTests/Sources/JoinRoomScreenViewModelTests.swift b/UnitTests/Sources/JoinRoomScreenViewModelTests.swift index 74f684e27..1a4025252 100644 --- a/UnitTests/Sources/JoinRoomScreenViewModelTests.swift +++ b/UnitTests/Sources/JoinRoomScreenViewModelTests.swift @@ -21,16 +21,16 @@ final class JoinRoomScreenViewModelTests { var viewModel: JoinRoomScreenViewModelProtocol! var clientProxy: ClientProxyMock! - var appSettings: AppSettings! var context: JoinRoomScreenViewModelType.Context { viewModel.context } + private let appSettings: AppSettings + init() { AppSettings.resetAllSettings() appSettings = AppSettings() - ServiceLocator.shared.register(appSettings: appSettings) } deinit { @@ -205,7 +205,7 @@ final class JoinRoomScreenViewModelTests { viewModel = JoinRoomScreenViewModel(source: .generic(roomID: "1", via: []), appSettings: appSettings, userSession: UserSessionMock(.init(clientProxy: clientProxy)), - userIndicatorController: ServiceLocator.shared.userIndicatorController) + userIndicatorController: UserIndicatorControllerMock.default) } } diff --git a/UnitTests/Sources/LocationSharingScreenViewModelTests.swift b/UnitTests/Sources/LocationSharingScreenViewModelTests.swift index f8cc6f46c..6c3c741ba 100644 --- a/UnitTests/Sources/LocationSharingScreenViewModelTests.swift +++ b/UnitTests/Sources/LocationSharingScreenViewModelTests.swift @@ -394,12 +394,14 @@ struct LocationSharingScreenViewModelTests { let roomProxyMock = JoinedRoomProxyMock(.init(members: .allMembers)) roomProxyMock.makeLiveLocationServiceReturnValue = liveLocationServiceMock + let appSettings = AppSettings() + viewModel = LocationSharingScreenViewModel(interactionMode: .viewLive(sender: nil, initialLiveLocationShare: nil), - mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration, + mapURLBuilder: appSettings.mapTilerConfiguration, roomProxy: roomProxyMock, timelineController: MockTimelineController(timelineProxy: TimelineProxyMock(.init())), liveLocationManager: LiveLocationManagerMock(.init()), - analytics: ServiceLocator.shared.analytics, + analytics: .mock(settings: appSettings), userIndicatorController: UserIndicatorControllerMock(), mediaProvider: MediaProviderMock(configuration: .init())) @@ -427,13 +429,14 @@ struct LocationSharingScreenViewModelTests { private mutating func setupViewModel(liveLocationManagerConfiguration: LiveLocationManagerMock.Configuration = .init(), members: [RoomMemberProxyMock] = .allMembersAsAdmin) { + let appSettings = AppSettings() timelineProxy = TimelineProxyMock(.init()) viewModel = LocationSharingScreenViewModel(interactionMode: .picker(shouldShowLiveLocationOption: true), - mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration, + mapURLBuilder: appSettings.mapTilerConfiguration, roomProxy: JoinedRoomProxyMock(.init(members: members)), timelineController: MockTimelineController(timelineProxy: timelineProxy), liveLocationManager: LiveLocationManagerMock(liveLocationManagerConfiguration), - analytics: ServiceLocator.shared.analytics, + analytics: .mock(settings: appSettings), userIndicatorController: UserIndicatorControllerMock(), mediaProvider: MediaProviderMock(configuration: .init())) viewModel.state.bindings.isLocationAuthorized = true @@ -441,13 +444,14 @@ struct LocationSharingScreenViewModelTests { private mutating func setupViewModel(liveLocationManagerMock: LiveLocationManagerMock, members: [RoomMemberProxyMock] = .allMembersAsAdmin) { + let appSettings = AppSettings() timelineProxy = TimelineProxyMock(.init()) viewModel = LocationSharingScreenViewModel(interactionMode: .picker(shouldShowLiveLocationOption: true), - mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration, + mapURLBuilder: appSettings.mapTilerConfiguration, roomProxy: JoinedRoomProxyMock(.init(members: members)), timelineController: MockTimelineController(timelineProxy: timelineProxy), liveLocationManager: liveLocationManagerMock, - analytics: ServiceLocator.shared.analytics, + analytics: .mock(settings: appSettings), userIndicatorController: UserIndicatorControllerMock(), mediaProvider: MediaProviderMock(configuration: .init())) viewModel.state.bindings.isLocationAuthorized = true @@ -457,6 +461,7 @@ struct LocationSharingScreenViewModelTests { initialShare: LiveLocationShare, liveLocationsSubject: CurrentValueSubject<[LiveLocationShare], Never>, members: [RoomMemberProxyMock] = .allMembers) { + let appSettings = AppSettings() let liveLocationServiceMock = RoomLiveLocationServiceMock() liveLocationServiceMock.liveLocationsPublisher = liveLocationsSubject.asCurrentValuePublisher() @@ -464,11 +469,11 @@ struct LocationSharingScreenViewModelTests { roomProxyMock.makeLiveLocationServiceReturnValue = liveLocationServiceMock viewModel = LocationSharingScreenViewModel(interactionMode: .viewLive(sender: sender, initialLiveLocationShare: initialShare), - mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration, + mapURLBuilder: appSettings.mapTilerConfiguration, roomProxy: roomProxyMock, timelineController: MockTimelineController(timelineProxy: TimelineProxyMock(.init())), liveLocationManager: LiveLocationManagerMock(.init()), - analytics: ServiceLocator.shared.analytics, + analytics: .mock(settings: appSettings), userIndicatorController: UserIndicatorControllerMock(), mediaProvider: MediaProviderMock(configuration: .init())) } diff --git a/UnitTests/Sources/LoginScreenViewModelTests.swift b/UnitTests/Sources/LoginScreenViewModelTests.swift index 0d8b3d8d1..7f740696e 100644 --- a/UnitTests/Sources/LoginScreenViewModelTests.swift +++ b/UnitTests/Sources/LoginScreenViewModelTests.swift @@ -227,12 +227,14 @@ struct LoginScreenViewModelTests { // MARK: - Helpers private mutating func setupViewModel(homeserverAddress: String = "example.com", loginHint: String? = nil) async { + let appSettings = AppSettings() + clientFactory = AuthenticationClientFactoryMock(configuration: .init()) service = AuthenticationService(userSessionStore: UserSessionStoreMock(configuration: .init()), encryptionKeyProvider: EncryptionKeyProvider(), classicAppManager: nil, clientFactory: clientFactory, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks()) guard case .success = await service @@ -244,7 +246,7 @@ struct LoginScreenViewModelTests { viewModel = LoginScreenViewModel(authenticationService: service, loginHint: loginHint, userIndicatorController: UserIndicatorControllerMock(), - appSettings: ServiceLocator.shared.settings, - analytics: ServiceLocator.shared.analytics) + appSettings: appSettings, + analytics: .mock(settings: appSettings)) } } diff --git a/UnitTests/Sources/ManageRoomMemberSheetViewModelTests.swift b/UnitTests/Sources/ManageRoomMemberSheetViewModelTests.swift index 1929e974a..804619093 100644 --- a/UnitTests/Sources/ManageRoomMemberSheetViewModelTests.swift +++ b/UnitTests/Sources/ManageRoomMemberSheetViewModelTests.swift @@ -32,7 +32,7 @@ struct ManageRoomMemberSheetViewModelTests { permissions: .init(canKick: true, canBan: true, ownPowerLevel: RoomMemberProxyMock.mockAdmin.powerLevel), roomProxy: roomProxy, userIndicatorController: UserIndicatorControllerMock(), - analyticsService: ServiceLocator.shared.analytics, + analyticsService: .mock(), mediaProvider: MediaProviderMock(configuration: .init())) let deferred = deferFulfillment(context.observe(\.viewState.bindings.alertInfo)) { $0 != nil } @@ -64,7 +64,7 @@ struct ManageRoomMemberSheetViewModelTests { permissions: .init(canKick: true, canBan: true, ownPowerLevel: RoomMemberProxyMock.mockAdmin.powerLevel), roomProxy: roomProxy, userIndicatorController: UserIndicatorControllerMock(), - analyticsService: ServiceLocator.shared.analytics, + analyticsService: .mock(), mediaProvider: MediaProviderMock(configuration: .init())) let deferred = deferFulfillment(context.observe(\.viewState.bindings.alertInfo)) { $0 != nil } @@ -87,7 +87,7 @@ struct ManageRoomMemberSheetViewModelTests { permissions: .init(canKick: true, canBan: true, ownPowerLevel: RoomMemberProxyMock.mockAdmin.powerLevel), roomProxy: roomProxy, userIndicatorController: UserIndicatorControllerMock(), - analyticsService: ServiceLocator.shared.analytics, + analyticsService: .mock(), mediaProvider: MediaProviderMock(configuration: .init())) let deferredAction = deferFulfillment(viewModel.actions) { action in diff --git a/UnitTests/Sources/MediaUploadPreviewScreenViewModelTests.swift b/UnitTests/Sources/MediaUploadPreviewScreenViewModelTests.swift index 31f0291b6..565f93f8b 100644 --- a/UnitTests/Sources/MediaUploadPreviewScreenViewModelTests.swift +++ b/UnitTests/Sources/MediaUploadPreviewScreenViewModelTests.swift @@ -14,8 +14,9 @@ import Testing final class MediaUploadPreviewScreenViewModelTests { var timelineProxy: TimelineProxyMock! var clientProxy: ClientProxyMock! - var userIndicatorController: UserIndicatorControllerMock! - + var userIndicatorController: UserIndicatorControllerMock + private let appSettings: AppSettings + var viewModel: MediaUploadPreviewScreenViewModel! var context: MediaUploadPreviewScreenViewModel.Context { viewModel.context @@ -28,9 +29,10 @@ final class MediaUploadPreviewScreenViewModelTests { init() { AppSettings.resetAllSettings() - let appSettings = AppSettings() + appSettings = AppSettings() appSettings.optimizeMediaUploads = false - ServiceLocator.shared.register(appSettings: appSettings) + + userIndicatorController = UserIndicatorControllerMock.default } deinit { @@ -289,14 +291,12 @@ final class MediaUploadPreviewScreenViewModelTests { if let maxUploadSizeResult { clientProxy.underlyingMaxMediaUploadSize = maxUploadSizeResult } - - userIndicatorController = UserIndicatorControllerMock() - + viewModel = MediaUploadPreviewScreenViewModel(mediaURLs: urls, title: "Some File", isRoomEncrypted: true, shouldShowCaptionWarning: true, - mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: ServiceLocator.shared.settings), + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: appSettings), timelineController: MockTimelineController(timelineProxy: timelineProxy), clientProxy: clientProxy, userIndicatorController: userIndicatorController) diff --git a/UnitTests/Sources/MediaUploadingPreprocessorTests.swift b/UnitTests/Sources/MediaUploadingPreprocessorTests.swift index 7484c49c7..f2479badc 100644 --- a/UnitTests/Sources/MediaUploadingPreprocessorTests.swift +++ b/UnitTests/Sources/MediaUploadingPreprocessorTests.swift @@ -20,7 +20,6 @@ final class MediaUploadingPreprocessorTests { AppSettings.resetAllSettings() appSettings = AppSettings() appSettings.optimizeMediaUploads = false - ServiceLocator.shared.register(appSettings: appSettings) mediaUploadingPreprocessor = MediaUploadingPreprocessor(appSettings: appSettings) } diff --git a/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift b/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift index 6ec714a8d..bfae29677 100644 --- a/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift +++ b/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift @@ -22,13 +22,11 @@ final class NotificationManagerTests { private var handleInlineReplyDelegateCalled = false private var notificationTappedDelegateCalled = false private var registerForRemoteNotificationsDelegateCalled: (() -> Void)? - - private var appSettings: AppSettings { - ServiceLocator.shared.settings - } + private let appSettings: AppSettings init() { AppSettings.resetAllSettings() + appSettings = AppSettings() notificationCenter = UserNotificationCenterMock() notificationCenter.requestAuthorizationOptionsReturnValue = true notificationCenter.authorizationStatusReturnValue = .authorized diff --git a/UnitTests/Sources/PillContextTests.swift b/UnitTests/Sources/PillContextTests.swift index 74663c24b..896e7a5f6 100644 --- a/UnitTests/Sources/PillContextTests.swift +++ b/UnitTests/Sources/PillContextTests.swift @@ -15,6 +15,10 @@ import Testing struct PillContextTests { @Test func user() async { + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + let userIndicatorController = UserIndicatorControllerMock.default + let id = "@test:matrix.org" let proxyMock = JoinedRoomProxyMock(.init(name: "Test")) let subject = CurrentValueSubject<[RoomMemberProxyProtocol], Never>([]) @@ -23,11 +27,11 @@ struct PillContextTests { timelineController: MockTimelineController(), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: userIndicatorController, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .user(userID: id), font: .preferredFont(forTextStyle: .body))) @@ -46,6 +50,10 @@ struct PillContextTests { @Test func ownUser() { + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + let userIndicatorController = UserIndicatorControllerMock.default + let id = "@test:matrix.org" let proxyMock = JoinedRoomProxyMock(.init(name: "Test", ownUserID: id)) let subject = CurrentValueSubject<[RoomMemberProxyProtocol], Never>([]) @@ -54,11 +62,11 @@ struct PillContextTests { timelineController: MockTimelineController(), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: userIndicatorController, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .user(userID: id), font: .preferredFont(forTextStyle: .body))) @@ -68,6 +76,10 @@ struct PillContextTests { @Test func allUsers() { + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + let userIndicatorController = UserIndicatorControllerMock.default + let avatarURL = URL(string: "https://matrix.jpg") let id = "test_room" let displayName = "Test" @@ -78,11 +90,11 @@ struct PillContextTests { timelineController: mockController, userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: userIndicatorController, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .allUsers, font: .preferredFont(forTextStyle: .body))) @@ -93,6 +105,10 @@ struct PillContextTests { @Test func roomIDMention() { + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + let userIndicatorController = UserIndicatorControllerMock.default + let proxyMock = JoinedRoomProxyMock(.init()) let mockController = MockTimelineController() let clientMock = ClientProxyMock(.init()) @@ -102,11 +118,11 @@ struct PillContextTests { timelineController: mockController, userSession: UserSessionMock(.init(clientProxy: clientMock)), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: userIndicatorController, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .roomID("1"), font: .preferredFont(forTextStyle: .body))) @@ -118,6 +134,10 @@ struct PillContextTests { @Test func roomIDMentionMissingRoom() { + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + let userIndicatorController = UserIndicatorControllerMock.default + let proxyMock = JoinedRoomProxyMock(.init()) let mockController = MockTimelineController() mockController.roomProxy = proxyMock @@ -125,11 +145,11 @@ struct PillContextTests { timelineController: mockController, userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: userIndicatorController, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .roomID("1"), font: .preferredFont(forTextStyle: .body))) @@ -141,6 +161,10 @@ struct PillContextTests { @Test func roomAliasMention() { + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + let userIndicatorController = UserIndicatorControllerMock.default + let proxyMock = JoinedRoomProxyMock(.init()) let mockController = MockTimelineController() mockController.roomProxy = proxyMock @@ -152,11 +176,11 @@ struct PillContextTests { timelineController: mockController, userSession: UserSessionMock(.init(clientProxy: clientMock)), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: userIndicatorController, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .roomAlias("#foundation-and-empire:matrix.org"), font: .preferredFont(forTextStyle: .body))) @@ -168,6 +192,10 @@ struct PillContextTests { @Test func roomAliasMentionMissingRoom() { + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + let userIndicatorController = UserIndicatorControllerMock.default + let proxyMock = JoinedRoomProxyMock(.init()) let mockController = MockTimelineController() mockController.roomProxy = proxyMock @@ -175,11 +203,11 @@ struct PillContextTests { timelineController: mockController, userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: userIndicatorController, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .roomAlias("#foundation-and-empire:matrix.org"), font: .preferredFont(forTextStyle: .body))) @@ -191,6 +219,10 @@ struct PillContextTests { @Test func eventOnRoomIDMention() { + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + let userIndicatorController = UserIndicatorControllerMock.default + let proxyMock = JoinedRoomProxyMock(.init()) let mockController = MockTimelineController() mockController.roomProxy = proxyMock @@ -200,11 +232,11 @@ struct PillContextTests { timelineController: mockController, userSession: UserSessionMock(.init(clientProxy: clientMock)), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: userIndicatorController, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .event(room: .roomID("1")), font: .preferredFont(forTextStyle: .body))) @@ -216,6 +248,10 @@ struct PillContextTests { @Test func eventOnRoomIDMentionMissingRoom() { + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + let userIndicatorController = UserIndicatorControllerMock.default + let proxyMock = JoinedRoomProxyMock(.init()) let mockController = MockTimelineController() mockController.roomProxy = proxyMock @@ -223,11 +259,11 @@ struct PillContextTests { timelineController: mockController, userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: userIndicatorController, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .event(room: .roomID("1")), font: .preferredFont(forTextStyle: .body))) @@ -239,6 +275,10 @@ struct PillContextTests { @Test func eventOnRoomAliasMention() { + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + let userIndicatorController = UserIndicatorControllerMock.default + let proxyMock = JoinedRoomProxyMock(.init()) let mockController = MockTimelineController() mockController.roomProxy = proxyMock @@ -250,11 +290,11 @@ struct PillContextTests { timelineController: mockController, userSession: UserSessionMock(.init(clientProxy: clientMock)), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: userIndicatorController, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .event(room: .roomAlias("#foundation-and-empire:matrix.org")), font: .preferredFont(forTextStyle: .body))) @@ -266,6 +306,10 @@ struct PillContextTests { @Test func eventOnRoomAliasMentionMissingRoom() { + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + let userIndicatorController = UserIndicatorControllerMock.default + let proxyMock = JoinedRoomProxyMock(.init()) let mockController = MockTimelineController() mockController.roomProxy = proxyMock @@ -273,11 +317,11 @@ struct PillContextTests { timelineController: mockController, userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: userIndicatorController, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: analytics, + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .event(room: .roomAlias("#foundation-and-empire:matrix.org")), font: .preferredFont(forTextStyle: .body))) diff --git a/UnitTests/Sources/PollFormScreenViewModelTests.swift b/UnitTests/Sources/PollFormScreenViewModelTests.swift index 43a84c208..176b06d31 100644 --- a/UnitTests/Sources/PollFormScreenViewModelTests.swift +++ b/UnitTests/Sources/PollFormScreenViewModelTests.swift @@ -179,7 +179,7 @@ struct PollFormScreenViewModelTests { private mutating func setupViewModel(mode: PollFormMode = .new) { viewModel = PollFormScreenViewModel(mode: mode, timelineController: MockTimelineController(timelineProxy: timelineProxy), - analytics: ServiceLocator.shared.analytics, + analytics: .mock(), userIndicatorController: UserIndicatorControllerMock()) } } diff --git a/UnitTests/Sources/RoomChangePermissionsScreenViewModelTests.swift b/UnitTests/Sources/RoomChangePermissionsScreenViewModelTests.swift index cf79523e8..7c7ca5847 100644 --- a/UnitTests/Sources/RoomChangePermissionsScreenViewModelTests.swift +++ b/UnitTests/Sources/RoomChangePermissionsScreenViewModelTests.swift @@ -125,6 +125,6 @@ struct RoomChangePermissionsScreenViewModelTests { ownPowerLevel: ownPowerLevel, roomProxy: roomProxy, userIndicatorController: UserIndicatorControllerMock(), - analytics: ServiceLocator.shared.analytics) + analytics: .mock()) } } diff --git a/UnitTests/Sources/RoomChangeRolesScreenViewModelTests.swift b/UnitTests/Sources/RoomChangeRolesScreenViewModelTests.swift index 88e52aea6..9a6607bee 100644 --- a/UnitTests/Sources/RoomChangeRolesScreenViewModelTests.swift +++ b/UnitTests/Sources/RoomChangeRolesScreenViewModelTests.swift @@ -197,6 +197,6 @@ struct RoomChangeRolesScreenViewModelTests { roomProxy: roomProxy, mediaProvider: MediaProviderMock(configuration: .init()), userIndicatorController: UserIndicatorControllerMock(), - analytics: ServiceLocator.shared.analytics) + analytics: .mock()) } } diff --git a/UnitTests/Sources/RoomDetailsEditScreenViewModelTests.swift b/UnitTests/Sources/RoomDetailsEditScreenViewModelTests.swift index 2566eddd3..4bdc1cbf2 100644 --- a/UnitTests/Sources/RoomDetailsEditScreenViewModelTests.swift +++ b/UnitTests/Sources/RoomDetailsEditScreenViewModelTests.swift @@ -167,7 +167,7 @@ struct RoomDetailsEditScreenViewModelTests { userIndicatorController = UserIndicatorControllerMock.default viewModel = .init(roomProxy: JoinedRoomProxyMock(roomProxyConfiguration), userSession: UserSessionMock(.init()), - mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: ServiceLocator.shared.settings), + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: AppSettings()), userIndicatorController: userIndicatorController) } } diff --git a/UnitTests/Sources/RoomDetailsScreenViewModelTests.swift b/UnitTests/Sources/RoomDetailsScreenViewModelTests.swift index b9b9be4dd..e3752da79 100644 --- a/UnitTests/Sources/RoomDetailsScreenViewModelTests.swift +++ b/UnitTests/Sources/RoomDetailsScreenViewModelTests.swift @@ -26,29 +26,33 @@ struct RoomDetailsScreenViewModelTests { init() { AppSettings.resetAllSettings() + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + cancellables.removeAll() roomProxyMock = JoinedRoomProxyMock(.init(name: "Test")) notificationSettingsProxyMock = NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: notificationSettingsProxyMock, attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) } @Test mutating func leaveRoomTappedWhenPublic() async throws { + let appSettings = AppSettings() let mockedMembers: [RoomMemberProxyMock] = [.mockBob, .mockAlice] roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", members: mockedMembers, joinRule: .public)) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()), attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) let deferred = deferFulfillment(context.observe(\.viewState.bindings.leaveRoomAlertItem)) { $0 != nil } context.send(viewAction: .processTapLeave) @@ -60,15 +64,17 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func leaveRoomTappedWhenRoomNotPublic() async throws { + let appSettings = AppSettings() + let mockedMembers: [RoomMemberProxyMock] = [.mockBob, .mockAlice] roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", members: mockedMembers)) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()), attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) let deferred = deferFulfillment(context.observe(\.viewState.bindings.leaveRoomAlertItem)) { $0 != nil } context.send(viewAction: .processTapLeave) @@ -81,15 +87,17 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func leaveRoomTappedWithLessThanTwoMembers() { + let appSettings = AppSettings() + let mockedMembers: [RoomMemberProxyMock] = [.mockAlice] roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", members: mockedMembers)) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()), attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) context.send(viewAction: .processTapLeave) #expect(context.leaveRoomAlertItem?.state == .empty) @@ -138,16 +146,18 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func initialDMDetailsState() async throws { + let appSettings = AppSettings() + let recipient = RoomMemberProxyMock.mockDan let mockedMembers: [RoomMemberProxyMock] = [.mockMe, recipient] roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: true, isEncrypted: true, members: mockedMembers)) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()), attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) let deferred = deferFulfillment(viewModel.context.observe(\.viewState.dmRecipientInfo)) { $0 != nil } @@ -158,17 +168,19 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func ignoreSuccess() async throws { + let appSettings = AppSettings() + let recipient = RoomMemberProxyMock.mockDan let mockedMembers: [RoomMemberProxyMock] = [.mockMe, recipient] roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: true, isEncrypted: true, members: mockedMembers)) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()), attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) let deferredRecipient = deferFulfillment(viewModel.context.observe(\.viewState.dmRecipientInfo)) { $0 != nil } @@ -188,6 +200,8 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func ignoreFailure() async throws { + let appSettings = AppSettings() + let recipient = RoomMemberProxyMock.mockDan let mockedMembers: [RoomMemberProxyMock] = [.mockMe, recipient] let clientProxy = ClientProxyMock(.init()) @@ -195,11 +209,11 @@ struct RoomDetailsScreenViewModelTests { roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: true, isEncrypted: true, members: mockedMembers)) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init(clientProxy: clientProxy)), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()), attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) let deferredRecipient = deferFulfillment(viewModel.context.observe(\.viewState.dmRecipientInfo)) { $0 != nil } @@ -220,16 +234,18 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func unignoreSuccess() async throws { + let appSettings = AppSettings() + let recipient = RoomMemberProxyMock.mockIgnored let mockedMembers: [RoomMemberProxyMock] = [.mockMe, recipient] roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: true, isEncrypted: true, members: mockedMembers)) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()), attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) let deferredRecipient = deferFulfillment(viewModel.context.observe(\.viewState.dmRecipientInfo)) { $0 != nil } @@ -249,6 +265,8 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func unignoreFailure() async throws { + let appSettings = AppSettings() + let recipient = RoomMemberProxyMock.mockIgnored let mockedMembers: [RoomMemberProxyMock] = [.mockMe, recipient] let clientProxy = ClientProxyMock(.init()) @@ -256,11 +274,11 @@ struct RoomDetailsScreenViewModelTests { roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: true, isEncrypted: true, members: mockedMembers)) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init(clientProxy: clientProxy)), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()), attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) let deferredRecipient = deferFulfillment(viewModel.context.observe(\.viewState.dmRecipientInfo)) { $0 != nil } @@ -281,6 +299,8 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func cannotInvitePeople() async { + let appSettings = AppSettings() + let mockedMembers: [RoomMemberProxyMock] = [.mockMe, .mockAlice] roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", members: mockedMembers, @@ -288,11 +308,11 @@ struct RoomDetailsScreenViewModelTests { powerLevelsConfiguration: .init(canUserInvite: false))) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()), attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) _ = await context.observe(\.viewState).debounce(for: .milliseconds(100)).first() @@ -301,15 +321,17 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func invitePeople() async { + let appSettings = AppSettings() + let mockedMembers: [RoomMemberProxyMock] = [.mockMe, .mockBob, .mockAlice] roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", members: mockedMembers, joinRule: .public)) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()), attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) _ = await context.observe(\.viewState).debounce(for: .milliseconds(100)).first() @@ -334,6 +356,8 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func canEditAvatar() async { + let appSettings = AppSettings() + let mockedMembers: [RoomMemberProxyMock] = [.mockMe, .mockBob, .mockAlice] let configuration = JoinedRoomProxyMockConfiguration(name: "Test", @@ -357,11 +381,11 @@ struct RoomDetailsScreenViewModelTests { viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()), attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) _ = await context.observe(\.viewState).debounce(for: .milliseconds(100)).first() @@ -373,6 +397,8 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func canEditName() async { + let appSettings = AppSettings() + let mockedMembers: [RoomMemberProxyMock] = [.mockMe, .mockBob, .mockAlice] let configuration = JoinedRoomProxyMockConfiguration(name: "Test", @@ -396,11 +422,11 @@ struct RoomDetailsScreenViewModelTests { viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()), attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) _ = await context.observe(\.viewState).debounce(for: .milliseconds(100)).first() @@ -412,6 +438,8 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func canEditTopic() async { + let appSettings = AppSettings() + let mockedMembers: [RoomMemberProxyMock] = [.mockMe, .mockBob, .mockAlice] let configuration = JoinedRoomProxyMockConfiguration(name: "Test", @@ -435,11 +463,11 @@ struct RoomDetailsScreenViewModelTests { viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()), attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) _ = await context.observe(\.viewState).debounce(for: .milliseconds(100)).first() @@ -451,15 +479,17 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func cannotEditRoom() async { + let appSettings = AppSettings() + let mockedMembers: [RoomMemberProxyMock] = [.mockMe, .mockBob, .mockAlice] roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: false, members: mockedMembers)) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()), attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) _ = await context.observe(\.viewState).debounce(for: .milliseconds(100)).first() @@ -471,15 +501,17 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func cannotEditDirectRoom() async { + let appSettings = AppSettings() + let mockedMembers: [RoomMemberProxyMock] = [.mockMeAdmin, .mockBob, .mockAlice] roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: true, members: mockedMembers)) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()), attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) _ = await context.observe(\.viewState).debounce(for: .milliseconds(100)).first() @@ -490,14 +522,16 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func notificationLoadingSettingsFailure() async throws { + let appSettings = AppSettings() + notificationSettingsProxyMock.getNotificationSettingsRoomIdIsEncryptedIsOneToOneThrowableError = NotificationSettingsError.Generic(msg: "error") viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: notificationSettingsProxyMock, attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) var deferred = deferFulfillment(context.observe(\.viewState.notificationSettingsState)) { $0.isError } @@ -697,15 +731,17 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func knockRequestsCounter() async throws { + let appSettings = AppSettings() + let mockedRequests: [KnockRequestProxyMock] = [.init(), .init()] roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: false, knockRequestsState: .loaded(mockedRequests), joinRule: .knock)) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: notificationSettingsProxyMock, attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) let deferred = deferFulfillment(context.observe(\.viewState)) { state in state.knockRequestsCount == 2 && state.canSeeKnockingRequests @@ -719,14 +755,16 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func knockRequestsCounterIsLoading() async throws { + let appSettings = AppSettings() + roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: false, knockRequestsState: .loading, joinRule: .knock)) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: notificationSettingsProxyMock, attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) let deferred = deferFulfillment(context.observe(\.viewState)) { state in state.knockRequestsCount == 0 && state.canSeeKnockingRequests @@ -737,6 +775,8 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func knockRequestsCounterIsNotShownIfNoPermissions() async throws { + let appSettings = AppSettings() + let mockedRequests: [KnockRequestProxyMock] = [.init(), .init()] roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: false, @@ -745,11 +785,11 @@ struct RoomDetailsScreenViewModelTests { powerLevelsConfiguration: .init(canUserInvite: false))) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: notificationSettingsProxyMock, attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) let deferred = deferFulfillment(context.observe(\.viewState)) { state in state.knockRequestsCount == 2 && @@ -763,16 +803,18 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func knockRequestsCounterIsNotShownIfDM() async throws { + let appSettings = AppSettings() + let mockedRequests: [KnockRequestProxyMock] = [.init(), .init()] let mockedMembers: [RoomMemberProxyMock] = [.mockMe, .mockAlice] roomProxyMock = JoinedRoomProxyMock(.init(name: "Test", isDirect: true, members: mockedMembers, knockRequestsState: .loaded(mockedRequests), joinRule: .knock)) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: notificationSettingsProxyMock, attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) let deferred = deferFulfillment(context.observe(\.viewState)) { state in state.knockRequestsCount == 2 && @@ -788,6 +830,8 @@ struct RoomDetailsScreenViewModelTests { @Test mutating func historySharingPillDisplayed() async throws { + let appSettings = AppSettings() + let configuration = JoinedRoomProxyMockConfiguration(historyVisibility: .shared) let infoSubject = CurrentValueSubject(RoomInfoProxyMock(configuration)) let roomProxyMock = JoinedRoomProxyMock(configuration) @@ -795,11 +839,11 @@ struct RoomDetailsScreenViewModelTests { viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, userSession: UserSessionMock(.init()), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationSettingsProxy: notificationSettingsProxyMock, attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) let deferredShared = deferFulfillment(context.observe(\.viewState), message: "The pill should be shown for rooms with shared history visibility") { state in diff --git a/UnitTests/Sources/RoomFlowCoordinatorTests.swift b/UnitTests/Sources/RoomFlowCoordinatorTests.swift index b38250dbc..71d9add7a 100644 --- a/UnitTests/Sources/RoomFlowCoordinatorTests.swift +++ b/UnitTests/Sources/RoomFlowCoordinatorTests.swift @@ -18,7 +18,13 @@ final class RoomFlowCoordinatorTests { var roomFlowCoordinator: RoomFlowCoordinator! var navigationStackCoordinator: NavigationStackCoordinator! var cancellables = Set() - + + private let appSettings: AppSettings + + init() { + appSettings = AppSettings() + } + deinit { AppSettings.resetAllSettings() } @@ -236,7 +242,7 @@ final class RoomFlowCoordinatorTests { @Test func threadedEventRoutes() async throws { - ServiceLocator.shared.settings.threadsEnabled = true + appSettings.threadsEnabled = true setupRoomFlowCoordinator() // Navigate directly to the threaded event @@ -479,13 +485,13 @@ final class RoomFlowCoordinatorTests { bugReportService: BugReportServiceMock(.init()), elementCallService: ElementCallServiceMock(.init()), timelineControllerFactory: timelineControllerFactory, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + analytics: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default, notificationManager: NotificationManagerMock(), stateMachineFactory: StateMachineFactory()) diff --git a/UnitTests/Sources/RoomMemberDetailsViewModelTests.swift b/UnitTests/Sources/RoomMemberDetailsViewModelTests.swift index 337c5d36b..cc66eb6f3 100644 --- a/UnitTests/Sources/RoomMemberDetailsViewModelTests.swift +++ b/UnitTests/Sources/RoomMemberDetailsViewModelTests.swift @@ -205,13 +205,17 @@ struct RoomMemberDetailsViewModelTests { roomProxyMock.getMemberUserIDClosure = { _ in .success(roomMemberProxyMock) } + + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + // swiftlint:disable:next force_unwrapping let userSession = clientProxy != nil ? UserSessionMock(.init(clientProxy: clientProxy!)) : UserSessionMock(.init()) viewModel = RoomMemberDetailsScreenViewModel(userID: roomMemberProxyMock.userID, roomProxy: roomProxyMock, userSession: userSession, - userIndicatorController: ServiceLocator.shared.userIndicatorController, - analytics: ServiceLocator.shared.analytics, - appSettings: ServiceLocator.shared.settings) + userIndicatorController: UserIndicatorControllerMock.default, + analytics: analytics, + appSettings: appSettings) } } diff --git a/UnitTests/Sources/RoomMembersFlowCoordinatorTests.swift b/UnitTests/Sources/RoomMembersFlowCoordinatorTests.swift index 74ba99292..4136cf511 100644 --- a/UnitTests/Sources/RoomMembersFlowCoordinatorTests.swift +++ b/UnitTests/Sources/RoomMembersFlowCoordinatorTests.swift @@ -51,16 +51,19 @@ struct RoomMembersFlowCoordinatorTests { let clientProxy = ClientProxyMock(.init()) clientProxy.directRoomForUserIDReturnValue = .success(nil) + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + let flowParameters = CommonFlowParameters(userSession: UserSessionMock(.init(clientProxy: clientProxy)), bugReportService: BugReportServiceMock(.init()), elementCallService: ElementCallServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init()), - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: analytics, userIndicatorController: UserIndicatorControllerMock(), notificationManager: NotificationManagerMock(), stateMachineFactory: stateMachineFactory) diff --git a/UnitTests/Sources/RoomMembersListScreenViewModelTests.swift b/UnitTests/Sources/RoomMembersListScreenViewModelTests.swift index 7b4ff8d94..98faab35e 100644 --- a/UnitTests/Sources/RoomMembersListScreenViewModelTests.swift +++ b/UnitTests/Sources/RoomMembersListScreenViewModelTests.swift @@ -277,8 +277,8 @@ struct RoomMembersListScreenViewModelTests { viewModel = RoomMembersListScreenViewModel(userSession: UserSessionMock(.init()), roomProxy: roomProxy, - userIndicatorController: ServiceLocator.shared.userIndicatorController, - analytics: ServiceLocator.shared.analytics) + userIndicatorController: UserIndicatorControllerMock.default, + analytics: .mock()) let context = viewModel.context @@ -297,7 +297,7 @@ struct RoomMembersListScreenViewModelTests { roomProxy = JoinedRoomProxyMock(.init(name: "test", members: members)) viewModel = RoomMembersListScreenViewModel(userSession: UserSessionMock(.init()), roomProxy: roomProxy, - userIndicatorController: ServiceLocator.shared.userIndicatorController, - analytics: ServiceLocator.shared.analytics) + userIndicatorController: UserIndicatorControllerMock.default, + analytics: .mock()) } } diff --git a/UnitTests/Sources/RoomRolesAndPermissionsScreenViewModelTests.swift b/UnitTests/Sources/RoomRolesAndPermissionsScreenViewModelTests.swift index 805fd44f4..c044b2026 100644 --- a/UnitTests/Sources/RoomRolesAndPermissionsScreenViewModelTests.swift +++ b/UnitTests/Sources/RoomRolesAndPermissionsScreenViewModelTests.swift @@ -84,6 +84,6 @@ struct RoomRolesAndPermissionsScreenViewModelTests { roomProxy = JoinedRoomProxyMock(.init(members: members)) viewModel = RoomRolesAndPermissionsScreenViewModel(roomProxy: roomProxy, userIndicatorController: UserIndicatorControllerMock(), - analytics: ServiceLocator.shared.analytics) + analytics: .mock()) } } diff --git a/UnitTests/Sources/RoomScreenViewModelTests.swift b/UnitTests/Sources/RoomScreenViewModelTests.swift index 7906fbb27..ea245f376 100644 --- a/UnitTests/Sources/RoomScreenViewModelTests.swift +++ b/UnitTests/Sources/RoomScreenViewModelTests.swift @@ -17,8 +17,11 @@ import Testing final class RoomScreenViewModelTests { private var viewModel: RoomScreenViewModel! + private let appSettings: AppSettings + init() async throws { AppSettings.resetAllSettings() + appSettings = AppSettings() } deinit { @@ -45,10 +48,10 @@ final class RoomScreenViewModelTests { roomProxy: roomProxyMock, initialSelectedPinnedEventID: nil, ongoingCallRoomIDPublisher: .init(.init(nil)), - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default) self.viewModel = viewModel // check if in the default state is not showing but is indeed loading @@ -126,10 +129,10 @@ final class RoomScreenViewModelTests { roomProxy: roomProxyMock, initialSelectedPinnedEventID: "test1", ongoingCallRoomIDPublisher: .init(.init(nil)), - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default) self.viewModel = viewModel // check if the banner is now in a loaded state and is showing the counter @@ -166,7 +169,7 @@ final class RoomScreenViewModelTests { @Test func pinnedEventsBannerThreadedSelection() async throws { - ServiceLocator.shared.settings.threadsEnabled = true + appSettings.threadsEnabled = true let roomProxyMock = JoinedRoomProxyMock(.init()) let eventMock = TimelineEventSDKMock() @@ -187,10 +190,10 @@ final class RoomScreenViewModelTests { roomProxy: roomProxyMock, initialSelectedPinnedEventID: "test1", ongoingCallRoomIDPublisher: .init(.init(nil)), - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default) self.viewModel = viewModel // check if the banner is now in a loaded state and is showing the counter @@ -246,10 +249,10 @@ final class RoomScreenViewModelTests { roomProxy: roomProxyMock, initialSelectedPinnedEventID: nil, ongoingCallRoomIDPublisher: .init(.init(nil)), - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default) self.viewModel = viewModel #expect(viewModel.state.roomTitle == "StartingName") @@ -283,10 +286,10 @@ final class RoomScreenViewModelTests { roomProxy: roomProxyMock, initialSelectedPinnedEventID: nil, ongoingCallRoomIDPublisher: ongoingCallRoomIDSubject.asCurrentValuePublisher(), - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default) self.viewModel = viewModel #expect(viewModel.state.shouldShowCallButton) @@ -328,10 +331,10 @@ final class RoomScreenViewModelTests { roomProxy: roomProxyMock, initialSelectedPinnedEventID: nil, ongoingCallRoomIDPublisher: .init(.init(nil)), - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default) self.viewModel = viewModel viewModel.stop() } @@ -349,10 +352,10 @@ final class RoomScreenViewModelTests { roomProxy: roomProxyMock, initialSelectedPinnedEventID: nil, ongoingCallRoomIDPublisher: .init(.init(nil)), - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default) self.viewModel = viewModel var deferred = deferFulfillment(viewModel.context.$viewState) { state in @@ -383,10 +386,10 @@ final class RoomScreenViewModelTests { roomProxy: roomProxyMock, initialSelectedPinnedEventID: nil, ongoingCallRoomIDPublisher: .init(.init(nil)), - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default) self.viewModel = viewModel var deferred = deferFulfillment(viewModel.context.$viewState) { state in @@ -412,10 +415,10 @@ final class RoomScreenViewModelTests { roomProxy: roomProxyMock, initialSelectedPinnedEventID: nil, ongoingCallRoomIDPublisher: .init(.init(nil)), - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default) self.viewModel = viewModel // Loading state just does not appear at all @@ -432,10 +435,10 @@ final class RoomScreenViewModelTests { roomProxy: roomProxyMock, initialSelectedPinnedEventID: nil, ongoingCallRoomIDPublisher: .init(.init(nil)), - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default) self.viewModel = viewModel let deferred = deferFulfillment(viewModel.context.$viewState) { state in @@ -459,10 +462,10 @@ final class RoomScreenViewModelTests { roomProxy: roomProxyMock, initialSelectedPinnedEventID: nil, ongoingCallRoomIDPublisher: .init(.init(nil)), - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analyticsService: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + analyticsService: .mock(settings: appSettings), + userIndicatorController: UserIndicatorControllerMock.default) self.viewModel = viewModel let deferredInvisible = deferFailure(viewModel.context.$viewState, diff --git a/UnitTests/Sources/ServerConfirmationScreenViewModelTests.swift b/UnitTests/Sources/ServerConfirmationScreenViewModelTests.swift index f91e1c380..2c762b923 100644 --- a/UnitTests/Sources/ServerConfirmationScreenViewModelTests.swift +++ b/UnitTests/Sources/ServerConfirmationScreenViewModelTests.swift @@ -16,18 +16,17 @@ final class ServerConfirmationScreenViewModelTests { var clientFactory: AuthenticationClientFactoryMock! var client: ClientSDKMock! var service: AuthenticationServiceProtocol! - var appSettings: AppSettings! - + var viewModel: ServerConfirmationScreenViewModel! var context: ServerConfirmationScreenViewModel.Context { viewModel.context } - + + private let appSettings: AppSettings + init() { AppSettings.resetAllSettings() appSettings = AppSettings() - // These app settings are kept local to the tests on purpose as if they are registered in the - // ServiceLocator, the providers override that we apply will break other tests in the suite. } deinit { @@ -367,7 +366,7 @@ final class ServerConfirmationScreenViewModelTests { viewModel = ServerConfirmationScreenViewModel(authenticationService: service, mode: mode, authenticationFlow: authenticationFlow, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, userIndicatorController: UserIndicatorControllerMock()) // Add a fake window in order for the OAuth flow to continue diff --git a/UnitTests/Sources/ServerSelectionScreenViewModelTests.swift b/UnitTests/Sources/ServerSelectionScreenViewModelTests.swift index a7a3a8d3d..780035dca 100644 --- a/UnitTests/Sources/ServerSelectionScreenViewModelTests.swift +++ b/UnitTests/Sources/ServerSelectionScreenViewModelTests.swift @@ -148,17 +148,19 @@ struct ServerSelectionScreenViewModelTests { // MARK: - Helpers private mutating func setup(authenticationFlow: AuthenticationFlow) { + let appSettings = AppSettings() + clientFactory = AuthenticationClientFactoryMock(configuration: .init()) service = AuthenticationService(userSessionStore: UserSessionStoreMock(configuration: .init()), encryptionKeyProvider: EncryptionKeyProvider(), classicAppManager: nil, clientFactory: clientFactory, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks()) viewModel = ServerSelectionScreenViewModel(authenticationService: service, authenticationFlow: authenticationFlow, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, userIndicatorController: UserIndicatorControllerMock()) } } diff --git a/UnitTests/Sources/SettingsScreenViewModelTests.swift b/UnitTests/Sources/SettingsScreenViewModelTests.swift index a9dff0746..1910bca93 100644 --- a/UnitTests/Sources/SettingsScreenViewModelTests.swift +++ b/UnitTests/Sources/SettingsScreenViewModelTests.swift @@ -16,9 +16,10 @@ struct SettingsScreenViewModelTests { private var context: SettingsScreenViewModelType.Context init() { + let appSettings = AppSettings() let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "")))) viewModel = SettingsScreenViewModel(userSession: userSession, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, isBugReportServiceEnabled: true, isInSecondaryWindow: false) context = viewModel.context diff --git a/UnitTests/Sources/SpaceListScreenViewModelTests.swift b/UnitTests/Sources/SpaceListScreenViewModelTests.swift index da1b21197..169af544b 100644 --- a/UnitTests/Sources/SpaceListScreenViewModelTests.swift +++ b/UnitTests/Sources/SpaceListScreenViewModelTests.swift @@ -14,7 +14,7 @@ import Testing final class SpacesScreenViewModelTests { var topLevelSpacesSubject: CurrentValueSubject<[SpaceServiceRoom], Never> var spaceServiceProxy: SpaceServiceProxyMock - var appSettings: AppSettings + var viewModel: SpacesScreenViewModelProtocol var context: SpacesScreenViewModelType.Context { @@ -23,7 +23,7 @@ final class SpacesScreenViewModelTests { init() { AppSettings.resetAllSettings() - appSettings = AppSettings() + let appSettings = AppSettings() let clientProxy = ClientProxyMock(.init()) let userSession = UserSessionMock(.init(clientProxy: clientProxy)) @@ -43,7 +43,7 @@ final class SpacesScreenViewModelTests { viewModel = SpacesScreenViewModel(userSession: userSession, selectedSpacePublisher: .init(nil), - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, userIndicatorController: UserIndicatorControllerMock()) } diff --git a/UnitTests/Sources/StartChatViewModelTests.swift b/UnitTests/Sources/StartChatViewModelTests.swift index aff2d69ae..4257dcc23 100644 --- a/UnitTests/Sources/StartChatViewModelTests.swift +++ b/UnitTests/Sources/StartChatViewModelTests.swift @@ -20,15 +20,17 @@ struct StartChatScreenViewModelTests { } init() { + let appSettings = AppSettings() + clientProxy = .init(.init(userID: "")) userDiscoveryService = UserDiscoveryServiceMock() userDiscoveryService.searchProfilesWithReturnValue = .success([]) let userSession = UserSessionMock(.init(clientProxy: clientProxy)) viewModel = StartChatScreenViewModel(userSession: userSession, - analytics: ServiceLocator.shared.analytics, + analytics: .mock(settings: appSettings), userIndicatorController: UserIndicatorControllerMock(), userDiscoveryService: userDiscoveryService, - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) } @Test diff --git a/UnitTests/Sources/TimelineViewModelTests.swift b/UnitTests/Sources/TimelineViewModelTests.swift index 34a362704..6a5f5e072 100644 --- a/UnitTests/Sources/TimelineViewModelTests.swift +++ b/UnitTests/Sources/TimelineViewModelTests.swift @@ -14,19 +14,13 @@ import Testing @MainActor final class TimelineViewModelTests { - var userIndicatorControllerMock: UserIndicatorControllerMock! var cancellables = Set() init() async throws { AppSettings.resetAllSettings() cancellables.removeAll() - userIndicatorControllerMock = UserIndicatorControllerMock.default } - deinit { - userIndicatorControllerMock = nil - } - // MARK: - Message Grouping @Test @@ -313,15 +307,17 @@ final class TimelineViewModelTests { timelineController.timelineItems = items timelineController.roomProxy = roomProxy + let appSettings = AppSettings() + let viewModel = TimelineViewModel(roomProxy: roomProxy, timelineController: timelineController, userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: userIndicatorControllerMock, + userIndicatorController: UserIndicatorControllerMock.default, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: .mock(settings: appSettings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) return (viewModel, roomProxy, timelineProxy, timelineController) @@ -337,6 +333,8 @@ final class TimelineViewModelTests { addReadReceipts: receipts) let id = message.id + let appSettings = AppSettings() + // When showing them in a timeline. let timelineController = MockTimelineController() timelineController.timelineItems = [message] @@ -344,11 +342,11 @@ final class TimelineViewModelTests { timelineController: timelineController, userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: userIndicatorControllerMock, + userIndicatorController: UserIndicatorControllerMock.default, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: .mock(settings: appSettings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) @@ -362,6 +360,8 @@ final class TimelineViewModelTests { @Test func showManageUserAsAdmin() async throws { + let appSettings = AppSettings() + let viewModel = TimelineViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "", members: [RoomMemberProxyMock.mockAdmin, RoomMemberProxyMock.mockAlice], @@ -369,11 +369,11 @@ final class TimelineViewModelTests { timelineController: MockTimelineController(), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: userIndicatorControllerMock, + userIndicatorController: UserIndicatorControllerMock.default, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: .mock(settings: appSettings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) @@ -399,6 +399,8 @@ final class TimelineViewModelTests { @Test func showDetailsForAnAdmin() async throws { + let appSettings = AppSettings() + let viewModel = TimelineViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "", members: [RoomMemberProxyMock.mockAdmin, RoomMemberProxyMock.mockAlice], @@ -406,11 +408,11 @@ final class TimelineViewModelTests { timelineController: MockTimelineController(), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: userIndicatorControllerMock, + userIndicatorController: UserIndicatorControllerMock.default, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: .mock(settings: appSettings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) @@ -436,6 +438,8 @@ final class TimelineViewModelTests { @Test func showDetailsForABannedUser() async throws { + let appSettings = AppSettings() + let viewModel = TimelineViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "", members: [RoomMemberProxyMock.mockAdmin, RoomMemberProxyMock.mockBanned[0]], @@ -443,11 +447,11 @@ final class TimelineViewModelTests { timelineController: MockTimelineController(), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: userIndicatorControllerMock, + userIndicatorController: UserIndicatorControllerMock.default, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: .mock(settings: appSettings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) @@ -476,6 +480,8 @@ final class TimelineViewModelTests { @Test func pinnedEvents() async throws { + let appSettings = AppSettings() + var configuration = JoinedRoomProxyMockConfiguration(name: "", pinnedEventIDs: .init(["test1"])) let roomProxyMock = JoinedRoomProxyMock(configuration) @@ -486,11 +492,11 @@ final class TimelineViewModelTests { timelineController: MockTimelineController(), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: userIndicatorControllerMock, + userIndicatorController: UserIndicatorControllerMock.default, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: .mock(settings: appSettings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) #expect(configuration.pinnedEventIDs == viewModel.context.viewState.pinnedEventIDs) @@ -505,6 +511,8 @@ final class TimelineViewModelTests { @Test func canUserPinEvents() async throws { + let appSettings = AppSettings() + let configuration = JoinedRoomProxyMockConfiguration(name: "", powerLevelsConfiguration: .init(canUserPin: true)) let roomProxyMock = JoinedRoomProxyMock(configuration) @@ -515,11 +523,11 @@ final class TimelineViewModelTests { timelineController: MockTimelineController(), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: userIndicatorControllerMock, + userIndicatorController: UserIndicatorControllerMock.default, appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appSettings: appSettings, + analyticsService: .mock(settings: appSettings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), timelineControllerFactory: TimelineControllerFactoryMock(.init())) @@ -580,18 +588,20 @@ final class TimelineViewModelTests { private func makeViewModel(roomProxy: JoinedRoomProxyProtocol? = nil, focussedEventID: String? = nil, timelineController: TimelineControllerProtocol) -> TimelineViewModel { - TimelineViewModel(roomProxy: roomProxy ?? JoinedRoomProxyMock(.init(name: "")), - focussedEventID: focussedEventID, - timelineController: timelineController, - userSession: UserSessionMock(.init()), - mediaPlayerProvider: MediaPlayerProviderMock(), - userIndicatorController: userIndicatorControllerMock, - appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - analyticsService: ServiceLocator.shared.analytics, - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), - linkMetadataProvider: LinkMetadataProvider(), - timelineControllerFactory: TimelineControllerFactoryMock(.init())) + let appSettings = AppSettings() + + return TimelineViewModel(roomProxy: roomProxy ?? JoinedRoomProxyMock(.init(name: "")), + focussedEventID: focussedEventID, + timelineController: timelineController, + userSession: UserSessionMock(.init()), + mediaPlayerProvider: MediaPlayerProviderMock(), + userIndicatorController: UserIndicatorControllerMock.default, + appMediator: AppMediatorMock.default, + appSettings: appSettings, + analyticsService: .mock(settings: appSettings), + emojiProvider: EmojiProvider(appSettings: appSettings), + linkMetadataProvider: LinkMetadataProvider(), + timelineControllerFactory: TimelineControllerFactoryMock(.init())) } } diff --git a/UnitTests/Sources/UserDetailsEditScreenViewModelTests.swift b/UnitTests/Sources/UserDetailsEditScreenViewModelTests.swift index 98e0661f0..f4e198a93 100644 --- a/UnitTests/Sources/UserDetailsEditScreenViewModelTests.swift +++ b/UnitTests/Sources/UserDetailsEditScreenViewModelTests.swift @@ -13,17 +13,15 @@ import Testing @MainActor struct UserDetailsEditScreenViewModelTests { private var viewModel: UserDetailsEditScreenViewModel! - private var userIndicatorController: UserIndicatorControllerMock! - + private var context: UserDetailsEditScreenViewModelType.Context { viewModel.context } init() { - userIndicatorController = UserIndicatorControllerMock.default viewModel = .init(userSession: UserSessionMock(.init()), - mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: ServiceLocator.shared.settings), - userIndicatorController: userIndicatorController) + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: AppSettings()), + userIndicatorController: UserIndicatorControllerMock.default) } @Test diff --git a/UnitTests/Sources/UserProfileScreenViewModelTests.swift b/UnitTests/Sources/UserProfileScreenViewModelTests.swift index fae3259d3..acb6e23f2 100644 --- a/UnitTests/Sources/UserProfileScreenViewModelTests.swift +++ b/UnitTests/Sources/UserProfileScreenViewModelTests.swift @@ -13,6 +13,10 @@ import Testing struct UserProfileScreenViewModelTests { @Test func initialState() async throws { + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + let userIndicatorController = UserIndicatorControllerMock.default + let profile = UserProfileProxy(userID: "@alice:matrix.org", displayName: "Alice", avatarURL: .mockMXCAvatar) let clientProxy = ClientProxyMock(.init()) clientProxy.profileForReturnValue = .success(profile) @@ -20,9 +24,9 @@ struct UserProfileScreenViewModelTests { let viewModel = UserProfileScreenViewModel(userID: profile.userID, isPresentedModally: false, userSession: UserSessionMock(.init(clientProxy: clientProxy)), - userIndicatorController: ServiceLocator.shared.userIndicatorController, - analytics: ServiceLocator.shared.analytics, - appSettings: ServiceLocator.shared.settings) + userIndicatorController: userIndicatorController, + analytics: analytics, + appSettings: appSettings) let context = viewModel.context let waitForMemberToLoad = deferFulfillment(context.observe(\.viewState.userProfile)) { $0 != nil } @@ -35,6 +39,10 @@ struct UserProfileScreenViewModelTests { @Test func initialStateAccountOwner() async throws { + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + let userIndicatorController = UserIndicatorControllerMock.default + let profile = UserProfileProxy(userID: RoomMemberProxyMock.mockMe.userID, displayName: "Me", avatarURL: .mockMXCAvatar) let clientProxy = ClientProxyMock(.init()) clientProxy.profileForReturnValue = .success(profile) @@ -42,9 +50,9 @@ struct UserProfileScreenViewModelTests { let viewModel = UserProfileScreenViewModel(userID: profile.userID, isPresentedModally: false, userSession: UserSessionMock(.init(clientProxy: clientProxy)), - userIndicatorController: ServiceLocator.shared.userIndicatorController, - analytics: ServiceLocator.shared.analytics, - appSettings: ServiceLocator.shared.settings) + userIndicatorController: userIndicatorController, + analytics: analytics, + appSettings: appSettings) let context = viewModel.context let waitForMemberToLoad = deferFulfillment(context.observe(\.viewState.userProfile)) { $0 != nil } @@ -57,6 +65,10 @@ struct UserProfileScreenViewModelTests { @Test func startingDmWithUnknownUserFetchesIdentity() async throws { + let appSettings = AppSettings() + let analytics = AnalyticsService.mock(settings: appSettings) + let userIndicatorController = UserIndicatorControllerMock.default + let profile = UserProfileProxy.mockAlice let clientProxy = ClientProxyMock(.init()) @@ -66,9 +78,9 @@ struct UserProfileScreenViewModelTests { let viewModel = UserProfileScreenViewModel(userID: profile.userID, isPresentedModally: false, userSession: UserSessionMock(.init(clientProxy: clientProxy)), - userIndicatorController: ServiceLocator.shared.userIndicatorController, - analytics: ServiceLocator.shared.analytics, - appSettings: ServiceLocator.shared.settings) + userIndicatorController: userIndicatorController, + analytics: analytics, + appSettings: appSettings) let context = viewModel.context diff --git a/UnitTests/Sources/UserSessionFlowCoordinatorTests.swift b/UnitTests/Sources/UserSessionFlowCoordinatorTests.swift index 4482408b2..7dad0fdb9 100644 --- a/UnitTests/Sources/UserSessionFlowCoordinatorTests.swift +++ b/UnitTests/Sources/UserSessionFlowCoordinatorTests.swift @@ -15,7 +15,7 @@ import Testing struct UserSessionFlowCoordinatorTests { private var userSessionFlowCoordinator: UserSessionFlowCoordinator! private var rootCoordinator: NavigationRootCoordinator! - private var userIndicatorController: UserIndicatorControllerMock! + private let userIndicatorController: UserIndicatorControllerMock private let stateMachineFactory = PublishedStateMachineFactory() private let networkReachabilitySubject: CurrentValueSubject = .init(.reachable) @@ -49,18 +49,19 @@ struct UserSessionFlowCoordinatorTests { let appMediator = AppMediatorMock.default appMediator.networkMonitor = networkMonitor - userIndicatorController = UserIndicatorControllerMock() - + userIndicatorController = UserIndicatorControllerMock.default + let appSettings = AppSettings() + let flowParameters = CommonFlowParameters(userSession: UserSessionMock(.init(clientProxy: clientProxy)), bugReportService: BugReportServiceMock(.init()), elementCallService: ElementCallServiceMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init()), - emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), appMediator: appMediator, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, + analytics: .mock(settings: appSettings), userIndicatorController: userIndicatorController, notificationManager: NotificationManagerMock(), stateMachineFactory: stateMachineFactory)