Skip to content
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
8 changes: 8 additions & 0 deletions .swiftformat
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
--swiftversion 6.1
--exclude Templates,.build
--header ignore
--extensionacl on-declarations
--trailingcommas never
--decimalgrouping 3,4
--modifierorder isolated,nonisolated,private,fileprivate,internal,package,public,open,private(set),fileprivate(set),internal(set),package(set),public(set),final,convenience
--disable swiftTestingTestCaseNames,redundantSendable,wrapMultilineStatementBraces
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ private struct AlertModifier: ViewModifier {
@Binding var model: AlertModel?

init(_ model: Binding<AlertModel?>) {
self._model = model
_model = model
}

func body(content: Content) -> some View {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import Foundation
/// compile but SwiftUI views will not react to state changes.
@MainActor
public protocol ComponentModel: AnyObject {

/// Type used to pass events to the *coordinator*. `enum` is used in most cases, but not required.
associatedtype Event

Expand Down
16 changes: 8 additions & 8 deletions Sources/FuturedArchitecture/Architecture/Coordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,17 @@ extension Coordinator {
public func present(modal destination: Destination, type: ModalCoverModelStyle) {
switch type {
case .sheet:
self.modalCover = .init(destination: destination, style: .sheet)
modalCover = .init(destination: destination, style: .sheet)
#if !os(macOS)
case .fullscreenCover:
self.modalCover = .init(destination: destination, style: .fullscreenCover)
case .fullscreenCover:
modalCover = .init(destination: destination, style: .fullscreenCover)
#endif
}
}

/// Convenience method for dismissing a modal.
public func dismissModal() {
self.modalCover = nil
modalCover = nil
}

public func onModalDismiss() {}
Expand Down Expand Up @@ -88,24 +88,24 @@ public protocol NavigationStackCoordinator: Coordinator {
extension NavigationStackCoordinator {
/// Convenience function used to add new view to the navigation stack.
public func navigate(to destination: Destination) {
self.path.append(destination)
path.append(destination)
}

/// Convenience function used to remove topmost view from the navigation stack.
public func pop() {
self.path.removeLast()
path.removeLast()
}

/// Convenience function used to remove all views from the stack, until the provided destination.
/// - Parameter destination: Destination to be reached. If nil is passed, or such destination
/// is not currently on the stack, all views are removed.
/// - Experiment: This API is in preview and subject to change.
public func pop(to destination: Destination) {
guard let index = self.path.lastIndex(of: destination) else {
guard let index = path.lastIndex(of: destination) else {
assertionFailure("Destination not found on the stack")
return
}
self.path = Array(path[path.startIndex...index])
path = Array(path[path.startIndex ... index])
}

public func popToRoot() {
Expand Down
11 changes: 5 additions & 6 deletions Sources/FuturedArchitecture/Architecture/DataCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import Foundation
@Observable
@MainActor
public final class DataCache<Model: Equatable & Sendable> {

/// The data held by this data cache.
public private(set) var value: Model

Expand Down Expand Up @@ -50,10 +49,10 @@ public final class DataCache<Model: Equatable & Sendable> {
with newItems: T
) where T: RangeReplaceableCollection & MutableCollection, T.Element: Identifiable & Equatable {
guard !newItems.isEmpty else { return }
let original = self.value[keyPath: keyPath]
let original = value[keyPath: keyPath]
let merged = merging(original, with: newItems)
guard !merged.elementsEqual(original) else { return }
self.value[keyPath: keyPath] = merged
value[keyPath: keyPath] = merged
}

/// Optional-collection variant of `populate(_:with:)`.
Expand All @@ -62,10 +61,10 @@ public final class DataCache<Model: Equatable & Sendable> {
with newItems: T
) where T: RangeReplaceableCollection & MutableCollection, T.Element: Identifiable & Equatable {
guard !newItems.isEmpty else { return }
let original = self.value[keyPath: keyPath] ?? T()
let original = value[keyPath: keyPath] ?? T()
let merged = merging(original, with: newItems)
guard !merged.elementsEqual(original) else { return }
self.value[keyPath: keyPath] = merged
value[keyPath: keyPath] = merged
}

private func merging<T>(
Expand All @@ -84,7 +83,7 @@ public final class DataCache<Model: Equatable & Sendable> {

var appendedIds = existingIds
for item in newItems where appendedIds.insert(item.id).inserted {
result.append(newItemsDict[item.id]!)
result.append(newItemsDict[item.id] ?? item)
}

return result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ public enum SheetDetent: Hashable {
func detent() -> PresentationDetent {
switch self {
case .medium:
return .medium
.medium
case .large:
return .large
.large
case let .fraction(fraction):
return .fraction(fraction)
.fraction(fraction)
}
}
}
Expand All @@ -32,7 +32,7 @@ public enum SheetDetent: Hashable {
public enum ModalCoverModelStyle {
case sheet
#if !os(macOS)
case fullscreenCover
case fullscreenCover
#endif
}

Expand Down
30 changes: 15 additions & 15 deletions Sources/FuturedArchitecture/Architecture/ModalCoverModifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,23 @@ struct ModalCoverModifier<C: Coordinator>: ViewModifier {
}

#if os(macOS)
func body(content: Content) -> some View {
content
.sheet(item: sheetBinding, onDismiss: coordinator.onModalDismiss, content: coordinator.scene(for:))
}
func body(content: Content) -> some View {
content
.sheet(item: sheetBinding, onDismiss: coordinator.onModalDismiss, content: coordinator.scene(for:))
}
#else
private var fullscreenCoverBinding: Binding<C.Destination?> {
.init {
coordinator.modalCover?.style == .fullscreenCover ? coordinator.modalCover?.destination : nil
} set: { destination in
coordinator.modalCover = destination.map { .init(destination: $0, style: .fullscreenCover) }
private var fullscreenCoverBinding: Binding<C.Destination?> {
.init {
coordinator.modalCover?.style == .fullscreenCover ? coordinator.modalCover?.destination : nil
} set: { destination in
coordinator.modalCover = destination.map { .init(destination: $0, style: .fullscreenCover) }
}
}
}

func body(content: Content) -> some View {
content
.sheet(item: sheetBinding, onDismiss: coordinator.onModalDismiss, content: coordinator.scene(for:))
.fullScreenCover(item: fullscreenCoverBinding, onDismiss: coordinator.onModalDismiss, content: coordinator.scene(for:))
}
func body(content: Content) -> some View {
content
.sheet(item: sheetBinding, onDismiss: coordinator.onModalDismiss, content: coordinator.scene(for:))
.fullScreenCover(item: fullscreenCoverBinding, onDismiss: coordinator.onModalDismiss, content: coordinator.scene(for:))
}
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ public struct NavigationStackFlow<Coordinator: NavigationStackCoordinator, Conte
coordinator: Coordinator,
content: @MainActor @escaping () -> Content
) {
self.navigationDetents = detents.map { Set($0.map { $0.detent() }) }
self._coordinator = State(wrappedValue: coordinator)
navigationDetents = detents.map { Set($0.map { $0.detent() }) }
_coordinator = State(wrappedValue: coordinator)
self.content = content
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/FuturedArchitecture/Architecture/TabViewFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public struct TabViewFlow<Coordinator: TabCoordinator, Content: View>: View {
/// - content: The definition of tabs held by this TabView should be placed into this ViewBuilder. You are required to use instances of `Tab`
/// type as tags of the views. For an example refer to the template.
public init(coordinator: Coordinator, @ViewBuilder content: @MainActor @escaping () -> Content) {
self._coordinator = State(wrappedValue: coordinator)
_coordinator = State(wrappedValue: coordinator)
self.content = content
}

Expand Down Expand Up @@ -56,7 +56,7 @@ public struct TabContentFlow<Coordinator: TabCoordinator, Content: TabContent<Co
/// - coordinator: The instance of the coordinator used as the model and retained as ``SwiftUI.State``
/// - content: The definition of tabs using the ``SwiftUI.Tab`` API.
public init(coordinator: Coordinator, @TabContentBuilder<Coordinator.TabValue> content: @MainActor @escaping () -> Content) {
self._coordinator = State(wrappedValue: coordinator)
_coordinator = State(wrappedValue: coordinator)
self.content = content
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/FuturedHelpers/Helpers/ConfigKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ public protocol ConfigKey: RawRepresentable where RawValue == String {
var value: String { get throws }
}

public extension ConfigKey {
extension ConfigKey {
/// Default implementation that reads from Info.plist and handles Base64 decoding
var value: String {
public var value: String {
get throws {
guard let rawValue = Bundle.main.object(forInfoDictionaryKey: rawValue) as? String else {
throw ConfigKeyError.valueNotFound(key: rawValue)
Expand Down
Loading