mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 21:39:12 +00:00
Require acknowledgement to send to verified users who have unsigned devices or have changed their identity. (#3215)
* Refactor HeroImage style. * Add a screen to resolve (crypto-related) timeline item send failures. * Refactor send failures. * Update the SDK.
This commit is contained in:
parent
f6c8aae09e
commit
cc4942fb78
@ -55,6 +55,7 @@
|
|||||||
09713669577CDA8D012EE380 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 6647C55D93508C7CE9D954A5 /* MatrixRustSDK */; };
|
09713669577CDA8D012EE380 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 6647C55D93508C7CE9D954A5 /* MatrixRustSDK */; };
|
||||||
09AAF04B27732046C755D914 /* SoftLogoutViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32C5DAA1773F57653BF1C4F9 /* SoftLogoutViewModelTests.swift */; };
|
09AAF04B27732046C755D914 /* SoftLogoutViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32C5DAA1773F57653BF1C4F9 /* SoftLogoutViewModelTests.swift */; };
|
||||||
09C83DDDB07C28364F325209 /* MockRoomTimelineController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D7074991B3267B26D89B22 /* MockRoomTimelineController.swift */; };
|
09C83DDDB07C28364F325209 /* MockRoomTimelineController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D7074991B3267B26D89B22 /* MockRoomTimelineController.swift */; };
|
||||||
|
09D3D7D115318CAD131B4FE7 /* ResolveVerifiedUserSendFailureScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57084488B03BDB33C7B7CA0E /* ResolveVerifiedUserSendFailureScreenViewModelTests.swift */; };
|
||||||
0A194F5E70B5A628C1BF4476 /* AdvancedSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4999B5FD50AED7CB0F590FF8 /* AdvancedSettingsScreenModels.swift */; };
|
0A194F5E70B5A628C1BF4476 /* AdvancedSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4999B5FD50AED7CB0F590FF8 /* AdvancedSettingsScreenModels.swift */; };
|
||||||
0ACAA31FD0399CEEBA3ECC21 /* UserDetailsEditScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85149F56BA333619900E2410 /* UserDetailsEditScreenViewModelProtocol.swift */; };
|
0ACAA31FD0399CEEBA3ECC21 /* UserDetailsEditScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85149F56BA333619900E2410 /* UserDetailsEditScreenViewModelProtocol.swift */; };
|
||||||
0AE0AB1952F186EB86719B4F /* HomeScreenRoomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */; };
|
0AE0AB1952F186EB86719B4F /* HomeScreenRoomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */; };
|
||||||
@ -80,6 +81,7 @@
|
|||||||
0EE5EBA18BA1FE10254BB489 /* UIFont+AttributedStringBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = E8CA187FE656EE5A3F6C7DE5 /* UIFont+AttributedStringBuilder.m */; };
|
0EE5EBA18BA1FE10254BB489 /* UIFont+AttributedStringBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = E8CA187FE656EE5A3F6C7DE5 /* UIFont+AttributedStringBuilder.m */; };
|
||||||
0EEC614342F823E5BF966C2C /* AppLockTimerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A5B4CD611DE7E94F5BA87B2 /* AppLockTimerTests.swift */; };
|
0EEC614342F823E5BF966C2C /* AppLockTimerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A5B4CD611DE7E94F5BA87B2 /* AppLockTimerTests.swift */; };
|
||||||
0F6C8033FA60CFD36F7CA205 /* AppLockSetupPINScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A019A12C866D64CF072024B9 /* AppLockSetupPINScreenViewModel.swift */; };
|
0F6C8033FA60CFD36F7CA205 /* AppLockSetupPINScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A019A12C866D64CF072024B9 /* AppLockSetupPINScreenViewModel.swift */; };
|
||||||
|
108D3C0707A90B0F848CDBB9 /* ResolveVerifiedUserSendFailureScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60011EF0086E49DBD78E16E5 /* ResolveVerifiedUserSendFailureScreenModels.swift */; };
|
||||||
109AEB7D33C4497727AFB87F /* TimelineInteractionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BA894BC09972DC45E497D37 /* TimelineInteractionHandler.swift */; };
|
109AEB7D33C4497727AFB87F /* TimelineInteractionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BA894BC09972DC45E497D37 /* TimelineInteractionHandler.swift */; };
|
||||||
10D60D287025B71F4743A425 /* RoomDirectorySearchProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 471BB7276C97AF60B3A5463B /* RoomDirectorySearchProxy.swift */; };
|
10D60D287025B71F4743A425 /* RoomDirectorySearchProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 471BB7276C97AF60B3A5463B /* RoomDirectorySearchProxy.swift */; };
|
||||||
1146E9EDCF8344F7D6E0D553 /* MockCoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0376C429FAB1687C3D905F3E /* MockCoder.swift */; };
|
1146E9EDCF8344F7D6E0D553 /* MockCoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0376C429FAB1687C3D905F3E /* MockCoder.swift */; };
|
||||||
@ -310,6 +312,7 @@
|
|||||||
46BA7F4B4D3A7164DED44B88 /* FullscreenDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 565F1B2B300597C616B37888 /* FullscreenDialog.swift */; };
|
46BA7F4B4D3A7164DED44B88 /* FullscreenDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 565F1B2B300597C616B37888 /* FullscreenDialog.swift */; };
|
||||||
46C9F8FE3810A04A005FE16B /* AudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B19B2BCC779ED934E0BBC2A /* AudioPlayer.swift */; };
|
46C9F8FE3810A04A005FE16B /* AudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B19B2BCC779ED934E0BBC2A /* AudioPlayer.swift */; };
|
||||||
46FCD999E92D9717D24AAB94 /* QRCodeLoginScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDEDD4D2DE0646DA724985D5 /* QRCodeLoginScreenModels.swift */; };
|
46FCD999E92D9717D24AAB94 /* QRCodeLoginScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDEDD4D2DE0646DA724985D5 /* QRCodeLoginScreenModels.swift */; };
|
||||||
|
4715FE33667C5899E64DD0E6 /* ResolveVerifiedUserSendFailureScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97287090CA64DAA95386ECED /* ResolveVerifiedUserSendFailureScreen.swift */; };
|
||||||
4716587A9BA69ED8FD1B986B /* PollOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6B19D10B102956066AF117B /* PollOptionView.swift */; };
|
4716587A9BA69ED8FD1B986B /* PollOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6B19D10B102956066AF117B /* PollOptionView.swift */; };
|
||||||
47305C0911C9E1AA774A4000 /* TemplateScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA90BD288E5AE6BC643AFDDF /* TemplateScreenCoordinator.swift */; };
|
47305C0911C9E1AA774A4000 /* TemplateScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA90BD288E5AE6BC643AFDDF /* TemplateScreenCoordinator.swift */; };
|
||||||
4799A852132F1744E2825994 /* CreateRoomViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340179A0FC1AD4AEDA7FC134 /* CreateRoomViewModelProtocol.swift */; };
|
4799A852132F1744E2825994 /* CreateRoomViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340179A0FC1AD4AEDA7FC134 /* CreateRoomViewModelProtocol.swift */; };
|
||||||
@ -385,6 +388,7 @@
|
|||||||
5710AAB27D5D866292C1FE06 /* SessionVerificationScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF848B41DAF1066F3054D4A1 /* SessionVerificationScreenModels.swift */; };
|
5710AAB27D5D866292C1FE06 /* SessionVerificationScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF848B41DAF1066F3054D4A1 /* SessionVerificationScreenModels.swift */; };
|
||||||
5732395A4F71F51F9C754C5A /* ElementCallService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33AE897D86784CCA5E4E9227 /* ElementCallService.swift */; };
|
5732395A4F71F51F9C754C5A /* ElementCallService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33AE897D86784CCA5E4E9227 /* ElementCallService.swift */; };
|
||||||
5780E444F405AA1304E1C23E /* DeveloperOptionsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E521D6C2BF8DF0DFB35146 /* DeveloperOptionsScreen.swift */; };
|
5780E444F405AA1304E1C23E /* DeveloperOptionsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E521D6C2BF8DF0DFB35146 /* DeveloperOptionsScreen.swift */; };
|
||||||
|
583A41A4BE76E2E9E0B97881 /* ResolveVerifiedUserSendFailureScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5AEB5907E24092D741718AF /* ResolveVerifiedUserSendFailureScreenCoordinator.swift */; };
|
||||||
588411C8FD72B2A2DFE5F7DE /* XCUIElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = E992D7B8BE54B2AB454613AF /* XCUIElement.swift */; };
|
588411C8FD72B2A2DFE5F7DE /* XCUIElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = E992D7B8BE54B2AB454613AF /* XCUIElement.swift */; };
|
||||||
5894C2514400A4FBC9327632 /* ServerConfirmationScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03277E40D0E0DE0712021A71 /* ServerConfirmationScreenCoordinator.swift */; };
|
5894C2514400A4FBC9327632 /* ServerConfirmationScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03277E40D0E0DE0712021A71 /* ServerConfirmationScreenCoordinator.swift */; };
|
||||||
5897A59DDBD3592282092223 /* MediaSourceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = D49B9785E3AD7D1C15A29F2F /* MediaSourceProxy.swift */; };
|
5897A59DDBD3592282092223 /* MediaSourceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = D49B9785E3AD7D1C15A29F2F /* MediaSourceProxy.swift */; };
|
||||||
@ -683,6 +687,7 @@
|
|||||||
9912F9EB2D6589141A2957B4 /* AppLockScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C44BBC892499BE45B074F89 /* AppLockScreenCoordinator.swift */; };
|
9912F9EB2D6589141A2957B4 /* AppLockScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C44BBC892499BE45B074F89 /* AppLockScreenCoordinator.swift */; };
|
||||||
992F5E750F5030C4BA2D0D03 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 01C4C7DB37597D7D8379511A /* Assets.xcassets */; };
|
992F5E750F5030C4BA2D0D03 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 01C4C7DB37597D7D8379511A /* Assets.xcassets */; };
|
||||||
99ED42B8F8D6BFB1DBCF4C45 /* AnalyticsEvents in Frameworks */ = {isa = PBXBuildFile; productRef = D661CAB418C075A94306A792 /* AnalyticsEvents */; };
|
99ED42B8F8D6BFB1DBCF4C45 /* AnalyticsEvents in Frameworks */ = {isa = PBXBuildFile; productRef = D661CAB418C075A94306A792 /* AnalyticsEvents */; };
|
||||||
|
9A0326D2375075871D2AB537 /* ResolveVerifiedUserSendFailureScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 574CB70E82D7EAEA538E4135 /* ResolveVerifiedUserSendFailureScreenViewModel.swift */; };
|
||||||
9A3B0CDF097E3838FB1B9595 /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E89E530A8E92EC44301CA1 /* Bundle.swift */; };
|
9A3B0CDF097E3838FB1B9595 /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E89E530A8E92EC44301CA1 /* Bundle.swift */; };
|
||||||
9A4E3D5AA44B041DAC3A0D81 /* OIDCAuthenticationPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92390F9FA98255440A6BF5F8 /* OIDCAuthenticationPresenter.swift */; };
|
9A4E3D5AA44B041DAC3A0D81 /* OIDCAuthenticationPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92390F9FA98255440A6BF5F8 /* OIDCAuthenticationPresenter.swift */; };
|
||||||
9AC5F8142413862A9E3A2D98 /* DTCoreText in Frameworks */ = {isa = PBXBuildFile; productRef = 531CE4334AC5CA8DFF6AEB84 /* DTCoreText */; };
|
9AC5F8142413862A9E3A2D98 /* DTCoreText in Frameworks */ = {isa = PBXBuildFile; productRef = 531CE4334AC5CA8DFF6AEB84 /* DTCoreText */; };
|
||||||
@ -1030,6 +1035,7 @@
|
|||||||
EBE13FAB4E29738AC41BD3E5 /* InfoPlistReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A580295A56B55A856CC4084 /* InfoPlistReader.swift */; };
|
EBE13FAB4E29738AC41BD3E5 /* InfoPlistReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A580295A56B55A856CC4084 /* InfoPlistReader.swift */; };
|
||||||
EC280623A42904341363EAAF /* Collections in Frameworks */ = {isa = PBXBuildFile; productRef = A20EA00CCB9DBE0FFB17DD09 /* Collections */; };
|
EC280623A42904341363EAAF /* Collections in Frameworks */ = {isa = PBXBuildFile; productRef = A20EA00CCB9DBE0FFB17DD09 /* Collections */; };
|
||||||
EC3320639828BED8B3E5F2C6 /* EncryptionResetScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5875F7C0A2398E9F134B1284 /* EncryptionResetScreenViewModel.swift */; };
|
EC3320639828BED8B3E5F2C6 /* EncryptionResetScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5875F7C0A2398E9F134B1284 /* EncryptionResetScreenViewModel.swift */; };
|
||||||
|
ED3E91E6166E4923791ACA84 /* ResolveVerifiedUserSendFailureScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56852036214ABA9D7D305768 /* ResolveVerifiedUserSendFailureScreenViewModelProtocol.swift */; };
|
||||||
ED564C8C7C43CF5F67000368 /* PlatformViewVersionPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D26813CCE39221FE30BF22CD /* PlatformViewVersionPredicate.swift */; };
|
ED564C8C7C43CF5F67000368 /* PlatformViewVersionPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D26813CCE39221FE30BF22CD /* PlatformViewVersionPredicate.swift */; };
|
||||||
ED635D7F00FA07E94D3CE1E8 /* PreviewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9B796D347E53631576F631C /* PreviewTests.swift */; };
|
ED635D7F00FA07E94D3CE1E8 /* PreviewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9B796D347E53631576F631C /* PreviewTests.swift */; };
|
||||||
ED90A59F068FD0CA27E602ED /* UserProfileListRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10DA51DBC8C7E1460DBCCBD /* UserProfileListRow.swift */; };
|
ED90A59F068FD0CA27E602ED /* UserProfileListRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10DA51DBC8C7E1460DBCCBD /* UserProfileListRow.swift */; };
|
||||||
@ -1555,7 +1561,10 @@
|
|||||||
55AEEF8142DF1B59DB40FB93 /* TimelineItemSender.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemSender.swift; sourceTree = "<group>"; };
|
55AEEF8142DF1B59DB40FB93 /* TimelineItemSender.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemSender.swift; sourceTree = "<group>"; };
|
||||||
5644919DB2022397D9D5825A /* MockSoftLogoutScreenState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockSoftLogoutScreenState.swift; sourceTree = "<group>"; };
|
5644919DB2022397D9D5825A /* MockSoftLogoutScreenState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockSoftLogoutScreenState.swift; sourceTree = "<group>"; };
|
||||||
565F1B2B300597C616B37888 /* FullscreenDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullscreenDialog.swift; sourceTree = "<group>"; };
|
565F1B2B300597C616B37888 /* FullscreenDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullscreenDialog.swift; sourceTree = "<group>"; };
|
||||||
|
56852036214ABA9D7D305768 /* ResolveVerifiedUserSendFailureScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResolveVerifiedUserSendFailureScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
56D6F88FE35A0979D2821E06 /* AppLockScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockScreen.swift; sourceTree = "<group>"; };
|
56D6F88FE35A0979D2821E06 /* AppLockScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockScreen.swift; sourceTree = "<group>"; };
|
||||||
|
57084488B03BDB33C7B7CA0E /* ResolveVerifiedUserSendFailureScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResolveVerifiedUserSendFailureScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
|
574CB70E82D7EAEA538E4135 /* ResolveVerifiedUserSendFailureScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResolveVerifiedUserSendFailureScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
57916A1578D8043BB0795441 /* GeneratedMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneratedMocks.swift; sourceTree = "<group>"; };
|
57916A1578D8043BB0795441 /* GeneratedMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneratedMocks.swift; sourceTree = "<group>"; };
|
||||||
57B6B383F1FD04CC0E7B60C6 /* AnalyticsConsentState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsConsentState.swift; sourceTree = "<group>"; };
|
57B6B383F1FD04CC0E7B60C6 /* AnalyticsConsentState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsConsentState.swift; sourceTree = "<group>"; };
|
||||||
57EAAF82432B0B53881CF826 /* AudioRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRoomTimelineItem.swift; sourceTree = "<group>"; };
|
57EAAF82432B0B53881CF826 /* AudioRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||||
@ -1589,6 +1598,7 @@
|
|||||||
5F12E996BFBEB43815189ABF /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = uk; path = uk.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
5F12E996BFBEB43815189ABF /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = uk; path = uk.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
5F4134FEFE4EB55759017408 /* UserSessionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionProtocol.swift; sourceTree = "<group>"; };
|
5F4134FEFE4EB55759017408 /* UserSessionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionProtocol.swift; sourceTree = "<group>"; };
|
||||||
5FACD034DB52525A3CEF2BDF /* SessionVerificationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreen.swift; sourceTree = "<group>"; };
|
5FACD034DB52525A3CEF2BDF /* SessionVerificationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreen.swift; sourceTree = "<group>"; };
|
||||||
|
60011EF0086E49DBD78E16E5 /* ResolveVerifiedUserSendFailureScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResolveVerifiedUserSendFailureScreenModels.swift; sourceTree = "<group>"; };
|
||||||
6033779EB37259F27F938937 /* ClientProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientProxyProtocol.swift; sourceTree = "<group>"; };
|
6033779EB37259F27F938937 /* ClientProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientProxyProtocol.swift; sourceTree = "<group>"; };
|
||||||
604A69C081B935D6A38DE6D8 /* UserProfileScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileScreenModels.swift; sourceTree = "<group>"; };
|
604A69C081B935D6A38DE6D8 /* UserProfileScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileScreenModels.swift; sourceTree = "<group>"; };
|
||||||
60C9BAE9F9436B14E4E22E8F /* PinnedItemsBannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedItemsBannerView.swift; sourceTree = "<group>"; };
|
60C9BAE9F9436B14E4E22E8F /* PinnedItemsBannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedItemsBannerView.swift; sourceTree = "<group>"; };
|
||||||
@ -1807,6 +1817,7 @@
|
|||||||
95BAC0F6C9644336E9567EE6 /* NSRegularExpresion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSRegularExpresion.swift; sourceTree = "<group>"; };
|
95BAC0F6C9644336E9567EE6 /* NSRegularExpresion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSRegularExpresion.swift; sourceTree = "<group>"; };
|
||||||
969694F67E844FCA51F7E051 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
969694F67E844FCA51F7E051 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
96C4762F8D6112E43117DB2F /* CustomStringConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomStringConvertible.swift; sourceTree = "<group>"; };
|
96C4762F8D6112E43117DB2F /* CustomStringConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomStringConvertible.swift; sourceTree = "<group>"; };
|
||||||
|
97287090CA64DAA95386ECED /* ResolveVerifiedUserSendFailureScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResolveVerifiedUserSendFailureScreen.swift; sourceTree = "<group>"; };
|
||||||
974AEAF3FE0C577A6C04AD6E /* RoomPermissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomPermissions.swift; sourceTree = "<group>"; };
|
974AEAF3FE0C577A6C04AD6E /* RoomPermissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomPermissions.swift; sourceTree = "<group>"; };
|
||||||
9780389F8A53E4D26E23DD03 /* LoginScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
9780389F8A53E4D26E23DD03 /* LoginScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
97B2ACA28A854E41AE3AC9AD /* TimelineViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineViewModel.swift; sourceTree = "<group>"; };
|
97B2ACA28A854E41AE3AC9AD /* TimelineViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineViewModel.swift; sourceTree = "<group>"; };
|
||||||
@ -2013,6 +2024,7 @@
|
|||||||
C5599255A6C98EBDA77B76E6 /* ImageRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRoomTimelineView.swift; sourceTree = "<group>"; };
|
C5599255A6C98EBDA77B76E6 /* ImageRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||||
C55CC239AE12339C565F6C9A /* AudioRecorderStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecorderStateTests.swift; sourceTree = "<group>"; };
|
C55CC239AE12339C565F6C9A /* AudioRecorderStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecorderStateTests.swift; sourceTree = "<group>"; };
|
||||||
C55D7E514F9DE4E3D72FDCAD /* SessionVerificationControllerProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationControllerProxy.swift; sourceTree = "<group>"; };
|
C55D7E514F9DE4E3D72FDCAD /* SessionVerificationControllerProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationControllerProxy.swift; sourceTree = "<group>"; };
|
||||||
|
C5AEB5907E24092D741718AF /* ResolveVerifiedUserSendFailureScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResolveVerifiedUserSendFailureScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
C5B7A755E985FA14469E86B2 /* RoomMembersListScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreenUITests.swift; sourceTree = "<group>"; };
|
C5B7A755E985FA14469E86B2 /* RoomMembersListScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreenUITests.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>"; };
|
C616D90B1E2F033CAA325439 /* StaticLocationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticLocationScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
@ -3763,6 +3775,7 @@
|
|||||||
347D708104CCEF771428C9A3 /* PollFormScreenViewModelTests.swift */,
|
347D708104CCEF771428C9A3 /* PollFormScreenViewModelTests.swift */,
|
||||||
25E7E9B7FEAB6169D960C206 /* QRCodeLoginScreenViewModelTests.swift */,
|
25E7E9B7FEAB6169D960C206 /* QRCodeLoginScreenViewModelTests.swift */,
|
||||||
086C19086DD16E9B38E25954 /* ReportContentViewModelTests.swift */,
|
086C19086DD16E9B38E25954 /* ReportContentViewModelTests.swift */,
|
||||||
|
57084488B03BDB33C7B7CA0E /* ResolveVerifiedUserSendFailureScreenViewModelTests.swift */,
|
||||||
A7978C9EFBDD7DE39BD86726 /* RestorationTokenTests.swift */,
|
A7978C9EFBDD7DE39BD86726 /* RestorationTokenTests.swift */,
|
||||||
41D041A857614A9AE13C7795 /* RoomChangePermissionsScreenViewModelTests.swift */,
|
41D041A857614A9AE13C7795 /* RoomChangePermissionsScreenViewModelTests.swift */,
|
||||||
8F841F219ACDFC1D3F42FEFB /* RoomChangeRolesScreenViewModelTests.swift */,
|
8F841F219ACDFC1D3F42FEFB /* RoomChangeRolesScreenViewModelTests.swift */,
|
||||||
@ -4059,6 +4072,14 @@
|
|||||||
path = Tools;
|
path = Tools;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
829DDE5AE36ADD18677C150C /* View */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
97287090CA64DAA95386ECED /* ResolveVerifiedUserSendFailureScreen.swift */,
|
||||||
|
);
|
||||||
|
path = View;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
82D5AD3EAE3A5C1068A44A88 /* Session */ = {
|
82D5AD3EAE3A5C1068A44A88 /* Session */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -4435,6 +4456,18 @@
|
|||||||
path = View;
|
path = View;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
A040ACE4D778FFCD65DDF5F8 /* ResolveVerifiedUserSendFailureScreen */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
C5AEB5907E24092D741718AF /* ResolveVerifiedUserSendFailureScreenCoordinator.swift */,
|
||||||
|
60011EF0086E49DBD78E16E5 /* ResolveVerifiedUserSendFailureScreenModels.swift */,
|
||||||
|
574CB70E82D7EAEA538E4135 /* ResolveVerifiedUserSendFailureScreenViewModel.swift */,
|
||||||
|
56852036214ABA9D7D305768 /* ResolveVerifiedUserSendFailureScreenViewModelProtocol.swift */,
|
||||||
|
829DDE5AE36ADD18677C150C /* View */,
|
||||||
|
);
|
||||||
|
path = ResolveVerifiedUserSendFailureScreen;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
A0C06C0F6A8621B22BFAEB56 /* Localizations */ = {
|
A0C06C0F6A8621B22BFAEB56 /* Localizations */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -5116,6 +5149,7 @@
|
|||||||
3E535010B850B53DDD3CFF2A /* PinnedEventsTimelineScreen */,
|
3E535010B850B53DDD3CFF2A /* PinnedEventsTimelineScreen */,
|
||||||
3D733E8352DD4C461CFD8B8A /* QRCodeLoginScreen */,
|
3D733E8352DD4C461CFD8B8A /* QRCodeLoginScreen */,
|
||||||
5970F275D6014548DCED6106 /* ReportContentScreen */,
|
5970F275D6014548DCED6106 /* ReportContentScreen */,
|
||||||
|
A040ACE4D778FFCD65DDF5F8 /* ResolveVerifiedUserSendFailureScreen */,
|
||||||
DAB7DC51866A6D1B51BDC3A2 /* RoomChangePermissionsScreen */,
|
DAB7DC51866A6D1B51BDC3A2 /* RoomChangePermissionsScreen */,
|
||||||
D8388454B5909D862CAC78F7 /* RoomChangeRolesScreen */,
|
D8388454B5909D862CAC78F7 /* RoomChangeRolesScreen */,
|
||||||
E71742A824A7192C8D378875 /* RoomDetailsEditScreen */,
|
E71742A824A7192C8D378875 /* RoomDetailsEditScreen */,
|
||||||
@ -6016,6 +6050,7 @@
|
|||||||
D415764645491F10344FC6AC /* Publisher.swift in Sources */,
|
D415764645491F10344FC6AC /* Publisher.swift in Sources */,
|
||||||
BDC4EB54CC3036730475CB8B /* QRCodeLoginScreenViewModelTests.swift in Sources */,
|
BDC4EB54CC3036730475CB8B /* QRCodeLoginScreenViewModelTests.swift in Sources */,
|
||||||
D53B80EF02C1062E68659EDD /* ReportContentViewModelTests.swift in Sources */,
|
D53B80EF02C1062E68659EDD /* ReportContentViewModelTests.swift in Sources */,
|
||||||
|
09D3D7D115318CAD131B4FE7 /* ResolveVerifiedUserSendFailureScreenViewModelTests.swift in Sources */,
|
||||||
C5627BCC3EBBB96A943B6D93 /* RestorationTokenTests.swift in Sources */,
|
C5627BCC3EBBB96A943B6D93 /* RestorationTokenTests.swift in Sources */,
|
||||||
9B03943616A1147539DF7F08 /* RoomChangePermissionsScreenViewModelTests.swift in Sources */,
|
9B03943616A1147539DF7F08 /* RoomChangePermissionsScreenViewModelTests.swift in Sources */,
|
||||||
D2825E013A8ECFB66D9A1DE6 /* RoomChangeRolesScreenViewModelTests.swift in Sources */,
|
D2825E013A8ECFB66D9A1DE6 /* RoomChangeRolesScreenViewModelTests.swift in Sources */,
|
||||||
@ -6557,6 +6592,11 @@
|
|||||||
46A261AA898344A1F3C406B1 /* ReportContentScreenModels.swift in Sources */,
|
46A261AA898344A1F3C406B1 /* ReportContentScreenModels.swift in Sources */,
|
||||||
42A5A42ACF063EEE6B1980D2 /* ReportContentScreenViewModel.swift in Sources */,
|
42A5A42ACF063EEE6B1980D2 /* ReportContentScreenViewModel.swift in Sources */,
|
||||||
8285FF4B2C2331758C437FF7 /* ReportContentScreenViewModelProtocol.swift in Sources */,
|
8285FF4B2C2331758C437FF7 /* ReportContentScreenViewModelProtocol.swift in Sources */,
|
||||||
|
4715FE33667C5899E64DD0E6 /* ResolveVerifiedUserSendFailureScreen.swift in Sources */,
|
||||||
|
583A41A4BE76E2E9E0B97881 /* ResolveVerifiedUserSendFailureScreenCoordinator.swift in Sources */,
|
||||||
|
108D3C0707A90B0F848CDBB9 /* ResolveVerifiedUserSendFailureScreenModels.swift in Sources */,
|
||||||
|
9A0326D2375075871D2AB537 /* ResolveVerifiedUserSendFailureScreenViewModel.swift in Sources */,
|
||||||
|
ED3E91E6166E4923791ACA84 /* ResolveVerifiedUserSendFailureScreenViewModelProtocol.swift in Sources */,
|
||||||
A494741843F087881299ACF0 /* RestorationToken.swift in Sources */,
|
A494741843F087881299ACF0 /* RestorationToken.swift in Sources */,
|
||||||
6E391F7F628D984AF44385D9 /* RoomAttachmentPicker.swift in Sources */,
|
6E391F7F628D984AF44385D9 /* RoomAttachmentPicker.swift in Sources */,
|
||||||
8587A53DE8EF94FD796DC375 /* RoomAvatarImage.swift in Sources */,
|
8587A53DE8EF94FD796DC375 /* RoomAvatarImage.swift in Sources */,
|
||||||
@ -7647,7 +7687,7 @@
|
|||||||
repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift";
|
repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift";
|
||||||
requirement = {
|
requirement = {
|
||||||
kind = exactVersion;
|
kind = exactVersion;
|
||||||
version = 1.0.44;
|
version = 1.0.45;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = {
|
701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = {
|
||||||
|
@ -149,8 +149,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/element-hq/matrix-rust-components-swift",
|
"location" : "https://github.com/element-hq/matrix-rust-components-swift",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "343d7045a0ad6fe508728f624a02698e679327fb",
|
"revision" : "103b7000e5191485873a81386d0134d71bd9fc36",
|
||||||
"version" : "1.0.44"
|
"version" : "1.0.45"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
"action_back" = "Back";
|
"action_back" = "Back";
|
||||||
"action_call" = "Call";
|
"action_call" = "Call";
|
||||||
"action_cancel" = "Cancel";
|
"action_cancel" = "Cancel";
|
||||||
|
"action_cancel_for_now" = "Cancel for now";
|
||||||
"action_choose_photo" = "Choose photo";
|
"action_choose_photo" = "Choose photo";
|
||||||
"action_clear" = "Clear";
|
"action_clear" = "Clear";
|
||||||
"action_close" = "Close";
|
"action_close" = "Close";
|
||||||
@ -106,6 +107,10 @@
|
|||||||
"action_view_source" = "View source";
|
"action_view_source" = "View source";
|
||||||
"action_yes" = "Yes";
|
"action_yes" = "Yes";
|
||||||
"action.load_more" = "Load more";
|
"action.load_more" = "Load more";
|
||||||
|
"banner_migrate_to_native_sliding_sync_action" = "Log Out & Upgrade";
|
||||||
|
"banner_migrate_to_native_sliding_sync_description" = "Your server now supports a new, faster protocol. Log out and log back in to upgrade now. Doing this now will help you avoid a forced logout when the old protocol is removed later.";
|
||||||
|
"banner_migrate_to_native_sliding_sync_force_logout_title" = "Your homeserver no longer supports the old protocol. Please log out and log back in to continue using the app.";
|
||||||
|
"banner_migrate_to_native_sliding_sync_title" = "Upgrade available";
|
||||||
"banner.set_up_recovery.content" = "Generate a new recovery key that can be used to restore your encrypted message history in case you lose access to your devices.";
|
"banner.set_up_recovery.content" = "Generate a new recovery key that can be used to restore your encrypted message history in case you lose access to your devices.";
|
||||||
"banner.set_up_recovery.title" = "Set up recovery";
|
"banner.set_up_recovery.title" = "Set up recovery";
|
||||||
"common_about" = "About";
|
"common_about" = "About";
|
||||||
@ -325,12 +330,20 @@
|
|||||||
"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_pinned_timeline_screen_title_empty" = "Pinned messages";
|
"screen_pinned_timeline_screen_title_empty" = "Pinned messages";
|
||||||
"screen_reset_encryption_password_error" = "An unknown error happened. Please check your account password is correct and try again.";
|
"screen_reset_encryption_password_error" = "An unknown error happened. Please check your account password is correct and try again.";
|
||||||
|
"screen_resolve_send_failure_changed_identity_primary_button_title" = "Withdraw verification and send";
|
||||||
|
"screen_resolve_send_failure_changed_identity_subtitle" = "You can withdraw your verification and send this message anyway, or you can cancel for now and try again later after reverifying %1$@.";
|
||||||
|
"screen_resolve_send_failure_changed_identity_title" = "Your message was not sent because %1$@’s verified identity has changed";
|
||||||
|
"screen_resolve_send_failure_unsigned_device_primary_button_title" = "Send message anyway";
|
||||||
|
"screen_resolve_send_failure_unsigned_device_subtitle" = "%1$@ is using one or more unverified devices. You can send the message anyway, or you can cancel for now and try again later after %2$@ has verified all their devices.";
|
||||||
|
"screen_resolve_send_failure_unsigned_device_title" = "Your message was not sent because %1$@ has not verified one or more devices";
|
||||||
"screen_room_mentions_at_room_subtitle" = "Notify the whole room";
|
"screen_room_mentions_at_room_subtitle" = "Notify the whole room";
|
||||||
"screen_room_pinned_banner_indicator" = "%1$@ of %2$@";
|
"screen_room_pinned_banner_indicator" = "%1$@ of %2$@";
|
||||||
"screen_room_pinned_banner_indicator_description" = "%1$@ Pinned messages";
|
"screen_room_pinned_banner_indicator_description" = "%1$@ Pinned messages";
|
||||||
"screen_room_pinned_banner_loading_description" = "Loading message…";
|
"screen_room_pinned_banner_loading_description" = "Loading message…";
|
||||||
"screen_room_pinned_banner_view_all_button_title" = "View All";
|
"screen_room_pinned_banner_view_all_button_title" = "View All";
|
||||||
"screen_room_details_pinned_events_row_title" = "Pinned messages";
|
"screen_room_details_pinned_events_row_title" = "Pinned messages";
|
||||||
|
"screen_timeline_item_menu_send_failure_changed_identity" = "Message not sent because %1$@’s verified identity has changed.";
|
||||||
|
"screen_timeline_item_menu_send_failure_unsigned_device" = "Message not sent because %1$@ has not verified one or more devices.";
|
||||||
"screen_account_provider_change" = "Change account provider";
|
"screen_account_provider_change" = "Change account provider";
|
||||||
"screen_account_provider_form_hint" = "Homeserver address";
|
"screen_account_provider_form_hint" = "Homeserver address";
|
||||||
"screen_account_provider_form_notice" = "Enter a search term or a domain address.";
|
"screen_account_provider_form_notice" = "Enter a search term or a domain address.";
|
||||||
@ -579,7 +592,6 @@
|
|||||||
"screen_recovery_key_confirm_error_content" = "Please try again to confirm access to your chat backup.";
|
"screen_recovery_key_confirm_error_content" = "Please try again to confirm access to your chat backup.";
|
||||||
"screen_recovery_key_confirm_error_title" = "Incorrect recovery key";
|
"screen_recovery_key_confirm_error_title" = "Incorrect recovery key";
|
||||||
"screen_recovery_key_confirm_key_description" = "If you have a security key or security phrase, this will work too.";
|
"screen_recovery_key_confirm_key_description" = "If you have a security key or security phrase, this will work too.";
|
||||||
"screen_recovery_key_confirm_key_label" = "Recovery key or passcode";
|
|
||||||
"screen_recovery_key_confirm_key_placeholder" = "Enter…";
|
"screen_recovery_key_confirm_key_placeholder" = "Enter…";
|
||||||
"screen_recovery_key_confirm_lost_recovery_key" = "Lost your recovery key?";
|
"screen_recovery_key_confirm_lost_recovery_key" = "Lost your recovery key?";
|
||||||
"screen_recovery_key_confirm_success" = "Recovery key confirmed";
|
"screen_recovery_key_confirm_success" = "Recovery key confirmed";
|
||||||
@ -806,9 +818,6 @@
|
|||||||
"screen_signout_save_recovery_key_title" = "Have you saved your recovery key?";
|
"screen_signout_save_recovery_key_title" = "Have you saved your recovery key?";
|
||||||
"screen_start_chat_error_starting_chat" = "An error occurred when trying to start a chat";
|
"screen_start_chat_error_starting_chat" = "An error occurred when trying to start a chat";
|
||||||
"screen_view_location_title" = "Location";
|
"screen_view_location_title" = "Location";
|
||||||
"screen_waitlist_message" = "There's a high demand for %1$@ on %2$@ at the moment. Come back to the app in a few days and try again.\n\nThanks for your patience!";
|
|
||||||
"screen_waitlist_title" = "You’re almost there.";
|
|
||||||
"screen_waitlist_title_success" = "You're in.";
|
|
||||||
"screen_welcome_bullet_1" = "Calls, polls, search and more will be added later this year.";
|
"screen_welcome_bullet_1" = "Calls, polls, search and more will be added later this year.";
|
||||||
"screen_welcome_bullet_2" = "Message history for encrypted rooms isn’t available yet.";
|
"screen_welcome_bullet_2" = "Message history for encrypted rooms isn’t available yet.";
|
||||||
"screen_welcome_bullet_3" = "We’d love to hear from you, let us know what you think via the settings page.";
|
"screen_welcome_bullet_3" = "We’d love to hear from you, let us know what you think via the settings page.";
|
||||||
@ -983,4 +992,3 @@
|
|||||||
"screen_signout_confirmation_dialog_submit" = "Sign out";
|
"screen_signout_confirmation_dialog_submit" = "Sign out";
|
||||||
"screen_signout_confirmation_dialog_title" = "Sign out";
|
"screen_signout_confirmation_dialog_title" = "Sign out";
|
||||||
"screen_signout_preference_item" = "Sign out";
|
"screen_signout_preference_item" = "Sign out";
|
||||||
"screen_waitlist_message_success" = "Welcome to %1$@!";
|
|
||||||
|
@ -349,6 +349,11 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
case (.roomDetails, .presentRoomMemberDetails(let userID)):
|
case (.roomDetails, .presentRoomMemberDetails(let userID)):
|
||||||
return .roomMemberDetails(userID: userID, previousState: fromState)
|
return .roomMemberDetails(userID: userID, previousState: fromState)
|
||||||
|
|
||||||
|
case (.room, .presentResolveSendFailure):
|
||||||
|
return .resolveSendFailure
|
||||||
|
case (.resolveSendFailure, .dismissResolveSendFailure):
|
||||||
|
return .room
|
||||||
|
|
||||||
// Child flow
|
// Child flow
|
||||||
|
|
||||||
case (_, .startChildFlow(let roomID, _, _)):
|
case (_, .startChildFlow(let roomID, _, _)):
|
||||||
@ -499,6 +504,11 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
case (.roomMemberDetails, .dismissUserProfile, .roomDetails):
|
case (.roomMemberDetails, .dismissUserProfile, .roomDetails):
|
||||||
break
|
break
|
||||||
|
|
||||||
|
case (.room, .presentResolveSendFailure(let failure, let itemID), .resolveSendFailure):
|
||||||
|
presentResolveSendFailure(failure: failure, itemID: itemID)
|
||||||
|
case (.resolveSendFailure, .dismissResolveSendFailure, .room):
|
||||||
|
break
|
||||||
|
|
||||||
// Child flow
|
// Child flow
|
||||||
case (_, .startChildFlow(let roomID, let via, let entryPoint), .presentingChild):
|
case (_, .startChildFlow(let roomID, let via, let entryPoint), .presentingChild):
|
||||||
Task { await self.startChildFlow(for: roomID, via: via, entryPoint: entryPoint) }
|
Task { await self.startChildFlow(for: roomID, via: via, entryPoint: entryPoint) }
|
||||||
@ -623,6 +633,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
actionsSubject.send(.presentCallScreen(roomProxy: roomProxy))
|
actionsSubject.send(.presentCallScreen(roomProxy: roomProxy))
|
||||||
case .presentPinnedEventsTimeline:
|
case .presentPinnedEventsTimeline:
|
||||||
stateMachine.tryEvent(.presentPinnedEventsTimeline)
|
stateMachine.tryEvent(.presentPinnedEventsTimeline)
|
||||||
|
case .presentResolveSendFailure(failure: let failure, itemID: let itemID):
|
||||||
|
stateMachine.tryEvent(.presentResolveSendFailure(failure: failure, itemID: itemID))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
@ -1351,6 +1363,25 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
coordinator.start()
|
coordinator.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func presentResolveSendFailure(failure: TimelineItemSendFailure.VerifiedUser, itemID: TimelineItemIdentifier) {
|
||||||
|
let coordinator = ResolveVerifiedUserSendFailureScreenCoordinator(parameters: .init(failure: failure,
|
||||||
|
itemID: itemID,
|
||||||
|
roomProxy: roomProxy))
|
||||||
|
coordinator.actionsPublisher.sink { [weak self] action in
|
||||||
|
guard let self else { return }
|
||||||
|
|
||||||
|
switch action {
|
||||||
|
case .dismiss:
|
||||||
|
navigationStackCoordinator.setSheetCoordinator(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
navigationStackCoordinator.setSheetCoordinator(coordinator) { [weak self] in
|
||||||
|
self?.stateMachine.tryEvent(.dismissResolveSendFailure)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Child Flow
|
// MARK: - Child Flow
|
||||||
|
|
||||||
private func startChildFlow(for roomID: String, via: [String], entryPoint: RoomFlowCoordinatorEntryPoint) async {
|
private func startChildFlow(for roomID: String, via: [String], entryPoint: RoomFlowCoordinatorEntryPoint) async {
|
||||||
@ -1425,6 +1456,7 @@ private extension RoomFlowCoordinator {
|
|||||||
case pollsHistoryForm
|
case pollsHistoryForm
|
||||||
case rolesAndPermissions
|
case rolesAndPermissions
|
||||||
case pinnedEventsTimeline(previousState: PinnedEventsTimelineSource)
|
case pinnedEventsTimeline(previousState: PinnedEventsTimelineSource)
|
||||||
|
case resolveSendFailure
|
||||||
|
|
||||||
/// A child flow is in progress.
|
/// A child flow is in progress.
|
||||||
case presentingChild(childRoomID: String, previousState: State)
|
case presentingChild(childRoomID: String, previousState: State)
|
||||||
@ -1497,6 +1529,9 @@ private extension RoomFlowCoordinator {
|
|||||||
case presentPinnedEventsTimeline
|
case presentPinnedEventsTimeline
|
||||||
case dismissPinnedEventsTimeline
|
case dismissPinnedEventsTimeline
|
||||||
|
|
||||||
|
case presentResolveSendFailure(failure: TimelineItemSendFailure.VerifiedUser, itemID: TimelineItemIdentifier)
|
||||||
|
case dismissResolveSendFailure
|
||||||
|
|
||||||
// Child room flow events
|
// Child room flow events
|
||||||
case startChildFlow(roomID: String, via: [String], entryPoint: RoomFlowCoordinatorEntryPoint)
|
case startChildFlow(roomID: String, via: [String], entryPoint: RoomFlowCoordinatorEntryPoint)
|
||||||
case dismissChildFlow
|
case dismissChildFlow
|
||||||
|
@ -84,6 +84,8 @@ internal enum L10n {
|
|||||||
internal static var actionCall: String { return L10n.tr("Localizable", "action_call") }
|
internal static var actionCall: String { return L10n.tr("Localizable", "action_call") }
|
||||||
/// Cancel
|
/// Cancel
|
||||||
internal static var actionCancel: String { return L10n.tr("Localizable", "action_cancel") }
|
internal static var actionCancel: String { return L10n.tr("Localizable", "action_cancel") }
|
||||||
|
/// Cancel for now
|
||||||
|
internal static var actionCancelForNow: String { return L10n.tr("Localizable", "action_cancel_for_now") }
|
||||||
/// Choose photo
|
/// Choose photo
|
||||||
internal static var actionChoosePhoto: String { return L10n.tr("Localizable", "action_choose_photo") }
|
internal static var actionChoosePhoto: String { return L10n.tr("Localizable", "action_choose_photo") }
|
||||||
/// Clear
|
/// Clear
|
||||||
@ -244,6 +246,14 @@ internal enum L10n {
|
|||||||
internal static var actionViewSource: String { return L10n.tr("Localizable", "action_view_source") }
|
internal static var actionViewSource: String { return L10n.tr("Localizable", "action_view_source") }
|
||||||
/// Yes
|
/// Yes
|
||||||
internal static var actionYes: String { return L10n.tr("Localizable", "action_yes") }
|
internal static var actionYes: String { return L10n.tr("Localizable", "action_yes") }
|
||||||
|
/// Log Out & Upgrade
|
||||||
|
internal static var bannerMigrateToNativeSlidingSyncAction: String { return L10n.tr("Localizable", "banner_migrate_to_native_sliding_sync_action") }
|
||||||
|
/// Your server now supports a new, faster protocol. Log out and log back in to upgrade now. Doing this now will help you avoid a forced logout when the old protocol is removed later.
|
||||||
|
internal static var bannerMigrateToNativeSlidingSyncDescription: String { return L10n.tr("Localizable", "banner_migrate_to_native_sliding_sync_description") }
|
||||||
|
/// Your homeserver no longer supports the old protocol. Please log out and log back in to continue using the app.
|
||||||
|
internal static var bannerMigrateToNativeSlidingSyncForceLogoutTitle: String { return L10n.tr("Localizable", "banner_migrate_to_native_sliding_sync_force_logout_title") }
|
||||||
|
/// Upgrade available
|
||||||
|
internal static var bannerMigrateToNativeSlidingSyncTitle: String { return L10n.tr("Localizable", "banner_migrate_to_native_sliding_sync_title") }
|
||||||
/// About
|
/// About
|
||||||
internal static var commonAbout: String { return L10n.tr("Localizable", "common_about") }
|
internal static var commonAbout: String { return L10n.tr("Localizable", "common_about") }
|
||||||
/// Acceptable use policy
|
/// Acceptable use policy
|
||||||
@ -1383,8 +1393,6 @@ internal enum L10n {
|
|||||||
internal static var screenRecoveryKeyConfirmErrorTitle: String { return L10n.tr("Localizable", "screen_recovery_key_confirm_error_title") }
|
internal static var screenRecoveryKeyConfirmErrorTitle: String { return L10n.tr("Localizable", "screen_recovery_key_confirm_error_title") }
|
||||||
/// If you have a security key or security phrase, this will work too.
|
/// If you have a security key or security phrase, this will work too.
|
||||||
internal static var screenRecoveryKeyConfirmKeyDescription: String { return L10n.tr("Localizable", "screen_recovery_key_confirm_key_description") }
|
internal static var screenRecoveryKeyConfirmKeyDescription: String { return L10n.tr("Localizable", "screen_recovery_key_confirm_key_description") }
|
||||||
/// Recovery key or passcode
|
|
||||||
internal static var screenRecoveryKeyConfirmKeyLabel: String { return L10n.tr("Localizable", "screen_recovery_key_confirm_key_label") }
|
|
||||||
/// Enter…
|
/// Enter…
|
||||||
internal static var screenRecoveryKeyConfirmKeyPlaceholder: String { return L10n.tr("Localizable", "screen_recovery_key_confirm_key_placeholder") }
|
internal static var screenRecoveryKeyConfirmKeyPlaceholder: String { return L10n.tr("Localizable", "screen_recovery_key_confirm_key_placeholder") }
|
||||||
/// Lost your recovery key?
|
/// Lost your recovery key?
|
||||||
@ -1447,6 +1455,26 @@ internal enum L10n {
|
|||||||
}
|
}
|
||||||
/// Can't confirm? Go to your account to reset your identity.
|
/// Can't confirm? Go to your account to reset your identity.
|
||||||
internal static var screenResetIdentityConfirmationTitle: String { return L10n.tr("Localizable", "screen_reset_identity_confirmation_title") }
|
internal static var screenResetIdentityConfirmationTitle: String { return L10n.tr("Localizable", "screen_reset_identity_confirmation_title") }
|
||||||
|
/// Withdraw verification and send
|
||||||
|
internal static var screenResolveSendFailureChangedIdentityPrimaryButtonTitle: String { return L10n.tr("Localizable", "screen_resolve_send_failure_changed_identity_primary_button_title") }
|
||||||
|
/// You can withdraw your verification and send this message anyway, or you can cancel for now and try again later after reverifying %1$@.
|
||||||
|
internal static func screenResolveSendFailureChangedIdentitySubtitle(_ p1: Any) -> String {
|
||||||
|
return L10n.tr("Localizable", "screen_resolve_send_failure_changed_identity_subtitle", String(describing: p1))
|
||||||
|
}
|
||||||
|
/// Your message was not sent because %1$@’s verified identity has changed
|
||||||
|
internal static func screenResolveSendFailureChangedIdentityTitle(_ p1: Any) -> String {
|
||||||
|
return L10n.tr("Localizable", "screen_resolve_send_failure_changed_identity_title", String(describing: p1))
|
||||||
|
}
|
||||||
|
/// Send message anyway
|
||||||
|
internal static var screenResolveSendFailureUnsignedDevicePrimaryButtonTitle: String { return L10n.tr("Localizable", "screen_resolve_send_failure_unsigned_device_primary_button_title") }
|
||||||
|
/// %1$@ is using one or more unverified devices. You can send the message anyway, or you can cancel for now and try again later after %2$@ has verified all their devices.
|
||||||
|
internal static func screenResolveSendFailureUnsignedDeviceSubtitle(_ p1: Any, _ p2: Any) -> String {
|
||||||
|
return L10n.tr("Localizable", "screen_resolve_send_failure_unsigned_device_subtitle", String(describing: p1), String(describing: p2))
|
||||||
|
}
|
||||||
|
/// Your message was not sent because %1$@ has not verified one or more devices
|
||||||
|
internal static func screenResolveSendFailureUnsignedDeviceTitle(_ p1: Any) -> String {
|
||||||
|
return L10n.tr("Localizable", "screen_resolve_send_failure_unsigned_device_title", String(describing: p1))
|
||||||
|
}
|
||||||
/// Failed to resolve room alias.
|
/// Failed to resolve room alias.
|
||||||
internal static var screenRoomAliasResolverResolveAliasFailure: String { return L10n.tr("Localizable", "screen_room_alias_resolver_resolve_alias_failure") }
|
internal static var screenRoomAliasResolverResolveAliasFailure: String { return L10n.tr("Localizable", "screen_room_alias_resolver_resolve_alias_failure") }
|
||||||
/// Camera
|
/// Camera
|
||||||
@ -1945,22 +1973,16 @@ internal enum L10n {
|
|||||||
internal static var screenSignoutSaveRecoveryKeyTitle: String { return L10n.tr("Localizable", "screen_signout_save_recovery_key_title") }
|
internal static var screenSignoutSaveRecoveryKeyTitle: String { return L10n.tr("Localizable", "screen_signout_save_recovery_key_title") }
|
||||||
/// An error occurred when trying to start a chat
|
/// An error occurred when trying to start a chat
|
||||||
internal static var screenStartChatErrorStartingChat: String { return L10n.tr("Localizable", "screen_start_chat_error_starting_chat") }
|
internal static var screenStartChatErrorStartingChat: String { return L10n.tr("Localizable", "screen_start_chat_error_starting_chat") }
|
||||||
|
/// Message not sent because %1$@’s verified identity has changed.
|
||||||
|
internal static func screenTimelineItemMenuSendFailureChangedIdentity(_ p1: Any) -> String {
|
||||||
|
return L10n.tr("Localizable", "screen_timeline_item_menu_send_failure_changed_identity", String(describing: p1))
|
||||||
|
}
|
||||||
|
/// Message not sent because %1$@ has not verified one or more devices.
|
||||||
|
internal static func screenTimelineItemMenuSendFailureUnsignedDevice(_ p1: Any) -> String {
|
||||||
|
return L10n.tr("Localizable", "screen_timeline_item_menu_send_failure_unsigned_device", String(describing: p1))
|
||||||
|
}
|
||||||
/// Location
|
/// Location
|
||||||
internal static var screenViewLocationTitle: String { return L10n.tr("Localizable", "screen_view_location_title") }
|
internal static var screenViewLocationTitle: String { return L10n.tr("Localizable", "screen_view_location_title") }
|
||||||
/// There's a high demand for %1$@ on %2$@ at the moment. Come back to the app in a few days and try again.
|
|
||||||
///
|
|
||||||
/// Thanks for your patience!
|
|
||||||
internal static func screenWaitlistMessage(_ p1: Any, _ p2: Any) -> String {
|
|
||||||
return L10n.tr("Localizable", "screen_waitlist_message", String(describing: p1), String(describing: p2))
|
|
||||||
}
|
|
||||||
/// Welcome to %1$@!
|
|
||||||
internal static func screenWaitlistMessageSuccess(_ p1: Any) -> String {
|
|
||||||
return L10n.tr("Localizable", "screen_waitlist_message_success", String(describing: p1))
|
|
||||||
}
|
|
||||||
/// You’re almost there.
|
|
||||||
internal static var screenWaitlistTitle: String { return L10n.tr("Localizable", "screen_waitlist_title") }
|
|
||||||
/// You're in.
|
|
||||||
internal static var screenWaitlistTitleSuccess: String { return L10n.tr("Localizable", "screen_waitlist_title_success") }
|
|
||||||
/// Calls, polls, search and more will be added later this year.
|
/// Calls, polls, search and more will be added later this year.
|
||||||
internal static var screenWelcomeBullet1: String { return L10n.tr("Localizable", "screen_welcome_bullet_1") }
|
internal static var screenWelcomeBullet1: String { return L10n.tr("Localizable", "screen_welcome_bullet_1") }
|
||||||
/// Message history for encrypted rooms isn’t available yet.
|
/// Message history for encrypted rooms isn’t available yet.
|
||||||
|
@ -6563,6 +6563,216 @@ class JoinedRoomProxyMock: JoinedRoomProxyProtocol {
|
|||||||
return sendTypingNotificationIsTypingReturnValue
|
return sendTypingNotificationIsTypingReturnValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//MARK: - resend
|
||||||
|
|
||||||
|
var resendItemIDUnderlyingCallsCount = 0
|
||||||
|
var resendItemIDCallsCount: Int {
|
||||||
|
get {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
return resendItemIDUnderlyingCallsCount
|
||||||
|
} else {
|
||||||
|
var returnValue: Int? = nil
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
returnValue = resendItemIDUnderlyingCallsCount
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
resendItemIDUnderlyingCallsCount = newValue
|
||||||
|
} else {
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
resendItemIDUnderlyingCallsCount = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var resendItemIDCalled: Bool {
|
||||||
|
return resendItemIDCallsCount > 0
|
||||||
|
}
|
||||||
|
var resendItemIDReceivedItemID: TimelineItemIdentifier?
|
||||||
|
var resendItemIDReceivedInvocations: [TimelineItemIdentifier] = []
|
||||||
|
|
||||||
|
var resendItemIDUnderlyingReturnValue: Result<Void, RoomProxyError>!
|
||||||
|
var resendItemIDReturnValue: Result<Void, RoomProxyError>! {
|
||||||
|
get {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
return resendItemIDUnderlyingReturnValue
|
||||||
|
} else {
|
||||||
|
var returnValue: Result<Void, RoomProxyError>? = nil
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
returnValue = resendItemIDUnderlyingReturnValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
resendItemIDUnderlyingReturnValue = newValue
|
||||||
|
} else {
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
resendItemIDUnderlyingReturnValue = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var resendItemIDClosure: ((TimelineItemIdentifier) async -> Result<Void, RoomProxyError>)?
|
||||||
|
|
||||||
|
func resend(itemID: TimelineItemIdentifier) async -> Result<Void, RoomProxyError> {
|
||||||
|
resendItemIDCallsCount += 1
|
||||||
|
resendItemIDReceivedItemID = itemID
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.resendItemIDReceivedInvocations.append(itemID)
|
||||||
|
}
|
||||||
|
if let resendItemIDClosure = resendItemIDClosure {
|
||||||
|
return await resendItemIDClosure(itemID)
|
||||||
|
} else {
|
||||||
|
return resendItemIDReturnValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//MARK: - ignoreDeviceTrustAndResend
|
||||||
|
|
||||||
|
var ignoreDeviceTrustAndResendDevicesItemIDUnderlyingCallsCount = 0
|
||||||
|
var ignoreDeviceTrustAndResendDevicesItemIDCallsCount: Int {
|
||||||
|
get {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
return ignoreDeviceTrustAndResendDevicesItemIDUnderlyingCallsCount
|
||||||
|
} else {
|
||||||
|
var returnValue: Int? = nil
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
returnValue = ignoreDeviceTrustAndResendDevicesItemIDUnderlyingCallsCount
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
ignoreDeviceTrustAndResendDevicesItemIDUnderlyingCallsCount = newValue
|
||||||
|
} else {
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
ignoreDeviceTrustAndResendDevicesItemIDUnderlyingCallsCount = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var ignoreDeviceTrustAndResendDevicesItemIDCalled: Bool {
|
||||||
|
return ignoreDeviceTrustAndResendDevicesItemIDCallsCount > 0
|
||||||
|
}
|
||||||
|
var ignoreDeviceTrustAndResendDevicesItemIDReceivedArguments: (devices: [String: [String]], itemID: TimelineItemIdentifier)?
|
||||||
|
var ignoreDeviceTrustAndResendDevicesItemIDReceivedInvocations: [(devices: [String: [String]], itemID: TimelineItemIdentifier)] = []
|
||||||
|
|
||||||
|
var ignoreDeviceTrustAndResendDevicesItemIDUnderlyingReturnValue: Result<Void, RoomProxyError>!
|
||||||
|
var ignoreDeviceTrustAndResendDevicesItemIDReturnValue: Result<Void, RoomProxyError>! {
|
||||||
|
get {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
return ignoreDeviceTrustAndResendDevicesItemIDUnderlyingReturnValue
|
||||||
|
} else {
|
||||||
|
var returnValue: Result<Void, RoomProxyError>? = nil
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
returnValue = ignoreDeviceTrustAndResendDevicesItemIDUnderlyingReturnValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
ignoreDeviceTrustAndResendDevicesItemIDUnderlyingReturnValue = newValue
|
||||||
|
} else {
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
ignoreDeviceTrustAndResendDevicesItemIDUnderlyingReturnValue = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var ignoreDeviceTrustAndResendDevicesItemIDClosure: (([String: [String]], TimelineItemIdentifier) async -> Result<Void, RoomProxyError>)?
|
||||||
|
|
||||||
|
func ignoreDeviceTrustAndResend(devices: [String: [String]], itemID: TimelineItemIdentifier) async -> Result<Void, RoomProxyError> {
|
||||||
|
ignoreDeviceTrustAndResendDevicesItemIDCallsCount += 1
|
||||||
|
ignoreDeviceTrustAndResendDevicesItemIDReceivedArguments = (devices: devices, itemID: itemID)
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.ignoreDeviceTrustAndResendDevicesItemIDReceivedInvocations.append((devices: devices, itemID: itemID))
|
||||||
|
}
|
||||||
|
if let ignoreDeviceTrustAndResendDevicesItemIDClosure = ignoreDeviceTrustAndResendDevicesItemIDClosure {
|
||||||
|
return await ignoreDeviceTrustAndResendDevicesItemIDClosure(devices, itemID)
|
||||||
|
} else {
|
||||||
|
return ignoreDeviceTrustAndResendDevicesItemIDReturnValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//MARK: - withdrawVerificationAndResend
|
||||||
|
|
||||||
|
var withdrawVerificationAndResendUserIDsItemIDUnderlyingCallsCount = 0
|
||||||
|
var withdrawVerificationAndResendUserIDsItemIDCallsCount: Int {
|
||||||
|
get {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
return withdrawVerificationAndResendUserIDsItemIDUnderlyingCallsCount
|
||||||
|
} else {
|
||||||
|
var returnValue: Int? = nil
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
returnValue = withdrawVerificationAndResendUserIDsItemIDUnderlyingCallsCount
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
withdrawVerificationAndResendUserIDsItemIDUnderlyingCallsCount = newValue
|
||||||
|
} else {
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
withdrawVerificationAndResendUserIDsItemIDUnderlyingCallsCount = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var withdrawVerificationAndResendUserIDsItemIDCalled: Bool {
|
||||||
|
return withdrawVerificationAndResendUserIDsItemIDCallsCount > 0
|
||||||
|
}
|
||||||
|
var withdrawVerificationAndResendUserIDsItemIDReceivedArguments: (userIDs: [String], itemID: TimelineItemIdentifier)?
|
||||||
|
var withdrawVerificationAndResendUserIDsItemIDReceivedInvocations: [(userIDs: [String], itemID: TimelineItemIdentifier)] = []
|
||||||
|
|
||||||
|
var withdrawVerificationAndResendUserIDsItemIDUnderlyingReturnValue: Result<Void, RoomProxyError>!
|
||||||
|
var withdrawVerificationAndResendUserIDsItemIDReturnValue: Result<Void, RoomProxyError>! {
|
||||||
|
get {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
return withdrawVerificationAndResendUserIDsItemIDUnderlyingReturnValue
|
||||||
|
} else {
|
||||||
|
var returnValue: Result<Void, RoomProxyError>? = nil
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
returnValue = withdrawVerificationAndResendUserIDsItemIDUnderlyingReturnValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
withdrawVerificationAndResendUserIDsItemIDUnderlyingReturnValue = newValue
|
||||||
|
} else {
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
withdrawVerificationAndResendUserIDsItemIDUnderlyingReturnValue = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var withdrawVerificationAndResendUserIDsItemIDClosure: (([String], TimelineItemIdentifier) async -> Result<Void, RoomProxyError>)?
|
||||||
|
|
||||||
|
func withdrawVerificationAndResend(userIDs: [String], itemID: TimelineItemIdentifier) async -> Result<Void, RoomProxyError> {
|
||||||
|
withdrawVerificationAndResendUserIDsItemIDCallsCount += 1
|
||||||
|
withdrawVerificationAndResendUserIDsItemIDReceivedArguments = (userIDs: userIDs, itemID: itemID)
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.withdrawVerificationAndResendUserIDsItemIDReceivedInvocations.append((userIDs: userIDs, itemID: itemID))
|
||||||
|
}
|
||||||
|
if let withdrawVerificationAndResendUserIDsItemIDClosure = withdrawVerificationAndResendUserIDsItemIDClosure {
|
||||||
|
return await withdrawVerificationAndResendUserIDsItemIDClosure(userIDs, itemID)
|
||||||
|
} else {
|
||||||
|
return withdrawVerificationAndResendUserIDsItemIDReturnValue
|
||||||
|
}
|
||||||
|
}
|
||||||
//MARK: - flagAsUnread
|
//MARK: - flagAsUnread
|
||||||
|
|
||||||
var flagAsUnreadUnderlyingCallsCount = 0
|
var flagAsUnreadUnderlyingCallsCount = 0
|
||||||
|
@ -9974,6 +9974,82 @@ open class NotificationSettingsSDKMock: MatrixRustSDK.NotificationSettings {
|
|||||||
try await unmuteRoomRoomIdIsEncryptedIsOneToOneClosure?(roomId, isEncrypted, isOneToOne)
|
try await unmuteRoomRoomIdIsEncryptedIsOneToOneClosure?(roomId, isEncrypted, isOneToOne)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
open class OidcAuthorizationDataSDKMock: MatrixRustSDK.OidcAuthorizationData {
|
||||||
|
init() {
|
||||||
|
super.init(noPointer: .init())
|
||||||
|
}
|
||||||
|
|
||||||
|
public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) {
|
||||||
|
fatalError("init(unsafeFromRawPointer:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate var pointer: UnsafeMutableRawPointer!
|
||||||
|
|
||||||
|
//MARK: - loginUrl
|
||||||
|
|
||||||
|
var loginUrlUnderlyingCallsCount = 0
|
||||||
|
open var loginUrlCallsCount: Int {
|
||||||
|
get {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
return loginUrlUnderlyingCallsCount
|
||||||
|
} else {
|
||||||
|
var returnValue: Int? = nil
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
returnValue = loginUrlUnderlyingCallsCount
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
loginUrlUnderlyingCallsCount = newValue
|
||||||
|
} else {
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
loginUrlUnderlyingCallsCount = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
open var loginUrlCalled: Bool {
|
||||||
|
return loginUrlCallsCount > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var loginUrlUnderlyingReturnValue: String!
|
||||||
|
open var loginUrlReturnValue: String! {
|
||||||
|
get {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
return loginUrlUnderlyingReturnValue
|
||||||
|
} else {
|
||||||
|
var returnValue: String? = nil
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
returnValue = loginUrlUnderlyingReturnValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
loginUrlUnderlyingReturnValue = newValue
|
||||||
|
} else {
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
loginUrlUnderlyingReturnValue = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
open var loginUrlClosure: (() -> String)?
|
||||||
|
|
||||||
|
open override func loginUrl() -> String {
|
||||||
|
loginUrlCallsCount += 1
|
||||||
|
if let loginUrlClosure = loginUrlClosure {
|
||||||
|
return loginUrlClosure()
|
||||||
|
} else {
|
||||||
|
return loginUrlReturnValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
open class QrCodeDataSDKMock: MatrixRustSDK.QrCodeData {
|
open class QrCodeDataSDKMock: MatrixRustSDK.QrCodeData {
|
||||||
init() {
|
init() {
|
||||||
super.init(noPointer: .init())
|
super.init(noPointer: .init())
|
||||||
@ -11588,6 +11664,52 @@ open class RoomSDKMock: MatrixRustSDK.Room {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//MARK: - ignoreDeviceTrustAndResend
|
||||||
|
|
||||||
|
open var ignoreDeviceTrustAndResendDevicesTransactionIdThrowableError: Error?
|
||||||
|
var ignoreDeviceTrustAndResendDevicesTransactionIdUnderlyingCallsCount = 0
|
||||||
|
open var ignoreDeviceTrustAndResendDevicesTransactionIdCallsCount: Int {
|
||||||
|
get {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
return ignoreDeviceTrustAndResendDevicesTransactionIdUnderlyingCallsCount
|
||||||
|
} else {
|
||||||
|
var returnValue: Int? = nil
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
returnValue = ignoreDeviceTrustAndResendDevicesTransactionIdUnderlyingCallsCount
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
ignoreDeviceTrustAndResendDevicesTransactionIdUnderlyingCallsCount = newValue
|
||||||
|
} else {
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
ignoreDeviceTrustAndResendDevicesTransactionIdUnderlyingCallsCount = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
open var ignoreDeviceTrustAndResendDevicesTransactionIdCalled: Bool {
|
||||||
|
return ignoreDeviceTrustAndResendDevicesTransactionIdCallsCount > 0
|
||||||
|
}
|
||||||
|
open var ignoreDeviceTrustAndResendDevicesTransactionIdReceivedArguments: (devices: [String: [String]], transactionId: String)?
|
||||||
|
open var ignoreDeviceTrustAndResendDevicesTransactionIdReceivedInvocations: [(devices: [String: [String]], transactionId: String)] = []
|
||||||
|
open var ignoreDeviceTrustAndResendDevicesTransactionIdClosure: (([String: [String]], String) async throws -> Void)?
|
||||||
|
|
||||||
|
open override func ignoreDeviceTrustAndResend(devices: [String: [String]], transactionId: String) async throws {
|
||||||
|
if let error = ignoreDeviceTrustAndResendDevicesTransactionIdThrowableError {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
ignoreDeviceTrustAndResendDevicesTransactionIdCallsCount += 1
|
||||||
|
ignoreDeviceTrustAndResendDevicesTransactionIdReceivedArguments = (devices: devices, transactionId: transactionId)
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.ignoreDeviceTrustAndResendDevicesTransactionIdReceivedInvocations.append((devices: devices, transactionId: transactionId))
|
||||||
|
}
|
||||||
|
try await ignoreDeviceTrustAndResendDevicesTransactionIdClosure?(devices, transactionId)
|
||||||
|
}
|
||||||
|
|
||||||
//MARK: - ignoreUser
|
//MARK: - ignoreUser
|
||||||
|
|
||||||
open var ignoreUserUserIdThrowableError: Error?
|
open var ignoreUserUserIdThrowableError: Error?
|
||||||
@ -13149,16 +13271,16 @@ open class RoomSDKMock: MatrixRustSDK.Room {
|
|||||||
|
|
||||||
//MARK: - pinnedEventsTimeline
|
//MARK: - pinnedEventsTimeline
|
||||||
|
|
||||||
open var pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadThrowableError: Error?
|
open var pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsThrowableError: Error?
|
||||||
var pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadUnderlyingCallsCount = 0
|
var pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsUnderlyingCallsCount = 0
|
||||||
open var pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadCallsCount: Int {
|
open var pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsCallsCount: Int {
|
||||||
get {
|
get {
|
||||||
if Thread.isMainThread {
|
if Thread.isMainThread {
|
||||||
return pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadUnderlyingCallsCount
|
return pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsUnderlyingCallsCount
|
||||||
} else {
|
} else {
|
||||||
var returnValue: Int? = nil
|
var returnValue: Int? = nil
|
||||||
DispatchQueue.main.sync {
|
DispatchQueue.main.sync {
|
||||||
returnValue = pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadUnderlyingCallsCount
|
returnValue = pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsUnderlyingCallsCount
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnValue!
|
return returnValue!
|
||||||
@ -13166,29 +13288,29 @@ open class RoomSDKMock: MatrixRustSDK.Room {
|
|||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
if Thread.isMainThread {
|
if Thread.isMainThread {
|
||||||
pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadUnderlyingCallsCount = newValue
|
pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsUnderlyingCallsCount = newValue
|
||||||
} else {
|
} else {
|
||||||
DispatchQueue.main.sync {
|
DispatchQueue.main.sync {
|
||||||
pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadUnderlyingCallsCount = newValue
|
pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsUnderlyingCallsCount = newValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
open var pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadCalled: Bool {
|
open var pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsCalled: Bool {
|
||||||
return pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadCallsCount > 0
|
return pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsCallsCount > 0
|
||||||
}
|
}
|
||||||
open var pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadReceivedArguments: (internalIdPrefix: String?, maxEventsToLoad: UInt16)?
|
open var pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsReceivedArguments: (internalIdPrefix: String?, maxEventsToLoad: UInt16, maxConcurrentRequests: UInt16)?
|
||||||
open var pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadReceivedInvocations: [(internalIdPrefix: String?, maxEventsToLoad: UInt16)] = []
|
open var pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsReceivedInvocations: [(internalIdPrefix: String?, maxEventsToLoad: UInt16, maxConcurrentRequests: UInt16)] = []
|
||||||
|
|
||||||
var pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadUnderlyingReturnValue: Timeline!
|
var pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsUnderlyingReturnValue: Timeline!
|
||||||
open var pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadReturnValue: Timeline! {
|
open var pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsReturnValue: Timeline! {
|
||||||
get {
|
get {
|
||||||
if Thread.isMainThread {
|
if Thread.isMainThread {
|
||||||
return pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadUnderlyingReturnValue
|
return pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsUnderlyingReturnValue
|
||||||
} else {
|
} else {
|
||||||
var returnValue: Timeline? = nil
|
var returnValue: Timeline? = nil
|
||||||
DispatchQueue.main.sync {
|
DispatchQueue.main.sync {
|
||||||
returnValue = pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadUnderlyingReturnValue
|
returnValue = pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsUnderlyingReturnValue
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnValue!
|
return returnValue!
|
||||||
@ -13196,29 +13318,29 @@ open class RoomSDKMock: MatrixRustSDK.Room {
|
|||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
if Thread.isMainThread {
|
if Thread.isMainThread {
|
||||||
pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadUnderlyingReturnValue = newValue
|
pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsUnderlyingReturnValue = newValue
|
||||||
} else {
|
} else {
|
||||||
DispatchQueue.main.sync {
|
DispatchQueue.main.sync {
|
||||||
pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadUnderlyingReturnValue = newValue
|
pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsUnderlyingReturnValue = newValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
open var pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadClosure: ((String?, UInt16) async throws -> Timeline)?
|
open var pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsClosure: ((String?, UInt16, UInt16) async throws -> Timeline)?
|
||||||
|
|
||||||
open override func pinnedEventsTimeline(internalIdPrefix: String?, maxEventsToLoad: UInt16) async throws -> Timeline {
|
open override func pinnedEventsTimeline(internalIdPrefix: String?, maxEventsToLoad: UInt16, maxConcurrentRequests: UInt16) async throws -> Timeline {
|
||||||
if let error = pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadThrowableError {
|
if let error = pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsThrowableError {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadCallsCount += 1
|
pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsCallsCount += 1
|
||||||
pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadReceivedArguments = (internalIdPrefix: internalIdPrefix, maxEventsToLoad: maxEventsToLoad)
|
pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsReceivedArguments = (internalIdPrefix: internalIdPrefix, maxEventsToLoad: maxEventsToLoad, maxConcurrentRequests: maxConcurrentRequests)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadReceivedInvocations.append((internalIdPrefix: internalIdPrefix, maxEventsToLoad: maxEventsToLoad))
|
self.pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsReceivedInvocations.append((internalIdPrefix: internalIdPrefix, maxEventsToLoad: maxEventsToLoad, maxConcurrentRequests: maxConcurrentRequests))
|
||||||
}
|
}
|
||||||
if let pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadClosure = pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadClosure {
|
if let pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsClosure = pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsClosure {
|
||||||
return try await pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadClosure(internalIdPrefix, maxEventsToLoad)
|
return try await pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsClosure(internalIdPrefix, maxEventsToLoad, maxConcurrentRequests)
|
||||||
} else {
|
} else {
|
||||||
return pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadReturnValue
|
return pinnedEventsTimelineInternalIdPrefixMaxEventsToLoadMaxConcurrentRequestsReturnValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14345,6 +14467,52 @@ open class RoomSDKMock: MatrixRustSDK.Room {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//MARK: - tryResend
|
||||||
|
|
||||||
|
open var tryResendTransactionIdThrowableError: Error?
|
||||||
|
var tryResendTransactionIdUnderlyingCallsCount = 0
|
||||||
|
open var tryResendTransactionIdCallsCount: Int {
|
||||||
|
get {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
return tryResendTransactionIdUnderlyingCallsCount
|
||||||
|
} else {
|
||||||
|
var returnValue: Int? = nil
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
returnValue = tryResendTransactionIdUnderlyingCallsCount
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
tryResendTransactionIdUnderlyingCallsCount = newValue
|
||||||
|
} else {
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
tryResendTransactionIdUnderlyingCallsCount = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
open var tryResendTransactionIdCalled: Bool {
|
||||||
|
return tryResendTransactionIdCallsCount > 0
|
||||||
|
}
|
||||||
|
open var tryResendTransactionIdReceivedTransactionId: String?
|
||||||
|
open var tryResendTransactionIdReceivedInvocations: [String] = []
|
||||||
|
open var tryResendTransactionIdClosure: ((String) async throws -> Void)?
|
||||||
|
|
||||||
|
open override func tryResend(transactionId: String) async throws {
|
||||||
|
if let error = tryResendTransactionIdThrowableError {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
tryResendTransactionIdCallsCount += 1
|
||||||
|
tryResendTransactionIdReceivedTransactionId = transactionId
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.tryResendTransactionIdReceivedInvocations.append(transactionId)
|
||||||
|
}
|
||||||
|
try await tryResendTransactionIdClosure?(transactionId)
|
||||||
|
}
|
||||||
|
|
||||||
//MARK: - typingNotice
|
//MARK: - typingNotice
|
||||||
|
|
||||||
open var typingNoticeIsTypingThrowableError: Error?
|
open var typingNoticeIsTypingThrowableError: Error?
|
||||||
@ -14528,6 +14696,52 @@ open class RoomSDKMock: MatrixRustSDK.Room {
|
|||||||
}
|
}
|
||||||
try await uploadAvatarMimeTypeDataMediaInfoClosure?(mimeType, data, mediaInfo)
|
try await uploadAvatarMimeTypeDataMediaInfoClosure?(mimeType, data, mediaInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//MARK: - withdrawVerificationAndResend
|
||||||
|
|
||||||
|
open var withdrawVerificationAndResendUserIdsTransactionIdThrowableError: Error?
|
||||||
|
var withdrawVerificationAndResendUserIdsTransactionIdUnderlyingCallsCount = 0
|
||||||
|
open var withdrawVerificationAndResendUserIdsTransactionIdCallsCount: Int {
|
||||||
|
get {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
return withdrawVerificationAndResendUserIdsTransactionIdUnderlyingCallsCount
|
||||||
|
} else {
|
||||||
|
var returnValue: Int? = nil
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
returnValue = withdrawVerificationAndResendUserIdsTransactionIdUnderlyingCallsCount
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
withdrawVerificationAndResendUserIdsTransactionIdUnderlyingCallsCount = newValue
|
||||||
|
} else {
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
withdrawVerificationAndResendUserIdsTransactionIdUnderlyingCallsCount = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
open var withdrawVerificationAndResendUserIdsTransactionIdCalled: Bool {
|
||||||
|
return withdrawVerificationAndResendUserIdsTransactionIdCallsCount > 0
|
||||||
|
}
|
||||||
|
open var withdrawVerificationAndResendUserIdsTransactionIdReceivedArguments: (userIds: [String], transactionId: String)?
|
||||||
|
open var withdrawVerificationAndResendUserIdsTransactionIdReceivedInvocations: [(userIds: [String], transactionId: String)] = []
|
||||||
|
open var withdrawVerificationAndResendUserIdsTransactionIdClosure: (([String], String) async throws -> Void)?
|
||||||
|
|
||||||
|
open override func withdrawVerificationAndResend(userIds: [String], transactionId: String) async throws {
|
||||||
|
if let error = withdrawVerificationAndResendUserIdsTransactionIdThrowableError {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
withdrawVerificationAndResendUserIdsTransactionIdCallsCount += 1
|
||||||
|
withdrawVerificationAndResendUserIdsTransactionIdReceivedArguments = (userIds: userIds, transactionId: transactionId)
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.withdrawVerificationAndResendUserIdsTransactionIdReceivedInvocations.append((userIds: userIds, transactionId: transactionId))
|
||||||
|
}
|
||||||
|
try await withdrawVerificationAndResendUserIdsTransactionIdClosure?(userIds, transactionId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
open class RoomDirectorySearchSDKMock: MatrixRustSDK.RoomDirectorySearch {
|
open class RoomDirectorySearchSDKMock: MatrixRustSDK.RoomDirectorySearch {
|
||||||
init() {
|
init() {
|
||||||
|
@ -95,6 +95,10 @@ extension JoinedRoomProxyMock {
|
|||||||
return .success(member)
|
return .success(member)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resendItemIDReturnValue = .success(())
|
||||||
|
ignoreDeviceTrustAndResendDevicesItemIDReturnValue = .success(())
|
||||||
|
withdrawVerificationAndResendUserIDsItemIDReturnValue = .success(())
|
||||||
|
|
||||||
flagAsUnreadReturnValue = .success(())
|
flagAsUnreadReturnValue = .success(())
|
||||||
markAsReadReceiptTypeReturnValue = .success(())
|
markAsReadReceiptTypeReturnValue = .success(())
|
||||||
underlyingIsFavourite = false
|
underlyingIsFavourite = false
|
||||||
|
@ -19,6 +19,7 @@ extension ClientBuilder {
|
|||||||
.enableCrossProcessRefreshLock(processId: InfoPlistReader.main.bundleIdentifier, sessionDelegate: sessionDelegate)
|
.enableCrossProcessRefreshLock(processId: InfoPlistReader.main.bundleIdentifier, sessionDelegate: sessionDelegate)
|
||||||
.userAgent(userAgent: UserAgentBuilder.makeASCIIUserAgent())
|
.userAgent(userAgent: UserAgentBuilder.makeASCIIUserAgent())
|
||||||
.requestConfig(config: .init(retryLimit: 0, timeout: 30000, maxConcurrentRequests: nil, retryTimeout: nil))
|
.requestConfig(config: .init(retryLimit: 0, timeout: 30000, maxConcurrentRequests: nil, retryTimeout: nil))
|
||||||
|
.roomKeyRecipientStrategy(strategy: .deviceBasedStrategy(onlyAllowTrustedDevices: false, errorOnVerifiedUserProblem: true))
|
||||||
|
|
||||||
builder = switch slidingSync {
|
builder = switch slidingSync {
|
||||||
case .restored: builder
|
case .restored: builder
|
||||||
|
@ -14,33 +14,36 @@ import SwiftUI
|
|||||||
struct HeroImage: View {
|
struct HeroImage: View {
|
||||||
enum Style {
|
enum Style {
|
||||||
case normal
|
case normal
|
||||||
case positive
|
|
||||||
case subtle
|
case subtle
|
||||||
|
case success
|
||||||
case critical
|
case critical
|
||||||
|
case criticalOnSecondary
|
||||||
|
|
||||||
var foregroundColor: Color {
|
var foregroundColor: Color {
|
||||||
switch self {
|
switch self {
|
||||||
case .normal:
|
case .normal:
|
||||||
return .compound.iconPrimary
|
.compound.iconPrimary
|
||||||
case .positive:
|
|
||||||
return .compound.iconSuccessPrimary
|
|
||||||
case .subtle:
|
case .subtle:
|
||||||
return .compound.iconSecondary
|
.compound.iconSecondary
|
||||||
case .critical:
|
case .success:
|
||||||
return .compound.iconCriticalPrimary
|
.compound.iconSuccessPrimary
|
||||||
|
case .critical, .criticalOnSecondary:
|
||||||
|
.compound.iconCriticalPrimary
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var backgroundFillColor: Color {
|
var backgroundFillColor: Color {
|
||||||
switch self {
|
switch self {
|
||||||
case .normal:
|
case .normal:
|
||||||
return .compound.bgSubtleSecondary
|
.compound.bgSubtleSecondary
|
||||||
case .positive:
|
|
||||||
return .compound.bgSuccessSubtle
|
|
||||||
case .subtle:
|
case .subtle:
|
||||||
return .compound.bgSubtlePrimary
|
.compound.bgSubtlePrimary
|
||||||
|
case .success:
|
||||||
|
.compound.bgSuccessSubtle
|
||||||
case .critical:
|
case .critical:
|
||||||
return .compound.bgCanvasDefault
|
.compound.bgCriticalSubtle
|
||||||
|
case .criticalOnSecondary:
|
||||||
|
.compound.bgCanvasDefault
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,12 +89,21 @@ private struct HeroImageModifier: ViewModifier {
|
|||||||
|
|
||||||
struct HeroImage_Previews: PreviewProvider, TestablePreview {
|
struct HeroImage_Previews: PreviewProvider, TestablePreview {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
HStack(spacing: 20) {
|
VStack(spacing: 20) {
|
||||||
HeroImage(icon: \.lockSolid)
|
HStack(spacing: 20) {
|
||||||
Image(systemName: "hourglass")
|
HeroImage(icon: \.lockSolid)
|
||||||
.heroImage()
|
Image(systemName: "hourglass")
|
||||||
Image(asset: Asset.Images.serverSelectionIcon)
|
.heroImage()
|
||||||
.heroImage(insets: 19)
|
Image(asset: Asset.Images.serverSelectionIcon)
|
||||||
|
.heroImage(insets: 19)
|
||||||
|
}
|
||||||
|
|
||||||
|
HStack(spacing: 20) {
|
||||||
|
HeroImage(icon: \.helpSolid, style: .subtle)
|
||||||
|
HeroImage(icon: \.checkCircleSolid, style: .success)
|
||||||
|
HeroImage(icon: \.error, style: .critical)
|
||||||
|
HeroImage(icon: \.error, style: .criticalOnSecondary)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ struct EncryptionResetScreen: View {
|
|||||||
|
|
||||||
private var header: some View {
|
private var header: some View {
|
||||||
VStack(spacing: 8) {
|
VStack(spacing: 8) {
|
||||||
HeroImage(icon: \.error, style: .critical)
|
HeroImage(icon: \.error, style: .criticalOnSecondary)
|
||||||
.padding(.bottom, 8)
|
.padding(.bottom, 8)
|
||||||
|
|
||||||
Text(L10n.screenEncryptionResetTitle)
|
Text(L10n.screenEncryptionResetTitle)
|
||||||
|
@ -29,7 +29,7 @@ struct IdentityConfirmedScreen: View {
|
|||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var screenHeader: some View {
|
private var screenHeader: some View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
HeroImage(icon: \.checkCircle, style: .positive)
|
HeroImage(icon: \.checkCircle, style: .success)
|
||||||
.padding(.bottom, 16)
|
.padding(.bottom, 16)
|
||||||
|
|
||||||
Text(L10n.screenIdentityConfirmedTitle)
|
Text(L10n.screenIdentityConfirmedTitle)
|
||||||
|
@ -78,7 +78,9 @@ final class PinnedEventsTimelineScreenCoordinator: CoordinatorProtocol {
|
|||||||
case .viewInRoomTimeline(let eventID):
|
case .viewInRoomTimeline(let eventID):
|
||||||
actionsSubject.send(.displayRoomScreenWithFocussedPin(eventID: eventID))
|
actionsSubject.send(.displayRoomScreenWithFocussedPin(eventID: eventID))
|
||||||
// These other actions will not be handled in this view
|
// These other actions will not be handled in this view
|
||||||
case .displayEmojiPicker, .displayReportContent, .displayCameraPicker, .displayMediaPicker, .displayDocumentPicker, .displayLocationPicker, .displayPollForm, .displayMediaUploadPreviewScreen, .composer, .hasScrolled:
|
case .displayEmojiPicker, .displayReportContent, .displayCameraPicker, .displayMediaPicker,
|
||||||
|
.displayDocumentPicker, .displayLocationPicker, .displayPollForm, .displayMediaUploadPreviewScreen,
|
||||||
|
.displayResolveSendFailure, .composer, .hasScrolled:
|
||||||
// These actions are not handled in this coordinator
|
// These actions are not handled in this coordinator
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -266,7 +266,7 @@ struct QRCodeLoginScreen: View {
|
|||||||
case .connectionNotSecure:
|
case .connectionNotSecure:
|
||||||
VStack(spacing: 40) {
|
VStack(spacing: 40) {
|
||||||
VStack(spacing: 16) {
|
VStack(spacing: 16) {
|
||||||
HeroImage(icon: \.error, style: .critical)
|
HeroImage(icon: \.error, style: .criticalOnSecondary)
|
||||||
|
|
||||||
VStack(spacing: 8) {
|
VStack(spacing: 8) {
|
||||||
Text(L10n.screenQrCodeLoginConnectionNoteSecureStateTitle)
|
Text(L10n.screenQrCodeLoginConnectionNoteSecureStateTitle)
|
||||||
@ -332,7 +332,7 @@ struct QRCodeLoginScreen: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VStack(spacing: 16) {
|
VStack(spacing: 16) {
|
||||||
HeroImage(icon: \.error, style: .critical)
|
HeroImage(icon: \.error, style: .criticalOnSecondary)
|
||||||
|
|
||||||
VStack(spacing: 8) {
|
VStack(spacing: 8) {
|
||||||
Text(title)
|
Text(title)
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ResolveVerifiedUserSendFailureScreenCoordinatorParameters {
|
||||||
|
let failure: TimelineItemSendFailure.VerifiedUser
|
||||||
|
let itemID: TimelineItemIdentifier
|
||||||
|
let roomProxy: JoinedRoomProxyProtocol
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ResolveVerifiedUserSendFailureScreenCoordinatorAction {
|
||||||
|
case dismiss
|
||||||
|
}
|
||||||
|
|
||||||
|
final class ResolveVerifiedUserSendFailureScreenCoordinator: CoordinatorProtocol {
|
||||||
|
private let parameters: ResolveVerifiedUserSendFailureScreenCoordinatorParameters
|
||||||
|
private let viewModel: ResolveVerifiedUserSendFailureScreenViewModelProtocol
|
||||||
|
|
||||||
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
private let actionsSubject: PassthroughSubject<ResolveVerifiedUserSendFailureScreenCoordinatorAction, Never> = .init()
|
||||||
|
var actionsPublisher: AnyPublisher<ResolveVerifiedUserSendFailureScreenCoordinatorAction, Never> {
|
||||||
|
actionsSubject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
init(parameters: ResolveVerifiedUserSendFailureScreenCoordinatorParameters) {
|
||||||
|
self.parameters = parameters
|
||||||
|
|
||||||
|
viewModel = ResolveVerifiedUserSendFailureScreenViewModel(failure: parameters.failure,
|
||||||
|
itemID: parameters.itemID,
|
||||||
|
roomProxy: parameters.roomProxy)
|
||||||
|
}
|
||||||
|
|
||||||
|
func start() {
|
||||||
|
viewModel.actionsPublisher.sink { [weak self] action in
|
||||||
|
MXLog.info("Coordinator: received view model action: \(action)")
|
||||||
|
|
||||||
|
guard let self else { return }
|
||||||
|
switch action {
|
||||||
|
case .dismiss:
|
||||||
|
actionsSubject.send(.dismiss)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toPresentable() -> AnyView {
|
||||||
|
AnyView(ResolveVerifiedUserSendFailureScreen(context: viewModel.context))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum ResolveVerifiedUserSendFailureScreenViewModelAction {
|
||||||
|
case dismiss
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ResolveVerifiedUserSendFailureScreenViewState: BindableState {
|
||||||
|
var currentFailure: TimelineItemSendFailure.VerifiedUser
|
||||||
|
var currentMemberDisplayName: String
|
||||||
|
|
||||||
|
var title: String {
|
||||||
|
switch currentFailure {
|
||||||
|
case .hasUnsignedDevice: L10n.screenResolveSendFailureUnsignedDeviceTitle(currentMemberDisplayName)
|
||||||
|
case .changedIdentity: L10n.screenResolveSendFailureChangedIdentityTitle(currentMemberDisplayName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var subtitle: String {
|
||||||
|
switch currentFailure {
|
||||||
|
case .hasUnsignedDevice: L10n.screenResolveSendFailureUnsignedDeviceSubtitle(currentMemberDisplayName, currentMemberDisplayName)
|
||||||
|
case .changedIdentity: L10n.screenResolveSendFailureChangedIdentitySubtitle(currentMemberDisplayName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var primaryButtonTitle: String {
|
||||||
|
switch currentFailure {
|
||||||
|
case .hasUnsignedDevice: L10n.screenResolveSendFailureUnsignedDevicePrimaryButtonTitle
|
||||||
|
case .changedIdentity: L10n.screenResolveSendFailureChangedIdentityPrimaryButtonTitle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ResolveVerifiedUserSendFailureScreenViewAction {
|
||||||
|
case resolveAndResend
|
||||||
|
case resend
|
||||||
|
case cancel
|
||||||
|
}
|
@ -0,0 +1,132 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
typealias ResolveVerifiedUserSendFailureScreenViewModelType = StateStoreViewModel<ResolveVerifiedUserSendFailureScreenViewState, ResolveVerifiedUserSendFailureScreenViewAction>
|
||||||
|
|
||||||
|
class ResolveVerifiedUserSendFailureScreenViewModel: ResolveVerifiedUserSendFailureScreenViewModelType, ResolveVerifiedUserSendFailureScreenViewModelProtocol {
|
||||||
|
private let iterator: VerifiedUserSendFailureIterator
|
||||||
|
private let failure: TimelineItemSendFailure.VerifiedUser
|
||||||
|
private let itemID: TimelineItemIdentifier
|
||||||
|
private let roomProxy: JoinedRoomProxyProtocol
|
||||||
|
private var members: [String: RoomMemberProxyProtocol]
|
||||||
|
|
||||||
|
private let actionsSubject: PassthroughSubject<ResolveVerifiedUserSendFailureScreenViewModelAction, Never> = .init()
|
||||||
|
var actionsPublisher: AnyPublisher<ResolveVerifiedUserSendFailureScreenViewModelAction, Never> {
|
||||||
|
actionsSubject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
init(failure: TimelineItemSendFailure.VerifiedUser, itemID: TimelineItemIdentifier, roomProxy: JoinedRoomProxyProtocol) {
|
||||||
|
iterator = switch failure {
|
||||||
|
case .hasUnsignedDevice(let devices): UnsignedDeviceFailureIterator(devices: devices)
|
||||||
|
case .changedIdentity(let users): ChangedIdentityFailureIterator(users: users)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.failure = failure
|
||||||
|
self.itemID = itemID
|
||||||
|
self.roomProxy = roomProxy
|
||||||
|
|
||||||
|
members = Dictionary(uniqueKeysWithValues: roomProxy.membersPublisher.value.map { ($0.userID, $0) })
|
||||||
|
|
||||||
|
guard let (userID, failure) = iterator.next() else {
|
||||||
|
MXLog.error("There aren't any known users/devices to resolve the failure with.")
|
||||||
|
fatalError("There aren't any known users/devices to resolve the failure with.")
|
||||||
|
}
|
||||||
|
|
||||||
|
super.init(initialViewState: ResolveVerifiedUserSendFailureScreenViewState(currentFailure: failure,
|
||||||
|
currentMemberDisplayName: members[userID]?.displayName ?? userID))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Public
|
||||||
|
|
||||||
|
override func process(viewAction: ResolveVerifiedUserSendFailureScreenViewAction) {
|
||||||
|
MXLog.info("View model: received view action: \(viewAction)")
|
||||||
|
|
||||||
|
switch viewAction {
|
||||||
|
case .resolveAndResend:
|
||||||
|
Task { await resolveAndResend() }
|
||||||
|
case .resend:
|
||||||
|
Task { await resend() }
|
||||||
|
case .cancel:
|
||||||
|
actionsSubject.send(.dismiss)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func resolveAndResend() async {
|
||||||
|
let result = switch failure {
|
||||||
|
case .hasUnsignedDevice(let devices):
|
||||||
|
await roomProxy.ignoreDeviceTrustAndResend(devices: devices, itemID: itemID)
|
||||||
|
case .changedIdentity(let users):
|
||||||
|
await roomProxy.withdrawVerificationAndResend(userIDs: users, itemID: itemID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if case let .failure(error) = result {
|
||||||
|
#warning("Show the error?")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if let (userID, failure) = iterator.next() {
|
||||||
|
state.currentMemberDisplayName = members[userID]?.displayName ?? userID
|
||||||
|
state.currentFailure = failure
|
||||||
|
} else {
|
||||||
|
actionsSubject.send(.dismiss)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func resend() async {
|
||||||
|
switch await roomProxy.resend(itemID: itemID) {
|
||||||
|
case .success:
|
||||||
|
actionsSubject.send(.dismiss)
|
||||||
|
case .failure(let failure):
|
||||||
|
#warning("Show the error?")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Iterators
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
private protocol VerifiedUserSendFailureIterator {
|
||||||
|
func next() -> (userID: String, failure: TimelineItemSendFailure.VerifiedUser)?
|
||||||
|
}
|
||||||
|
|
||||||
|
private class UnsignedDeviceFailureIterator: VerifiedUserSendFailureIterator {
|
||||||
|
private var iterator: [String: [String]].Iterator
|
||||||
|
|
||||||
|
init(devices: [String: [String]]) {
|
||||||
|
iterator = devices.makeIterator()
|
||||||
|
}
|
||||||
|
|
||||||
|
func next() -> (userID: String, failure: TimelineItemSendFailure.VerifiedUser)? {
|
||||||
|
guard let nextUserDevices = iterator.next() else { return nil }
|
||||||
|
return (nextUserDevices.key, .hasUnsignedDevice(devices: [nextUserDevices.key: nextUserDevices.value]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ChangedIdentityFailureIterator: VerifiedUserSendFailureIterator {
|
||||||
|
private var iterator: [String].Iterator
|
||||||
|
|
||||||
|
init(users: [String]) {
|
||||||
|
iterator = users.makeIterator()
|
||||||
|
}
|
||||||
|
|
||||||
|
func next() -> (userID: String, failure: TimelineItemSendFailure.VerifiedUser)? {
|
||||||
|
guard let nextUserID = iterator.next() else { return nil }
|
||||||
|
return (nextUserID, .changedIdentity(users: [nextUserID]))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
protocol ResolveVerifiedUserSendFailureScreenViewModelProtocol {
|
||||||
|
var actionsPublisher: AnyPublisher<ResolveVerifiedUserSendFailureScreenViewModelAction, Never> { get }
|
||||||
|
var context: ResolveVerifiedUserSendFailureScreenViewModelType.Context { get }
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Compound
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ResolveVerifiedUserSendFailureScreen: View {
|
||||||
|
@ObservedObject var context: ResolveVerifiedUserSendFailureScreenViewModel.Context
|
||||||
|
@State private var sheetFrame: CGRect = .zero
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ScrollView {
|
||||||
|
VStack(spacing: 40) {
|
||||||
|
header
|
||||||
|
buttons
|
||||||
|
}
|
||||||
|
.padding(.top, 24)
|
||||||
|
.padding(.bottom, 16)
|
||||||
|
.padding(.horizontal, 16)
|
||||||
|
.readFrame($sheetFrame)
|
||||||
|
}
|
||||||
|
.scrollBounceBehavior(.basedOnSize)
|
||||||
|
.presentationDetents([.height(sheetFrame.height)])
|
||||||
|
}
|
||||||
|
|
||||||
|
var header: some View {
|
||||||
|
VStack(spacing: 8) {
|
||||||
|
HeroImage(icon: \.error, style: .critical)
|
||||||
|
.padding(.bottom, 8)
|
||||||
|
|
||||||
|
Text(context.viewState.title)
|
||||||
|
.font(.compound.headingMDBold)
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
.foregroundColor(.compound.textPrimary)
|
||||||
|
|
||||||
|
Text(context.viewState.subtitle)
|
||||||
|
.font(.compound.bodyMD)
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
.foregroundColor(.compound.textSecondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var buttons: some View {
|
||||||
|
VStack(spacing: 16) {
|
||||||
|
Button(context.viewState.primaryButtonTitle) {
|
||||||
|
context.send(viewAction: .resolveAndResend)
|
||||||
|
}
|
||||||
|
.buttonStyle(.compound(.primary))
|
||||||
|
|
||||||
|
Button(L10n.actionRetry) {
|
||||||
|
context.send(viewAction: .resend)
|
||||||
|
}
|
||||||
|
.buttonStyle(.compound(.secondary))
|
||||||
|
|
||||||
|
Button { context.send(viewAction: .cancel) } label: {
|
||||||
|
Text(L10n.actionCancelForNow)
|
||||||
|
.padding(.vertical, 14)
|
||||||
|
}
|
||||||
|
.buttonStyle(.compound(.plain))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Previews
|
||||||
|
|
||||||
|
struct ResolveVerifiedUserSendFailureScreen_Previews: PreviewProvider, TestablePreview {
|
||||||
|
static let unsignedDeviceViewModel = makeViewModel(failure: .hasUnsignedDevice(devices: ["@alice:matrix.org": []]))
|
||||||
|
static let changedIdentityViewModel = makeViewModel(failure: .changedIdentity(users: ["@alice:matrix.org"]))
|
||||||
|
|
||||||
|
static var previews: some View {
|
||||||
|
ResolveVerifiedUserSendFailureScreen(context: unsignedDeviceViewModel.context)
|
||||||
|
.previewDisplayName("Unsigned Device")
|
||||||
|
|
||||||
|
ResolveVerifiedUserSendFailureScreen(context: changedIdentityViewModel.context)
|
||||||
|
.previewDisplayName("Identity Changed")
|
||||||
|
}
|
||||||
|
|
||||||
|
static func makeViewModel(failure: TimelineItemSendFailure.VerifiedUser) -> ResolveVerifiedUserSendFailureScreenViewModel {
|
||||||
|
ResolveVerifiedUserSendFailureScreenViewModel(failure: failure,
|
||||||
|
itemID: .random,
|
||||||
|
roomProxy: JoinedRoomProxyMock(.init()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ResolveVerifiedUserSendFailureScreenSheet_Previews: PreviewProvider {
|
||||||
|
static let viewModel = ResolveVerifiedUserSendFailureScreenViewModel(failure: .changedIdentity(users: ["@alice:matrix.org"]),
|
||||||
|
itemID: .random,
|
||||||
|
roomProxy: JoinedRoomProxyMock(.init()))
|
||||||
|
|
||||||
|
static var previews: some View {
|
||||||
|
Text("Hello")
|
||||||
|
.sheet(isPresented: .constant(true)) {
|
||||||
|
ResolveVerifiedUserSendFailureScreen(context: viewModel.context)
|
||||||
|
}
|
||||||
|
.previewDisplayName("Sheet")
|
||||||
|
}
|
||||||
|
}
|
@ -38,6 +38,7 @@ enum RoomScreenCoordinatorAction {
|
|||||||
case presentMessageForwarding(forwardingItem: MessageForwardingItem)
|
case presentMessageForwarding(forwardingItem: MessageForwardingItem)
|
||||||
case presentCallScreen
|
case presentCallScreen
|
||||||
case presentPinnedEventsTimeline
|
case presentPinnedEventsTimeline
|
||||||
|
case presentResolveSendFailure(failure: TimelineItemSendFailure.VerifiedUser, itemID: TimelineItemIdentifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
final class RoomScreenCoordinator: CoordinatorProtocol {
|
final class RoomScreenCoordinator: CoordinatorProtocol {
|
||||||
@ -126,6 +127,8 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
|
|||||||
actionsSubject.send(.presentMessageForwarding(forwardingItem: forwardingItem))
|
actionsSubject.send(.presentMessageForwarding(forwardingItem: forwardingItem))
|
||||||
case .displayLocation(let body, let geoURI, let description):
|
case .displayLocation(let body, let geoURI, let description):
|
||||||
actionsSubject.send(.presentLocationViewer(body: body, geoURI: geoURI, description: description))
|
actionsSubject.send(.presentLocationViewer(body: body, geoURI: geoURI, description: description))
|
||||||
|
case .displayResolveSendFailure(let failure, let itemID):
|
||||||
|
actionsSubject.send(.presentResolveSendFailure(failure: failure, itemID: itemID))
|
||||||
case .composer(let action):
|
case .composer(let action):
|
||||||
composerViewModel.process(timelineAction: action)
|
composerViewModel.process(timelineAction: action)
|
||||||
case .hasScrolled(direction: let direction):
|
case .hasScrolled(direction: let direction):
|
||||||
|
@ -75,7 +75,10 @@ struct RoomScreen: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.sheet(item: $timelineContext.reactionSummaryInfo) {
|
.sheet(item: $timelineContext.reactionSummaryInfo) {
|
||||||
ReactionsSummaryView(reactions: $0.reactions, members: timelineContext.viewState.members, mediaProvider: timelineContext.mediaProvider, selectedReactionKey: $0.selectedKey)
|
ReactionsSummaryView(reactions: $0.reactions,
|
||||||
|
members: timelineContext.viewState.members,
|
||||||
|
mediaProvider: timelineContext.mediaProvider,
|
||||||
|
selectedReactionKey: $0.selectedKey)
|
||||||
.edgesIgnoringSafeArea([.bottom])
|
.edgesIgnoringSafeArea([.bottom])
|
||||||
}
|
}
|
||||||
.sheet(item: $timelineContext.readReceiptsSummaryInfo) {
|
.sheet(item: $timelineContext.readReceiptsSummaryInfo) {
|
||||||
|
@ -21,6 +21,7 @@ enum TimelineViewModelAction {
|
|||||||
case tappedOnSenderDetails(userID: String)
|
case tappedOnSenderDetails(userID: String)
|
||||||
case displayMessageForwarding(forwardingItem: MessageForwardingItem)
|
case displayMessageForwarding(forwardingItem: MessageForwardingItem)
|
||||||
case displayLocation(body: String, geoURI: GeoURI, description: String?)
|
case displayLocation(body: String, geoURI: GeoURI, description: String?)
|
||||||
|
case displayResolveSendFailure(failure: TimelineItemSendFailure.VerifiedUser, itemID: TimelineItemIdentifier)
|
||||||
case composer(action: TimelineComposerAction)
|
case composer(action: TimelineComposerAction)
|
||||||
case hasScrolled(direction: ScrollDirection)
|
case hasScrolled(direction: ScrollDirection)
|
||||||
case viewInRoomTimeline(eventID: String)
|
case viewInRoomTimeline(eventID: String)
|
||||||
|
@ -550,9 +550,10 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
|||||||
fatalError("Only events can have send info.")
|
fatalError("Only events can have send info.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if case .sendingFailed = eventTimelineItem.properties.deliveryStatus {
|
if case .sendingFailed(.unknown) = eventTimelineItem.properties.deliveryStatus {
|
||||||
// In the future we will show different errors for the various failure reasons.
|
|
||||||
displayAlert(.sendingFailed)
|
displayAlert(.sendingFailed)
|
||||||
|
} else if case let .sendingFailed(.verifiedUser(failure)) = eventTimelineItem.properties.deliveryStatus {
|
||||||
|
actionsSubject.send(.displayResolveSendFailure(failure: failure, itemID: itemID))
|
||||||
} else if let authenticityMessage = eventTimelineItem.properties.encryptionAuthenticity?.message {
|
} else if let authenticityMessage = eventTimelineItem.properties.encryptionAuthenticity?.message {
|
||||||
displayAlert(.encryptionAuthenticity(authenticityMessage))
|
displayAlert(.encryptionAuthenticity(authenticityMessage))
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,9 @@ struct TimelineItemMenu: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 8) {
|
VStack(spacing: 8) {
|
||||||
messagePreview
|
messagePreview
|
||||||
|
.padding(.horizontal, 16)
|
||||||
|
.padding(.top, 32.0)
|
||||||
|
.padding(.bottom, 4.0)
|
||||||
.frame(idealWidth: 300.0)
|
.frame(idealWidth: 300.0)
|
||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
@ -30,7 +33,6 @@ struct TimelineItemMenu: View {
|
|||||||
VStack(alignment: .leading, spacing: 0.0) {
|
VStack(alignment: .leading, spacing: 0.0) {
|
||||||
if !actions.reactions.isEmpty {
|
if !actions.reactions.isEmpty {
|
||||||
reactionsSection
|
reactionsSection
|
||||||
.padding(.top, 4.0)
|
|
||||||
.padding(.bottom, 8.0)
|
.padding(.bottom, 8.0)
|
||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
@ -87,15 +89,20 @@ struct TimelineItemMenu: View {
|
|||||||
}
|
}
|
||||||
.accessibilityElement(children: .combine)
|
.accessibilityElement(children: .combine)
|
||||||
|
|
||||||
if let authenticity = item.properties.encryptionAuthenticity {
|
if case let .sendingFailed(.verifiedUser(failure)) = item.properties.deliveryStatus {
|
||||||
|
Divider()
|
||||||
|
.padding(.horizontal, -16)
|
||||||
|
|
||||||
|
VerifiedUserSendFailureView(failure: failure, members: context.viewState.members) {
|
||||||
|
send(.itemSendInfoTapped(itemID: item.id))
|
||||||
|
}
|
||||||
|
.padding(.bottom, 8)
|
||||||
|
} else if let authenticity = item.properties.encryptionAuthenticity {
|
||||||
Label(authenticity.message, icon: authenticity.icon, iconSize: .small, relativeTo: .compound.bodySMSemibold)
|
Label(authenticity.message, icon: authenticity.icon, iconSize: .small, relativeTo: .compound.bodySMSemibold)
|
||||||
.font(.compound.bodySMSemibold)
|
.font(.compound.bodySMSemibold)
|
||||||
.foregroundStyle(authenticity.foregroundStyle)
|
.foregroundStyle(authenticity.foregroundStyle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal)
|
|
||||||
.padding(.top, 32.0)
|
|
||||||
.padding(.bottom, 4.0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var reactionsSection: some View {
|
private var reactionsSection: some View {
|
||||||
@ -162,10 +169,50 @@ struct TimelineItemMenu: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func send(_ action: TimelineItemMenuAction) {
|
private func send(_ action: TimelineItemMenuAction) {
|
||||||
|
send(.handleTimelineItemMenuAction(itemID: item.id, action: action))
|
||||||
|
}
|
||||||
|
|
||||||
|
private func send(_ action: TimelineViewAction) {
|
||||||
dismiss()
|
dismiss()
|
||||||
// Otherwise we might get errors that a sheet is already presented
|
// Otherwise we might get errors that a sheet is already presented
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||||
context.send(viewAction: .handleTimelineItemMenuAction(itemID: item.id, action: action))
|
context.send(viewAction: action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct VerifiedUserSendFailureView: View {
|
||||||
|
let failure: TimelineItemSendFailure.VerifiedUser
|
||||||
|
let action: () -> Void
|
||||||
|
|
||||||
|
private let memberDisplayName: String
|
||||||
|
|
||||||
|
init(failure: TimelineItemSendFailure.VerifiedUser,
|
||||||
|
members: [String: RoomMemberState],
|
||||||
|
action: @escaping () -> Void) {
|
||||||
|
self.failure = failure
|
||||||
|
self.action = action
|
||||||
|
|
||||||
|
let userIDs = failure.affectedUserIDs
|
||||||
|
memberDisplayName = userIDs.first.map { members[$0]?.displayName ?? $0 } ?? ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var title: String {
|
||||||
|
switch failure {
|
||||||
|
case .hasUnsignedDevice: L10n.screenTimelineItemMenuSendFailureUnsignedDevice(memberDisplayName)
|
||||||
|
case .changedIdentity: L10n.screenTimelineItemMenuSendFailureChangedIdentity(memberDisplayName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Button(action: action) {
|
||||||
|
HStack(spacing: 8) {
|
||||||
|
Label(title, icon: \.error, iconSize: .small, relativeTo: .compound.bodySMSemibold)
|
||||||
|
.font(.compound.bodySMSemibold)
|
||||||
|
.foregroundStyle(.compound.textCriticalPrimary)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
ListRowAccessory.navigationLink
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,20 +234,27 @@ struct TimelineItemMenu_Previews: PreviewProvider, TestablePreview {
|
|||||||
static let (backupItem, _) = makeItem(authenticity: .notGuaranteed(color: .gray))
|
static let (backupItem, _) = makeItem(authenticity: .notGuaranteed(color: .gray))
|
||||||
static let (unsignedItem, _) = makeItem(authenticity: .unsignedDevice(color: .red))
|
static let (unsignedItem, _) = makeItem(authenticity: .unsignedDevice(color: .red))
|
||||||
static let (unencryptedItem, _) = makeItem(authenticity: .sentInClear(color: .red))
|
static let (unencryptedItem, _) = makeItem(authenticity: .sentInClear(color: .red))
|
||||||
|
static let (unknownFailureItem, _) = makeItem(deliveryStatus: .sendingFailed(.unknown))
|
||||||
|
static let (identityChangedItem, _) = makeItem(deliveryStatus: .sendingFailed(.verifiedUser(.changedIdentity(users: [
|
||||||
|
"@alice:matrix.org"
|
||||||
|
]))))
|
||||||
|
static let (unsignedDevicesItem, _) = makeItem(deliveryStatus: .sendingFailed(.verifiedUser(.hasUnsignedDevice(devices: [
|
||||||
|
"@alice:matrix.org": ["DEVICE1", "DEVICE2"]
|
||||||
|
]))))
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
TimelineItemMenu(item: item, actions: actions)
|
TimelineItemMenu(item: item, actions: actions)
|
||||||
.environmentObject(viewModel.context)
|
.environmentObject(viewModel.context)
|
||||||
.previewDisplayName("With button shapes off")
|
.previewDisplayName("Normal")
|
||||||
|
|
||||||
TimelineItemMenu(item: item, actions: actions)
|
TimelineItemMenu(item: item, actions: actions)
|
||||||
.environmentObject(viewModel.context)
|
.environmentObject(viewModel.context)
|
||||||
.environment(\._accessibilityShowButtonShapes, true)
|
.environment(\._accessibilityShowButtonShapes, true)
|
||||||
.previewDisplayName("With button shapes on")
|
.previewDisplayName("Button shapes")
|
||||||
|
|
||||||
TimelineItemMenu(item: backupItem, actions: actions)
|
TimelineItemMenu(item: backupItem, actions: actions)
|
||||||
.environmentObject(viewModel.context)
|
.environmentObject(viewModel.context)
|
||||||
.previewDisplayName("Authenticity not guaranteed")
|
.previewDisplayName("Authenticity")
|
||||||
|
|
||||||
TimelineItemMenu(item: unsignedItem, actions: actions)
|
TimelineItemMenu(item: unsignedItem, actions: actions)
|
||||||
.environmentObject(viewModel.context)
|
.environmentObject(viewModel.context)
|
||||||
@ -209,9 +263,22 @@ struct TimelineItemMenu_Previews: PreviewProvider, TestablePreview {
|
|||||||
TimelineItemMenu(item: unencryptedItem, actions: actions)
|
TimelineItemMenu(item: unencryptedItem, actions: actions)
|
||||||
.environmentObject(viewModel.context)
|
.environmentObject(viewModel.context)
|
||||||
.previewDisplayName("Unencrypted")
|
.previewDisplayName("Unencrypted")
|
||||||
|
|
||||||
|
TimelineItemMenu(item: unknownFailureItem, actions: actions)
|
||||||
|
.environmentObject(viewModel.context)
|
||||||
|
.previewDisplayName("Unknown failure")
|
||||||
|
|
||||||
|
TimelineItemMenu(item: unsignedDevicesItem, actions: actions)
|
||||||
|
.environmentObject(viewModel.context)
|
||||||
|
.previewDisplayName("Unsigned Devices")
|
||||||
|
|
||||||
|
TimelineItemMenu(item: identityChangedItem, actions: actions)
|
||||||
|
.environmentObject(viewModel.context)
|
||||||
|
.previewDisplayName("Identity Changed")
|
||||||
}
|
}
|
||||||
|
|
||||||
static func makeItem(authenticity: EncryptionAuthenticity? = nil) -> (TextRoomTimelineItem, TimelineItemMenuActions)! {
|
static func makeItem(authenticity: EncryptionAuthenticity? = nil,
|
||||||
|
deliveryStatus: TimelineItemDeliveryStatus? = nil) -> (TextRoomTimelineItem, TimelineItemMenuActions)! {
|
||||||
guard var item = RoomTimelineItemFixtures.singleMessageChunk.first as? TextRoomTimelineItem,
|
guard var item = RoomTimelineItemFixtures.singleMessageChunk.first as? TextRoomTimelineItem,
|
||||||
let actions = TimelineItemMenuActions(isReactable: true,
|
let actions = TimelineItemMenuActions(isReactable: true,
|
||||||
actions: [.copy, .edit, .reply(isThread: false), .pin, .redact],
|
actions: [.copy, .edit, .reply(isThread: false), .pin, .redact],
|
||||||
@ -223,6 +290,10 @@ struct TimelineItemMenu_Previews: PreviewProvider, TestablePreview {
|
|||||||
item.properties.encryptionAuthenticity = authenticity
|
item.properties.encryptionAuthenticity = authenticity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let deliveryStatus {
|
||||||
|
item.properties.deliveryStatus = deliveryStatus
|
||||||
|
}
|
||||||
|
|
||||||
return (item, actions)
|
return (item, actions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
|||||||
private var innerPinnedEventsTimelineTask: Task<TimelineProxyProtocol?, Never>?
|
private var innerPinnedEventsTimelineTask: Task<TimelineProxyProtocol?, Never>?
|
||||||
var pinnedEventsTimeline: TimelineProxyProtocol? {
|
var pinnedEventsTimeline: TimelineProxyProtocol? {
|
||||||
get async {
|
get async {
|
||||||
// Check if is alrrady available.
|
// Check if is already available.
|
||||||
if let innerPinnedEventsTimeline {
|
if let innerPinnedEventsTimeline {
|
||||||
return innerPinnedEventsTimeline
|
return innerPinnedEventsTimeline
|
||||||
// Otherwise check if there is already a task loading it, and wait for it.
|
// Otherwise check if there is already a task loading it, and wait for it.
|
||||||
@ -35,7 +35,10 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let timeline = try await TimelineProxy(timeline: room.pinnedEventsTimeline(internalIdPrefix: nil, maxEventsToLoad: 100), kind: .pinned)
|
let timeline = try await TimelineProxy(timeline: room.pinnedEventsTimeline(internalIdPrefix: nil,
|
||||||
|
maxEventsToLoad: 100,
|
||||||
|
maxConcurrentRequests: 10),
|
||||||
|
kind: .pinned)
|
||||||
await timeline.subscribeForUpdates()
|
await timeline.subscribeForUpdates()
|
||||||
innerPinnedEventsTimeline = timeline
|
innerPinnedEventsTimeline = timeline
|
||||||
return timeline
|
return timeline
|
||||||
@ -377,6 +380,51 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resend(itemID: TimelineItemIdentifier) async -> Result<Void, RoomProxyError> {
|
||||||
|
guard let transactionID = itemID.transactionID else {
|
||||||
|
MXLog.error("Attempting to resend an item that has no transaction ID: \(itemID)")
|
||||||
|
return .failure(.missingTransactionID)
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
try await room.tryResend(transactionId: transactionID)
|
||||||
|
return .success(())
|
||||||
|
} catch {
|
||||||
|
MXLog.error("Failed resending \(transactionID) with error: \(error)")
|
||||||
|
return .failure(.sdkError(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ignoreDeviceTrustAndResend(devices: [String: [String]], itemID: TimelineItemIdentifier) async -> Result<Void, RoomProxyError> {
|
||||||
|
guard let transactionID = itemID.transactionID else {
|
||||||
|
MXLog.error("Attempting to resend an item that has no transaction ID: \(itemID)")
|
||||||
|
return .failure(.missingTransactionID)
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
try await room.ignoreDeviceTrustAndResend(devices: devices, transactionId: transactionID)
|
||||||
|
return .success(())
|
||||||
|
} catch {
|
||||||
|
MXLog.error("Failed trusting devices \(devices) and resending \(transactionID) with error: \(error)")
|
||||||
|
return .failure(.sdkError(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func withdrawVerificationAndResend(userIDs: [String], itemID: TimelineItemIdentifier) async -> Result<Void, RoomProxyError> {
|
||||||
|
guard let transactionID = itemID.transactionID else {
|
||||||
|
MXLog.error("Attempting to resend an item that has no transaction ID: \(itemID)")
|
||||||
|
return .failure(.missingTransactionID)
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
try await room.withdrawVerificationAndResend(userIds: userIDs, transactionId: transactionID)
|
||||||
|
return .success(())
|
||||||
|
} catch {
|
||||||
|
MXLog.error("Failed withdrawing verification of \(userIDs) and resending \(transactionID) with error: \(error)")
|
||||||
|
return .failure(.sdkError(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Room flags
|
// MARK: - Room flags
|
||||||
|
|
||||||
func flagAsUnread(_ isUnread: Bool) async -> Result<Void, RoomProxyError> {
|
func flagAsUnread(_ isUnread: Bool) async -> Result<Void, RoomProxyError> {
|
||||||
|
@ -15,6 +15,7 @@ enum RoomProxyError: Error {
|
|||||||
case invalidURL
|
case invalidURL
|
||||||
case invalidMedia
|
case invalidMedia
|
||||||
case eventNotFound
|
case eventNotFound
|
||||||
|
case missingTransactionID
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RoomProxyType {
|
enum RoomProxyType {
|
||||||
@ -111,6 +112,12 @@ protocol JoinedRoomProxyProtocol: RoomProxyProtocol {
|
|||||||
/// https://spec.matrix.org/v1.9/client-server-api/#typing-notifications
|
/// https://spec.matrix.org/v1.9/client-server-api/#typing-notifications
|
||||||
@discardableResult func sendTypingNotification(isTyping: Bool) async -> Result<Void, RoomProxyError>
|
@discardableResult func sendTypingNotification(isTyping: Bool) async -> Result<Void, RoomProxyError>
|
||||||
|
|
||||||
|
func resend(itemID: TimelineItemIdentifier) async -> Result<Void, RoomProxyError>
|
||||||
|
|
||||||
|
func ignoreDeviceTrustAndResend(devices: [String: [String]], itemID: TimelineItemIdentifier) async -> Result<Void, RoomProxyError>
|
||||||
|
|
||||||
|
func withdrawVerificationAndResend(userIDs: [String], itemID: TimelineItemIdentifier) async -> Result<Void, RoomProxyError>
|
||||||
|
|
||||||
// MARK: - Room Flags
|
// MARK: - Room Flags
|
||||||
|
|
||||||
func flagAsUnread(_ isUnread: Bool) async -> Result<Void, RoomProxyError>
|
func flagAsUnread(_ isUnread: Bool) async -> Result<Void, RoomProxyError>
|
||||||
|
@ -59,13 +59,7 @@ enum TimelineItemProxy {
|
|||||||
enum TimelineItemDeliveryStatus: Hashable {
|
enum TimelineItemDeliveryStatus: Hashable {
|
||||||
case sending
|
case sending
|
||||||
case sent
|
case sent
|
||||||
case sendingFailed(SendFailureReason)
|
case sendingFailed(TimelineItemSendFailure)
|
||||||
|
|
||||||
enum SendFailureReason: Hashable {
|
|
||||||
case verifiedUserHasUnsignedDevice(devices: [String: [String]])
|
|
||||||
case verifiedUserChangedIdentity(users: [String])
|
|
||||||
case unknown
|
|
||||||
}
|
|
||||||
|
|
||||||
var isSendingFailed: Bool {
|
var isSendingFailed: Bool {
|
||||||
switch self {
|
switch self {
|
||||||
@ -75,6 +69,24 @@ enum TimelineItemDeliveryStatus: Hashable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The reason a timeline item failed to send.
|
||||||
|
enum TimelineItemSendFailure: Hashable {
|
||||||
|
enum VerifiedUser: Hashable {
|
||||||
|
case hasUnsignedDevice(devices: [String: [String]])
|
||||||
|
case changedIdentity(users: [String])
|
||||||
|
|
||||||
|
var affectedUserIDs: [String] {
|
||||||
|
switch self {
|
||||||
|
case .hasUnsignedDevice(let devices): Array(devices.keys)
|
||||||
|
case .changedIdentity(let users): users
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case verifiedUser(VerifiedUser)
|
||||||
|
case unknown
|
||||||
|
}
|
||||||
|
|
||||||
/// A light wrapper around event timeline items returned from Rust.
|
/// A light wrapper around event timeline items returned from Rust.
|
||||||
class EventTimelineItemProxy {
|
class EventTimelineItemProxy {
|
||||||
let item: MatrixRustSDK.EventTimelineItem
|
let item: MatrixRustSDK.EventTimelineItem
|
||||||
@ -98,9 +110,9 @@ class EventTimelineItemProxy {
|
|||||||
case .sent:
|
case .sent:
|
||||||
return .sent
|
return .sent
|
||||||
case .verifiedUserHasUnsignedDevice(devices: let devices):
|
case .verifiedUserHasUnsignedDevice(devices: let devices):
|
||||||
return .sendingFailed(.verifiedUserHasUnsignedDevice(devices: devices))
|
return .sendingFailed(.verifiedUser(.hasUnsignedDevice(devices: devices)))
|
||||||
case .verifiedUserChangedIdentity(users: let users):
|
case .verifiedUserChangedIdentity(users: let users):
|
||||||
return .sendingFailed(.verifiedUserChangedIdentity(users: users))
|
return .sendingFailed(.verifiedUser(.changedIdentity(users: users)))
|
||||||
case .crossSigningNotSetup, .sendingFromUnverifiedDevice:
|
case .crossSigningNotSetup, .sendingFromUnverifiedDevice:
|
||||||
return .sendingFailed(.unknown)
|
return .sendingFailed(.unknown)
|
||||||
}
|
}
|
||||||
|
@ -531,6 +531,12 @@ class PreviewTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func test_resolveVerifiedUserSendFailureScreen() {
|
||||||
|
for preview in ResolveVerifiedUserSendFailureScreen_Previews._allPreviews {
|
||||||
|
assertSnapshots(matching: preview)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func test_roomAttachmentPicker() {
|
func test_roomAttachmentPicker() {
|
||||||
for preview in RoomAttachmentPicker_Previews._allPreviews {
|
for preview in RoomAttachmentPicker_Previews._allPreviews {
|
||||||
assertSnapshots(matching: preview)
|
assertSnapshots(matching: preview)
|
||||||
|
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_heroImage-iPad-en-GB.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_heroImage-iPad-en-GB.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_heroImage-iPad-pseudo.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_heroImage-iPad-pseudo.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_heroImage-iPhone-15-en-GB.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_heroImage-iPhone-15-en-GB.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_heroImage-iPhone-15-pseudo.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_heroImage-iPhone-15-pseudo.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_resolveVerifiedUserSendFailureScreen-iPad-en-GB.Identity-Changed.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_resolveVerifiedUserSendFailureScreen-iPad-en-GB.Identity-Changed.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_resolveVerifiedUserSendFailureScreen-iPad-en-GB.Unsigned-Device.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_resolveVerifiedUserSendFailureScreen-iPad-en-GB.Unsigned-Device.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_resolveVerifiedUserSendFailureScreen-iPad-pseudo.Identity-Changed.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_resolveVerifiedUserSendFailureScreen-iPad-pseudo.Identity-Changed.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_resolveVerifiedUserSendFailureScreen-iPad-pseudo.Unsigned-Device.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_resolveVerifiedUserSendFailureScreen-iPad-pseudo.Unsigned-Device.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_resolveVerifiedUserSendFailureScreen-iPhone-15-en-GB.Identity-Changed.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_resolveVerifiedUserSendFailureScreen-iPhone-15-en-GB.Identity-Changed.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_resolveVerifiedUserSendFailureScreen-iPhone-15-en-GB.Unsigned-Device.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_resolveVerifiedUserSendFailureScreen-iPhone-15-en-GB.Unsigned-Device.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_resolveVerifiedUserSendFailureScreen-iPhone-15-pseudo.Identity-Changed.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_resolveVerifiedUserSendFailureScreen-iPhone-15-pseudo.Identity-Changed.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_resolveVerifiedUserSendFailureScreen-iPhone-15-pseudo.Unsigned-Device.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_resolveVerifiedUserSendFailureScreen-iPhone-15-pseudo.Unsigned-Device.png
(Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.Authenticity.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.Authenticity.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.Button-shapes.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.Button-shapes.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.Identity-Changed.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.Identity-Changed.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.Normal.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.Normal.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.Unencrypted.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.Unencrypted.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.Unknown-failure.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.Unknown-failure.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.Unsigned-Devices.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.Unsigned-Devices.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.Unsigned.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.Unsigned.png
(Stored with Git LFS)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.Authenticity.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.Authenticity.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.Button-shapes.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.Button-shapes.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.Identity-Changed.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.Identity-Changed.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.Normal.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.Normal.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.Unencrypted.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.Unencrypted.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.Unknown-failure.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.Unknown-failure.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.Unsigned-Devices.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.Unsigned-Devices.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.Unsigned.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.Unsigned.png
(Stored with Git LFS)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.Authenticity.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.Authenticity.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.Button-shapes.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.Button-shapes.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.Identity-Changed.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.Identity-Changed.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.Normal.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.Normal.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.Unencrypted.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.Unencrypted.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.Unknown-failure.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.Unknown-failure.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.Unsigned-Devices.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.Unsigned-Devices.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.Unsigned.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.Unsigned.png
(Stored with Git LFS)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-pseudo.Authenticity.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-pseudo.Authenticity.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-pseudo.Button-shapes.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-pseudo.Button-shapes.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-pseudo.Identity-Changed.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-pseudo.Identity-Changed.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-pseudo.Normal.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-pseudo.Normal.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-pseudo.Unencrypted.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-pseudo.Unencrypted.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-pseudo.Unknown-failure.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-pseudo.Unknown-failure.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-pseudo.Unsigned-Devices.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-pseudo.Unsigned-Devices.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-pseudo.Unsigned.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-pseudo.Unsigned.png
(Stored with Git LFS)
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,121 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
@testable import ElementX
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
class ResolveVerifiedUserSendFailureScreenViewModelTests: XCTestCase {
|
||||||
|
let roomProxy = JoinedRoomProxyMock(.init())
|
||||||
|
var viewModel: ResolveVerifiedUserSendFailureScreenViewModel!
|
||||||
|
var context: ResolveVerifiedUserSendFailureScreenViewModel.Context { viewModel.context }
|
||||||
|
|
||||||
|
func testUnsignedDevice() async throws {
|
||||||
|
// Given a failure where a single user has an unverified device
|
||||||
|
let userID = "@alice:matrix.org"
|
||||||
|
viewModel = makeViewModel(with: .hasUnsignedDevice(devices: [userID: ["DEVICE1"]]))
|
||||||
|
|
||||||
|
try await verifyResolving(userIDs: [userID])
|
||||||
|
}
|
||||||
|
|
||||||
|
func testMultipleUnsignedDevices() async throws {
|
||||||
|
// Given a failure where a multiple users have unverified devices.
|
||||||
|
let userIDs = ["@alice:matrix.org", "@bob:matrix.org", "@charlie:matrix.org"]
|
||||||
|
let devices = Dictionary(uniqueKeysWithValues: userIDs.map { (key: $0, value: ["DEVICE1, DEVICE2"]) })
|
||||||
|
viewModel = makeViewModel(with: .hasUnsignedDevice(devices: devices))
|
||||||
|
|
||||||
|
try await verifyResolving(userIDs: userIDs, assertStrings: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testChangedIdentity() async throws {
|
||||||
|
// Given a failure where a single user's identity has changed.
|
||||||
|
let userID = "@alice:matrix.org"
|
||||||
|
viewModel = makeViewModel(with: .changedIdentity(users: [userID]))
|
||||||
|
|
||||||
|
try await verifyResolving(userIDs: [userID])
|
||||||
|
}
|
||||||
|
|
||||||
|
func testMultipleChangedIdentities() async throws {
|
||||||
|
// Given a failure where a multiple users have unverified devices.
|
||||||
|
let userIDs = ["@alice:matrix.org", "@bob:matrix.org", "@charlie:matrix.org"]
|
||||||
|
viewModel = makeViewModel(with: .changedIdentity(users: userIDs))
|
||||||
|
|
||||||
|
try await verifyResolving(userIDs: userIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Helpers
|
||||||
|
|
||||||
|
private func makeViewModel(with failure: TimelineItemSendFailure.VerifiedUser) -> ResolveVerifiedUserSendFailureScreenViewModel {
|
||||||
|
ResolveVerifiedUserSendFailureScreenViewModel(failure: failure, itemID: .random, roomProxy: roomProxy)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func verifyResolving(userIDs: [String], assertStrings: Bool = true) async throws {
|
||||||
|
var remainingUserIDs = userIDs
|
||||||
|
|
||||||
|
while remainingUserIDs.count > 1 {
|
||||||
|
// Verify that the strings are being updated.
|
||||||
|
if assertStrings {
|
||||||
|
verifyDisplayName(from: remainingUserIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// When resolving the first failure.
|
||||||
|
let deferredFailure = deferFailure(viewModel.actionsPublisher, timeout: 1) { $0.isDismiss }
|
||||||
|
context.send(viewAction: .resolveAndResend)
|
||||||
|
|
||||||
|
// Then the sheet should remain open for the next failure.
|
||||||
|
try await deferredFailure.fulfill()
|
||||||
|
|
||||||
|
remainingUserIDs.removeFirst()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the final string.
|
||||||
|
if assertStrings {
|
||||||
|
verifyDisplayName(from: remainingUserIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// When resolving the final failure.
|
||||||
|
let deferred = deferFulfillment(viewModel.actionsPublisher) { $0.isDismiss }
|
||||||
|
context.send(viewAction: .resolveAndResend)
|
||||||
|
|
||||||
|
// Then the sheet should be dismissed.
|
||||||
|
try await deferred.fulfill()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func verifyDisplayName(from remainingUserIDs: [String]) {
|
||||||
|
guard let userID = remainingUserIDs.first else {
|
||||||
|
XCTFail("There should be a user ID to check.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let displayName = roomProxy.membersPublisher.value.first(where: { $0.userID == userID })?.displayName else {
|
||||||
|
XCTFail("There should be a matching mock user")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
XCTAssertTrue(context.viewState.title.contains(displayName))
|
||||||
|
XCTAssertTrue(context.viewState.subtitle.contains(displayName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension ResolveVerifiedUserSendFailureScreenViewModelAction {
|
||||||
|
var isDismiss: Bool {
|
||||||
|
switch self {
|
||||||
|
case .dismiss: true
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -60,7 +60,7 @@ packages:
|
|||||||
# Element/Matrix dependencies
|
# Element/Matrix dependencies
|
||||||
MatrixRustSDK:
|
MatrixRustSDK:
|
||||||
url: https://github.com/element-hq/matrix-rust-components-swift
|
url: https://github.com/element-hq/matrix-rust-components-swift
|
||||||
exactVersion: 1.0.44
|
exactVersion: 1.0.45
|
||||||
# path: ../matrix-rust-sdk
|
# path: ../matrix-rust-sdk
|
||||||
Compound:
|
Compound:
|
||||||
url: https://github.com/element-hq/compound-ios
|
url: https://github.com/element-hq/compound-ios
|
||||||
|
Loading…
x
Reference in New Issue
Block a user