.editMode

/// host both a static, summary view of profile information
/// and an edit mode.
struct ProfileHost: View {
    
    /// ⭐️ 1. copy data
    /// To avoid updating the global app state before confirming any edits,
    /// the editing view operates on a **copy** of the user's profile.
    @State private var draftProfile = Profile.default
    
    /// ⭐️ 2. access edit mode:
    /// an `@Environment` view property that keys off of the environment’s `\.editMode`.
    /// - key off: to take something as a controlling input datum. (意思跟「控制...」差不多)
    /// See [FreeDictionary][1]
    ///
    /// SwiftUI provides storage in the environment for values you can access
    /// using the `@Environment` property wrapper. Access the `editMode` value
    /// to read or write the edit scope.
    ///
    /// [1]: https://idioms.thefreedictionary.com/key+off
    @Environment(\.editMode) var editMode
    
    /// ⭐️ global app state
    /// Read the user’s profile data from the environment
    /// to pass control of the data to the profile host.
    @EnvironmentObject var modelData: ModelData
    
    var body: some View {
        VStack(alignment: .leading, spacing: 20) {
            
            HStack {
                
                /// ⭐️ 3. cancel button
                if editMode?.wrappedValue == .active {
                    Button("Cancel", role: .cancel) {
                        draftProfile = modelData.profile
                        editMode?.animation().wrappedValue = .inactive
                    }
                }
                
                Spacer()
                
                /// ⭐️ 4. edit button
                /// button that toggles the environment’s `editMode` value on and off.
                EditButton()
            }
            
            /// ⭐️ 5. normal/editor view
            /// displays either the static profile or
            /// the view for Edit mode.
            if editMode?.wrappedValue == .inactive {
                ProfileSummary(profile: modelData.profile)
            } else {
                ProfileEditor(profile: $draftProfile)
                    /// ⭐️ 6. a draft copy of real data
                    .onAppear { draftProfile = modelData.profile }
                    /// ⭐️ 7. write draft data back to real data
                    .onDisappear { modelData.profile = draftProfile }
            }
        }
        .padding()
    }
}

Last updated