From ed3cce4bf05e1b04420315888501a10db6d136ff Mon Sep 17 00:00:00 2001 From: Jakub Marek Date: Fri, 4 Sep 2026 09:12:00 +0200 Subject: [PATCH 1/3] Fix Xcode 27 warnings in SwiftUI App template Swift 6.4 warns when a nested closure captures a value weakly while the enclosing @ViewBuilder closure captures it strongly by implication (#ImplicitStrongCapture). Assign the capture explicitly to silence it. Enable INFOPLIST_KEY_UILaunchScreen_Generation, as Apple's own SwiftUI App template does, so generated projects run full screen without a manual Info.plist edit, and drop the #warning that asked for it. Co-Authored-By: Claude Fable 5.1 --- Templates/SwiftUI App.xctemplate/App.swift | 3 --- Templates/SwiftUI App.xctemplate/ExampleFlowCoordinator.swift | 2 +- Templates/SwiftUI App.xctemplate/TemplateInfo.plist | 2 ++ 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Templates/SwiftUI App.xctemplate/App.swift b/Templates/SwiftUI App.xctemplate/App.swift index 2642b7e..1843ffb 100644 --- a/Templates/SwiftUI App.xctemplate/App.swift +++ b/Templates/SwiftUI App.xctemplate/App.swift @@ -4,9 +4,6 @@ import SwiftUI #error("Add https://github.com/futuredapp/FuturedKit.git to the project!") -// swiftlint:disable:next line_length -#warning("Add UILaunchScreen (dictionary) to Info.plist. Without it, iOS runs the app in legacy compatibility mode and the UI does not fill the full screen on modern devices.") - #warning("Move the SwiftFormat and SwiftLint build phases above Compile Sources (templates can only append phases).") @main diff --git a/Templates/SwiftUI App.xctemplate/ExampleFlowCoordinator.swift b/Templates/SwiftUI App.xctemplate/ExampleFlowCoordinator.swift index a6da911..f22bbc9 100644 --- a/Templates/SwiftUI App.xctemplate/ExampleFlowCoordinator.swift +++ b/Templates/SwiftUI App.xctemplate/ExampleFlowCoordinator.swift @@ -19,7 +19,7 @@ final class ExampleFlowCoordinator: @MainActor NavigationStackCoordinator { NavigationStackFlow(coordinator: instance) { ExampleComponent( model: ExampleComponentModel( - dataCache: instance.container.dataCache) { [weak instance] event in + dataCache: instance.container.dataCache) { [weak instance = instance] event in switch event { case .touchEvent: instance?.navigate(to: .destination) diff --git a/Templates/SwiftUI App.xctemplate/TemplateInfo.plist b/Templates/SwiftUI App.xctemplate/TemplateInfo.plist index e5583e0..5c20261 100644 --- a/Templates/SwiftUI App.xctemplate/TemplateInfo.plist +++ b/Templates/SwiftUI App.xctemplate/TemplateInfo.plist @@ -103,6 +103,8 @@ 1,2 INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents YES + INFOPLIST_KEY_UILaunchScreen_Generation + YES INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad From 9b9a528b3ee233af2feda5c4622ed5283ff9dc68 Mon Sep 17 00:00:00 2001 From: Jakub Marek Date: Fri, 4 Sep 2026 09:52:02 +0200 Subject: [PATCH 2/3] Make generated template code SwiftFormat and SwiftLint clean A project created from the template had 18 files rewritten by the SwiftFormat phase and 2 more by swiftlint --fix on the first build. Apply the same formatting to the template sources so the first build changes nothing. - Use Apple's //___FILEHEADER___ form; the two-space variant expanded to a first header line with trailing whitespace in every file. - Remove redundant self, unused argument names, empty-body line breaks, indent #if DEBUG blocks, implicit returns, sorted imports. - MARK comments without dash, trailing closures, StateInfoConfig init with defaulted parameters last (project SwiftLint rules). Co-Authored-By: Claude Fable 5.1 --- ...rdinatorIdentifier___FlowCoordinator.swift | 2 +- ...LE_sceneIdentifier___CacheProjection.swift | 4 +- ...VARIABLE_sceneIdentifier___Component.swift | 12 +++--- ...BLE_sceneIdentifier___ComponentModel.swift | 17 ++++---- ...VARIABLE_sceneIdentifier___Component.swift | 12 +++--- ...BLE_sceneIdentifier___ComponentModel.swift | 15 ++++--- ..._VARIABLE_sceneIdentifier___Resource.swift | 8 ++-- ...VARIABLE_sceneIdentifier___Component.swift | 12 +++--- ...BLE_sceneIdentifier___ComponentModel.swift | 15 ++++--- ...oviderIdentifier___SceneFlowProvider.swift | 6 +-- .../___VARIABLE_serviceIdentifier___.swift | 8 ++-- Templates/SwiftUI App.xctemplate/App.swift | 6 +-- .../AppCoordinator.swift | 5 +-- .../SwiftUI App.xctemplate/AppDelegate.swift | 5 ++- .../CacheProjection.swift | 4 +- .../ComponentState.swift | 14 ++++--- .../ComponentStateView.swift | 20 +++++----- .../SwiftUI App.xctemplate/Container.swift | 4 +- .../DataCacheModel.swift | 4 +- .../ExampleCacheProjection.swift | 2 +- .../ExampleComponent.swift | 12 +++--- .../ExampleComponentModel.swift | 19 +++++---- .../ExampleFlowCoordinator.swift | 5 ++- .../SwiftUI App.xctemplate/ItemState.swift | 2 +- .../ItemStateView.swift | 10 ++--- .../SwiftUI App.xctemplate/Mockable.swift | 2 +- .../StateInfoConfig.swift | 4 +- .../StateInfoView.swift | 40 +++++++++---------- ...ordinatorIdentifier___TabCoordinator.swift | 3 +- 29 files changed, 133 insertions(+), 139 deletions(-) diff --git a/Templates/Flow Coordinator.xctemplate/___VARIABLE_flowCoordinatorIdentifier___FlowCoordinator.swift b/Templates/Flow Coordinator.xctemplate/___VARIABLE_flowCoordinatorIdentifier___FlowCoordinator.swift index d4caa8a..6db1223 100644 --- a/Templates/Flow Coordinator.xctemplate/___VARIABLE_flowCoordinatorIdentifier___FlowCoordinator.swift +++ b/Templates/Flow Coordinator.xctemplate/___VARIABLE_flowCoordinatorIdentifier___FlowCoordinator.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import EnumIdentable import FuturedArchitecture diff --git a/Templates/Scene.xctemplate/Projection Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___CacheProjection.swift b/Templates/Scene.xctemplate/Projection Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___CacheProjection.swift index b90cc97..c037b74 100644 --- a/Templates/Scene.xctemplate/Projection Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___CacheProjection.swift +++ b/Templates/Scene.xctemplate/Projection Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___CacheProjection.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import ProxyMembers @@ -11,7 +11,7 @@ nonisolated struct ___VARIABLE_sceneIdentifier___CacheProjection: CacheProjectio Self(state: state, data: .mock) } - static func data(from cache: DataCacheModel) -> Self? { + static func data(from _: DataCacheModel) -> Self? { // TODO: Map cache data to projection nil } diff --git a/Templates/Scene.xctemplate/Projection Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___Component.swift b/Templates/Scene.xctemplate/Projection Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___Component.swift index 6d5e360..a59bbb4 100644 --- a/Templates/Scene.xctemplate/Projection Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___Component.swift +++ b/Templates/Scene.xctemplate/Projection Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___Component.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import SwiftUI @@ -16,9 +16,9 @@ struct ___VARIABLE_sceneIdentifier___Component Void private let dataCache: DataCache @@ -38,13 +37,13 @@ extension ___VARIABLE_sceneIdentifier___ComponentModel { } #if DEBUG -@Observable -final class ___VARIABLE_sceneIdentifier___ComponentModelMock: ___VARIABLE_sceneIdentifier___ComponentModelProtocol { - typealias Event = ___VARIABLE_sceneIdentifier___ComponentModel.Event + @Observable + final class ___VARIABLE_sceneIdentifier___ComponentModelMock: ___VARIABLE_sceneIdentifier___ComponentModelProtocol { + typealias Event = ___VARIABLE_sceneIdentifier___ComponentModel.Event - var onEvent: (Event) -> Void = { _ in } - var projection: ___VARIABLE_sceneIdentifier___CacheProjection = .empty(state: .ready) + var onEvent: (Event) -> Void = { _ in } + var projection: ___VARIABLE_sceneIdentifier___CacheProjection = .empty(state: .ready) - func onAppear() async {} -} + func onAppear() async {} + } #endif diff --git a/Templates/Scene.xctemplate/Resource Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___Component.swift b/Templates/Scene.xctemplate/Resource Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___Component.swift index 9156483..cd6af67 100644 --- a/Templates/Scene.xctemplate/Resource Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___Component.swift +++ b/Templates/Scene.xctemplate/Resource Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___Component.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import SwiftUI @@ -14,9 +14,9 @@ struct ___VARIABLE_sceneIdentifier___Component Void private let dataCache: DataCache @@ -35,12 +34,12 @@ extension ___VARIABLE_sceneIdentifier___ComponentModel { } #if DEBUG -@Observable -final class ___VARIABLE_sceneIdentifier___ComponentModelMock: ___VARIABLE_sceneIdentifier___ComponentModelProtocol { - typealias Event = ___VARIABLE_sceneIdentifier___ComponentModel.Event + @Observable + final class ___VARIABLE_sceneIdentifier___ComponentModelMock: ___VARIABLE_sceneIdentifier___ComponentModelProtocol { + typealias Event = ___VARIABLE_sceneIdentifier___ComponentModel.Event - var onEvent: (Event) -> Void = { _ in } + var onEvent: (Event) -> Void = { _ in } - func onAppear() async {} -} + func onAppear() async {} + } #endif diff --git a/Templates/Scene.xctemplate/Resource Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___Resource.swift b/Templates/Scene.xctemplate/Resource Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___Resource.swift index 83ec313..aed1b60 100644 --- a/Templates/Scene.xctemplate/Resource Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___Resource.swift +++ b/Templates/Scene.xctemplate/Resource Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___Resource.swift @@ -1,7 +1,5 @@ -// ___FILEHEADER___ +//___FILEHEADER___ -protocol ___VARIABLE_sceneIdentifier___ResourceProtocol { -} +protocol ___VARIABLE_sceneIdentifier___ResourceProtocol {} -struct ___VARIABLE_sceneIdentifier___Resource: ___VARIABLE_sceneIdentifier___ResourceProtocol { -} +struct ___VARIABLE_sceneIdentifier___Resource: ___VARIABLE_sceneIdentifier___ResourceProtocol {} diff --git a/Templates/Scene.xctemplate/Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___Component.swift b/Templates/Scene.xctemplate/Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___Component.swift index 9156483..cd6af67 100644 --- a/Templates/Scene.xctemplate/Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___Component.swift +++ b/Templates/Scene.xctemplate/Scene/___VARIABLE_sceneIdentifier___/___VARIABLE_sceneIdentifier___Component.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import SwiftUI @@ -14,9 +14,9 @@ struct ___VARIABLE_sceneIdentifier___Component Void private let dataCache: DataCache @@ -32,12 +31,12 @@ extension ___VARIABLE_sceneIdentifier___ComponentModel { } #if DEBUG -@Observable -final class ___VARIABLE_sceneIdentifier___ComponentModelMock: ___VARIABLE_sceneIdentifier___ComponentModelProtocol { - typealias Event = ___VARIABLE_sceneIdentifier___ComponentModel.Event + @Observable + final class ___VARIABLE_sceneIdentifier___ComponentModelMock: ___VARIABLE_sceneIdentifier___ComponentModelProtocol { + typealias Event = ___VARIABLE_sceneIdentifier___ComponentModel.Event - var onEvent: (Event) -> Void = { _ in } + var onEvent: (Event) -> Void = { _ in } - func onAppear() async {} -} + func onAppear() async {} + } #endif diff --git a/Templates/SceneFlowProvider.xctemplate/___VARIABLE_sceneFlowProviderIdentifier___SceneFlowProvider.swift b/Templates/SceneFlowProvider.xctemplate/___VARIABLE_sceneFlowProviderIdentifier___SceneFlowProvider.swift index 5a8f126..702653c 100644 --- a/Templates/SceneFlowProvider.xctemplate/___VARIABLE_sceneFlowProviderIdentifier___SceneFlowProvider.swift +++ b/Templates/SceneFlowProvider.xctemplate/___VARIABLE_sceneFlowProviderIdentifier___SceneFlowProvider.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import EnumIdentable import FuturedArchitecture @@ -31,8 +31,8 @@ final class ___VARIABLE_sceneFlowProviderIdentifier___SceneFlowProvider: @MainAc EmptyView() case .otherDestination: EmptyView() - // case .end: - // EmptyView() + // case .end: + // EmptyView() } } } diff --git a/Templates/Service.xctemplate/___VARIABLE_serviceIdentifier___.swift b/Templates/Service.xctemplate/___VARIABLE_serviceIdentifier___.swift index 73ed352..a52be0c 100644 --- a/Templates/Service.xctemplate/___VARIABLE_serviceIdentifier___.swift +++ b/Templates/Service.xctemplate/___VARIABLE_serviceIdentifier___.swift @@ -1,7 +1,5 @@ -// ___FILEHEADER___ +//___FILEHEADER___ -protocol ___VARIABLE_serviceIdentifier___ { -} +protocol ___VARIABLE_serviceIdentifier___ {} -final class Production___VARIABLE_serviceIdentifier___: ___VARIABLE_serviceIdentifier___ { -} +final class Production___VARIABLE_serviceIdentifier___: ___VARIABLE_serviceIdentifier___ {} diff --git a/Templates/SwiftUI App.xctemplate/App.swift b/Templates/SwiftUI App.xctemplate/App.swift index 1843ffb..b193937 100644 --- a/Templates/SwiftUI App.xctemplate/App.swift +++ b/Templates/SwiftUI App.xctemplate/App.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import SwiftUI @@ -14,8 +14,8 @@ struct ___PACKAGENAME:identifier___App: App { init() { let coordinator = AppCoordinator(container: Container()) - self._coordinator = State(wrappedValue: coordinator) - self.appDelegate.delegate = coordinator + _coordinator = State(wrappedValue: coordinator) + appDelegate.delegate = coordinator } var body: some Scene { diff --git a/Templates/SwiftUI App.xctemplate/AppCoordinator.swift b/Templates/SwiftUI App.xctemplate/AppCoordinator.swift index 54b29c1..3a80690 100644 --- a/Templates/SwiftUI App.xctemplate/AppCoordinator.swift +++ b/Templates/SwiftUI App.xctemplate/AppCoordinator.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import SwiftUI @@ -19,6 +19,5 @@ final class AppCoordinator { extension AppCoordinator: AppDelegateProtocol { // swiftlint:disable:next discouraged_optional_collection - func applicationDidFinishLaunching(with launchOptions: [UIApplication.LaunchOptionsKey: Any]?) { - } + func applicationDidFinishLaunching(with _: [UIApplication.LaunchOptionsKey: Any]?) {} } diff --git a/Templates/SwiftUI App.xctemplate/AppDelegate.swift b/Templates/SwiftUI App.xctemplate/AppDelegate.swift index 4cfc1cb..21c1642 100644 --- a/Templates/SwiftUI App.xctemplate/AppDelegate.swift +++ b/Templates/SwiftUI App.xctemplate/AppDelegate.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import UIKit @@ -12,11 +12,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate { weak var delegate: AppDelegateProtocol? func application( - _ application: UIApplication, + _: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil ) -> Bool { delegate?.applicationDidFinishLaunching(with: launchOptions) return true } } + // swiftlint:enable discouraged_optional_collection diff --git a/Templates/SwiftUI App.xctemplate/CacheProjection.swift b/Templates/SwiftUI App.xctemplate/CacheProjection.swift index 884736f..41177fc 100644 --- a/Templates/SwiftUI App.xctemplate/CacheProjection.swift +++ b/Templates/SwiftUI App.xctemplate/CacheProjection.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ protocol CacheProjection: Equatable { associatedtype CacheModel: Equatable @@ -20,7 +20,7 @@ protocol CacheProjection: Equatable { /// Default `data(for:from:)` for projections that don't use an ID. /// Projections with a real `ID` type are forced to implement it. extension CacheProjection where ID == Void { - static func data(for id: ID, from cache: CacheModel) -> Self? { + static func data(for _: ID, from _: CacheModel) -> Self? { nil } } diff --git a/Templates/SwiftUI App.xctemplate/ComponentState.swift b/Templates/SwiftUI App.xctemplate/ComponentState.swift index 890be99..3a3f36e 100644 --- a/Templates/SwiftUI App.xctemplate/ComponentState.swift +++ b/Templates/SwiftUI App.xctemplate/ComponentState.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ /// Screen/component-level lifecycle state. /// @@ -11,21 +11,25 @@ nonisolated enum ComponentState: Equatable { case error(StateInfoConfig) var isLoading: Bool { - if case .loading = self { return true } + if case .loading = self { + return true + } return false } var isError: Bool { - if case .error = self { return true } + if case .error = self { + return true + } return false } var infoConfig: StateInfoConfig? { switch self { case let .empty(config), let .error(config): - return config + config case .ready, .loading: - return nil + nil } } } diff --git a/Templates/SwiftUI App.xctemplate/ComponentStateView.swift b/Templates/SwiftUI App.xctemplate/ComponentStateView.swift index f384fdd..e30e4bf 100644 --- a/Templates/SwiftUI App.xctemplate/ComponentStateView.swift +++ b/Templates/SwiftUI App.xctemplate/ComponentStateView.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import SwiftUI @@ -51,7 +51,7 @@ struct ComponentStateView< } } -// MARK: - Default empty/error via StateInfoView +// MARK: Default empty/error via StateInfoView extension ComponentStateView where EmptyView == StateInfoView, ErrorView == StateInfoView { /// Uses `StateInfoView` as the default renderer for both empty and @@ -91,7 +91,7 @@ extension ComponentStateView where } } -// MARK: - Custom loading, default empty/error +// MARK: Custom loading, default empty/error extension ComponentStateView where LoadingView == PopulatedView { /// Loading reuses populated; empty and error fully custom. @@ -111,7 +111,7 @@ extension ComponentStateView where LoadingView == PopulatedView { } } -// MARK: - Customize only error (empty defaults to StateInfoView) +// MARK: Customize only error (empty defaults to StateInfoView) extension ComponentStateView where EmptyView == StateInfoView { /// Custom error view; empty stays as the default `StateInfoView`. @@ -148,7 +148,7 @@ extension ComponentStateView where LoadingView == PopulatedView, EmptyView == St } } -// MARK: - Customize only empty (error defaults to StateInfoView) +// MARK: Customize only empty (error defaults to StateInfoView) extension ComponentStateView where ErrorView == StateInfoView { /// Custom empty view; error stays as the default `StateInfoView`. @@ -162,9 +162,8 @@ extension ComponentStateView where ErrorView == StateInfoView { state: state, populatedView: populatedView, loadingView: loadingView, - emptyView: emptyView, - errorView: { StateInfoView(config: $0) } - ) + emptyView: emptyView + ) { StateInfoView(config: $0) } } } @@ -179,8 +178,7 @@ extension ComponentStateView where LoadingView == PopulatedView, ErrorView == St state: state, populatedView: populatedView, loadingView: populatedView, - emptyView: emptyView, - errorView: { StateInfoView(config: $0) } - ) + emptyView: emptyView + ) { StateInfoView(config: $0) } } } diff --git a/Templates/SwiftUI App.xctemplate/Container.swift b/Templates/SwiftUI App.xctemplate/Container.swift index 793881f..60c8ca9 100644 --- a/Templates/SwiftUI App.xctemplate/Container.swift +++ b/Templates/SwiftUI App.xctemplate/Container.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import FuturedArchitecture @@ -11,6 +11,6 @@ final class Container { func resetContainer() { // Reset services - self.dataCache = DataCache(value: DataCacheModel()) + dataCache = DataCache(value: DataCacheModel()) } } diff --git a/Templates/SwiftUI App.xctemplate/DataCacheModel.swift b/Templates/SwiftUI App.xctemplate/DataCacheModel.swift index f30abe1..d63e3f3 100644 --- a/Templates/SwiftUI App.xctemplate/DataCacheModel.swift +++ b/Templates/SwiftUI App.xctemplate/DataCacheModel.swift @@ -1,7 +1,7 @@ -// ___FILEHEADER___ +//___FILEHEADER___ nonisolated struct DataCacheModel: Equatable, Sendable { - // Cached properties + /// Cached properties var exampleItem: ExampleItem? } diff --git a/Templates/SwiftUI App.xctemplate/ExampleCacheProjection.swift b/Templates/SwiftUI App.xctemplate/ExampleCacheProjection.swift index bb3bdc3..c9fde8c 100644 --- a/Templates/SwiftUI App.xctemplate/ExampleCacheProjection.swift +++ b/Templates/SwiftUI App.xctemplate/ExampleCacheProjection.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import ProxyMembers diff --git a/Templates/SwiftUI App.xctemplate/ExampleComponent.swift b/Templates/SwiftUI App.xctemplate/ExampleComponent.swift index 4e6ac29..b3b3711 100644 --- a/Templates/SwiftUI App.xctemplate/ExampleComponent.swift +++ b/Templates/SwiftUI App.xctemplate/ExampleComponent.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import SwiftUI @@ -26,9 +26,9 @@ struct ExampleComponent: View { } #if DEBUG -#Preview { - ExampleComponent( - model: ExampleComponentModelMock() - ) -} + #Preview { + ExampleComponent( + model: ExampleComponentModelMock() + ) + } #endif diff --git a/Templates/SwiftUI App.xctemplate/ExampleComponentModel.swift b/Templates/SwiftUI App.xctemplate/ExampleComponentModel.swift index ed73655..6e854ae 100644 --- a/Templates/SwiftUI App.xctemplate/ExampleComponentModel.swift +++ b/Templates/SwiftUI App.xctemplate/ExampleComponentModel.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import FuturedArchitecture import Observation @@ -12,7 +12,6 @@ protocol ExampleComponentModelProtocol: ComponentModel { @Observable final class ExampleComponentModel: ExampleComponentModelProtocol { - let onEvent: (Event) -> Void private let dataCache: DataCache @@ -49,15 +48,15 @@ extension ExampleComponentModel { } #if DEBUG -@Observable -final class ExampleComponentModelMock: ExampleComponentModelProtocol { - typealias Event = ExampleComponentModel.Event + @Observable + final class ExampleComponentModelMock: ExampleComponentModelProtocol { + typealias Event = ExampleComponentModel.Event - var onEvent: (Event) -> Void = { _ in } - var projection: ExampleCacheProjection = .empty(state: .ready) + var onEvent: (Event) -> Void = { _ in } + var projection: ExampleCacheProjection = .empty(state: .ready) - func onAppear() async { } + func onAppear() async {} - func onTouchUpInside() { } -} + func onTouchUpInside() {} + } #endif diff --git a/Templates/SwiftUI App.xctemplate/ExampleFlowCoordinator.swift b/Templates/SwiftUI App.xctemplate/ExampleFlowCoordinator.swift index f22bbc9..49a7393 100644 --- a/Templates/SwiftUI App.xctemplate/ExampleFlowCoordinator.swift +++ b/Templates/SwiftUI App.xctemplate/ExampleFlowCoordinator.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import EnumIdentable import FuturedArchitecture @@ -19,7 +19,8 @@ final class ExampleFlowCoordinator: @MainActor NavigationStackCoordinator { NavigationStackFlow(coordinator: instance) { ExampleComponent( model: ExampleComponentModel( - dataCache: instance.container.dataCache) { [weak instance = instance] event in + dataCache: instance.container.dataCache + ) { [weak instance = instance] event in switch event { case .touchEvent: instance?.navigate(to: .destination) diff --git a/Templates/SwiftUI App.xctemplate/ItemState.swift b/Templates/SwiftUI App.xctemplate/ItemState.swift index 7be9501..fd76ebf 100644 --- a/Templates/SwiftUI App.xctemplate/ItemState.swift +++ b/Templates/SwiftUI App.xctemplate/ItemState.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ /// State wrapper for a single data item inside a component. /// diff --git a/Templates/SwiftUI App.xctemplate/ItemStateView.swift b/Templates/SwiftUI App.xctemplate/ItemStateView.swift index 0a974df..04e3eeb 100644 --- a/Templates/SwiftUI App.xctemplate/ItemStateView.swift +++ b/Templates/SwiftUI App.xctemplate/ItemStateView.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import SwiftUI @@ -51,7 +51,7 @@ extension ItemStateView where LoadingView == PopulatedView { ) { self.state = state self.populatedView = populatedView - self.loadingView = populatedView + loadingView = populatedView self.errorView = errorView } } @@ -67,7 +67,7 @@ extension ItemStateView where ErrorView == StateInfoView { self.state = state self.populatedView = populatedView self.loadingView = loadingView - self.errorView = { StateInfoView(config: $0) } + errorView = { StateInfoView(config: $0) } } } @@ -80,7 +80,7 @@ extension ItemStateView where LoadingView == PopulatedView, ErrorView == StateIn ) { self.state = state self.populatedView = populatedView - self.loadingView = populatedView - self.errorView = { StateInfoView(config: $0) } + loadingView = populatedView + errorView = { StateInfoView(config: $0) } } } diff --git a/Templates/SwiftUI App.xctemplate/Mockable.swift b/Templates/SwiftUI App.xctemplate/Mockable.swift index 5ec6f89..23aa464 100644 --- a/Templates/SwiftUI App.xctemplate/Mockable.swift +++ b/Templates/SwiftUI App.xctemplate/Mockable.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ protocol Mockable { nonisolated static var mock: Self { get } diff --git a/Templates/SwiftUI App.xctemplate/StateInfoConfig.swift b/Templates/SwiftUI App.xctemplate/StateInfoConfig.swift index f737124..89992ef 100644 --- a/Templates/SwiftUI App.xctemplate/StateInfoConfig.swift +++ b/Templates/SwiftUI App.xctemplate/StateInfoConfig.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import SwiftUI @@ -21,8 +21,8 @@ nonisolated struct StateInfoConfig: Equatable { let actions: [Action] init( - icon: Image? = nil, title: String, + icon: Image? = nil, message: String? = nil, actions: [Action] = [] ) { diff --git a/Templates/SwiftUI App.xctemplate/StateInfoView.swift b/Templates/SwiftUI App.xctemplate/StateInfoView.swift index 1038893..2458a82 100644 --- a/Templates/SwiftUI App.xctemplate/StateInfoView.swift +++ b/Templates/SwiftUI App.xctemplate/StateInfoView.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import SwiftUI @@ -63,24 +63,24 @@ struct StateInfoView: View { } #if DEBUG -#Preview("Empty") { - StateInfoView(config: .init( - icon: Image(systemName: "tray"), - title: "No items yet", - message: "Pull to refresh or tap the button below.", - actions: [.init(title: "Refresh", action: {})] - )) -} + #Preview("Empty") { + StateInfoView(config: .init( + title: "No items yet", + icon: Image(systemName: "tray"), + message: "Pull to refresh or tap the button below.", + actions: [.init(title: "Refresh") {}] + )) + } -#Preview("Error") { - StateInfoView(config: .init( - icon: Image(systemName: "exclamationmark.triangle"), - title: "Something went wrong", - message: "We couldn't load this screen. Please try again.", - actions: [ - .init(title: "Retry", action: {}), - .init(title: "Cancel", action: {}) - ] - )) -} + #Preview("Error") { + StateInfoView(config: .init( + title: "Something went wrong", + icon: Image(systemName: "exclamationmark.triangle"), + message: "We couldn't load this screen. Please try again.", + actions: [ + .init(title: "Retry") {}, + .init(title: "Cancel") {} + ] + )) + } #endif diff --git a/Templates/Tab Coordinator.xctemplate/___VARIABLE_tabCoordinatorIdentifier___TabCoordinator.swift b/Templates/Tab Coordinator.xctemplate/___VARIABLE_tabCoordinatorIdentifier___TabCoordinator.swift index c5b4b45..e82c4af 100644 --- a/Templates/Tab Coordinator.xctemplate/___VARIABLE_tabCoordinatorIdentifier___TabCoordinator.swift +++ b/Templates/Tab Coordinator.xctemplate/___VARIABLE_tabCoordinatorIdentifier___TabCoordinator.swift @@ -1,4 +1,4 @@ -// ___FILEHEADER___ +//___FILEHEADER___ import EnumIdentable import FuturedArchitecture @@ -21,7 +21,6 @@ final class ___VARIABLE_tabCoordinatorIdentifier___TabCoordinator: @MainActor Ta self.selectedTab = selectedTab } - @ViewBuilder static func rootView(with instance: ___VARIABLE_tabCoordinatorIdentifier___TabCoordinator) -> some View { TabContentFlow(coordinator: instance) { Tab("First", systemImage: "1.circle", value: AppTab.firstTab) { From 7b6f6b889f91822c2073ae861edf27e31a9afe91 Mon Sep 17 00:00:00 2001 From: Jakub Marek Date: Fri, 4 Sep 2026 11:00:20 +0200 Subject: [PATCH 3/3] docs: point the SPM install snippet at FuturedKit 2.0 Co-Authored-By: Claude Fable 5.1 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8ae377d..0f03657 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ are commonly used. When using Swift package manager install using or add following line to your dependencies: ```swift -.package(url: "https://github.com/futuredapp/FuturedKit.git", from: "1.0.0") +.package(url: "https://github.com/futuredapp/FuturedKit.git", from: "2.0.0") ``` The repository provides number of Xcode Templates for user convenience.