mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Refactor and redesign Location Sharing Screen (#5155)
* refactored the static location screen to the location sharing screen # Conflicts: # UnitTests/Sources/LocationSharingScreenViewModelTests.swift # Conflicts: # ElementX.xcodeproj/project.pbxproj * implemented a custom pin with an overlayable view * implemented the render of the user when the location is sender instead of the pin type * removed description and body they are not used at all. * reimplemented single button for sharing this or user location + implemented an experimental way to update annotations * removed unnecessary @Suite description * implemented a way to display the alert on top of the sheet and added a spinner to the center user location button * fixed alerts strings * fixed a failing test * improved preview tests
This commit is contained in:
@@ -303,6 +303,10 @@ extension AccessibilityTests {
|
|||||||
try await performAccessibilityAudit(named: "LocationRoomTimelineView_Previews")
|
try await performAccessibilityAudit(named: "LocationRoomTimelineView_Previews")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testLocationSharingScreen() async throws {
|
||||||
|
try await performAccessibilityAudit(named: "LocationSharingScreen_Previews")
|
||||||
|
}
|
||||||
|
|
||||||
func testLoginScreen() async throws {
|
func testLoginScreen() async throws {
|
||||||
try await performAccessibilityAudit(named: "LoginScreen_Previews")
|
try await performAccessibilityAudit(named: "LoginScreen_Previews")
|
||||||
}
|
}
|
||||||
@@ -695,10 +699,6 @@ extension AccessibilityTests {
|
|||||||
try await performAccessibilityAudit(named: "StateRoomTimelineView_Previews")
|
try await performAccessibilityAudit(named: "StateRoomTimelineView_Previews")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStaticLocationScreenViewer() async throws {
|
|
||||||
try await performAccessibilityAudit(named: "StaticLocationScreenViewer_Previews")
|
|
||||||
}
|
|
||||||
|
|
||||||
func testStickerRoomTimelineView() async throws {
|
func testStickerRoomTimelineView() async throws {
|
||||||
try await performAccessibilityAudit(named: "StickerRoomTimelineView_Previews")
|
try await performAccessibilityAudit(named: "StickerRoomTimelineView_Previews")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@
|
|||||||
053B8BD2496207838878C6C9 /* PinnedItemsBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60C9BAE9F9436B14E4E22E8F /* PinnedItemsBannerView.swift */; };
|
053B8BD2496207838878C6C9 /* PinnedItemsBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60C9BAE9F9436B14E4E22E8F /* PinnedItemsBannerView.swift */; };
|
||||||
059173B3C77056C406906B6D /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = D4DA544B2520BFA65D6DB4BB /* target.yml */; };
|
059173B3C77056C406906B6D /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = D4DA544B2520BFA65D6DB4BB /* target.yml */; };
|
||||||
059A6BEDE9BADF3C81AC4146 /* SpaceAddRoomsScreenSelectedItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AB44FFCF7DA5300D943169 /* SpaceAddRoomsScreenSelectedItem.swift */; };
|
059A6BEDE9BADF3C81AC4146 /* SpaceAddRoomsScreenSelectedItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AB44FFCF7DA5300D943169 /* SpaceAddRoomsScreenSelectedItem.swift */; };
|
||||||
|
05B02B9508E922677F0E9451 /* LocationSharingScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 052A8C0B00FE8AD7C972F2A4 /* LocationSharingScreenViewModel.swift */; };
|
||||||
05BAB510CBC2ED35C154ADD0 /* AnalyticsPromptScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AFD012C3A9F5EF276DDD4AA /* AnalyticsPromptScreenViewModelProtocol.swift */; };
|
05BAB510CBC2ED35C154ADD0 /* AnalyticsPromptScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AFD012C3A9F5EF276DDD4AA /* AnalyticsPromptScreenViewModelProtocol.swift */; };
|
||||||
05E797C4E0048BB487E5C4D6 /* AppLockTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8495F37D6245AD0CFA1F60B /* AppLockTests.swift */; };
|
05E797C4E0048BB487E5C4D6 /* AppLockTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8495F37D6245AD0CFA1F60B /* AppLockTests.swift */; };
|
||||||
05FF0CD80EDAB3A7C0D4700A /* InfoPlistReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A580295A56B55A856CC4084 /* InfoPlistReader.swift */; };
|
05FF0CD80EDAB3A7C0D4700A /* InfoPlistReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A580295A56B55A856CC4084 /* InfoPlistReader.swift */; };
|
||||||
@@ -168,7 +169,6 @@
|
|||||||
1A3B073568D1DC8F76F1F3A0 /* UserProfileScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23EE69982BBA18C6D51AD08E /* UserProfileScreen.swift */; };
|
1A3B073568D1DC8F76F1F3A0 /* UserProfileScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23EE69982BBA18C6D51AD08E /* UserProfileScreen.swift */; };
|
||||||
1A70A2199394B5EC660934A5 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = A678E40E917620059695F067 /* MatrixRustSDK */; };
|
1A70A2199394B5EC660934A5 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = A678E40E917620059695F067 /* MatrixRustSDK */; };
|
||||||
1A83DD22F3E6F76B13B6E2F9 /* VideoRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C8616254EE40CA8BA5E9BC2 /* VideoRoomTimelineItemContent.swift */; };
|
1A83DD22F3E6F76B13B6E2F9 /* VideoRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C8616254EE40CA8BA5E9BC2 /* VideoRoomTimelineItemContent.swift */; };
|
||||||
1AB3D8563AB12635250A6A6E /* StaticLocationScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C15E0017717EAE3A1D02D005 /* StaticLocationScreenCoordinator.swift */; };
|
|
||||||
1AE4532D92E6ED42BFE87064 /* JoinRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = A566F8F2C27B99E1FB80C69B /* JoinRule.swift */; };
|
1AE4532D92E6ED42BFE87064 /* JoinRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = A566F8F2C27B99E1FB80C69B /* JoinRule.swift */; };
|
||||||
1AE4AEA0FA8DEF52671832E0 /* RoomTimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */; };
|
1AE4AEA0FA8DEF52671832E0 /* RoomTimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */; };
|
||||||
1AF4A82B4332CAD2DB3EB5DA /* TopBannerModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78483F0143E185EDC6ECD741 /* TopBannerModifier.swift */; };
|
1AF4A82B4332CAD2DB3EB5DA /* TopBannerModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78483F0143E185EDC6ECD741 /* TopBannerModifier.swift */; };
|
||||||
@@ -308,6 +308,7 @@
|
|||||||
352C439BE0F75E101EF11FB1 /* RoomScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2886615BEBAE33A0AA4D5F8 /* RoomScreenModels.swift */; };
|
352C439BE0F75E101EF11FB1 /* RoomScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2886615BEBAE33A0AA4D5F8 /* RoomScreenModels.swift */; };
|
||||||
355B11D08CE0CEF97A813236 /* AppRoutes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27A9E3FBE8A66B5A17AD7F74 /* AppRoutes.swift */; };
|
355B11D08CE0CEF97A813236 /* AppRoutes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27A9E3FBE8A66B5A17AD7F74 /* AppRoutes.swift */; };
|
||||||
3582056513A384F110EC8274 /* MediaPlayerProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D7A2C4A3A74F0D2FFE9356A /* MediaPlayerProviderTests.swift */; };
|
3582056513A384F110EC8274 /* MediaPlayerProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D7A2C4A3A74F0D2FFE9356A /* MediaPlayerProviderTests.swift */; };
|
||||||
|
358290C2E4574456FE0C2DF6 /* LocationSharingScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B73675A21580971E9ADF66A /* LocationSharingScreenViewModelProtocol.swift */; };
|
||||||
35E975CFDA60E05362A7CF79 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = 1222DB76B917EB8A55365BA5 /* target.yml */; };
|
35E975CFDA60E05362A7CF79 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = 1222DB76B917EB8A55365BA5 /* target.yml */; };
|
||||||
36206F74DDEBF9BEAF6A6A1F /* ExtensionLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41A8571A8A071FB41778C016 /* ExtensionLogger.swift */; };
|
36206F74DDEBF9BEAF6A6A1F /* ExtensionLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41A8571A8A071FB41778C016 /* ExtensionLogger.swift */; };
|
||||||
3684AD01C5FCB7616B28F629 /* TimelineMediaPreviewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDE60FEE95039CCCEEEE3B0 /* TimelineMediaPreviewController.swift */; };
|
3684AD01C5FCB7616B28F629 /* TimelineMediaPreviewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDE60FEE95039CCCEEEE3B0 /* TimelineMediaPreviewController.swift */; };
|
||||||
@@ -521,7 +522,6 @@
|
|||||||
5B6E5AD224509E6C0B520D6E /* RoomMemberDetailsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DDF49CEBC0DFC59C308335F /* RoomMemberDetailsScreenViewModelProtocol.swift */; };
|
5B6E5AD224509E6C0B520D6E /* RoomMemberDetailsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DDF49CEBC0DFC59C308335F /* RoomMemberDetailsScreenViewModelProtocol.swift */; };
|
||||||
5BC6C4ADFE7F2A795ECDE130 /* SecureBackupKeyBackupScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2D4EEBE8C098BBADD10939 /* SecureBackupKeyBackupScreenCoordinator.swift */; };
|
5BC6C4ADFE7F2A795ECDE130 /* SecureBackupKeyBackupScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2D4EEBE8C098BBADD10939 /* SecureBackupKeyBackupScreenCoordinator.swift */; };
|
||||||
5C02841B2A86327B2C377682 /* NotificationConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C830A64609CBD152F06E0457 /* NotificationConstants.swift */; };
|
5C02841B2A86327B2C377682 /* NotificationConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C830A64609CBD152F06E0457 /* NotificationConstants.swift */; };
|
||||||
5C164551F7D26E24F09083D3 /* StaticLocationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C616D90B1E2F033CAA325439 /* StaticLocationScreenViewModelProtocol.swift */; };
|
|
||||||
5C33976A720B64094CBC56B1 /* VideoMediaEventsTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B1FB56520A847DD2532D5C8 /* VideoMediaEventsTimelineView.swift */; };
|
5C33976A720B64094CBC56B1 /* VideoMediaEventsTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B1FB56520A847DD2532D5C8 /* VideoMediaEventsTimelineView.swift */; };
|
||||||
5C61810ED7B7CB48346B1B9D /* portrait_test_video.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = E5E7D4EE7CA295E5039FDA21 /* portrait_test_video.mp4 */; };
|
5C61810ED7B7CB48346B1B9D /* portrait_test_video.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = E5E7D4EE7CA295E5039FDA21 /* portrait_test_video.mp4 */; };
|
||||||
5C8804B4F25903516E2DAB81 /* RoomInfoProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40A66E8BC8D9AE4A08EFB2DF /* RoomInfoProxy.swift */; };
|
5C8804B4F25903516E2DAB81 /* RoomInfoProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40A66E8BC8D9AE4A08EFB2DF /* RoomInfoProxy.swift */; };
|
||||||
@@ -702,6 +702,7 @@
|
|||||||
7A02EB29F3B993AB20E0A198 /* RoomPollsHistoryScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C8C368A611B9CB79C7F5FA /* RoomPollsHistoryScreen.swift */; };
|
7A02EB29F3B993AB20E0A198 /* RoomPollsHistoryScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C8C368A611B9CB79C7F5FA /* RoomPollsHistoryScreen.swift */; };
|
||||||
7A0D335D38ECA095A575B4F7 /* TimelineStyler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DB0E533508094156D8024C3 /* TimelineStyler.swift */; };
|
7A0D335D38ECA095A575B4F7 /* TimelineStyler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DB0E533508094156D8024C3 /* TimelineStyler.swift */; };
|
||||||
7A25D6926A2C01DB8D0D67A5 /* BadgeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A028783CFFF861C5E44FFB1 /* BadgeLabel.swift */; };
|
7A25D6926A2C01DB8D0D67A5 /* BadgeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A028783CFFF861C5E44FFB1 /* BadgeLabel.swift */; };
|
||||||
|
7A37EC9D7164319587539E1D /* LocationSharingScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FA4F7FFF0704D1C5471BF6E /* LocationSharingScreenCoordinator.swift */; };
|
||||||
7A495A5F3E5522DD7928CF8F /* UserIdentityProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 964093C7CA8823CAB7FFD88E /* UserIdentityProxy.swift */; };
|
7A495A5F3E5522DD7928CF8F /* UserIdentityProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 964093C7CA8823CAB7FFD88E /* UserIdentityProxy.swift */; };
|
||||||
7A642EE5F1ADC5D520F21924 /* MediaProviderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85EB16E7FE59A947CA441531 /* MediaProviderProtocol.swift */; };
|
7A642EE5F1ADC5D520F21924 /* MediaProviderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85EB16E7FE59A947CA441531 /* MediaProviderProtocol.swift */; };
|
||||||
7A71AEF419904209BB8C2833 /* UserAgentBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F2529D434C750ED78ADF1ED /* UserAgentBuilder.swift */; };
|
7A71AEF419904209BB8C2833 /* UserAgentBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F2529D434C750ED78ADF1ED /* UserAgentBuilder.swift */; };
|
||||||
@@ -744,6 +745,7 @@
|
|||||||
80F6C8EFCA4564B67F0D34B0 /* DeactivateAccountScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77F75B3E9F99864048A422A /* DeactivateAccountScreenViewModelTests.swift */; };
|
80F6C8EFCA4564B67F0D34B0 /* DeactivateAccountScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77F75B3E9F99864048A422A /* DeactivateAccountScreenViewModelTests.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 */; };
|
||||||
8285FF4B2C2331758C437FF7 /* ReportContentScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 713B48DBF65DE4B0DD445D66 /* ReportContentScreenViewModelProtocol.swift */; };
|
8285FF4B2C2331758C437FF7 /* ReportContentScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 713B48DBF65DE4B0DD445D66 /* ReportContentScreenViewModelProtocol.swift */; };
|
||||||
828EA5009557C2B9DCD4CA0F /* UserDiscoverySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D071F86CD47582B9196C9D16 /* UserDiscoverySection.swift */; };
|
828EA5009557C2B9DCD4CA0F /* UserDiscoverySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D071F86CD47582B9196C9D16 /* UserDiscoverySection.swift */; };
|
||||||
832A4EA1094B8FE423A08700 /* RoomChangeRolesScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B2A421198FD20AAAED20004 /* RoomChangeRolesScreen.swift */; };
|
832A4EA1094B8FE423A08700 /* RoomChangeRolesScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B2A421198FD20AAAED20004 /* RoomChangeRolesScreen.swift */; };
|
||||||
@@ -898,7 +900,6 @@
|
|||||||
9B3589276CA008E38FAAAE91 /* SpacesScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 358528B29FA72ACFD0D9644B /* SpacesScreenCoordinator.swift */; };
|
9B3589276CA008E38FAAAE91 /* SpacesScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 358528B29FA72ACFD0D9644B /* SpacesScreenCoordinator.swift */; };
|
||||||
9B84F55288AB98783C11CC49 /* SpaceRoomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0E7B059E84E7E374D3322A2 /* SpaceRoomCell.swift */; };
|
9B84F55288AB98783C11CC49 /* SpaceRoomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0E7B059E84E7E374D3322A2 /* SpaceRoomCell.swift */; };
|
||||||
9B872FF37DBE6BE054903831 /* MediaUploadPreviewScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D54E12B98252F6C527E31FEE /* MediaUploadPreviewScreenViewModelProtocol.swift */; };
|
9B872FF37DBE6BE054903831 /* MediaUploadPreviewScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D54E12B98252F6C527E31FEE /* MediaUploadPreviewScreenViewModelProtocol.swift */; };
|
||||||
9BB91CABB10D8FE90C491BCD /* StaticLocationScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C833673B334A0651AB46F30B /* StaticLocationScreenViewModelTests.swift */; };
|
|
||||||
9C11138F7D8C291494BB0B20 /* Secrets.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3557ACB95D0F666EF5AF0CE /* Secrets.swift */; };
|
9C11138F7D8C291494BB0B20 /* Secrets.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3557ACB95D0F666EF5AF0CE /* Secrets.swift */; };
|
||||||
9C4EC28A921486B1775D7F8C /* IdentityConfirmedScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 307702DD66E7DDCDD9214784 /* IdentityConfirmedScreen.swift */; };
|
9C4EC28A921486B1775D7F8C /* IdentityConfirmedScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 307702DD66E7DDCDD9214784 /* IdentityConfirmedScreen.swift */; };
|
||||||
9C63171267E22FEB288EC860 /* RoomHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1627F2D56477BD331F6D732C /* RoomHeaderView.swift */; };
|
9C63171267E22FEB288EC860 /* RoomHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1627F2D56477BD331F6D732C /* RoomHeaderView.swift */; };
|
||||||
@@ -1017,7 +1018,6 @@
|
|||||||
AFE2AB612A1460E49578D746 /* JoinRoomScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BDCCD2F6B405C14B9BCE94E /* JoinRoomScreenCoordinator.swift */; };
|
AFE2AB612A1460E49578D746 /* JoinRoomScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BDCCD2F6B405C14B9BCE94E /* JoinRoomScreenCoordinator.swift */; };
|
||||||
B04E9EB589CE99C3929E817A /* HomeScreenRecoveryKeyConfirmationBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05512FB13987D221B7205DE0 /* HomeScreenRecoveryKeyConfirmationBanner.swift */; };
|
B04E9EB589CE99C3929E817A /* HomeScreenRecoveryKeyConfirmationBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05512FB13987D221B7205DE0 /* HomeScreenRecoveryKeyConfirmationBanner.swift */; };
|
||||||
B0CB16349B96262AA65A04AF /* GZIP in Frameworks */ = {isa = PBXBuildFile; productRef = 997C7385E1A07E061D7E2100 /* GZIP */; };
|
B0CB16349B96262AA65A04AF /* GZIP in Frameworks */ = {isa = PBXBuildFile; productRef = 997C7385E1A07E061D7E2100 /* GZIP */; };
|
||||||
B1069F361E604D5436AE9FFD /* StaticLocationScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B06663F7858E45882E63471 /* StaticLocationScreen.swift */; };
|
|
||||||
B1088417801A962BA861C13F /* RoomPowerLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7E247E29C7A0E421DB839D7 /* RoomPowerLevel.swift */; };
|
B1088417801A962BA861C13F /* RoomPowerLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7E247E29C7A0E421DB839D7 /* RoomPowerLevel.swift */; };
|
||||||
B10F7D5C237417DA160F4603 /* LongPressWithFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D9F148717D74F73BE724434 /* LongPressWithFeedback.swift */; };
|
B10F7D5C237417DA160F4603 /* LongPressWithFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D9F148717D74F73BE724434 /* LongPressWithFeedback.swift */; };
|
||||||
B13774779EA19FDD7A35A4A8 /* RoomRolesAndPermissionsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C28B70BEFD3676F11D5D51F /* RoomRolesAndPermissionsScreenCoordinator.swift */; };
|
B13774779EA19FDD7A35A4A8 /* RoomRolesAndPermissionsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C28B70BEFD3676F11D5D51F /* RoomRolesAndPermissionsScreenCoordinator.swift */; };
|
||||||
@@ -1133,6 +1133,7 @@
|
|||||||
C5A07E2D88BE7D51DCECD166 /* LoginScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D0B159AFFBBD8ECFD0E37FA /* LoginScreenModels.swift */; };
|
C5A07E2D88BE7D51DCECD166 /* LoginScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D0B159AFFBBD8ECFD0E37FA /* LoginScreenModels.swift */; };
|
||||||
C5E3A4A678B4F8900830B76A /* NavigationTabCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C39B1D3FC8CF41D6C3B054F /* NavigationTabCoordinator.swift */; };
|
C5E3A4A678B4F8900830B76A /* NavigationTabCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C39B1D3FC8CF41D6C3B054F /* NavigationTabCoordinator.swift */; };
|
||||||
C646CFE86CA46495D6BB7448 /* ManageAuthorizedSpacesScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74AE4F02A507882743973214 /* ManageAuthorizedSpacesScreenViewModelProtocol.swift */; };
|
C646CFE86CA46495D6BB7448 /* ManageAuthorizedSpacesScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74AE4F02A507882743973214 /* ManageAuthorizedSpacesScreenViewModelProtocol.swift */; };
|
||||||
|
C67156445600FAE6430DE41E /* LocationSharingScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F56E6E41C6DFE8054787D57 /* LocationSharingScreen.swift */; };
|
||||||
C67FCC854F3A6FC7A2EC04D0 /* MediaUploadPreviewScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C86696AC9521F8ED88FBEB /* MediaUploadPreviewScreen.swift */; };
|
C67FCC854F3A6FC7A2EC04D0 /* MediaUploadPreviewScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C86696AC9521F8ED88FBEB /* MediaUploadPreviewScreen.swift */; };
|
||||||
C6AC34B731F4F853E9D15146 /* AnalyticsConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA2397174D0DC3918A7A8A7B /* AnalyticsConfiguration.swift */; };
|
C6AC34B731F4F853E9D15146 /* AnalyticsConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA2397174D0DC3918A7A8A7B /* AnalyticsConfiguration.swift */; };
|
||||||
C6C06DDA8881260303FBA3A0 /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2141693488CE5446BB391964 /* Date.swift */; };
|
C6C06DDA8881260303FBA3A0 /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2141693488CE5446BB391964 /* Date.swift */; };
|
||||||
@@ -1268,7 +1269,6 @@
|
|||||||
DF40CDBEFE1D02B5F9C4ACB1 /* test_image.png in Resources */ = {isa = PBXBuildFile; fileRef = 810133CF215075C285FC6F3A /* test_image.png */; };
|
DF40CDBEFE1D02B5F9C4ACB1 /* test_image.png in Resources */ = {isa = PBXBuildFile; fileRef = 810133CF215075C285FC6F3A /* test_image.png */; };
|
||||||
DF504B10A4918F971A57BEF2 /* PostHogAnalyticsClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1715E3D7F53C0748AA50C91C /* PostHogAnalyticsClient.swift */; };
|
DF504B10A4918F971A57BEF2 /* PostHogAnalyticsClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1715E3D7F53C0748AA50C91C /* PostHogAnalyticsClient.swift */; };
|
||||||
DF8F1211F2B0B56F0FCCA5C2 /* CertificateValidatorHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3865AD7B7249C939D7C69C33 /* CertificateValidatorHook.swift */; };
|
DF8F1211F2B0B56F0FCCA5C2 /* CertificateValidatorHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3865AD7B7249C939D7C69C33 /* CertificateValidatorHook.swift */; };
|
||||||
DFD5AA8688A34C72D48AF3B1 /* StaticLocationScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5311C989EC15B4C2D699025 /* StaticLocationScreenViewModel.swift */; };
|
|
||||||
DFF7D6A6C26DDD40D00AE579 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = F012CB5EE3F2B67359F6CC52 /* target.yml */; };
|
DFF7D6A6C26DDD40D00AE579 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = F012CB5EE3F2B67359F6CC52 /* target.yml */; };
|
||||||
E010DDE938032D3B8E84CC35 /* TracingHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A95C9B8299A36A6495DECA6 /* TracingHook.swift */; };
|
E010DDE938032D3B8E84CC35 /* TracingHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A95C9B8299A36A6495DECA6 /* TracingHook.swift */; };
|
||||||
E02DAD9FD8D62587049FFFEC /* LinkNewDeviceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80F04B12FA231E797B7151A8 /* LinkNewDeviceTests.swift */; };
|
E02DAD9FD8D62587049FFFEC /* LinkNewDeviceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80F04B12FA231E797B7151A8 /* LinkNewDeviceTests.swift */; };
|
||||||
@@ -1411,6 +1411,7 @@
|
|||||||
F66BCCC825D6CA51724A94D0 /* MediaPlayerProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A1F98AE670377B20679FF5 /* MediaPlayerProvider.swift */; };
|
F66BCCC825D6CA51724A94D0 /* MediaPlayerProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A1F98AE670377B20679FF5 /* MediaPlayerProvider.swift */; };
|
||||||
F6767F17D538578B370DD805 /* TimelineItemBubbleBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE739A6836E86E3780748477 /* TimelineItemBubbleBackground.swift */; };
|
F6767F17D538578B370DD805 /* TimelineItemBubbleBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE739A6836E86E3780748477 /* TimelineItemBubbleBackground.swift */; };
|
||||||
F6BF52CB027393EE03CEC523 /* TimelineMediaPreviewViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1F000589F2CEE6B03ECFAB /* TimelineMediaPreviewViewModelTests.swift */; };
|
F6BF52CB027393EE03CEC523 /* TimelineMediaPreviewViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1F000589F2CEE6B03ECFAB /* TimelineMediaPreviewViewModelTests.swift */; };
|
||||||
|
F6D07D834279BE17D18A33E9 /* LocationSharingScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EED6D8956E554CEDFD4FE00D /* LocationSharingScreenViewModelTests.swift */; };
|
||||||
F6DFA23885980118AD7359C5 /* NotificationSettingsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2389732B0E115A999A069083 /* NotificationSettingsScreenCoordinator.swift */; };
|
F6DFA23885980118AD7359C5 /* NotificationSettingsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2389732B0E115A999A069083 /* NotificationSettingsScreenCoordinator.swift */; };
|
||||||
F6F49E37272AD7397CD29A01 /* HomeScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505208F28007C0FEC14E1FF0 /* HomeScreenViewModelTests.swift */; };
|
F6F49E37272AD7397CD29A01 /* HomeScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505208F28007C0FEC14E1FF0 /* HomeScreenViewModelTests.swift */; };
|
||||||
F71C2B24AFB566119ACCDDA1 /* Secrets.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3557ACB95D0F666EF5AF0CE /* Secrets.swift */; };
|
F71C2B24AFB566119ACCDDA1 /* Secrets.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3557ACB95D0F666EF5AF0CE /* Secrets.swift */; };
|
||||||
@@ -1583,6 +1584,7 @@
|
|||||||
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>"; };
|
||||||
0516C69708D5CBDE1A8E77EC /* RoomDirectorySearchProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDirectorySearchProxyProtocol.swift; sourceTree = "<group>"; };
|
0516C69708D5CBDE1A8E77EC /* RoomDirectorySearchProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDirectorySearchProxyProtocol.swift; sourceTree = "<group>"; };
|
||||||
|
052A8C0B00FE8AD7C972F2A4 /* LocationSharingScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationSharingScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
052B2F924572AFD70B5F500E /* StartChatScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatScreenViewModel.swift; sourceTree = "<group>"; };
|
052B2F924572AFD70B5F500E /* StartChatScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
0545AC444BEEA89FF8C509FD /* zh-Hant-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant-TW"; path = "zh-Hant-TW.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
0545AC444BEEA89FF8C509FD /* zh-Hant-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant-TW"; path = "zh-Hant-TW.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||||
05512FB13987D221B7205DE0 /* HomeScreenRecoveryKeyConfirmationBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRecoveryKeyConfirmationBanner.swift; sourceTree = "<group>"; };
|
05512FB13987D221B7205DE0 /* HomeScreenRecoveryKeyConfirmationBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRecoveryKeyConfirmationBanner.swift; sourceTree = "<group>"; };
|
||||||
@@ -1975,10 +1977,11 @@
|
|||||||
4A2B5274C1D3D2999D643786 /* EncryptionResetPasswordScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionResetPasswordScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
4A2B5274C1D3D2999D643786 /* EncryptionResetPasswordScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionResetPasswordScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
4A5B4CD611DE7E94F5BA87B2 /* AppLockTimerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockTimerTests.swift; sourceTree = "<group>"; };
|
4A5B4CD611DE7E94F5BA87B2 /* AppLockTimerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockTimerTests.swift; sourceTree = "<group>"; };
|
||||||
4AB29A2D95D3469B5F016655 /* SecureBackupControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupControllerMock.swift; sourceTree = "<group>"; };
|
4AB29A2D95D3469B5F016655 /* SecureBackupControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupControllerMock.swift; sourceTree = "<group>"; };
|
||||||
4B1F71AC585827E6C416C15A /* AppIcon.icon */ = {isa = PBXFileReference; lastKnownFileType = wrapper.icon; path = AppIcon.icon; sourceTree = "<group>"; };
|
4B1F71AC585827E6C416C15A /* AppIcon.icon */ = {isa = PBXFileReference; path = AppIcon.icon; sourceTree = "<group>"; };
|
||||||
4B2B564CA6570E1487A7C7CC /* SpaceRoomListProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceRoomListProxy.swift; sourceTree = "<group>"; };
|
4B2B564CA6570E1487A7C7CC /* SpaceRoomListProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceRoomListProxy.swift; sourceTree = "<group>"; };
|
||||||
4B2D4EEBE8C098BBADD10939 /* SecureBackupKeyBackupScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupKeyBackupScreenCoordinator.swift; sourceTree = "<group>"; };
|
4B2D4EEBE8C098BBADD10939 /* SecureBackupKeyBackupScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupKeyBackupScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
4B41FABA2B0AEF4389986495 /* LoginMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginMode.swift; sourceTree = "<group>"; };
|
4B41FABA2B0AEF4389986495 /* LoginMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginMode.swift; sourceTree = "<group>"; };
|
||||||
|
4B73675A21580971E9ADF66A /* LocationSharingScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationSharingScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
4BD371B60E07A5324B9507EF /* AnalyticsSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenCoordinator.swift; sourceTree = "<group>"; };
|
4BD371B60E07A5324B9507EF /* AnalyticsSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
4C8D988E82A8DFA13BE46F7C /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = pl; path = pl.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
4C8D988E82A8DFA13BE46F7C /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = pl; path = pl.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
4CD6AC7546E8D7E5C73CEA48 /* ElementX.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = ElementX.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
4CD6AC7546E8D7E5C73CEA48 /* ElementX.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = ElementX.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
@@ -1993,6 +1996,7 @@
|
|||||||
4F5F0662483ED69791D63B16 /* et */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = et; path = et.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
4F5F0662483ED69791D63B16 /* et */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = et; path = et.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
4F75EF13F49DD2204E760910 /* FileRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileRoomTimelineView.swift; sourceTree = "<group>"; };
|
4F75EF13F49DD2204E760910 /* FileRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||||
4FA29BAE9B0F2D90E57B261C /* UserSessionFlowCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionFlowCoordinatorTests.swift; sourceTree = "<group>"; };
|
4FA29BAE9B0F2D90E57B261C /* UserSessionFlowCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionFlowCoordinatorTests.swift; sourceTree = "<group>"; };
|
||||||
|
4FA4F7FFF0704D1C5471BF6E /* LocationSharingScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationSharingScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
4FCB2126C091EEF2454B4D56 /* RoomFlowCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomFlowCoordinatorTests.swift; sourceTree = "<group>"; };
|
4FCB2126C091EEF2454B4D56 /* RoomFlowCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomFlowCoordinatorTests.swift; sourceTree = "<group>"; };
|
||||||
4FDD775CFD72DD2D3C8A8390 /* NotificationSettingsProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsProxyProtocol.swift; sourceTree = "<group>"; };
|
4FDD775CFD72DD2D3C8A8390 /* NotificationSettingsProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsProxyProtocol.swift; sourceTree = "<group>"; };
|
||||||
502F986D57158674172C58E3 /* AppLockSetupSettingsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupSettingsScreenModels.swift; sourceTree = "<group>"; };
|
502F986D57158674172C58E3 /* AppLockSetupSettingsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupSettingsScreenModels.swift; sourceTree = "<group>"; };
|
||||||
@@ -2144,6 +2148,7 @@
|
|||||||
6F054DE7D47849687662C9D9 /* BootDetectionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BootDetectionManager.swift; sourceTree = "<group>"; };
|
6F054DE7D47849687662C9D9 /* BootDetectionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BootDetectionManager.swift; sourceTree = "<group>"; };
|
||||||
6F1C3CBBC62C566DDF5E84C1 /* TimelineItemMenuAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemMenuAction.swift; sourceTree = "<group>"; };
|
6F1C3CBBC62C566DDF5E84C1 /* TimelineItemMenuAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemMenuAction.swift; sourceTree = "<group>"; };
|
||||||
6F3DFE5B444F131648066F05 /* StateStoreViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateStoreViewModel.swift; sourceTree = "<group>"; };
|
6F3DFE5B444F131648066F05 /* StateStoreViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateStoreViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
6F56E6E41C6DFE8054787D57 /* LocationSharingScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationSharingScreen.swift; sourceTree = "<group>"; };
|
||||||
6F65E4BB9E82EB8373207CF8 /* MediaProviderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProviderMock.swift; sourceTree = "<group>"; };
|
6F65E4BB9E82EB8373207CF8 /* MediaProviderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProviderMock.swift; sourceTree = "<group>"; };
|
||||||
6F6E6EDC4BBF962B2ED595A4 /* MessageForwardingScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageForwardingScreenViewModelTests.swift; sourceTree = "<group>"; };
|
6F6E6EDC4BBF962B2ED595A4 /* MessageForwardingScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageForwardingScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
6FA38E813BE14149F173F461 /* PinnedEventsBannerStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedEventsBannerStateTests.swift; sourceTree = "<group>"; };
|
6FA38E813BE14149F173F461 /* PinnedEventsBannerStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedEventsBannerStateTests.swift; sourceTree = "<group>"; };
|
||||||
@@ -2392,7 +2397,6 @@
|
|||||||
9A34D9BCA1A7D9A56E1EAF1D /* ManageRoomMemberSheetViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageRoomMemberSheetViewModel.swift; sourceTree = "<group>"; };
|
9A34D9BCA1A7D9A56E1EAF1D /* ManageRoomMemberSheetViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageRoomMemberSheetViewModel.swift; sourceTree = "<group>"; };
|
||||||
9A68BCE6438873D2661D93D0 /* BugReportServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportServiceProtocol.swift; sourceTree = "<group>"; };
|
9A68BCE6438873D2661D93D0 /* BugReportServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportServiceProtocol.swift; sourceTree = "<group>"; };
|
||||||
9AA3AF94A06D319BB37E52DA /* TimelineItemFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemFactoryTests.swift; sourceTree = "<group>"; };
|
9AA3AF94A06D319BB37E52DA /* TimelineItemFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemFactoryTests.swift; sourceTree = "<group>"; };
|
||||||
9B06663F7858E45882E63471 /* StaticLocationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticLocationScreen.swift; sourceTree = "<group>"; };
|
|
||||||
9B6572E6EF5D5F4B0C338A40 /* PinnedEventsTimelineScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedEventsTimelineScreenModels.swift; sourceTree = "<group>"; };
|
9B6572E6EF5D5F4B0C338A40 /* PinnedEventsTimelineScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedEventsTimelineScreenModels.swift; sourceTree = "<group>"; };
|
||||||
9B663BE498BB39EADC24025D /* SettingsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenModels.swift; sourceTree = "<group>"; };
|
9B663BE498BB39EADC24025D /* SettingsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenModels.swift; sourceTree = "<group>"; };
|
||||||
9B67DF223EEB8DCAF178A1D4 /* AnalyticsPromptScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreenCoordinator.swift; sourceTree = "<group>"; };
|
9B67DF223EEB8DCAF178A1D4 /* AnalyticsPromptScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
@@ -2612,7 +2616,6 @@
|
|||||||
C142248014E08E885E323E56 /* Avatars.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Avatars.swift; sourceTree = "<group>"; };
|
C142248014E08E885E323E56 /* Avatars.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Avatars.swift; sourceTree = "<group>"; };
|
||||||
C14D83B2B7CD5501A0089EFC /* LayoutDirection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutDirection.swift; sourceTree = "<group>"; };
|
C14D83B2B7CD5501A0089EFC /* LayoutDirection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutDirection.swift; sourceTree = "<group>"; };
|
||||||
C1511766C534367700C8DD75 /* RoomNotificationModeProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationModeProxy.swift; sourceTree = "<group>"; };
|
C1511766C534367700C8DD75 /* RoomNotificationModeProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationModeProxy.swift; sourceTree = "<group>"; };
|
||||||
C15E0017717EAE3A1D02D005 /* StaticLocationScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticLocationScreenCoordinator.swift; sourceTree = "<group>"; };
|
|
||||||
C1D737F4672021D0A7D218CD /* OIDCAccountSettingsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OIDCAccountSettingsPresenter.swift; sourceTree = "<group>"; };
|
C1D737F4672021D0A7D218CD /* OIDCAccountSettingsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OIDCAccountSettingsPresenter.swift; sourceTree = "<group>"; };
|
||||||
C1FA515B3B0D61EF1E907D2D /* BadgeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeView.swift; sourceTree = "<group>"; };
|
C1FA515B3B0D61EF1E907D2D /* BadgeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeView.swift; sourceTree = "<group>"; };
|
||||||
C258C9C815272911A5B132C3 /* FormattedBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormattedBodyText.swift; sourceTree = "<group>"; };
|
C258C9C815272911A5B132C3 /* FormattedBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormattedBodyText.swift; sourceTree = "<group>"; };
|
||||||
@@ -2635,7 +2638,6 @@
|
|||||||
C57DB49B8426AA721BF85D83 /* SpaceServiceProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceServiceProxyProtocol.swift; sourceTree = "<group>"; };
|
C57DB49B8426AA721BF85D83 /* SpaceServiceProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceServiceProxyProtocol.swift; sourceTree = "<group>"; };
|
||||||
C5AEB5907E24092D741718AF /* ResolveVerifiedUserSendFailureScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResolveVerifiedUserSendFailureScreenCoordinator.swift; sourceTree = "<group>"; };
|
C5AEB5907E24092D741718AF /* ResolveVerifiedUserSendFailureScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResolveVerifiedUserSendFailureScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
C5F06F2F09B2EDD067DC2174 /* NotificationSettingsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsScreen.swift; sourceTree = "<group>"; };
|
C5F06F2F09B2EDD067DC2174 /* NotificationSettingsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsScreen.swift; sourceTree = "<group>"; };
|
||||||
C616D90B1E2F033CAA325439 /* StaticLocationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticLocationScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
|
||||||
C687844F60BFF532D49A994C /* AnalyticsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsTests.swift; sourceTree = "<group>"; };
|
C687844F60BFF532D49A994C /* AnalyticsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsTests.swift; sourceTree = "<group>"; };
|
||||||
C6A9F49B3EE59147AF2F70BB /* SeparatorRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorRoomTimelineItem.swift; sourceTree = "<group>"; };
|
C6A9F49B3EE59147AF2F70BB /* SeparatorRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||||
C705E605EF57C19DBE86FFA1 /* PlaceholderAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceholderAvatarImage.swift; sourceTree = "<group>"; };
|
C705E605EF57C19DBE86FFA1 /* PlaceholderAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceholderAvatarImage.swift; sourceTree = "<group>"; };
|
||||||
@@ -2645,7 +2647,6 @@
|
|||||||
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>"; };
|
||||||
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>"; };
|
||||||
C833673B334A0651AB46F30B /* StaticLocationScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticLocationScreenViewModelTests.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>"; };
|
||||||
@@ -2696,6 +2697,7 @@
|
|||||||
D1D97BAF04AA150C0EF03021 /* VerificationBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerificationBadge.swift; sourceTree = "<group>"; };
|
D1D97BAF04AA150C0EF03021 /* VerificationBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerificationBadge.swift; sourceTree = "<group>"; };
|
||||||
D263254AFE5B7993FFBBF324 /* NSE.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NSE.entitlements; sourceTree = "<group>"; };
|
D263254AFE5B7993FFBBF324 /* NSE.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NSE.entitlements; sourceTree = "<group>"; };
|
||||||
D28F7A6CEEA4A2815B0F0F55 /* SettingsFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsFlowCoordinator.swift; sourceTree = "<group>"; };
|
D28F7A6CEEA4A2815B0F0F55 /* SettingsFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsFlowCoordinator.swift; sourceTree = "<group>"; };
|
||||||
|
D2C513A6CD99E6C3C163DA1E /* RowDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RowDivider.swift; sourceTree = "<group>"; };
|
||||||
D316BB02636AF2174F2580E6 /* SoftLogoutScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoftLogoutScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
D316BB02636AF2174F2580E6 /* SoftLogoutScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoftLogoutScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
D33116993D54FADC0C721C1F /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = "<group>"; };
|
D33116993D54FADC0C721C1F /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = "<group>"; };
|
||||||
D3557ACB95D0F666EF5AF0CE /* Secrets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Secrets.swift; sourceTree = "<group>"; };
|
D3557ACB95D0F666EF5AF0CE /* Secrets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Secrets.swift; sourceTree = "<group>"; };
|
||||||
@@ -2849,6 +2851,7 @@
|
|||||||
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>"; };
|
||||||
EE378083653EF0C9B5E9D580 /* EmoteRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItemContent.swift; sourceTree = "<group>"; };
|
EE378083653EF0C9B5E9D580 /* EmoteRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItemContent.swift; sourceTree = "<group>"; };
|
||||||
EEAB5662310AE73D93815134 /* JoinRoomScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinRoomScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
EEAB5662310AE73D93815134 /* JoinRoomScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinRoomScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
|
EED6D8956E554CEDFD4FE00D /* LocationSharingScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationSharingScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
EF13BFD415CA84B1272E94F8 /* PINTextFieldTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PINTextFieldTests.swift; sourceTree = "<group>"; };
|
EF13BFD415CA84B1272E94F8 /* PINTextFieldTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PINTextFieldTests.swift; sourceTree = "<group>"; };
|
||||||
EF1593DD87F974F8509BB619 /* ElementAnimations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementAnimations.swift; sourceTree = "<group>"; };
|
EF1593DD87F974F8509BB619 /* ElementAnimations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementAnimations.swift; sourceTree = "<group>"; };
|
||||||
EF36FC3DE25B20B7FA91F1FD /* SpaceServiceProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceServiceProxyMock.swift; sourceTree = "<group>"; };
|
EF36FC3DE25B20B7FA91F1FD /* SpaceServiceProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceServiceProxyMock.swift; sourceTree = "<group>"; };
|
||||||
@@ -2891,7 +2894,6 @@
|
|||||||
F4CEB4590CCF70F0E3C0B171 /* GeneratedAccessibilityTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneratedAccessibilityTests.swift; sourceTree = "<group>"; };
|
F4CEB4590CCF70F0E3C0B171 /* GeneratedAccessibilityTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneratedAccessibilityTests.swift; sourceTree = "<group>"; };
|
||||||
F506C6ADB1E1DA6638078E11 /* UITests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
F506C6ADB1E1DA6638078E11 /* UITests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
F51D674A5B5F1FE1B878E20F /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = "<group>"; };
|
F51D674A5B5F1FE1B878E20F /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
F5311C989EC15B4C2D699025 /* StaticLocationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticLocationScreenViewModel.swift; sourceTree = "<group>"; };
|
|
||||||
F57C8022B8A871A1DCD1750A /* UserIndicatorToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorToastView.swift; sourceTree = "<group>"; };
|
F57C8022B8A871A1DCD1750A /* UserIndicatorToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorToastView.swift; sourceTree = "<group>"; };
|
||||||
F5D1BAA90F3A073D91B4F16B /* RoomNotificationSettingsProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsProxyMock.swift; sourceTree = "<group>"; };
|
F5D1BAA90F3A073D91B4F16B /* RoomNotificationSettingsProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsProxyMock.swift; sourceTree = "<group>"; };
|
||||||
F5D8FEB1FED10E995CB002F7 /* TimelineBubbleLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineBubbleLayout.swift; sourceTree = "<group>"; };
|
F5D8FEB1FED10E995CB002F7 /* TimelineBubbleLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineBubbleLayout.swift; sourceTree = "<group>"; };
|
||||||
@@ -3118,6 +3120,7 @@
|
|||||||
children = (
|
children = (
|
||||||
76A46ABD27628CB5FC402541 /* Backports.swift */,
|
76A46ABD27628CB5FC402541 /* Backports.swift */,
|
||||||
F03AEAA2F66E796C365EFD58 /* ElementNavigationStack.swift */,
|
F03AEAA2F66E796C365EFD58 /* ElementNavigationStack.swift */,
|
||||||
|
D2C513A6CD99E6C3C163DA1E /* RowDivider.swift */,
|
||||||
693E16574C6F7F9FA1015A8C /* Search.swift */,
|
693E16574C6F7F9FA1015A8C /* Search.swift */,
|
||||||
832397B5C3D00A4BF52C5F0B /* ShouldScrollOnKeyboardDidShow.swift */,
|
832397B5C3D00A4BF52C5F0B /* ShouldScrollOnKeyboardDidShow.swift */,
|
||||||
D1D97BAF04AA150C0EF03021 /* VerificationBadge.swift */,
|
D1D97BAF04AA150C0EF03021 /* VerificationBadge.swift */,
|
||||||
@@ -4777,6 +4780,7 @@
|
|||||||
FDB9C37196A4C79F24CE80C6 /* KeychainControllerTests.swift */,
|
FDB9C37196A4C79F24CE80C6 /* KeychainControllerTests.swift */,
|
||||||
C9AC2CC94FA06F728883B694 /* KnockRequestsListScreenViewModelTests.swift */,
|
C9AC2CC94FA06F728883B694 /* KnockRequestsListScreenViewModelTests.swift */,
|
||||||
C070FD43DC6BF4E50217965A /* LocalizationTests.swift */,
|
C070FD43DC6BF4E50217965A /* LocalizationTests.swift */,
|
||||||
|
EED6D8956E554CEDFD4FE00D /* LocationSharingScreenViewModelTests.swift */,
|
||||||
3DC1943ADE6A62ED5129D7C8 /* LoggingTests.swift */,
|
3DC1943ADE6A62ED5129D7C8 /* LoggingTests.swift */,
|
||||||
5A43964330459965AF048A8C /* LoginScreenViewModelTests.swift */,
|
5A43964330459965AF048A8C /* LoginScreenViewModelTests.swift */,
|
||||||
D80807B554CF9C524F98674F /* ManageRoomMemberSheetViewModelTests.swift */,
|
D80807B554CF9C524F98674F /* ManageRoomMemberSheetViewModelTests.swift */,
|
||||||
@@ -4836,7 +4840,6 @@
|
|||||||
5557DDA438841AF5DC003D0B /* SpaceListScreenViewModelTests.swift */,
|
5557DDA438841AF5DC003D0B /* SpaceListScreenViewModelTests.swift */,
|
||||||
18B223FA339BF53085328DEE /* SpaceScreenViewModelTests.swift */,
|
18B223FA339BF53085328DEE /* SpaceScreenViewModelTests.swift */,
|
||||||
6DF438EAFC732D2D95D34BF6 /* StartChatViewModelTests.swift */,
|
6DF438EAFC732D2D95D34BF6 /* StartChatViewModelTests.swift */,
|
||||||
C833673B334A0651AB46F30B /* StaticLocationScreenViewModelTests.swift */,
|
|
||||||
2CEBCB9676FCD1D0F13188DD /* StringTests.swift */,
|
2CEBCB9676FCD1D0F13188DD /* StringTests.swift */,
|
||||||
2AB2C848BB9A7A9B618B7B89 /* TextBasedRoomTimelineTests.swift */,
|
2AB2C848BB9A7A9B618B7B89 /* TextBasedRoomTimelineTests.swift */,
|
||||||
9AA3AF94A06D319BB37E52DA /* TimelineItemFactoryTests.swift */,
|
9AA3AF94A06D319BB37E52DA /* TimelineItemFactoryTests.swift */,
|
||||||
@@ -5395,10 +5398,10 @@
|
|||||||
948DD12A5533BE1BC260E437 /* LocationSharing */ = {
|
948DD12A5533BE1BC260E437 /* LocationSharing */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
4FA4F7FFF0704D1C5471BF6E /* LocationSharingScreenCoordinator.swift */,
|
||||||
8BEBF0E59F25E842EDB6FD11 /* LocationSharingScreenModels.swift */,
|
8BEBF0E59F25E842EDB6FD11 /* LocationSharingScreenModels.swift */,
|
||||||
C15E0017717EAE3A1D02D005 /* StaticLocationScreenCoordinator.swift */,
|
052A8C0B00FE8AD7C972F2A4 /* LocationSharingScreenViewModel.swift */,
|
||||||
F5311C989EC15B4C2D699025 /* StaticLocationScreenViewModel.swift */,
|
4B73675A21580971E9ADF66A /* LocationSharingScreenViewModelProtocol.swift */,
|
||||||
C616D90B1E2F033CAA325439 /* StaticLocationScreenViewModelProtocol.swift */,
|
|
||||||
9FD8D798D879069243A7E7F7 /* View */,
|
9FD8D798D879069243A7E7F7 /* View */,
|
||||||
);
|
);
|
||||||
path = LocationSharing;
|
path = LocationSharing;
|
||||||
@@ -5555,7 +5558,7 @@
|
|||||||
9FD8D798D879069243A7E7F7 /* View */ = {
|
9FD8D798D879069243A7E7F7 /* View */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
9B06663F7858E45882E63471 /* StaticLocationScreen.swift */,
|
6F56E6E41C6DFE8054787D57 /* LocationSharingScreen.swift */,
|
||||||
);
|
);
|
||||||
path = View;
|
path = View;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -7158,6 +7161,7 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
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 = (
|
||||||
@@ -7233,7 +7237,6 @@
|
|||||||
C89CF7729E028671C5DC461E /* XCLocalSwiftPackageReference "compound-ios" */,
|
C89CF7729E028671C5DC461E /* XCLocalSwiftPackageReference "compound-ios" */,
|
||||||
);
|
);
|
||||||
preferredProjectObjectVersion = 77;
|
preferredProjectObjectVersion = 77;
|
||||||
productRefGroup = 681566846AF307E9BA4C72C6 /* Products */;
|
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
targets = (
|
targets = (
|
||||||
@@ -7652,6 +7655,7 @@
|
|||||||
BA48D6AFF6421D199148C0A1 /* KnockRequestsListScreenViewModelTests.swift in Sources */,
|
BA48D6AFF6421D199148C0A1 /* KnockRequestsListScreenViewModelTests.swift in Sources */,
|
||||||
CC961529F9F1854BEC3272C9 /* LayoutMocks.swift in Sources */,
|
CC961529F9F1854BEC3272C9 /* LayoutMocks.swift in Sources */,
|
||||||
0033481EE363E4914295F188 /* LocalizationTests.swift in Sources */,
|
0033481EE363E4914295F188 /* LocalizationTests.swift in Sources */,
|
||||||
|
F6D07D834279BE17D18A33E9 /* LocationSharingScreenViewModelTests.swift in Sources */,
|
||||||
149D1942DC005D0485FB8D93 /* LoggingTests.swift in Sources */,
|
149D1942DC005D0485FB8D93 /* LoggingTests.swift in Sources */,
|
||||||
7434A7F02D587A920B376A9A /* LoginScreenViewModelTests.swift in Sources */,
|
7434A7F02D587A920B376A9A /* LoginScreenViewModelTests.swift in Sources */,
|
||||||
1C1750C009F7214B967928BC /* ManageRoomMemberSheetViewModelTests.swift in Sources */,
|
1C1750C009F7214B967928BC /* ManageRoomMemberSheetViewModelTests.swift in Sources */,
|
||||||
@@ -7718,7 +7722,6 @@
|
|||||||
920DC020F18ABC88175114D3 /* SpaceListScreenViewModelTests.swift in Sources */,
|
920DC020F18ABC88175114D3 /* SpaceListScreenViewModelTests.swift in Sources */,
|
||||||
72D2298DE695A6797CDA1A2A /* SpaceScreenViewModelTests.swift in Sources */,
|
72D2298DE695A6797CDA1A2A /* SpaceScreenViewModelTests.swift in Sources */,
|
||||||
6189B4ABD535CE526FA1107B /* StartChatViewModelTests.swift in Sources */,
|
6189B4ABD535CE526FA1107B /* StartChatViewModelTests.swift in Sources */,
|
||||||
9BB91CABB10D8FE90C491BCD /* StaticLocationScreenViewModelTests.swift in Sources */,
|
|
||||||
1FEC0A4EC6E6DF693C16B32A /* StringTests.swift in Sources */,
|
1FEC0A4EC6E6DF693C16B32A /* StringTests.swift in Sources */,
|
||||||
E75CE800B3E64D0F7F8E228D /* TemplateScreenViewModelTests.swift in Sources */,
|
E75CE800B3E64D0F7F8E228D /* TemplateScreenViewModelTests.swift in Sources */,
|
||||||
3A7DD0D13B0FB8876D69D829 /* TextBasedRoomTimelineTests.swift in Sources */,
|
3A7DD0D13B0FB8876D69D829 /* TextBasedRoomTimelineTests.swift in Sources */,
|
||||||
@@ -8217,7 +8220,11 @@
|
|||||||
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 */,
|
||||||
|
C67156445600FAE6430DE41E /* LocationSharingScreen.swift in Sources */,
|
||||||
|
7A37EC9D7164319587539E1D /* LocationSharingScreenCoordinator.swift in Sources */,
|
||||||
29491EE7AE37E239E839C5A3 /* LocationSharingScreenModels.swift in Sources */,
|
29491EE7AE37E239E839C5A3 /* LocationSharingScreenModels.swift in Sources */,
|
||||||
|
05B02B9508E922677F0E9451 /* LocationSharingScreenViewModel.swift in Sources */,
|
||||||
|
358290C2E4574456FE0C2DF6 /* LocationSharingScreenViewModelProtocol.swift in Sources */,
|
||||||
5EDBDE802761B5ECB54E6787 /* LogLevel.swift in Sources */,
|
5EDBDE802761B5ECB54E6787 /* LogLevel.swift in Sources */,
|
||||||
36DE961B784087D5E18EF9BA /* LogViewerScreen.swift in Sources */,
|
36DE961B784087D5E18EF9BA /* LogViewerScreen.swift in Sources */,
|
||||||
CF38B70D8C6DD42C00A56A27 /* LogViewerScreenCoordinator.swift in Sources */,
|
CF38B70D8C6DD42C00A56A27 /* LogViewerScreenCoordinator.swift in Sources */,
|
||||||
@@ -8546,6 +8553,7 @@
|
|||||||
AD55E245FE686D7DB4C86406 /* RoomTimelineItemView.swift in Sources */,
|
AD55E245FE686D7DB4C86406 /* RoomTimelineItemView.swift in Sources */,
|
||||||
41CE5E1289C8768FC5B6490C /* RoomTimelineItemViewState.swift in Sources */,
|
41CE5E1289C8768FC5B6490C /* RoomTimelineItemViewState.swift in Sources */,
|
||||||
B2F8E01ABA1BA30265B4ECBE /* RoundedCornerShape.swift in Sources */,
|
B2F8E01ABA1BA30265B4ECBE /* RoundedCornerShape.swift in Sources */,
|
||||||
|
82434593648CB74121F1A821 /* RowDivider.swift in Sources */,
|
||||||
3F55721B5C08E8D9F1295592 /* SDKListener.swift in Sources */,
|
3F55721B5C08E8D9F1295592 /* SDKListener.swift in Sources */,
|
||||||
88CBF1595E39CE697928DE48 /* SFNumberedListView.swift in Sources */,
|
88CBF1595E39CE697928DE48 /* SFNumberedListView.swift in Sources */,
|
||||||
FB595EC9C00AB32F39034055 /* SceneDelegate.swift in Sources */,
|
FB595EC9C00AB32F39034055 /* SceneDelegate.swift in Sources */,
|
||||||
@@ -8670,10 +8678,6 @@
|
|||||||
3B277D9538090766DA6C4566 /* StateRoomTimelineView.swift in Sources */,
|
3B277D9538090766DA6C4566 /* StateRoomTimelineView.swift in Sources */,
|
||||||
B4AAB3257A83B73F53FB2689 /* StateStoreViewModel.swift in Sources */,
|
B4AAB3257A83B73F53FB2689 /* StateStoreViewModel.swift in Sources */,
|
||||||
CF638B8C6FDCE920AE061FAE /* StateStoreViewModelV2.swift in Sources */,
|
CF638B8C6FDCE920AE061FAE /* StateStoreViewModelV2.swift in Sources */,
|
||||||
B1069F361E604D5436AE9FFD /* StaticLocationScreen.swift in Sources */,
|
|
||||||
1AB3D8563AB12635250A6A6E /* StaticLocationScreenCoordinator.swift in Sources */,
|
|
||||||
DFD5AA8688A34C72D48AF3B1 /* StaticLocationScreenViewModel.swift in Sources */,
|
|
||||||
5C164551F7D26E24F09083D3 /* StaticLocationScreenViewModelProtocol.swift in Sources */,
|
|
||||||
C58E305C380D3ADDF7912180 /* StickerRoomTimelineItem.swift in Sources */,
|
C58E305C380D3ADDF7912180 /* StickerRoomTimelineItem.swift in Sources */,
|
||||||
197441F1EF23A5DABACCA79F /* StickerRoomTimelineView.swift in Sources */,
|
197441F1EF23A5DABACCA79F /* StickerRoomTimelineView.swift in Sources */,
|
||||||
2F94054F50E312AF30BE07F3 /* String.swift in Sources */,
|
2F94054F50E312AF30BE07F3 /* String.swift in Sources */,
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"a11y_session_verification_time_limited_action_required" = "Time limited action required, you have one minute to verify";
|
"a11y_session_verification_time_limited_action_required" = "Time limited action required, you have one minute to verify";
|
||||||
"a11y_show_password" = "Show password";
|
"a11y_show_password" = "Show password";
|
||||||
"a11y_start_call" = "Start a call";
|
"a11y_start_call" = "Start a call";
|
||||||
|
"a11y_start_voice_call" = "Start a voice call";
|
||||||
"a11y_tombstoned_room" = "Tombstoned room";
|
"a11y_tombstoned_room" = "Tombstoned room";
|
||||||
"a11y_user_menu" = "User menu";
|
"a11y_user_menu" = "User menu";
|
||||||
"a11y_view_avatar" = "View avatar";
|
"a11y_view_avatar" = "View avatar";
|
||||||
@@ -262,6 +263,7 @@
|
|||||||
"common_open_source_licenses" = "Open source licenses";
|
"common_open_source_licenses" = "Open source licenses";
|
||||||
"common_optic_id_ios" = "Optic ID";
|
"common_optic_id_ios" = "Optic ID";
|
||||||
"common_or" = "or";
|
"common_or" = "or";
|
||||||
|
"common_other_options" = "Other options";
|
||||||
"common_password" = "Password";
|
"common_password" = "Password";
|
||||||
"common_people" = "People";
|
"common_people" = "People";
|
||||||
"common_permalink" = "Permalink";
|
"common_permalink" = "Permalink";
|
||||||
@@ -396,7 +398,7 @@
|
|||||||
"dialog_file_too_large_to_upload_title" = "The file size is too large to upload";
|
"dialog_file_too_large_to_upload_title" = "The file size is too large to upload";
|
||||||
"dialog_permission_camera" = "In order to let the application use the camera, please grant the permission in the system settings.";
|
"dialog_permission_camera" = "In order to let the application use the camera, please grant the permission in the system settings.";
|
||||||
"dialog_permission_generic" = "Please grant the permission in the system settings.";
|
"dialog_permission_generic" = "Please grant the permission in the system settings.";
|
||||||
"dialog_permission_location_description_ios" = "To share your current location, Element needs location access. Go to Settings > Location.";
|
"dialog_permission_location_description_ios" = "To share your current location, %1$@ needs location access. Go to Settings > Location.";
|
||||||
"dialog_permission_location_title_ios" = "%1$@ does not have access to your location.";
|
"dialog_permission_location_title_ios" = "%1$@ does not have access to your location.";
|
||||||
"dialog_permission_microphone" = "In order to let the application use the microphone, please grant the permission in the system settings.";
|
"dialog_permission_microphone" = "In order to let the application use the microphone, please grant the permission in the system settings.";
|
||||||
"dialog_permission_microphone_description_ios" = "Grant access so you can record and send messages with audio.";
|
"dialog_permission_microphone_description_ios" = "Grant access so you can record and send messages with audio.";
|
||||||
@@ -458,6 +460,7 @@
|
|||||||
"notification_channel_ringing_calls" = "Ringing calls";
|
"notification_channel_ringing_calls" = "Ringing calls";
|
||||||
"notification_channel_silent" = "Silent notifications";
|
"notification_channel_silent" = "Silent notifications";
|
||||||
"notification_fallback_content" = "You have new messages.";
|
"notification_fallback_content" = "You have new messages.";
|
||||||
|
"notification_incoming_audio_call" = "📞 Incoming call";
|
||||||
"notification_incoming_call" = "📹 Incoming call";
|
"notification_incoming_call" = "📹 Incoming call";
|
||||||
"notification_inline_reply_failed" = "** Failed to send - please open room";
|
"notification_inline_reply_failed" = "** Failed to send - please open room";
|
||||||
"notification_invite_body" = "Invited you to chat";
|
"notification_invite_body" = "Invited you to chat";
|
||||||
@@ -665,6 +668,7 @@
|
|||||||
"screen_media_upload_preview_item_count" = "Item %1$d of %2$d";
|
"screen_media_upload_preview_item_count" = "Item %1$d of %2$d";
|
||||||
"screen_media_upload_preview_optimize_image_quality_title" = "Optimize image quality";
|
"screen_media_upload_preview_optimize_image_quality_title" = "Optimize image quality";
|
||||||
"screen_media_upload_preview_processing" = "Processing...";
|
"screen_media_upload_preview_processing" = "Processing...";
|
||||||
|
"screen_onboarding_welcome_back" = "Welcome back";
|
||||||
"screen_pinned_timeline_empty_state_description" = "Press on a message and choose “%1$@” to include here.";
|
"screen_pinned_timeline_empty_state_description" = "Press on a message and choose “%1$@” to include here.";
|
||||||
"screen_pinned_timeline_empty_state_headline" = "Pin important messages so that they can be easily discovered";
|
"screen_pinned_timeline_empty_state_headline" = "Pin important messages so that they can be easily discovered";
|
||||||
"screen_push_history_title" = "Push history";
|
"screen_push_history_title" = "Push history";
|
||||||
@@ -1267,7 +1271,7 @@
|
|||||||
"screen_share_open_apple_maps" = "Open in Apple Maps";
|
"screen_share_open_apple_maps" = "Open in Apple Maps";
|
||||||
"screen_share_open_google_maps" = "Open in Google Maps";
|
"screen_share_open_google_maps" = "Open in Google Maps";
|
||||||
"screen_share_open_osm_maps" = "Open in OpenStreetMap";
|
"screen_share_open_osm_maps" = "Open in OpenStreetMap";
|
||||||
"screen_share_this_location_action" = "Share this location";
|
"screen_share_this_location_action" = "Share pinned location";
|
||||||
"screen_signed_out_reason_1" = "You’ve changed your password on another session";
|
"screen_signed_out_reason_1" = "You’ve changed your password on another session";
|
||||||
"screen_signed_out_reason_2" = "You have deleted the session from another session";
|
"screen_signed_out_reason_2" = "You have deleted the session from another session";
|
||||||
"screen_signed_out_reason_3" = "Your server’s administrator has invalidated your access";
|
"screen_signed_out_reason_3" = "Your server’s administrator has invalidated your access";
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"a11y_session_verification_time_limited_action_required" = "Time limited action required, you have one minute to verify";
|
"a11y_session_verification_time_limited_action_required" = "Time limited action required, you have one minute to verify";
|
||||||
"a11y_show_password" = "Show password";
|
"a11y_show_password" = "Show password";
|
||||||
"a11y_start_call" = "Start a call";
|
"a11y_start_call" = "Start a call";
|
||||||
|
"a11y_start_voice_call" = "Start a voice call";
|
||||||
"a11y_tombstoned_room" = "Tombstoned room";
|
"a11y_tombstoned_room" = "Tombstoned room";
|
||||||
"a11y_user_menu" = "User menu";
|
"a11y_user_menu" = "User menu";
|
||||||
"a11y_view_avatar" = "View avatar";
|
"a11y_view_avatar" = "View avatar";
|
||||||
@@ -262,6 +263,7 @@
|
|||||||
"common_open_source_licenses" = "Open source licenses";
|
"common_open_source_licenses" = "Open source licenses";
|
||||||
"common_optic_id_ios" = "Optic ID";
|
"common_optic_id_ios" = "Optic ID";
|
||||||
"common_or" = "or";
|
"common_or" = "or";
|
||||||
|
"common_other_options" = "Other options";
|
||||||
"common_password" = "Password";
|
"common_password" = "Password";
|
||||||
"common_people" = "People";
|
"common_people" = "People";
|
||||||
"common_permalink" = "Permalink";
|
"common_permalink" = "Permalink";
|
||||||
@@ -396,7 +398,7 @@
|
|||||||
"dialog_file_too_large_to_upload_title" = "The file size is too large to upload";
|
"dialog_file_too_large_to_upload_title" = "The file size is too large to upload";
|
||||||
"dialog_permission_camera" = "In order to let the application use the camera, please grant the permission in the system settings.";
|
"dialog_permission_camera" = "In order to let the application use the camera, please grant the permission in the system settings.";
|
||||||
"dialog_permission_generic" = "Please grant the permission in the system settings.";
|
"dialog_permission_generic" = "Please grant the permission in the system settings.";
|
||||||
"dialog_permission_location_description_ios" = "To share your current location, Element needs location access. Go to Settings > Location.";
|
"dialog_permission_location_description_ios" = "To share your current location, %1$@ needs location access. Go to Settings > Location.";
|
||||||
"dialog_permission_location_title_ios" = "%1$@ does not have access to your location.";
|
"dialog_permission_location_title_ios" = "%1$@ does not have access to your location.";
|
||||||
"dialog_permission_microphone" = "In order to let the application use the microphone, please grant the permission in the system settings.";
|
"dialog_permission_microphone" = "In order to let the application use the microphone, please grant the permission in the system settings.";
|
||||||
"dialog_permission_microphone_description_ios" = "Grant access so you can record and send messages with audio.";
|
"dialog_permission_microphone_description_ios" = "Grant access so you can record and send messages with audio.";
|
||||||
@@ -458,6 +460,7 @@
|
|||||||
"notification_channel_ringing_calls" = "Ringing calls";
|
"notification_channel_ringing_calls" = "Ringing calls";
|
||||||
"notification_channel_silent" = "Silent notifications";
|
"notification_channel_silent" = "Silent notifications";
|
||||||
"notification_fallback_content" = "You have new messages.";
|
"notification_fallback_content" = "You have new messages.";
|
||||||
|
"notification_incoming_audio_call" = "📞 Incoming call";
|
||||||
"notification_incoming_call" = "📹 Incoming call";
|
"notification_incoming_call" = "📹 Incoming call";
|
||||||
"notification_inline_reply_failed" = "** Failed to send - please open room";
|
"notification_inline_reply_failed" = "** Failed to send - please open room";
|
||||||
"notification_invite_body" = "Invited you to chat";
|
"notification_invite_body" = "Invited you to chat";
|
||||||
@@ -665,6 +668,7 @@
|
|||||||
"screen_media_upload_preview_item_count" = "Item %1$d of %2$d";
|
"screen_media_upload_preview_item_count" = "Item %1$d of %2$d";
|
||||||
"screen_media_upload_preview_optimize_image_quality_title" = "Optimise image quality";
|
"screen_media_upload_preview_optimize_image_quality_title" = "Optimise image quality";
|
||||||
"screen_media_upload_preview_processing" = "Processing...";
|
"screen_media_upload_preview_processing" = "Processing...";
|
||||||
|
"screen_onboarding_welcome_back" = "Welcome back";
|
||||||
"screen_pinned_timeline_empty_state_description" = "Press on a message and choose “%1$@” to include here.";
|
"screen_pinned_timeline_empty_state_description" = "Press on a message and choose “%1$@” to include here.";
|
||||||
"screen_pinned_timeline_empty_state_headline" = "Pin important messages so that they can be easily discovered";
|
"screen_pinned_timeline_empty_state_headline" = "Pin important messages so that they can be easily discovered";
|
||||||
"screen_push_history_title" = "Push history";
|
"screen_push_history_title" = "Push history";
|
||||||
@@ -1267,7 +1271,7 @@
|
|||||||
"screen_share_open_apple_maps" = "Open in Apple Maps";
|
"screen_share_open_apple_maps" = "Open in Apple Maps";
|
||||||
"screen_share_open_google_maps" = "Open in Google Maps";
|
"screen_share_open_google_maps" = "Open in Google Maps";
|
||||||
"screen_share_open_osm_maps" = "Open in OpenStreetMap";
|
"screen_share_open_osm_maps" = "Open in OpenStreetMap";
|
||||||
"screen_share_this_location_action" = "Share this location";
|
"screen_share_this_location_action" = "Share pinned location";
|
||||||
"screen_signed_out_reason_1" = "You’ve changed your password on another session";
|
"screen_signed_out_reason_1" = "You’ve changed your password on another session";
|
||||||
"screen_signed_out_reason_2" = "You have deleted the session from another session";
|
"screen_signed_out_reason_2" = "You have deleted the session from another session";
|
||||||
"screen_signed_out_reason_3" = "Your server’s administrator has invalidated your access";
|
"screen_signed_out_reason_3" = "Your server’s administrator has invalidated your access";
|
||||||
|
|||||||
@@ -64,6 +64,8 @@ final class AppSettings {
|
|||||||
|
|
||||||
case elementCallBaseURLOverride
|
case elementCallBaseURLOverride
|
||||||
|
|
||||||
|
case voiceMessagePlaybackSpeed
|
||||||
|
|
||||||
// Feature flags
|
// Feature flags
|
||||||
case publicSearchEnabled
|
case publicSearchEnabled
|
||||||
case fuzzyRoomListSearchEnabled
|
case fuzzyRoomListSearchEnabled
|
||||||
@@ -76,9 +78,8 @@ final class AppSettings {
|
|||||||
case linkPreviewsEnabled
|
case linkPreviewsEnabled
|
||||||
case focusEventOnNotificationTap
|
case focusEventOnNotificationTap
|
||||||
case linkNewDeviceEnabled
|
case linkNewDeviceEnabled
|
||||||
|
case liveLocationSharingEnabled
|
||||||
|
|
||||||
case voiceMessagePlaybackSpeed
|
|
||||||
|
|
||||||
// Doug's tweaks 🔧
|
// Doug's tweaks 🔧
|
||||||
case hideUnreadMessagesBadge
|
case hideUnreadMessagesBadge
|
||||||
case hideQuietNotificationAlerts
|
case hideQuietNotificationAlerts
|
||||||
@@ -432,6 +433,9 @@ final class AppSettings {
|
|||||||
@UserPreference(key: UserDefaultsKeys.linkNewDeviceEnabled, defaultValue: false, storageType: .userDefaults(store))
|
@UserPreference(key: UserDefaultsKeys.linkNewDeviceEnabled, defaultValue: false, storageType: .userDefaults(store))
|
||||||
var linkNewDeviceEnabled
|
var linkNewDeviceEnabled
|
||||||
|
|
||||||
|
@UserPreference(key: UserDefaultsKeys.liveLocationSharingEnabled, defaultValue: false, storageType: .userDefaults(store))
|
||||||
|
var liveLocationSharingEnabled
|
||||||
|
|
||||||
@UserPreference(key: UserDefaultsKeys.developerOptionsEnabled, defaultValue: appBuildType == .debug, storageType: .userDefaults(store))
|
@UserPreference(key: UserDefaultsKeys.developerOptionsEnabled, defaultValue: appBuildType == .debug, storageType: .userDefaults(store))
|
||||||
var developerOptionsEnabled
|
var developerOptionsEnabled
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,8 +85,10 @@ class PinnedEventsTimelineFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
actionsSubject.send(.finished)
|
actionsSubject.send(.finished)
|
||||||
case .displayUser(let userID):
|
case .displayUser(let userID):
|
||||||
actionsSubject.send(.displayUser(userID: userID))
|
actionsSubject.send(.displayUser(userID: userID))
|
||||||
case .presentLocationViewer(let geoURI, let description):
|
case .presentLocationViewer(let senderID, let geoURI):
|
||||||
presentMapNavigator(geoURI: geoURI, description: description, timelineController: timelineController)
|
presentMapNavigator(senderID: senderID,
|
||||||
|
geoURI: geoURI,
|
||||||
|
timelineController: timelineController)
|
||||||
case .displayMessageForwarding(let forwardingItem):
|
case .displayMessageForwarding(let forwardingItem):
|
||||||
presentMessageForwarding(with: forwardingItem)
|
presentMessageForwarding(with: forwardingItem)
|
||||||
case .displayRoomScreenWithFocussedPin(let eventID, let threadRootEventID):
|
case .displayRoomScreenWithFocussedPin(let eventID, let threadRootEventID):
|
||||||
@@ -98,16 +100,22 @@ class PinnedEventsTimelineFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func presentMapNavigator(geoURI: GeoURI, description: String?, timelineController: TimelineControllerProtocol) {
|
private func presentMapNavigator(senderID: String?,
|
||||||
|
geoURI: GeoURI,
|
||||||
|
timelineController: TimelineControllerProtocol) {
|
||||||
let stackCoordinator = NavigationStackCoordinator()
|
let stackCoordinator = NavigationStackCoordinator()
|
||||||
|
|
||||||
let params = StaticLocationScreenCoordinatorParameters(interactionMode: .viewOnly(geoURI: geoURI, description: description),
|
let params = LocationSharingScreenCoordinatorParameters(interactionMode: .viewStatic(senderID: senderID,
|
||||||
mapURLBuilder: flowParameters.appSettings.mapTilerConfiguration,
|
geoURI: geoURI),
|
||||||
timelineController: timelineController,
|
mapURLBuilder: flowParameters.appSettings.mapTilerConfiguration,
|
||||||
appMediator: flowParameters.appMediator,
|
liveLocationSharingEnabled: flowParameters.appSettings.liveLocationSharingEnabled,
|
||||||
analytics: flowParameters.analytics,
|
roomProxy: roomProxy,
|
||||||
userIndicatorController: flowParameters.userIndicatorController)
|
timelineController: timelineController,
|
||||||
let coordinator = StaticLocationScreenCoordinator(parameters: params)
|
appMediator: flowParameters.appMediator,
|
||||||
|
analytics: flowParameters.analytics,
|
||||||
|
userIndicatorController: flowParameters.userIndicatorController,
|
||||||
|
mediaProvider: flowParameters.userSession.mediaProvider)
|
||||||
|
let coordinator = LocationSharingScreenCoordinator(parameters: params)
|
||||||
|
|
||||||
coordinator.actions.sink { [weak self] action in
|
coordinator.actions.sink { [weak self] action in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
|
|||||||
@@ -703,8 +703,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
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))
|
||||||
case .presentLocationViewer(_, let geoURI, let description):
|
case .presentLocationViewer(let senderID, let geoURI):
|
||||||
stateMachine.tryEvent(.presentMapNavigator(interactionMode: .viewOnly(geoURI: geoURI, description: description)),
|
stateMachine.tryEvent(.presentMapNavigator(interactionMode: .viewStatic(senderID: senderID, geoURI: geoURI)),
|
||||||
userInfo: EventUserInfo(animated: animated, timelineController: timelineController))
|
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)))
|
||||||
@@ -788,10 +788,11 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
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))
|
||||||
case .presentLocationViewer(_, let geoURI, let description):
|
case .presentLocationViewer(let senderID, let geoURI):
|
||||||
stateMachine.tryEvent(.presentMapNavigator(interactionMode: .viewOnly(geoURI: geoURI,
|
stateMachine.tryEvent(.presentMapNavigator(interactionMode: .viewStatic(senderID: senderID,
|
||||||
description: description)),
|
geoURI: geoURI)),
|
||||||
userInfo: EventUserInfo(animated: animated, timelineController: timelineController))
|
userInfo: EventUserInfo(animated: animated,
|
||||||
|
timelineController: timelineController))
|
||||||
case .presentEmojiPicker(let itemID, let selectedEmojis):
|
case .presentEmojiPicker(let itemID, let selectedEmojis):
|
||||||
stateMachine.tryEvent(.presentEmojiPicker(itemID: itemID, selectedEmojis: selectedEmojis),
|
stateMachine.tryEvent(.presentEmojiPicker(itemID: itemID, selectedEmojis: selectedEmojis),
|
||||||
userInfo: EventUserInfo(animated: animated, timelineController: timelineController))
|
userInfo: EventUserInfo(animated: animated, timelineController: timelineController))
|
||||||
@@ -1128,18 +1129,21 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func presentMapNavigator(interactionMode: StaticLocationInteractionMode,
|
private func presentMapNavigator(interactionMode: LocationSharingInteractionMode,
|
||||||
timelineController: TimelineControllerProtocol,
|
timelineController: TimelineControllerProtocol,
|
||||||
animated: Bool) {
|
animated: Bool) {
|
||||||
let stackCoordinator = NavigationStackCoordinator()
|
let stackCoordinator = NavigationStackCoordinator()
|
||||||
|
|
||||||
let params = StaticLocationScreenCoordinatorParameters(interactionMode: interactionMode,
|
let params = LocationSharingScreenCoordinatorParameters(interactionMode: interactionMode,
|
||||||
mapURLBuilder: flowParameters.appSettings.mapTilerConfiguration,
|
mapURLBuilder: flowParameters.appSettings.mapTilerConfiguration,
|
||||||
timelineController: timelineController,
|
liveLocationSharingEnabled: flowParameters.appSettings.liveLocationSharingEnabled,
|
||||||
appMediator: flowParameters.appMediator,
|
roomProxy: roomProxy,
|
||||||
analytics: flowParameters.analytics,
|
timelineController: timelineController,
|
||||||
userIndicatorController: flowParameters.userIndicatorController)
|
appMediator: flowParameters.appMediator,
|
||||||
let coordinator = StaticLocationScreenCoordinator(parameters: params)
|
analytics: flowParameters.analytics,
|
||||||
|
userIndicatorController: flowParameters.userIndicatorController,
|
||||||
|
mediaProvider: flowParameters.userSession.mediaProvider)
|
||||||
|
let coordinator = LocationSharingScreenCoordinator(parameters: params)
|
||||||
|
|
||||||
coordinator.actions.sink { [weak self] action in
|
coordinator.actions.sink { [weak self] action in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ extension RoomFlowCoordinator {
|
|||||||
case presentEmojiPicker(itemID: TimelineItemIdentifier, selectedEmojis: Set<String>)
|
case presentEmojiPicker(itemID: TimelineItemIdentifier, selectedEmojis: Set<String>)
|
||||||
case dismissEmojiPicker
|
case dismissEmojiPicker
|
||||||
|
|
||||||
case presentMapNavigator(interactionMode: StaticLocationInteractionMode)
|
case presentMapNavigator(interactionMode: LocationSharingInteractionMode)
|
||||||
case dismissMapNavigator
|
case dismissMapNavigator
|
||||||
|
|
||||||
case presentMessageForwarding(forwardingItem: MessageForwardingItem)
|
case presentMessageForwarding(forwardingItem: MessageForwardingItem)
|
||||||
|
|||||||
@@ -116,6 +116,8 @@ internal enum L10n {
|
|||||||
internal static var a11yShowPassword: String { return L10n.tr("Localizable", "a11y_show_password") }
|
internal static var a11yShowPassword: String { return L10n.tr("Localizable", "a11y_show_password") }
|
||||||
/// Start a call
|
/// Start a call
|
||||||
internal static var a11yStartCall: String { return L10n.tr("Localizable", "a11y_start_call") }
|
internal static var a11yStartCall: String { return L10n.tr("Localizable", "a11y_start_call") }
|
||||||
|
/// Start a voice call
|
||||||
|
internal static var a11yStartVoiceCall: String { return L10n.tr("Localizable", "a11y_start_voice_call") }
|
||||||
/// Tombstoned room
|
/// Tombstoned room
|
||||||
internal static var a11yTombstonedRoom: String { return L10n.tr("Localizable", "a11y_tombstoned_room") }
|
internal static var a11yTombstonedRoom: String { return L10n.tr("Localizable", "a11y_tombstoned_room") }
|
||||||
/// User menu
|
/// User menu
|
||||||
@@ -584,6 +586,8 @@ internal enum L10n {
|
|||||||
internal static var commonOpticIdIos: String { return L10n.tr("Localizable", "common_optic_id_ios") }
|
internal static var commonOpticIdIos: String { return L10n.tr("Localizable", "common_optic_id_ios") }
|
||||||
/// or
|
/// or
|
||||||
internal static var commonOr: String { return L10n.tr("Localizable", "common_or") }
|
internal static var commonOr: String { return L10n.tr("Localizable", "common_or") }
|
||||||
|
/// Other options
|
||||||
|
internal static var commonOtherOptions: String { return L10n.tr("Localizable", "common_other_options") }
|
||||||
/// Password
|
/// Password
|
||||||
internal static var commonPassword: String { return L10n.tr("Localizable", "common_password") }
|
internal static var commonPassword: String { return L10n.tr("Localizable", "common_password") }
|
||||||
/// People
|
/// People
|
||||||
@@ -908,8 +912,10 @@ internal enum L10n {
|
|||||||
internal static var dialogPermissionCamera: String { return L10n.tr("Localizable", "dialog_permission_camera") }
|
internal static var dialogPermissionCamera: String { return L10n.tr("Localizable", "dialog_permission_camera") }
|
||||||
/// Please grant the permission in the system settings.
|
/// Please grant the permission in the system settings.
|
||||||
internal static var dialogPermissionGeneric: String { return L10n.tr("Localizable", "dialog_permission_generic") }
|
internal static var dialogPermissionGeneric: String { return L10n.tr("Localizable", "dialog_permission_generic") }
|
||||||
/// To share your current location, Element needs location access. Go to Settings > Location.
|
/// To share your current location, %1$@ needs location access. Go to Settings > Location.
|
||||||
internal static var dialogPermissionLocationDescriptionIos: String { return L10n.tr("Localizable", "dialog_permission_location_description_ios") }
|
internal static func dialogPermissionLocationDescriptionIos(_ p1: Any) -> String {
|
||||||
|
return L10n.tr("Localizable", "dialog_permission_location_description_ios", String(describing: p1))
|
||||||
|
}
|
||||||
/// %1$@ does not have access to your location.
|
/// %1$@ does not have access to your location.
|
||||||
internal static func dialogPermissionLocationTitleIos(_ p1: Any) -> String {
|
internal static func dialogPermissionLocationTitleIos(_ p1: Any) -> String {
|
||||||
return L10n.tr("Localizable", "dialog_permission_location_title_ios", String(describing: p1))
|
return L10n.tr("Localizable", "dialog_permission_location_title_ios", String(describing: p1))
|
||||||
@@ -1062,6 +1068,8 @@ internal enum L10n {
|
|||||||
internal static func notificationFallbackNContent(_ p1: Int) -> String {
|
internal static func notificationFallbackNContent(_ p1: Int) -> String {
|
||||||
return L10n.tr("Localizable", "notification_fallback_n_content", p1)
|
return L10n.tr("Localizable", "notification_fallback_n_content", p1)
|
||||||
}
|
}
|
||||||
|
/// 📞 Incoming call
|
||||||
|
internal static var notificationIncomingAudioCall: String { return L10n.tr("Localizable", "notification_incoming_audio_call") }
|
||||||
/// 📹 Incoming call
|
/// 📹 Incoming call
|
||||||
internal static var notificationIncomingCall: String { return L10n.tr("Localizable", "notification_incoming_call") }
|
internal static var notificationIncomingCall: String { return L10n.tr("Localizable", "notification_incoming_call") }
|
||||||
/// ** Failed to send - please open room
|
/// ** Failed to send - please open room
|
||||||
@@ -2238,6 +2246,8 @@ internal enum L10n {
|
|||||||
internal static var screenOnboardingSignInWithQrCode: String { return L10n.tr("Localizable", "screen_onboarding_sign_in_with_qr_code") }
|
internal static var screenOnboardingSignInWithQrCode: String { return L10n.tr("Localizable", "screen_onboarding_sign_in_with_qr_code") }
|
||||||
/// Create account
|
/// Create account
|
||||||
internal static var screenOnboardingSignUp: String { return L10n.tr("Localizable", "screen_onboarding_sign_up") }
|
internal static var screenOnboardingSignUp: String { return L10n.tr("Localizable", "screen_onboarding_sign_up") }
|
||||||
|
/// Welcome back
|
||||||
|
internal static var screenOnboardingWelcomeBack: String { return L10n.tr("Localizable", "screen_onboarding_welcome_back") }
|
||||||
/// Welcome to the fastest %1$@ ever. Supercharged for speed and simplicity.
|
/// Welcome to the fastest %1$@ ever. Supercharged for speed and simplicity.
|
||||||
internal static func screenOnboardingWelcomeMessage(_ p1: Any) -> String {
|
internal static func screenOnboardingWelcomeMessage(_ p1: Any) -> String {
|
||||||
return L10n.tr("Localizable", "screen_onboarding_welcome_message", String(describing: p1))
|
return L10n.tr("Localizable", "screen_onboarding_welcome_message", String(describing: p1))
|
||||||
@@ -3157,7 +3167,7 @@ internal enum L10n {
|
|||||||
internal static var screenShareOpenGoogleMaps: String { return L10n.tr("Localizable", "screen_share_open_google_maps") }
|
internal static var screenShareOpenGoogleMaps: String { return L10n.tr("Localizable", "screen_share_open_google_maps") }
|
||||||
/// Open in OpenStreetMap
|
/// Open in OpenStreetMap
|
||||||
internal static var screenShareOpenOsmMaps: String { return L10n.tr("Localizable", "screen_share_open_osm_maps") }
|
internal static var screenShareOpenOsmMaps: String { return L10n.tr("Localizable", "screen_share_open_osm_maps") }
|
||||||
/// Share this location
|
/// Share pinned location
|
||||||
internal static var screenShareThisLocationAction: String { return L10n.tr("Localizable", "screen_share_this_location_action") }
|
internal static var screenShareThisLocationAction: String { return L10n.tr("Localizable", "screen_share_this_location_action") }
|
||||||
/// You’ve changed your password on another session
|
/// You’ve changed your password on another session
|
||||||
internal static var screenSignedOutReason1: String { return L10n.tr("Localizable", "screen_signed_out_reason_1") }
|
internal static var screenSignedOutReason1: String { return L10n.tr("Localizable", "screen_signed_out_reason_1") }
|
||||||
|
|||||||
@@ -84,55 +84,38 @@ enum UserAvatarSizeOnScreen {
|
|||||||
case sendInviteConfirmation
|
case sendInviteConfirmation
|
||||||
case sessionVerification
|
case sessionVerification
|
||||||
case threadSummary
|
case threadSummary
|
||||||
|
case map
|
||||||
|
|
||||||
var value: CGFloat {
|
var value: CGFloat {
|
||||||
switch self {
|
switch self {
|
||||||
case .chats, .spaces:
|
|
||||||
return 32
|
|
||||||
case .timeline:
|
|
||||||
return 32
|
|
||||||
case .readReceipt:
|
case .readReceipt:
|
||||||
return 16
|
16
|
||||||
case .readReceiptSheet:
|
|
||||||
return 32
|
|
||||||
case .spaceHeader:
|
case .spaceHeader:
|
||||||
return 20
|
20
|
||||||
case .completionSuggestions:
|
|
||||||
return 32
|
|
||||||
case .blockedUsers:
|
|
||||||
return 32
|
|
||||||
case .settings:
|
|
||||||
return 52
|
|
||||||
case .roomDetails:
|
|
||||||
return 44
|
|
||||||
case .roomMembersList:
|
|
||||||
return 32
|
|
||||||
case .roomChangeRoles:
|
|
||||||
return 56
|
|
||||||
case .startChat:
|
|
||||||
return 36
|
|
||||||
case .memberDetails:
|
|
||||||
return 96
|
|
||||||
case .inviteUsers:
|
|
||||||
return 52
|
|
||||||
case .editUserDetails:
|
|
||||||
return 96
|
|
||||||
case .dmDetails:
|
|
||||||
return 75
|
|
||||||
case .knockingUsersBannerStack:
|
|
||||||
return 28
|
|
||||||
case .knockingUserBanner:
|
|
||||||
return 32
|
|
||||||
case .knockingUserList:
|
|
||||||
return 52
|
|
||||||
case .mediaPreviewDetails:
|
|
||||||
return 32
|
|
||||||
case .sendInviteConfirmation:
|
|
||||||
return 64
|
|
||||||
case .sessionVerification:
|
|
||||||
return 52
|
|
||||||
case .threadSummary:
|
case .threadSummary:
|
||||||
return 24
|
24
|
||||||
|
case .knockingUsersBannerStack:
|
||||||
|
28
|
||||||
|
case .chats, .spaces, .map,
|
||||||
|
.timeline, .readReceiptSheet, .completionSuggestions,
|
||||||
|
.blockedUsers, .roomMembersList, .knockingUserBanner,
|
||||||
|
.mediaPreviewDetails:
|
||||||
|
32
|
||||||
|
case .startChat:
|
||||||
|
36
|
||||||
|
case .roomDetails:
|
||||||
|
44
|
||||||
|
case .inviteUsers, .knockingUserList, .sessionVerification,
|
||||||
|
.settings:
|
||||||
|
52
|
||||||
|
case .roomChangeRoles:
|
||||||
|
56
|
||||||
|
case .sendInviteConfirmation:
|
||||||
|
64
|
||||||
|
case .dmDetails:
|
||||||
|
75
|
||||||
|
case .memberDetails, .editUserDetails:
|
||||||
|
96
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,24 +143,22 @@ enum RoomAvatarSizeOnScreen {
|
|||||||
|
|
||||||
var value: CGFloat {
|
var value: CGFloat {
|
||||||
switch self {
|
switch self {
|
||||||
case .chats, .spaces, .spaceSettings:
|
case .notificationSettings:
|
||||||
return 52
|
30
|
||||||
case .timeline, .leaveSpace, .roomDirectorySearch,
|
case .timeline, .leaveSpace, .roomDirectorySearch,
|
||||||
.completionSuggestions, .authorizedSpaces, .createRoomSelectSpace,
|
.completionSuggestions, .authorizedSpaces, .createRoomSelectSpace,
|
||||||
.spaceFilters:
|
.spaceFilters:
|
||||||
return 32
|
32
|
||||||
case .notificationSettings:
|
case .messageForwarding, .globalSearch, .roomSelection,
|
||||||
return 30
|
.spaceAddRooms:
|
||||||
case .messageForwarding, .globalSearch, .roomSelection, .spaceAddRooms:
|
36
|
||||||
return 36
|
case .chats, .spaces, .spaceSettings,
|
||||||
case .spaceAddRoomsSelected:
|
.spaceAddRoomsSelected:
|
||||||
return 52
|
52
|
||||||
|
case .joinRoom, .spaceHeader:
|
||||||
|
64
|
||||||
case .details:
|
case .details:
|
||||||
return 96
|
96
|
||||||
case .joinRoom:
|
|
||||||
return 64
|
|
||||||
case .spaceHeader:
|
|
||||||
return 64
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,23 +11,32 @@ import MapLibre
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
final class LocationAnnotation: NSObject, MLNAnnotation {
|
final class LocationAnnotation: NSObject, MLNAnnotation {
|
||||||
let coordinate: CLLocationCoordinate2D
|
let id: String
|
||||||
|
var coordinate: CLLocationCoordinate2D
|
||||||
let anchorPoint: CGPoint
|
let anchorPoint: CGPoint
|
||||||
let view: AnyView
|
var view: AnyView
|
||||||
|
|
||||||
// MARK: - Setup
|
// MARK: - Setup
|
||||||
|
|
||||||
init(coordinate: CLLocationCoordinate2D,
|
init(id: String = UUID().uuidString,
|
||||||
|
coordinate: CLLocationCoordinate2D,
|
||||||
anchorPoint: CGPoint = .init(x: 0.5, y: 0.5),
|
anchorPoint: CGPoint = .init(x: 0.5, y: 0.5),
|
||||||
@ViewBuilder label: () -> some View) {
|
@ViewBuilder label: () -> some View) {
|
||||||
|
self.id = id
|
||||||
self.coordinate = coordinate
|
self.coordinate = coordinate
|
||||||
self.anchorPoint = anchorPoint
|
self.anchorPoint = anchorPoint
|
||||||
view = AnyView(label())
|
view = AnyView(label())
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateView(@ViewBuilder label: () -> some View) {
|
||||||
|
view = AnyView(label())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class LocationAnnotationView: MLNUserLocationAnnotationView {
|
final class LocationAnnotationView: MLNUserLocationAnnotationView {
|
||||||
|
private var hostingController: UIHostingController<AnyView>?
|
||||||
|
|
||||||
// MARK: - Setup
|
// MARK: - Setup
|
||||||
|
|
||||||
override init(annotation: MLNAnnotation?, reuseIdentifier: String?) {
|
override init(annotation: MLNAnnotation?, reuseIdentifier: String?) {
|
||||||
@@ -37,12 +46,21 @@ final class LocationAnnotationView: MLNUserLocationAnnotationView {
|
|||||||
|
|
||||||
convenience init(annotation: LocationAnnotation) {
|
convenience init(annotation: LocationAnnotation) {
|
||||||
self.init(annotation: annotation, reuseIdentifier: "\(Self.self)")
|
self.init(annotation: annotation, reuseIdentifier: "\(Self.self)")
|
||||||
let view: UIView = UIHostingController(rootView: annotation.view).view
|
let hostingController = UIHostingController(rootView: annotation.view)
|
||||||
|
self.hostingController = hostingController
|
||||||
|
let view: UIView = hostingController.view
|
||||||
view.backgroundColor = .clear
|
view.backgroundColor = .clear
|
||||||
view.anchorPoint = annotation.anchorPoint
|
view.anchorPoint = annotation.anchorPoint
|
||||||
addSubview(view)
|
addSubview(view)
|
||||||
view.bounds.size = view.intrinsicContentSize
|
view.bounds.size = view.intrinsicContentSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateContent(with view: AnyView) {
|
||||||
|
hostingController?.rootView = view
|
||||||
|
if let hostedView = hostingController?.view {
|
||||||
|
hostedView.bounds.size = hostedView.intrinsicContentSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@available(*, unavailable)
|
@available(*, unavailable)
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ struct MapLibreMapView: UIViewRepresentable {
|
|||||||
/// The initial map center
|
/// The initial map center
|
||||||
let mapCenter: CLLocationCoordinate2D
|
let mapCenter: CLLocationCoordinate2D
|
||||||
|
|
||||||
/// Map annotations
|
/// Map annotations keyed by a stable identifier (e.g. sender userID for user pins, UUID string for generic pins)
|
||||||
let annotations: [LocationAnnotation]
|
let annotations: [String: LocationAnnotation]
|
||||||
|
|
||||||
init(zoomLevel: Double, initialZoomLevel: Double, mapCenter: CLLocationCoordinate2D, annotations: [LocationAnnotation] = []) {
|
init(zoomLevel: Double, initialZoomLevel: Double, mapCenter: CLLocationCoordinate2D, annotations: [String: LocationAnnotation] = [:]) {
|
||||||
self.zoomLevel = zoomLevel
|
self.zoomLevel = zoomLevel
|
||||||
self.initialZoomLevel = initialZoomLevel
|
self.initialZoomLevel = initialZoomLevel
|
||||||
self.mapCenter = mapCenter
|
self.mapCenter = mapCenter
|
||||||
@@ -45,6 +45,7 @@ struct MapLibreMapView: UIViewRepresentable {
|
|||||||
@Binding var error: MapLibreError?
|
@Binding var error: MapLibreError?
|
||||||
/// Coordinate of the center of the map
|
/// Coordinate of the center of the map
|
||||||
@Binding var mapCenterCoordinate: CLLocationCoordinate2D?
|
@Binding var mapCenterCoordinate: CLLocationCoordinate2D?
|
||||||
|
@Binding var hasLoadedUserLocation: Bool
|
||||||
@Binding var isLocationAuthorized: Bool?
|
@Binding var isLocationAuthorized: Bool?
|
||||||
/// The radius of uncertainty for the location, measured in meters.
|
/// The radius of uncertainty for the location, measured in meters.
|
||||||
@Binding var geolocationUncertainty: CLLocationAccuracy?
|
@Binding var geolocationUncertainty: CLLocationAccuracy?
|
||||||
@@ -70,6 +71,11 @@ struct MapLibreMapView: UIViewRepresentable {
|
|||||||
mapView.styleURL = dynamicMapURL
|
mapView.styleURL = dynamicMapURL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update existing annotation views with fresh SwiftUI content.
|
||||||
|
// This handles the case where the annotation's view data changes after
|
||||||
|
// the annotation was initially placed (e.g. user avatar loads asynchronously).
|
||||||
|
updateAnnotations(in: mapView)
|
||||||
|
|
||||||
showUserLocation(in: mapView)
|
showUserLocation(in: mapView)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,17 +86,52 @@ 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(options.annotations)
|
mapView.addAnnotations(Array(options.annotations.values))
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func updateAnnotations(in mapView: MLNMapView) {
|
||||||
|
let existingByID = Dictionary(uniqueKeysWithValues:
|
||||||
|
(mapView.annotations ?? []).compactMap { $0 as? LocationAnnotation }.map { ($0.id, $0) })
|
||||||
|
|
||||||
|
let existingIDs = Set(existingByID.keys)
|
||||||
|
let updatedIDs = Set(options.annotations.keys)
|
||||||
|
|
||||||
|
// Remove annotations that are no longer present
|
||||||
|
let removedIDs = existingIDs.subtracting(updatedIDs)
|
||||||
|
if !removedIDs.isEmpty {
|
||||||
|
let toRemove = removedIDs.compactMap { existingByID[$0] }
|
||||||
|
mapView.removeAnnotations(toRemove)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new annotations
|
||||||
|
let addedIDs = updatedIDs.subtracting(existingIDs)
|
||||||
|
if !addedIDs.isEmpty {
|
||||||
|
let toAdd = addedIDs.compactMap { options.annotations[$0] }
|
||||||
|
mapView.addAnnotations(toAdd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update existing annotations that are still present
|
||||||
|
let keptIDs = existingIDs.intersection(updatedIDs)
|
||||||
|
for id in keptIDs {
|
||||||
|
guard let existingAnnotation = existingByID[id],
|
||||||
|
let updatedAnnotation = options.annotations[id] else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
existingAnnotation.coordinate = updatedAnnotation.coordinate
|
||||||
|
if let annotationView = mapView.view(for: existingAnnotation) as? LocationAnnotationView {
|
||||||
|
annotationView.updateContent(with: updatedAnnotation.view)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func makeMapView() -> MLNMapView {
|
private func makeMapView() -> MLNMapView {
|
||||||
let mapView = MLNMapView(frame: .zero, styleURL: mapURLBuilder.interactiveMapURL(for: colorScheme == .dark ? .dark : .light))
|
let mapView = MLNMapView(frame: .zero, styleURL: mapURLBuilder.interactiveMapURL(for: colorScheme == .dark ? .dark : .light))
|
||||||
mapView.logoViewPosition = .topLeft
|
mapView.logoViewPosition = .topLeft
|
||||||
mapView.attributionButtonPosition = .topLeft
|
mapView.attributionButtonPosition = .topLeft
|
||||||
mapView.attributionButtonMargins = .init(x: mapView.logoView.frame.maxX + 8, y: mapView.logoView.center.y / 2)
|
mapView.attributionButtonMargins = .init(x: mapView.logoView.frame.maxX + 8, y: mapView.logoView.center.y / 2)
|
||||||
mapView.tintColor = .black
|
mapView.tintColor = .compound.iconAccentPrimary
|
||||||
mapView.allowsRotating = false
|
mapView.allowsRotating = false
|
||||||
mapView.allowsTilting = false
|
mapView.allowsTilting = false
|
||||||
return mapView
|
return mapView
|
||||||
@@ -149,7 +190,8 @@ extension MapLibreMapView {
|
|||||||
|
|
||||||
func mapView(_ mapView: MLNMapView, didUpdate userLocation: MLNUserLocation?) {
|
func mapView(_ mapView: MLNMapView, didUpdate userLocation: MLNUserLocation?) {
|
||||||
guard let userLocation else { return }
|
guard let userLocation else { return }
|
||||||
|
mapLibreView.hasLoadedUserLocation = true
|
||||||
|
|
||||||
if previousUserLocation == nil, mapLibreView.options.annotations.isEmpty {
|
if previousUserLocation == nil, mapLibreView.options.annotations.isEmpty {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||||
mapView.setCenter(userLocation.coordinate, zoomLevel: self.mapLibreView.options.zoomLevel, animated: true)
|
mapView.setCenter(userLocation.coordinate, zoomLevel: self.mapLibreView.options.zoomLevel, animated: true)
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ final class ShareToMapsAppActivity: UIActivity {
|
|||||||
|
|
||||||
private let type: MapsAppType
|
private let type: MapsAppType
|
||||||
private let location: CLLocationCoordinate2D
|
private let location: CLLocationCoordinate2D
|
||||||
private let locationDescription: String?
|
private let senderName: String?
|
||||||
|
|
||||||
init(type: MapsAppType, location: CLLocationCoordinate2D, locationDescription: String?) {
|
init(type: MapsAppType, location: CLLocationCoordinate2D, senderName: String?) {
|
||||||
self.type = type
|
self.type = type
|
||||||
self.location = location
|
self.location = location
|
||||||
self.locationDescription = locationDescription
|
self.senderName = senderName
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,20 +44,20 @@ final class ShareToMapsAppActivity: UIActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func prepare(withActivityItems activityItems: [Any]) {
|
override func prepare(withActivityItems activityItems: [Any]) {
|
||||||
UIApplication.shared.open(type.activityURL(for: location, locationDescription: locationDescription), options: [:]) { [weak self] result in
|
UIApplication.shared.open(type.activityURL(for: location, senderName: senderName), options: [:]) { [weak self] result in
|
||||||
self?.activityDidFinish(result)
|
self?.activityDidFinish(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ShareToMapsAppActivity.MapsAppType {
|
extension ShareToMapsAppActivity.MapsAppType {
|
||||||
func activityURL(for location: CLLocationCoordinate2D, locationDescription: String?) -> URL {
|
func activityURL(for location: CLLocationCoordinate2D, senderName: String?) -> URL {
|
||||||
switch self {
|
switch self {
|
||||||
case .apple:
|
case .apple:
|
||||||
var url: URL = "https://maps.apple.com/"
|
var url: URL = "https://maps.apple.com/"
|
||||||
url.append(queryItems: [
|
url.append(queryItems: [
|
||||||
.init(name: "ll", value: "\(location.latitude),\(location.longitude)"),
|
.init(name: "ll", value: "\(location.latitude),\(location.longitude)"),
|
||||||
.init(name: "q", value: locationDescription ?? "Pin")
|
.init(name: "q", value: senderName ?? "Pin") // We need to provide a value or no marker is displayed.
|
||||||
])
|
])
|
||||||
return url
|
return url
|
||||||
case .google:
|
case .google:
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
//
|
||||||
|
// 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 SwiftUI
|
||||||
|
|
||||||
|
struct RowDivider: ViewModifier {
|
||||||
|
@Environment(\.pixelLength) var pixelLength: CGFloat
|
||||||
|
let alignment: Alignment
|
||||||
|
let horizontalInsets: CGFloat
|
||||||
|
|
||||||
|
func body(content: Content) -> some View {
|
||||||
|
content
|
||||||
|
.overlay(alignment: alignment) {
|
||||||
|
Rectangle()
|
||||||
|
.fill(Color.compound.borderDisabled)
|
||||||
|
.frame(height: pixelLength)
|
||||||
|
.padding(.trailing, -horizontalInsets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension View {
|
||||||
|
func rowDivider(alignment: Alignment = .bottom, horizontalInsets: CGFloat) -> some View {
|
||||||
|
modifier(RowDivider(alignment: alignment, horizontalInsets: horizontalInsets))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,28 +10,84 @@ import Compound
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct LocationMarkerView: View {
|
struct LocationMarkerView: View {
|
||||||
private let pinColor: Color = .compound.iconOnSolidPrimary
|
var userProfile: UserProfileProxy?
|
||||||
private let pinInsets = EdgeInsets(top: 13, leading: 12, bottom: 15, trailing: 12)
|
var fillColor = Color.compound.bgCanvasDefault
|
||||||
|
var strokeColor = Color.compound.iconSecondaryAlpha
|
||||||
|
var dotColor = Color.compound.iconPrimary
|
||||||
|
@ScaledMetric var size: CGFloat = 42
|
||||||
|
var mediaProvider: MediaProviderProtocol?
|
||||||
|
|
||||||
|
private let circleCenter = CGPoint(x: 21, y: 21) // in SVG space
|
||||||
|
private let circleRadius: CGFloat = 6 // in SVG space
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
CompoundIcon(\.locationPinSolid)
|
// Generated from the SVG
|
||||||
.dynamicTypeSize(.large)
|
Canvas { context, canvasSize in
|
||||||
.foregroundStyle(pinColor)
|
let scaleX = canvasSize.width / 42
|
||||||
.padding(pinInsets)
|
let scaleY = canvasSize.height / 50
|
||||||
.background {
|
|
||||||
backgroundShape
|
let pinPath = Path { p in
|
||||||
.shadow(color: .black.opacity(0.2), radius: 4.1129, x: 0, y: 4.93548)
|
p.move(to: CGPoint(x: 21 * scaleX, y: 49 * scaleY))
|
||||||
|
p.addCurve(to: CGPoint(x: 17.6875 * scaleX, y: 47.7581 * scaleY),
|
||||||
|
control1: CGPoint(x: 19.25 * scaleX, y: 49 * scaleY),
|
||||||
|
control2: CGPoint(x: 18.1458 * scaleX, y: 48.4825 * scaleY))
|
||||||
|
p.addCurve(to: CGPoint(x: 5.28125 * scaleX, y: 33.6313 * scaleY),
|
||||||
|
control1: CGPoint(x: 12.5833 * scaleX, y: 42.8525 * scaleY),
|
||||||
|
control2: CGPoint(x: 8.41667 * scaleX, y: 38.1332 * scaleY))
|
||||||
|
p.addCurve(to: CGPoint(x: 1 * scaleX, y: 21.3674 * scaleY),
|
||||||
|
control1: CGPoint(x: 2.82292 * scaleX, y: 29.2846 * scaleY),
|
||||||
|
control2: CGPoint(x: 1 * scaleX, y: 25.1863 * scaleY))
|
||||||
|
p.addCurve(to: CGPoint(x: 21 * scaleX, y: 1 * scaleY),
|
||||||
|
control1: CGPoint(x: 1 * scaleX, y: 10.2109 * scaleY),
|
||||||
|
control2: CGPoint(x: 9.5 * scaleX, y: 1 * scaleY))
|
||||||
|
p.addCurve(to: CGPoint(x: 41 * scaleX, y: 21.3674 * scaleY),
|
||||||
|
control1: CGPoint(x: 32.5 * scaleX, y: 1 * scaleY),
|
||||||
|
control2: CGPoint(x: 41 * scaleX, y: 10.2109 * scaleY))
|
||||||
|
p.addCurve(to: CGPoint(x: 36.7188 * scaleX, y: 33.6313 * scaleY),
|
||||||
|
control1: CGPoint(x: 41 * scaleX, y: 25.1863 * scaleY),
|
||||||
|
control2: CGPoint(x: 39.1771 * scaleX, y: 29.2846 * scaleY))
|
||||||
|
p.addCurve(to: CGPoint(x: 24.3125 * scaleX, y: 47.7581 * scaleY),
|
||||||
|
control1: CGPoint(x: 33.5833 * scaleX, y: 38.1332 * scaleY),
|
||||||
|
control2: CGPoint(x: 29.4167 * scaleX, y: 42.8525 * scaleY))
|
||||||
|
p.addCurve(to: CGPoint(x: 21 * scaleX, y: 49 * scaleY),
|
||||||
|
control1: CGPoint(x: 23.3333 * scaleX, y: 48.4825 * scaleY),
|
||||||
|
control2: CGPoint(x: 21.5833 * scaleX, y: 49 * scaleY))
|
||||||
|
p.closeSubpath()
|
||||||
}
|
}
|
||||||
.alignmentGuide(VerticalAlignment.center) { dimensions in
|
|
||||||
dimensions[.bottom]
|
context.stroke(pinPath, with: .color(strokeColor), lineWidth: 2 * scaleX)
|
||||||
|
context.fill(pinPath, with: .color(fillColor))
|
||||||
|
|
||||||
|
// Dot
|
||||||
|
let dotPath = Path(ellipseIn: CGRect(x: (circleCenter.x - circleRadius) * scaleX,
|
||||||
|
y: (circleCenter.y - circleRadius) * scaleY,
|
||||||
|
width: circleRadius * 2 * scaleX,
|
||||||
|
height: circleRadius * 2 * scaleY))
|
||||||
|
context.fill(dotPath, with: .color(dotColor))
|
||||||
|
|
||||||
|
// Draw resolved symbol centered on the circle
|
||||||
|
if userProfile != nil, let symbol = context.resolveSymbol(id: 0) {
|
||||||
|
let center = CGPoint(x: circleCenter.x * scaleX,
|
||||||
|
y: circleCenter.y * scaleY)
|
||||||
|
context.draw(symbol, at: center, anchor: .center)
|
||||||
}
|
}
|
||||||
}
|
} symbols: {
|
||||||
|
if let userProfile {
|
||||||
var backgroundShape: some View {
|
LoadableAvatarImage(url: userProfile.avatarURL,
|
||||||
Image(asset: Asset.Images.locationMarkerShape)
|
name: userProfile.displayName,
|
||||||
.resizable()
|
contentID: userProfile.userID,
|
||||||
.aspectRatio(contentMode: .fill)
|
avatarSize: .user(on: .map),
|
||||||
.foregroundStyle(.compound.iconPrimary)
|
mediaProvider: mediaProvider)
|
||||||
|
.overlay {
|
||||||
|
Circle().inset(by: 0.5).stroke(strokeColor)
|
||||||
|
}
|
||||||
|
.tag(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(width: size, height: size * 50 / 42)
|
||||||
|
.alignmentGuide(VerticalAlignment.center) { dimensions in
|
||||||
|
dimensions[.bottom]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,9 +95,19 @@ struct LocationMarkerView_Previews: PreviewProvider, TestablePreview {
|
|||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
VStack(spacing: 30) {
|
VStack(spacing: 30) {
|
||||||
LocationMarkerView()
|
LocationMarkerView()
|
||||||
|
|
||||||
LocationMarkerView()
|
LocationMarkerView()
|
||||||
.colorScheme(.dark)
|
.colorScheme(.dark)
|
||||||
|
|
||||||
|
LocationMarkerView(userProfile: UserProfileProxy.mockDan,
|
||||||
|
mediaProvider: MediaProviderMock(configuration: .init()))
|
||||||
|
|
||||||
|
LocationMarkerView(userProfile: UserProfileProxy.mockDan,
|
||||||
|
mediaProvider: MediaProviderMock(configuration: .init()))
|
||||||
|
.colorScheme(.dark)
|
||||||
}
|
}
|
||||||
|
.padding(16)
|
||||||
|
.background(Color(red: 0.9, green: 0.85, blue: 0.8))
|
||||||
|
.previewLayout(.sizeThatFits)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ struct ToolbarButton: View {
|
|||||||
static let cancel = Role.cancel(title: L10n.actionCancel)
|
static let cancel = Role.cancel(title: L10n.actionCancel)
|
||||||
static let done = Role.confirm(title: L10n.actionDone)
|
static let done = Role.confirm(title: L10n.actionDone)
|
||||||
static let save = Role.confirm(title: L10n.actionSave)
|
static let save = Role.confirm(title: L10n.actionSave)
|
||||||
|
static let close = Role.cancel(title: L10n.actionClose)
|
||||||
|
|
||||||
case cancel(title: String)
|
case cancel(title: String)
|
||||||
case confirm(title: String)
|
case confirm(title: String)
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ enum TestablePreviewsDictionary {
|
|||||||
"LoadableImage_Previews" : LoadableImage_Previews.self,
|
"LoadableImage_Previews" : LoadableImage_Previews.self,
|
||||||
"LocationMarkerView_Previews" : LocationMarkerView_Previews.self,
|
"LocationMarkerView_Previews" : LocationMarkerView_Previews.self,
|
||||||
"LocationRoomTimelineView_Previews" : LocationRoomTimelineView_Previews.self,
|
"LocationRoomTimelineView_Previews" : LocationRoomTimelineView_Previews.self,
|
||||||
|
"LocationSharingScreen_Previews" : LocationSharingScreen_Previews.self,
|
||||||
"LoginScreen_Previews" : LoginScreen_Previews.self,
|
"LoginScreen_Previews" : LoginScreen_Previews.self,
|
||||||
"LongPressWithFeedback_Previews" : LongPressWithFeedback_Previews.self,
|
"LongPressWithFeedback_Previews" : LongPressWithFeedback_Previews.self,
|
||||||
"ManageAuthorizedSpacesScreen_Previews" : ManageAuthorizedSpacesScreen_Previews.self,
|
"ManageAuthorizedSpacesScreen_Previews" : ManageAuthorizedSpacesScreen_Previews.self,
|
||||||
@@ -181,7 +182,6 @@ enum TestablePreviewsDictionary {
|
|||||||
"StackedAvatarsView_Previews" : StackedAvatarsView_Previews.self,
|
"StackedAvatarsView_Previews" : StackedAvatarsView_Previews.self,
|
||||||
"StartChatScreen_Previews" : StartChatScreen_Previews.self,
|
"StartChatScreen_Previews" : StartChatScreen_Previews.self,
|
||||||
"StateRoomTimelineView_Previews" : StateRoomTimelineView_Previews.self,
|
"StateRoomTimelineView_Previews" : StateRoomTimelineView_Previews.self,
|
||||||
"StaticLocationScreenViewer_Previews" : StaticLocationScreenViewer_Previews.self,
|
|
||||||
"StickerRoomTimelineView_Previews" : StickerRoomTimelineView_Previews.self,
|
"StickerRoomTimelineView_Previews" : StickerRoomTimelineView_Previews.self,
|
||||||
"SwipeRightAction_Previews" : SwipeRightAction_Previews.self,
|
"SwipeRightAction_Previews" : SwipeRightAction_Previews.self,
|
||||||
"SwipeToReplyView_Previews" : SwipeToReplyView_Previews.self,
|
"SwipeToReplyView_Previews" : SwipeToReplyView_Previews.self,
|
||||||
|
|||||||
@@ -33,12 +33,7 @@ struct HomeScreenRoomCell: View {
|
|||||||
|
|
||||||
content
|
content
|
||||||
.padding(.vertical, verticalInsets)
|
.padding(.vertical, verticalInsets)
|
||||||
.overlay(alignment: .bottom) {
|
.rowDivider(horizontalInsets: horizontalInsets)
|
||||||
Rectangle()
|
|
||||||
.fill(Color.compound.borderDisabled)
|
|
||||||
.frame(height: 1 / UIScreen.main.scale)
|
|
||||||
.padding(.trailing, -horizontalInsets)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.padding(.horizontal, horizontalInsets)
|
.padding(.horizontal, horizontalInsets)
|
||||||
.accessibilityElement(children: .combine)
|
.accessibilityElement(children: .combine)
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2025 Element Creations Ltd.
|
||||||
|
// Copyright 2023-2025 New Vector Ltd.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct LocationSharingScreenCoordinatorParameters {
|
||||||
|
let interactionMode: LocationSharingInteractionMode
|
||||||
|
let mapURLBuilder: MapTilerURLBuilderProtocol
|
||||||
|
let liveLocationSharingEnabled: Bool
|
||||||
|
let roomProxy: JoinedRoomProxyProtocol
|
||||||
|
let timelineController: TimelineControllerProtocol
|
||||||
|
let appMediator: AppMediatorProtocol
|
||||||
|
let analytics: AnalyticsService
|
||||||
|
let userIndicatorController: UserIndicatorControllerProtocol
|
||||||
|
let mediaProvider: MediaProviderProtocol
|
||||||
|
}
|
||||||
|
|
||||||
|
enum LocationSharingScreenCoordinatorAction {
|
||||||
|
case close
|
||||||
|
}
|
||||||
|
|
||||||
|
final class LocationSharingScreenCoordinator: CoordinatorProtocol {
|
||||||
|
private let parameters: LocationSharingScreenCoordinatorParameters
|
||||||
|
private let viewModel: LocationSharingScreenViewModelProtocol
|
||||||
|
|
||||||
|
private let actionsSubject: PassthroughSubject<LocationSharingScreenCoordinatorAction, Never> = .init()
|
||||||
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
var actions: AnyPublisher<LocationSharingScreenCoordinatorAction, Never> {
|
||||||
|
actionsSubject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
init(parameters: LocationSharingScreenCoordinatorParameters) {
|
||||||
|
self.parameters = parameters
|
||||||
|
|
||||||
|
viewModel = LocationSharingScreenViewModel(interactionMode: parameters.interactionMode,
|
||||||
|
mapURLBuilder: parameters.mapURLBuilder,
|
||||||
|
liveLocationSharingEnabled: parameters.liveLocationSharingEnabled,
|
||||||
|
roomProxy: parameters.roomProxy,
|
||||||
|
timelineController: parameters.timelineController,
|
||||||
|
analytics: parameters.analytics,
|
||||||
|
userIndicatorController: parameters.userIndicatorController,
|
||||||
|
mediaProvider: parameters.mediaProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Public
|
||||||
|
|
||||||
|
func start() {
|
||||||
|
viewModel.actions.sink { [weak self] action in
|
||||||
|
guard let self else { return }
|
||||||
|
switch action {
|
||||||
|
case .close:
|
||||||
|
actionsSubject.send(.close)
|
||||||
|
case .openSystemSettings:
|
||||||
|
parameters.appMediator.openAppSettings()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toPresentable() -> AnyView {
|
||||||
|
AnyView(LocationSharingScreen(context: viewModel.context))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,31 +14,44 @@ enum LocationSharingViewError: Error, Hashable {
|
|||||||
case mapError(MapLibreError)
|
case mapError(MapLibreError)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum StaticLocationScreenViewModelAction {
|
enum LocationSharingScreenViewModelAction {
|
||||||
case close
|
case close
|
||||||
case openSystemSettings
|
case openSystemSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
enum StaticLocationInteractionMode: Hashable {
|
enum LocationSharingInteractionMode: Hashable {
|
||||||
case picker
|
case picker
|
||||||
case viewOnly(geoURI: GeoURI, description: String? = nil)
|
case viewStatic(senderID: String?, geoURI: GeoURI)
|
||||||
|
|
||||||
|
var canShowAvatar: Bool {
|
||||||
|
switch self {
|
||||||
|
case .picker, .viewStatic(.some(_), _):
|
||||||
|
true
|
||||||
|
default:
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StaticLocationScreenViewState: BindableState {
|
struct LocationSharingScreenViewState: BindableState {
|
||||||
init(interactionMode: StaticLocationInteractionMode, mapURLBuilder: MapTilerURLBuilderProtocol) {
|
init(interactionMode: LocationSharingInteractionMode,
|
||||||
|
mapURLBuilder: MapTilerURLBuilderProtocol,
|
||||||
|
showLiveLocationSharingButton: Bool) {
|
||||||
self.interactionMode = interactionMode
|
self.interactionMode = interactionMode
|
||||||
self.mapURLBuilder = mapURLBuilder
|
self.mapURLBuilder = mapURLBuilder
|
||||||
|
self.showLiveLocationSharingButton = showLiveLocationSharingButton
|
||||||
|
|
||||||
bindings.showsUserLocationMode = switch interactionMode {
|
bindings.showsUserLocationMode = switch interactionMode {
|
||||||
case .picker: .showAndFollow
|
case .picker: .showAndFollow
|
||||||
case .viewOnly: .show
|
case .viewStatic: .show
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let interactionMode: StaticLocationInteractionMode
|
let interactionMode: LocationSharingInteractionMode
|
||||||
let mapURLBuilder: MapTilerURLBuilderProtocol
|
let mapURLBuilder: MapTilerURLBuilderProtocol
|
||||||
|
let showLiveLocationSharingButton: Bool
|
||||||
|
|
||||||
var bindings = StaticLocationScreenBindings(showsUserLocationMode: .hide)
|
var bindings = LocationSharingScreenBindings(showsUserLocationMode: .hide)
|
||||||
|
|
||||||
/// Indicates whether the user is sharing his current location
|
/// Indicates whether the user is sharing his current location
|
||||||
var isSharingUserLocation: Bool {
|
var isSharingUserLocation: Bool {
|
||||||
@@ -50,21 +63,17 @@ struct StaticLocationScreenViewState: BindableState {
|
|||||||
case .picker:
|
case .picker:
|
||||||
// middle point in Europe, to be used if the users location is not yet known
|
// middle point in Europe, to be used if the users location is not yet known
|
||||||
return .init(latitude: 49.843, longitude: 9.902056)
|
return .init(latitude: 49.843, longitude: 9.902056)
|
||||||
case .viewOnly(let geoURI, _):
|
case .viewStatic(_, let geoURI):
|
||||||
return .init(latitude: geoURI.latitude, longitude: geoURI.longitude)
|
return .init(latitude: geoURI.latitude, longitude: geoURI.longitude)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var isLocationPickerMode: Bool {
|
var isLocationPickerMode: Bool {
|
||||||
interactionMode == .picker
|
|
||||||
}
|
|
||||||
|
|
||||||
var navigationTitle: String {
|
|
||||||
switch interactionMode {
|
switch interactionMode {
|
||||||
case .picker:
|
case .picker:
|
||||||
return L10n.screenShareLocationTitle
|
true
|
||||||
case .viewOnly:
|
default:
|
||||||
return L10n.screenViewLocationTitle
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,10 +81,14 @@ struct StaticLocationScreenViewState: BindableState {
|
|||||||
switch interactionMode {
|
switch interactionMode {
|
||||||
case .picker:
|
case .picker:
|
||||||
return false
|
return false
|
||||||
case .viewOnly:
|
case .viewStatic:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isLocationLoading: Bool {
|
||||||
|
!bindings.hasLoadedUserLocation && bindings.isLocationAuthorized != false
|
||||||
|
}
|
||||||
|
|
||||||
var zoomLevel: Double {
|
var zoomLevel: Double {
|
||||||
15.0
|
15.0
|
||||||
@@ -85,27 +98,28 @@ struct StaticLocationScreenViewState: BindableState {
|
|||||||
switch interactionMode {
|
switch interactionMode {
|
||||||
case .picker:
|
case .picker:
|
||||||
return 2.7
|
return 2.7
|
||||||
case .viewOnly:
|
case .viewStatic:
|
||||||
return 15.0
|
return 15.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var locationDescription: String? {
|
var userProfile: UserProfileProxy?
|
||||||
|
|
||||||
|
var shownUserProfile: UserProfileProxy? {
|
||||||
switch interactionMode {
|
switch interactionMode {
|
||||||
case .picker:
|
case .picker:
|
||||||
return nil
|
isSharingUserLocation ? userProfile : nil
|
||||||
case .viewOnly(_, let description):
|
case .viewStatic:
|
||||||
return description
|
userProfile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StaticLocationScreenBindings {
|
struct LocationSharingScreenBindings {
|
||||||
var mapCenterLocation: CLLocationCoordinate2D?
|
var mapCenterLocation: CLLocationCoordinate2D?
|
||||||
var geolocationUncertainty: CLLocationAccuracy?
|
var geolocationUncertainty: CLLocationAccuracy?
|
||||||
|
|
||||||
var showsUserLocationMode: ShowUserLocationMode
|
var showsUserLocationMode: ShowUserLocationMode
|
||||||
|
var hasLoadedUserLocation = false
|
||||||
var isLocationAuthorized: Bool?
|
var isLocationAuthorized: Bool?
|
||||||
|
|
||||||
/// Information describing the currently displayed alert.
|
/// Information describing the currently displayed alert.
|
||||||
@@ -127,7 +141,7 @@ struct StaticLocationScreenBindings {
|
|||||||
var showShareSheet = false
|
var showShareSheet = false
|
||||||
}
|
}
|
||||||
|
|
||||||
enum StaticLocationScreenViewAction {
|
enum LocationSharingScreenViewAction {
|
||||||
case close
|
case close
|
||||||
case selectLocation
|
case selectLocation
|
||||||
case centerToUser
|
case centerToUser
|
||||||
@@ -141,20 +155,18 @@ extension AlertInfo where T == LocationSharingViewError {
|
|||||||
switch error {
|
switch error {
|
||||||
case .missingAuthorization:
|
case .missingAuthorization:
|
||||||
self.init(id: error,
|
self.init(id: error,
|
||||||
title: L10n.dialogPermissionLocationTitleIos(InfoPlistReader.main.bundleDisplayName),
|
title: L10n.dialogAllowAccess,
|
||||||
message: L10n.dialogPermissionLocationDescriptionIos,
|
message: L10n.dialogPermissionLocationDescriptionIos(InfoPlistReader.main.bundleDisplayName),
|
||||||
primaryButton: primaryButton,
|
primaryButton: primaryButton,
|
||||||
secondaryButton: secondaryButton)
|
secondaryButton: secondaryButton)
|
||||||
case .mapError(.failedLoadingMap):
|
case .mapError(.failedLoadingMap):
|
||||||
self.init(id: error,
|
self.init(id: error,
|
||||||
title: "",
|
title: L10n.errorFailedLoadingMap(InfoPlistReader.main.bundleDisplayName),
|
||||||
message: L10n.errorFailedLoadingMap(InfoPlistReader.main.bundleDisplayName),
|
|
||||||
primaryButton: primaryButton,
|
primaryButton: primaryButton,
|
||||||
secondaryButton: secondaryButton)
|
secondaryButton: secondaryButton)
|
||||||
case .mapError(.failedLocatingUser):
|
case .mapError(.failedLocatingUser):
|
||||||
self.init(id: error,
|
self.init(id: error,
|
||||||
title: "",
|
title: L10n.errorFailedLocatingUser(InfoPlistReader.main.bundleDisplayName),
|
||||||
message: L10n.errorFailedLocatingUser(InfoPlistReader.main.bundleDisplayName),
|
|
||||||
primaryButton: primaryButton,
|
primaryButton: primaryButton,
|
||||||
secondaryButton: secondaryButton)
|
secondaryButton: secondaryButton)
|
||||||
}
|
}
|
||||||
|
|||||||
+47
-8
@@ -9,31 +9,44 @@
|
|||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
typealias StaticLocationScreenViewModelType = StateStoreViewModelV2<StaticLocationScreenViewState, StaticLocationScreenViewAction>
|
typealias LocationSharingScreenViewModelType = StateStoreViewModelV2<LocationSharingScreenViewState, LocationSharingScreenViewAction>
|
||||||
|
|
||||||
class StaticLocationScreenViewModel: StaticLocationScreenViewModelType, StaticLocationScreenViewModelProtocol {
|
class LocationSharingScreenViewModel: LocationSharingScreenViewModelType, LocationSharingScreenViewModelProtocol {
|
||||||
|
private let roomProxy: JoinedRoomProxyProtocol
|
||||||
private let timelineController: TimelineControllerProtocol
|
private let timelineController: TimelineControllerProtocol
|
||||||
private let analytics: AnalyticsService
|
private let analytics: AnalyticsService
|
||||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||||
|
|
||||||
private let actionsSubject: PassthroughSubject<StaticLocationScreenViewModelAction, Never> = .init()
|
private let actionsSubject: PassthroughSubject<LocationSharingScreenViewModelAction, Never> = .init()
|
||||||
var actions: AnyPublisher<StaticLocationScreenViewModelAction, Never> {
|
var actions: AnyPublisher<LocationSharingScreenViewModelAction, Never> {
|
||||||
actionsSubject.eraseToAnyPublisher()
|
actionsSubject.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
init(interactionMode: StaticLocationInteractionMode,
|
init(interactionMode: LocationSharingInteractionMode,
|
||||||
mapURLBuilder: MapTilerURLBuilderProtocol,
|
mapURLBuilder: MapTilerURLBuilderProtocol,
|
||||||
|
liveLocationSharingEnabled: Bool,
|
||||||
|
roomProxy: JoinedRoomProxyProtocol,
|
||||||
timelineController: TimelineControllerProtocol,
|
timelineController: TimelineControllerProtocol,
|
||||||
analytics: AnalyticsService,
|
analytics: AnalyticsService,
|
||||||
userIndicatorController: UserIndicatorControllerProtocol) {
|
userIndicatorController: UserIndicatorControllerProtocol,
|
||||||
|
mediaProvider: MediaProviderProtocol) {
|
||||||
|
self.roomProxy = roomProxy
|
||||||
self.timelineController = timelineController
|
self.timelineController = timelineController
|
||||||
self.analytics = analytics
|
self.analytics = analytics
|
||||||
self.userIndicatorController = userIndicatorController
|
self.userIndicatorController = userIndicatorController
|
||||||
|
|
||||||
super.init(initialViewState: .init(interactionMode: interactionMode, mapURLBuilder: mapURLBuilder))
|
super.init(initialViewState: .init(interactionMode: interactionMode,
|
||||||
|
mapURLBuilder: mapURLBuilder,
|
||||||
|
showLiveLocationSharingButton: liveLocationSharingEnabled),
|
||||||
|
mediaProvider: mediaProvider)
|
||||||
|
|
||||||
|
if interactionMode.canShowAvatar {
|
||||||
|
updateShownUserProfile(members: roomProxy.membersPublisher.value)
|
||||||
|
setupSubscriptions()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func process(viewAction: StaticLocationScreenViewAction) {
|
override func process(viewAction: LocationSharingScreenViewAction) {
|
||||||
switch viewAction {
|
switch viewAction {
|
||||||
case .close:
|
case .close:
|
||||||
actionsSubject.send(.close)
|
actionsSubject.send(.close)
|
||||||
@@ -58,6 +71,32 @@ class StaticLocationScreenViewModel: StaticLocationScreenViewModelType, StaticLo
|
|||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
|
private func setupSubscriptions() {
|
||||||
|
roomProxy.membersPublisher.sink { [weak self] members in
|
||||||
|
self?.updateShownUserProfile(members: members)
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateShownUserProfile(members: [RoomMemberProxyProtocol]) {
|
||||||
|
switch state.interactionMode {
|
||||||
|
case .picker:
|
||||||
|
if let ownUser = members.first(where: { $0.userID == roomProxy.ownUserID }).map(UserProfileProxy.init) {
|
||||||
|
state.userProfile = ownUser
|
||||||
|
} else {
|
||||||
|
state.userProfile = .init(userID: roomProxy.ownUserID)
|
||||||
|
}
|
||||||
|
case .viewStatic(.some(let senderID), _):
|
||||||
|
if let sender = members.first(where: { $0.userID == senderID }).map(UserProfileProxy.init) {
|
||||||
|
state.userProfile = sender
|
||||||
|
} else {
|
||||||
|
state.userProfile = .init(userID: senderID)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
state.userProfile = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func sendLocation(_ geoURI: GeoURI, isUserLocation: Bool) async {
|
private func sendLocation(_ geoURI: GeoURI, isUserLocation: Bool) async {
|
||||||
guard case .success = await timelineController.sendLocation(body: geoURI.bodyMessage,
|
guard case .success = await timelineController.sendLocation(body: geoURI.bodyMessage,
|
||||||
geoURI: geoURI,
|
geoURI: geoURI,
|
||||||
+3
-3
@@ -9,7 +9,7 @@
|
|||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
protocol StaticLocationScreenViewModelProtocol {
|
protocol LocationSharingScreenViewModelProtocol {
|
||||||
var actions: AnyPublisher<StaticLocationScreenViewModelAction, Never> { get }
|
var actions: AnyPublisher<LocationSharingScreenViewModelAction, Never> { get }
|
||||||
var context: StaticLocationScreenViewModelType.Context { get }
|
var context: LocationSharingScreenViewModelType.Context { get }
|
||||||
}
|
}
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2025 Element Creations Ltd.
|
|
||||||
// Copyright 2023-2025 New Vector Ltd.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
|
||||||
// Please see LICENSE files in the repository root for full details.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Combine
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct StaticLocationScreenCoordinatorParameters {
|
|
||||||
let interactionMode: StaticLocationInteractionMode
|
|
||||||
let mapURLBuilder: MapTilerURLBuilderProtocol
|
|
||||||
let timelineController: TimelineControllerProtocol
|
|
||||||
let appMediator: AppMediatorProtocol
|
|
||||||
let analytics: AnalyticsService
|
|
||||||
let userIndicatorController: UserIndicatorControllerProtocol
|
|
||||||
}
|
|
||||||
|
|
||||||
enum StaticLocationScreenCoordinatorAction {
|
|
||||||
case close
|
|
||||||
}
|
|
||||||
|
|
||||||
final class StaticLocationScreenCoordinator: CoordinatorProtocol {
|
|
||||||
private let parameters: StaticLocationScreenCoordinatorParameters
|
|
||||||
private let viewModel: StaticLocationScreenViewModelProtocol
|
|
||||||
|
|
||||||
private let actionsSubject: PassthroughSubject<StaticLocationScreenCoordinatorAction, Never> = .init()
|
|
||||||
private var cancellables = Set<AnyCancellable>()
|
|
||||||
|
|
||||||
var actions: AnyPublisher<StaticLocationScreenCoordinatorAction, Never> {
|
|
||||||
actionsSubject.eraseToAnyPublisher()
|
|
||||||
}
|
|
||||||
|
|
||||||
init(parameters: StaticLocationScreenCoordinatorParameters) {
|
|
||||||
self.parameters = parameters
|
|
||||||
|
|
||||||
viewModel = StaticLocationScreenViewModel(interactionMode: parameters.interactionMode,
|
|
||||||
mapURLBuilder: parameters.mapURLBuilder,
|
|
||||||
timelineController: parameters.timelineController,
|
|
||||||
analytics: parameters.analytics,
|
|
||||||
userIndicatorController: parameters.userIndicatorController)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Public
|
|
||||||
|
|
||||||
func start() {
|
|
||||||
viewModel.actions.sink { [weak self] action in
|
|
||||||
guard let self else { return }
|
|
||||||
switch action {
|
|
||||||
case .close:
|
|
||||||
actionsSubject.send(.close)
|
|
||||||
case .openSystemSettings:
|
|
||||||
parameters.appMediator.openAppSettings()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.store(in: &cancellables)
|
|
||||||
}
|
|
||||||
|
|
||||||
func toPresentable() -> AnyView {
|
|
||||||
AnyView(StaticLocationScreen(context: viewModel.context))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,264 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2025 Element Creations Ltd.
|
||||||
|
// Copyright 2023-2025 New Vector Ltd.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Compound
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct LocationSharingScreen: View {
|
||||||
|
@Bindable var context: LocationSharingScreenViewModel.Context
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
if context.viewState.isLocationPickerMode {
|
||||||
|
mainContent
|
||||||
|
.sheet(isPresented: .constant(true)) {
|
||||||
|
sharingOptionsSheet
|
||||||
|
.alert(item: $context.alertInfo)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mainContent
|
||||||
|
.alert(item: $context.alertInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private
|
||||||
|
|
||||||
|
private var mainContent: some View {
|
||||||
|
mapView
|
||||||
|
.ignoresSafeArea(edges: .bottom)
|
||||||
|
.track(screen: context.viewState.isLocationPickerMode ? .LocationSend : .LocationView)
|
||||||
|
.navigationTitle(L10n.screenViewLocationTitle)
|
||||||
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
.toolbar { toolbar }
|
||||||
|
}
|
||||||
|
|
||||||
|
private var mapView: some View {
|
||||||
|
ZStack(alignment: .center) {
|
||||||
|
MapLibreMapView(mapURLBuilder: context.viewState.mapURLBuilder,
|
||||||
|
options: mapOptions,
|
||||||
|
showsUserLocationMode: $context.showsUserLocationMode,
|
||||||
|
error: $context.mapError,
|
||||||
|
mapCenterCoordinate: $context.mapCenterLocation,
|
||||||
|
hasLoadedUserLocation: $context.hasLoadedUserLocation,
|
||||||
|
isLocationAuthorized: $context.isLocationAuthorized,
|
||||||
|
geolocationUncertainty: $context.geolocationUncertainty) {
|
||||||
|
context.send(viewAction: .userDidPan)
|
||||||
|
}
|
||||||
|
.ignoresSafeArea(.all, edges: mapSafeAreaEdges)
|
||||||
|
|
||||||
|
if context.viewState.isLocationPickerMode {
|
||||||
|
LocationMarkerView(userProfile: context.viewState.shownUserProfile, mediaProvider: context.mediaProvider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.overlay(alignment: .topTrailing) {
|
||||||
|
centerToUserLocationButton
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ToolbarContentBuilder
|
||||||
|
private var toolbar: some ToolbarContent {
|
||||||
|
ToolbarItem(placement: context.viewState.showShareAction ? .topBarLeading : .topBarTrailing) {
|
||||||
|
ToolbarButton(role: .close) {
|
||||||
|
context.send(viewAction: .close)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if context.viewState.showShareAction {
|
||||||
|
ToolbarItem(placement: .topBarTrailing) {
|
||||||
|
Button {
|
||||||
|
context.showShareSheet = true
|
||||||
|
} label: {
|
||||||
|
Image(systemName: "square.and.arrow.up")
|
||||||
|
}
|
||||||
|
.popover(isPresented: $context.showShareSheet) { shareSheet }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var mapOptions: MapLibreMapView.Options {
|
||||||
|
var annotations: [String: LocationAnnotation] = [:]
|
||||||
|
if !context.viewState.isLocationPickerMode {
|
||||||
|
let id = context.viewState.shownUserProfile?.userID ?? UUID().uuidString
|
||||||
|
let annotation = LocationAnnotation(id: id,
|
||||||
|
coordinate: context.viewState.initialMapCenter,
|
||||||
|
anchorPoint: .bottomCenter) {
|
||||||
|
LocationMarkerView(userProfile: context.viewState.shownUserProfile, mediaProvider: context.mediaProvider)
|
||||||
|
}
|
||||||
|
annotations[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
|
||||||
|
private var centerToUseIcon: some View {
|
||||||
|
if context.viewState.isLocationLoading {
|
||||||
|
ProgressView()
|
||||||
|
.tint(.compound.iconPrimary)
|
||||||
|
.padding(13)
|
||||||
|
} else {
|
||||||
|
CompoundIcon(context.viewState.isSharingUserLocation ? \.locationNavigatorCentred : \.locationNavigator)
|
||||||
|
.foregroundStyle(.compound.iconPrimary)
|
||||||
|
.padding(13)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var centerToUserLocationButton: some View {
|
||||||
|
Button {
|
||||||
|
context.send(viewAction: .centerToUser)
|
||||||
|
} label: {
|
||||||
|
if #available(iOS 26.0, *) {
|
||||||
|
centerToUseIcon
|
||||||
|
.glassEffect(.regular.interactive(), in: Circle())
|
||||||
|
.tint(.compound.bgCanvasDefault)
|
||||||
|
} else {
|
||||||
|
centerToUseIcon
|
||||||
|
.background(.compound.bgCanvasDefault, in: RoundedRectangle(cornerRadius: 6))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.disabled(context.viewState.isLocationLoading)
|
||||||
|
.dynamicTypeSize(.large)
|
||||||
|
.padding(13)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var shareSheet: some View {
|
||||||
|
let location = context.viewState.initialMapCenter
|
||||||
|
let senderName = context.viewState.shownUserProfile?.displayName
|
||||||
|
AppActivityView(activityItems: [ShareToMapsAppActivity.MapsAppType.apple.activityURL(for: location, senderName: senderName)],
|
||||||
|
applicationActivities: ShareToMapsAppActivity.MapsAppType.allCases.map { ShareToMapsAppActivity(type: $0, location: location, senderName: senderName) })
|
||||||
|
.edgesIgnoringSafeArea(.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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@State private var sharingOptionsSheetHeight: CGFloat = .zero
|
||||||
|
|
||||||
|
private var sharingOptionsSheet: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
|
Button {
|
||||||
|
context.send(viewAction: .selectLocation)
|
||||||
|
} label: {
|
||||||
|
if context.viewState.isSharingUserLocation {
|
||||||
|
LocationSharingLabel(text: L10n.screenShareMyLocationAction,
|
||||||
|
icon: \.locationNavigatorCentred,
|
||||||
|
iconColor: .compound.iconSecondary)
|
||||||
|
} else {
|
||||||
|
LocationSharingLabel(text: L10n.screenShareThisLocationAction,
|
||||||
|
icon: \.locationNavigator,
|
||||||
|
iconColor: .compound.iconSecondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if context.viewState.showLiveLocationSharingButton {
|
||||||
|
Button { } label: {
|
||||||
|
LocationSharingLabel(text: L10n.actionShareLiveLocation,
|
||||||
|
icon: \.locationPinSolid,
|
||||||
|
iconColor: .compound.iconAccentPrimary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.font(.compound.bodyLG)
|
||||||
|
.foregroundStyle(.compound.textPrimary)
|
||||||
|
.padding(.top, 38)
|
||||||
|
.readHeight($sharingOptionsSheetHeight)
|
||||||
|
.interactiveDismissDisabled()
|
||||||
|
.presentationBackground(.compound.bgCanvasDefault)
|
||||||
|
.presentationBackgroundInteraction(.enabled)
|
||||||
|
.presentationDragIndicator(.hidden)
|
||||||
|
.presentationDetents([.height(sharingOptionsSheetHeight)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct LocationSharingLabel: View {
|
||||||
|
let text: String
|
||||||
|
let icon: KeyPath<CompoundIcons, Image>
|
||||||
|
let iconColor: Color
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Label {
|
||||||
|
Text(text)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
.padding(.vertical, 14)
|
||||||
|
.rowDivider(alignment: .top, horizontalInsets: 16.0)
|
||||||
|
} icon: {
|
||||||
|
CompoundIcon(icon)
|
||||||
|
.foregroundStyle(iconColor)
|
||||||
|
}
|
||||||
|
.padding(.leading, 16)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Previews
|
||||||
|
|
||||||
|
struct LocationSharingScreen_Previews: PreviewProvider, TestablePreview {
|
||||||
|
static let viewModel = LocationSharingScreenViewModel(interactionMode: .viewStatic(senderID: "@dan:matrix.org", geoURI: .init(latitude: 41.9027835,
|
||||||
|
longitude: 12.4963655)),
|
||||||
|
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
|
||||||
|
liveLocationSharingEnabled: true,
|
||||||
|
roomProxy: JoinedRoomProxyMock(.init()),
|
||||||
|
timelineController: MockTimelineController(),
|
||||||
|
analytics: ServiceLocator.shared.analytics,
|
||||||
|
userIndicatorController: UserIndicatorControllerMock(),
|
||||||
|
mediaProvider: MediaProviderMock(configuration: .init()))
|
||||||
|
|
||||||
|
static let pinViewModel = LocationSharingScreenViewModel(interactionMode: .viewStatic(senderID: nil, geoURI: .init(latitude: 41.9027835,
|
||||||
|
longitude: 12.4963655)),
|
||||||
|
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
|
||||||
|
liveLocationSharingEnabled: true,
|
||||||
|
roomProxy: JoinedRoomProxyMock(.init()),
|
||||||
|
timelineController: MockTimelineController(),
|
||||||
|
analytics: ServiceLocator.shared.analytics,
|
||||||
|
userIndicatorController: UserIndicatorControllerMock(),
|
||||||
|
mediaProvider: MediaProviderMock(configuration: .init()))
|
||||||
|
|
||||||
|
static let pickerViewModel = LocationSharingScreenViewModel(interactionMode: .picker,
|
||||||
|
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
|
||||||
|
liveLocationSharingEnabled: true,
|
||||||
|
roomProxy: JoinedRoomProxyMock(.init()),
|
||||||
|
timelineController: MockTimelineController(),
|
||||||
|
analytics: ServiceLocator.shared.analytics,
|
||||||
|
userIndicatorController: UserIndicatorControllerMock(),
|
||||||
|
mediaProvider: MediaProviderMock(configuration: .init()))
|
||||||
|
|
||||||
|
static var previews: some View {
|
||||||
|
ElementNavigationStack {
|
||||||
|
LocationSharingScreen(context: pickerViewModel.context)
|
||||||
|
}
|
||||||
|
.previewDisplayName("Picker")
|
||||||
|
|
||||||
|
ElementNavigationStack {
|
||||||
|
LocationSharingScreen(context: viewModel.context)
|
||||||
|
}
|
||||||
|
.previewDisplayName("User Static Location")
|
||||||
|
|
||||||
|
ElementNavigationStack {
|
||||||
|
LocationSharingScreen(context: pinViewModel.context)
|
||||||
|
}
|
||||||
|
.previewDisplayName("Pin Static Location")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension CGPoint {
|
||||||
|
static let bottomCenter: Self = .init(x: 0.5, y: 1)
|
||||||
|
}
|
||||||
@@ -1,198 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2025 Element Creations Ltd.
|
|
||||||
// Copyright 2023-2025 New Vector Ltd.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
|
||||||
// Please see LICENSE files in the repository root for full details.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Compound
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct StaticLocationScreen: View {
|
|
||||||
@Bindable var context: StaticLocationScreenViewModel.Context
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
VStack(spacing: 0) {
|
|
||||||
if let locationDescription = context.viewState.locationDescription {
|
|
||||||
Text(locationDescription)
|
|
||||||
.lineLimit(2)
|
|
||||||
.foregroundColor(Color.compound.textPrimary)
|
|
||||||
.font(.compound.bodyMD)
|
|
||||||
.padding(.horizontal, 16)
|
|
||||||
.padding(.vertical, 8)
|
|
||||||
}
|
|
||||||
mapView
|
|
||||||
}
|
|
||||||
.track(screen: context.viewState.isLocationPickerMode ? .LocationSend : .LocationView)
|
|
||||||
.navigationTitle(context.viewState.navigationTitle)
|
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
|
||||||
.toolbar { toolbar }
|
|
||||||
.alert(item: $context.alertInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var mapView: some View {
|
|
||||||
ZStack(alignment: .center) {
|
|
||||||
MapLibreMapView(mapURLBuilder: context.viewState.mapURLBuilder,
|
|
||||||
options: mapOptions,
|
|
||||||
showsUserLocationMode: $context.showsUserLocationMode,
|
|
||||||
error: $context.mapError,
|
|
||||||
mapCenterCoordinate: $context.mapCenterLocation,
|
|
||||||
isLocationAuthorized: $context.isLocationAuthorized,
|
|
||||||
geolocationUncertainty: $context.geolocationUncertainty) {
|
|
||||||
context.send(viewAction: .userDidPan)
|
|
||||||
}
|
|
||||||
.ignoresSafeArea(.all, edges: mapSafeAreaEdges)
|
|
||||||
|
|
||||||
if context.viewState.isLocationPickerMode {
|
|
||||||
LocationMarkerView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.overlay(alignment: .bottomTrailing) {
|
|
||||||
centerToUserLocationButton
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Private
|
|
||||||
|
|
||||||
@ToolbarContentBuilder
|
|
||||||
private var toolbar: some ToolbarContent {
|
|
||||||
ToolbarItem(placement: .navigationBarLeading) {
|
|
||||||
closeButton
|
|
||||||
}
|
|
||||||
|
|
||||||
if context.viewState.showShareAction {
|
|
||||||
ToolbarItem(placement: .navigationBarTrailing) {
|
|
||||||
shareButton
|
|
||||||
.popover(isPresented: $context.showShareSheet) { shareSheet }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if context.viewState.isLocationPickerMode {
|
|
||||||
ToolbarItemGroup(placement: .bottomBar) {
|
|
||||||
selectLocationButton
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var mapOptions: MapLibreMapView.Options {
|
|
||||||
var annotations: [LocationAnnotation] = []
|
|
||||||
if context.viewState.isLocationPickerMode == false {
|
|
||||||
let annotation = LocationAnnotation(coordinate: context.viewState.initialMapCenter, anchorPoint: .bottomCenter) {
|
|
||||||
LocationMarkerView()
|
|
||||||
}
|
|
||||||
annotations.append(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]
|
|
||||||
}
|
|
||||||
|
|
||||||
private var selectLocationButton: some View {
|
|
||||||
Button {
|
|
||||||
context.send(viewAction: .selectLocation)
|
|
||||||
} label: {
|
|
||||||
HStack(spacing: 8) {
|
|
||||||
CompoundIcon(\.shareIos)
|
|
||||||
Text(context.viewState.isSharingUserLocation ? L10n.screenShareMyLocationAction : L10n.screenShareThisLocationAction)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var centerToUserLocationButton: some View {
|
|
||||||
Button {
|
|
||||||
context.send(viewAction: .centerToUser)
|
|
||||||
} label: {
|
|
||||||
CompoundIcon(context.viewState.isSharingUserLocation ? \.locationNavigatorCentred : \.locationNavigator)
|
|
||||||
.padding(8)
|
|
||||||
.background(.compound.bgCanvasDefault, in: RoundedRectangle(cornerRadius: 6))
|
|
||||||
}
|
|
||||||
.dynamicTypeSize(.large)
|
|
||||||
.padding(16)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var closeButton: some View {
|
|
||||||
Button(L10n.actionCancel) {
|
|
||||||
context.send(viewAction: .close)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var shareButton: some View {
|
|
||||||
Button {
|
|
||||||
context.showShareSheet = true
|
|
||||||
} label: {
|
|
||||||
Image(systemName: "square.and.arrow.up")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private var shareSheet: some View {
|
|
||||||
let location = context.viewState.initialMapCenter
|
|
||||||
let locationDescription = context.viewState.locationDescription
|
|
||||||
AppActivityView(activityItems: [ShareToMapsAppActivity.MapsAppType.apple.activityURL(for: location, locationDescription: locationDescription)],
|
|
||||||
applicationActivities: ShareToMapsAppActivity.MapsAppType.allCases.map { ShareToMapsAppActivity(type: $0, location: location, locationDescription: locationDescription) })
|
|
||||||
.edgesIgnoringSafeArea(.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
|
|
||||||
|
|
||||||
struct StaticLocationScreenViewer_Previews: PreviewProvider, TestablePreview {
|
|
||||||
static let viewModel = StaticLocationScreenViewModel(interactionMode: .viewOnly(geoURI: .init(latitude: 41.9027835,
|
|
||||||
longitude: 12.4963655)),
|
|
||||||
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
|
|
||||||
timelineController: MockTimelineController(),
|
|
||||||
analytics: ServiceLocator.shared.analytics,
|
|
||||||
userIndicatorController: UserIndicatorControllerMock())
|
|
||||||
static let pickerViewModel = StaticLocationScreenViewModel(interactionMode: .picker,
|
|
||||||
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
|
|
||||||
timelineController: MockTimelineController(),
|
|
||||||
analytics: ServiceLocator.shared.analytics,
|
|
||||||
userIndicatorController: UserIndicatorControllerMock())
|
|
||||||
static let descriptionViewModel = StaticLocationScreenViewModel(interactionMode: .viewOnly(geoURI: .init(latitude: 41.9027835,
|
|
||||||
longitude: 12.4963655),
|
|
||||||
description: "Cool position"),
|
|
||||||
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
|
|
||||||
timelineController: MockTimelineController(),
|
|
||||||
analytics: ServiceLocator.shared.analytics,
|
|
||||||
userIndicatorController: UserIndicatorControllerMock())
|
|
||||||
|
|
||||||
static var previews: some View {
|
|
||||||
ElementNavigationStack {
|
|
||||||
StaticLocationScreen(context: pickerViewModel.context)
|
|
||||||
}
|
|
||||||
.previewDisplayName("Picker")
|
|
||||||
|
|
||||||
ElementNavigationStack {
|
|
||||||
StaticLocationScreen(context: viewModel.context)
|
|
||||||
}
|
|
||||||
.previewDisplayName("View Only")
|
|
||||||
|
|
||||||
ElementNavigationStack {
|
|
||||||
StaticLocationScreen(context: descriptionViewModel.context)
|
|
||||||
}
|
|
||||||
.previewDisplayName("View Only (with description)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private extension CGPoint {
|
|
||||||
static let bottomCenter: Self = .init(x: 0.5, y: 1)
|
|
||||||
}
|
|
||||||
+4
-3
@@ -26,7 +26,7 @@ struct PinnedEventsTimelineScreenCoordinatorParameters {
|
|||||||
enum PinnedEventsTimelineScreenCoordinatorAction {
|
enum PinnedEventsTimelineScreenCoordinatorAction {
|
||||||
case dismiss
|
case dismiss
|
||||||
case displayUser(userID: String)
|
case displayUser(userID: String)
|
||||||
case presentLocationViewer(geoURI: GeoURI, description: String?)
|
case presentLocationViewer(senderID: String?, geoURI: GeoURI)
|
||||||
case displayMessageForwarding(forwardingItem: MessageForwardingItem)
|
case displayMessageForwarding(forwardingItem: MessageForwardingItem)
|
||||||
case displayRoomScreenWithFocussedPin(eventID: String, threadRootEventID: String?)
|
case displayRoomScreenWithFocussedPin(eventID: String, threadRootEventID: String?)
|
||||||
}
|
}
|
||||||
@@ -87,8 +87,9 @@ final class PinnedEventsTimelineScreenCoordinator: CoordinatorProtocol {
|
|||||||
actionsSubject.send(.displayMessageForwarding(forwardingItem: forwardingItem))
|
actionsSubject.send(.displayMessageForwarding(forwardingItem: forwardingItem))
|
||||||
case .displayMediaPreview(let mediaPreviewViewModel):
|
case .displayMediaPreview(let mediaPreviewViewModel):
|
||||||
viewModel.displayMediaPreview(mediaPreviewViewModel)
|
viewModel.displayMediaPreview(mediaPreviewViewModel)
|
||||||
case .displayLocation(_, let geoURI, let description):
|
case .displayLocation(let senderID, let geoURI):
|
||||||
actionsSubject.send(.presentLocationViewer(geoURI: geoURI, description: description))
|
actionsSubject.send(.presentLocationViewer(senderID: senderID,
|
||||||
|
geoURI: geoURI))
|
||||||
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
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ enum RoomScreenCoordinatorAction {
|
|||||||
case presentRoomDetails
|
case presentRoomDetails
|
||||||
case presentLocationPicker
|
case presentLocationPicker
|
||||||
case presentPollForm(mode: PollFormMode)
|
case presentPollForm(mode: PollFormMode)
|
||||||
case presentLocationViewer(body: String, geoURI: GeoURI, description: String?)
|
case presentLocationViewer(senderID: String?, geoURI: GeoURI)
|
||||||
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)
|
||||||
@@ -137,8 +137,8 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
|
|||||||
actionsSubject.send(.presentRoomMemberDetails(userID: userID))
|
actionsSubject.send(.presentRoomMemberDetails(userID: userID))
|
||||||
case .displayMessageForwarding(let forwardingItem):
|
case .displayMessageForwarding(let forwardingItem):
|
||||||
actionsSubject.send(.presentMessageForwarding(forwardingItem: forwardingItem))
|
actionsSubject.send(.presentMessageForwarding(forwardingItem: forwardingItem))
|
||||||
case .displayLocation(let body, let geoURI, let description):
|
case .displayLocation(let senderID, let geoURI):
|
||||||
actionsSubject.send(.presentLocationViewer(body: body, geoURI: geoURI, description: description))
|
actionsSubject.send(.presentLocationViewer(senderID: senderID, geoURI: geoURI))
|
||||||
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):
|
||||||
|
|||||||
+2
@@ -67,6 +67,8 @@ protocol DeveloperOptionsProtocol: AnyObject {
|
|||||||
var linkPreviewsEnabled: Bool { get set }
|
var linkPreviewsEnabled: Bool { get set }
|
||||||
|
|
||||||
var linkNewDeviceEnabled: Bool { get set }
|
var linkNewDeviceEnabled: Bool { get set }
|
||||||
|
|
||||||
|
var liveLocationSharingEnabled: Bool { get set }
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AppSettings: DeveloperOptionsProtocol { }
|
extension AppSettings: DeveloperOptionsProtocol { }
|
||||||
|
|||||||
+4
@@ -76,6 +76,10 @@ struct DeveloperOptionsScreen: View {
|
|||||||
Text("Can leak the device IP address when loading link metadata.")
|
Text("Can leak the device IP address when loading link metadata.")
|
||||||
.foregroundStyle(.compound.textCriticalPrimary)
|
.foregroundStyle(.compound.textCriticalPrimary)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Toggle(isOn: $context.liveLocationSharingEnabled) {
|
||||||
|
Text("Live location sharing")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Section("Join rules") {
|
Section("Join rules") {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ enum ThreadTimelineScreenCoordinatorAction {
|
|||||||
case presentMediaUploadPicker(mode: MediaPickerScreenMode)
|
case presentMediaUploadPicker(mode: MediaPickerScreenMode)
|
||||||
case presentMediaUploadPreviewScreen(mediaURLs: [URL])
|
case presentMediaUploadPreviewScreen(mediaURLs: [URL])
|
||||||
case presentLocationPicker
|
case presentLocationPicker
|
||||||
case presentLocationViewer(body: String, geoURI: GeoURI, description: String?)
|
case presentLocationViewer(senderID: String?, geoURI: GeoURI)
|
||||||
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)
|
||||||
@@ -118,10 +118,9 @@ final class ThreadTimelineScreenCoordinator: CoordinatorProtocol {
|
|||||||
viewModel.displayMediaPreview(mediaPreviewViewModel)
|
viewModel.displayMediaPreview(mediaPreviewViewModel)
|
||||||
case .displayLocationPicker:
|
case .displayLocationPicker:
|
||||||
actionsSubject.send(.presentLocationPicker)
|
actionsSubject.send(.presentLocationPicker)
|
||||||
case .displayLocation(let body, let geoURI, let description):
|
case .displayLocation(let senderID, let geoURI):
|
||||||
actionsSubject.send(.presentLocationViewer(body: body,
|
actionsSubject.send(.presentLocationViewer(senderID: senderID,
|
||||||
geoURI: geoURI,
|
geoURI: geoURI))
|
||||||
description: description))
|
|
||||||
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):
|
||||||
|
|||||||
@@ -536,7 +536,8 @@ class TimelineInteractionHandler {
|
|||||||
switch timelineItem {
|
switch timelineItem {
|
||||||
case let item as LocationRoomTimelineItem:
|
case let item as LocationRoomTimelineItem:
|
||||||
guard let geoURI = item.content.geoURI else { return .none }
|
guard let geoURI = item.content.geoURI else { return .none }
|
||||||
return .displayLocation(body: item.content.body, geoURI: geoURI, description: item.content.description)
|
return .displayLocation(senderID: item.content.kind == .sender ? item.sender.id : nil,
|
||||||
|
geoURI: geoURI)
|
||||||
case is ImageRoomTimelineItem,
|
case is ImageRoomTimelineItem,
|
||||||
is VideoRoomTimelineItem:
|
is VideoRoomTimelineItem:
|
||||||
return await mediaPreviewAction(for: timelineItem, messageTypes: [.image, .video])
|
return await mediaPreviewAction(for: timelineItem, messageTypes: [.image, .video])
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ enum TimelineViewModelAction {
|
|||||||
case displaySenderDetails(userID: String)
|
case displaySenderDetails(userID: String)
|
||||||
case displayMessageForwarding(forwardingItem: MessageForwardingItem)
|
case displayMessageForwarding(forwardingItem: MessageForwardingItem)
|
||||||
case displayMediaPreview(TimelineMediaPreviewViewModel)
|
case displayMediaPreview(TimelineMediaPreviewViewModel)
|
||||||
case displayLocation(body: String, geoURI: GeoURI, description: String?)
|
case displayLocation(senderID: String?, geoURI: GeoURI)
|
||||||
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)
|
||||||
|
|||||||
@@ -655,8 +655,8 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
|||||||
|
|
||||||
let mediaPreviewViewModel = makeMediaPreviewViewModel(item: item, timelineViewModelKind: timelineViewModelKind)
|
let mediaPreviewViewModel = makeMediaPreviewViewModel(item: item, timelineViewModelKind: timelineViewModelKind)
|
||||||
actionsSubject.send(.displayMediaPreview(mediaPreviewViewModel))
|
actionsSubject.send(.displayMediaPreview(mediaPreviewViewModel))
|
||||||
case .displayLocation(let body, let geoURI, let description):
|
case .displayLocation(let senderID, let geoURI):
|
||||||
actionsSubject.send(.displayLocation(body: body, geoURI: geoURI, description: description))
|
actionsSubject.send(.displayLocation(senderID: senderID, geoURI: geoURI))
|
||||||
case .none:
|
case .none:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -705,20 +705,7 @@ private struct MockTimelineContent: View {
|
|||||||
sender: .init(id: "Bob"),
|
sender: .init(id: "Bob"),
|
||||||
content: .init(body: "Fallback geo uri description",
|
content: .init(body: "Fallback geo uri description",
|
||||||
geoURI: .init(latitude: 41.902782,
|
geoURI: .init(latitude: 41.902782,
|
||||||
longitude: 12.496366),
|
longitude: 12.496366)),
|
||||||
description: "Location description description description description description description description description"),
|
|
||||||
properties: .init(replyDetails: replyDetails,
|
|
||||||
isThreaded: isThreaded,
|
|
||||||
threadSummary: threadSummary)))
|
|
||||||
|
|
||||||
LocationRoomTimelineView(timelineItem: .init(id: makeItemIdentifier(),
|
|
||||||
timestamp: .mock,
|
|
||||||
isOutgoing: false,
|
|
||||||
isEditable: false,
|
|
||||||
canBeRepliedTo: true,
|
|
||||||
sender: .init(id: "Bob"),
|
|
||||||
content: .init(body: "Fallback geo uri description",
|
|
||||||
geoURI: .init(latitude: 41.902782, longitude: 12.496366), description: nil),
|
|
||||||
properties: .init(replyDetails: replyDetails,
|
properties: .init(replyDetails: replyDetails,
|
||||||
isThreaded: isThreaded,
|
isThreaded: isThreaded,
|
||||||
threadSummary: threadSummary)))
|
threadSummary: threadSummary)))
|
||||||
|
|||||||
+12
-32
@@ -16,7 +16,7 @@ struct LocationRoomTimelineView: View {
|
|||||||
TimelineStyler(timelineItem: timelineItem) {
|
TimelineStyler(timelineItem: timelineItem) {
|
||||||
mainContent
|
mainContent
|
||||||
.accessibilityElement(children: .ignore)
|
.accessibilityElement(children: .ignore)
|
||||||
.accessibilityLabel(accessibilityLabel)
|
.accessibilityLabel(L10n.commonSharedLocation)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
guard context.viewState.mapTilerConfiguration.isEnabled else { return }
|
guard context.viewState.mapTilerConfiguration.isEnabled else { return }
|
||||||
context.send(viewAction: .mediaTapped(itemID: timelineItem.id))
|
context.send(viewAction: .mediaTapped(itemID: timelineItem.id))
|
||||||
@@ -27,41 +27,20 @@ struct LocationRoomTimelineView: View {
|
|||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var mainContent: some View {
|
private var mainContent: some View {
|
||||||
if let geoURI = timelineItem.content.geoURI {
|
if let geoURI = timelineItem.content.geoURI {
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
MapLibreStaticMapView(geoURI: geoURI,
|
||||||
descriptionView
|
mapURLBuilder: context.viewState.mapTilerConfiguration,
|
||||||
.frame(maxWidth: mapAspectRatio * mapMaxHeight, alignment: .leading)
|
mapSize: .init(width: mapAspectRatio * mapMaxHeight, height: mapMaxHeight)) {
|
||||||
|
LocationMarkerView(userProfile: timelineItem.content.kind == .sender ? .init(sender: timelineItem.sender) : nil, mediaProvider: context.mediaProvider)
|
||||||
MapLibreStaticMapView(geoURI: geoURI,
|
|
||||||
mapURLBuilder: context.viewState.mapTilerConfiguration,
|
|
||||||
mapSize: .init(width: mapAspectRatio * mapMaxHeight, height: mapMaxHeight)) {
|
|
||||||
LocationMarkerView()
|
|
||||||
}
|
|
||||||
.frame(maxHeight: mapMaxHeight)
|
|
||||||
.aspectRatio(mapAspectRatio, contentMode: .fit)
|
|
||||||
.clipped()
|
|
||||||
}
|
}
|
||||||
|
.frame(maxHeight: mapMaxHeight)
|
||||||
|
.aspectRatio(mapAspectRatio, contentMode: .fit)
|
||||||
|
.clipped()
|
||||||
} else {
|
} else {
|
||||||
FormattedBodyText(text: timelineItem.body, additionalWhitespacesCount: timelineItem.additionalWhitespaces())
|
FormattedBodyText(text: timelineItem.body, additionalWhitespacesCount: timelineItem.additionalWhitespaces())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
private var accessibilityLabel: String {
|
|
||||||
if let description = timelineItem.content.description {
|
|
||||||
return "\(L10n.commonSharedLocation), \(description)"
|
|
||||||
}
|
|
||||||
|
|
||||||
return L10n.commonSharedLocation
|
|
||||||
}
|
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private var descriptionView: some View {
|
|
||||||
if let description = timelineItem.content.description, !description.isEmpty {
|
|
||||||
FormattedBodyText(text: description)
|
|
||||||
.padding(8)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private let mapAspectRatio: Double = 3 / 2
|
private let mapAspectRatio: Double = 3 / 2
|
||||||
private let mapMaxHeight: Double = 300
|
private let mapMaxHeight: Double = 300
|
||||||
@@ -107,9 +86,9 @@ struct LocationRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
canBeRepliedTo: true,
|
canBeRepliedTo: true,
|
||||||
sender: .init(id: "Bob"),
|
sender: .init(id: "@bob:matrix.org", displayName: "Bob", avatarURL: .mockMXCUserAvatar),
|
||||||
content: .init(body: "Fallback geo uri description",
|
content: .init(body: "Fallback geo uri description",
|
||||||
geoURI: .init(latitude: 41.902782, longitude: 12.496366), description: "Location description description description description description description description description")))
|
geoURI: .init(latitude: 41.902782, longitude: 12.496366))))
|
||||||
LocationRoomTimelineView(timelineItem: .init(id: .randomEvent,
|
LocationRoomTimelineView(timelineItem: .init(id: .randomEvent,
|
||||||
timestamp: .mock,
|
timestamp: .mock,
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
@@ -117,7 +96,8 @@ struct LocationRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
canBeRepliedTo: true,
|
canBeRepliedTo: true,
|
||||||
sender: .init(id: "Bob"),
|
sender: .init(id: "Bob"),
|
||||||
content: .init(body: "Fallback geo uri description",
|
content: .init(body: "Fallback geo uri description",
|
||||||
geoURI: .init(latitude: 41.902782, longitude: 12.496366), description: "Location description description description description description description description description"),
|
geoURI: .init(latitude: 41.902782, longitude: 12.496366),
|
||||||
|
kind: .pin),
|
||||||
properties: .init(replyDetails: .loaded(sender: .init(id: "Someone"),
|
properties: .init(replyDetails: .loaded(sender: .init(id: "Someone"),
|
||||||
eventID: "123",
|
eventID: "123",
|
||||||
eventContent: .message(.text(.init(body: "The thread content goes 'ere.")))),
|
eventContent: .message(.text(.init(body: "The thread content goes 'ere.")))),
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ enum TimelineControllerAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case displayMediaPreview(item: EventBasedMessageTimelineItemProtocol, timelineViewModel: TimelineViewModelKind)
|
case displayMediaPreview(item: EventBasedMessageTimelineItemProtocol, timelineViewModel: TimelineViewModelKind)
|
||||||
case displayLocation(body: String, geoURI: GeoURI, description: String?)
|
case displayLocation(senderID: String?, geoURI: GeoURI)
|
||||||
case none
|
case none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+19
-3
@@ -6,16 +6,32 @@
|
|||||||
// Please see LICENSE files in the repository root for full details.
|
// Please see LICENSE files in the repository root for full details.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import MatrixRustSDK
|
||||||
|
|
||||||
struct LocationRoomTimelineItemContent: Hashable {
|
struct LocationRoomTimelineItemContent: Hashable {
|
||||||
|
enum Kind {
|
||||||
|
case sender
|
||||||
|
case pin
|
||||||
|
|
||||||
|
init(from asset: AssetType?) {
|
||||||
|
self = switch asset {
|
||||||
|
case .pin:
|
||||||
|
.pin
|
||||||
|
case .sender, .none:
|
||||||
|
.sender
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let body: String
|
let body: String
|
||||||
let geoURI: GeoURI?
|
let geoURI: GeoURI?
|
||||||
let description: String?
|
let kind: Kind
|
||||||
|
|
||||||
init(body: String,
|
init(body: String,
|
||||||
geoURI: GeoURI? = nil,
|
geoURI: GeoURI? = nil,
|
||||||
description: String? = nil) {
|
kind: Kind = .sender) {
|
||||||
self.body = body
|
self.body = body
|
||||||
self.geoURI = geoURI
|
self.geoURI = geoURI
|
||||||
self.description = description
|
self.kind = kind
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -583,7 +583,7 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
|||||||
private func buildLocationTimelineItemContent(_ locationContent: LocationContent) -> LocationRoomTimelineItemContent {
|
private func buildLocationTimelineItemContent(_ locationContent: LocationContent) -> LocationRoomTimelineItemContent {
|
||||||
LocationRoomTimelineItemContent(body: locationContent.body,
|
LocationRoomTimelineItemContent(body: locationContent.body,
|
||||||
geoURI: .init(string: locationContent.geoUri),
|
geoURI: .init(string: locationContent.geoUri),
|
||||||
description: locationContent.description)
|
kind: .init(from: locationContent.asset))
|
||||||
}
|
}
|
||||||
|
|
||||||
private func buildFileTimelineItemContent(_ messageContent: FileMessageContent) -> FileRoomTimelineItemContent {
|
private func buildFileTimelineItemContent(_ messageContent: FileMessageContent) -> FileRoomTimelineItemContent {
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ struct UserProfileProxy: Equatable, Hashable {
|
|||||||
avatarURL = sdkRoomHero.avatarUrl.flatMap(URL.init(string:))
|
avatarURL = sdkRoomHero.avatarUrl.flatMap(URL.init(string:))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init(member: RoomMemberProxyProtocol) {
|
||||||
|
self.init(member: RoomMemberDetails(withProxy: member))
|
||||||
|
}
|
||||||
|
|
||||||
/// A user is meant to be "verified" when the GET profile returns back either the display name or the avatar
|
/// A user is meant to be "verified" when the GET profile returns back either the display name or the avatar
|
||||||
/// If isn't we aren't sure that the related matrix id really exists.
|
/// If isn't we aren't sure that the related matrix id really exists.
|
||||||
var isVerified: Bool {
|
var isVerified: Bool {
|
||||||
|
|||||||
@@ -603,6 +603,14 @@ extension PreviewTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
func locationSharingScreen() async throws {
|
||||||
|
AppSettings.resetAllSettings() // Ensure this test's previews start with fresh settings.
|
||||||
|
for (index, preview) in LocationSharingScreen_Previews._allPreviews.enumerated() {
|
||||||
|
try await assertSnapshots(matching: preview, step: index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
func loginScreen() async throws {
|
func loginScreen() async throws {
|
||||||
AppSettings.resetAllSettings() // Ensure this test's previews start with fresh settings.
|
AppSettings.resetAllSettings() // Ensure this test's previews start with fresh settings.
|
||||||
@@ -1387,14 +1395,6 @@ extension PreviewTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
func staticLocationScreenViewer() async throws {
|
|
||||||
AppSettings.resetAllSettings() // Ensure this test's previews start with fresh settings.
|
|
||||||
for (index, preview) in StaticLocationScreenViewer_Previews._allPreviews.enumerated() {
|
|
||||||
try await assertSnapshots(matching: preview, step: index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
func stickerRoomTimelineView() async throws {
|
func stickerRoomTimelineView() async throws {
|
||||||
AppSettings.resetAllSettings() // Ensure this test's previews start with fresh settings.
|
AppSettings.resetAllSettings() // Ensure this test's previews start with fresh settings.
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:43c010abad7474002e5830bf5332ae068c82deaa789ba26f0aa3cb26d61edb25
|
oid sha256:c00139208711b767a8f19c563bc7cef80314c3382ce5ce7d481a71d5ef70df1a
|
||||||
size 82843
|
size 69042
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:43c010abad7474002e5830bf5332ae068c82deaa789ba26f0aa3cb26d61edb25
|
oid sha256:c00139208711b767a8f19c563bc7cef80314c3382ce5ce7d481a71d5ef70df1a
|
||||||
size 82843
|
size 69042
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:6275a174efe2615503282742972c952b8a66e0d00bfbb806b8eea3f2ffee9b27
|
oid sha256:5dcaa6876ed9b9ef600f3c8327aed5a1b5e87cfc3990994d2b44d89973597c2f
|
||||||
size 40724
|
size 51341
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:6275a174efe2615503282742972c952b8a66e0d00bfbb806b8eea3f2ffee9b27
|
oid sha256:5dcaa6876ed9b9ef600f3c8327aed5a1b5e87cfc3990994d2b44d89973597c2f
|
||||||
size 40724
|
size 51341
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:7fb62383066a45ae514f8736f6ea08b8a5c0bab0c231836613ff57d1ddb95975
|
oid sha256:71845ef91726086a8b88816e8535cbf5bbdd82e0de0d5a0ca9ebca75c376944b
|
||||||
size 1027619
|
size 1227270
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:8575f49f01e82cbca9366dab9b31954df18e0c8a2fc267225fc3ca9d93286695
|
oid sha256:9a8b87ca66a0447bf808b4ef2d67569f1a88fbc798073eefd56fcb39d4f126d3
|
||||||
size 1029185
|
size 1228934
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:667d2b653d460a351e8c9b1adf708532d215b465ecfe3548409a1de3abc12ba5
|
oid sha256:edeeccdfbfb21821ad3eb56836d92e78e2f36516ffbf8cdd9ab7b068a9b2b68c
|
||||||
size 607504
|
size 580022
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:547c133de43262b6e4a3a91231af8ed39af98357dd7962df14dc8011379100a7
|
oid sha256:410475fefb08e8e59d5f5e6c3b25a6ce8d220dd819a51708ead024754f4ece73
|
||||||
size 580526
|
size 580183
|
||||||
|
|||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:64737509400fe27cdb017b8f66cffe8c0807f958827cff84a9ce5484db0ca3fc
|
||||||
|
size 80109
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:64737509400fe27cdb017b8f66cffe8c0807f958827cff84a9ce5484db0ca3fc
|
||||||
|
size 80109
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:08e72ae0c7d34108690371b29952267b1ac06bb62f203515f3c5e4143efd2ca8
|
||||||
|
size 38511
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:08e72ae0c7d34108690371b29952267b1ac06bb62f203515f3c5e4143efd2ca8
|
||||||
|
size 38511
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:cbf4a51ed98c176336fc2e5be99311342bdae0d931d5d78dabca0ace3dd3a85b
|
||||||
|
size 80783
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:cbf4a51ed98c176336fc2e5be99311342bdae0d931d5d78dabca0ace3dd3a85b
|
||||||
|
size 80783
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:117ab2273ccfba15cee5546e521a85b87c8f7b915b869a299234c7d1a0caecd2
|
||||||
|
size 41622
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:117ab2273ccfba15cee5546e521a85b87c8f7b915b869a299234c7d1a0caecd2
|
||||||
|
size 41622
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:b4635f42e9d912d20f4963c5c3627f543cb00f95183fa0e902c9cc61b1afc921
|
||||||
|
size 93073
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:b4635f42e9d912d20f4963c5c3627f543cb00f95183fa0e902c9cc61b1afc921
|
||||||
|
size 93073
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:c68d58d06123afaa7e02fc798b2360e1818c450fd277b275308d5704203e5547
|
||||||
|
size 53102
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:c68d58d06123afaa7e02fc798b2360e1818c450fd277b275308d5704203e5547
|
||||||
|
size 53102
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:7fe3be6ac7144e77a64deea2ec9abe990b7066df18bf693018e3cbbac95f7b19
|
|
||||||
size 92909
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:29136dedce23b9175a539c68f190f339972cfeedd51714b2d7dbcd487c0918c1
|
|
||||||
size 94512
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:dd7467f8fecb694a44d88e404999373428dd5b0909f9a821a8cbc9961f132b59
|
|
||||||
size 46905
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:c3cd2e0746b0f78394304c614d9a80cd15392986a58b4b64eaa36757997aff42
|
|
||||||
size 48123
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:1fed42a97d568cc0d024afb9be2c7c8ae2359a88f1335b307ab5b8cbe0929f59
|
|
||||||
size 88451
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:79e7bdc97b95baf9ec65240a09543d1efa7a6f0ee8178a0ad24ec7fa25f4fbcf
|
|
||||||
size 88813
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:8dc6d6f2dcdac244d56349c4d432e43c281e539a83769e4711ebfa43d5b62462
|
|
||||||
size 42173
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:8dc6d6f2dcdac244d56349c4d432e43c281e539a83769e4711ebfa43d5b62462
|
|
||||||
size 42173
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:3ec7064466b5a91fd490c9aebdcfb36efbc2a585b86998725bcd90e2c280c726
|
|
||||||
size 91675
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:241dd732058072774947a9aa0dbd7c6bf410608ba8b4e1733942161feb7d725e
|
|
||||||
size 92048
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:763523520732699428fcf758b36119ff450d13b6f69b250e5c977651ae06d05e
|
|
||||||
size 45091
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:763523520732699428fcf758b36119ff450d13b6f69b250e5c977651ae06d05e
|
|
||||||
size 45091
|
|
||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:d4c2e14e3362efa21a236c61fa17fe94c14f08c35965cc68cc7375e837b63e6e
|
oid sha256:7905d4da975ca2f8c8ba13afc3112081360e1c2586e780e0bf7f63e79f11e907
|
||||||
size 2459797
|
size 1816558
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:3bed8adcdeed91791208203243bec9edab8c6cf233538382a6775e5b997f2970
|
oid sha256:6f225a517befd7486ca940036f0b32b051471e6179dddc1afec04027f0e5a34b
|
||||||
size 2458950
|
size 1815989
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:39e3c3ea4d8f07c295f6c716e568e4900c4fe3977ac008728d63a5679f8f1099
|
oid sha256:711bdb8bba6cf0b1148695e599599a34b137bfb41577ccf53f70402c188f7336
|
||||||
size 1032059
|
size 762444
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:1aadd13737eb2768c20d5cd48fcb503120275ce73ef27ee3ec151ac5629be78c
|
oid sha256:bc8677193d2595d5d6993d2e39c40b74fd033e02ac952da52dfc320824b857b0
|
||||||
size 1029398
|
size 760909
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:89b62418f7c716f317fb3d0faee0ed5271cc99166740f517bb9082639465c618
|
oid sha256:8a3e77518c1d7225d0d89ac5d94f3a050721abb0320ac94c7768a64d9f8064c0
|
||||||
size 2574127
|
size 1912810
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:bb2a87744f36cd3317bfa0e79a8f0bc3f2a5077751b4da2e039c0c9edb23c149
|
oid sha256:648eb3d7089c0ce01bc4d20cddd0f0092421d78f2a0f483135b30f4d1bc5e665
|
||||||
size 2585620
|
size 1919591
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:a122378791c1f44057926bf054374e6f31eb3b4644438a7f3df988f62e8422aa
|
oid sha256:6ec385fa56fdea70874f4ec43623561cba05f1b2c13633a46d560974e8487cb0
|
||||||
size 1154014
|
size 865130
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:1752a98b3ddfa33cd8ee71fe2a49146b9a87d222fbad6fc41b4615d112948032
|
oid sha256:918a059719a7ff6f3974664904e9ce6473241a20907ebefda0c40561e6235823
|
||||||
size 1157827
|
size 868790
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:68bbaa372d7ef0f92176d530311c8484370aa38c7227a3a1f2dd7ed4d45240fc
|
oid sha256:f1a2e2ed1e99b2ff6b92fe5ea4cf70af039ed09c542ede3f471e88f3d8883a2c
|
||||||
size 2575915
|
size 1916887
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:b8cecf8be430f6efbe9451a6a1b4e6e2df8e3140e7a4fcea3c0a22e85e846d41
|
oid sha256:ad75f5eb536ef43505a9713b17d64424451b5f4136795ff72e6318f2cc74998b
|
||||||
size 2601396
|
size 1939145
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:0a86e9f58d2cde2339de39905762d92f57f8447896e16f24afa1adbd8329fd40
|
oid sha256:7f33ce5a5b646d0de6f7d57a86ec2cd4ffa2c0a88c99f0607b4388aff3ba7099
|
||||||
size 1259715
|
size 944690
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:09fb516ddcf8ab30b8ded663a15dec446cc932f9173ecdeb09a7b68d9d7515e6
|
oid sha256:44fb917f17f99ea73143c6f81c4a935e5f5d6de51ff6dccb61eb44e6a006b2f9
|
||||||
size 1259289
|
size 945021
|
||||||
|
|||||||
+14
-11
@@ -11,20 +11,23 @@ import Combine
|
|||||||
import Testing
|
import Testing
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
struct StaticLocationScreenViewModelTests {
|
struct LocationSharingScreenViewModelTests {
|
||||||
private let timelineProxy = TimelineProxyMock(.init())
|
private let timelineProxy = TimelineProxyMock(.init())
|
||||||
private var viewModel: StaticLocationScreenViewModelProtocol
|
private var viewModel: LocationSharingScreenViewModelProtocol
|
||||||
|
|
||||||
private var context: StaticLocationScreenViewModel.Context {
|
private var context: LocationSharingScreenViewModel.Context {
|
||||||
viewModel.context
|
viewModel.context
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
let viewModel = StaticLocationScreenViewModel(interactionMode: .picker,
|
let viewModel = LocationSharingScreenViewModel(interactionMode: .picker,
|
||||||
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
|
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
|
||||||
timelineController: MockTimelineController(timelineProxy: timelineProxy),
|
liveLocationSharingEnabled: true,
|
||||||
analytics: ServiceLocator.shared.analytics,
|
roomProxy: JoinedRoomProxyMock(.init()),
|
||||||
userIndicatorController: UserIndicatorControllerMock())
|
timelineController: MockTimelineController(timelineProxy: timelineProxy),
|
||||||
|
analytics: ServiceLocator.shared.analytics,
|
||||||
|
userIndicatorController: UserIndicatorControllerMock(),
|
||||||
|
mediaProvider: MediaProviderMock(configuration: .init()))
|
||||||
viewModel.state.bindings.isLocationAuthorized = true
|
viewModel.state.bindings.isLocationAuthorized = true
|
||||||
self.viewModel = viewModel
|
self.viewModel = viewModel
|
||||||
}
|
}
|
||||||
@@ -68,11 +71,11 @@ struct StaticLocationScreenViewModelTests {
|
|||||||
@Test
|
@Test
|
||||||
func errorMapping() {
|
func errorMapping() {
|
||||||
let mapError = AlertInfo(locationSharingViewError: .mapError(.failedLoadingMap))
|
let mapError = AlertInfo(locationSharingViewError: .mapError(.failedLoadingMap))
|
||||||
#expect(mapError.message == L10n.errorFailedLoadingMap(InfoPlistReader.main.bundleDisplayName))
|
#expect(mapError.title == L10n.errorFailedLoadingMap(InfoPlistReader.main.bundleDisplayName))
|
||||||
let locationError = AlertInfo(locationSharingViewError: .mapError(.failedLocatingUser))
|
let locationError = AlertInfo(locationSharingViewError: .mapError(.failedLocatingUser))
|
||||||
#expect(locationError.message == L10n.errorFailedLocatingUser(InfoPlistReader.main.bundleDisplayName))
|
#expect(locationError.title == L10n.errorFailedLocatingUser(InfoPlistReader.main.bundleDisplayName))
|
||||||
let authorizationError = AlertInfo(locationSharingViewError: .missingAuthorization)
|
let authorizationError = AlertInfo(locationSharingViewError: .missingAuthorization)
|
||||||
#expect(authorizationError.message == L10n.dialogPermissionLocationDescriptionIos)
|
#expect(authorizationError.message == L10n.dialogPermissionLocationDescriptionIos(InfoPlistReader.main.bundleDisplayName))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
Reference in New Issue
Block a user