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

Version 1.1.0 #26

Merged
merged 18 commits into from
Aug 16, 2024
Merged
18 changes: 18 additions & 0 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,24 @@
"revision" : "b4f23e24b5a1bff301efc5e70871083ca029ff95",
"version" : "0.2.0"
}
},
{
"identity" : "futured-macros",
"kind" : "remoteSourceControl",
"location" : "https://github.com/futuredapp/futured-macros",
"state" : {
"branch" : "main",
"revision" : "e2d832df517e1dd00be6c45a1560b349ca9d337f"
}
},
{
"identity" : "swift-syntax",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "64889f0c732f210a935a0ad7cda38f77f876262d",
"version" : "509.1.1"
}
}
],
"version" : 2
Expand Down
11 changes: 8 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// swift-tools-version:5.7.1
// swift-tools-version:5.9

import PackageDescription
import CompilerPluginSupport

let package = Package(
name: "FuturedKit",
Expand All @@ -22,11 +23,15 @@ let package = Package(
],
dependencies: [
.package(url: "https://github.com/mkj-is/BindingKit", from: "1.0.0"),
.package(url: "https://github.com/JohnSundell/CollectionConcurrencyKit", from: "0.1.0")
.package(url: "https://github.com/JohnSundell/CollectionConcurrencyKit", from: "0.1.0"),
.package(url: "https://github.com/futuredapp/futured-macros", branch: "main")
],
targets: [
.target(
name: "FuturedArchitecture"
name: "FuturedArchitecture",
dependencies: [
.product(name: "FuturedMacros", package: "futured-macros")
]
),
.target(
name: "FuturedHelpers",
Expand Down
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ SwiftUI state management tools, resources and views used by Futured.
- ``CameraImagePicker``
- ``GalleryImagePicker``

### Alert presentation

- ``AlertModel``

## Installation

When using Swift package manager install using or add following line to your dependencies:
Expand Down
53 changes: 20 additions & 33 deletions Sources/FuturedArchitecture/Architecture/Coordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,56 +5,43 @@ public protocol Coordinator: ObservableObject {
associatedtype RootView: View
associatedtype DestinationViews: View

/// `rootView` returns the coordinator's main view. Maintain its purity by defining only the view, without added logic or modifiers.
/// If logic or modifiers are needed, encapsulate them in a separate view that can accommodate necessary dependencies.
/// Skipping this recommendation may prevent UI updates when changing `@Published` properties, as `rootView` is static.
@ViewBuilder
static func rootView(with instance: Self) -> RootView

var sheet: Destination? { get set }
#if !os(macOS)
var fullscreenCover: Destination? { get set }
#endif
var alertModel: AlertModel? { get set }
var modalCover: ModalCoverModel<Destination>? { get set }

@ViewBuilder
func scene(for destination: Destination) -> DestinationViews
func onSheetDismiss()
#if !os(macOS)
func onFullscreenCoverDismiss()
#endif
func onModalDismiss()
}

public extension Coordinator {
func present(sheet: Destination) {
Task { @MainActor in
self.sheet = sheet
}
}

func dismissSheet() {
Task { @MainActor in
self.sheet = nil
}
}

func onSheetDismiss() {}
}

#if !os(macOS)
public extension Coordinator {
func present(fullscreenCover: Destination) {
Task { @MainActor in
self.fullscreenCover = fullscreenCover
func present(modal destination: Destination, type: ModalCoverModel<Destination>.Style) {
switch type {
case .sheet:
Task { @MainActor in
self.modalCover = .init(destination: destination, style: .sheet)
}
#if !os(macOS)
case .fullscreenCover:
Task { @MainActor in
self.modalCover = .init(destination: destination, style: .fullscreenCover)
}
#endif
}
}

func dismissFullscreenCover() {
func dismissModal() {
Task { @MainActor in
self.fullscreenCover = nil
self.modalCover = nil
}
}

func onFullscreenCoverDismiss() {}
func onModalDismiss() {}
}
#endif

public protocol TabCoordinator: Coordinator {
associatedtype Tab: Hashable
Expand Down
24 changes: 24 additions & 0 deletions Sources/FuturedArchitecture/Architecture/ModalCoverModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// ModalCoverModel.swift
//
//
// Created by Simon Sestak on 01/08/2024.
//

import Foundation

public struct ModalCoverModel<Destination: Hashable & Identifiable>: Identifiable {
let destination: Destination
let style: Style

public enum Style {
case sheet
#if !os(macOS)
case fullscreenCover
#endif
}

public var id: Destination.ID {
destination.id
}
}
26 changes: 21 additions & 5 deletions Sources/FuturedArchitecture/Architecture/NavigationStackFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,33 @@ public struct NavigationStackFlow<Coordinator: NavigationStackCoordinator, Conte
NavigationStack(path: $coordinator.path) {
content().navigationDestination(for: Coordinator.Destination.self, destination: coordinator.scene(for:))
}
.sheet(item: $coordinator.sheet, onDismiss: coordinator.onSheetDismiss, content: coordinator.scene(for:))
.defaultAlert(model: $coordinator.alertModel)
.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:))
}
.sheet(item: $coordinator.sheet, onDismiss: coordinator.onSheetDismiss, content: coordinator.scene(for:))
.fullScreenCover(item: $coordinator.fullscreenCover, onDismiss: coordinator.onFullscreenCoverDismiss, content: coordinator.scene(for:))
.defaultAlert(model: $coordinator.alertModel)
.sheet(item: sheetBinding, onDismiss: coordinator.onModalDismiss, content: coordinator.scene(for:))
.fullScreenCover(item: fullscreenCoverBinding, onDismiss: coordinator.onModalDismiss, content: coordinator.scene(for:))
}
#endif

private var sheetBinding: Binding<Coordinator.Destination?> {
.init {
coordinator.modalCover?.style == .sheet ? coordinator.modalCover?.destination : nil
} set: { destination in
coordinator.modalCover = destination.map { .init(destination: $0, style: .sheet) }
}
}

#if !os(macOS)
private var fullscreenCoverBinding: Binding<Coordinator.Destination?> {
.init {
coordinator.modalCover?.style == .fullscreenCover ? coordinator.modalCover?.destination : nil
} set: { destination in
coordinator.modalCover = destination.map { .init(destination: $0, style: .fullscreenCover) }
}
}
#endif
}
26 changes: 21 additions & 5 deletions Sources/FuturedArchitecture/Architecture/TabViewFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,33 @@ public struct TabViewFlow<Coordinator: TabCoordinator, Content: View>: View {
TabView(selection: $coordinator.selectedTab) {
content()
}
.sheet(item: $coordinator.sheet, onDismiss: coordinator.onSheetDismiss, content: coordinator.scene(for:))
.defaultAlert(model: $coordinator.alertModel)
.sheet(item: sheetBinding, onDismiss: coordinator.onModalDismiss, content: coordinator.scene(for:))
}
#else
public var body: some View {
TabView(selection: $coordinator.selectedTab) {
content()
}
.sheet(item: $coordinator.sheet, onDismiss: coordinator.onSheetDismiss, content: coordinator.scene(for:))
.fullScreenCover(item: $coordinator.fullscreenCover, onDismiss: coordinator.onFullscreenCoverDismiss, content: coordinator.scene(for:))
.defaultAlert(model: $coordinator.alertModel)
.sheet(item: sheetBinding, onDismiss: coordinator.onModalDismiss, content: coordinator.scene(for:))
.fullScreenCover(item: fullscreenCoverBinding, onDismiss: coordinator.onModalDismiss, content: coordinator.scene(for:))
}
#endif

private var sheetBinding: Binding<Coordinator.Destination?> {
.init {
coordinator.modalCover?.style == .sheet ? coordinator.modalCover?.destination : nil
} set: { destination in
coordinator.modalCover = destination.map { .init(destination: $0, style: .sheet) }
}
}

#if !os(macOS)
private var fullscreenCoverBinding: Binding<Coordinator.Destination?> {
.init {
coordinator.modalCover?.style == .fullscreenCover ? coordinator.modalCover?.destination : nil
} set: { destination in
coordinator.modalCover = destination.map { .init(destination: $0, style: .fullscreenCover) }
}
}
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,3 @@ SwiftUI architecture, resources and views used by Futured.
- ``WrappedUIImagePicker``
- ``CameraImagePicker``
- ``GalleryImagePicker``

### Alert presentation

- ``AlertModel``
Loading
Loading