Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modal navigation stack presentation detents #38

Merged
merged 6 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions Sources/FuturedArchitecture/Architecture/ModalCoverModel.swift
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
//
// ModalCoverModel.swift
//
//
//
// Created by Simon Sestak on 01/08/2024.
//

import SwiftUI
import Foundation

/// Style of the modally presented view.

public enum SheetDetent: Hashable {
case medium
case large
case fraction(CGFloat)

func detent() -> PresentationDetent {
switch self {
case .medium:
return .medium
case .large:
return .large
case let .fraction(fraction):
return .fraction(fraction)
}
}
}

/// Style of the modally presented view.
///
/// It is intended to be used with ``ModalCoverModel``. Style has been placed to
/// the global scope, since the Model is generic.
Expand Down
23 changes: 13 additions & 10 deletions Sources/FuturedArchitecture/Architecture/NavigationStackFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,34 @@ public struct NavigationStackFlow<Coordinator: NavigationStackCoordinator, Conte
@StateObject private var coordinator: Coordinator
@ViewBuilder private let content: () -> Content

/// Use in case when whole navigation stack should have detents.
@State private var navigationDetents: Set<PresentationDetent>?

/// - Parameters:
/// - detents: The set of detents which should be applied to the whole navigation stack.
/// - coordinator: The instance of the coordinator used as the model and retained as the ``SwiftUI.StateObject``
/// - content: The root view of this navigation stack. The ``navigationDestination(for:destination:)`` modifier
/// is applied to this content.
public init(coordinator: @autoclosure @escaping () -> Coordinator, content: @MainActor @escaping () -> Content) {
public init(
detents: Set<SheetDetent>? = nil,
coordinator: @autoclosure @escaping () -> Coordinator,
content: @MainActor @escaping () -> Content
) {
self.navigationDetents = detents == nil ? nil : Set(detents!.map { $0.detent() })
self._coordinator = StateObject(wrappedValue: coordinator())
self.content = content
}

#if os(macOS)
public var body: some View {
NavigationStack(path: $coordinator.path) {
content().navigationDestination(for: Coordinator.Destination.self, destination: coordinator.scene(for:))
}
.sheet(item: sheetBinding, onDismiss: coordinator.onModalDismiss, content: coordinator.scene(for:))
}
#else
public var body: some View {
NavigationStack(path: $coordinator.path) {
content().navigationDestination(for: Coordinator.Destination.self, destination: coordinator.scene(for:))
}
.presentationDetents(navigationDetents ?? [])
.sheet(item: sheetBinding, onDismiss: coordinator.onModalDismiss, content: coordinator.scene(for:))
#if !os(macOS)
.fullScreenCover(item: fullscreenCoverBinding, onDismiss: coordinator.onModalDismiss, content: coordinator.scene(for:))
#endif
}
#endif

private var sheetBinding: Binding<Coordinator.Destination?> {
.init {
Expand Down