// // Alert.swift // MacBackend // // Created by david-swift on 01.12.2024. // import SwiftUI /// The alert view. public struct Alert: SwiftUIWidget { /// The alert's title. var title: String /// The alert's description. var description: String /// Whether the alert is presented. var isPresented: Meta.Binding /// The alert's actions. var actions: [Action] = [] /// The wrapped view. var child: Meta.AnyView /// The wrapped views. public var wrappedViews: [String: Meta.AnyView] { [.mainContent: child] } /// Initialize the alert. /// - Parameters: /// - title: The alert's title. /// - description: The alert's description. /// - isPresented: Whether the alert is presented. /// - child: The wrapped view. public init(title: String, description: String, isPresented: Meta.Binding, child: Meta.AnyView) { self.title = title self.description = description self.isPresented = isPresented self.child = child } /// An alert action. enum Action { /// A regular button. case button(button: Button) /// A cancel button. case cancel(button: Button) /// A destructive button. case destructive(button: Button) /// Get the SwiftUI button. @SwiftUI.ViewBuilder var button: some SwiftUI.View { switch self { case let .button(button): button.button() case let .cancel(button): button.button(cancel: true) case let .destructive(button): button.button(destructive: true) } } } /// The button. struct Button { /// The button's label. var label: String /// The button's action. var action: () -> Void /// Whether it is the default action. var defaultAction: Bool /// Get the SwiftUI button. /// - Parameters: /// - cancel: Whether it is the cancel action. /// - destructive: Whether it is a destructive action. /// - Returns: The SwiftUI view. @SwiftUI.ViewBuilder func button(cancel: Bool = false, destructive: Bool = false) -> some SwiftUI.View { let button = SwiftUI.Button( label, role: cancel ? .cancel : (destructive ? .destructive : nil), action: action ) if defaultAction { button .keyboardShortcut(.defaultAction) } else { button } } } /// Get the SwiftUI view. /// - Parameter properties: The widget data. /// - Returns: The SwiftUI view. public static func view(properties: Self) -> some SwiftUI.View { MacBackendView(.mainContent) .alert(properties.title, isPresented: properties.isPresented.swiftUI) { SwiftUI.ForEach(Array(properties.actions.enumerated()), id: \.offset) { action in action.element.button } } message: { SwiftUI.Text(properties.description) } } /// Add a button to the alert. /// - Parameters: /// - label: The button's label. /// - defaultAction: Whether it is a default action. /// - action: The handler. /// - Returns: The alert. public func button( _ label: String, default defaultAction: Bool = false, action: @escaping () -> Void ) -> Self { modify { alert in alert.actions.append(.button(button: .init(label: label, action: action, defaultAction: defaultAction))) } } /// Add a cancel button to the alert. /// - Parameters: /// - label: The button's label. /// - defaultAction: Whether it is a default action. /// - action: The handler. /// - Returns: The alert. public func cancelButton( _ label: String, default defaultAction: Bool = false, action: @escaping () -> Void ) -> Self { modify { alert in alert.actions.append(.cancel(button: .init(label: label, action: action, defaultAction: defaultAction))) } } /// Add a destructive button to the alert. /// - Parameters: /// - label: The button's label. /// - defaultAction: Whether it is a default action. /// - action: The handler. /// - Returns: The alert. public func destructiveButton( _ label: String, default defaultAction: Bool = false, action: @escaping () -> Void ) -> Self { modify { alert in alert.actions .append(.destructive(button: .init(label: label, action: action, defaultAction: defaultAction))) } } }