mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 13:37:11 +00:00
Add support for account deactivation when not using OIDC. (#3295)
This commit is contained in:
parent
8660a22b3e
commit
5625e78fc9
@ -48,6 +48,7 @@
|
||||
07756D532EFE33DD1FA258E5 /* GeoURITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A7ED2EF5BDBAD2A7DBC4636 /* GeoURITests.swift */; };
|
||||
077CB230153E072C94B1E6C3 /* AppAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D65BCC659FD9087E49B3C25 /* AppAppearance.swift */; };
|
||||
07CC13C5729C24255348CBBD /* ElementCallWidgetDriver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 309AD8BAE6437C31BA7157BF /* ElementCallWidgetDriver.swift */; };
|
||||
07F6382E29845D235BFA3308 /* DeactivateAccountScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE78CAD0B964C66FD06EF83E /* DeactivateAccountScreenModels.swift */; };
|
||||
086D01E79C8E8D3F004FAF21 /* AudioPlayerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC9104846487244648D32C6D /* AudioPlayerProtocol.swift */; };
|
||||
08CB4BD12CEEDE6AAE4A18DD /* WindowManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035177BCD8E8308B098AC3C2 /* WindowManager.swift */; };
|
||||
095C0ACFC234E0550A6404C5 /* AppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FC803282F9268D49F4ABF14 /* AppCoordinator.swift */; };
|
||||
@ -162,6 +163,7 @@
|
||||
238D561CA231339C6D4D06F3 /* ClientBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A1C33355FFB0F0953C35036 /* ClientBuilder.swift */; };
|
||||
241CDEFE23819867D9B39066 /* RoomChangePermissionsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE75941583A033A9EDC9FE0 /* RoomChangePermissionsScreenViewModel.swift */; };
|
||||
244407B18B2F2D6466BA5961 /* RoomChangeRolesScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DFA1B7B088D033E0794B82 /* RoomChangeRolesScreenCoordinator.swift */; };
|
||||
244CB93DD7390379D905AFA8 /* DeactivateAccountScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E49D10BFA7E4D70A947888C /* DeactivateAccountScreen.swift */; };
|
||||
24A1BBADAC43DC3F3A7347DA /* AnalyticsPromptScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = E53BFB7E4F329621C844E8C3 /* AnalyticsPromptScreen.swift */; };
|
||||
24A75F72EEB7561B82D726FD /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2141693488CE5446BB391964 /* Date.swift */; };
|
||||
24B7CD41342C143117ADA768 /* Comparable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2B1CC9AA154F4D5435BF60A /* Comparable.swift */; };
|
||||
@ -333,6 +335,7 @@
|
||||
4A85928E27D4C1A548A06EE9 /* StartChatScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 052B2F924572AFD70B5F500E /* StartChatScreenViewModel.swift */; };
|
||||
4A9CEEE612D6D8B3DDBD28BA /* RoomListFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24EC819497BB5F8C4998D760 /* RoomListFilterView.swift */; };
|
||||
4AAA8606FBA290E23D15422E /* AvatarHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC743C7A85E3171BCBF0A653 /* AvatarHeaderView.swift */; };
|
||||
4AD2B5426DBED97196AA4783 /* DeactivateAccountScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82EE3B877D91030248B1242D /* DeactivateAccountScreenViewModelProtocol.swift */; };
|
||||
4B978C09567387EF4366BD7A /* MediaLoaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EF1AC723C2609C7705569CA /* MediaLoaderTests.swift */; };
|
||||
4BAB8222DBA0B4207D1223E0 /* NotificationSettingsProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382B50F7E379B3DBBD174364 /* NotificationSettingsProxyMock.swift */; };
|
||||
4BB282209EA82015D0DF8F89 /* NavigationStackCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C698E30698EC59302A8EEBD /* NavigationStackCoordinatorTests.swift */; };
|
||||
@ -383,6 +386,7 @@
|
||||
55CDD3968D95D1A820B5491E /* PlaceholderAvatarImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C705E605EF57C19DBE86FFA1 /* PlaceholderAvatarImage.swift */; };
|
||||
55D18AA4F4A2257642EBDB94 /* GlobalSearchScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38354164AF59C5006CD05878 /* GlobalSearchScreenViewModel.swift */; };
|
||||
562EFB9AB62B38830D9AA778 /* TimelineMediaFrame.swift in Sources */ = {isa = PBXBuildFile; fileRef = 933B074F006F8E930DB98B4E /* TimelineMediaFrame.swift */; };
|
||||
564910A38858306301C1C21E /* DeactivateAccountScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A1009E4A78F86DA42E1EAF0 /* DeactivateAccountScreenCoordinator.swift */; };
|
||||
564BF06B3E93D6DD55F903B2 /* CreateRoomCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C618CA2B6C8758B06C88013C /* CreateRoomCoordinator.swift */; };
|
||||
565868808A1DA565707394ED /* CurrentValuePublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 127C8472672A5BA09EF1ACF8 /* CurrentValuePublisher.swift */; };
|
||||
56DACDD379A86A1F5DEFE7BE /* AuthenticationServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E75948AA1FE1D1A7809931F /* AuthenticationServiceProtocol.swift */; };
|
||||
@ -571,6 +575,7 @@
|
||||
8015842CB4DE1BE414D2CDED /* AppLockSetupBiometricsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C62E07C1164F5120727A2A8 /* AppLockSetupBiometricsScreenCoordinator.swift */; };
|
||||
804C15D8ADE0EA7A5268F58A /* OverridableAvatarImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648DD1C10E4957CB791FE0B8 /* OverridableAvatarImage.swift */; };
|
||||
80DEA2A4B20F9E279EAE6B2B /* UserProfile+Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAD01F7FC2BBAC7351948595 /* UserProfile+Mock.swift */; };
|
||||
80F6C8EFCA4564B67F0D34B0 /* DeactivateAccountScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77F75B3E9F99864048A422A /* DeactivateAccountScreenViewModelTests.swift */; };
|
||||
81A7C020CB5F6232242A8414 /* UserSessionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F36C0A6D59717193F49EA986 /* UserSessionTests.swift */; };
|
||||
8285FF4B2C2331758C437FF7 /* ReportContentScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 713B48DBF65DE4B0DD445D66 /* ReportContentScreenViewModelProtocol.swift */; };
|
||||
828EA5009557C2B9DCD4CA0F /* UserDiscoverySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D071F86CD47582B9196C9D16 /* UserDiscoverySection.swift */; };
|
||||
@ -893,6 +898,7 @@
|
||||
C915347779B3C7FDD073A87A /* AVMetadataMachineReadableCodeObjectExtensionsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93E1FF0DFBB3768F79FDBF6D /* AVMetadataMachineReadableCodeObjectExtensionsTest.swift */; };
|
||||
C97325EFDCCEE457432A9E82 /* MessageText.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E0B4A34E69BD2132BEC521 /* MessageText.swift */; };
|
||||
C9A631FD968249B4BA0B7B3C /* ReactionsSummaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02EE0FABA8ED6D6C1D6CE71D /* ReactionsSummaryView.swift */; };
|
||||
C9ABF75A43F2D26F1D9A1F27 /* DeactivateAccountScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AC3FDB58F57386741A4FC7F /* DeactivateAccountScreenViewModel.swift */; };
|
||||
C9BE065FA7D4E77E4C61CB69 /* MapLibreModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B81B6170DB690013CEB646F4 /* MapLibreModels.swift */; };
|
||||
C9F5B48D15B9BCAE1F8D564E /* RoomNotificationModeProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1511766C534367700C8DD75 /* RoomNotificationModeProxy.swift */; };
|
||||
CA12AE0DCD57D49CD96C699A /* WaveformCursorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB9EABCA9348DFA27439A809 /* WaveformCursorView.swift */; };
|
||||
@ -1321,6 +1327,7 @@
|
||||
1DE7969EBCAF078813E18EA1 /* RoomRolesAndPermissionsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomRolesAndPermissionsScreenModels.swift; sourceTree = "<group>"; };
|
||||
1DF8F7A3AD83D04C08D75E01 /* RoomDetailsEditScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||
1DFE0E493FB55E5A62E7852A /* ProposedViewSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProposedViewSize.swift; sourceTree = "<group>"; };
|
||||
1E49D10BFA7E4D70A947888C /* DeactivateAccountScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeactivateAccountScreen.swift; sourceTree = "<group>"; };
|
||||
1E508AB0EDEE017FF4F6F8D1 /* DTHTMLElement+AttributedStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DTHTMLElement+AttributedStringBuilder.swift"; sourceTree = "<group>"; };
|
||||
1F2529D434C750ED78ADF1ED /* UserAgentBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAgentBuilder.swift; sourceTree = "<group>"; };
|
||||
1F7C6DDBB5D12F6EF6A3D6E1 /* CollapsibleReactionLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsibleReactionLayout.swift; sourceTree = "<group>"; };
|
||||
@ -1380,6 +1387,7 @@
|
||||
29A953B6C0C431DBF4DD00B4 /* RoomSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummary.swift; sourceTree = "<group>"; };
|
||||
2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilder.swift; sourceTree = "<group>"; };
|
||||
2AB2C848BB9A7A9B618B7B89 /* TextBasedRoomTimelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineTests.swift; sourceTree = "<group>"; };
|
||||
2AC3FDB58F57386741A4FC7F /* DeactivateAccountScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeactivateAccountScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
2AE807361805463F5AEDD1CA /* VoiceMessagePreviewComposer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessagePreviewComposer.swift; sourceTree = "<group>"; };
|
||||
2AE83A3DD63BCFBB956FE5CB /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = nl; path = nl.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
2AF715D4FD4710EBB637D661 /* SettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||
@ -1745,6 +1753,7 @@
|
||||
8296D6FB451E25CEC0767BBA /* RoomNotificationSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||
82B612853BFB68373249777B /* SecureBackupKeyBackupScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupKeyBackupScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
82DFA1B7B088D033E0794B82 /* RoomChangeRolesScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangeRolesScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||
82EE3B877D91030248B1242D /* DeactivateAccountScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeactivateAccountScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||
8319173DD66C07F45DC48848 /* IdentityConfirmedScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityConfirmedScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||
837B440C4705E4B899BCB899 /* RoomDetailsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
839E2C35DF3F9C7B54C3CE49 /* RoundedCornerShape.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedCornerShape.swift; sourceTree = "<group>"; };
|
||||
@ -1781,6 +1790,7 @@
|
||||
897DF5E9A70CE05A632FC8AF /* UTType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTType.swift; sourceTree = "<group>"; };
|
||||
89AAEA70CFF3284920811941 /* RoomChangePermissionsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangePermissionsScreen.swift; sourceTree = "<group>"; };
|
||||
89FBFC09F9DAFF1E4BA97849 /* FormButtonStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormButtonStyles.swift; sourceTree = "<group>"; };
|
||||
8A1009E4A78F86DA42E1EAF0 /* DeactivateAccountScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeactivateAccountScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||
8A9AE4967817E9608E22EB44 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
8AE0C9653870803E4F91F474 /* RoomListFiltersStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomListFiltersStateTests.swift; sourceTree = "<group>"; };
|
||||
8AE78FA0011E07920AE83135 /* PlainMentionBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlainMentionBuilder.swift; sourceTree = "<group>"; };
|
||||
@ -1998,6 +2008,7 @@
|
||||
BC8AA23D4F37CC26564F63C5 /* LayoutMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutMocks.swift; sourceTree = "<group>"; };
|
||||
BCDA016D05107DED3B9495CB /* TimelineItemDebugView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemDebugView.swift; sourceTree = "<group>"; };
|
||||
BE148A4FFEE853C5A281500C /* UNNotificationContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UNNotificationContent.swift; sourceTree = "<group>"; };
|
||||
BE78CAD0B964C66FD06EF83E /* DeactivateAccountScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeactivateAccountScreenModels.swift; sourceTree = "<group>"; };
|
||||
BE89A8BD65CCE3FCC925CA14 /* TimelineItemReplyDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemReplyDetails.swift; sourceTree = "<group>"; };
|
||||
BE9BBB18FB27F09032AD8769 /* NotificationPermissionsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPermissionsScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
BEA38B9851CFCC4D67F5587D /* EmojiPickerScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||
@ -2115,6 +2126,7 @@
|
||||
D66B5D86A9AB95E0E01BED82 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
D6DC38E64A5ED3FDB201029A /* BugReportService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportService.swift; sourceTree = "<group>"; };
|
||||
D77B3D4950F1707E66E4A45A /* AnalyticsConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsConfiguration.swift; sourceTree = "<group>"; };
|
||||
D77F75B3E9F99864048A422A /* DeactivateAccountScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeactivateAccountScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||
D79BB714D28C9F588DD69353 /* SecureBackupScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||
D7BB243B26D54EF1A0C422C0 /* NotificationContentBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationContentBuilder.swift; sourceTree = "<group>"; };
|
||||
D7BEB970F500BFB248443FA1 /* BloomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BloomView.swift; sourceTree = "<group>"; };
|
||||
@ -2446,6 +2458,14 @@
|
||||
path = Logging;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
07831A7BA411CC407B4727E2 /* View */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1E49D10BFA7E4D70A947888C /* DeactivateAccountScreen.swift */,
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0787F81684E503024BD0C051 /* Services */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -3640,6 +3660,18 @@
|
||||
path = TimelineItemContent;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6C708A9F46EDE1105C640335 /* DeactivateAccountScreen */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8A1009E4A78F86DA42E1EAF0 /* DeactivateAccountScreenCoordinator.swift */,
|
||||
BE78CAD0B964C66FD06EF83E /* DeactivateAccountScreenModels.swift */,
|
||||
2AC3FDB58F57386741A4FC7F /* DeactivateAccountScreenViewModel.swift */,
|
||||
82EE3B877D91030248B1242D /* DeactivateAccountScreenViewModelProtocol.swift */,
|
||||
07831A7BA411CC407B4727E2 /* View */,
|
||||
);
|
||||
path = DeactivateAccountScreen;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6D7503E64A458DD09E65A3F7 /* View */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -3769,6 +3801,7 @@
|
||||
CA29952595B804DA221A0C1D /* ComposerToolbarViewModelTests.swift */,
|
||||
69D42EE0102D2857933625DD /* CreateRoomViewModelTests.swift */,
|
||||
3B5E97E9615A158C76B2AB77 /* DateTests.swift */,
|
||||
D77F75B3E9F99864048A422A /* DeactivateAccountScreenViewModelTests.swift */,
|
||||
6D0A27607AB09784C8501B5C /* DeveloperOptionsScreenViewModelTests.swift */,
|
||||
A58E93D91DE3288010390DEE /* EmojiDetectionTests.swift */,
|
||||
099F2D36C141D845A445B1E6 /* EmojiProviderTests.swift */,
|
||||
@ -5171,6 +5204,7 @@
|
||||
1185EECDD07495D65AC84AFC /* CallScreen */,
|
||||
90DC2E28718955ED87AD1456 /* CreatePollScreen */,
|
||||
C18958141C8ED6D778F779A4 /* CreateRoom */,
|
||||
6C708A9F46EDE1105C640335 /* DeactivateAccountScreen */,
|
||||
F5A65D1D3B83593598DC278D /* EmojiPickerScreen */,
|
||||
8656AFF06650360A5D0695FF /* EncryptionReset */,
|
||||
448435400B561C40E514BE1C /* FilePreviewScreen */,
|
||||
@ -6050,6 +6084,7 @@
|
||||
0C932A5158C1D0604DFC5750 /* ComposerToolbarViewModelTests.swift in Sources */,
|
||||
D3FD96913D2B1AAA3149DAC7 /* CreateRoomViewModelTests.swift in Sources */,
|
||||
CD0088B763CD970CF1CBF8CB /* DateTests.swift in Sources */,
|
||||
80F6C8EFCA4564B67F0D34B0 /* DeactivateAccountScreenViewModelTests.swift in Sources */,
|
||||
864C69CF951BF36D25BE0C03 /* DeveloperOptionsScreenViewModelTests.swift in Sources */,
|
||||
F697284B9B5F2C00CFEA3B12 /* EmojiDetectionTests.swift in Sources */,
|
||||
25618589E0DE0F1E95FC7B5C /* EmojiProviderTests.swift in Sources */,
|
||||
@ -6329,6 +6364,11 @@
|
||||
C4F69156C31A447FEFF2A47C /* DTHTMLElement+AttributedStringBuilder.swift in Sources */,
|
||||
9905C1B1C6EFE38F3A6533F3 /* Data.swift in Sources */,
|
||||
C6C06DDA8881260303FBA3A0 /* Date.swift in Sources */,
|
||||
244CB93DD7390379D905AFA8 /* DeactivateAccountScreen.swift in Sources */,
|
||||
564910A38858306301C1C21E /* DeactivateAccountScreenCoordinator.swift in Sources */,
|
||||
07F6382E29845D235BFA3308 /* DeactivateAccountScreenModels.swift in Sources */,
|
||||
C9ABF75A43F2D26F1D9A1F27 /* DeactivateAccountScreenViewModel.swift in Sources */,
|
||||
4AD2B5426DBED97196AA4783 /* DeactivateAccountScreenViewModelProtocol.swift in Sources */,
|
||||
EE8491AD81F47DF3C192497B /* DecorationTimelineItemProtocol.swift in Sources */,
|
||||
5780E444F405AA1304E1C23E /* DeveloperOptionsScreen.swift in Sources */,
|
||||
5DD85A0FE3D85AEC3C7EFE36 /* DeveloperOptionsScreenCoordinator.swift in Sources */,
|
||||
@ -7847,7 +7887,7 @@
|
||||
repositoryURL = "https://github.com/element-hq/compound-ios";
|
||||
requirement = {
|
||||
kind = revision;
|
||||
revision = 22f9d801dd001e8aaed0f62546cdb42c7594cf92;
|
||||
revision = a9270392b3269ef072c47dea623815a9fb87311d;
|
||||
};
|
||||
};
|
||||
F76A08D0EA29A07A54F4EB4D /* XCRemoteSwiftPackageReference "swift-collections" */ = {
|
||||
|
@ -15,7 +15,7 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/element-hq/compound-ios",
|
||||
"state" : {
|
||||
"revision" : "22f9d801dd001e8aaed0f62546cdb42c7594cf92"
|
||||
"revision" : "a9270392b3269ef072c47dea623815a9fb87311d"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -33,12 +33,14 @@
|
||||
"action_close" = "Close";
|
||||
"action_complete_verification" = "Complete verification";
|
||||
"action_confirm" = "Confirm";
|
||||
"action_confirm_password" = "Confirm password";
|
||||
"action_continue" = "Continue";
|
||||
"action_copy" = "Copy";
|
||||
"action_copy_link" = "Copy link";
|
||||
"action_copy_link_to_message" = "Copy link to message";
|
||||
"action_create" = "Create";
|
||||
"action_create_a_room" = "Create a room";
|
||||
"action_deactivate" = "Deactivate";
|
||||
"action_decline" = "Decline";
|
||||
"action_delete_poll" = "Delete Poll";
|
||||
"action_disable" = "Disable";
|
||||
@ -107,6 +109,7 @@
|
||||
"action_view_source" = "View source";
|
||||
"action_yes" = "Yes";
|
||||
"action.load_more" = "Load more";
|
||||
"action_deactivate_account" = "Deactivate account";
|
||||
"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.";
|
||||
@ -255,7 +258,7 @@
|
||||
"emoji_picker_category_people" = "Smileys & People";
|
||||
"emoji_picker_category_places" = "Travel & Places";
|
||||
"emoji_picker_category_symbols" = "Symbols";
|
||||
"error_account_creation_not_possible" = "Your homeserver needs to be upgraded to support Matrix Authentication Server and account creation.";
|
||||
"error_account_creation_not_possible" = "Your homeserver needs to be upgraded to support Matrix Authentication Service and account creation.";
|
||||
"error_failed_creating_the_permalink" = "Failed creating the permalink";
|
||||
"error_failed_loading_map" = "%1$@ could not load the map. Please try again later.";
|
||||
"error_failed_loading_messages" = "Failed loading messages";
|
||||
@ -336,7 +339,9 @@
|
||||
"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_resolve_send_failure_unsigned_device_title" = "Your message was not sent because %1$@ has not verified all devices";
|
||||
"screen_resolve_send_failure_you_unsigned_device_subtitle" = "One or more of your devices are unverified. You can send the message anyway, or you can cancel for now and try again later after you have verified all of your devices.";
|
||||
"screen_resolve_send_failure_you_unsigned_device_title" = "Your message was not sent because you have not verified one or more of your devices";
|
||||
"screen_room_mentions_at_room_subtitle" = "Notify the whole room";
|
||||
"screen_room_pinned_banner_indicator" = "%1$@ of %2$@";
|
||||
"screen_room_pinned_banner_indicator_description" = "%1$@ Pinned messages";
|
||||
@ -344,7 +349,8 @@
|
||||
"screen_room_pinned_banner_view_all_button_title" = "View All";
|
||||
"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_timeline_item_menu_send_failure_unsigned_device" = "Message not sent because %1$@ has not verified all devices.";
|
||||
"screen_timeline_item_menu_send_failure_you_unsigned_device" = "Message not sent because you have not verified one or more of your devices.";
|
||||
"screen_account_provider_change" = "Change account provider";
|
||||
"screen_account_provider_form_hint" = "Homeserver address";
|
||||
"screen_account_provider_form_notice" = "Enter a search term or a domain address.";
|
||||
@ -451,6 +457,17 @@
|
||||
"screen_create_room_public_option_description" = "Messages are not encrypted and anyone can read them. You can enable encryption at a later date.";
|
||||
"screen_create_room_public_option_title" = "Public room (anyone)";
|
||||
"screen_create_room_topic_label" = "Topic (optional)";
|
||||
"screen_deactivate_account_confirmation_dialog_content" = "Please confirm that you want to deactivate your account. This action cannot be undone.";
|
||||
"screen_deactivate_account_delete_all_messages" = "Delete all my messages";
|
||||
"screen_deactivate_account_delete_all_messages_notice" = "Warning: Future users may see incomplete conversations.";
|
||||
"screen_deactivate_account_description" = "Deactivating your account is %1$@, it will:";
|
||||
"screen_deactivate_account_description_bold_part" = "irreversible";
|
||||
"screen_deactivate_account_list_item_1" = "%1$@ your account (you can't log back in, and your ID can't be reused).";
|
||||
"screen_deactivate_account_list_item_1_bold_part" = "Permanently disable";
|
||||
"screen_deactivate_account_list_item_2" = "Remove you from all chat rooms.";
|
||||
"screen_deactivate_account_list_item_3" = "Delete your account information from our identity server.";
|
||||
"screen_deactivate_account_list_item_4" = "Your messages will still be visible to registered users but won’t be available to new or unregistered users if you choose to delete them.";
|
||||
"screen_deactivate_account_title" = "Deactivate account";
|
||||
"screen_edit_poll_delete_confirmation" = "Are you sure you want to delete this poll?";
|
||||
"screen_edit_profile_display_name" = "Display name";
|
||||
"screen_edit_profile_display_name_placeholder" = "Your display name";
|
||||
|
@ -126,6 +126,8 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
presentAdvancedSettings()
|
||||
case .developerOptions:
|
||||
presentDeveloperOptions()
|
||||
case .deactivateAccount:
|
||||
presentDeactivateAccount()
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
@ -238,6 +240,30 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
navigationStackCoordinator.push(coordinator)
|
||||
}
|
||||
|
||||
private func presentDeactivateAccount() {
|
||||
let navigationCoordinator = NavigationStackCoordinator()
|
||||
|
||||
let parameters = DeactivateAccountScreenCoordinatorParameters(clientProxy: parameters.userSession.clientProxy,
|
||||
userIndicatorController: parameters.userIndicatorController)
|
||||
let coordinator = DeactivateAccountScreenCoordinator(parameters: parameters)
|
||||
|
||||
coordinator.actionsPublisher
|
||||
.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
switch action {
|
||||
case .cancel:
|
||||
navigationStackCoordinator.setSheetCoordinator(nil)
|
||||
case .accountDeactivated:
|
||||
actionsSubject.send(.forceLogout)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
navigationCoordinator.setRootCoordinator(coordinator)
|
||||
navigationStackCoordinator.setSheetCoordinator(navigationCoordinator)
|
||||
}
|
||||
|
||||
// MARK: OIDC Account Management
|
||||
|
||||
|
@ -96,6 +96,8 @@ internal enum L10n {
|
||||
internal static var actionCompleteVerification: String { return L10n.tr("Localizable", "action_complete_verification") }
|
||||
/// Confirm
|
||||
internal static var actionConfirm: String { return L10n.tr("Localizable", "action_confirm") }
|
||||
/// Confirm password
|
||||
internal static var actionConfirmPassword: String { return L10n.tr("Localizable", "action_confirm_password") }
|
||||
/// Continue
|
||||
internal static var actionContinue: String { return L10n.tr("Localizable", "action_continue") }
|
||||
/// Copy
|
||||
@ -108,6 +110,10 @@ internal enum L10n {
|
||||
internal static var actionCreate: String { return L10n.tr("Localizable", "action_create") }
|
||||
/// Create a room
|
||||
internal static var actionCreateARoom: String { return L10n.tr("Localizable", "action_create_a_room") }
|
||||
/// Deactivate
|
||||
internal static var actionDeactivate: String { return L10n.tr("Localizable", "action_deactivate") }
|
||||
/// Deactivate account
|
||||
internal static var actionDeactivateAccount: String { return L10n.tr("Localizable", "action_deactivate_account") }
|
||||
/// Decline
|
||||
internal static var actionDecline: String { return L10n.tr("Localizable", "action_decline") }
|
||||
/// Delete Poll
|
||||
@ -558,7 +564,7 @@ internal enum L10n {
|
||||
internal static var emojiPickerCategoryPlaces: String { return L10n.tr("Localizable", "emoji_picker_category_places") }
|
||||
/// Symbols
|
||||
internal static var emojiPickerCategorySymbols: String { return L10n.tr("Localizable", "emoji_picker_category_symbols") }
|
||||
/// Your homeserver needs to be upgraded to support Matrix Authentication Server and account creation.
|
||||
/// Your homeserver needs to be upgraded to support Matrix Authentication Service and account creation.
|
||||
internal static var errorAccountCreationNotPossible: String { return L10n.tr("Localizable", "error_account_creation_not_possible") }
|
||||
/// Failed creating the permalink
|
||||
internal static var errorFailedCreatingThePermalink: String { return L10n.tr("Localizable", "error_failed_creating_the_permalink") }
|
||||
@ -1041,6 +1047,32 @@ internal enum L10n {
|
||||
internal static var screenCreateRoomTitle: String { return L10n.tr("Localizable", "screen_create_room_title") }
|
||||
/// Topic (optional)
|
||||
internal static var screenCreateRoomTopicLabel: String { return L10n.tr("Localizable", "screen_create_room_topic_label") }
|
||||
/// Please confirm that you want to deactivate your account. This action cannot be undone.
|
||||
internal static var screenDeactivateAccountConfirmationDialogContent: String { return L10n.tr("Localizable", "screen_deactivate_account_confirmation_dialog_content") }
|
||||
/// Delete all my messages
|
||||
internal static var screenDeactivateAccountDeleteAllMessages: String { return L10n.tr("Localizable", "screen_deactivate_account_delete_all_messages") }
|
||||
/// Warning: Future users may see incomplete conversations.
|
||||
internal static var screenDeactivateAccountDeleteAllMessagesNotice: String { return L10n.tr("Localizable", "screen_deactivate_account_delete_all_messages_notice") }
|
||||
/// Deactivating your account is %1$@, it will:
|
||||
internal static func screenDeactivateAccountDescription(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "screen_deactivate_account_description", String(describing: p1))
|
||||
}
|
||||
/// irreversible
|
||||
internal static var screenDeactivateAccountDescriptionBoldPart: String { return L10n.tr("Localizable", "screen_deactivate_account_description_bold_part") }
|
||||
/// %1$@ your account (you can't log back in, and your ID can't be reused).
|
||||
internal static func screenDeactivateAccountListItem1(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "screen_deactivate_account_list_item_1", String(describing: p1))
|
||||
}
|
||||
/// Permanently disable
|
||||
internal static var screenDeactivateAccountListItem1BoldPart: String { return L10n.tr("Localizable", "screen_deactivate_account_list_item_1_bold_part") }
|
||||
/// Remove you from all chat rooms.
|
||||
internal static var screenDeactivateAccountListItem2: String { return L10n.tr("Localizable", "screen_deactivate_account_list_item_2") }
|
||||
/// Delete your account information from our identity server.
|
||||
internal static var screenDeactivateAccountListItem3: String { return L10n.tr("Localizable", "screen_deactivate_account_list_item_3") }
|
||||
/// Your messages will still be visible to registered users but won’t be available to new or unregistered users if you choose to delete them.
|
||||
internal static var screenDeactivateAccountListItem4: String { return L10n.tr("Localizable", "screen_deactivate_account_list_item_4") }
|
||||
/// Deactivate account
|
||||
internal static var screenDeactivateAccountTitle: String { return L10n.tr("Localizable", "screen_deactivate_account_title") }
|
||||
/// Block
|
||||
internal static var screenDmDetailsBlockAlertAction: String { return L10n.tr("Localizable", "screen_dm_details_block_alert_action") }
|
||||
/// Blocked users won't be able to send you messages and all their messages will be hidden. You can unblock them anytime.
|
||||
@ -1475,10 +1507,14 @@ internal enum L10n {
|
||||
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
|
||||
/// Your message was not sent because %1$@ has not verified all devices
|
||||
internal static func screenResolveSendFailureUnsignedDeviceTitle(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "screen_resolve_send_failure_unsigned_device_title", String(describing: p1))
|
||||
}
|
||||
/// One or more of your devices are unverified. You can send the message anyway, or you can cancel for now and try again later after you have verified all of your devices.
|
||||
internal static var screenResolveSendFailureYouUnsignedDeviceSubtitle: String { return L10n.tr("Localizable", "screen_resolve_send_failure_you_unsigned_device_subtitle") }
|
||||
/// Your message was not sent because you have not verified one or more of your devices
|
||||
internal static var screenResolveSendFailureYouUnsignedDeviceTitle: String { return L10n.tr("Localizable", "screen_resolve_send_failure_you_unsigned_device_title") }
|
||||
/// Failed to resolve room alias.
|
||||
internal static var screenRoomAliasResolverResolveAliasFailure: String { return L10n.tr("Localizable", "screen_room_alias_resolver_resolve_alias_failure") }
|
||||
/// Camera
|
||||
@ -1981,10 +2017,12 @@ internal enum L10n {
|
||||
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.
|
||||
/// Message not sent because %1$@ has not verified all devices.
|
||||
internal static func screenTimelineItemMenuSendFailureUnsignedDevice(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "screen_timeline_item_menu_send_failure_unsigned_device", String(describing: p1))
|
||||
}
|
||||
/// Message not sent because you have not verified one or more of your devices.
|
||||
internal static var screenTimelineItemMenuSendFailureYouUnsignedDevice: String { return L10n.tr("Localizable", "screen_timeline_item_menu_send_failure_you_unsigned_device") }
|
||||
/// Location
|
||||
internal static var screenViewLocationTitle: String { return L10n.tr("Localizable", "screen_view_location_title") }
|
||||
/// Calls, polls, search and more will be added later this year.
|
||||
|
@ -47,6 +47,7 @@ extension ClientProxyMock {
|
||||
|
||||
isOnlyDeviceLeftReturnValue = .success(false)
|
||||
accountURLActionReturnValue = "https://matrix.org/account"
|
||||
canDeactivateAccount = false
|
||||
directRoomForUserIDReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
|
||||
createDirectRoomWithExpectedRoomNameReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
|
||||
createRoomNameTopicIsRoomPrivateUserIDsAvatarURLReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
|
||||
|
@ -1947,6 +1947,11 @@ class ClientProxyMock: ClientProxyProtocol {
|
||||
}
|
||||
var underlyingAvailableSlidingSyncVersions: [SlidingSyncVersion]!
|
||||
var availableSlidingSyncVersionsClosure: (() async -> [SlidingSyncVersion])?
|
||||
var canDeactivateAccount: Bool {
|
||||
get { return underlyingCanDeactivateAccount }
|
||||
set(value) { underlyingCanDeactivateAccount = value }
|
||||
}
|
||||
var underlyingCanDeactivateAccount: Bool!
|
||||
var userIDServerName: String?
|
||||
var userDisplayNamePublisher: CurrentValuePublisher<String?, Never> {
|
||||
get { return underlyingUserDisplayNamePublisher }
|
||||
@ -3209,6 +3214,76 @@ class ClientProxyMock: ClientProxyProtocol {
|
||||
return sessionVerificationControllerProxyReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - deactivateAccount
|
||||
|
||||
var deactivateAccountPasswordEraseDataUnderlyingCallsCount = 0
|
||||
var deactivateAccountPasswordEraseDataCallsCount: Int {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return deactivateAccountPasswordEraseDataUnderlyingCallsCount
|
||||
} else {
|
||||
var returnValue: Int? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = deactivateAccountPasswordEraseDataUnderlyingCallsCount
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
deactivateAccountPasswordEraseDataUnderlyingCallsCount = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
deactivateAccountPasswordEraseDataUnderlyingCallsCount = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var deactivateAccountPasswordEraseDataCalled: Bool {
|
||||
return deactivateAccountPasswordEraseDataCallsCount > 0
|
||||
}
|
||||
var deactivateAccountPasswordEraseDataReceivedArguments: (password: String?, eraseData: Bool)?
|
||||
var deactivateAccountPasswordEraseDataReceivedInvocations: [(password: String?, eraseData: Bool)] = []
|
||||
|
||||
var deactivateAccountPasswordEraseDataUnderlyingReturnValue: Result<Void, ClientProxyError>!
|
||||
var deactivateAccountPasswordEraseDataReturnValue: Result<Void, ClientProxyError>! {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return deactivateAccountPasswordEraseDataUnderlyingReturnValue
|
||||
} else {
|
||||
var returnValue: Result<Void, ClientProxyError>? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = deactivateAccountPasswordEraseDataUnderlyingReturnValue
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
deactivateAccountPasswordEraseDataUnderlyingReturnValue = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
deactivateAccountPasswordEraseDataUnderlyingReturnValue = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var deactivateAccountPasswordEraseDataClosure: ((String?, Bool) async -> Result<Void, ClientProxyError>)?
|
||||
|
||||
func deactivateAccount(password: String?, eraseData: Bool) async -> Result<Void, ClientProxyError> {
|
||||
deactivateAccountPasswordEraseDataCallsCount += 1
|
||||
deactivateAccountPasswordEraseDataReceivedArguments = (password: password, eraseData: eraseData)
|
||||
DispatchQueue.main.async {
|
||||
self.deactivateAccountPasswordEraseDataReceivedInvocations.append((password: password, eraseData: eraseData))
|
||||
}
|
||||
if let deactivateAccountPasswordEraseDataClosure = deactivateAccountPasswordEraseDataClosure {
|
||||
return await deactivateAccountPasswordEraseDataClosure(password, eraseData)
|
||||
} else {
|
||||
return deactivateAccountPasswordEraseDataReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - logout
|
||||
|
||||
var logoutUnderlyingCallsCount = 0
|
||||
|
@ -485,6 +485,71 @@ open class ClientSDKMock: MatrixRustSDK.Client {
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - canDeactivateAccount
|
||||
|
||||
var canDeactivateAccountUnderlyingCallsCount = 0
|
||||
open var canDeactivateAccountCallsCount: Int {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return canDeactivateAccountUnderlyingCallsCount
|
||||
} else {
|
||||
var returnValue: Int? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = canDeactivateAccountUnderlyingCallsCount
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
canDeactivateAccountUnderlyingCallsCount = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
canDeactivateAccountUnderlyingCallsCount = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
open var canDeactivateAccountCalled: Bool {
|
||||
return canDeactivateAccountCallsCount > 0
|
||||
}
|
||||
|
||||
var canDeactivateAccountUnderlyingReturnValue: Bool!
|
||||
open var canDeactivateAccountReturnValue: Bool! {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return canDeactivateAccountUnderlyingReturnValue
|
||||
} else {
|
||||
var returnValue: Bool? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = canDeactivateAccountUnderlyingReturnValue
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
canDeactivateAccountUnderlyingReturnValue = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
canDeactivateAccountUnderlyingReturnValue = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
open var canDeactivateAccountClosure: (() -> Bool)?
|
||||
|
||||
open override func canDeactivateAccount() -> Bool {
|
||||
canDeactivateAccountCallsCount += 1
|
||||
if let canDeactivateAccountClosure = canDeactivateAccountClosure {
|
||||
return canDeactivateAccountClosure()
|
||||
} else {
|
||||
return canDeactivateAccountReturnValue
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - createRoom
|
||||
|
||||
open var createRoomRequestThrowableError: Error?
|
||||
@ -560,6 +625,52 @@ open class ClientSDKMock: MatrixRustSDK.Client {
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - deactivateAccount
|
||||
|
||||
open var deactivateAccountAuthDataEraseDataThrowableError: Error?
|
||||
var deactivateAccountAuthDataEraseDataUnderlyingCallsCount = 0
|
||||
open var deactivateAccountAuthDataEraseDataCallsCount: Int {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return deactivateAccountAuthDataEraseDataUnderlyingCallsCount
|
||||
} else {
|
||||
var returnValue: Int? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = deactivateAccountAuthDataEraseDataUnderlyingCallsCount
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
deactivateAccountAuthDataEraseDataUnderlyingCallsCount = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
deactivateAccountAuthDataEraseDataUnderlyingCallsCount = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
open var deactivateAccountAuthDataEraseDataCalled: Bool {
|
||||
return deactivateAccountAuthDataEraseDataCallsCount > 0
|
||||
}
|
||||
open var deactivateAccountAuthDataEraseDataReceivedArguments: (authData: AuthData?, eraseData: Bool)?
|
||||
open var deactivateAccountAuthDataEraseDataReceivedInvocations: [(authData: AuthData?, eraseData: Bool)] = []
|
||||
open var deactivateAccountAuthDataEraseDataClosure: ((AuthData?, Bool) async throws -> Void)?
|
||||
|
||||
open override func deactivateAccount(authData: AuthData?, eraseData: Bool) async throws {
|
||||
if let error = deactivateAccountAuthDataEraseDataThrowableError {
|
||||
throw error
|
||||
}
|
||||
deactivateAccountAuthDataEraseDataCallsCount += 1
|
||||
deactivateAccountAuthDataEraseDataReceivedArguments = (authData: authData, eraseData: eraseData)
|
||||
DispatchQueue.main.async {
|
||||
self.deactivateAccountAuthDataEraseDataReceivedInvocations.append((authData: authData, eraseData: eraseData))
|
||||
}
|
||||
try await deactivateAccountAuthDataEraseDataClosure?(authData, eraseData)
|
||||
}
|
||||
|
||||
//MARK: - deletePusher
|
||||
|
||||
open var deletePusherIdentifiersThrowableError: Error?
|
||||
|
@ -0,0 +1,57 @@
|
||||
//
|
||||
// Copyright 2022-2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
struct DeactivateAccountScreenCoordinatorParameters {
|
||||
let clientProxy: ClientProxyProtocol
|
||||
let userIndicatorController: UserIndicatorControllerProtocol
|
||||
}
|
||||
|
||||
enum DeactivateAccountScreenCoordinatorAction {
|
||||
case cancel
|
||||
case accountDeactivated
|
||||
}
|
||||
|
||||
final class DeactivateAccountScreenCoordinator: CoordinatorProtocol {
|
||||
private let parameters: DeactivateAccountScreenCoordinatorParameters
|
||||
private let viewModel: DeactivateAccountScreenViewModelProtocol
|
||||
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
private let actionsSubject: PassthroughSubject<DeactivateAccountScreenCoordinatorAction, Never> = .init()
|
||||
var actionsPublisher: AnyPublisher<DeactivateAccountScreenCoordinatorAction, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(parameters: DeactivateAccountScreenCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
|
||||
viewModel = DeactivateAccountScreenViewModel(clientProxy: parameters.clientProxy,
|
||||
userIndicatorController: parameters.userIndicatorController)
|
||||
}
|
||||
|
||||
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 .cancel:
|
||||
actionsSubject.send(.cancel)
|
||||
case .accountDeactivated:
|
||||
actionsSubject.send(.accountDeactivated)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
func toPresentable() -> AnyView {
|
||||
AnyView(DeactivateAccountScreen(context: viewModel.context))
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
//
|
||||
// Copyright 2022-2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum DeactivateAccountScreenViewModelAction {
|
||||
case cancel
|
||||
case accountDeactivated
|
||||
}
|
||||
|
||||
struct DeactivateAccountScreenViewState: BindableState {
|
||||
let info: AttributedString
|
||||
let infoPoint1: AttributedString
|
||||
let infoPoint2 = AttributedString(L10n.screenDeactivateAccountListItem2)
|
||||
let infoPoint3 = AttributedString(L10n.screenDeactivateAccountListItem3)
|
||||
let infoPoint4 = AttributedString(L10n.screenDeactivateAccountListItem4)
|
||||
|
||||
var bindings = DeactivateAccountScreenViewStateBindings()
|
||||
|
||||
init() {
|
||||
let boldPlaceholder = "{bold}"
|
||||
var attributedString = AttributedString(L10n.screenDeactivateAccountDescription(boldPlaceholder))
|
||||
var boldString = AttributedString(L10n.screenDeactivateAccountDescriptionBoldPart)
|
||||
boldString.bold()
|
||||
attributedString.replace(boldPlaceholder, with: boldString)
|
||||
info = attributedString
|
||||
|
||||
attributedString = AttributedString(L10n.screenDeactivateAccountListItem1(boldPlaceholder))
|
||||
boldString = AttributedString(L10n.screenDeactivateAccountListItem1BoldPart)
|
||||
boldString.bold()
|
||||
attributedString.replace(boldPlaceholder, with: boldString)
|
||||
infoPoint1 = attributedString
|
||||
}
|
||||
}
|
||||
|
||||
struct DeactivateAccountScreenViewStateBindings {
|
||||
var password = ""
|
||||
var eraseData = false
|
||||
var alertInfo: AlertInfo<DeactivateAccountScreenAlert>?
|
||||
}
|
||||
|
||||
enum DeactivateAccountScreenAlert {
|
||||
case confirmation
|
||||
case deactivationFailed
|
||||
}
|
||||
|
||||
enum DeactivateAccountScreenViewAction {
|
||||
case deactivate
|
||||
case cancel
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
//
|
||||
// Copyright 2022-2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
typealias DeactivateAccountScreenViewModelType = StateStoreViewModel<DeactivateAccountScreenViewState, DeactivateAccountScreenViewAction>
|
||||
|
||||
class DeactivateAccountScreenViewModel: DeactivateAccountScreenViewModelType, DeactivateAccountScreenViewModelProtocol {
|
||||
private let clientProxy: ClientProxyProtocol
|
||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||
|
||||
private let actionsSubject: PassthroughSubject<DeactivateAccountScreenViewModelAction, Never> = .init()
|
||||
var actionsPublisher: AnyPublisher<DeactivateAccountScreenViewModelAction, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(clientProxy: ClientProxyProtocol, userIndicatorController: UserIndicatorControllerProtocol) {
|
||||
self.clientProxy = clientProxy
|
||||
self.userIndicatorController = userIndicatorController
|
||||
|
||||
super.init(initialViewState: DeactivateAccountScreenViewState())
|
||||
}
|
||||
|
||||
override func process(viewAction: DeactivateAccountScreenViewAction) {
|
||||
MXLog.info("View model: received view action: \(viewAction)")
|
||||
|
||||
switch viewAction {
|
||||
case .cancel:
|
||||
actionsSubject.send(.cancel)
|
||||
case .deactivate:
|
||||
showDeactivationConfirmation()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private let deactivatingIndicatorID = "\(DeactivateAccountScreenViewModel.self)-Deactivating"
|
||||
|
||||
func showDeactivationConfirmation() {
|
||||
state.bindings.alertInfo = .init(id: .confirmation,
|
||||
title: L10n.screenDeactivateAccountTitle,
|
||||
message: L10n.screenDeactivateAccountConfirmationDialogContent,
|
||||
primaryButton: .init(title: L10n.actionDeactivate, action: {
|
||||
Task { await self.deactivateAccount() }
|
||||
}),
|
||||
secondaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil))
|
||||
}
|
||||
|
||||
func deactivateAccount() async {
|
||||
userIndicatorController.submitIndicator(UserIndicator(id: deactivatingIndicatorID,
|
||||
type: .modal(progress: .indeterminate, interactiveDismissDisabled: true, allowsInteraction: false),
|
||||
title: L10n.commonPleaseWait,
|
||||
persistent: true))
|
||||
|
||||
MXLog.warning("Deactivating account.")
|
||||
|
||||
switch await clientProxy.deactivateAccount(password: nil, eraseData: state.bindings.eraseData) {
|
||||
case .success:
|
||||
MXLog.info("Account deactivated (no password needed).")
|
||||
actionsSubject.send(.accountDeactivated)
|
||||
return
|
||||
case .failure:
|
||||
MXLog.info("Request failed, including password.")
|
||||
}
|
||||
|
||||
switch await clientProxy.deactivateAccount(password: state.bindings.password, eraseData: state.bindings.eraseData) {
|
||||
case .success:
|
||||
MXLog.info("Account deactivated.")
|
||||
actionsSubject.send(.accountDeactivated)
|
||||
return
|
||||
case .failure(let failure):
|
||||
MXLog.info("Deactivation failed \(failure).")
|
||||
state.bindings.alertInfo = .init(id: .deactivationFailed,
|
||||
title: L10n.errorUnknown,
|
||||
message: String(describing: failure))
|
||||
userIndicatorController.retractIndicatorWithId(deactivatingIndicatorID)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
//
|
||||
// Copyright 2022-2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
//
|
||||
|
||||
import Combine
|
||||
|
||||
@MainActor
|
||||
protocol DeactivateAccountScreenViewModelProtocol {
|
||||
var actionsPublisher: AnyPublisher<DeactivateAccountScreenViewModelAction, Never> { get }
|
||||
var context: DeactivateAccountScreenViewModelType.Context { get }
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
//
|
||||
// Copyright 2022-2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
//
|
||||
|
||||
import Compound
|
||||
import SwiftUI
|
||||
|
||||
struct DeactivateAccountScreen: View {
|
||||
@ObservedObject var context: DeactivateAccountScreenViewModel.Context
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
infoSection
|
||||
eraseDataSection
|
||||
passwordSection
|
||||
}
|
||||
.compoundList()
|
||||
.safeAreaInset(edge: .bottom) {
|
||||
Button(L10n.actionDeactivateAccount, role: .destructive) {
|
||||
context.send(viewAction: .deactivate)
|
||||
}
|
||||
.buttonStyle(.compound(.primary))
|
||||
.disabled(context.password.isEmpty)
|
||||
.padding(16)
|
||||
.background(Color.compound.bgSubtleSecondaryLevel0.ignoresSafeArea())
|
||||
}
|
||||
.navigationTitle(L10n.screenDeactivateAccountTitle)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar { toolbar }
|
||||
.alert(item: $context.alertInfo)
|
||||
}
|
||||
|
||||
private var infoSection: some View {
|
||||
ListRow(kind: .custom {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
Text(context.viewState.info)
|
||||
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
InfoItem(title: context.viewState.infoPoint1)
|
||||
InfoItem(title: context.viewState.infoPoint2)
|
||||
InfoItem(title: context.viewState.infoPoint3)
|
||||
InfoItem(title: context.viewState.infoPoint4, isSuccess: true)
|
||||
}
|
||||
}
|
||||
.foregroundColor(.compound.textSecondary)
|
||||
.font(.compound.bodyMD)
|
||||
.listRowBackground(Color.clear)
|
||||
})
|
||||
}
|
||||
|
||||
private var eraseDataSection: some View {
|
||||
Section {
|
||||
ListRow(label: .plain(title: L10n.screenDeactivateAccountDeleteAllMessages),
|
||||
kind: .toggle($context.eraseData))
|
||||
} footer: {
|
||||
Text(L10n.screenDeactivateAccountDeleteAllMessagesNotice)
|
||||
.compoundListSectionFooter()
|
||||
}
|
||||
}
|
||||
|
||||
private var passwordSection: some View {
|
||||
Section {
|
||||
ListRow(label: .plain(title: L10n.commonPassword),
|
||||
kind: .secureField(text: $context.password))
|
||||
.submitLabel(.done)
|
||||
} header: {
|
||||
Text(L10n.actionConfirmPassword)
|
||||
.compoundListSectionHeader()
|
||||
}
|
||||
}
|
||||
|
||||
private var toolbar: some ToolbarContent {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button(L10n.actionCancel) {
|
||||
context.send(viewAction: .cancel)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct InfoItem: View {
|
||||
let title: AttributedString
|
||||
var isSuccess = false
|
||||
|
||||
var body: some View {
|
||||
Label {
|
||||
Text(title).padding(.vertical, 1)
|
||||
} icon: {
|
||||
CompoundIcon(isSuccess ? \.check : \.close,
|
||||
size: .small,
|
||||
relativeTo: .compound.bodyMD)
|
||||
.foregroundStyle(isSuccess ? .compound.iconSuccessPrimary : .compound.iconCriticalPrimary)
|
||||
}
|
||||
.labelStyle(.custom(spacing: 8, alignment: .top))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Previews
|
||||
|
||||
struct DeactivateAccountScreen_Previews: PreviewProvider, TestablePreview {
|
||||
static let viewModel = DeactivateAccountScreenViewModel(clientProxy: ClientProxyMock(.init()),
|
||||
userIndicatorController: UserIndicatorControllerMock())
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
DeactivateAccountScreen(context: viewModel.context)
|
||||
}
|
||||
}
|
||||
}
|
@ -36,6 +36,7 @@ struct EncryptionResetPasswordScreen: View {
|
||||
}
|
||||
.buttonStyle(.compound(.primary))
|
||||
}
|
||||
.background()
|
||||
.backgroundStyle(.compound.bgCanvasDefault)
|
||||
.interactiveDismissDisabled()
|
||||
.onAppear { textFieldFocus = true }
|
||||
@ -49,6 +50,7 @@ struct EncryptionResetPasswordScreen: View {
|
||||
.font(.compound.bodySMSemibold)
|
||||
|
||||
SecureField(L10n.screenResetEncryptionPasswordPlaceholder, text: $context.password)
|
||||
.tint(.compound.iconAccentTertiary)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
.background(Color.compound.bgSubtleSecondaryLevel0)
|
||||
|
@ -196,6 +196,7 @@ struct SecureBackupRecoveryKeyScreen: View {
|
||||
.font(.compound.bodySMSemibold)
|
||||
|
||||
SecureField(L10n.screenRecoveryKeyConfirmKeyPlaceholder, text: $context.confirmationRecoveryKey)
|
||||
.tint(.compound.iconAccentTertiary)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
.background(Color.compound.bgSubtleSecondaryLevel0)
|
||||
|
@ -27,6 +27,7 @@ enum SettingsScreenCoordinatorAction {
|
||||
case notifications
|
||||
case advancedSettings
|
||||
case developerOptions
|
||||
case deactivateAccount
|
||||
}
|
||||
|
||||
final class SettingsScreenCoordinator: CoordinatorProtocol {
|
||||
@ -75,6 +76,8 @@ final class SettingsScreenCoordinator: CoordinatorProtocol {
|
||||
actionsSubject.send(.developerOptions)
|
||||
case .logout:
|
||||
actionsSubject.send(.logout)
|
||||
case .deactivateAccount:
|
||||
actionsSubject.send(.deactivateAccount)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
@ -22,6 +22,7 @@ enum SettingsScreenViewModelAction: Equatable {
|
||||
case advancedSettings
|
||||
case developerOptions
|
||||
case logout
|
||||
case deactivateAccount
|
||||
}
|
||||
|
||||
enum SettingsScreenSecuritySectionMode {
|
||||
@ -34,6 +35,7 @@ struct SettingsScreenViewState: BindableState {
|
||||
var userID: String
|
||||
var accountProfileURL: URL?
|
||||
var accountSessionsListURL: URL?
|
||||
var showAccountDeactivation: Bool
|
||||
var userAvatarURL: URL?
|
||||
var userDisplayName: String?
|
||||
var showDeveloperOptions: Bool
|
||||
@ -42,6 +44,12 @@ struct SettingsScreenViewState: BindableState {
|
||||
var showSecuritySectionBadge = false
|
||||
|
||||
var showBlockedUsers = false
|
||||
|
||||
var bindings = SettingsScreenViewStateBindings()
|
||||
}
|
||||
|
||||
struct SettingsScreenViewStateBindings {
|
||||
var isPresentingAccountDeactivationConfirmation = false
|
||||
}
|
||||
|
||||
enum SettingsScreenViewAction {
|
||||
@ -59,4 +67,5 @@ enum SettingsScreenViewAction {
|
||||
case developerOptions
|
||||
case advancedSettings
|
||||
case logout
|
||||
case deactivateAccount
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewMo
|
||||
init(userSession: UserSessionProtocol) {
|
||||
super.init(initialViewState: .init(deviceID: userSession.clientProxy.deviceID,
|
||||
userID: userSession.clientProxy.userID,
|
||||
showAccountDeactivation: userSession.clientProxy.canDeactivateAccount,
|
||||
showDeveloperOptions: AppSettings.isDevelopmentBuild),
|
||||
mediaProvider: userSession.mediaProvider)
|
||||
|
||||
@ -105,6 +106,8 @@ class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewMo
|
||||
state.showDeveloperOptions = true
|
||||
case .developerOptions:
|
||||
actionsSubject.send(.developerOptions)
|
||||
case .deactivateAccount:
|
||||
actionsSubject.send(.deactivateAccount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ struct SettingsScreen: View {
|
||||
}
|
||||
|
||||
generalSection
|
||||
|
||||
signOutSection
|
||||
}
|
||||
.compoundList()
|
||||
.navigationTitle(L10n.commonSettings)
|
||||
@ -167,7 +169,11 @@ struct SettingsScreen: View {
|
||||
})
|
||||
.accessibilityIdentifier(A11yIdentifiers.settingsScreen.developerOptions)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private var signOutSection: some View {
|
||||
Section {
|
||||
ListRow(label: .action(title: L10n.screenSignoutPreferenceItem,
|
||||
icon: \.signOut,
|
||||
role: .destructive),
|
||||
@ -175,6 +181,14 @@ struct SettingsScreen: View {
|
||||
context.send(viewAction: .logout)
|
||||
})
|
||||
.accessibilityIdentifier(A11yIdentifiers.settingsScreen.logout)
|
||||
if context.viewState.showAccountDeactivation {
|
||||
ListRow(label: .action(title: L10n.actionDeactivateAccount,
|
||||
icon: \.warning,
|
||||
role: .destructive),
|
||||
kind: .button {
|
||||
context.send(viewAction: .deactivateAccount)
|
||||
})
|
||||
}
|
||||
} footer: {
|
||||
VStack(spacing: 0) {
|
||||
versionText
|
||||
|
@ -213,6 +213,10 @@ class ClientProxy: ClientProxyProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
var canDeactivateAccount: Bool {
|
||||
client.canDeactivateAccount()
|
||||
}
|
||||
|
||||
var userIDServerName: String? {
|
||||
do {
|
||||
return try client.userIdServerName()
|
||||
@ -546,6 +550,16 @@ class ClientProxy: ClientProxyProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func deactivateAccount(password: String?, eraseData: Bool) async -> Result<Void, ClientProxyError> {
|
||||
do {
|
||||
try await client.deactivateAccount(authData: password.map { .password(passwordDetails: .init(identifier: userID, password: $0)) },
|
||||
eraseData: eraseData)
|
||||
return .success(())
|
||||
} catch {
|
||||
return .failure(.sdkError(error))
|
||||
}
|
||||
}
|
||||
|
||||
func setPusher(with configuration: PusherConfiguration) async throws {
|
||||
try await client.setPusher(identifiers: configuration.identifiers,
|
||||
kind: configuration.kind,
|
||||
|
@ -99,6 +99,8 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
|
||||
var slidingSyncVersion: SlidingSyncVersion { get }
|
||||
var availableSlidingSyncVersions: [SlidingSyncVersion] { get async }
|
||||
|
||||
var canDeactivateAccount: Bool { get }
|
||||
|
||||
var userIDServerName: String? { get }
|
||||
|
||||
var userDisplayNamePublisher: CurrentValuePublisher<String?, Never> { get }
|
||||
@ -157,6 +159,8 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
|
||||
|
||||
func sessionVerificationControllerProxy() async -> Result<SessionVerificationControllerProxyProtocol, ClientProxyError>
|
||||
|
||||
func deactivateAccount(password: String?, eraseData: Bool) async -> Result<Void, ClientProxyError>
|
||||
|
||||
func logout() async -> URL?
|
||||
|
||||
func setPusher(with configuration: PusherConfiguration) async throws
|
||||
|
@ -147,6 +147,12 @@ class PreviewTests: XCTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
func test_deactivateAccountScreen() {
|
||||
for preview in DeactivateAccountScreen_Previews._allPreviews {
|
||||
assertSnapshots(matching: preview)
|
||||
}
|
||||
}
|
||||
|
||||
func test_emojiPickerScreenHeaderView() {
|
||||
for preview in EmojiPickerScreenHeaderView_Previews._allPreviews {
|
||||
assertSnapshots(matching: preview)
|
||||
|
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_deactivateAccountScreen-iPad-en-GB.1.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_deactivateAccountScreen-iPad-en-GB.1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_deactivateAccountScreen-iPad-pseudo.1.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_deactivateAccountScreen-iPad-pseudo.1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_deactivateAccountScreen-iPhone-15-en-GB.1.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_deactivateAccountScreen-iPhone-15-en-GB.1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_deactivateAccountScreen-iPhone-15-pseudo.1.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_deactivateAccountScreen-iPhone-15-pseudo.1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_settingsScreen-iPad-en-GB.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_settingsScreen-iPad-en-GB.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_settingsScreen-iPad-pseudo.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_settingsScreen-iPad-pseudo.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_settingsScreen-iPhone-15-en-GB.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_settingsScreen-iPhone-15-en-GB.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_settingsScreen-iPhone-15-pseudo.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_settingsScreen-iPhone-15-pseudo.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.Unsigned-Devices.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.Unsigned-Devices.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.Unsigned-Devices.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.Unsigned-Devices.png
(Stored with Git LFS)
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -42,7 +42,7 @@ final class TemplateScreenCoordinator: CoordinatorProtocol {
|
||||
guard let self else { return }
|
||||
switch action {
|
||||
case .done:
|
||||
self.actionsSubject.send(.done)
|
||||
actionsSubject.send(.done)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
@ -0,0 +1,91 @@
|
||||
//
|
||||
// Copyright 2022-2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
@testable import ElementX
|
||||
|
||||
@MainActor
|
||||
class DeactivateAccountScreenViewModelTests: XCTestCase {
|
||||
var clientProxy: ClientProxyMock!
|
||||
var viewModel: DeactivateAccountScreenViewModelProtocol!
|
||||
|
||||
var context: DeactivateAccountScreenViewModelType.Context {
|
||||
viewModel.context
|
||||
}
|
||||
|
||||
override func setUpWithError() throws {
|
||||
clientProxy = ClientProxyMock(.init())
|
||||
viewModel = DeactivateAccountScreenViewModel(clientProxy: clientProxy, userIndicatorController: UserIndicatorControllerMock())
|
||||
}
|
||||
|
||||
func testDeactivate() async throws {
|
||||
try await validateDeactivate(erasingData: false)
|
||||
}
|
||||
|
||||
func testDeactivateAndErase() async throws {
|
||||
try await validateDeactivate(erasingData: true)
|
||||
}
|
||||
|
||||
func validateDeactivate(erasingData shouldErase: Bool) async throws {
|
||||
let enteredPassword = UUID().uuidString
|
||||
|
||||
clientProxy.deactivateAccountPasswordEraseDataClosure = { [weak self] password, eraseData in
|
||||
guard let self else { return .failure(.sdkError(ClientProxyMockError.generic)) }
|
||||
|
||||
if clientProxy.deactivateAccountPasswordEraseDataCallsCount == 1 {
|
||||
if password != nil {
|
||||
XCTFail("The password shouldn't be sent first time round.")
|
||||
}
|
||||
if eraseData != shouldErase {
|
||||
XCTFail("The erase parameter is unexpected.")
|
||||
}
|
||||
return .failure(.sdkError(ClientProxyMockError.generic))
|
||||
} else {
|
||||
if password != enteredPassword {
|
||||
XCTFail("The password should match the user's input on the second call.")
|
||||
}
|
||||
if eraseData != shouldErase {
|
||||
XCTFail("The erase parameter is unexpected.")
|
||||
}
|
||||
return .success(())
|
||||
}
|
||||
}
|
||||
|
||||
context.eraseData = shouldErase
|
||||
context.password = enteredPassword
|
||||
|
||||
XCTAssertNil(context.alertInfo)
|
||||
|
||||
let deferredState = deferFulfillment(context.$viewState) { $0.bindings.alertInfo != nil }
|
||||
context.send(viewAction: .deactivate)
|
||||
try await deferredState.fulfill()
|
||||
|
||||
guard let confirmationAction = context.alertInfo?.primaryButton.action else {
|
||||
XCTFail("Couldn't find the confirmation action.")
|
||||
return
|
||||
}
|
||||
|
||||
let deferredAction = deferFulfillment(viewModel.actionsPublisher) { $0 == .accountDeactivated }
|
||||
confirmationAction()
|
||||
try await deferredAction.fulfill()
|
||||
|
||||
XCTAssertEqual(clientProxy.deactivateAccountPasswordEraseDataCallsCount, 2)
|
||||
XCTAssertEqual(clientProxy.deactivateAccountPasswordEraseDataReceivedArguments?.password, enteredPassword)
|
||||
XCTAssertEqual(clientProxy.deactivateAccountPasswordEraseDataReceivedArguments?.eraseData, shouldErase)
|
||||
}
|
||||
|
||||
func testCancel() async throws {
|
||||
// When cancelling the view.
|
||||
let deferred = deferFulfillment(viewModel.actionsPublisher) { $0 == .cancel }
|
||||
context.send(viewAction: .cancel)
|
||||
try await deferred.fulfill()
|
||||
|
||||
// Then no API call should be made to deactivate the account.
|
||||
XCTAssertFalse(clientProxy.deactivateAccountPasswordEraseDataCalled)
|
||||
}
|
||||
}
|
@ -64,7 +64,7 @@ packages:
|
||||
# path: ../matrix-rust-sdk
|
||||
Compound:
|
||||
url: https://github.com/element-hq/compound-ios
|
||||
revision: 22f9d801dd001e8aaed0f62546cdb42c7594cf92
|
||||
revision: a9270392b3269ef072c47dea623815a9fb87311d
|
||||
# path: ../compound-ios
|
||||
AnalyticsEvents:
|
||||
url: https://github.com/matrix-org/matrix-analytics-events
|
||||
|
Loading…
x
Reference in New Issue
Block a user