@@ -27,59 +27,54 @@ struct SettingsView: View {
2727 // MARK: View
2828
2929 var body : some View {
30- settingsItems
31- . scrollView ( )
32- . navigationBar ( title: Localizations . settings, titleDisplayMode: titleDisplayMode)
33- . toast ( store. binding (
34- get: \. toast,
35- send: SettingsAction . toastShown,
36- ) )
37- . onChange ( of: store. state. url) { newValue in
38- guard let url = newValue else { return }
39- openURL ( url)
40- store. send ( . clearURL)
41- }
42- . task {
43- await store. perform ( . loadData)
44- }
30+ VStack ( spacing: 16 ) {
31+ securitySection
32+ dataSection
33+ appearanceSection
34+ helpSection
35+ aboutSection
36+ copyrightNotice
37+ }
38+ . scrollView ( )
39+ . navigationBar ( title: Localizations . settings, titleDisplayMode: titleDisplayMode)
40+ . toast ( store. binding (
41+ get: \. toast,
42+ send: SettingsAction . toastShown,
43+ ) )
44+ . onChange ( of: store. state. url) { newValue in
45+ guard let url = newValue else { return }
46+ openURL ( url)
47+ store. send ( . clearURL)
48+ }
49+ . task {
50+ await store. perform ( . loadData)
51+ }
4552 }
4653
4754 // MARK: Private views
4855
49- /// A view for the user's biometrics setting
50- ///
51- @ViewBuilder private var biometricsSetting : some View {
52- switch store. state. biometricUnlockStatus {
53- case let . available( type, enabled: enabled, _) :
54- SectionView ( Localizations . security) {
55- VStack ( spacing: 8 ) {
56- biometricUnlockToggle ( enabled: enabled, type: type)
57- SettingsMenuField (
58- title: Localizations . sessionTimeout,
59- options: SessionTimeoutValue . allCases,
60- hasDivider: false ,
61- accessibilityIdentifier: " VaultTimeoutChooser " ,
62- selectionAccessibilityID: " SessionTimeoutStatusLabel " ,
63- selection: store. bindingAsync (
64- get: \. sessionTimeoutValue,
65- perform: SettingsEffect . sessionTimeoutValueChanged,
66- ) ,
67- )
68- . clipShape ( RoundedRectangle ( cornerRadius: 10 ) )
56+ /// The about section containing privacy policy and version information.
57+ @ViewBuilder private var aboutSection : some View {
58+ SectionView ( Localizations . about) {
59+ ContentBlock ( dividerLeadingPadding: 16 ) {
60+ externalLinkRow ( Localizations . privacyPolicy, action: . privacyPolicyTapped)
61+
62+ SettingsListItem ( store. state. version) {
63+ store. send ( . versionTapped)
64+ } trailingContent: {
65+ SharedAsset . Icons. copy24. swiftUIImage
66+ . imageStyle ( . rowIcon)
6967 }
7068 }
71- . padding ( . bottom, 32 )
72- default :
73- EmptyView ( )
7469 }
7570 }
7671
77- /// The chevron shown in the settings list item .
78- private var chevron : some View {
79- Image ( asset : SharedAsset . Icons . chevronRight16 )
80- . resizable ( )
81- . scaledFrame ( width : 12 , height : 12 )
82- . foregroundColor ( Color ( asset : Asset . Colors . textSecondary ) )
72+ /// The appearance section containing language and theme settings .
73+ @ ViewBuilder private var appearanceSection : some View {
74+ SectionView ( Localizations . appearance , contentSpacing : 8 ) {
75+ language
76+ theme
77+ }
8378 }
8479
8580 /// The copyright notice.
@@ -91,31 +86,9 @@ struct SettingsView: View {
9186 . frame ( maxWidth: . infinity)
9287 }
9388
94- /// The language picker view
95- private var language : some View {
96- Button {
97- store. send ( . languageTapped)
98- } label: {
99- BitwardenField (
100- title: Localizations . language,
101- footer: Localizations . languageChangeRequiresAppRestart,
102- ) {
103- Text ( store. state. currentLanguage. title)
104- . styleGuide ( . body)
105- . foregroundColor ( Color ( asset: SharedAsset . Colors. textPrimary) )
106- . multilineTextAlignment ( . leading)
107- } accessoryContent: {
108- SharedAsset . Icons. chevronDown24. swiftUIImage
109- . imageStyle ( . rowIcon)
110- }
111- }
112- }
113-
114- /// The settings items.
115- private var settingsItems : some View {
116- VStack ( spacing: 0 ) {
117- biometricsSetting
118-
89+ /// The data section containing import, export, backup, and sync options.
90+ @ViewBuilder private var dataSection : some View {
91+ SectionView ( Localizations . data) {
11992 ContentBlock ( dividerLeadingPadding: 16 ) {
12093 SettingsListItem ( Localizations . import) {
12194 store. send ( . importItemsTapped)
@@ -135,46 +108,47 @@ struct SettingsView: View {
135108 defaultSaveOption
136109 }
137110 }
138- . padding ( . bottom, 32 )
139-
140- SectionView ( Localizations . appearance) {
141- language
142- theme
143- }
144- . padding ( . bottom, 32 )
111+ }
112+ }
145113
114+ /// The help section containing tutorial and help center links.
115+ @ViewBuilder private var helpSection : some View {
116+ SectionView ( Localizations . help) {
146117 ContentBlock ( dividerLeadingPadding: 16 ) {
147118 SettingsListItem ( Localizations . launchTutorial) {
148119 store. send ( . tutorialTapped)
149120 }
150121
151122 externalLinkRow ( Localizations . bitwardenHelpCenter, action: . helpCenterTapped)
152123 }
153- . padding ( . bottom, 32 )
154-
155- ContentBlock ( dividerLeadingPadding: 16 ) {
156- externalLinkRow ( Localizations . privacyPolicy, action: . privacyPolicyTapped)
124+ }
125+ }
157126
158- SettingsListItem ( store. state. version) {
159- store. send ( . versionTapped)
160- } trailingContent: {
161- SharedAsset . Icons. copy24. swiftUIImage
162- . imageStyle ( . rowIcon)
163- }
127+ /// The language picker view.
128+ private var language : some View {
129+ Button {
130+ store. send ( . languageTapped)
131+ } label: {
132+ BitwardenField (
133+ title: Localizations . language,
134+ footer: Localizations . languageChangeRequiresAppRestart,
135+ ) {
136+ Text ( store. state. currentLanguage. title)
137+ . styleGuide ( . body)
138+ . foregroundColor ( Color ( asset: SharedAsset . Colors. textPrimary) )
139+ . multilineTextAlignment ( . leading)
140+ } accessoryContent: {
141+ SharedAsset . Icons. chevronDown24. swiftUIImage
142+ . imageStyle ( . rowIcon)
164143 }
165- . padding ( . bottom, 16 )
166-
167- copyrightNotice
168144 }
169- . cornerRadius ( 10 )
170145 }
171146
172- /// The application's default save option picker view
147+ /// The application's default save option picker view.
173148 @ViewBuilder private var defaultSaveOption : some View {
174- SettingsMenuField (
149+ BitwardenMenuField (
175150 title: Localizations . defaultSaveOption,
176151 options: DefaultSaveOption . allCases,
177- hasDivider: false ,
178152 selection: store. binding (
179153 get: \. defaultSaveOption,
180154 send: SettingsAction . defaultSaveChanged,
@@ -183,7 +157,31 @@ struct SettingsView: View {
183157 . accessibilityIdentifier ( " DefaultSaveOptionChooser " )
184158 }
185159
186- /// The application's color theme picker view
160+ /// The security section containing biometric unlock and session timeout settings.
161+ @ViewBuilder private var securitySection : some View {
162+ switch store. state. biometricUnlockStatus {
163+ case let . available( type, enabled: enabled, _) :
164+ SectionView ( Localizations . security) {
165+ ContentBlock {
166+ biometricUnlockToggle ( enabled: enabled, type: type)
167+
168+ BitwardenMenuField (
169+ title: Localizations . sessionTimeout,
170+ accessibilityIdentifier: " VaultTimeoutChooser " ,
171+ options: SessionTimeoutValue . allCases,
172+ selection: store. bindingAsync (
173+ get: \. sessionTimeoutValue,
174+ perform: SettingsEffect . sessionTimeoutValueChanged,
175+ ) ,
176+ )
177+ }
178+ }
179+ default :
180+ EmptyView ( )
181+ }
182+ }
183+
184+ /// The application's color theme picker view.
187185 private var theme : some View {
188186 BitwardenMenuField (
189187 title: Localizations . theme,
@@ -202,16 +200,15 @@ struct SettingsView: View {
202200 @ViewBuilder
203201 private func biometricUnlockToggle( enabled: Bool , type: BiometricAuthenticationType ) -> some View {
204202 let toggleText = biometricsToggleText ( type)
205- Toggle ( isOn : store . bindingAsync (
206- get : { _ in enabled } ,
207- perform : SettingsEffect . toggleUnlockWithBiometrics ,
208- ) ) {
209- Text ( toggleText )
210- }
211- . padding ( . trailing , 3 )
203+ BitwardenToggle (
204+ toggleText ,
205+ isOn : store . bindingAsync (
206+ get : { _ in enabled } ,
207+ perform : SettingsEffect . toggleUnlockWithBiometrics ,
208+ ) ,
209+ )
212210 . accessibilityIdentifier ( " UnlockWithBiometricsSwitch " )
213211 . accessibilityLabel ( toggleText)
214- . toggleStyle ( . bitwarden)
215212 }
216213
217214 private func biometricsToggleText( _ biometryType: BiometricAuthenticationType ) -> String {
0 commit comments