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.
This commit is contained in:
Michael
2026-05-14 01:45:49 -05:00
committed by GitHub
parent f70182d09a
commit ff5dcb040d
108 changed files with 971 additions and 729 deletions
+88 -44
View File
@@ -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)))