From 3b40aadc98a007eb063eae7288e6f4b18162cd3e Mon Sep 17 00:00:00 2001 From: Doug <6060466+pixlwave@users.noreply.github.com> Date: Wed, 7 Oct 2026 16:51:28 +0100 Subject: [PATCH] Re-organise SettingsScreen to have distinct Account/App settings. (#6288) * Re-organise SettingsScreen to have distinct Account/App settings. * Remove the AdvancedSettingsScreen. --- .../Sources/GeneratedAccessibilityTests.swift | 4 - ElementX.xcodeproj/project.pbxproj | 36 --- .../SettingsFlowCoordinator.swift | 85 ++++--- .../TestablePreviewsDictionary.swift | 1 - .../AdvancedSettingsScreenCoordinator.swift | 32 --- .../AdvancedSettingsScreenModels.swift | 65 ------ .../AdvancedSettingsScreenViewModel.swift | 101 --------- ...ancedSettingsScreenViewModelProtocol.swift | 13 -- .../View/AdvancedSettingsScreen.swift | 181 --------------- ...onAndSafetySettingsScreenCoordinator.swift | 22 ++ .../SettingsScreenCoordinator.swift | 77 ++++--- .../SettingsScreen/SettingsScreenModels.swift | 70 ++++-- .../SettingsScreenViewModel.swift | 63 +++--- .../SettingsScreen/View/SettingsScreen.swift | 207 +++++++++--------- .../Sources/GeneratedPreviewTests.swift | 7 - .../advancedSettingsScreen.iPad-en-GB-0.png | 3 - .../advancedSettingsScreen.iPad-pseudo-0.png | 3 - .../advancedSettingsScreen.iPhone-en-GB-0.png | 3 - ...advancedSettingsScreen.iPhone-pseudo-0.png | 3 - ...sScreen.Bug-report-disabled-iPad-en-GB.png | 4 +- ...Screen.Bug-report-disabled-iPad-pseudo.png | 4 +- ...creen.Bug-report-disabled-iPhone-en-GB.png | 4 +- ...reen.Bug-report-disabled-iPhone-pseudo.png | 4 +- .../settingsScreen.Default-iPad-en-GB.png | 4 +- .../settingsScreen.Default-iPad-pseudo.png | 4 +- .../settingsScreen.Default-iPhone-en-GB.png | 4 +- .../settingsScreen.Default-iPhone-pseudo.png | 4 +- 27 files changed, 321 insertions(+), 687 deletions(-) delete mode 100644 ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/AdvancedSettingsScreenCoordinator.swift delete mode 100644 ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/AdvancedSettingsScreenModels.swift delete mode 100644 ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/AdvancedSettingsScreenViewModel.swift delete mode 100644 ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/AdvancedSettingsScreenViewModelProtocol.swift delete mode 100644 ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/View/AdvancedSettingsScreen.swift delete mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/advancedSettingsScreen.iPad-en-GB-0.png delete mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/advancedSettingsScreen.iPad-pseudo-0.png delete mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/advancedSettingsScreen.iPhone-en-GB-0.png delete mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/advancedSettingsScreen.iPhone-pseudo-0.png diff --git a/AccessibilityTests/Sources/GeneratedAccessibilityTests.swift b/AccessibilityTests/Sources/GeneratedAccessibilityTests.swift index d5d5c2822..8ecded246 100644 --- a/AccessibilityTests/Sources/GeneratedAccessibilityTests.swift +++ b/AccessibilityTests/Sources/GeneratedAccessibilityTests.swift @@ -11,10 +11,6 @@ extension AccessibilityTests { try await performAccessibilityAudit(named: "ActiveCallTimelineItemView_Previews") } - func testAdvancedSettingsScreen() async throws { - try await performAccessibilityAudit(named: "AdvancedSettingsScreen_Previews") - } - func testAnalyticsPromptScreen() async throws { try await performAccessibilityAudit(named: "AnalyticsPromptScreen_Previews") } diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 5046a393b..9bd6e56b1 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -81,7 +81,6 @@ 09693596AA3CA4E598C0D2F1 /* ThreadTimelineScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73FEE625AB52042049DB9268 /* ThreadTimelineScreenCoordinator.swift */; }; 09713669577CDA8D012EE380 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 6647C55D93508C7CE9D954A5 /* MatrixRustSDK */; }; 09D3D7D115318CAD131B4FE7 /* ResolveVerifiedUserSendFailureScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57084488B03BDB33C7B7CA0E /* ResolveVerifiedUserSendFailureScreenViewModelTests.swift */; }; - 09E1A358EA4205480AEF4698 /* AdvancedSettingsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = F229480685F30BCB96C439EC /* AdvancedSettingsScreen.swift */; }; 0AB4FF7645175FF1F6E942CC /* DeferredFulfillment.swift in Sources */ = {isa = PBXBuildFile; fileRef = B91AD590B0B40718A0AA0C61 /* DeferredFulfillment.swift */; }; 0ACAA31FD0399CEEBA3ECC21 /* UserDetailsEditScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85149F56BA333619900E2410 /* UserDetailsEditScreenViewModelProtocol.swift */; }; 0AD8EF040A60D62F488C18B5 /* KnockRequestProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F957320D0EB7D7B4E30C79D /* KnockRequestProxyMock.swift */; }; @@ -286,7 +285,6 @@ 2BBC0EB1E07963810A5D7423 /* ReadMarkerRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A284622B32052015F1F89 /* ReadMarkerRoomTimelineView.swift */; }; 2BBE320EE426A347AAE5C7DA /* IdentityConfirmationScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00AFC5F08734C2EA4EE79C59 /* IdentityConfirmationScreen.swift */; }; 2BC579CB5CE90CFE07CA0955 /* EditRoomAddressScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41656BC6267D55C56A2AAC08 /* EditRoomAddressScreenCoordinator.swift */; }; - 2BEDEA4851E1DF901779362C /* AdvancedSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 922E498EB74CF6F5CC236F81 /* AdvancedSettingsScreenModels.swift */; }; 2BFA4C6D5B3D327B02C66AB0 /* TimelineController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4216C12C0369A8AB059EDE9 /* TimelineController.swift */; }; 2C289BECCCBEDBA48DC9AC67 /* ClassicAppMXAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74240BE69DACAD01AA670730 /* ClassicAppMXAccount.swift */; }; 2C4C750D0039AFABDF24236C /* TemplateScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 342BEBC3C5FC3F9943C41C4C /* TemplateScreenViewModelProtocol.swift */; }; @@ -337,7 +335,6 @@ 34320DB3C585FD34F4DEC5C8 /* HomeserverHistoryManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D2BBDB7E80E119D5C906285 /* HomeserverHistoryManager.swift */; }; 34357B287357BC0B9715DD51 /* UserAgentBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F2529D434C750ED78ADF1ED /* UserAgentBuilder.swift */; }; 34390DAE0C574DAD30CCA7D9 /* DeclineAndBlockScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ADF12A50186B75C68017B61 /* DeclineAndBlockScreenViewModelTests.swift */; }; - 34ADC506C929D10B138EBA51 /* AdvancedSettingsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C58159916ABD7F454CE689 /* AdvancedSettingsScreenCoordinator.swift */; }; 34C752A73717C691582DC6C7 /* UnsupportedRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1B8500C152BC59445647DA8 /* UnsupportedRoomTimelineItem.swift */; }; 34F1261CEF6D6A00D559B520 /* SettingsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CFD5EB0B0EEA4549FB49784 /* SettingsScreen.swift */; }; 352C439BE0F75E101EF11FB1 /* RoomScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2886615BEBAE33A0AA4D5F8 /* RoomScreenModels.swift */; }; @@ -1439,7 +1436,6 @@ E1428612B08ED3030EC1FEC3 /* SpacesScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 104B7747499487538483FEAF /* SpacesScreen.swift */; }; E14E469CD97550D0FC58F3CA /* CancellableTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE52983FAFB4E0998C00EE8A /* CancellableTask.swift */; }; E184FFAD32342D3D6E2F89AA /* PinnedEventsTimelineScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D53754227CEBD06358956D7 /* PinnedEventsTimelineScreenCoordinator.swift */; }; - E1A0752244567A25E376A2F4 /* AdvancedSettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7A1B80FE6E3BA72F9C748AD /* AdvancedSettingsScreenViewModel.swift */; }; E1C67E5D9E22135A8FEBBD60 /* StackedAvatarsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8558D41DD4B553A752C868A /* StackedAvatarsView.swift */; }; E1CC93B1842137A8AB25B815 /* SearchBreadcrumb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 095B8ED0CA87F4A0A4858719 /* SearchBreadcrumb.swift */; }; E1DE8A5422643F759385290F /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD5523BDEDB247E29228476 /* AppSettings.swift */; }; @@ -1629,7 +1625,6 @@ FC10228E73323BDC09526F97 /* LRUCache in Frameworks */ = {isa = PBXBuildFile; productRef = 1081D3630AAD3ACEDDEC3A98 /* LRUCache */; }; FC31493979ED1FDF7D5EA3F9 /* KeychainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E36CB905A2B9EC2C92A2DA7C /* KeychainController.swift */; }; FCD3F2B82CAB29A07887A127 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = DE8DC9B3FBA402117DC4C49F /* Kingfisher */; }; - FCF95603F1D056B1B106A415 /* AdvancedSettingsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83E2B20431F890ED64255CA1 /* AdvancedSettingsScreenViewModelProtocol.swift */; }; FD19654C18E7C6D8AC79408D /* libMatrixRustSDKMocks.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 73F3153AB9D628110878E24F /* libMatrixRustSDKMocks.a */; }; FD29471C72872F8B7580E3E1 /* KeychainControllerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39C0D861FC397AC34BCF089E /* KeychainControllerMock.swift */; }; FD573B5D665824EB79EABF06 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5327E3B3C58BEB0E65F4CF98 /* Observable.swift */; }; @@ -2196,7 +2191,6 @@ 421E716C521F96D24ECE69B3 /* NoticeRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineItem.swift; sourceTree = ""; }; 421FA93BCC2840E66E4F306F /* NotificationSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsScreenViewModelProtocol.swift; sourceTree = ""; }; 42236480CF0431535EBE8387 /* CustomLayoutLabelStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomLayoutLabelStyle.swift; sourceTree = ""; }; - 42C58159916ABD7F454CE689 /* AdvancedSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenCoordinator.swift; sourceTree = ""; }; 42C64A14EE89928207E3B42B /* AnalyticsSettingsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenModels.swift; sourceTree = ""; }; 42C8C368A611B9CB79C7F5FA /* RoomPollsHistoryScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomPollsHistoryScreen.swift; sourceTree = ""; }; 430C73079A84654BF46A7FF5 /* FileMediaEventsTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileMediaEventsTimelineView.swift; sourceTree = ""; }; @@ -2580,7 +2574,6 @@ 839E2C35DF3F9C7B54C3CE49 /* RoundedCornerShape.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedCornerShape.swift; sourceTree = ""; }; 83B4E3F1265581683E4997B8 /* RoomSelectionScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSelectionScreenViewModel.swift; sourceTree = ""; }; 83B574805B9812C111D6215D /* Tracing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tracing.swift; sourceTree = ""; }; - 83E2B20431F890ED64255CA1 /* AdvancedSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenViewModelProtocol.swift; sourceTree = ""; }; 840182D7A61402D5947DE094 /* NotificationItemProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationItemProxyMock.swift; sourceTree = ""; }; 842F63AA68E8EB410B1BA29F /* MapLibreInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MapLibreInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 84311D707B09854D67F78BBF /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -2671,7 +2664,6 @@ 91C8BD78F7B9247AC57FA1A3 /* RedactedRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedactedRoomTimelineView.swift; sourceTree = ""; }; 91CF6F7D08228D16BA69B63B /* zh-Hant-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant-TW"; path = "zh-Hant-TW.lproj/Localizable.strings"; sourceTree = ""; }; 91FFE1F410969ECB23FE9BB2 /* TimelineItemMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemMenu.swift; sourceTree = ""; }; - 922E498EB74CF6F5CC236F81 /* AdvancedSettingsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenModels.swift; sourceTree = ""; }; 92DB574F954CC2B40F7BE892 /* QRCodeScannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeScannerView.swift; sourceTree = ""; }; 9332DFE9642F0A46ECA0497B /* BlurHashEncode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurHashEncode.swift; sourceTree = ""; }; 933B074F006F8E930DB98B4E /* TimelineMediaFrame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaFrame.swift; sourceTree = ""; }; @@ -2795,7 +2787,6 @@ A768CA51A59B8A5D8C8FD599 /* AuthenticationStartScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationStartScreen.swift; sourceTree = ""; }; A7978C9EFBDD7DE39BD86726 /* RestorationTokenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestorationTokenTests.swift; sourceTree = ""; }; A79A78330B9329E3A99E4105 /* SearchScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchScreen.swift; sourceTree = ""; }; - A7A1B80FE6E3BA72F9C748AD /* AdvancedSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenViewModel.swift; sourceTree = ""; }; A7C4EA55DA62F9D0F984A2AE /* CollapsibleTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsibleTimelineItem.swift; sourceTree = ""; }; A7D452AF7B5F7E3A0A7DB54C /* SessionVerificationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModelProtocol.swift; sourceTree = ""; }; A7E37072597F67C4DD8CC2DB /* ComposerDraftServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerDraftServiceProtocol.swift; sourceTree = ""; }; @@ -3259,7 +3250,6 @@ F17EFA1D3D09FC2F9C5E1CB2 /* MediaProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProvider.swift; sourceTree = ""; }; F1B0FC6A77FDFDE2BFE49E13 /* MediaUploadQualitySettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaUploadQualitySettingsScreenCoordinator.swift; sourceTree = ""; }; F1B8500C152BC59445647DA8 /* UnsupportedRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsupportedRoomTimelineItem.swift; sourceTree = ""; }; - F229480685F30BCB96C439EC /* AdvancedSettingsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreen.swift; sourceTree = ""; }; F276F31C1AEC19E52B951B62 /* SendInviteConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendInviteConfirmationView.swift; sourceTree = ""; }; F288457CD4C821DF48C1B6EE /* NativeCallRoomContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeCallRoomContext.swift; sourceTree = ""; }; F2B94F1B0B5D9D42B15AA6E8 /* ChatsTabFlowCoordinatorStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatsTabFlowCoordinatorStateMachine.swift; sourceTree = ""; }; @@ -3489,14 +3479,6 @@ path = VoiceMessage; sourceTree = ""; }; - 018074F385C9417ECBEA793E /* View */ = { - isa = PBXGroup; - children = ( - F229480685F30BCB96C439EC /* AdvancedSettingsScreen.swift */, - ); - path = View; - sourceTree = ""; - }; 01C939DDDF02F155F115DEF5 /* Sources */ = { isa = PBXGroup; children = ( @@ -5273,7 +5255,6 @@ isa = PBXGroup; children = ( EB5B1119B5AD79297F1D49EB /* AccountSettings */, - FF2C35C46D5B8879A71F0BAC /* AdvancedSettingsScreen */, 09C599CB430ABF160C1EE55C /* AnalyticsSettingsScreen */, CBB8EC37B802F3DD74A0205E /* DeactivateAccountScreen */, 1CA6CD0DE6F0445156361B6D /* DeveloperOptionsScreen */, @@ -7605,18 +7586,6 @@ path = View; sourceTree = ""; }; - FF2C35C46D5B8879A71F0BAC /* AdvancedSettingsScreen */ = { - isa = PBXGroup; - children = ( - 42C58159916ABD7F454CE689 /* AdvancedSettingsScreenCoordinator.swift */, - 922E498EB74CF6F5CC236F81 /* AdvancedSettingsScreenModels.swift */, - A7A1B80FE6E3BA72F9C748AD /* AdvancedSettingsScreenViewModel.swift */, - 83E2B20431F890ED64255CA1 /* AdvancedSettingsScreenViewModelProtocol.swift */, - 018074F385C9417ECBEA793E /* View */, - ); - path = AdvancedSettingsScreen; - sourceTree = ""; - }; FF654D7FD6693839E3185FAD /* View */ = { isa = PBXGroup; children = ( @@ -8739,11 +8708,6 @@ 4A7957D034F5D96909127881 /* AccountSettings.swift in Sources */, EFB3033FE782773D4F105681 /* AccountUserDefaults.swift in Sources */, 21215E17C9908F1EBF621BE0 /* ActiveCallTimelineItemView.swift in Sources */, - 09E1A358EA4205480AEF4698 /* AdvancedSettingsScreen.swift in Sources */, - 34ADC506C929D10B138EBA51 /* AdvancedSettingsScreenCoordinator.swift in Sources */, - 2BEDEA4851E1DF901779362C /* AdvancedSettingsScreenModels.swift in Sources */, - E1A0752244567A25E376A2F4 /* AdvancedSettingsScreenViewModel.swift in Sources */, - FCF95603F1D056B1B106A415 /* AdvancedSettingsScreenViewModelProtocol.swift in Sources */, 53C1E7F6A7D6409D89F36ED7 /* AggregatedReactionMock.swift in Sources */, 4219391CD2351E410554B3E8 /* AggregratedReaction.swift in Sources */, 64D05250CEDE8B604119F6E6 /* Alert.swift in Sources */, diff --git a/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift index 2594fe505..2de2b9677 100644 --- a/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift @@ -85,44 +85,52 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol { switch action { case .dismiss: actionsSubject.send(.dismiss) - case .logout: - actionsSubject.send(.runLogoutFlow) - case .secureBackup: - startEncryptionSettingsFlow() + case .userDetails: presentUserDetailsEditScreen() case let .userStatusEmojiPicker(continuation): presentEmojiPicker(emojiPickerContinuation: continuation) + case .addAccount: break // Nothing to present until the add account flow exists. - case .linkNewDevice: - startLinkNewDeviceFlow() + case let .manageAccount(url): presentAccountManagementURL(url) - case .analytics: - presentAnalyticsScreen() - case .appLock: - presentAppLockSetupFlow() + case .linkNewDevice: + startLinkNewDeviceFlow() + case .notifications: + presentNotificationSettings() + case .secureBackup: + startEncryptionSettingsFlow() + case .moderationAndSafety: + presentModerationAndSafetySettings() case .bugReport: bugReportFlowCoordinator = BugReportFlowCoordinator(parameters: .init(presentationMode: .push(navigationStackCoordinator), userIndicatorController: flowParameters.userIndicatorController, bugReportService: flowParameters.bugReportService, userSession: flowParameters.userSession)) bugReportFlowCoordinator?.start() - case .about: - presentLegalInformationScreen() - case .blockedUsers: - presentBlockedUsersScreen() - case .notifications: - presentNotificationSettings() - case .advancedSettings: - presentAdvancedSettings() - case .labs: - presentLabs() - case .developerOptions: - presentDeveloperOptions() + + case .logout: + actionsSubject.send(.runLogoutFlow) case .deactivateAccount: presentDeactivateAccount() + + case .mediaUploadQuality: + presentMediaUploadQualitySettings() + case .appLock: + presentAppLockSetupFlow() + case .locationSharing: + presentLocationSharingSettings() + case .analytics: + presentAnalyticsScreen() + case .labs: + presentLabs() + case .about: + presentLegalInformationScreen() + + case .developerOptions: + presentDeveloperOptions() } } .store(in: &cancellables) @@ -273,11 +281,34 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol { navigationStackCoordinator.push(coordinator) } - private func presentAdvancedSettings() { - let coordinator = AdvancedSettingsScreenCoordinator(parameters: .init(userSettings: flowParameters.userSettings, - analytics: flowParameters.analytics, - clientProxy: flowParameters.userSession.clientProxy, - userIndicatorController: flowParameters.userIndicatorController)) + private func presentModerationAndSafetySettings() { + let parameters = ModerationAndSafetySettingsScreenCoordinatorParameters(userSession: flowParameters.userSession, + userIndicatorController: flowParameters.userIndicatorController) + let coordinator = ModerationAndSafetySettingsScreenCoordinator(parameters: parameters) + coordinator.actionsPublisher + .sink { [weak self] action in + guard let self else { return } + + switch action { + case .blockedUsers: + presentBlockedUsersScreen() + } + } + .store(in: &cancellables) + + navigationStackCoordinator.push(coordinator) + } + + private func presentMediaUploadQualitySettings() { + let parameters = MediaUploadQualitySettingsScreenCoordinatorParameters(userSettings: flowParameters.userSettings, + analytics: flowParameters.analytics) + let coordinator = MediaUploadQualitySettingsScreenCoordinator(parameters: parameters) + navigationStackCoordinator.push(coordinator) + } + + private func presentLocationSharingSettings() { + let parameters = LocationSharingSettingsScreenCoordinatorParameters(userSettings: flowParameters.userSettings) + let coordinator = LocationSharingSettingsScreenCoordinator(parameters: parameters) navigationStackCoordinator.push(coordinator) } diff --git a/ElementX/Sources/Other/TestablePreview/TestablePreviewsDictionary.swift b/ElementX/Sources/Other/TestablePreview/TestablePreviewsDictionary.swift index c6f389434..fa5a0c4e5 100644 --- a/ElementX/Sources/Other/TestablePreview/TestablePreviewsDictionary.swift +++ b/ElementX/Sources/Other/TestablePreview/TestablePreviewsDictionary.swift @@ -11,7 +11,6 @@ enum TestablePreviewsDictionary { static let dictionary: [String: any PreviewProvider.Type] = { var dictionary: [String: any PreviewProvider.Type] = [ "ActiveCallTimelineItemView_Previews" : ActiveCallTimelineItemView_Previews.self, - "AdvancedSettingsScreen_Previews" : AdvancedSettingsScreen_Previews.self, "AnalyticsPromptScreen_Previews" : AnalyticsPromptScreen_Previews.self, "AnalyticsSettingsScreen_Previews" : AnalyticsSettingsScreen_Previews.self, "AppLockScreen_Previews" : AppLockScreen_Previews.self, diff --git a/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/AdvancedSettingsScreenCoordinator.swift b/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/AdvancedSettingsScreenCoordinator.swift deleted file mode 100644 index 0e6a702b3..000000000 --- a/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/AdvancedSettingsScreenCoordinator.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright 2025 Element Creations Ltd. -// Copyright 2022-2025 New Vector Ltd. -// -// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial -// Please see LICENSE files in the repository root for full details. -// - -import Combine -import SwiftUI - -struct AdvancedSettingsScreenCoordinatorParameters { - let userSettings: UserSettings - let analytics: AnalyticsServiceProtocol - let clientProxy: ClientProxyProtocol - let userIndicatorController: UserIndicatorControllerProtocol -} - -final class AdvancedSettingsScreenCoordinator: CoordinatorProtocol { - private var viewModel: AdvancedSettingsScreenViewModelProtocol - - init(parameters: AdvancedSettingsScreenCoordinatorParameters) { - viewModel = AdvancedSettingsScreenViewModel(advancedSettings: parameters.userSettings.app, - analytics: parameters.analytics, - clientProxy: parameters.clientProxy, - userIndicatorController: parameters.userIndicatorController) - } - - func toPresentable() -> AnyView { - AnyView(AdvancedSettingsScreen(context: viewModel.context)) - } -} diff --git a/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/AdvancedSettingsScreenModels.swift b/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/AdvancedSettingsScreenModels.swift deleted file mode 100644 index 41adad23d..000000000 --- a/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/AdvancedSettingsScreenModels.swift +++ /dev/null @@ -1,65 +0,0 @@ -// -// Copyright 2025 Element Creations Ltd. -// Copyright 2022-2025 New Vector Ltd. -// -// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial -// Please see LICENSE files in the repository root for full details. -// - -import Foundation -import UIKit - -struct AdvancedSettingsScreenViewState: BindableState { - init(timelineMediaVisibility: TimelineMediaVisibility, hideInviteAvatars: Bool, isWaitingTimelineMediaVisibility: Bool = false, isWaitingHideInviteAvatars: Bool = false, bindings: AdvancedSettingsScreenViewStateBindings) { - self.timelineMediaVisibility = timelineMediaVisibility - self.hideInviteAvatars = hideInviteAvatars - self.isWaitingTimelineMediaVisibility = isWaitingTimelineMediaVisibility - self.isWaitingHideInviteAvatars = isWaitingHideInviteAvatars - self.bindings = bindings - - let linkPlaceholder = "{link}" - var footerString = AttributedString(L10n.screenAdvancedSettingsLiveLocationSectionFooter(linkPlaceholder)) - var linkString = AttributedString(L10n.screenAdvancedSettingsLiveLocationSectionFooterLink) - linkString.link = URL(string: UIApplication.openSettingsURLString) - linkString.bold() - footerString.replace(linkPlaceholder, with: linkString) - liveLocationUpdateFooterAttributedString = footerString - } - - let liveLocationUpdateFooterAttributedString: AttributedString - var timelineMediaVisibility: TimelineMediaVisibility - var hideInviteAvatars: Bool - var isWaitingTimelineMediaVisibility: Bool - var isWaitingHideInviteAvatars: Bool - var bindings: AdvancedSettingsScreenViewStateBindings -} - -@dynamicMemberLookup -struct AdvancedSettingsScreenViewStateBindings { - private let advancedSettings: AdvancedSettingsProtocol - - init(advancedSettings: AdvancedSettingsProtocol) { - self.advancedSettings = advancedSettings - } - - subscript(dynamicMember keyPath: ReferenceWritableKeyPath) -> Setting { - get { advancedSettings[keyPath: keyPath] } - set { advancedSettings[keyPath: keyPath] = newValue } - } -} - -enum AdvancedSettingsScreenViewAction { - case optimizeMediaUploadsChanged - case updateTimelineMediaVisibility(TimelineMediaVisibility) - case updateHideInviteAvatars(Bool) -} - -protocol AdvancedSettingsProtocol: AnyObject { - var viewSourceEnabled: Bool { get set } - var appAppearance: AppAppearance { get set } - var sharePresence: Bool { get set } - var optimizeMediaUploads: Bool { get set } - var liveLocationMinimumDistanceUpdate: Int { get set } -} - -extension AppSettings: AdvancedSettingsProtocol { } diff --git a/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/AdvancedSettingsScreenViewModel.swift b/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/AdvancedSettingsScreenViewModel.swift deleted file mode 100644 index c59085694..000000000 --- a/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/AdvancedSettingsScreenViewModel.swift +++ /dev/null @@ -1,101 +0,0 @@ -// -// Copyright 2025 Element Creations Ltd. -// Copyright 2022-2025 New Vector Ltd. -// -// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial -// Please see LICENSE files in the repository root for full details. -// - -import Combine -import SwiftUI - -typealias AdvancedSettingsScreenViewModelType = StateStoreViewModelV2 - -class AdvancedSettingsScreenViewModel: AdvancedSettingsScreenViewModelType, AdvancedSettingsScreenViewModelProtocol { - private let analytics: AnalyticsServiceProtocol - private let clientProxy: ClientProxyProtocol - private let userIndicatorController: UserIndicatorControllerProtocol - - private var timelineMediaVisibilityTask: Task? - private var hideInviteAvatarsTask: Task? - - init(advancedSettings: AdvancedSettingsProtocol, - analytics: AnalyticsServiceProtocol, - clientProxy: ClientProxyProtocol, - userIndicatorController: UserIndicatorControllerProtocol) { - self.analytics = analytics - self.clientProxy = clientProxy - self.userIndicatorController = userIndicatorController - - let state = AdvancedSettingsScreenViewState(timelineMediaVisibility: clientProxy.timelineMediaVisibilityPublisher.value, - hideInviteAvatars: clientProxy.hideInviteAvatarsPublisher.value, - bindings: .init(advancedSettings: advancedSettings)) - super.init(initialViewState: state) - - clientProxy.timelineMediaVisibilityPublisher - .removeDuplicates() - .receive(on: DispatchQueue.main) - .weakAssign(to: \.state.timelineMediaVisibility, on: self) - .store(in: &cancellables) - - clientProxy.hideInviteAvatarsPublisher - .removeDuplicates() - .receive(on: DispatchQueue.main) - .weakAssign(to: \.state.hideInviteAvatars, on: self) - .store(in: &cancellables) - } - - override func process(viewAction: AdvancedSettingsScreenViewAction) { - switch viewAction { - case .optimizeMediaUploadsChanged: - // Note: Using a view action here as sinking the UserSettings publisher tracks the initial value. - analytics.trackInteraction(name: state.bindings.optimizeMediaUploads ? .MobileSettingsOptimizeMediaUploadsEnabled : .MobileSettingsOptimizeMediaUploadsDisabled) - case let .updateHideInviteAvatars(value): - hideInviteAvatarsTask = Task { [weak self] in await self?.updateHideInviteAvatars(value) } - case let .updateTimelineMediaVisibility(value): - timelineMediaVisibilityTask = Task { [weak self] in await self?.updateTimelineMediaVisibility(value) } - } - } - - private func updateTimelineMediaVisibility(_ value: TimelineMediaVisibility) async { - defer { - timelineMediaVisibilityTask = nil - state.isWaitingTimelineMediaVisibility = false - } - - let previousState = state.timelineMediaVisibility - state.isWaitingTimelineMediaVisibility = true - state.timelineMediaVisibility = value - // If the other value is updating wait also for it to finish - await hideInviteAvatarsTask?.value - - switch await clientProxy.setTimelineMediaVisibility(value) { - case .success: - break - case .failure: - state.timelineMediaVisibility = previousState - userIndicatorController.submitIndicator(.init(title: L10n.errorUnknown)) - } - } - - private func updateHideInviteAvatars(_ value: Bool) async { - defer { - hideInviteAvatarsTask = nil - state.isWaitingHideInviteAvatars = false - } - - let previousState = state.hideInviteAvatars - state.isWaitingHideInviteAvatars = true - state.hideInviteAvatars = value - // If the other value is updating wait also for it to finish - await timelineMediaVisibilityTask?.value - - switch await clientProxy.setHideInviteAvatars(value) { - case .success: - break - case .failure: - state.hideInviteAvatars = previousState - userIndicatorController.submitIndicator(.init(title: L10n.errorUnknown)) - } - } -} diff --git a/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/AdvancedSettingsScreenViewModelProtocol.swift b/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/AdvancedSettingsScreenViewModelProtocol.swift deleted file mode 100644 index d918236b3..000000000 --- a/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/AdvancedSettingsScreenViewModelProtocol.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright 2025 Element Creations Ltd. -// Copyright 2022-2025 New Vector Ltd. -// -// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial -// Please see LICENSE files in the repository root for full details. -// - -import Combine - -protocol AdvancedSettingsScreenViewModelProtocol { - var context: AdvancedSettingsScreenViewModelType.Context { get } -} diff --git a/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/View/AdvancedSettingsScreen.swift b/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/View/AdvancedSettingsScreen.swift deleted file mode 100644 index de2d8b5d4..000000000 --- a/ElementX/Sources/Screens/Settings/AdvancedSettingsScreen/View/AdvancedSettingsScreen.swift +++ /dev/null @@ -1,181 +0,0 @@ -// -// Copyright 2025 Element Creations Ltd. -// Copyright 2022-2025 New Vector Ltd. -// -// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial -// Please see LICENSE files in the repository root for full details. -// - -import Compound -import SwiftUI - -struct AdvancedSettingsScreen: View { - static let measurementFormatter = { - let formatter = MeasurementFormatter() - formatter.unitOptions = .providedUnit - formatter.unitStyle = .short - return formatter - }() - - @Bindable var context: AdvancedSettingsScreenViewModel.Context - - var body: some View { - Form { - Section { - ListRow(label: .plain(title: L10n.commonAppearance), - kind: .picker(selection: $context.appAppearance, - items: AppAppearance.allCases.map { (title: $0.name, tag: $0) })) - - ListRow(label: .plain(title: L10n.actionViewSource, - description: L10n.screenAdvancedSettingsViewSourceDescription), - kind: .toggle($context.viewSourceEnabled)) - - ListRow(label: .plain(title: L10n.screenAdvancedSettingsSharePresence, - description: L10n.screenAdvancedSettingsSharePresenceDescription), - kind: .toggle($context.sharePresence)) - - ListRow(label: .plain(title: L10n.screenAdvancedSettingsMediaCompressionTitle, - description: L10n.screenAdvancedSettingsMediaCompressionDescription), - kind: .toggle($context.optimizeMediaUploads)) - .onChange(of: context.optimizeMediaUploads) { - context.send(viewAction: .optimizeMediaUploadsChanged) - } - } - - moderationAndSafetySection - timelineMediaSection - liveLocationSection - } - .compoundList() - .navigationTitle(L10n.commonAdvancedSettings) - .navigationBarTitleDisplayMode(.inline) - } - - @ViewBuilder - private var moderationAndSafetySection: some View { - let binding = Binding(get: { - context.viewState.hideInviteAvatars - }, set: { newValue in - context.send(viewAction: .updateHideInviteAvatars(newValue)) - }) - - Section { - ListRow(label: .plain(title: L10n.screenAdvancedSettingsHideInviteAvatarsToggleTitle), - details: context.viewState.isWaitingHideInviteAvatars ? .isWaiting(true) : nil, - kind: .toggle(binding)) - .disabled(context.viewState.isWaitingHideInviteAvatars) - } header: { - Text(L10n.screenAdvancedSettingsModerationAndSafetySectionTitle) - .compoundListSectionHeader() - } - } - - @ViewBuilder - private var timelineMediaSection: some View { - let binding = Binding(get: { - context.viewState.timelineMediaVisibility - }, set: { newValue in - context.send(viewAction: .updateTimelineMediaVisibility(newValue)) - }) - - Section { - ListRow(label: .plain(title: L10n.screenAdvancedSettingsShowMediaTimelineTitle), - details: .isWaiting(context.viewState.isWaitingTimelineMediaVisibility), - kind: .inlinePicker(selection: binding, - items: TimelineMediaVisibility.items)) - .disabled(context.viewState.isWaitingTimelineMediaVisibility) - } header: { - Text(L10n.screenAdvancedSettingsShowMediaTimelineTitle) - .compoundListSectionHeader() - } footer: { - Text(L10n.screenAdvancedSettingsShowMediaTimelineSubtitle) - .compoundListSectionFooter() - } - } - - @ViewBuilder - private var liveLocationSection: some View { - let binding = Binding(get: { - Double(context.liveLocationMinimumDistanceUpdate) - }, set: { newValue in - context.liveLocationMinimumDistanceUpdate = Int(newValue) - }) - - Section { - ListRow(kind: .custom { - VStack(alignment: .leading, spacing: 0) { - Text(L10n.screenAdvancedSettingsLiveLocationUpdateDistance(context.liveLocationMinimumDistanceUpdate)) - .font(.compound.bodyLG) - .foregroundStyle(.compound.textPrimary) - // The internal hidden label of the slider will read voice over - .accessibilityHidden(true) - Slider(value: binding, in: 1...100) { - Text(L10n.screenAdvancedSettingsLiveLocationUpdateDistance(context.liveLocationMinimumDistanceUpdate)) - } minimumValueLabel: { - Text(Self.measurementFormatter.string(from: .init(value: 1, - unit: UnitLength.meters))) - .font(.compound.bodyLG) - .foregroundStyle(.compound.textSecondary) - .padding(.trailing, 15) - } maximumValueLabel: { - Text(Self.measurementFormatter.string(from: .init(value: 100, - unit: UnitLength.meters))) - .font(.compound.bodyLG) - .foregroundStyle(.compound.textSecondary) - .padding(.leading, 15) - } - .tint(.compound.iconAccentPrimary) - } - .padding(.horizontal, ListRowPadding.horizontal) - .padding(.vertical, ListRowPadding.vertical) - }) - } header: { - VStack(alignment: .leading, spacing: 4) { - Text(L10n.screenAdvancedSettingsLiveLocationSectionTitle) - .compoundListSectionHeader() - Text(L10n.screenAdvancedSettingsLiveLocationSectionDescription) - .font(.compound.bodyMD) - .foregroundStyle(.compound.textSecondary) - } - } footer: { - Text(context.viewState.liveLocationUpdateFooterAttributedString) - .compoundListSectionFooter() - } - } -} - -private extension AppAppearance { - var name: String { - switch self { - case .system: - L10n.themeSystem - case .light: - L10n.themeLight - case .dark: - L10n.themeDark - } - } -} - -// MARK: - Previews - -struct AdvancedSettingsScreen_Previews: PreviewProvider, TestablePreview { - static let viewModel = AdvancedSettingsScreenViewModel(advancedSettings: AppSettings.volatile(), - analytics: AnalyticsServiceMock(.init()), - clientProxy: ClientProxyMock(.init()), - userIndicatorController: UserIndicatorControllerMock()) - - static var previews: some View { - ElementNavigationStack { - AdvancedSettingsScreen(context: viewModel.context) - } - } -} - -private extension TimelineMediaVisibility { - static var items: [(title: String, tag: TimelineMediaVisibility)] { - [(title: L10n.screenAdvancedSettingsShowMediaTimelineAlwaysHide, tag: .never), - (title: L10n.screenAdvancedSettingsShowMediaTimelinePrivateRooms, tag: .privateOnly), - (title: L10n.screenAdvancedSettingsShowMediaTimelineAlwaysShow, tag: .always)] - } -} diff --git a/ElementX/Sources/Screens/Settings/ModerationAndSafetySettingsScreen/ModerationAndSafetySettingsScreenCoordinator.swift b/ElementX/Sources/Screens/Settings/ModerationAndSafetySettingsScreen/ModerationAndSafetySettingsScreenCoordinator.swift index bb632d908..9f3d15bcc 100644 --- a/ElementX/Sources/Screens/Settings/ModerationAndSafetySettingsScreen/ModerationAndSafetySettingsScreenCoordinator.swift +++ b/ElementX/Sources/Screens/Settings/ModerationAndSafetySettingsScreen/ModerationAndSafetySettingsScreenCoordinator.swift @@ -13,12 +13,34 @@ struct ModerationAndSafetySettingsScreenCoordinatorParameters { let userIndicatorController: UserIndicatorControllerProtocol } +enum ModerationAndSafetySettingsScreenCoordinatorAction { + case blockedUsers +} + final class ModerationAndSafetySettingsScreenCoordinator: CoordinatorProtocol { private var viewModel: ModerationAndSafetySettingsScreenViewModelProtocol + private let actionsSubject: PassthroughSubject = .init() + var actionsPublisher: AnyPublisher { + actionsSubject.eraseToAnyPublisher() + } + + private var cancellables = Set() + init(parameters: ModerationAndSafetySettingsScreenCoordinatorParameters) { viewModel = ModerationAndSafetySettingsScreenViewModel(userSession: parameters.userSession, userIndicatorController: parameters.userIndicatorController) + + viewModel.actionsPublisher + .sink { [weak self] action in + guard let self else { return } + + switch action { + case .blockedUsers: + actionsSubject.send(.blockedUsers) + } + } + .store(in: &cancellables) } func toPresentable() -> AnyView { diff --git a/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenCoordinator.swift b/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenCoordinator.swift index ef2a7d189..622d116a8 100644 --- a/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenCoordinator.swift +++ b/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenCoordinator.swift @@ -19,23 +19,30 @@ struct SettingsScreenCoordinatorParameters { enum SettingsScreenCoordinatorAction { case dismiss - case logout - case secureBackup + case userDetails case userStatusEmojiPicker(EmojiPickerScreenContinuation) + case addAccount - case analytics - case appLock - case bugReport - case about - case blockedUsers - case linkNewDevice + case manageAccount(url: URL) + case linkNewDevice case notifications - case advancedSettings - case labs - case developerOptions + case secureBackup + case moderationAndSafety + case bugReport + + case logout case deactivateAccount + + case mediaUploadQuality + case appLock + case locationSharing + case analytics + case labs + case about + + case developerOptions } final class SettingsScreenCoordinator: CoordinatorProtocol { @@ -64,40 +71,48 @@ final class SettingsScreenCoordinator: CoordinatorProtocol { switch action { case .close: actionsSubject.send(.dismiss) + case .userDetails: actionsSubject.send(.userDetails) case let .userStatusEmojiPicker(continuation): actionsSubject.send(.userStatusEmojiPicker(continuation)) + case .addAccount: actionsSubject.send(.addAccount) - case .linkNewDevice: - actionsSubject.send(.linkNewDevice) + case let .manageAccount(url): actionsSubject.send(.manageAccount(url: url)) - case .analytics: - actionsSubject.send(.analytics) - case .appLock: - actionsSubject.send(.appLock) - case .reportBug: - actionsSubject.send(.bugReport) - case .about: - actionsSubject.send(.about) - case .blockedUsers: - actionsSubject.send(.blockedUsers) - case .secureBackup: - actionsSubject.send(.secureBackup) + case .linkNewDevice: + actionsSubject.send(.linkNewDevice) case .notifications: actionsSubject.send(.notifications) - case .advancedSettings: - actionsSubject.send(.advancedSettings) - case .labs: - actionsSubject.send(.labs) - case .developerOptions: - actionsSubject.send(.developerOptions) + case .secureBackup: + actionsSubject.send(.secureBackup) + case .moderationAndSafety: + actionsSubject.send(.moderationAndSafety) + case .reportBug: + actionsSubject.send(.bugReport) + case .logout: actionsSubject.send(.logout) case .deactivateAccount: actionsSubject.send(.deactivateAccount) + + case .mediaUploadQuality: + actionsSubject.send(.mediaUploadQuality) + case .appLock: + actionsSubject.send(.appLock) + case .locationSharing: + actionsSubject.send(.locationSharing) + case .analytics: + actionsSubject.send(.analytics) + case .labs: + actionsSubject.send(.labs) + case .about: + actionsSubject.send(.about) + + case .developerOptions: + actionsSubject.send(.developerOptions) } } .store(in: &cancellables) diff --git a/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenModels.swift b/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenModels.swift index 74085bdf6..915f8f67e 100644 --- a/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenModels.swift +++ b/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenModels.swift @@ -10,23 +10,30 @@ import SwiftUI enum SettingsScreenViewModelAction { case close + case userDetails case userStatusEmojiPicker(EmojiPickerScreenContinuation) + case addAccount - case linkNewDevice + case manageAccount(url: URL) - case analytics - case appLock - case reportBug - case about - case blockedUsers - case secureBackup + case linkNewDevice case notifications - case advancedSettings - case labs - case developerOptions + case secureBackup + case moderationAndSafety + case reportBug + case logout case deactivateAccount + + case mediaUploadQuality + case appLock + case locationSharing + case analytics + case labs + case about + + case developerOptions } enum SettingsScreenSecuritySectionMode { @@ -47,14 +54,13 @@ struct SettingsScreenViewState: BindableState { var securitySectionMode = SettingsScreenSecuritySectionMode.none var showSecuritySectionBadge = false - var showBlockedUsers = false let showAnalyticsSettings: Bool let isBugReportServiceEnabled: Bool let navigationBarVisibility: Visibility - var bindings = SettingsScreenViewStateBindings() + var bindings: SettingsScreenViewStateBindings var userStatusRowMode: SettingsScreenUserStatusRow.Mode { if bindings.isShowingCustomStatusField { @@ -68,6 +74,8 @@ struct SettingsScreenViewState: BindableState { } struct SettingsScreenViewStateBindings { + private let userSettings: UserSettings + var isPresentingStatusPicker = false var customStatusEmoji: Character = "😄" var isShowingCustomStatusField = false { @@ -79,29 +87,45 @@ struct SettingsScreenViewStateBindings { } var isPresentingAccountDeactivationConfirmation = false + + var appAppearance: AppAppearance { + get { userSettings.appAppearance } + set { userSettings.appAppearance = newValue } + } + + init(userSettings: UserSettings) { + self.userSettings = userSettings + } } enum SettingsScreenViewAction { case close + case userDetails case userStatus(UserStatusAction) + case addAccount - case analytics - case appLock - case reportBug - case about - case blockedUsers - case secureBackup - case linkNewDevice + case manageAccount(url: URL) + case linkNewDevice case notifications - case enableDeveloperOptions - case developerOptions - case advancedSettings - case labs + case secureBackup + case moderationAndSafety + case reportBug + case logout case deactivateAccount + case mediaUploadQuality + case appLock + case locationSharing + case analytics + case labs + case about + + case enableDeveloperOptions + case developerOptions + enum UserStatusAction { /// Show status picker sheet to select a preset status. case pickStatus diff --git a/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenViewModel.swift b/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenViewModel.swift index 9634e4bee..345444496 100644 --- a/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenViewModel.swift +++ b/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenViewModel.swift @@ -35,7 +35,8 @@ class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewMo showDeveloperOptions: userSettings.developerOptionsEnabled, showAnalyticsSettings: userSettings.canPromptForAnalytics, isBugReportServiceEnabled: isBugReportServiceEnabled, - navigationBarVisibility: isInSecondaryWindow ? .hidden : .automatic), + navigationBarVisibility: isInSecondaryWindow ? .hidden : .automatic, + bindings: .init(userSettings: userSettings)), mediaProvider: userSession.mediaProvider) userSettings.developerOptionsEnabledPublisher @@ -77,18 +78,6 @@ class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewMo } .store(in: &cancellables) - userSession.clientProxy.ignoredUsersPublisher - .receive(on: DispatchQueue.main) - .map { - guard let blockedUsers = $0 else { - return false - } - - return !blockedUsers.isEmpty - } - .weakAssign(to: \.state.showBlockedUsers, on: self) - .store(in: &cancellables) - Task { if case .success(true) = await userSession.clientProxy.isUserStatusSupported() { state.showUserStatusInput = true @@ -102,6 +91,7 @@ class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewMo switch viewAction { case .close: actionsSubject.send(.close) + case .userDetails: actionsSubject.send(.userDetails) case .userStatus(.pickStatus): @@ -118,38 +108,45 @@ class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewMo case .userStatus(.cancel): state.bindings.isPresentingStatusPicker = false state.bindings.isShowingCustomStatusField = false + case .addAccount: actionsSubject.send(.addAccount) - case .linkNewDevice: - actionsSubject.send(.linkNewDevice) + case let .manageAccount(url): actionsSubject.send(.manageAccount(url: url)) - case .analytics: - actionsSubject.send(.analytics) - case .appLock: - actionsSubject.send(.appLock) - case .reportBug: - actionsSubject.send(.reportBug) - case .about: - actionsSubject.send(.about) - case .blockedUsers: - actionsSubject.send(.blockedUsers) - case .logout: - actionsSubject.send(.logout) - case .secureBackup: - actionsSubject.send(.secureBackup) + case .linkNewDevice: + actionsSubject.send(.linkNewDevice) case .notifications: actionsSubject.send(.notifications) - case .advancedSettings: - actionsSubject.send(.advancedSettings) + case .secureBackup: + actionsSubject.send(.secureBackup) + case .moderationAndSafety: + actionsSubject.send(.moderationAndSafety) + case .reportBug: + actionsSubject.send(.reportBug) + + case .logout: + actionsSubject.send(.logout) + case .deactivateAccount: + actionsSubject.send(.deactivateAccount) + + case .mediaUploadQuality: + actionsSubject.send(.mediaUploadQuality) + case .appLock: + actionsSubject.send(.appLock) + case .locationSharing: + actionsSubject.send(.locationSharing) + case .analytics: + actionsSubject.send(.analytics) case .labs: actionsSubject.send(.labs) + case .about: + actionsSubject.send(.about) + case .enableDeveloperOptions: userSettings.developerOptionsEnabled.toggle() case .developerOptions: actionsSubject.send(.developerOptions) - case .deactivateAccount: - actionsSubject.send(.deactivateAccount) } } diff --git a/ElementX/Sources/Screens/Settings/SettingsScreen/View/SettingsScreen.swift b/ElementX/Sources/Screens/Settings/SettingsScreen/View/SettingsScreen.swift index 31a025ab9..e65e72c26 100644 --- a/ElementX/Sources/Screens/Settings/SettingsScreen/View/SettingsScreen.swift +++ b/ElementX/Sources/Screens/Settings/SettingsScreen/View/SettingsScreen.swift @@ -13,37 +13,19 @@ import SwiftUI struct SettingsScreen: View { @Bindable var context: SettingsScreenViewModel.Context - private var shouldHideManageAccountSection: Bool { - context.viewState.accountProfileURL == nil && - !context.viewState.showBlockedUsers && - !context.viewState.showLinkNewDeviceButton - } - var body: some View { Form { userSection - if context.viewState.showUserStatusInput { - userStatusSection - } - if context.viewState.showAddAccountButton { addAccountSection } - if !shouldHideManageAccountSection { - manageAccountSection - } - - manageMyAppSection - - generalSection + accountSettingsSection signOutSection - if context.viewState.showDeveloperOptions { - developerOptionsSection - } + appSettingsSection } .compoundList() .navigationTitle(L10n.commonSettings) @@ -91,13 +73,11 @@ struct SettingsScreen: View { .padding(.vertical, 8) } }) - } - } - - private var userStatusSection: some View { - Section { - SettingsScreenUserStatusRow(mode: context.viewState.userStatusRowMode) { action in - context.send(viewAction: .userStatus(action)) + + if context.viewState.showUserStatusInput { + SettingsScreenUserStatusRow(mode: context.viewState.userStatusRowMode) { action in + context.send(viewAction: .userStatus(action)) + } } } } @@ -113,36 +93,7 @@ struct SettingsScreen: View { } } - private var manageMyAppSection: some View { - Section { - ListRow(label: .default(title: L10n.screenNotificationSettingsTitle, - icon: \.notifications), - kind: .navigationLink { - context.send(viewAction: .notifications) - }) - .accessibilityIdentifier(A11yIdentifiers.settingsScreen.notifications) - - ListRow(label: .default(title: L10n.commonScreenLock, - icon: \.lock), - kind: .navigationLink { - context.send(viewAction: .appLock) - }) - .accessibilityIdentifier(A11yIdentifiers.settingsScreen.screenLock) - - switch context.viewState.securitySectionMode { - case .secureBackup: - ListRow(label: .default(title: L10n.commonEncryption, - icon: \.key), - details: context.viewState.showSecuritySectionBadge ? .icon(securitySectionBadge) : nil, - kind: .navigationLink { context.send(viewAction: .secureBackup) }) - .accessibilityIdentifier(A11yIdentifiers.settingsScreen.secureBackup) - default: - EmptyView() - } - } - } - - private var manageAccountSection: some View { + private var accountSettingsSection: some View { Section { if let url = context.viewState.accountProfileURL { ListRow(label: .default(title: L10n.actionManageAccountAndDevices, @@ -161,39 +112,30 @@ struct SettingsScreen: View { }) } - if context.viewState.showBlockedUsers { - ListRow(label: .default(title: L10n.commonBlockedUsers, - icon: \.block), - kind: .navigationLink { - context.send(viewAction: .blockedUsers) - }) - .accessibilityIdentifier(A11yIdentifiers.settingsScreen.blockedUsers) + ListRow(label: .default(title: L10n.screenNotificationSettingsTitle, + icon: \.notifications), + kind: .navigationLink { + context.send(viewAction: .notifications) + }) + .accessibilityIdentifier(A11yIdentifiers.settingsScreen.notifications) + + switch context.viewState.securitySectionMode { + case .secureBackup: + ListRow(label: .default(title: L10n.commonEncryption, + icon: \.key), + details: context.viewState.showSecuritySectionBadge ? .icon(securitySectionBadge) : nil, + kind: .navigationLink { context.send(viewAction: .secureBackup) }) + .accessibilityIdentifier(A11yIdentifiers.settingsScreen.secureBackup) + default: + EmptyView() } - } - } - - private var generalSection: some View { - Section { - ListRow(label: .default(title: L10n.commonAdvancedSettings, - icon: \.settings), - kind: .navigationLink { - context.send(viewAction: .advancedSettings) - }) - .accessibilityIdentifier(A11yIdentifiers.settingsScreen.advancedSettings) - ListRow(label: .default(title: L10n.screenAdvancedSettingsLabs, - icon: \.labs), + ListRow(label: .default(title: L10n.commonModerationAndSafety, + icon: \.admin), kind: .navigationLink { - context.send(viewAction: .labs) + context.send(viewAction: .moderationAndSafety) }) - ListRow(label: .default(title: L10n.commonAbout, - icon: \.info), - kind: .navigationLink { - context.send(viewAction: .about) - }) - .accessibilityIdentifier(A11yIdentifiers.settingsScreen.about) - if context.viewState.isBugReportServiceEnabled { ListRow(label: .default(title: L10n.commonReportAProblem, icon: \.chatProblem), @@ -202,15 +144,9 @@ struct SettingsScreen: View { }) .accessibilityIdentifier(A11yIdentifiers.settingsScreen.reportBug) } - - if context.viewState.showAnalyticsSettings { - ListRow(label: .default(title: L10n.commonAnalytics, - icon: \.chart), - kind: .navigationLink { - context.send(viewAction: .analytics) - }) - .accessibilityIdentifier(A11yIdentifiers.settingsScreen.analytics) - } + } header: { + Text(L10n.commonAccountSettings) + .compoundListSectionHeader() } } @@ -232,21 +168,68 @@ struct SettingsScreen: View { context.send(viewAction: .deactivateAccount) }) } - } footer: { - if !context.viewState.showDeveloperOptions { - versionSection - } } } - private var developerOptionsSection: some View { + private var appSettingsSection: some View { Section { - ListRow(label: .default(title: L10n.commonDeveloperOptions, - icon: \.code), + ListRow(label: .default(title: L10n.commonAppearance, + icon: \.darkMode), + kind: .picker(selection: $context.appAppearance, + items: AppAppearance.allCases.map { (title: $0.name, tag: $0) })) + + ListRow(label: .default(title: L10n.commonMediaUploadQuality, + icon: \.image), kind: .navigationLink { - context.send(viewAction: .developerOptions) + context.send(viewAction: .mediaUploadQuality) }) - .accessibilityIdentifier(A11yIdentifiers.settingsScreen.developerOptions) + + ListRow(label: .default(title: L10n.commonScreenLock, + icon: \.lock), + kind: .navigationLink { + context.send(viewAction: .appLock) + }) + .accessibilityIdentifier(A11yIdentifiers.settingsScreen.screenLock) + + ListRow(label: .default(title: L10n.commonLocationSharing, + icon: \.locationPin), + kind: .navigationLink { + context.send(viewAction: .locationSharing) + }) + + if context.viewState.showAnalyticsSettings { + ListRow(label: .default(title: L10n.commonAnalytics, + icon: \.chart), + kind: .navigationLink { + context.send(viewAction: .analytics) + }) + .accessibilityIdentifier(A11yIdentifiers.settingsScreen.analytics) + } + + ListRow(label: .default(title: L10n.screenAdvancedSettingsLabs, + icon: \.labs), + kind: .navigationLink { + context.send(viewAction: .labs) + }) + + ListRow(label: .default(title: L10n.commonAbout, + icon: \.info), + kind: .navigationLink { + context.send(viewAction: .about) + }) + .accessibilityIdentifier(A11yIdentifiers.settingsScreen.about) + + if context.viewState.showDeveloperOptions { + ListRow(label: .default(title: L10n.commonDeveloperOptions, + icon: \.code), + kind: .navigationLink { + context.send(viewAction: .developerOptions) + }) + .accessibilityIdentifier(A11yIdentifiers.settingsScreen.developerOptions) + } + } header: { + Text(L10n.commonAppSettings) + .compoundListSectionHeader() } footer: { versionSection } @@ -291,6 +274,19 @@ struct SettingsScreen: View { } } +private extension AppAppearance { + var name: String { + switch self { + case .system: + L10n.themeSystem + case .light: + L10n.themeLight + case .dark: + L10n.themeDark + } + } +} + // MARK: - Previews @available(iOS 26.0, *) @@ -303,7 +299,7 @@ struct SettingsScreen_Previews: PreviewProvider, TestablePreview { SettingsScreen(context: viewModel.context) } .snapshotPreferences(expect: viewModel.context.observe(\.viewState.accountProfileURL).map { $0 != nil }) - .frame(height: 1200) + .frame(height: 1300) .previewLayout(.sizeThatFits) .previewDisplayName("Default") @@ -311,7 +307,7 @@ struct SettingsScreen_Previews: PreviewProvider, TestablePreview { SettingsScreen(context: bugReportDisabledViewModel.context) } .snapshotPreferences(expect: bugReportDisabledViewModel.context.observe(\.viewState.accountProfileURL).map { $0 != nil }) - .frame(height: 1150) + .frame(height: 1250) .previewLayout(.sizeThatFits) .previewDisplayName("Bug report disabled") } @@ -323,6 +319,7 @@ struct SettingsScreen_Previews: PreviewProvider, TestablePreview { status: .mockFocussing)))) let userSettings = UserSettings.mock() userSettings.multiAccountEnabled = true + userSettings.linkNewDeviceEnabled = true return SettingsScreenViewModel(userSession: userSession, userSettings: userSettings, isBugReportServiceEnabled: isBugReportServiceEnabled, diff --git a/PreviewTests/Sources/GeneratedPreviewTests.swift b/PreviewTests/Sources/GeneratedPreviewTests.swift index 3239295f1..332dff215 100644 --- a/PreviewTests/Sources/GeneratedPreviewTests.swift +++ b/PreviewTests/Sources/GeneratedPreviewTests.swift @@ -18,13 +18,6 @@ extension PreviewTests { } } - @Test - func advancedSettingsScreen() async throws { - for (index, preview) in AdvancedSettingsScreen_Previews._allPreviews.enumerated() { - try await assertSnapshots(matching: preview, step: index) - } - } - @Test func analyticsPromptScreen() async throws { for (index, preview) in AnalyticsPromptScreen_Previews._allPreviews.enumerated() { diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/advancedSettingsScreen.iPad-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/advancedSettingsScreen.iPad-en-GB-0.png deleted file mode 100644 index bb2123b17..000000000 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/advancedSettingsScreen.iPad-en-GB-0.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e8ebdf9faecc3f6a907749856b1626392b83fb4bfd4ea05965fa2e36c53bc21e -size 203603 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/advancedSettingsScreen.iPad-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/advancedSettingsScreen.iPad-pseudo-0.png deleted file mode 100644 index 818ecc084..000000000 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/advancedSettingsScreen.iPad-pseudo-0.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:694ab48bbf3b7d016ee5e6923bbcf984cfc54db145cf9e7bf60360671894ca40 -size 241401 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/advancedSettingsScreen.iPhone-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/advancedSettingsScreen.iPhone-en-GB-0.png deleted file mode 100644 index 23a574596..000000000 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/advancedSettingsScreen.iPhone-en-GB-0.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f12e47794c0e762f3169a2f3f79d72932e4c26aa16f4c6932570adb506b5105e -size 139589 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/advancedSettingsScreen.iPhone-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/advancedSettingsScreen.iPhone-pseudo-0.png deleted file mode 100644 index 0cb923a1a..000000000 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/advancedSettingsScreen.iPhone-pseudo-0.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fd0a047fe7214cfd947d44e59f30af73cea884eeb30199d3c782bc2f7430d32b -size 165304 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Bug-report-disabled-iPad-en-GB.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Bug-report-disabled-iPad-en-GB.png index a15146503..04b067b3f 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Bug-report-disabled-iPad-en-GB.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Bug-report-disabled-iPad-en-GB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9eeed90de894bbf66e72b23a9cfe8b8aa455e8a9ff3f509a227203b2734bd411 -size 208003 +oid sha256:6bac7010123a1a0362bd97ce148379de1be158efff8a4173cbf24bae6db91f8e +size 239301 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Bug-report-disabled-iPad-pseudo.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Bug-report-disabled-iPad-pseudo.png index 256f2a2f0..8ffc7fd4d 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Bug-report-disabled-iPad-pseudo.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Bug-report-disabled-iPad-pseudo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:daa1d62daa786fa52e35f9f9924b969a627649037cf64e6949b692de837f3f89 -size 218666 +oid sha256:15740810913e01029cc6aa4b2529601d34a3469e834c45d6070122b0eeef7a67 +size 255708 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Bug-report-disabled-iPhone-en-GB.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Bug-report-disabled-iPhone-en-GB.png index 53e7066ec..d27bc99b1 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Bug-report-disabled-iPhone-en-GB.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Bug-report-disabled-iPhone-en-GB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:02ddd70542f4e8963f1745ee9f65e6f42e864bad5a28dffe052de35ac2ead3aa -size 132702 +oid sha256:487b3d2c1c331d620ba5b25392f5e634fddd3066739a8f49781c018851f3721a +size 158210 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Bug-report-disabled-iPhone-pseudo.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Bug-report-disabled-iPhone-pseudo.png index c12942184..356c094c6 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Bug-report-disabled-iPhone-pseudo.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Bug-report-disabled-iPhone-pseudo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ef1a98de9b2ddfb490882c5a937d2d7159a0a0ab513f41a8e1a1b1b3c95d5323 -size 148131 +oid sha256:06720e67dd18586e9fad302dc8bb2f130785ed17867d98cfbe16b428186be812 +size 179850 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Default-iPad-en-GB.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Default-iPad-en-GB.png index e3bbe45a8..876c0caeb 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Default-iPad-en-GB.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Default-iPad-en-GB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:56417caadb44c989b9ca9032d8eb6b13e5d02cead1537eb04a2ea262c8a3ea00 -size 218308 +oid sha256:483cb6201103f76f2f102442e16be41c3a6cea8fe66d1b80bb1c111609a6c9fd +size 249597 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Default-iPad-pseudo.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Default-iPad-pseudo.png index 261e22ee4..abe2b32bd 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Default-iPad-pseudo.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Default-iPad-pseudo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:450405a9646962d1889af363b6da096a651d3d40dcb9a0212cafb7c1a2695f7d -size 230377 +oid sha256:b39b2a748e16f9da207f2b732afccd521baa926e452c90ec2291d8ede6ad1679 +size 267272 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Default-iPhone-en-GB.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Default-iPhone-en-GB.png index c20a39d8a..72163ab10 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Default-iPhone-en-GB.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Default-iPhone-en-GB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a3dcc827b87f5b49344477648239fa7bb46c1101324fab00ac8690943369fcf6 -size 140339 +oid sha256:7a06ade1aacefd2c027fd317857ce1a55ce96e7c0a264b87c0cb4352fc6b21d2 +size 165653 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Default-iPhone-pseudo.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Default-iPhone-pseudo.png index db90fff62..3b2fb9252 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Default-iPhone-pseudo.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/settingsScreen.Default-iPhone-pseudo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:91c5820e827e06ff4c2ab55c5ff86425fe0634172e3cfc2134574a6c955fb89e -size 158619 +oid sha256:926584ed061ee942d65d348016ee15775dbf01b91ec8a8408333e48ae16a26c4 +size 189795