diff --git a/App/Sources/View Modifiers/NewTaskButtonModifier.swift b/App/Sources/View Modifiers/NewTaskButtonModifier.swift new file mode 100644 index 0000000..2722de8 --- /dev/null +++ b/App/Sources/View Modifiers/NewTaskButtonModifier.swift @@ -0,0 +1,98 @@ +import SwiftUI + +/// A view modifier that adds a floating action button for creating new tasks. +/// +/// This modifier overlays a glass-effect button in the bottom-trailing corner of the view. +/// The button can be conditionally shown or hidden with smooth animations. +struct NewTaskButtonModifier: ViewModifier { + + // MARK: Properties + + /// Whether the floating button should be displayed. + let showButton: Bool + + /// The action to perform when the button is tapped. + let action: () -> Void + + // MARK: Functions + + /// Applies the floating action button to the content view. + /// + /// When `showButton` is true, overlays a blue glass-effect button with a plus icon + /// in the bottom-trailing corner. The button animates in/out with opacity and scale transitions, + /// and includes a spring animation when pressed. + /// + /// - Parameter content: The view to which the button will be added. + /// - Returns: The modified view with the floating button overlay. + func body(content: Content) -> some View { + ZStack(alignment: .bottomTrailing) { + content + + if showButton { + Button(action: action) { + Image(systemName: "plus") + .frame(width: 48, height: 48) + .foregroundStyle(.white) + } + .glassEffect(.regular.tint(.blue.opacity(0.8)).interactive()) + .padding(.trailing, 20) + } + } + .animation( + .spring(response: 0.4, dampingFraction: 0.8), + value: showButton + ) + } + +} + +// MARK: - View Extension + +extension View { + + /// Adds a floating action button for creating new tasks. + /// + /// This convenience method applies the ``NewTaskButtonModifier`` to show a glass-effect + /// button in the bottom-trailing corner of the view. + /// + /// - Parameters: + /// - show: Whether the floating button should be displayed. + /// - action: The action to perform when the button is tapped. + /// - Returns: The modified view with the floating button overlay. + func newTaskButton( + show: Bool, + action: @escaping () -> Void + ) -> some View { + modifier( + NewTaskButtonModifier( + showButton: show, + action: action + ) + ) + } + +} +// MARK: - Previews + +#Preview("New Task Button") { + @Previewable + @State + var showButton = true + + VStack { + Spacer() + Toggle( + "Show Button", + isOn: $showButton + ) + Spacer() + } + .padding(.horizontal) + .frame( + maxWidth: .infinity, + maxHeight: .infinity + ) + .newTaskButton(show: showButton) { + // On action closure. + } +}