Reverting @AppStorage when dismissing a preference view via cancel

47 Views Asked by At

Consider the following PreferencesView presented as a sheet:

struct PreferencesView: View {
    @Environment(\.dismiss) private var dismiss

    @AppStorage("setting1") var setting1: Bool = true
    @AppStorage("setting2") var setting2: Bool = false
    @AppStorage("setting3") var setting3: Bool = false
    // many more

    var body: some View {
        NavigationView {
            Form {
                Toggle("Setting 1", isOn: $setting1)
                Toggle("Setting 2", isOn: $setting2)
                Toggle("Setting 3", isOn: $setting3)
            }
            .navigationTitle("Preferences")
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button("Cancel") {
                        reset()

                        dismiss()
                    }
                }
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button("Save") {
                        dismiss()
                    }
                }
            }
        }
    }

    private func reset() {
        // what do I put here?
    }
}

If the user hits cancel, I'd like the value of the settings be set back to when the sheet opened. I could add separate initialSetting1, etc properties, and then in the reset function add setting1 = initialSetting1. But with a lot of settings that becomes tedious.

Is there another way?

1

There are 1 best solutions below

1
timbre timbre On BEST ANSWER
  • Load current settings using onAppear
  • Use local @State to bind to a toggle
  • Save current values from @State to settings when user presses Save button.

Like this:

struct PreferencesView: View {
    @Environment(\.dismiss) private var dismiss

    @AppStorage("setting1") var setting1: Bool = true
    @AppStorage("setting2") var setting2: Bool = false
    @AppStorage("setting3") var setting3: Bool = false
    
    // Initial value doesn't matter, will be overwritten
    @State var currentSetting1: Bool = false
    @State var currentSetting2: Bool = false
    @State var currentSetting3: Bool = false
    // many more

    var body: some View {
        NavigationView {
            Form {
                // Change internal state, not settings
                Toggle("Setting 1", isOn: $currentSetting1)
                Toggle("Setting 2", isOn: $currentSetting2)
                Toggle("Setting 3", isOn: $currentSetting3)
            }
            .navigationTitle("Preferences")
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button("Cancel") {
                        // No need to do anything here
                        dismiss()
                    }
                }
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button("Save") {
                        // Save current internal state to settings
                        setting1 = currentSetting1
                        setting2 = currentSetting2
                        setting3 = currentSetting3
                        dismiss()
                    }
                }
            }
            .onAppear() {
                // Load settings
                currentSetting1 = setting1
                currentSetting2 = setting2
                currentSetting3 = setting3
            }
        }
    }
}