Render LiveLocations in the map (#5394)

This commit is contained in:
Mauro
2026-04-14 18:27:34 +02:00
committed by GitHub
parent a40fab5f5e
commit 602d779e3a
19 changed files with 380 additions and 163 deletions
+56 -36
View File
@@ -161,11 +161,13 @@
18867F4F1C8991EEC56EA932 /* UTType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 897DF5E9A70CE05A632FC8AF /* UTType.swift */; }; 18867F4F1C8991EEC56EA932 /* UTType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 897DF5E9A70CE05A632FC8AF /* UTType.swift */; };
18978C9438206828C1D5AF2A /* test_animated_image.gif in Resources */ = {isa = PBXBuildFile; fileRef = 53FD6D3D38F556CEAA280C58 /* test_animated_image.gif */; }; 18978C9438206828C1D5AF2A /* test_animated_image.gif in Resources */ = {isa = PBXBuildFile; fileRef = 53FD6D3D38F556CEAA280C58 /* test_animated_image.gif */; };
18E3786918486D4C9726BC84 /* FormButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89FBFC09F9DAFF1E4BA97849 /* FormButtonStyles.swift */; }; 18E3786918486D4C9726BC84 /* FormButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89FBFC09F9DAFF1E4BA97849 /* FormButtonStyles.swift */; };
18FD4EA36456910FD9CB1B95 /* RoomLiveLocationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 118892B93A8CFDD691D9B5E3 /* RoomLiveLocationService.swift */; };
18FDE4ED6D83B0771452B43D /* RoomSelectionScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F104596B0620CEFE5DFD31B1 /* RoomSelectionScreenCoordinator.swift */; }; 18FDE4ED6D83B0771452B43D /* RoomSelectionScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F104596B0620CEFE5DFD31B1 /* RoomSelectionScreenCoordinator.swift */; };
192A3CDCD0174AD1E4A128E4 /* AudioRecorderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2441E2424E78A40FC95DBA76 /* AudioRecorderTests.swift */; }; 192A3CDCD0174AD1E4A128E4 /* AudioRecorderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2441E2424E78A40FC95DBA76 /* AudioRecorderTests.swift */; };
194585F6CD77242B36D4ADF1 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = DADECBBB672497BCD4822468 /* Result.swift */; }; 194585F6CD77242B36D4ADF1 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = DADECBBB672497BCD4822468 /* Result.swift */; };
1950A80CD198BED283DFC2CE /* ClientProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18F2958E6D247AE2516BEEE8 /* ClientProxy.swift */; }; 1950A80CD198BED283DFC2CE /* ClientProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18F2958E6D247AE2516BEEE8 /* ClientProxy.swift */; };
197441F1EF23A5DABACCA79F /* StickerRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5338450E6783A576B5C16DD /* StickerRoomTimelineView.swift */; }; 197441F1EF23A5DABACCA79F /* StickerRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5338450E6783A576B5C16DD /* StickerRoomTimelineView.swift */; };
19946B8EEE158356EB5E1107 /* LocationShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9406BD5F99685C5ABDEDD93 /* LocationShareSheet.swift */; };
19DED23340D0855B59693ED2 /* VoiceMessageRecorderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D45C9EAA86423D7D3126DE4F /* VoiceMessageRecorderProtocol.swift */; }; 19DED23340D0855B59693ED2 /* VoiceMessageRecorderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D45C9EAA86423D7D3126DE4F /* VoiceMessageRecorderProtocol.swift */; };
19DF5600A7F547B22DD7872A /* CompletionSuggestionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A12D3D8138F1B71AFA7C858 /* CompletionSuggestionService.swift */; }; 19DF5600A7F547B22DD7872A /* CompletionSuggestionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A12D3D8138F1B71AFA7C858 /* CompletionSuggestionService.swift */; };
19FE025AE9BA2959B6589B0D /* RoomMemberDetailsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC575D1895FA62591451A93 /* RoomMemberDetailsScreen.swift */; }; 19FE025AE9BA2959B6589B0D /* RoomMemberDetailsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC575D1895FA62591451A93 /* RoomMemberDetailsScreen.swift */; };
@@ -740,7 +742,6 @@
7C1A7B594B2F8143F0DD0005 /* ElementXAttributeScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = C024C151639C4E1B91FCC68B /* ElementXAttributeScope.swift */; }; 7C1A7B594B2F8143F0DD0005 /* ElementXAttributeScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = C024C151639C4E1B91FCC68B /* ElementXAttributeScope.swift */; };
7C545FFEC9930F7247352593 /* SecurityAndPrivacyScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 978092B01BEAB39F2C4389AE /* SecurityAndPrivacyScreenViewModel.swift */; }; 7C545FFEC9930F7247352593 /* SecurityAndPrivacyScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 978092B01BEAB39F2C4389AE /* SecurityAndPrivacyScreenViewModel.swift */; };
7C6376192F578E0BA801BFEC /* AnalyticsSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C64A14EE89928207E3B42B /* AnalyticsSettingsScreenModels.swift */; }; 7C6376192F578E0BA801BFEC /* AnalyticsSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C64A14EE89928207E3B42B /* AnalyticsSettingsScreenModels.swift */; };
7C9A62022717060DFC1878D7 /* RoomLiveLocationServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2C9C6EFC19EBB79E35806ED /* RoomLiveLocationServiceProtocol.swift */; };
7C9BDF1FC7BD46C4676536AB /* AuthenticationStartScreenBackgroundImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 682BC7BAF0EFEF512A8C5140 /* AuthenticationStartScreenBackgroundImage.swift */; }; 7C9BDF1FC7BD46C4676536AB /* AuthenticationStartScreenBackgroundImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 682BC7BAF0EFEF512A8C5140 /* AuthenticationStartScreenBackgroundImage.swift */; };
7CD16990BA843BE9ED639129 /* ImageRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DFE4453AB0B34C203447162 /* ImageRoomTimelineItem.swift */; }; 7CD16990BA843BE9ED639129 /* ImageRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DFE4453AB0B34C203447162 /* ImageRoomTimelineItem.swift */; };
7D249465ED00988EEEC14E05 /* JoinedRoomProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 867DC9530C42F7B5176BE465 /* JoinedRoomProxyMock.swift */; }; 7D249465ED00988EEEC14E05 /* JoinedRoomProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 867DC9530C42F7B5176BE465 /* JoinedRoomProxyMock.swift */; };
@@ -765,6 +766,7 @@
805D16A15BDF97B4EA8D3EC6 /* RoomThreadListScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A14FD296A75F5F5637EDC365 /* RoomThreadListScreenCoordinator.swift */; }; 805D16A15BDF97B4EA8D3EC6 /* RoomThreadListScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A14FD296A75F5F5637EDC365 /* RoomThreadListScreenCoordinator.swift */; };
80DEA2A4B20F9E279EAE6B2B /* UserProfile+Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAD01F7FC2BBAC7351948595 /* UserProfile+Mock.swift */; }; 80DEA2A4B20F9E279EAE6B2B /* UserProfile+Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAD01F7FC2BBAC7351948595 /* UserProfile+Mock.swift */; };
80F6C8EFCA4564B67F0D34B0 /* DeactivateAccountScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77F75B3E9F99864048A422A /* DeactivateAccountScreenViewModelTests.swift */; }; 80F6C8EFCA4564B67F0D34B0 /* DeactivateAccountScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77F75B3E9F99864048A422A /* DeactivateAccountScreenViewModelTests.swift */; };
811D9AA152443037BEDA6F22 /* RoomLiveLocationServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCDB4B1DAB0FE01CC874E8DA /* RoomLiveLocationServiceProtocol.swift */; };
81CFE6FE42DF26BBCEDC7FF2 /* JoinCallButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98ABC939BC8F08CA3E967D6C /* JoinCallButton.swift */; }; 81CFE6FE42DF26BBCEDC7FF2 /* JoinCallButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98ABC939BC8F08CA3E967D6C /* JoinCallButton.swift */; };
81D4E550668B230A63B26CFB /* SpacesScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB98BFD8E93C7FCCEDEC46F9 /* SpacesScreenViewModel.swift */; }; 81D4E550668B230A63B26CFB /* SpacesScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB98BFD8E93C7FCCEDEC46F9 /* SpacesScreenViewModel.swift */; };
82434593648CB74121F1A821 /* RowDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2C513A6CD99E6C3C163DA1E /* RowDivider.swift */; }; 82434593648CB74121F1A821 /* RowDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2C513A6CD99E6C3C163DA1E /* RowDivider.swift */; };
@@ -774,6 +776,7 @@
8358D145F9BF94F412BEDCA8 /* RoomRolesAndPermissionsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE7969EBCAF078813E18EA1 /* RoomRolesAndPermissionsScreenModels.swift */; }; 8358D145F9BF94F412BEDCA8 /* RoomRolesAndPermissionsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE7969EBCAF078813E18EA1 /* RoomRolesAndPermissionsScreenModels.swift */; };
83B17A44D3E7E6DF22D9A2A4 /* RoomModerationRole.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B32BBA8887BD7A5C4ECF16F /* RoomModerationRole.swift */; }; 83B17A44D3E7E6DF22D9A2A4 /* RoomModerationRole.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B32BBA8887BD7A5C4ECF16F /* RoomModerationRole.swift */; };
83D519C509F0F76EDBB60455 /* KnockRequestProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F062DD2CCD95DC33528A16F /* KnockRequestProxy.swift */; }; 83D519C509F0F76EDBB60455 /* KnockRequestProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F062DD2CCD95DC33528A16F /* KnockRequestProxy.swift */; };
84196A8F1963D55726261879 /* RoomLiveLocationServiceMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C79C2C6E7F66646D1D254927 /* RoomLiveLocationServiceMock.swift */; };
84226AD2E1F1FBC965F3B09E /* UnitTestsAppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A8E19C4645D3F5F9FB02355 /* UnitTestsAppCoordinator.swift */; }; 84226AD2E1F1FBC965F3B09E /* UnitTestsAppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A8E19C4645D3F5F9FB02355 /* UnitTestsAppCoordinator.swift */; };
8446C2A7ECEFDA79F622725F /* TimelineReactionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54AD70D6E03D2031AE1B5A52 /* TimelineReactionsView.swift */; }; 8446C2A7ECEFDA79F622725F /* TimelineReactionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54AD70D6E03D2031AE1B5A52 /* TimelineReactionsView.swift */; };
8478992479B296C45150208F /* AppLockScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC0275CEE9CA078B34028BDF /* AppLockScreenViewModelTests.swift */; }; 8478992479B296C45150208F /* AppLockScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC0275CEE9CA078B34028BDF /* AppLockScreenViewModelTests.swift */; };
@@ -1183,7 +1186,6 @@
C8E1E4E06B7C7A3A8246FC9B /* MediaEventsTimelineScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8512B82404B1751D0BCC82D2 /* MediaEventsTimelineScreenCoordinator.swift */; }; C8E1E4E06B7C7A3A8246FC9B /* MediaEventsTimelineScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8512B82404B1751D0BCC82D2 /* MediaEventsTimelineScreenCoordinator.swift */; };
C900127318820AD04D6C90B8 /* LabsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E43D8784B0054C048060FEB /* LabsScreenModels.swift */; }; C900127318820AD04D6C90B8 /* LabsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E43D8784B0054C048060FEB /* LabsScreenModels.swift */; };
C915347779B3C7FDD073A87A /* AVMetadataMachineReadableCodeObjectExtensionsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93E1FF0DFBB3768F79FDBF6D /* AVMetadataMachineReadableCodeObjectExtensionsTest.swift */; }; C915347779B3C7FDD073A87A /* AVMetadataMachineReadableCodeObjectExtensionsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93E1FF0DFBB3768F79FDBF6D /* AVMetadataMachineReadableCodeObjectExtensionsTest.swift */; };
C9169AB88A0953C0B3D8601B /* RoomLiveLocationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89EE3CE58040FD2DF63DC23 /* RoomLiveLocationService.swift */; };
C960BACE42A9D8C535E8CB34 /* Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1912062B53CE95E6F700DA60 /* Pagination.swift */; }; C960BACE42A9D8C535E8CB34 /* Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1912062B53CE95E6F700DA60 /* Pagination.swift */; };
C969A62F3D9F14318481A33B /* KnockedRoomProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 858DA81F2ACF484B7CAD6AE4 /* KnockedRoomProxy.swift */; }; C969A62F3D9F14318481A33B /* KnockedRoomProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 858DA81F2ACF484B7CAD6AE4 /* KnockedRoomProxy.swift */; };
C97325EFDCCEE457432A9E82 /* MessageText.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E0B4A34E69BD2132BEC521 /* MessageText.swift */; }; C97325EFDCCEE457432A9E82 /* MessageText.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E0B4A34E69BD2132BEC521 /* MessageText.swift */; };
@@ -1478,7 +1480,6 @@
FA2BBAE9FC5E2E9F960C0980 /* NavigationCoordinators.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F28602AC7AC881AED37EBA /* NavigationCoordinators.swift */; }; FA2BBAE9FC5E2E9F960C0980 /* NavigationCoordinators.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F28602AC7AC881AED37EBA /* NavigationCoordinators.swift */; };
FA53FA227FFBE469AFF32F71 /* TimelineControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C585CE1F721A2770C70D47 /* TimelineControllerProtocol.swift */; }; FA53FA227FFBE469AFF32F71 /* TimelineControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C585CE1F721A2770C70D47 /* TimelineControllerProtocol.swift */; };
FA5A7E32B1920FCB4EEDC1BA /* RoomDetailsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6493AC9979CEB1410302BFE3 /* RoomDetailsScreenCoordinator.swift */; }; FA5A7E32B1920FCB4EEDC1BA /* RoomDetailsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6493AC9979CEB1410302BFE3 /* RoomDetailsScreenCoordinator.swift */; };
FA5FD4910EA871ACCED8D47B /* RoomLiveLocationServiceMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4609B3576A5E612A95352EC1 /* RoomLiveLocationServiceMock.swift */; };
FA71CD334F2D2289BEF0D749 /* SecureBackupRecoveryKeyScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A2FCA3D0F239B9E911B966B /* SecureBackupRecoveryKeyScreen.swift */; }; FA71CD334F2D2289BEF0D749 /* SecureBackupRecoveryKeyScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A2FCA3D0F239B9E911B966B /* SecureBackupRecoveryKeyScreen.swift */; };
FA9C427FFB11B1AA2DCC5602 /* RoomProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47111410B6E659A697D472B5 /* RoomProxyProtocol.swift */; }; FA9C427FFB11B1AA2DCC5602 /* RoomProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47111410B6E659A697D472B5 /* RoomProxyProtocol.swift */; };
FB0A9D06FC9122E37992D962 /* LayoutDirection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14D83B2B7CD5501A0089EFC /* LayoutDirection.swift */; }; FB0A9D06FC9122E37992D962 /* LayoutDirection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14D83B2B7CD5501A0089EFC /* LayoutDirection.swift */; };
@@ -1623,7 +1624,7 @@
044E501B8331B339874D1B96 /* CompoundIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompoundIcon.swift; sourceTree = "<group>"; }; 044E501B8331B339874D1B96 /* CompoundIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompoundIcon.swift; sourceTree = "<group>"; };
045253F9967A535EE5B16691 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = "<group>"; }; 045253F9967A535EE5B16691 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = "<group>"; };
046C0D3F53B0B5EF0A1F5BEA /* RoomSummaryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryTests.swift; sourceTree = "<group>"; }; 046C0D3F53B0B5EF0A1F5BEA /* RoomSummaryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryTests.swift; sourceTree = "<group>"; };
048A21188AB19349D026BECD /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; }; 048A21188AB19349D026BECD /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
04BB8DDE245ED86C489BA983 /* AccessibilityIdentifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityIdentifiers.swift; sourceTree = "<group>"; }; 04BB8DDE245ED86C489BA983 /* AccessibilityIdentifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityIdentifiers.swift; sourceTree = "<group>"; };
04DF593C3F7AF4B2FBAEB05D /* FileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManager.swift; sourceTree = "<group>"; }; 04DF593C3F7AF4B2FBAEB05D /* FileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManager.swift; sourceTree = "<group>"; };
04EB6035C1F33F25F1EBFB7D /* RoomThreadListServiceProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomThreadListServiceProxyProtocol.swift; sourceTree = "<group>"; }; 04EB6035C1F33F25F1EBFB7D /* RoomThreadListServiceProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomThreadListServiceProxyProtocol.swift; sourceTree = "<group>"; };
@@ -1703,6 +1704,7 @@
111B698739E3410E2CDB7144 /* MXLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXLog.swift; sourceTree = "<group>"; }; 111B698739E3410E2CDB7144 /* MXLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXLog.swift; sourceTree = "<group>"; };
113356152C099951A6D17D85 /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/Localizable.strings; sourceTree = "<group>"; }; 113356152C099951A6D17D85 /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/Localizable.strings; sourceTree = "<group>"; };
113873B97F27394ABE41BCFD /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/InfoPlist.strings; sourceTree = "<group>"; }; 113873B97F27394ABE41BCFD /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/InfoPlist.strings; sourceTree = "<group>"; };
118892B93A8CFDD691D9B5E3 /* RoomLiveLocationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomLiveLocationService.swift; sourceTree = "<group>"; };
11FCAE847556719BBE7A0882 /* ReportRoomScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportRoomScreenModels.swift; sourceTree = "<group>"; }; 11FCAE847556719BBE7A0882 /* ReportRoomScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportRoomScreenModels.swift; sourceTree = "<group>"; };
1215A4FC53D2319E81AE8970 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; }; 1215A4FC53D2319E81AE8970 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
1222DB76B917EB8A55365BA5 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = "<group>"; }; 1222DB76B917EB8A55365BA5 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = "<group>"; };
@@ -1712,7 +1714,7 @@
128501375217576AF0FE3E92 /* RoomAttachmentPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomAttachmentPicker.swift; sourceTree = "<group>"; }; 128501375217576AF0FE3E92 /* RoomAttachmentPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomAttachmentPicker.swift; sourceTree = "<group>"; };
12B09A94C519227264A41208 /* RoomMembershipDetailsProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembershipDetailsProxy.swift; sourceTree = "<group>"; }; 12B09A94C519227264A41208 /* RoomMembershipDetailsProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembershipDetailsProxy.swift; sourceTree = "<group>"; };
12FD5280AF55AB7F50F8E47D /* preview_avatar_room.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = preview_avatar_room.jpg; sourceTree = "<group>"; }; 12FD5280AF55AB7F50F8E47D /* preview_avatar_room.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = preview_avatar_room.jpg; sourceTree = "<group>"; };
1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = IntegrationTests.xctestplan; sourceTree = "<group>"; }; 1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; path = IntegrationTests.xctestplan; sourceTree = "<group>"; };
130ED565A078F7E0B59D9D25 /* UNTextInputNotificationResponse+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNTextInputNotificationResponse+Creator.swift"; sourceTree = "<group>"; }; 130ED565A078F7E0B59D9D25 /* UNTextInputNotificationResponse+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNTextInputNotificationResponse+Creator.swift"; sourceTree = "<group>"; };
136F80A613B55BDD071DCEA5 /* JoinRoomScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinRoomScreenModels.swift; sourceTree = "<group>"; }; 136F80A613B55BDD071DCEA5 /* JoinRoomScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinRoomScreenModels.swift; sourceTree = "<group>"; };
13802897C7AFA360EA74C0B0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; }; 13802897C7AFA360EA74C0B0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
@@ -1733,7 +1735,7 @@
16D09C79746BDCD9173EB3A7 /* RoomDetailsEditScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenModels.swift; sourceTree = "<group>"; }; 16D09C79746BDCD9173EB3A7 /* RoomDetailsEditScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenModels.swift; sourceTree = "<group>"; };
16D353E10A64172D863769BF /* TombstonedAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TombstonedAvatarImage.swift; sourceTree = "<group>"; }; 16D353E10A64172D863769BF /* TombstonedAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TombstonedAvatarImage.swift; sourceTree = "<group>"; };
1715E3D7F53C0748AA50C91C /* PostHogAnalyticsClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostHogAnalyticsClient.swift; sourceTree = "<group>"; }; 1715E3D7F53C0748AA50C91C /* PostHogAnalyticsClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostHogAnalyticsClient.swift; sourceTree = "<group>"; };
174E4AEF3DED300AA81046EC /* compound-ios */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "compound-ios"; sourceTree = SOURCE_ROOT; }; 174E4AEF3DED300AA81046EC /* compound-ios */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "compound-ios"; path = "compound-ios"; sourceTree = SOURCE_ROOT; };
17A8AA0DFA06012A9DAB951E /* TimelineProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineProxyMock.swift; sourceTree = "<group>"; }; 17A8AA0DFA06012A9DAB951E /* TimelineProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineProxyMock.swift; sourceTree = "<group>"; };
17BAE25A0E9E9F2F1BBA8930 /* DeactivateAccountScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeactivateAccountScreenViewModel.swift; sourceTree = "<group>"; }; 17BAE25A0E9E9F2F1BBA8930 /* DeactivateAccountScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeactivateAccountScreenViewModel.swift; sourceTree = "<group>"; };
181CF280BC8E3F335AFCB4B8 /* RemotePreferenceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemotePreferenceTests.swift; sourceTree = "<group>"; }; 181CF280BC8E3F335AFCB4B8 /* RemotePreferenceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemotePreferenceTests.swift; sourceTree = "<group>"; };
@@ -1760,7 +1762,7 @@
1B9D191A81FFB0C72CE73E77 /* RoomSelectionScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSelectionScreenModels.swift; sourceTree = "<group>"; }; 1B9D191A81FFB0C72CE73E77 /* RoomSelectionScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSelectionScreenModels.swift; sourceTree = "<group>"; };
1BA5A62DA4B543827FF82354 /* LAContextMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LAContextMock.swift; sourceTree = "<group>"; }; 1BA5A62DA4B543827FF82354 /* LAContextMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LAContextMock.swift; sourceTree = "<group>"; };
1BA8082E26C77A2C587B34B3 /* MockTimelineController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTimelineController.swift; sourceTree = "<group>"; }; 1BA8082E26C77A2C587B34B3 /* MockTimelineController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTimelineController.swift; sourceTree = "<group>"; };
1BC752C2A4606C4C2D1ADB41 /* 94 */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = 94; sourceTree = "<group>"; }; 1BC752C2A4606C4C2D1ADB41 /* 94 */ = {isa = PBXFileReference; path = 94; sourceTree = "<group>"; };
1C21A715237F2B6D6E80998C /* SecureBackupControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupControllerProtocol.swift; sourceTree = "<group>"; }; 1C21A715237F2B6D6E80998C /* SecureBackupControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupControllerProtocol.swift; sourceTree = "<group>"; };
1C25B6EBEB414431187D73B7 /* TimelineReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReplyView.swift; sourceTree = "<group>"; }; 1C25B6EBEB414431187D73B7 /* TimelineReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReplyView.swift; sourceTree = "<group>"; };
1C78111573987B1D79ED0868 /* LinkMetadataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkMetadataProvider.swift; sourceTree = "<group>"; }; 1C78111573987B1D79ED0868 /* LinkMetadataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkMetadataProvider.swift; sourceTree = "<group>"; };
@@ -1825,7 +1827,7 @@
25E7E9B7FEAB6169D960C206 /* QRCodeLoginScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeLoginScreenViewModelTests.swift; sourceTree = "<group>"; }; 25E7E9B7FEAB6169D960C206 /* QRCodeLoginScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeLoginScreenViewModelTests.swift; sourceTree = "<group>"; };
25F8664F1FB95AF3C4202478 /* PollFormScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenCoordinator.swift; sourceTree = "<group>"; }; 25F8664F1FB95AF3C4202478 /* PollFormScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenCoordinator.swift; sourceTree = "<group>"; };
260004737C573A56FA01E86E /* Encodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Encodable.swift; sourceTree = "<group>"; }; 260004737C573A56FA01E86E /* Encodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Encodable.swift; sourceTree = "<group>"; };
267BB1D5B08A9511F894CB57 /* PreviewTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = PreviewTests.xctestplan; sourceTree = "<group>"; }; 267BB1D5B08A9511F894CB57 /* PreviewTests.xctestplan */ = {isa = PBXFileReference; path = PreviewTests.xctestplan; sourceTree = "<group>"; };
26B0A96B8FE4849227945067 /* VoiceMessageRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageRecorder.swift; sourceTree = "<group>"; }; 26B0A96B8FE4849227945067 /* VoiceMessageRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageRecorder.swift; sourceTree = "<group>"; };
26EAAB54C6CE91D64B69A9F8 /* AppLockServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockServiceProtocol.swift; sourceTree = "<group>"; }; 26EAAB54C6CE91D64B69A9F8 /* AppLockServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockServiceProtocol.swift; sourceTree = "<group>"; };
2711E5996016ABD6EAAEB58A /* LogLevel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogLevel.swift; sourceTree = "<group>"; }; 2711E5996016ABD6EAAEB58A /* LogLevel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogLevel.swift; sourceTree = "<group>"; };
@@ -1850,7 +1852,7 @@
29A953B6C0C431DBF4DD00B4 /* RoomSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummary.swift; sourceTree = "<group>"; }; 29A953B6C0C431DBF4DD00B4 /* RoomSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummary.swift; sourceTree = "<group>"; };
2A2BB38DF61F5100B8723112 /* TimelineMediaPreviewModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewModels.swift; sourceTree = "<group>"; }; 2A2BB38DF61F5100B8723112 /* TimelineMediaPreviewModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewModels.swift; sourceTree = "<group>"; };
2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilder.swift; sourceTree = "<group>"; }; 2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilder.swift; sourceTree = "<group>"; };
2A7BE2B89310058659E6F459 /* accountsV2 */ = {isa = PBXFileReference; lastKnownFileType = file; path = accountsV2; sourceTree = "<group>"; }; 2A7BE2B89310058659E6F459 /* accountsV2 */ = {isa = PBXFileReference; path = accountsV2; sourceTree = "<group>"; };
2A95C9B8299A36A6495DECA6 /* TracingHook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingHook.swift; sourceTree = "<group>"; }; 2A95C9B8299A36A6495DECA6 /* TracingHook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingHook.swift; sourceTree = "<group>"; };
2AB2C848BB9A7A9B618B7B89 /* TextBasedRoomTimelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineTests.swift; sourceTree = "<group>"; }; 2AB2C848BB9A7A9B618B7B89 /* TextBasedRoomTimelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineTests.swift; sourceTree = "<group>"; };
2ADF12A50186B75C68017B61 /* DeclineAndBlockScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeclineAndBlockScreenViewModelTests.swift; sourceTree = "<group>"; }; 2ADF12A50186B75C68017B61 /* DeclineAndBlockScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeclineAndBlockScreenViewModelTests.swift; sourceTree = "<group>"; };
@@ -1910,7 +1912,7 @@
358528B29FA72ACFD0D9644B /* SpacesScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpacesScreenCoordinator.swift; sourceTree = "<group>"; }; 358528B29FA72ACFD0D9644B /* SpacesScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpacesScreenCoordinator.swift; sourceTree = "<group>"; };
35A057BA9BE0F079784CD061 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; }; 35A057BA9BE0F079784CD061 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
35AFCF4C05DEED04E3DB1A16 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; }; 35AFCF4C05DEED04E3DB1A16 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
36DA824791172B9821EACBED /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; }; 36DA824791172B9821EACBED /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberProxyMock.swift; sourceTree = "<group>"; }; 36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberProxyMock.swift; sourceTree = "<group>"; };
3747C96188856006F784BF49 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ko; path = ko.lproj/Localizable.stringsdict; sourceTree = "<group>"; }; 3747C96188856006F784BF49 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ko; path = ko.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
37A63A59BFDDC494B1C20119 /* CallScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreenViewModel.swift; sourceTree = "<group>"; }; 37A63A59BFDDC494B1C20119 /* CallScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreenViewModel.swift; sourceTree = "<group>"; };
@@ -2002,7 +2004,6 @@
45A4B934BA41D6C255900265 /* preview_video.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = preview_video.jpg; sourceTree = "<group>"; }; 45A4B934BA41D6C255900265 /* preview_video.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = preview_video.jpg; sourceTree = "<group>"; };
45CDF9A107BFE6C79B58D6B5 /* RoomMembersListScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreenViewModelProtocol.swift; sourceTree = "<group>"; }; 45CDF9A107BFE6C79B58D6B5 /* RoomMembersListScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreenViewModelProtocol.swift; sourceTree = "<group>"; };
45D8149FDDA0315CDC553B4B /* UserNotificationCenterProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNotificationCenterProtocol.swift; sourceTree = "<group>"; }; 45D8149FDDA0315CDC553B4B /* UserNotificationCenterProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNotificationCenterProtocol.swift; sourceTree = "<group>"; };
4609B3576A5E612A95352EC1 /* RoomLiveLocationServiceMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomLiveLocationServiceMock.swift; sourceTree = "<group>"; };
4629710C0337ADD9C8909542 /* ka */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ka; path = ka.lproj/Localizable.strings; sourceTree = "<group>"; }; 4629710C0337ADD9C8909542 /* ka */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ka; path = ka.lproj/Localizable.strings; sourceTree = "<group>"; };
466C71A0FED9BFF287613C82 /* RoomDetailsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsScreenModels.swift; sourceTree = "<group>"; }; 466C71A0FED9BFF287613C82 /* RoomDetailsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsScreenModels.swift; sourceTree = "<group>"; };
467498BEA681758BE2F80826 /* TimelineMediaPreviewDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewDetailsView.swift; sourceTree = "<group>"; }; 467498BEA681758BE2F80826 /* TimelineMediaPreviewDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewDetailsView.swift; sourceTree = "<group>"; };
@@ -2392,7 +2393,7 @@
8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomStateEventStringBuilder.swift; sourceTree = "<group>"; }; 8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomStateEventStringBuilder.swift; sourceTree = "<group>"; };
8D8169443E5AC5FF71BFB3DB /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = "<group>"; }; 8D8169443E5AC5FF71BFB3DB /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = "<group>"; };
8DA1E8F287680C8ED25EDBAC /* NetworkMonitorMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkMonitorMock.swift; sourceTree = "<group>"; }; 8DA1E8F287680C8ED25EDBAC /* NetworkMonitorMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkMonitorMock.swift; sourceTree = "<group>"; };
8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UITests.xctestplan; sourceTree = "<group>"; }; 8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; path = UITests.xctestplan; sourceTree = "<group>"; };
8E1584F8BCF407BB94F48F04 /* EncryptionResetPasswordScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionResetPasswordScreen.swift; sourceTree = "<group>"; }; 8E1584F8BCF407BB94F48F04 /* EncryptionResetPasswordScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionResetPasswordScreen.swift; sourceTree = "<group>"; };
8E97CF050B0168F3D605F0E9 /* InviteUsersConfirmationSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersConfirmationSheetView.swift; sourceTree = "<group>"; }; 8E97CF050B0168F3D605F0E9 /* InviteUsersConfirmationSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersConfirmationSheetView.swift; sourceTree = "<group>"; };
8EAF4A49F3ACD8BB8B0D2371 /* ClientSDKMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientSDKMock.swift; sourceTree = "<group>"; }; 8EAF4A49F3ACD8BB8B0D2371 /* ClientSDKMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientSDKMock.swift; sourceTree = "<group>"; };
@@ -2551,7 +2552,7 @@
AAD8234D0E9C9B12BF9F240B /* LocationAnnotation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationAnnotation.swift; sourceTree = "<group>"; }; AAD8234D0E9C9B12BF9F240B /* LocationAnnotation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationAnnotation.swift; sourceTree = "<group>"; };
AB07F03461023BC39C730922 /* PhishingDetector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhishingDetector.swift; sourceTree = "<group>"; }; AB07F03461023BC39C730922 /* PhishingDetector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhishingDetector.swift; sourceTree = "<group>"; };
AB26D5444A4A7E095222DE8B /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.stringsdict"; sourceTree = "<group>"; }; AB26D5444A4A7E095222DE8B /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
AB389C38BD41EB3E47092CFB /* AccessibilityTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = AccessibilityTests.xctestplan; sourceTree = "<group>"; }; AB389C38BD41EB3E47092CFB /* AccessibilityTests.xctestplan */ = {isa = PBXFileReference; path = AccessibilityTests.xctestplan; sourceTree = "<group>"; };
ABA4CF2F5B4F68D02E412004 /* ServerConfirmationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfirmationScreenViewModelProtocol.swift; sourceTree = "<group>"; }; ABA4CF2F5B4F68D02E412004 /* ServerConfirmationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfirmationScreenViewModelProtocol.swift; sourceTree = "<group>"; };
ABF84AA68B2B7584D9275769 /* VoiceMessageTrashButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageTrashButton.swift; sourceTree = "<group>"; }; ABF84AA68B2B7584D9275769 /* VoiceMessageTrashButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageTrashButton.swift; sourceTree = "<group>"; };
AC0275CEE9CA078B34028BDF /* AppLockScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockScreenViewModelTests.swift; sourceTree = "<group>"; }; AC0275CEE9CA078B34028BDF /* AppLockScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockScreenViewModelTests.swift; sourceTree = "<group>"; };
@@ -2620,7 +2621,7 @@
B53AC78E49A297AC1D72A7CF /* AppMediator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppMediator.swift; sourceTree = "<group>"; }; B53AC78E49A297AC1D72A7CF /* AppMediator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppMediator.swift; sourceTree = "<group>"; };
B590BD4507D4F0A377FDE01A /* LoadableAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadableAvatarImage.swift; sourceTree = "<group>"; }; B590BD4507D4F0A377FDE01A /* LoadableAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadableAvatarImage.swift; sourceTree = "<group>"; };
B5D829FD8958376614504B18 /* TargetConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TargetConfiguration.swift; sourceTree = "<group>"; }; B5D829FD8958376614504B18 /* TargetConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TargetConfiguration.swift; sourceTree = "<group>"; };
B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = ConfettiScene.scn; sourceTree = "<group>"; }; B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; path = ConfettiScene.scn; sourceTree = "<group>"; };
B6404166CBF5CC88673FF9E2 /* RoomDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetails.swift; sourceTree = "<group>"; }; B6404166CBF5CC88673FF9E2 /* RoomDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetails.swift; sourceTree = "<group>"; };
B65DDCF8E41759890355ACBC /* AuthenticationStartScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationStartScreenViewModelProtocol.swift; sourceTree = "<group>"; }; B65DDCF8E41759890355ACBC /* AuthenticationStartScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationStartScreenViewModelProtocol.swift; sourceTree = "<group>"; };
B682FE2C44C5E163E7023B05 /* CopyTextButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyTextButton.swift; sourceTree = "<group>"; }; B682FE2C44C5E163E7023B05 /* CopyTextButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyTextButton.swift; sourceTree = "<group>"; };
@@ -2647,13 +2648,14 @@
B8F28602AC7AC881AED37EBA /* NavigationCoordinators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationCoordinators.swift; sourceTree = "<group>"; }; B8F28602AC7AC881AED37EBA /* NavigationCoordinators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationCoordinators.swift; sourceTree = "<group>"; };
B902EA6CD3296B0E10EE432B /* HomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreen.swift; sourceTree = "<group>"; }; B902EA6CD3296B0E10EE432B /* HomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreen.swift; sourceTree = "<group>"; };
B91AD590B0B40718A0AA0C61 /* DeferredFulfillment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeferredFulfillment.swift; sourceTree = "<group>"; }; B91AD590B0B40718A0AA0C61 /* DeferredFulfillment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeferredFulfillment.swift; sourceTree = "<group>"; };
B9406BD5F99685C5ABDEDD93 /* LocationShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationShareSheet.swift; sourceTree = "<group>"; };
B99E13633862847D8B7E2815 /* StartChatScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatScreenModels.swift; sourceTree = "<group>"; }; B99E13633862847D8B7E2815 /* StartChatScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatScreenModels.swift; sourceTree = "<group>"; };
BA241DEEF7C8A7181C0AEDC9 /* UserPreferenceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserPreferenceTests.swift; sourceTree = "<group>"; }; BA241DEEF7C8A7181C0AEDC9 /* UserPreferenceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserPreferenceTests.swift; sourceTree = "<group>"; };
BA257D747DD7E6FFA5C2BE2D /* LinkNewDeviceServiceMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkNewDeviceServiceMock.swift; sourceTree = "<group>"; }; BA257D747DD7E6FFA5C2BE2D /* LinkNewDeviceServiceMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkNewDeviceServiceMock.swift; sourceTree = "<group>"; };
BA40B98B098B6F0371B750B3 /* TemplateScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenModels.swift; sourceTree = "<group>"; }; BA40B98B098B6F0371B750B3 /* TemplateScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenModels.swift; sourceTree = "<group>"; };
BA919F521E9F0EE3638AFC85 /* BugReportScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportScreen.swift; sourceTree = "<group>"; }; BA919F521E9F0EE3638AFC85 /* BugReportScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportScreen.swift; sourceTree = "<group>"; };
BB284643AF7AB131E307DCE0 /* AudioSessionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioSessionProtocol.swift; sourceTree = "<group>"; }; BB284643AF7AB131E307DCE0 /* AudioSessionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioSessionProtocol.swift; sourceTree = "<group>"; };
BB576F4118C35E6B5124FA22 /* test_apple_image.heic */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_apple_image.heic; sourceTree = "<group>"; }; BB576F4118C35E6B5124FA22 /* test_apple_image.heic */ = {isa = PBXFileReference; path = test_apple_image.heic; sourceTree = "<group>"; };
BB5B00A014307CE37B2812CD /* TimelineViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineViewModelProtocol.swift; sourceTree = "<group>"; }; BB5B00A014307CE37B2812CD /* TimelineViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineViewModelProtocol.swift; sourceTree = "<group>"; };
BB6ED50FE104992419310EEB /* NotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationHandler.swift; sourceTree = "<group>"; }; BB6ED50FE104992419310EEB /* NotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationHandler.swift; sourceTree = "<group>"; };
BB8BC4C791D0E88CFCF4E5DF /* ServerSelectionScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionScreenCoordinator.swift; sourceTree = "<group>"; }; BB8BC4C791D0E88CFCF4E5DF /* ServerSelectionScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionScreenCoordinator.swift; sourceTree = "<group>"; };
@@ -2722,8 +2724,8 @@
C75EF87651B00A176AB08E97 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; C75EF87651B00A176AB08E97 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
C75FE3F524B575D53787868C /* TimelineMediaPreviewRedactConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewRedactConfirmationView.swift; sourceTree = "<group>"; }; C75FE3F524B575D53787868C /* TimelineMediaPreviewRedactConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewRedactConfirmationView.swift; sourceTree = "<group>"; };
C7661EFFCAA307A97D71132A /* HomeScreenRoomList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRoomList.swift; sourceTree = "<group>"; }; C7661EFFCAA307A97D71132A /* HomeScreenRoomList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRoomList.swift; sourceTree = "<group>"; };
C79C2C6E7F66646D1D254927 /* RoomLiveLocationServiceMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomLiveLocationServiceMock.swift; sourceTree = "<group>"; };
C830A64609CBD152F06E0457 /* NotificationConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationConstants.swift; sourceTree = "<group>"; }; C830A64609CBD152F06E0457 /* NotificationConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationConstants.swift; sourceTree = "<group>"; };
C89EE3CE58040FD2DF63DC23 /* RoomLiveLocationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomLiveLocationService.swift; sourceTree = "<group>"; };
C90514BE9B8ACCBCF0AD2489 /* ComposerToolbarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerToolbarViewModel.swift; sourceTree = "<group>"; }; C90514BE9B8ACCBCF0AD2489 /* ComposerToolbarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerToolbarViewModel.swift; sourceTree = "<group>"; };
C95ADE8D9527523572532219 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = hu; path = hu.lproj/Localizable.stringsdict; sourceTree = "<group>"; }; C95ADE8D9527523572532219 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = hu; path = hu.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
C97F8963B14EB0AF3940DDBF /* NotificationSettingsEditScreenRoomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenRoomCell.swift; sourceTree = "<group>"; }; C97F8963B14EB0AF3940DDBF /* NotificationSettingsEditScreenRoomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenRoomCell.swift; sourceTree = "<group>"; };
@@ -2760,7 +2762,7 @@
CDB3227C7A74B734924942E9 /* RoomSummaryProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryProvider.swift; sourceTree = "<group>"; }; CDB3227C7A74B734924942E9 /* RoomSummaryProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryProvider.swift; sourceTree = "<group>"; };
CDE3F3911FF7CC639BDE5844 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; }; CDE3F3911FF7CC639BDE5844 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
CEE20623EB4A9B88FB29F2BA /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/SAS.strings; sourceTree = "<group>"; }; CEE20623EB4A9B88FB29F2BA /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/SAS.strings; sourceTree = "<group>"; };
CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UnitTests.xctestplan; sourceTree = "<group>"; }; CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; path = UnitTests.xctestplan; sourceTree = "<group>"; };
CF19027E7FFA5E63D148873A /* CreateRoomScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomScreenViewModel.swift; sourceTree = "<group>"; }; CF19027E7FFA5E63D148873A /* CreateRoomScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomScreenViewModel.swift; sourceTree = "<group>"; };
CF847A34FC4C8C937CD39E08 /* LabsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabsScreenViewModelProtocol.swift; sourceTree = "<group>"; }; CF847A34FC4C8C937CD39E08 /* LabsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
CFFA5E881D281810AB428EA3 /* RoomPowerLevelsProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomPowerLevelsProxy.swift; sourceTree = "<group>"; }; CFFA5E881D281810AB428EA3 /* RoomPowerLevelsProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomPowerLevelsProxy.swift; sourceTree = "<group>"; };
@@ -2834,7 +2836,7 @@
DC0AEA686E425F86F6BA0404 /* UNNotification+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNNotification+Creator.swift"; sourceTree = "<group>"; }; DC0AEA686E425F86F6BA0404 /* UNNotification+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNNotification+Creator.swift"; sourceTree = "<group>"; };
DC10CCC8D68B863E20660DBC /* MessageForwardingScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageForwardingScreenViewModelProtocol.swift; sourceTree = "<group>"; }; DC10CCC8D68B863E20660DBC /* MessageForwardingScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageForwardingScreenViewModelProtocol.swift; sourceTree = "<group>"; };
DC528B3764E3CF7FCFEF40E7 /* PollInteractionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollInteractionHandler.swift; sourceTree = "<group>"; }; DC528B3764E3CF7FCFEF40E7 /* PollInteractionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollInteractionHandler.swift; sourceTree = "<group>"; };
DCA2D836BD10303F37FAAEED /* test_voice_message.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_voice_message.m4a; sourceTree = "<group>"; }; DCA2D836BD10303F37FAAEED /* test_voice_message.m4a */ = {isa = PBXFileReference; path = test_voice_message.m4a; sourceTree = "<group>"; };
DCAC01A97A43BE07B9E94E43 /* ShareExtensionModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareExtensionModels.swift; sourceTree = "<group>"; }; DCAC01A97A43BE07B9E94E43 /* ShareExtensionModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareExtensionModels.swift; sourceTree = "<group>"; };
DCDAB580109C09A6AA97AF7E /* PollFormScreenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenTests.swift; sourceTree = "<group>"; }; DCDAB580109C09A6AA97AF7E /* PollFormScreenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenTests.swift; sourceTree = "<group>"; };
DCF239C619971FDE48132550 /* SecureBackupLogoutConfirmationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenModels.swift; sourceTree = "<group>"; }; DCF239C619971FDE48132550 /* SecureBackupLogoutConfirmationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenModels.swift; sourceTree = "<group>"; };
@@ -2880,7 +2882,7 @@
E5272BC4A60B6AD7553BACA1 /* BlurHashDecode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurHashDecode.swift; sourceTree = "<group>"; }; E5272BC4A60B6AD7553BACA1 /* BlurHashDecode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurHashDecode.swift; sourceTree = "<group>"; };
E53BFB7E4F329621C844E8C3 /* AnalyticsPromptScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreen.swift; sourceTree = "<group>"; }; E53BFB7E4F329621C844E8C3 /* AnalyticsPromptScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreen.swift; sourceTree = "<group>"; };
E55B5EA766E89FF1F87C3ACB /* RoomNotificationSettingsProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsProxyProtocol.swift; sourceTree = "<group>"; }; E55B5EA766E89FF1F87C3ACB /* RoomNotificationSettingsProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsProxyProtocol.swift; sourceTree = "<group>"; };
E5E7D4EE7CA295E5039FDA21 /* portrait_test_video.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = portrait_test_video.mp4; sourceTree = "<group>"; }; E5E7D4EE7CA295E5039FDA21 /* portrait_test_video.mp4 */ = {isa = PBXFileReference; path = portrait_test_video.mp4; sourceTree = "<group>"; };
E5E94DCFEE803E5ABAE8ACCE /* KeychainControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainControllerProtocol.swift; sourceTree = "<group>"; }; E5E94DCFEE803E5ABAE8ACCE /* KeychainControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainControllerProtocol.swift; sourceTree = "<group>"; };
E5F2B6443D1ED8602F328539 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ru; path = ru.lproj/Localizable.stringsdict; sourceTree = "<group>"; }; E5F2B6443D1ED8602F328539 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ru; path = ru.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
E5FDFAA04174CC99FB66391C /* EditRoomAddressScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditRoomAddressScreenViewModel.swift; sourceTree = "<group>"; }; E5FDFAA04174CC99FB66391C /* EditRoomAddressScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditRoomAddressScreenViewModel.swift; sourceTree = "<group>"; };
@@ -2933,7 +2935,7 @@
ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemProtocol.swift; sourceTree = "<group>"; }; ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemProtocol.swift; sourceTree = "<group>"; };
ED25719E19B205B668FDACFF /* UserToInvite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserToInvite.swift; sourceTree = "<group>"; }; ED25719E19B205B668FDACFF /* UserToInvite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserToInvite.swift; sourceTree = "<group>"; };
ED33988DA4FD4FC666800106 /* SessionVerificationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModel.swift; sourceTree = "<group>"; }; ED33988DA4FD4FC666800106 /* SessionVerificationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModel.swift; sourceTree = "<group>"; };
ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = message.caf; sourceTree = "<group>"; }; ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; path = message.caf; sourceTree = "<group>"; };
ED49073BB1C1FC649DAC2CCD /* LocationRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRoomTimelineView.swift; sourceTree = "<group>"; }; ED49073BB1C1FC649DAC2CCD /* LocationRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRoomTimelineView.swift; sourceTree = "<group>"; };
ED60E4D2CD678E1EBF16F77A /* BlockedUsersScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreen.swift; sourceTree = "<group>"; }; ED60E4D2CD678E1EBF16F77A /* BlockedUsersScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreen.swift; sourceTree = "<group>"; };
EDDE826EAB1BAB80C1104980 /* SpaceFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceFlowCoordinator.swift; sourceTree = "<group>"; }; EDDE826EAB1BAB80C1104980 /* SpaceFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceFlowCoordinator.swift; sourceTree = "<group>"; };
@@ -2963,7 +2965,6 @@
F229480685F30BCB96C439EC /* AdvancedSettingsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreen.swift; sourceTree = "<group>"; }; F229480685F30BCB96C439EC /* AdvancedSettingsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreen.swift; sourceTree = "<group>"; };
F276F31C1AEC19E52B951B62 /* SendInviteConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendInviteConfirmationView.swift; sourceTree = "<group>"; }; F276F31C1AEC19E52B951B62 /* SendInviteConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendInviteConfirmationView.swift; sourceTree = "<group>"; };
F2B94F1B0B5D9D42B15AA6E8 /* ChatsTabFlowCoordinatorStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatsTabFlowCoordinatorStateMachine.swift; sourceTree = "<group>"; }; F2B94F1B0B5D9D42B15AA6E8 /* ChatsTabFlowCoordinatorStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatsTabFlowCoordinatorStateMachine.swift; sourceTree = "<group>"; };
F2C9C6EFC19EBB79E35806ED /* RoomLiveLocationServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomLiveLocationServiceProtocol.swift; sourceTree = "<group>"; };
F2DC502B1A566E99969D34DD /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/InfoPlist.strings; sourceTree = "<group>"; }; F2DC502B1A566E99969D34DD /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/InfoPlist.strings; sourceTree = "<group>"; };
F2E4EF80DFB8FE7C4469B15D /* RoomDirectorySearchScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDirectorySearchScreen.swift; sourceTree = "<group>"; }; F2E4EF80DFB8FE7C4469B15D /* RoomDirectorySearchScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDirectorySearchScreen.swift; sourceTree = "<group>"; };
F3082001D373607455CB08A1 /* QRCodeErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeErrorView.swift; sourceTree = "<group>"; }; F3082001D373607455CB08A1 /* QRCodeErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeErrorView.swift; sourceTree = "<group>"; };
@@ -3012,6 +3013,7 @@
FC3797A2325BE44FFB478BE9 /* LeaveSpaceRoomDetailsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeaveSpaceRoomDetailsCell.swift; sourceTree = "<group>"; }; FC3797A2325BE44FFB478BE9 /* LeaveSpaceRoomDetailsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeaveSpaceRoomDetailsCell.swift; sourceTree = "<group>"; };
FC83F47D2173B7538AA72E0E /* RoomSummaryProviderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryProviderMock.swift; sourceTree = "<group>"; }; FC83F47D2173B7538AA72E0E /* RoomSummaryProviderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryProviderMock.swift; sourceTree = "<group>"; };
FC9044BE0E4A66F5B963E834 /* AudioFileEventsTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioFileEventsTimelineView.swift; sourceTree = "<group>"; }; FC9044BE0E4A66F5B963E834 /* AudioFileEventsTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioFileEventsTimelineView.swift; sourceTree = "<group>"; };
FCDB4B1DAB0FE01CC874E8DA /* RoomLiveLocationServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomLiveLocationServiceProtocol.swift; sourceTree = "<group>"; };
FCE93F0CBF0D96B77111C413 /* AppLockFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockFlowCoordinator.swift; sourceTree = "<group>"; }; FCE93F0CBF0D96B77111C413 /* AppLockFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockFlowCoordinator.swift; sourceTree = "<group>"; };
FD1275D9CE0FFBA6E8E85426 /* UserIndicatorController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorController.swift; sourceTree = "<group>"; }; FD1275D9CE0FFBA6E8E85426 /* UserIndicatorController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorController.swift; sourceTree = "<group>"; };
FDB9C37196A4C79F24CE80C6 /* KeychainControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainControllerTests.swift; sourceTree = "<group>"; }; FDB9C37196A4C79F24CE80C6 /* KeychainControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainControllerTests.swift; sourceTree = "<group>"; };
@@ -3756,7 +3758,6 @@
7F957320D0EB7D7B4E30C79D /* KnockRequestProxyMock.swift */, 7F957320D0EB7D7B4E30C79D /* KnockRequestProxyMock.swift */,
BA257D747DD7E6FFA5C2BE2D /* LinkNewDeviceServiceMock.swift */, BA257D747DD7E6FFA5C2BE2D /* LinkNewDeviceServiceMock.swift */,
0B5DF0E888F66652F8C4CEC5 /* LiveLocationManagerMock.swift */, 0B5DF0E888F66652F8C4CEC5 /* LiveLocationManagerMock.swift */,
4609B3576A5E612A95352EC1 /* RoomLiveLocationServiceMock.swift */,
6F65E4BB9E82EB8373207CF8 /* MediaProviderMock.swift */, 6F65E4BB9E82EB8373207CF8 /* MediaProviderMock.swift */,
8DA1E8F287680C8ED25EDBAC /* NetworkMonitorMock.swift */, 8DA1E8F287680C8ED25EDBAC /* NetworkMonitorMock.swift */,
840182D7A61402D5947DE094 /* NotificationItemProxyMock.swift */, 840182D7A61402D5947DE094 /* NotificationItemProxyMock.swift */,
@@ -3766,6 +3767,7 @@
DD955A0380C287C418F1A74D /* PhotoLibraryManagerMock.swift */, DD955A0380C287C418F1A74D /* PhotoLibraryManagerMock.swift */,
D38391154120264910D19528 /* PollMock.swift */, D38391154120264910D19528 /* PollMock.swift */,
894EE8F5B399A165BA2A6634 /* RoomDirectorySearchMock.swift */, 894EE8F5B399A165BA2A6634 /* RoomDirectorySearchMock.swift */,
C79C2C6E7F66646D1D254927 /* RoomLiveLocationServiceMock.swift */,
36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */, 36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */,
F5D1BAA90F3A073D91B4F16B /* RoomNotificationSettingsProxyMock.swift */, F5D1BAA90F3A073D91B4F16B /* RoomNotificationSettingsProxyMock.swift */,
E944F717FC10A428D027074D /* RoomPowerLevelsProxyMock.swift */, E944F717FC10A428D027074D /* RoomPowerLevelsProxyMock.swift */,
@@ -5478,8 +5480,8 @@
D17F49E39CC38DAB7B305701 /* LiveLocationManager.swift */, D17F49E39CC38DAB7B305701 /* LiveLocationManager.swift */,
33752AE856E93CE62412B7A1 /* LiveLocationManagerProtocol.swift */, 33752AE856E93CE62412B7A1 /* LiveLocationManagerProtocol.swift */,
AA12A7F5EF5C6D0B992869ED /* LiveLocationShareProxy.swift */, AA12A7F5EF5C6D0B992869ED /* LiveLocationShareProxy.swift */,
C89EE3CE58040FD2DF63DC23 /* RoomLiveLocationService.swift */, 118892B93A8CFDD691D9B5E3 /* RoomLiveLocationService.swift */,
F2C9C6EFC19EBB79E35806ED /* RoomLiveLocationServiceProtocol.swift */, FCDB4B1DAB0FE01CC874E8DA /* RoomLiveLocationServiceProtocol.swift */,
); );
path = Location; path = Location;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -5703,6 +5705,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
408ACC0D28656F82A5EB6A7E /* LocationPickerSheet.swift */, 408ACC0D28656F82A5EB6A7E /* LocationPickerSheet.swift */,
B9406BD5F99685C5ABDEDD93 /* LocationShareSheet.swift */,
6F56E6E41C6DFE8054787D57 /* LocationSharingScreen.swift */, 6F56E6E41C6DFE8054787D57 /* LocationSharingScreen.swift */,
ECE03E834CC8C2721899E6AC /* StaticLocationSheet.swift */, ECE03E834CC8C2721899E6AC /* StaticLocationSheet.swift */,
); );
@@ -7343,7 +7346,6 @@
}; };
}; };
buildConfigurationList = 7AE41FCCF9D1352E2770D1F9 /* Build configuration list for PBXProject "ElementX" */; buildConfigurationList = 7AE41FCCF9D1352E2770D1F9 /* Build configuration list for PBXProject "ElementX" */;
compatibilityVersion = "Xcode 14.0";
developmentRegion = en; developmentRegion = en;
hasScannedForEncodings = 0; hasScannedForEncodings = 0;
knownRegions = ( knownRegions = (
@@ -7421,6 +7423,7 @@
C89CF7729E028671C5DC461E /* XCLocalSwiftPackageReference "compound-ios" */, C89CF7729E028671C5DC461E /* XCLocalSwiftPackageReference "compound-ios" */,
); );
preferredProjectObjectVersion = 77; preferredProjectObjectVersion = 77;
productRefGroup = 681566846AF307E9BA4C72C6 /* Products */;
projectDirPath = ""; projectDirPath = "";
projectRoot = ""; projectRoot = "";
targets = ( targets = (
@@ -8420,9 +8423,6 @@
C8D0AC22E03F652118A2BB73 /* LiveLocationRoomTimelineItem.swift in Sources */, C8D0AC22E03F652118A2BB73 /* LiveLocationRoomTimelineItem.swift in Sources */,
F7977C53B2B1D73030C69761 /* LiveLocationRoomTimelineView.swift in Sources */, F7977C53B2B1D73030C69761 /* LiveLocationRoomTimelineView.swift in Sources */,
633400018E07D2DC7175B16E /* LiveLocationShareProxy.swift in Sources */, 633400018E07D2DC7175B16E /* LiveLocationShareProxy.swift in Sources */,
FA5FD4910EA871ACCED8D47B /* RoomLiveLocationServiceMock.swift in Sources */,
C9169AB88A0953C0B3D8601B /* RoomLiveLocationService.swift in Sources */,
7C9A62022717060DFC1878D7 /* RoomLiveLocationServiceProtocol.swift in Sources */,
9223E5F2A2CE0AFFDFF0AFFB /* LiveLocationSharingBannerView.swift in Sources */, 9223E5F2A2CE0AFFDFF0AFFB /* LiveLocationSharingBannerView.swift in Sources */,
6E47D126DD7585E8F8237CE7 /* LoadableAvatarImage.swift in Sources */, 6E47D126DD7585E8F8237CE7 /* LoadableAvatarImage.swift in Sources */,
D9F80CE61BF8FF627FDB0543 /* LoadableImage.swift in Sources */, D9F80CE61BF8FF627FDB0543 /* LoadableImage.swift in Sources */,
@@ -8432,6 +8432,7 @@
D46C33F8B61B55F0C8C2D15F /* LocationRoomTimelineItem.swift in Sources */, D46C33F8B61B55F0C8C2D15F /* LocationRoomTimelineItem.swift in Sources */,
854E82E064BA53CD0BC45600 /* LocationRoomTimelineItemContent.swift in Sources */, 854E82E064BA53CD0BC45600 /* LocationRoomTimelineItemContent.swift in Sources */,
973C48F9E4EFB808F61BE401 /* LocationRoomTimelineView.swift in Sources */, 973C48F9E4EFB808F61BE401 /* LocationRoomTimelineView.swift in Sources */,
19946B8EEE158356EB5E1107 /* LocationShareSheet.swift in Sources */,
C67156445600FAE6430DE41E /* LocationSharingScreen.swift in Sources */, C67156445600FAE6430DE41E /* LocationSharingScreen.swift in Sources */,
7A37EC9D7164319587539E1D /* LocationSharingScreenCoordinator.swift in Sources */, 7A37EC9D7164319587539E1D /* LocationSharingScreenCoordinator.swift in Sources */,
29491EE7AE37E239E839C5A3 /* LocationSharingScreenModels.swift in Sources */, 29491EE7AE37E239E839C5A3 /* LocationSharingScreenModels.swift in Sources */,
@@ -8690,6 +8691,9 @@
4A9CEEE612D6D8B3DDBD28BA /* RoomListFilterView.swift in Sources */, 4A9CEEE612D6D8B3DDBD28BA /* RoomListFilterView.swift in Sources */,
BD0BE20DBCE31253AE4490A1 /* RoomListFiltersEmptyStateView.swift in Sources */, BD0BE20DBCE31253AE4490A1 /* RoomListFiltersEmptyStateView.swift in Sources */,
33F1FB19F222BA9930AB1A00 /* RoomListFiltersView.swift in Sources */, 33F1FB19F222BA9930AB1A00 /* RoomListFiltersView.swift in Sources */,
18FD4EA36456910FD9CB1B95 /* RoomLiveLocationService.swift in Sources */,
84196A8F1963D55726261879 /* RoomLiveLocationServiceMock.swift in Sources */,
811D9AA152443037BEDA6F22 /* RoomLiveLocationServiceProtocol.swift in Sources */,
8DC176CC5ABA24138EB443DD /* RoomMemberDetails.swift in Sources */, 8DC176CC5ABA24138EB443DD /* RoomMemberDetails.swift in Sources */,
19FE025AE9BA2959B6589B0D /* RoomMemberDetailsScreen.swift in Sources */, 19FE025AE9BA2959B6589B0D /* RoomMemberDetailsScreen.swift in Sources */,
899793EFC63DF93C3E0141E7 /* RoomMemberDetailsScreenCoordinator.swift in Sources */, 899793EFC63DF93C3E0141E7 /* RoomMemberDetailsScreenCoordinator.swift in Sources */,
@@ -9383,7 +9387,9 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@loader_path/Frameworks", "@loader_path/Frameworks",
); );
OTHER_SWIFT_FLAGS = "-DRELEASE"; OTHER_SWIFT_FLAGS = (
"-DRELEASE",
);
PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.accessibility.tests"; PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.accessibility.tests";
PRODUCT_NAME = AccessibilityTests; PRODUCT_NAME = AccessibilityTests;
SDKROOT = iphoneos; SDKROOT = iphoneos;
@@ -9402,7 +9408,9 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@loader_path/Frameworks", "@loader_path/Frameworks",
); );
OTHER_SWIFT_FLAGS = "-DDEBUG"; OTHER_SWIFT_FLAGS = (
"-DDEBUG",
);
PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.accessibility.tests"; PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.accessibility.tests";
PRODUCT_NAME = AccessibilityTests; PRODUCT_NAME = AccessibilityTests;
SDKROOT = iphoneos; SDKROOT = iphoneos;
@@ -9424,7 +9432,9 @@
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = "$(MARKETING_VERSION)"; MARKETING_VERSION = "$(MARKETING_VERSION)";
OTHER_SWIFT_FLAGS = "-DIS_NSE"; OTHER_SWIFT_FLAGS = (
"-DIS_NSE",
);
PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.nse"; PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.nse";
PRODUCT_DISPLAY_NAME = "$(APP_DISPLAY_NAME)"; PRODUCT_DISPLAY_NAME = "$(APP_DISPLAY_NAME)";
PRODUCT_NAME = NSE; PRODUCT_NAME = NSE;
@@ -9491,7 +9501,9 @@
"$(inherited)", "$(inherited)",
"-ObjC", "-ObjC",
); );
OTHER_SWIFT_FLAGS = "-DIS_MAIN_APP"; OTHER_SWIFT_FLAGS = (
"-DIS_MAIN_APP",
);
PILLS_UT_TYPE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).pills"; PILLS_UT_TYPE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).pills";
PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)"; PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)";
PRODUCT_NAME = "$(APP_NAME)"; PRODUCT_NAME = "$(APP_NAME)";
@@ -9521,7 +9533,9 @@
"$(inherited)", "$(inherited)",
"-ObjC", "-ObjC",
); );
OTHER_SWIFT_FLAGS = "-DIS_MAIN_APP"; OTHER_SWIFT_FLAGS = (
"-DIS_MAIN_APP",
);
PILLS_UT_TYPE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).pills"; PILLS_UT_TYPE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).pills";
PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)"; PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)";
PRODUCT_NAME = "$(APP_NAME)"; PRODUCT_NAME = "$(APP_NAME)";
@@ -9754,7 +9768,9 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@loader_path/Frameworks", "@loader_path/Frameworks",
); );
OTHER_SWIFT_FLAGS = "-DDEBUG"; OTHER_SWIFT_FLAGS = (
"-DDEBUG",
);
PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.ui.tests"; PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.ui.tests";
PRODUCT_NAME = UITests; PRODUCT_NAME = UITests;
SDKROOT = iphoneos; SDKROOT = iphoneos;
@@ -9773,7 +9789,9 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@loader_path/Frameworks", "@loader_path/Frameworks",
); );
OTHER_SWIFT_FLAGS = "-DRELEASE"; OTHER_SWIFT_FLAGS = (
"-DRELEASE",
);
PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.ui.tests"; PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.ui.tests";
PRODUCT_NAME = UITests; PRODUCT_NAME = UITests;
SDKROOT = iphoneos; SDKROOT = iphoneos;
@@ -9795,7 +9813,9 @@
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = "$(MARKETING_VERSION)"; MARKETING_VERSION = "$(MARKETING_VERSION)";
OTHER_SWIFT_FLAGS = "-DIS_NSE"; OTHER_SWIFT_FLAGS = (
"-DIS_NSE",
);
PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.nse"; PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.nse";
PRODUCT_DISPLAY_NAME = "$(APP_DISPLAY_NAME)"; PRODUCT_DISPLAY_NAME = "$(APP_DISPLAY_NAME)";
PRODUCT_NAME = NSE; PRODUCT_NAME = NSE;
@@ -86,7 +86,10 @@ class PinnedEventsTimelineFlowCoordinator: FlowCoordinatorProtocol {
case .displayUser(let userID): case .displayUser(let userID):
actionsSubject.send(.displayUser(userID: userID)) actionsSubject.send(.displayUser(userID: userID))
case .presentLocationViewer(let location): case .presentLocationViewer(let location):
presentMapNavigator(location: location, presentMapNavigator(interactionMode: .viewStatic(location),
timelineController: timelineController)
case .presentLiveLocationViewer(let sender, let initialLiveLocationShare):
presentMapNavigator(interactionMode: .viewLive(sender: sender, initialLiveLocationShare: initialLiveLocationShare),
timelineController: timelineController) timelineController: timelineController)
case .displayMessageForwarding(let forwardingItem): case .displayMessageForwarding(let forwardingItem):
presentMessageForwarding(with: forwardingItem) presentMessageForwarding(with: forwardingItem)
@@ -99,11 +102,11 @@ class PinnedEventsTimelineFlowCoordinator: FlowCoordinatorProtocol {
navigationStackCoordinator.setRootCoordinator(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator)
} }
private func presentMapNavigator(location: StaticLocationData, private func presentMapNavigator(interactionMode: LocationSharingInteractionMode,
timelineController: TimelineControllerProtocol) { timelineController: TimelineControllerProtocol) {
let stackCoordinator = NavigationStackCoordinator() let stackCoordinator = NavigationStackCoordinator()
let params = LocationSharingScreenCoordinatorParameters(interactionMode: .viewStatic(location), let params = LocationSharingScreenCoordinatorParameters(interactionMode: interactionMode,
mapURLBuilder: flowParameters.appSettings.mapTilerConfiguration, mapURLBuilder: flowParameters.appSettings.mapTilerConfiguration,
liveLocationSharingEnabled: flowParameters.appSettings.liveLocationSharingEnabled, liveLocationSharingEnabled: flowParameters.appSettings.liveLocationSharingEnabled,
roomProxy: roomProxy, roomProxy: roomProxy,
@@ -712,6 +712,9 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
stateMachine.tryEvent(.presentMapNavigator(interactionMode: .viewStatic(location)), stateMachine.tryEvent(.presentMapNavigator(interactionMode: .viewStatic(location)),
userInfo: EventUserInfo(animated: animated, userInfo: EventUserInfo(animated: animated,
timelineController: timelineController)) timelineController: timelineController))
case .presentLiveLocationViewer(let sender, let initialLiveLocationShare):
stateMachine.tryEvent(.presentMapNavigator(interactionMode: .viewLive(sender: sender, initialLiveLocationShare: initialLiveLocationShare)),
userInfo: EventUserInfo(animated: animated, timelineController: timelineController))
case .presentRoomMemberDetails(userID: let userID): case .presentRoomMemberDetails(userID: let userID):
stateMachine.tryEvent(.startMembersFlow(entryPoint: .roomMember(userID: userID))) stateMachine.tryEvent(.startMembersFlow(entryPoint: .roomMember(userID: userID)))
case .presentMessageForwarding(let forwardingItem): case .presentMessageForwarding(let forwardingItem):
@@ -811,6 +814,9 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
case .presentLocationPicker: case .presentLocationPicker:
stateMachine.tryEvent(.presentMapNavigator(interactionMode: .picker), stateMachine.tryEvent(.presentMapNavigator(interactionMode: .picker),
userInfo: EventUserInfo(animated: animated, timelineController: timelineController)) userInfo: EventUserInfo(animated: animated, timelineController: timelineController))
case .presentLiveLocationViewer(let sender, let initialLiveLocationShare):
stateMachine.tryEvent(.presentMapNavigator(interactionMode: .viewLive(sender: sender, initialLiveLocationShare: initialLiveLocationShare)),
userInfo: EventUserInfo(animated: animated, timelineController: timelineController))
case .presentPollForm(let mode): case .presentPollForm(let mode):
stateMachine.tryEvent(.presentPollForm(mode: mode), stateMachine.tryEvent(.presentPollForm(mode: mode),
userInfo: EventUserInfo(animated: animated, timelineController: timelineController)) userInfo: EventUserInfo(animated: animated, timelineController: timelineController))
@@ -6,32 +6,24 @@
// Please see LICENSE files in the repository root for full details. // Please see LICENSE files in the repository root for full details.
// //
import CoreLocation
import Foundation import Foundation
import MapLibre import MapLibre
import SwiftUI import SwiftUI
final class LocationAnnotation: NSObject, MLNAnnotation { final class LocationAnnotation: NSObject, MLNAnnotation, Identifiable {
let id: String let id: String
var coordinate: CLLocationCoordinate2D var coordinate: CLLocationCoordinate2D
let anchorPoint: CGPoint var kind: LocationMarkerKind
var view: AnyView
// MARK: - Setup // MARK: - Setup
init(id: String = UUID().uuidString, init(id: String, coordinate: CLLocationCoordinate2D, kind: LocationMarkerKind) {
coordinate: CLLocationCoordinate2D,
anchorPoint: CGPoint = .init(x: 0.5, y: 0.5),
@ViewBuilder label: () -> some View) {
self.id = id self.id = id
self.coordinate = coordinate self.coordinate = coordinate
self.anchorPoint = anchorPoint self.kind = kind
view = AnyView(label())
super.init() super.init()
} }
func updateView(@ViewBuilder label: () -> some View) {
view = AnyView(label())
}
} }
final class LocationAnnotationView: MLNUserLocationAnnotationView { final class LocationAnnotationView: MLNUserLocationAnnotationView {
@@ -44,19 +36,21 @@ final class LocationAnnotationView: MLNUserLocationAnnotationView {
reuseIdentifier) reuseIdentifier)
} }
convenience init(annotation: LocationAnnotation) { convenience init(annotation: LocationAnnotation, mediaProvider: MediaProviderProtocol?) {
self.init(annotation: annotation, reuseIdentifier: "\(Self.self)") self.init(annotation: annotation, reuseIdentifier: "\(Self.self)")
let hostingController = UIHostingController(rootView: annotation.view) let markerView = LocationMarkerView(kind: annotation.kind, mediaProvider: mediaProvider)
let hostingController = UIHostingController(rootView: AnyView(markerView))
self.hostingController = hostingController self.hostingController = hostingController
let view: UIView = hostingController.view let view: UIView = hostingController.view
view.backgroundColor = .clear view.backgroundColor = .clear
view.anchorPoint = annotation.anchorPoint view.anchorPoint = .init(x: 0.5, y: 1.0)
addSubview(view) addSubview(view)
view.bounds.size = view.intrinsicContentSize view.bounds.size = view.intrinsicContentSize
} }
func updateContent(with view: AnyView) { func updateContent(with kind: LocationMarkerKind, mediaProvider: MediaProviderProtocol?) {
hostingController?.rootView = view let markerView = LocationMarkerView(kind: kind, mediaProvider: mediaProvider)
hostingController?.rootView = AnyView(markerView)
if let hostedView = hostingController?.view { if let hostedView = hostingController?.view {
hostedView.bounds.size = hostedView.intrinsicContentSize hostedView.bounds.size = hostedView.intrinsicContentSize
} }
@@ -20,10 +20,10 @@ struct MapLibreMapView: UIViewRepresentable {
/// The initial map center /// The initial map center
let mapCenter: CLLocationCoordinate2D let mapCenter: CLLocationCoordinate2D
/// Map annotations keyed by a stable identifier (e.g. sender userID for user pins, UUID string for generic pins) /// Map annotations
let annotations: [String: LocationAnnotation] let annotations: [LocationAnnotation]
init(zoomLevel: Double, initialZoomLevel: Double, mapCenter: CLLocationCoordinate2D, annotations: [String: LocationAnnotation] = [:]) { init(zoomLevel: Double, initialZoomLevel: Double, mapCenter: CLLocationCoordinate2D, annotations: [LocationAnnotation] = []) {
self.zoomLevel = zoomLevel self.zoomLevel = zoomLevel
self.initialZoomLevel = initialZoomLevel self.initialZoomLevel = initialZoomLevel
self.mapCenter = mapCenter self.mapCenter = mapCenter
@@ -39,6 +39,8 @@ struct MapLibreMapView: UIViewRepresentable {
let options: Options let options: Options
let mediaProvider: MediaProviderProtocol?
/// Behavior mode of the current user's location, can be hidden, only shown and shown following the user /// Behavior mode of the current user's location, can be hidden, only shown and shown following the user
@Binding var showsUserLocationMode: ShowUserLocationMode @Binding var showsUserLocationMode: ShowUserLocationMode
/// Bind view errors if any /// Bind view errors if any
@@ -86,7 +88,7 @@ struct MapLibreMapView: UIViewRepresentable {
// MARK: - Private // MARK: - Private
private func setupMap(mapView: MLNMapView, with options: Options) { private func setupMap(mapView: MLNMapView, with options: Options) {
mapView.addAnnotations(Array(options.annotations.values)) mapView.addAnnotations(options.annotations)
mapView.zoomLevel = options.annotations.isEmpty ? options.initialZoomLevel : options.zoomLevel mapView.zoomLevel = options.annotations.isEmpty ? options.initialZoomLevel : options.zoomLevel
mapView.centerCoordinate = options.mapCenter mapView.centerCoordinate = options.mapCenter
} }
@@ -94,9 +96,10 @@ struct MapLibreMapView: UIViewRepresentable {
private func updateAnnotations(in mapView: MLNMapView) { private func updateAnnotations(in mapView: MLNMapView) {
let existingByID = Dictionary(uniqueKeysWithValues: let existingByID = Dictionary(uniqueKeysWithValues:
(mapView.annotations ?? []).compactMap { $0 as? LocationAnnotation }.map { ($0.id, $0) }) (mapView.annotations ?? []).compactMap { $0 as? LocationAnnotation }.map { ($0.id, $0) })
let updatedByID = Dictionary(uniqueKeysWithValues: options.annotations.map { ($0.id, $0) })
let existingIDs = Set(existingByID.keys) let existingIDs = Set(existingByID.keys)
let updatedIDs = Set(options.annotations.keys) let updatedIDs = Set(updatedByID.keys)
// Remove annotations that are no longer present // Remove annotations that are no longer present
let removedIDs = existingIDs.subtracting(updatedIDs) let removedIDs = existingIDs.subtracting(updatedIDs)
@@ -108,7 +111,7 @@ struct MapLibreMapView: UIViewRepresentable {
// Add new annotations // Add new annotations
let addedIDs = updatedIDs.subtracting(existingIDs) let addedIDs = updatedIDs.subtracting(existingIDs)
if !addedIDs.isEmpty { if !addedIDs.isEmpty {
let toAdd = addedIDs.compactMap { options.annotations[$0] } let toAdd = addedIDs.compactMap { updatedByID[$0] }
mapView.addAnnotations(toAdd) mapView.addAnnotations(toAdd)
} }
@@ -116,12 +119,12 @@ struct MapLibreMapView: UIViewRepresentable {
let keptIDs = existingIDs.intersection(updatedIDs) let keptIDs = existingIDs.intersection(updatedIDs)
for id in keptIDs { for id in keptIDs {
guard let existingAnnotation = existingByID[id], guard let existingAnnotation = existingByID[id],
let updatedAnnotation = options.annotations[id] else { let updatedAnnotation = updatedByID[id] else {
continue continue
} }
existingAnnotation.coordinate = updatedAnnotation.coordinate existingAnnotation.coordinate = updatedAnnotation.coordinate
if let annotationView = mapView.view(for: existingAnnotation) as? LocationAnnotationView { if let annotationView = mapView.view(for: existingAnnotation) as? LocationAnnotationView {
annotationView.updateContent(with: updatedAnnotation.view) annotationView.updateContent(with: updatedAnnotation.kind, mediaProvider: mediaProvider)
} }
} }
} }
@@ -179,7 +182,7 @@ extension MapLibreMapView {
guard let annotation = annotation as? LocationAnnotation else { guard let annotation = annotation as? LocationAnnotation else {
return nil return nil
} }
return LocationAnnotationView(annotation: annotation) return LocationAnnotationView(annotation: annotation, mediaProvider: mapLibreView.mediaProvider)
} }
func mapViewDidFailLoadingMap(_ mapView: MLNMapView, withError error: Error) { func mapViewDidFailLoadingMap(_ mapView: MLNMapView, withError error: Error) {
@@ -26,6 +26,7 @@ enum LocationSharingScreenViewModelAction {
enum LocationSharingInteractionMode: Hashable { enum LocationSharingInteractionMode: Hashable {
case picker case picker
case viewStatic(StaticLocationData) case viewStatic(StaticLocationData)
case viewLive(sender: TimelineItemSender, initialLiveLocationShare: LiveLocationShare)
} }
struct LocationSharingScreenViewState: BindableState { struct LocationSharingScreenViewState: BindableState {
@@ -38,16 +39,23 @@ struct LocationSharingScreenViewState: BindableState {
self.showLiveLocationSharingButton = showLiveLocationSharingButton self.showLiveLocationSharingButton = showLiveLocationSharingButton
self.ownUserID = ownUserID self.ownUserID = ownUserID
userProfile = switch interactionMode { let initialProfile: UserProfileProxy = switch interactionMode {
case .viewStatic(let locationData): case .viewStatic(let locationData):
.init(sender: locationData.sender) .init(sender: locationData.sender)
case .viewLive(let sender, _):
.init(sender: sender)
case .picker: case .picker:
.init(userID: ownUserID) .init(userID: ownUserID)
} }
userProfiles = [initialProfile.userID: initialProfile]
if case .viewLive(_, let initialLiveLocationShare) = interactionMode {
liveLocationShares = [initialLiveLocationShare]
}
bindings.showsUserLocationMode = switch interactionMode { bindings.showsUserLocationMode = switch interactionMode {
case .picker: .showAndFollow case .picker: .showAndFollow
case .viewStatic: .show case .viewStatic, .viewLive: .show
} }
} }
@@ -55,10 +63,35 @@ struct LocationSharingScreenViewState: BindableState {
let mapURLBuilder: MapTilerURLBuilderProtocol let mapURLBuilder: MapTilerURLBuilderProtocol
let showLiveLocationSharingButton: Bool let showLiveLocationSharingButton: Bool
let ownUserID: String let ownUserID: String
var userProfile: UserProfileProxy var userProfiles: [String: UserProfileProxy]
var liveLocationShares: [LiveLocationShare] = []
var isOwnUser: Bool { var annotations: [LocationAnnotation] {
userProfile.userID == ownUserID switch interactionMode {
case .viewStatic(let location):
let profile = userProfiles.values.first
let kind: LocationMarkerKind = if location.kind == .sender, let profile {
.staticUser(profile)
} else {
.pin
}
let coordinate = CLLocationCoordinate2D(latitude: location.geoURI.latitude, longitude: location.geoURI.longitude)
return [LocationAnnotation(id: kind.id, coordinate: coordinate, kind: kind)]
case .viewLive:
return liveLocationShares.compactMap { share in
guard let geoURI = share.geoURI else { return nil }
let profile = userProfiles[share.userID] ?? UserProfileProxy(userID: share.userID)
let kind = LocationMarkerKind.liveUser(profile)
let coordinate = CLLocationCoordinate2D(latitude: geoURI.latitude, longitude: geoURI.longitude)
return LocationAnnotation(id: profile.userID, coordinate: coordinate, kind: kind)
}
case .picker:
return []
}
}
func isOwnUser(_ userID: String) -> Bool {
userID == ownUserID
} }
var bindings = LocationSharingScreenBindings(showsUserLocationMode: .hide) var bindings = LocationSharingScreenBindings(showsUserLocationMode: .hide)
@@ -75,15 +108,9 @@ struct LocationSharingScreenViewState: BindableState {
.init(latitude: 49.843, longitude: 9.902056) .init(latitude: 49.843, longitude: 9.902056)
case .viewStatic(let location): case .viewStatic(let location):
.init(latitude: location.geoURI.latitude, longitude: location.geoURI.longitude) .init(latitude: location.geoURI.latitude, longitude: location.geoURI.longitude)
} case .viewLive(_, let initialLiveLocationShare):
} .init(latitude: initialLiveLocationShare.geoURI?.latitude ?? 0,
longitude: initialLiveLocationShare.geoURI?.longitude ?? 0)
var isLocationPickerMode: Bool {
switch interactionMode {
case .picker:
true
default:
false
} }
} }
@@ -101,18 +128,18 @@ struct LocationSharingScreenViewState: BindableState {
switch interactionMode { switch interactionMode {
case .picker: case .picker:
return 2.7 return 2.7
case .viewStatic: case .viewStatic, .viewLive:
return 15.0 return 15.0
} }
} }
var locationMarkerKind: LocationMarkerKind { /// The marker kind used for the picker overlay (not a map annotation).
switch interactionMode { var pickerMarkerKind: LocationMarkerKind? {
case .picker: guard case .picker = interactionMode else { return nil }
isSharingUserLocation ? .staticUser(userProfile) : .pin if let profile = userProfiles.values.first {
case .viewStatic(let location): return isSharingUserLocation ? .staticUser(profile) : .pin
location.kind == .sender ? .staticUser(userProfile) : .pin
} }
return .pin
} }
} }
@@ -139,7 +166,7 @@ struct LocationSharingScreenBindings {
/// Information describing the currently displayed alert. /// Information describing the currently displayed alert.
var alertInfo: AlertInfo<LocationSharingViewAlert>? var alertInfo: AlertInfo<LocationSharingViewAlert>?
var showShareSheet = false var sharedAnnotation: LocationAnnotation?
} }
enum LocationSharingScreenViewAction { enum LocationSharingScreenViewAction {
@@ -193,7 +220,7 @@ extension AlertInfo where T == LocationSharingViewAlert {
} }
} }
enum LocationMarkerKind { enum LocationMarkerKind: Equatable {
case pin case pin
case staticUser(UserProfileProxy) case staticUser(UserProfileProxy)
case liveUser(UserProfileProxy) case liveUser(UserProfileProxy)
@@ -7,6 +7,7 @@
// //
import Combine import Combine
import CoreLocation
import Foundation import Foundation
import SwiftUI import SwiftUI
@@ -26,6 +27,8 @@ class LocationSharingScreenViewModel: LocationSharingScreenViewModelType, Locati
} }
private var authorizationStatusSubscription: AnyCancellable? private var authorizationStatusSubscription: AnyCancellable?
// periphery:ignore - keep alive to keep receiving updates.
private var liveLocationService: RoomLiveLocationServiceProtocol?
init(interactionMode: LocationSharingInteractionMode, init(interactionMode: LocationSharingInteractionMode,
mapURLBuilder: MapTilerURLBuilderProtocol, mapURLBuilder: MapTilerURLBuilderProtocol,
@@ -50,8 +53,12 @@ class LocationSharingScreenViewModel: LocationSharingScreenViewModelType, Locati
ownUserID: roomProxy.ownUserID), ownUserID: roomProxy.ownUserID),
mediaProvider: mediaProvider) mediaProvider: mediaProvider)
updateShownUserProfile(members: roomProxy.membersPublisher.value) updateUserProfiles(members: roomProxy.membersPublisher.value)
setupSubscriptions() setupSubscriptions()
if case .viewLive = interactionMode {
Task { await setupLiveLocationSubscription() }
}
} }
override func process(viewAction: LocationSharingScreenViewAction) { override func process(viewAction: LocationSharingScreenViewAction) {
@@ -81,9 +88,23 @@ class LocationSharingScreenViewModel: LocationSharingScreenViewModelType, Locati
// MARK: - Private // MARK: - Private
private func setupLiveLocationSubscription() async {
let liveLocationService = await roomProxy.makeLiveLocationService()
self.liveLocationService = liveLocationService
liveLocationService.liveLocationsPublisher
.sink { [weak self] liveLocationsShares in
guard let self else { return }
MXLog.info("Received live location shares update: \(liveLocationsShares.count) share(s)")
state.liveLocationShares = liveLocationsShares
updateUserProfiles(members: roomProxy.membersPublisher.value)
}
.store(in: &cancellables)
}
private func setupSubscriptions() { private func setupSubscriptions() {
roomProxy.membersPublisher.sink { [weak self] members in roomProxy.membersPublisher.sink { [weak self] members in
self?.updateShownUserProfile(members: members) self?.updateUserProfiles(members: members)
} }
.store(in: &cancellables) .store(in: &cancellables)
@@ -95,19 +116,23 @@ class LocationSharingScreenViewModel: LocationSharingScreenViewModelType, Locati
.store(in: &cancellables) .store(in: &cancellables)
} }
private func updateShownUserProfile(members: [RoomMemberProxyProtocol]) { private func updateUserProfiles(members: [RoomMemberProxyProtocol]) {
switch state.interactionMode { switch state.interactionMode {
case .picker: case .picker:
if let ownUser = members.first(where: { $0.userID == roomProxy.ownUserID }).map(UserProfileProxy.init) { let ownUser = members.first(where: { $0.userID == roomProxy.ownUserID }).map(UserProfileProxy.init) ?? .init(userID: roomProxy.ownUserID)
state.userProfile = ownUser state.userProfiles = [ownUser.userID: ownUser]
} else {
state.userProfile = .init(userID: roomProxy.ownUserID)
}
case .viewStatic(let location): case .viewStatic(let location):
if let sender = members.first(where: { $0.userID == location.sender.id }).map(UserProfileProxy.init) { let sender = members.first(where: { $0.userID == location.sender.id }).map(UserProfileProxy.init) ?? .init(sender: location.sender)
state.userProfile = sender state.userProfiles = [sender.userID: sender]
} else { case .viewLive(let sender, _):
state.userProfile = .init(sender: location.sender) var userIDs = Set(state.liveLocationShares.map(\.userID))
userIDs.insert(sender.id)
state.userProfiles = userIDs.reduce(into: [:]) { dict, userID in
if let member = members.first(where: { $0.userID == userID }) {
dict[userID] = UserProfileProxy(member: member)
} else {
dict[userID] = UserProfileProxy(userID: userID)
}
} }
} }
} }
@@ -0,0 +1,52 @@
//
// 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.
//
import CoreLocation
import SwiftUI
struct LocationShareSheet: View {
let annotation: LocationAnnotation
private var location: CLLocationCoordinate2D {
annotation.coordinate
}
private var senderName: String? {
annotation.kind.displayName ?? annotation.kind.userProfile?.userID
}
var body: some View {
AppActivityView(activityItems: [ShareToMapsAppActivity.MapsAppType.apple.activityURL(for: location, senderName: senderName)],
applicationActivities: ShareToMapsAppActivity.MapsAppType.allCases.map { ShareToMapsAppActivity(type: $0, location: location, senderName: senderName) })
.ignoresSafeArea(edges: .bottom)
.presentationDetents([.medium, .large])
.presentationCompactAdaptation(compactPresentation)
.presentationDragIndicator(.hidden)
}
private var compactPresentation: PresentationAdaptation {
if #available(iOS 26.0, *) {
.none // ShareLinks use a popover presentation on iOS 26, let it match that.
} else {
.sheet
}
}
}
// MARK: - Previews
struct LocationShareSheet_Previews: PreviewProvider {
static let profile = UserProfileProxy(userID: "@alice:example.com", displayName: "Alice")
static let annotation = LocationAnnotation(id: profile.userID,
coordinate: .init(latitude: 51.509865, longitude: -0.118092),
kind: .liveUser(profile))
static var previews: some View {
LocationShareSheet(annotation: annotation)
.previewDisplayName("Live location share sheet")
}
}
@@ -25,8 +25,12 @@ struct LocationSharingScreen: View {
.sheet(isPresented: .constant(true)) { .sheet(isPresented: .constant(true)) {
StaticLocationSheet(context: context) StaticLocationSheet(context: context)
.alert(item: $context.alertInfo) .alert(item: $context.alertInfo)
.popover(isPresented: $context.showShareSheet) { shareSheet } .popover(item: $context.sharedAnnotation) { annotation in
LocationShareSheet(annotation: annotation)
}
} }
case .viewLive:
mainContent
} }
} }
@@ -35,7 +39,7 @@ struct LocationSharingScreen: View {
private var mainContent: some View { private var mainContent: some View {
mapView mapView
.ignoresSafeArea(edges: .bottom) .ignoresSafeArea(edges: .bottom)
.track(screen: context.viewState.isLocationPickerMode ? .LocationSend : .LocationView) .track(screen: context.viewState.interactionMode == .picker ? .LocationSend : .LocationView)
.navigationTitle(L10n.screenViewLocationTitle) .navigationTitle(L10n.screenViewLocationTitle)
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { toolbar } .toolbar { toolbar }
@@ -45,6 +49,7 @@ struct LocationSharingScreen: View {
ZStack(alignment: .center) { ZStack(alignment: .center) {
MapLibreMapView(mapURLBuilder: context.viewState.mapURLBuilder, MapLibreMapView(mapURLBuilder: context.viewState.mapURLBuilder,
options: mapOptions, options: mapOptions,
mediaProvider: context.mediaProvider,
showsUserLocationMode: $context.showsUserLocationMode, showsUserLocationMode: $context.showsUserLocationMode,
error: $context.mapError, error: $context.mapError,
mapCenterCoordinate: $context.mapCenterLocation, mapCenterCoordinate: $context.mapCenterLocation,
@@ -53,10 +58,10 @@ struct LocationSharingScreen: View {
geolocationUncertainty: $context.geolocationUncertainty) { geolocationUncertainty: $context.geolocationUncertainty) {
context.send(viewAction: .userDidPan) context.send(viewAction: .userDidPan)
} }
.ignoresSafeArea(.all, edges: mapSafeAreaEdges) .ignoresSafeArea(edges: mapSafeAreaEdges)
if context.viewState.isLocationPickerMode { if let pickerMarkerKind = context.viewState.pickerMarkerKind {
LocationMarkerView(kind: context.viewState.locationMarkerKind, mediaProvider: context.mediaProvider) LocationMarkerView(kind: pickerMarkerKind, mediaProvider: context.mediaProvider)
} }
} }
.overlay(alignment: .topTrailing) { .overlay(alignment: .topTrailing) {
@@ -64,6 +69,10 @@ struct LocationSharingScreen: View {
} }
} }
private var mapSafeAreaEdges: Edge.Set {
context.viewState.interactionMode == .picker ? .horizontal : [.horizontal, .bottom]
}
@ToolbarContentBuilder @ToolbarContentBuilder
private var toolbar: some ToolbarContent { private var toolbar: some ToolbarContent {
ToolbarItem(placement: .primaryAction) { ToolbarItem(placement: .primaryAction) {
@@ -74,25 +83,10 @@ struct LocationSharingScreen: View {
} }
private var mapOptions: MapLibreMapView.Options { private var mapOptions: MapLibreMapView.Options {
var annotations: [String: LocationAnnotation] = [:] .init(zoomLevel: context.viewState.zoomLevel,
if !context.viewState.isLocationPickerMode { initialZoomLevel: context.viewState.initialZoomLevel,
let kind = context.viewState.locationMarkerKind mapCenter: context.viewState.initialMapCenter,
let annotation = LocationAnnotation(id: kind.id, annotations: context.viewState.annotations)
coordinate: context.viewState.initialMapCenter,
anchorPoint: .bottomCenter) {
LocationMarkerView(kind: kind, mediaProvider: context.mediaProvider)
}
annotations[kind.id] = annotation
}
return .init(zoomLevel: context.viewState.zoomLevel,
initialZoomLevel: context.viewState.initialZoomLevel,
mapCenter: context.viewState.initialMapCenter,
annotations: annotations)
}
private var mapSafeAreaEdges: Edge.Set {
context.viewState.isLocationPickerMode ? .horizontal : [.horizontal, .bottom]
} }
@ViewBuilder @ViewBuilder
@@ -125,26 +119,6 @@ struct LocationSharingScreen: View {
.dynamicTypeSize(.large) .dynamicTypeSize(.large)
.padding(13) .padding(13)
} }
@ViewBuilder
private var shareSheet: some View {
let location = context.viewState.initialMapCenter
let senderName = context.viewState.locationMarkerKind.displayName ?? context.viewState.locationMarkerKind.userProfile?.userID
AppActivityView(activityItems: [ShareToMapsAppActivity.MapsAppType.apple.activityURL(for: location, senderName: senderName)],
applicationActivities: ShareToMapsAppActivity.MapsAppType.allCases.map { ShareToMapsAppActivity(type: $0, location: location, senderName: senderName) })
.ignoresSafeArea(edges: .bottom)
.presentationDetents([.medium, .large])
.presentationCompactAdaptation(shareSheetCompactPresentation)
.presentationDragIndicator(.hidden)
}
private var shareSheetCompactPresentation: PresentationAdaptation {
if #available(iOS 26.0, *) {
.none // ShareLinks use a popover presentation on iOS 26, let it match that.
} else {
.sheet
}
}
} }
// MARK: - Previews // MARK: - Previews
@@ -180,7 +154,3 @@ struct LocationSharingScreen_Previews: PreviewProvider, TestablePreview {
.previewDisplayName("Pin Static Location") .previewDisplayName("Pin Static Location")
} }
} }
private extension CGPoint {
static let bottomCenter: Self = .init(x: 0.5, y: 1)
}
@@ -34,12 +34,13 @@ struct StaticLocationSheet: View {
.font(.compound.bodyLGSemibold) .font(.compound.bodyLGSemibold)
.padding(.bottom, 25) .padding(.bottom, 25)
.padding(.top, 29) .padding(.top, 29)
if case let .viewStatic(location) = context.viewState.interactionMode { if case let .viewStatic(location) = context.viewState.interactionMode,
let profile = context.viewState.userProfiles.values.first {
Button { Button {
context.showShareSheet = true context.sharedAnnotation = context.viewState.annotations.first
} label: { } label: {
UserLocationCell(profile: context.viewState.userProfile, UserLocationCell(profile: profile,
isOwnUser: context.viewState.isOwnUser, isOwnUser: context.viewState.isOwnUser(profile.userID),
isUserLocation: location.kind == .sender, isUserLocation: location.kind == .sender,
timestamp: location.timestamp, timestamp: location.timestamp,
mediaProvider: context.mediaProvider) mediaProvider: context.mediaProvider)
@@ -72,7 +72,7 @@ class MediaEventsTimelineScreenViewModel: MediaEventsTimelineScreenViewModelType
case .displayMediaDetails(item: let item): case .displayMediaDetails(item: let item):
displayMediaPreviewSheet(for: item) displayMediaPreviewSheet(for: item)
case .displayEmojiPicker, .displayReportContent, .displayCameraPicker, .displayMediaPicker, case .displayEmojiPicker, .displayReportContent, .displayCameraPicker, .displayMediaPicker,
.displayDocumentPicker, .displayLocationPicker, .displayPollForm, .displayMediaUploadPreviewScreen, .displayDocumentPicker, .displayLocationPicker, .displayLiveLocation, .displayPollForm, .displayMediaUploadPreviewScreen,
.displaySenderDetails, .displayMessageForwarding, .displayLocation, .displayResolveSendFailure, .displaySenderDetails, .displayMessageForwarding, .displayLocation, .displayResolveSendFailure,
.displayThread, .composer, .hasScrolled, .viewInRoomTimeline, .displayRoom: .displayThread, .composer, .hasScrolled, .viewInRoomTimeline, .displayRoom:
break break
@@ -97,7 +97,7 @@ class MediaEventsTimelineScreenViewModel: MediaEventsTimelineScreenViewModelType
case .displayMediaDetails(item: let item): case .displayMediaDetails(item: let item):
displayMediaPreviewSheet(for: item) displayMediaPreviewSheet(for: item)
case .displayEmojiPicker, .displayReportContent, .displayCameraPicker, .displayMediaPicker, case .displayEmojiPicker, .displayReportContent, .displayCameraPicker, .displayMediaPicker,
.displayDocumentPicker, .displayLocationPicker, .displayPollForm, .displayMediaUploadPreviewScreen, .displayDocumentPicker, .displayLocationPicker, .displayLiveLocation, .displayPollForm, .displayMediaUploadPreviewScreen,
.displaySenderDetails, .displayMessageForwarding, .displayLocation, .displayResolveSendFailure, .displaySenderDetails, .displayMessageForwarding, .displayLocation, .displayResolveSendFailure,
.displayThread, .composer, .hasScrolled, .viewInRoomTimeline, .displayRoom: .displayThread, .composer, .hasScrolled, .viewInRoomTimeline, .displayRoom:
break break
@@ -27,6 +27,7 @@ enum PinnedEventsTimelineScreenCoordinatorAction {
case dismiss case dismiss
case displayUser(userID: String) case displayUser(userID: String)
case presentLocationViewer(StaticLocationData) case presentLocationViewer(StaticLocationData)
case presentLiveLocationViewer(sender: TimelineItemSender, initialLiveLocationShare: LiveLocationShare)
case displayMessageForwarding(forwardingItem: MessageForwardingItem) case displayMessageForwarding(forwardingItem: MessageForwardingItem)
case displayRoomScreenWithFocussedPin(eventID: String, threadRootEventID: String?) case displayRoomScreenWithFocussedPin(eventID: String, threadRootEventID: String?)
} }
@@ -89,6 +90,8 @@ final class PinnedEventsTimelineScreenCoordinator: CoordinatorProtocol {
viewModel.displayMediaPreview(mediaPreviewViewModel) viewModel.displayMediaPreview(mediaPreviewViewModel)
case .displayLocation(let location): case .displayLocation(let location):
actionsSubject.send(.presentLocationViewer(location)) actionsSubject.send(.presentLocationViewer(location))
case .displayLiveLocation(let sender, let initialLiveLocationShare):
actionsSubject.send(.presentLiveLocationViewer(sender: sender, initialLiveLocationShare: initialLiveLocationShare))
case .viewInRoomTimeline(let eventID, let threadRootEventID): case .viewInRoomTimeline(let eventID, let threadRootEventID):
actionsSubject.send(.displayRoomScreenWithFocussedPin(eventID: eventID, threadRootEventID: threadRootEventID)) actionsSubject.send(.displayRoomScreenWithFocussedPin(eventID: eventID, threadRootEventID: threadRootEventID))
// These other actions will not be handled in this view // These other actions will not be handled in this view
@@ -40,6 +40,7 @@ enum RoomScreenCoordinatorAction {
case presentLocationPicker case presentLocationPicker
case presentPollForm(mode: PollFormMode) case presentPollForm(mode: PollFormMode)
case presentLocationViewer(StaticLocationData) case presentLocationViewer(StaticLocationData)
case presentLiveLocationViewer(sender: TimelineItemSender, initialLiveLocationShare: LiveLocationShare)
case presentEmojiPicker(itemID: TimelineItemIdentifier, selectedEmojis: Set<String>) case presentEmojiPicker(itemID: TimelineItemIdentifier, selectedEmojis: Set<String>)
case presentRoomMemberDetails(userID: String) case presentRoomMemberDetails(userID: String)
case presentMessageForwarding(forwardingItem: MessageForwardingItem) case presentMessageForwarding(forwardingItem: MessageForwardingItem)
@@ -140,6 +141,8 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
actionsSubject.send(.presentMessageForwarding(forwardingItem: forwardingItem)) actionsSubject.send(.presentMessageForwarding(forwardingItem: forwardingItem))
case .displayLocation(let location): case .displayLocation(let location):
actionsSubject.send(.presentLocationViewer(location)) actionsSubject.send(.presentLocationViewer(location))
case .displayLiveLocation(let sender, let initialLiveLocationShare):
actionsSubject.send(.presentLiveLocationViewer(sender: sender, initialLiveLocationShare: initialLiveLocationShare))
case .displayResolveSendFailure(let failure, let sendHandle): case .displayResolveSendFailure(let failure, let sendHandle):
actionsSubject.send(.presentResolveSendFailure(failure: failure, sendHandle: sendHandle)) actionsSubject.send(.presentResolveSendFailure(failure: failure, sendHandle: sendHandle))
case .displayThread(let itemID): case .displayThread(let itemID):
@@ -34,6 +34,7 @@ enum ThreadTimelineScreenCoordinatorAction {
case presentMediaUploadPreviewScreen(mediaURLs: [URL]) case presentMediaUploadPreviewScreen(mediaURLs: [URL])
case presentLocationPicker case presentLocationPicker
case presentLocationViewer(StaticLocationData) case presentLocationViewer(StaticLocationData)
case presentLiveLocationViewer(sender: TimelineItemSender, initialLiveLocationShare: LiveLocationShare)
case presentPollForm(mode: PollFormMode) case presentPollForm(mode: PollFormMode)
case presentEmojiPicker(itemID: TimelineItemIdentifier, selectedEmojis: Set<String>) case presentEmojiPicker(itemID: TimelineItemIdentifier, selectedEmojis: Set<String>)
case presentRoomMemberDetails(userID: String) case presentRoomMemberDetails(userID: String)
@@ -120,6 +121,8 @@ final class ThreadTimelineScreenCoordinator: CoordinatorProtocol {
actionsSubject.send(.presentLocationPicker) actionsSubject.send(.presentLocationPicker)
case .displayLocation(let location): case .displayLocation(let location):
actionsSubject.send(.presentLocationViewer(location)) actionsSubject.send(.presentLocationViewer(location))
case .displayLiveLocation(let sender, let initialLiveLocationShare):
actionsSubject.send(.presentLiveLocationViewer(sender: sender, initialLiveLocationShare: initialLiveLocationShare))
case .displayPollForm(let mode): case .displayPollForm(let mode):
actionsSubject.send(.presentPollForm(mode: mode)) actionsSubject.send(.presentPollForm(mode: mode))
case .displayMediaUploadPreviewScreen(let mediaURLs): case .displayMediaUploadPreviewScreen(let mediaURLs):
@@ -529,7 +529,7 @@ class TimelineInteractionHandler {
} }
func processItemTap(_ itemID: TimelineItemIdentifier) async -> TimelineControllerAction { func processItemTap(_ itemID: TimelineItemIdentifier) async -> TimelineControllerAction {
guard let timelineItem = timelineController.timelineItems.firstUsingStableID(itemID) as? EventBasedMessageTimelineItemProtocol else { guard let timelineItem = timelineController.timelineItems.firstUsingStableID(itemID) as? EventBasedTimelineItemProtocol else {
return .none return .none
} }
@@ -540,12 +540,21 @@ class TimelineInteractionHandler {
geoURI: geoURI, geoURI: geoURI,
kind: item.content.kind, kind: item.content.kind,
timestamp: item.timestamp)) timestamp: item.timestamp))
case is ImageRoomTimelineItem, case let item as LiveLocationRoomTimelineItem:
is VideoRoomTimelineItem: guard let geoURI = item.content.lastGeoURI else { return .none }
return await mediaPreviewAction(for: timelineItem, messageTypes: [.image, .video]) let initialLiveLocationShare = LiveLocationShare(userID: item.sender.id,
case is AudioRoomTimelineItem, geoURI: geoURI,
is FileRoomTimelineItem: timestamp: item.timestamp,
return await mediaPreviewAction(for: timelineItem, messageTypes: [.audio, .file]) timeoutDate: item.content.timeoutDate)
return .displayLiveLocation(sender: item.sender, initialLiveLocationShare: initialLiveLocationShare)
case let item as ImageRoomTimelineItem:
return await mediaPreviewAction(for: item, messageTypes: [.image, .video])
case let item as VideoRoomTimelineItem:
return await mediaPreviewAction(for: item, messageTypes: [.image, .video])
case let item as AudioRoomTimelineItem:
return await mediaPreviewAction(for: item, messageTypes: [.audio, .file])
case let item as FileRoomTimelineItem:
return await mediaPreviewAction(for: item, messageTypes: [.audio, .file])
default: default:
return .none return .none
} }
@@ -24,6 +24,7 @@ enum TimelineViewModelAction {
case displayMessageForwarding(forwardingItem: MessageForwardingItem) case displayMessageForwarding(forwardingItem: MessageForwardingItem)
case displayMediaPreview(TimelineMediaPreviewViewModel) case displayMediaPreview(TimelineMediaPreviewViewModel)
case displayLocation(StaticLocationData) case displayLocation(StaticLocationData)
case displayLiveLocation(sender: TimelineItemSender, initialLiveLocationShare: LiveLocationShare)
case displayResolveSendFailure(failure: TimelineItemSendFailure.VerifiedUser, sendHandle: SendHandleProxy) case displayResolveSendFailure(failure: TimelineItemSendFailure.VerifiedUser, sendHandle: SendHandleProxy)
case displayThread(itemID: TimelineItemIdentifier) case displayThread(itemID: TimelineItemIdentifier)
case composer(action: TimelineComposerAction) case composer(action: TimelineComposerAction)
@@ -666,6 +666,8 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
actionsSubject.send(.displayMediaPreview(mediaPreviewViewModel)) actionsSubject.send(.displayMediaPreview(mediaPreviewViewModel))
case .displayLocation(let location): case .displayLocation(let location):
actionsSubject.send(.displayLocation(location)) actionsSubject.send(.displayLocation(location))
case .displayLiveLocation(let sender, let initialLiveLocationShare):
actionsSubject.send(.displayLiveLocation(sender: sender, initialLiveLocationShare: initialLiveLocationShare))
case .none: case .none:
break break
} }
@@ -26,6 +26,7 @@ enum TimelineControllerAction {
case displayMediaPreview(item: EventBasedMessageTimelineItemProtocol, timelineViewModel: TimelineViewModelKind) case displayMediaPreview(item: EventBasedMessageTimelineItemProtocol, timelineViewModel: TimelineViewModelKind)
case displayLocation(StaticLocationData) case displayLocation(StaticLocationData)
case displayLiveLocation(sender: TimelineItemSender, initialLiveLocationShare: LiveLocationShare)
case none case none
} }
@@ -257,6 +257,72 @@ final class LocationSharingScreenViewModelTests {
try await deferredFailure.fulfill() try await deferredFailure.fulfill()
} }
// MARK: - Live Location Share Update Tests
@Test
func viewLiveInitialSenderShownCorrectly() {
let aliceShare = makeLiveLocationShare(userID: "@alice:matrix.org", latitude: 51.5, longitude: -0.1)
let sender = TimelineItemSender(id: "@alice:matrix.org", displayName: "Alice")
let liveLocationsSubject = CurrentValueSubject<[LiveLocationShare], Never>([aliceShare])
setupViewModelForViewLive(sender: sender, initialShare: aliceShare, liveLocationsSubject: liveLocationsSubject)
// Initial state is synchronously set from the interaction mode before the async subscription runs.
let annotations = context.viewState.annotations
#expect(annotations.count == 1)
let annotation = annotations.first
#expect(annotation?.id == "@alice:matrix.org")
#expect(annotation?.coordinate.latitude == 51.5)
#expect(annotation?.coordinate.longitude == -0.1)
#expect(annotation?.kind == .liveUser(.init(userID: "@alice:matrix.org", displayName: "Alice")))
}
@Test
func viewLiveReceivesAdditionalLocationUpdates() async throws {
let aliceShare = makeLiveLocationShare(userID: "@alice:matrix.org", latitude: 51.5, longitude: -0.1)
let sender = TimelineItemSender(id: "@alice:matrix.org", displayName: "Alice")
let liveLocationsSubject = CurrentValueSubject<[LiveLocationShare], Never>([aliceShare])
setupViewModelForViewLive(sender: sender, initialShare: aliceShare, liveLocationsSubject: liveLocationsSubject)
let bobShare = makeLiveLocationShare(userID: "@bob:matrix.org", latitude: 48.8, longitude: 2.3)
let charlieShare = makeLiveLocationShare(userID: "@charlie:matrix.org", latitude: 40.7, longitude: -74.0)
let deferred = deferFulfillment(context.observe(\.viewState.annotations)) { $0.count == 3 }
liveLocationsSubject.send([aliceShare, bobShare, charlieShare])
try await deferred.fulfill()
let annotations = context.viewState.annotations
#expect(annotations.count == 3)
let annotationIDs = Set(annotations.map(\.id))
#expect(annotationIDs == ["@alice:matrix.org", "@bob:matrix.org", "@charlie:matrix.org"])
#expect(annotations.first { $0.id == "@alice:matrix.org" }?.coordinate.latitude == 51.5)
#expect(annotations.first { $0.id == "@bob:matrix.org" }?.coordinate.latitude == 48.8)
#expect(annotations.first { $0.id == "@charlie:matrix.org" }?.coordinate.latitude == 40.7)
}
@Test
func viewLiveProfilesResolvedFromRoomMembers() async throws {
let aliceShare = makeLiveLocationShare(userID: "@alice:matrix.org", latitude: 51.5, longitude: -0.1)
let sender = TimelineItemSender(id: "@alice:matrix.org", displayName: "Alice")
let liveLocationsSubject = CurrentValueSubject<[LiveLocationShare], Never>([aliceShare])
setupViewModelForViewLive(sender: sender, initialShare: aliceShare, liveLocationsSubject: liveLocationsSubject)
let bobShare = makeLiveLocationShare(userID: "@bob:matrix.org", latitude: 48.8, longitude: 2.3)
let charlieShare = makeLiveLocationShare(userID: "@charlie:matrix.org", latitude: 40.7, longitude: -74.0)
let deferred = deferFulfillment(context.observe(\.viewState.annotations)) { $0.count == 3 }
liveLocationsSubject.send([aliceShare, bobShare, charlieShare])
try await deferred.fulfill()
// Annotation marker kinds should carry profiles resolved from room members.
let annotations = context.viewState.annotations
#expect(annotations.first { $0.id == "@alice:matrix.org" }?.kind == .liveUser(.init(userID: "@alice:matrix.org", displayName: "Alice")))
#expect(annotations.first { $0.id == "@bob:matrix.org" }?.kind == .liveUser(.init(userID: "@bob:matrix.org", displayName: "Bob")))
#expect(annotations.first { $0.id == "@charlie:matrix.org" }?.kind == .liveUser(.init(userID: "@charlie:matrix.org", displayName: "Charlie")))
}
// MARK: - Private // MARK: - Private
private func setupViewModel(liveLocationManagerConfiguration: LiveLocationManagerMock.Configuration = .init()) { private func setupViewModel(liveLocationManagerConfiguration: LiveLocationManagerMock.Configuration = .init()) {
@@ -286,4 +352,32 @@ final class LocationSharingScreenViewModelTests {
mediaProvider: MediaProviderMock(configuration: .init())) mediaProvider: MediaProviderMock(configuration: .init()))
viewModel.state.bindings.isLocationAuthorized = true viewModel.state.bindings.isLocationAuthorized = true
} }
private func setupViewModelForViewLive(sender: TimelineItemSender,
initialShare: LiveLocationShare,
liveLocationsSubject: CurrentValueSubject<[LiveLocationShare], Never>,
members: [RoomMemberProxyMock] = .allMembers) {
let liveLocationServiceMock = RoomLiveLocationServiceMock()
liveLocationServiceMock.liveLocationsPublisher = liveLocationsSubject.eraseToAnyPublisher()
let roomProxyMock = JoinedRoomProxyMock(.init(members: members))
roomProxyMock.makeLiveLocationServiceReturnValue = liveLocationServiceMock
viewModel = LocationSharingScreenViewModel(interactionMode: .viewLive(sender: sender, initialLiveLocationShare: initialShare),
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
liveLocationSharingEnabled: true,
roomProxy: roomProxyMock,
timelineController: MockTimelineController(timelineProxy: TimelineProxyMock(.init())),
liveLocationManager: LiveLocationManagerMock(.init()),
analytics: ServiceLocator.shared.analytics,
userIndicatorController: UserIndicatorControllerMock(),
mediaProvider: MediaProviderMock(configuration: .init()))
}
private func makeLiveLocationShare(userID: String, latitude: Double = 0.0, longitude: Double = 0.0) -> LiveLocationShare {
LiveLocationShare(userID: userID,
geoURI: .init(latitude: latitude, longitude: longitude),
timestamp: .distantPast,
timeoutDate: .distantFuture)
}
} }