From 2e1cfd36f7dda29422eba9c93d507a44c82a72fb Mon Sep 17 00:00:00 2001 From: Paul Kraft Date: Wed, 21 Jul 2021 00:04:26 +0200 Subject: [PATCH 01/10] Rewrite Logic & Include Example project --- Example/Shared/Actions/LoadAction.swift | 16 ++ Example/Shared/Actions/LoginAction.swift | 32 ++++ Example/Shared/Actions/LogoutAction.swift | 18 +++ Example/Shared/App/AppPlugin.swift | 29 ++++ Example/Shared/App/ExampleApp.swift | 56 +++++++ Example/Shared/App/Model+Key.swift | 65 ++++++++ .../AccentColor.colorset/Contents.json | 11 ++ .../AppIcon.appiconset/Contents.json | 148 ++++++++++++++++++ Example/Shared/Assets.xcassets/Contents.json | 6 + Example/Shared/Views/ContentView.swift | 23 +++ Example/Shared/Views/HomeView.swift | 20 +++ Example/Shared/Views/LoginView.swift | 31 ++++ Example/iOS/Info.plist | 50 ++++++ Example/macOS/Info.plist | 26 +++ Example/macOS/macOS.entitlements | 10 ++ Package.swift | 91 ++++++++--- README.md | 102 +++++++++++- Sources/ChartPresenter/Chart+AreaStyle.swift | 2 +- Sources/ChartPresenter/Chart+Charts.swift | 28 ++-- .../ChartPresenter/Chart+ColumnStyle.swift | 4 +- Sources/ChartPresenter/Chart+LineStyle.swift | 2 + .../Chart+StackedAreaStyle.swift | 2 + Sources/ChartPresenter/Chart+Style.swift | 22 +-- Sources/ChartPresenter/Chart.swift | 6 +- Sources/ChartPresenter/UIservCharts.swift | 2 +- Sources/Example/App.swift | 8 - Sources/Example/ContentView.swift | 7 +- Sources/MetricPresenter/Card.swift | 8 +- Sources/MetricPresenter/Gauge.swift | 16 +- Sources/MetricPresenter/Graph+Labeling.swift | 2 +- Sources/MetricPresenter/Graph.swift | 6 +- Sources/MetricPresenter/MetricCard.swift | 8 +- Sources/MetricPresenter/MetricPresenter.swift | 4 +- .../Configuration/Configuration+Plugin.swift | 22 +-- .../Configuration/Configuration+Use.swift | 12 +- .../Configuration/Configuration.swift | 12 +- .../Configuration/DefaultPlugin.swift | 4 +- .../Presenter/Configuration/NamedType.swift | 2 - Sources/Presenter/Configuration/Plugin.swift | 8 +- Sources/Presenter/Model/CopyAction.swift | 2 +- .../Presenter/Model/JavaScriptAction.swift | 7 +- Sources/Presenter/Model/Model.swift | 12 +- Sources/Presenter/Model/ModelView.swift | 8 +- Sources/Presenter/Model/SetAction.swift | 2 +- Sources/Presenter/Model/Value.swift | 2 +- Sources/Presenter/Types/Gradient.swift | 2 +- .../Presenter/View - General/CoderView.swift | 76 ++++----- .../View - General/InternalView.swift | 32 ---- .../Presenter/View - General/ServedView.swift | 143 ++++++++++++++--- .../View - General/SwiftUIView.swift | 33 ---- Sources/Presenter/View - General/View.swift | 79 ++++------ .../View - General/ViewBuilder.swift | 12 +- .../AnyViewModifying.swift | 30 ---- .../CoderViewModifier.swift | 20 +-- .../ViewModifier - General/ViewModifier.swift | 48 ++++++ .../Presenter/ViewModifiers/AccentColor.swift | 10 +- .../ViewModifiers/AnimationModifier.swift | 8 +- .../Presenter/ViewModifiers/AspectRatio.swift | 20 +-- .../Presenter/ViewModifiers/Background.swift | 26 ++- Sources/Presenter/ViewModifiers/Blur.swift | 8 +- Sources/Presenter/ViewModifiers/Clipped.swift | 8 +- .../ViewModifiers/CornerRadius.swift | 8 +- .../ViewModifiers/DrawingGroup.swift | 8 +- .../ViewModifiers/DynamicFrame.swift | 8 +- .../ViewModifiers/FontModifier.swift | 8 +- .../ViewModifiers/ForegroundColor.swift | 10 +- Sources/Presenter/ViewModifiers/Frame.swift | 10 +- .../ViewModifiers/LayoutPriority.swift | 8 +- .../ViewModifiers/LifecycleModifier.swift | 12 +- Sources/Presenter/ViewModifiers/Mask.swift | 21 ++- .../ViewModifiers/NavigationBarTitle.swift | 8 +- Sources/Presenter/ViewModifiers/Opacity.swift | 8 +- Sources/Presenter/ViewModifiers/Overlay.swift | 26 ++- Sources/Presenter/ViewModifiers/Padding.swift | 12 +- Sources/Presenter/ViewModifiers/Shadow.swift | 10 +- Sources/Presenter/ViewModifiers/Sheet.swift | 29 ++-- Sources/Presenter/Views/AngularGradient.swift | 6 +- Sources/Presenter/Views/ArrayView.swift | 8 +- Sources/Presenter/Views/Button.swift | 10 +- Sources/Presenter/Views/Capsule.swift | 6 +- Sources/Presenter/Views/Circle.swift | 6 +- Sources/Presenter/Views/Color.swift | 8 +- Sources/Presenter/Views/ColorPicker.swift | 44 +++--- Sources/Presenter/Views/ComposedView.swift | 8 +- Sources/Presenter/Views/DataView.swift | 17 +- Sources/Presenter/Views/Divider.swift | 6 +- Sources/Presenter/Views/HGrid.swift | 21 ++- Sources/Presenter/Views/HStack.swift | 12 +- Sources/Presenter/Views/If.swift | 46 ++++-- Sources/Presenter/Views/Image.swift | 6 +- Sources/Presenter/Views/LinearGradient.swift | 6 +- Sources/Presenter/Views/Link.swift | 31 ++-- Sources/Presenter/Views/Local.swift | 10 +- Sources/Presenter/Views/NavigationLink.swift | 37 +++-- Sources/Presenter/Views/NavigationView.swift | 12 +- Sources/Presenter/Views/Nil.swift | 39 ++--- Sources/Presenter/Views/Path.swift | 6 +- Sources/Presenter/Views/ScrollView.swift | 12 +- Sources/Presenter/Views/Section.swift | 91 +++++------ Sources/Presenter/Views/SecureField.swift | 6 +- Sources/Presenter/Views/Slider.swift | 10 +- Sources/Presenter/Views/Spacer.swift | 6 +- Sources/Presenter/Views/TabView.swift | 14 +- Sources/Presenter/Views/Text.swift | 6 +- Sources/Presenter/Views/TextEditor.swift | 8 +- Sources/Presenter/Views/TextField.swift | 6 +- Sources/Presenter/Views/Toggle.swift | 10 +- Sources/Presenter/Views/VGrid.swift | 18 +-- Sources/Presenter/Views/VStack.swift | 25 ++- Sources/Presenter/Views/ZStack.swift | 12 +- Sources/TracePresenter/TraceGraph.swift | 6 +- Sources/TracePresenter/TracePresenter.swift | 2 +- Tests/PresenterTests/PresenterTests.swift | 60 +++---- 113 files changed, 1545 insertions(+), 787 deletions(-) create mode 100644 Example/Shared/Actions/LoadAction.swift create mode 100644 Example/Shared/Actions/LoginAction.swift create mode 100644 Example/Shared/Actions/LogoutAction.swift create mode 100644 Example/Shared/App/AppPlugin.swift create mode 100644 Example/Shared/App/ExampleApp.swift create mode 100644 Example/Shared/App/Model+Key.swift create mode 100644 Example/Shared/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 Example/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 Example/Shared/Assets.xcassets/Contents.json create mode 100644 Example/Shared/Views/ContentView.swift create mode 100644 Example/Shared/Views/HomeView.swift create mode 100644 Example/Shared/Views/LoginView.swift create mode 100644 Example/iOS/Info.plist create mode 100644 Example/macOS/Info.plist create mode 100644 Example/macOS/macOS.entitlements delete mode 100644 Sources/Presenter/View - General/InternalView.swift delete mode 100644 Sources/Presenter/View - General/SwiftUIView.swift delete mode 100644 Sources/Presenter/ViewModifier - General/AnyViewModifying.swift create mode 100644 Sources/Presenter/ViewModifier - General/ViewModifier.swift diff --git a/Example/Shared/Actions/LoadAction.swift b/Example/Shared/Actions/LoadAction.swift new file mode 100644 index 0000000..9ed9092 --- /dev/null +++ b/Example/Shared/Actions/LoadAction.swift @@ -0,0 +1,16 @@ +// +// LoadAction.swift +// Example +// +// Created by Paul Kraft on 20.07.21. +// + +import Presenter + +struct LoadAction: Action { + + func perform(on model: Model) { + // TODO + } + +} diff --git a/Example/Shared/Actions/LoginAction.swift b/Example/Shared/Actions/LoginAction.swift new file mode 100644 index 0000000..566b9a0 --- /dev/null +++ b/Example/Shared/Actions/LoginAction.swift @@ -0,0 +1,32 @@ +// +// LoginAction.swift +// Example +// +// Created by Paul Kraft on 20.07.21. +// + +import Presenter + +struct LoginAction: Action { + + func perform(on model: Model) { + guard let username = model[.username], + let password = model[.password] else { + model[.loginErrorMessage] = "Could not find username or password." + model[.showLoginError] = true + return + } + + guard username.count > 0 && password.count > 0 else { + model[.loginErrorMessage] = "Please enter username and password." + model[.showLoginError] = true + return + } + + let prefix = Data(username.utf8).base64EncodedString() + let suffix = Data(password.utf8).base64EncodedString() + model[.authenticationToken] = prefix + ":" + suffix + model[.isAuthenticated] = true + } + +} diff --git a/Example/Shared/Actions/LogoutAction.swift b/Example/Shared/Actions/LogoutAction.swift new file mode 100644 index 0000000..6f1ec2e --- /dev/null +++ b/Example/Shared/Actions/LogoutAction.swift @@ -0,0 +1,18 @@ +// +// Logout.swift +// Example +// +// Created by Paul Kraft on 20.07.21. +// +import Presenter + +struct LogoutAction: Action { + + func perform(on model: Model) { + model[.username] = nil + model[.password] = nil + model[.authenticationToken] = nil + model[.isAuthenticated] = false + } + +} diff --git a/Example/Shared/App/AppPlugin.swift b/Example/Shared/App/AppPlugin.swift new file mode 100644 index 0000000..0c2232e --- /dev/null +++ b/Example/Shared/App/AppPlugin.swift @@ -0,0 +1,29 @@ +// +// AppPlugin.swift +// Example +// +// Created by Paul Kraft on 20.07.21. +// + +import Presenter +import MetricPresenter +import TracePresenter + +struct AppPlugin: Plugin { + + var plugins: [Plugin] { + [ + MetricPresenter(), + TracePresenter(), + ] + } + + var actions: [Action.Type] { + [ + LoadAction.self, + LoginAction.self, + LogoutAction.self, + ] + } + +} diff --git a/Example/Shared/App/ExampleApp.swift b/Example/Shared/App/ExampleApp.swift new file mode 100644 index 0000000..900b4df --- /dev/null +++ b/Example/Shared/App/ExampleApp.swift @@ -0,0 +1,56 @@ +// +// ExampleApp.swift +// Shared +// +// Created by Paul Kraft on 20.07.21. +// + +import Presenter +import SwiftUI + +@main +struct ExampleApp: App { + + // MARK: Stored Properties + + @SwiftUI.StateObject private var model = Model() + @SwiftUI.State private var view: AnyView? + + // MARK: Initialization + + init() { + Presenter.use(plugin: AppPlugin()) + } + + // MARK: Views + + var body: some Scene { + WindowGroup { + load(ContentView()) + .environmentObject(model) + } + } + + // MARK: Helpers + + private func load(_ presenterView: V) -> AnyView? { + if let view = view { + return view + } + DispatchQueue.global(qos: .userInitiated).async { + let view: AnyView + do { + let data = try Presenter.encode(presenterView) + view = try Presenter.decode(from: data) + .eraseToAnyView() + } catch { + view = AnyView(SwiftUI.Text(error.localizedDescription)) + } + DispatchQueue.main.async { + self.view = view + } + } + return nil + } + +} diff --git a/Example/Shared/App/Model+Key.swift b/Example/Shared/App/Model+Key.swift new file mode 100644 index 0000000..7067fa2 --- /dev/null +++ b/Example/Shared/App/Model+Key.swift @@ -0,0 +1,65 @@ +// +// Model+Key.swift +// Example +// +// Created by Paul Kraft on 20.07.21. +// + +import Presenter + +extension Model.Key { + + static var username: Model.Key { + .init(rawValue: "login-username") + } + + static var password: Model.Key { + .init(rawValue: "login-password") + } + + static var authenticationToken: Model.Key { + .init(rawValue: "login-token") + } + + static var isAuthenticated: Model.Key { + .init(rawValue: "login-active") + } + + static var showLoginError: Model.Key { + .init(rawValue: "login-show-error") + } + + static var loginErrorMessage: Model.Key { + .init(rawValue: "login-error-message") + } + + static var isLoadingAllRecipes: Model.Key { + .init(rawValue: "recipe-all-loading") + } + + static var allRecipeIdentifiers: Model.Key<[String]> { + .init(rawValue: "recipe-all-ids") + } + +} + +extension State { + + init(_ key: Model.Key, default defaultValue: Content) { + self.init(key.rawValue, default: defaultValue) + } + +} + +extension Model { + + struct Key { + let rawValue: String + } + + subscript(key: Key) -> Value? { + get { get(key.rawValue) as? Value } + set { set(key.rawValue, to: newValue) } + } + +} diff --git a/Example/Shared/Assets.xcassets/AccentColor.colorset/Contents.json b/Example/Shared/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/Example/Shared/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json b/Example/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..c136eaf --- /dev/null +++ b/Example/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,148 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/Shared/Assets.xcassets/Contents.json b/Example/Shared/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Example/Shared/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/Shared/Views/ContentView.swift b/Example/Shared/Views/ContentView.swift new file mode 100644 index 0000000..b256c84 --- /dev/null +++ b/Example/Shared/Views/ContentView.swift @@ -0,0 +1,23 @@ +// +// ContentView.swift +// Shared +// +// Created by Paul Kraft on 20.07.21. +// + +import Presenter + +typealias PresenterModel = Model +typealias PresenterView = View + +struct ContentView: UserView { + + @State(.isAuthenticated, default: false) var isAuthenticated + + var body: View { + If(isAuthenticated, + then: HomeView(), + else: LoginView()) + } + +} diff --git a/Example/Shared/Views/HomeView.swift b/Example/Shared/Views/HomeView.swift new file mode 100644 index 0000000..0bf0edd --- /dev/null +++ b/Example/Shared/Views/HomeView.swift @@ -0,0 +1,20 @@ +// +// HomeView.swift +// Example +// +// Created by Paul Kraft on 20.07.21. +// + +import Presenter + +struct HomeView: UserView { + + var body: View { + VStack(spacing: 8) { + Text("You are logged in!") + Button(Text("Logout"), action: LogoutAction()) + } + .onAppear(perform: LoadAction()) + } + +} diff --git a/Example/Shared/Views/LoginView.swift b/Example/Shared/Views/LoginView.swift new file mode 100644 index 0000000..74c7694 --- /dev/null +++ b/Example/Shared/Views/LoginView.swift @@ -0,0 +1,31 @@ +// +// LoginView.swift +// Example +// +// Created by Paul Kraft on 20.07.21. +// + +import Presenter + +struct LoginView: UserView { + + @State(.username, default: "") var username + @State(.password, default: "") var password + @State(.showLoginError, default: false) var showLoginError + @State(.loginErrorMessage, default: "Unknown Error") var loginErrorMessage + + var body: View { + VStack { + TextField("Username", text: $username) + SecureField("Password", text: $password) + Button(Text("Login"), action: LoginAction()) + } + .padding(16) + .background(Color(red: 1, green: 1, blue: 1)) + .cornerRadius(8) + .shadow(radius: 8) + .padding(16) + .sheet(isPresented: $showLoginError, content: Text(loginErrorMessage)) + } + +} diff --git a/Example/iOS/Info.plist b/Example/iOS/Info.plist new file mode 100644 index 0000000..efc211a --- /dev/null +++ b/Example/iOS/Info.plist @@ -0,0 +1,50 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + + UIApplicationSupportsIndirectInputEvents + + UILaunchScreen + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Example/macOS/Info.plist b/Example/macOS/Info.plist new file mode 100644 index 0000000..bacbc56 --- /dev/null +++ b/Example/macOS/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + + diff --git a/Example/macOS/macOS.entitlements b/Example/macOS/macOS.entitlements new file mode 100644 index 0000000..f2ef3ae --- /dev/null +++ b/Example/macOS/macOS.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + + + diff --git a/Package.swift b/Package.swift index 241940a..c7c36a2 100644 --- a/Package.swift +++ b/Package.swift @@ -2,29 +2,69 @@ import PackageDescription - #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) -let exampleTarget: [Target] = [ - .executableTarget( - name: "Example", - dependencies: ["Presenter"] - ) -] -let exampleProduct: [Product] = [ - .executable( - name: "Example", - targets: ["Example", "Presenter"] - ) -] -#else -let exampleTarget: [Target] = [] -let exampleProduct: [Product] = [] -#endif +let package = Package( + name: "Presenter", + platforms: [.iOS(.v13), .macOS(.v10_15), .tvOS(.v13), .watchOS(.v6)], + products: [ + .library( + name: "Presenter", + targets: ["Presenter"] + ), + .library( + name: "ChartPresenter", + targets: ["ChartPresenter"] + ), + .library( + name: "MetricPresenter", + targets: ["MetricPresenter"] + ), + .library( + name: "TracePresenter", + targets: ["TracePresenter"] + ), + .executable( + name: "Example", + targets: ["Example", "Presenter"] + ) + ], + dependencies: [ + .package(name: "Charts", url: "https://github.com/spacenation/swiftui-charts.git", from: "1.0.0"), + ], + targets: [ + .target( + name: "Presenter", + dependencies: [] + ), + .target( + name: "ChartPresenter", + dependencies: ["Presenter", "Charts"] + ), + .target( + name: "MetricPresenter", + dependencies: ["ChartPresenter"] + ), + .target( + name: "TracePresenter", + dependencies: ["Presenter"] + ), + .testTarget( + name: "PresenterTests", + dependencies: ["Presenter", "ChartPresenter", "MetricPresenter", "TracePresenter"] + ), + .executableTarget( + name: "Example", + dependencies: ["Presenter"] + ) + ] +) + +#else let package = Package( name: "Presenter", - platforms: [.macOS(.v10_15), .watchOS(.v6), .tvOS(.v13), .iOS(.v13)], + platforms: [.iOS(.v13), .macOS(.v10_15), .tvOS(.v13), .watchOS(.v6)], products: [ .library( name: "Presenter", @@ -41,8 +81,13 @@ let package = Package( .library( name: "TracePresenter", targets: ["TracePresenter"] + ), + .executable( + name: "Example", + targets: ["Example", "Presenter"] ) - ] + exampleProduct, + ], + dependencies: [], targets: [ .target( name: "Presenter", @@ -63,6 +108,12 @@ let package = Package( .testTarget( name: "PresenterTests", dependencies: ["Presenter", "ChartPresenter", "MetricPresenter", "TracePresenter"] + ), + .executableTarget( + name: "Example", + dependencies: ["Presenter"] ) - ] + exampleTarget + ] ) + +#endif diff --git a/README.md b/README.md index 4017b3b..3fdbfe0 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,112 @@ # Presenter -## Requirements +The `Presenter` framework to encode, decode and use distributed user interfaces. While `Presenter` can be used on a server to encode user interfaces in a similar style to SwiftUI, it can be used on the client-side (iOS, watchOS, tvOS and macOS) to decode these user interfaces and display to the user using the SwiftUI framework. -## Installation/Setup/Integration +## Features + +- Create user interfaces on the server using a declarative DSL similar to SwiftUI +- Encode the user interface using the Codable API (e.g. to JSON) +- Decode the user interface using the Codable API (e.g. from JSON) +- Display the user interface using SwiftUI Components + +- Use local memory to store temporary state +- Interact with system functionality using local actions +- Create custom views, view modifiers and actions +- Add plugins with custom views, view modifiers and actions + +## Installation + +Presenter uses the Swift Package Manager. + +```swift +dependencies: [ + .package(url: "https://github.com/Apodini/Presenter.git", from: "0.1.0") +] +``` + +After specifying the package as a dependency, you can use it in your targets. + +```swift +targets: [ + .target( + name: "YourTarget", + dependencies: [ + .product(name: "Presenter", package: "Presenter") + ] + ) +] +``` ## Usage +### Server + +You can specify `Presenter` views similar to SwiftUI. + +```swift +struct LoginView: UserView { + + @State("login-username", default: "") var username + @State("login-password", default: "") var password + + var body: View { + VStack { + TextField("Username", text: $username) + SecureField("Password", text: $password) + Button(Text("Login"), action: LoginAction()) + } + .padding(16) + .background(Color(red: 1, green: 1, blue: 1)) + .shadow(radius: 8) + .padding(16) + } + +} +``` + +This example above already showcases some of the more complicated features of SwiftUI, including state management and local actions. + +### Client + +On the client side, `Presenter` uses `ServedView` to provide a SwiftUI interface from a url or a custom publisher. + +```swift +import Presenter +import SwiftUI + +struct ContentView: SwiftUI.View { + + @StateObject var model = Model() + + var body: some SwiftUI.View { + ServedView(url: URL(string: "..."), model: model) { state in + switch state { + case .empty: + Text("Empty") + case .loading: + Text("Loading") + case let .failure(error): + Text("Error: " + error.localizedDescription) + } + } + } + +} +``` + +When using plugins, custom views, custom view modifiers or actions, please make sure to register them during app start using `Presenter.use(plugin:)`, `Presenter.use(view:)`, `Presenter.use(modifier:)` or `Presenter.use(action:)` respectively. Tip: You can also create an app-specific plugin to register multiple views, view modifiers and actions at once. + ## Example -We provide a small example proejct to showcase Presenter. -Clone the repo, navigate in the root folder and start the example application using `swift run Example`. +We provide a small example project to showcase Presenter. + +Clone the repo, navigate in the root folder and start the example server application using `swift run Example`. +To check out how to use Presenter on the client side, see the [example client application](Example). ## Contributing + Contributions to this projects are welcome. Please make sure to read the [contribution guidelines](https://github.com/Apodini/.github/blob/release/CONTRIBUTING.md) first. ## License + This project is licensed under the MIT License. See [License](https://github.com/Apodini/Presenter/blob/release/LICENSE) for more information. diff --git a/Sources/ChartPresenter/Chart+AreaStyle.swift b/Sources/ChartPresenter/Chart+AreaStyle.swift index 40bb640..d19feb1 100644 --- a/Sources/ChartPresenter/Chart+AreaStyle.swift +++ b/Sources/ChartPresenter/Chart+AreaStyle.swift @@ -5,7 +5,7 @@ extension Chart { public internal(set) var lineType: LineType public internal(set) var fill: CoderView - public init(_ lineType: LineType, fill: Fill) { + public init(_ lineType: LineType, fill: View) { self.lineType = lineType self.fill = CoderView(fill) } diff --git a/Sources/ChartPresenter/Chart+Charts.swift b/Sources/ChartPresenter/Chart+Charts.swift index f039ecc..4e11fcd 100644 --- a/Sources/ChartPresenter/Chart+Charts.swift +++ b/Sources/ChartPresenter/Chart+Charts.swift @@ -3,23 +3,27 @@ extension Chart.Style { - func chart(for data: [[Double]]) -> AnyView { + @SwiftUI.ViewBuilder + func chart(for data: [[Double]]) -> some SwiftUI.View { switch self { case let .line(style): - return chart(data: data, style: style.chartsValue) + Charts.Chart(data: data) + .chartStyle(style.chartsValue) case let .area(style): - return chart(data: data, style: style.chartsValue) + Charts.Chart(data: data) + .chartStyle(style.chartsValue) case let .stackedArea(style): - return chart(data: data, style: style.chartsValue) + Charts.Chart(data: data) + .chartStyle(style.chartsValue) case let .column(style): - return chart(data: data, style: style.chartsValue) + Charts.Chart(data: data) + .chartStyle(style.chartsValue) } } - private func chart(data: [[Double]], style: Style) -> AnyView { + private func chart(data: [[Double]], style: Style) -> some SwiftUI.View { Charts.Chart(data: data) - .chartStyle(style) - .eraseToAnyView() + .chartStyle(style) } } @@ -72,12 +76,4 @@ extension Chart.LineType { } -extension SwiftUI.View { - - fileprivate func eraseToAnyView() -> AnyView { - AnyView(self) - } - -} - #endif diff --git a/Sources/ChartPresenter/Chart+ColumnStyle.swift b/Sources/ChartPresenter/Chart+ColumnStyle.swift index 002216b..74f406e 100644 --- a/Sources/ChartPresenter/Chart+ColumnStyle.swift +++ b/Sources/ChartPresenter/Chart+ColumnStyle.swift @@ -2,13 +2,15 @@ extension Chart { public struct ColumnStyle: Codable { + public internal(set) var column: CoderView public internal(set) var spacing: CGFloat - public init(column: Column, spacing: CGFloat) { + public init(column: View, spacing: CGFloat) { self.column = CoderView(column) self.spacing = spacing } + } } diff --git a/Sources/ChartPresenter/Chart+LineStyle.swift b/Sources/ChartPresenter/Chart+LineStyle.swift index cfbd24e..f47edfe 100644 --- a/Sources/ChartPresenter/Chart+LineStyle.swift +++ b/Sources/ChartPresenter/Chart+LineStyle.swift @@ -2,6 +2,7 @@ extension Chart { public struct LineStyle: Codable { + public internal(set) var lineType: LineType public internal(set) var color: ColorCode public internal(set) var width: CGFloat @@ -11,6 +12,7 @@ extension Chart { self.color = ColorCode(color) self.width = width } + } public enum LineType: String, Codable { diff --git a/Sources/ChartPresenter/Chart+StackedAreaStyle.swift b/Sources/ChartPresenter/Chart+StackedAreaStyle.swift index e0cb673..02f4a68 100644 --- a/Sources/ChartPresenter/Chart+StackedAreaStyle.swift +++ b/Sources/ChartPresenter/Chart+StackedAreaStyle.swift @@ -2,6 +2,7 @@ extension Chart { public struct StackedAreaStyle: Codable { + public internal(set) var lineType: LineType public internal(set) var colors: [ColorCode] @@ -9,6 +10,7 @@ extension Chart { self.lineType = lineType self.colors = colors.map(ColorCode.init) } + } } diff --git a/Sources/ChartPresenter/Chart+Style.swift b/Sources/ChartPresenter/Chart+Style.swift index 519b491..fb67fd6 100644 --- a/Sources/ChartPresenter/Chart+Style.swift +++ b/Sources/ChartPresenter/Chart+Style.swift @@ -9,6 +9,13 @@ extension Chart { case type } + private enum StyleKind: String, Codable { + case line + case area + case stackedArea + case column + } + // MARK: Cases case line(LineStyle) @@ -46,13 +53,13 @@ extension Chart { } switch kind { case .line: - self = .line(try LineStyle(from: decoder)) + self = try .line(LineStyle(from: decoder)) case .area: - self = .area(try AreaStyle(from: decoder)) + self = try .area(AreaStyle(from: decoder)) case .column: - self = .column(try ColumnStyle(from: decoder)) + self = try .column(ColumnStyle(from: decoder)) case .stackedArea: - self = .stackedArea(try StackedAreaStyle(from: decoder)) + self = try .stackedArea(StackedAreaStyle(from: decoder)) } } @@ -76,11 +83,4 @@ extension Chart { } - private enum StyleKind: String, Codable { - case line - case area - case stackedArea - case column - } - } diff --git a/Sources/ChartPresenter/Chart.swift b/Sources/ChartPresenter/Chart.swift index 3d1840b..717e14d 100644 --- a/Sources/ChartPresenter/Chart.swift +++ b/Sources/ChartPresenter/Chart.swift @@ -1,5 +1,5 @@ -public struct Chart: SwiftUIView { +public struct Chart: CodableView { // MARK: Stored Properties @@ -42,9 +42,9 @@ extension Chart: SwiftUI.View { #elseif canImport(SwiftUI) -extension Chart { +extension Chart: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { EmptyView() } diff --git a/Sources/ChartPresenter/UIservCharts.swift b/Sources/ChartPresenter/UIservCharts.swift index ed9f9e1..9a26de7 100644 --- a/Sources/ChartPresenter/UIservCharts.swift +++ b/Sources/ChartPresenter/UIservCharts.swift @@ -3,7 +3,7 @@ public struct ChartPresenter: Plugin { public init() {} - public var views: [_CodableView.Type] { + public var views: [CodableView.Type] { [ Chart.self, ] diff --git a/Sources/Example/App.swift b/Sources/Example/App.swift index 8041195..c94e401 100644 --- a/Sources/Example/App.swift +++ b/Sources/Example/App.swift @@ -19,11 +19,3 @@ struct ExampleApp: App { } } - - -struct ContentView_Provider: PreviewProvider { - static var previews: some SwiftUI.View { - ContentView().eraseToAnyView() - } -} - diff --git a/Sources/Example/ContentView.swift b/Sources/Example/ContentView.swift index d55e26d..c035e5a 100644 --- a/Sources/Example/ContentView.swift +++ b/Sources/Example/ContentView.swift @@ -3,11 +3,12 @@ import Presenter typealias PresenterModel = Model -struct ContentView: View { +struct ContentView: UserView { + @State("text", default: "") var text - - var body: some View { + var body: View { TextField("hallo", text: $text) } + } diff --git a/Sources/MetricPresenter/Card.swift b/Sources/MetricPresenter/Card.swift index d564521..c5482ed 100644 --- a/Sources/MetricPresenter/Card.swift +++ b/Sources/MetricPresenter/Card.swift @@ -1,5 +1,5 @@ -struct Card: AnyViewModifying { +struct Card: CodableViewModifier { // MARK: Stored Properties @@ -17,7 +17,7 @@ extension Card: CustomStringConvertible { #if canImport(SwiftUI) -extension Card: ViewModifier { +extension Card: SwiftUI.ViewModifier { #if os(macOS) @@ -53,8 +53,8 @@ extension SwiftUI.View { extension View { - public func card(cornerRadius: CGFloat? = nil) -> some View { - modified(using: Card(radius: cornerRadius)) + public func card(cornerRadius: CGFloat? = nil) -> View { + modifier(Card(radius: cornerRadius)) } } diff --git a/Sources/MetricPresenter/Gauge.swift b/Sources/MetricPresenter/Gauge.swift index f92e592..b61ed50 100644 --- a/Sources/MetricPresenter/Gauge.swift +++ b/Sources/MetricPresenter/Gauge.swift @@ -1,5 +1,5 @@ -public struct Gauge: View { +public struct Gauge: CodableWrapperView { // MARK: Stored Properties @@ -11,12 +11,12 @@ public struct Gauge: View { // MARK: Initialization - public init( + public init( value: CGFloat, thickness: CGFloat = 6, scale: CGFloat = 1.777, colors: [ColorCode], - @ViewBuilder content: () -> Content + @ViewBuilder content: () -> View ) { self.value = value self.thickness = thickness @@ -27,9 +27,9 @@ public struct Gauge: View { // MARK: Views - public var body: some View { + public var body: View { content - .modified(using: + .modifier( GaugeModifier( value: value, thickness: thickness, @@ -41,7 +41,7 @@ public struct Gauge: View { } -struct GaugeModifier: AnyViewModifying { +struct GaugeModifier: CodableViewModifier { var value: CGFloat var thickness: CGFloat @@ -63,7 +63,7 @@ private struct GaugeView: SwiftUI.View { var gradient: SwiftUI.AngularGradient { .init( - gradient: .init(colors: gauge.colors.map { $0.color.view }), + gradient: .init(colors: gauge.colors.map { $0.color.body }), center: .center, startAngle: .degrees(0), endAngle: .degrees(270) @@ -110,7 +110,7 @@ private struct GaugeView: SwiftUI.View { } -extension GaugeModifier: ViewModifier { +extension GaugeModifier: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { GaugeView(gauge: self, content: content) diff --git a/Sources/MetricPresenter/Graph+Labeling.swift b/Sources/MetricPresenter/Graph+Labeling.swift index ac05f05..f9f83e8 100644 --- a/Sources/MetricPresenter/Graph+Labeling.swift +++ b/Sources/MetricPresenter/Graph+Labeling.swift @@ -19,7 +19,7 @@ extension Graph { } -extension Graph.Labeling: ViewModifier { +extension Graph.Labeling: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { GeometryReader { geometry in diff --git a/Sources/MetricPresenter/Graph.swift b/Sources/MetricPresenter/Graph.swift index bc6bab3..472164e 100644 --- a/Sources/MetricPresenter/Graph.swift +++ b/Sources/MetricPresenter/Graph.swift @@ -1,5 +1,5 @@ -public struct Graph: SwiftUIView { +public struct Graph: CodableView { // MARK: Nested Types @@ -103,9 +103,9 @@ extension Graph.DataSet { } -extension Graph { +extension Graph: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { content .graphGrid( vertical: verticalGridValues, diff --git a/Sources/MetricPresenter/MetricCard.swift b/Sources/MetricPresenter/MetricCard.swift index 65976dd..0ca5c0e 100644 --- a/Sources/MetricPresenter/MetricCard.swift +++ b/Sources/MetricPresenter/MetricCard.swift @@ -1,5 +1,5 @@ -struct MetricCard: AnyViewModifying { +struct MetricCard: CodableViewModifier { // MARK: Stored Properties @@ -10,7 +10,7 @@ struct MetricCard: AnyViewModifying { #if canImport(SwiftUI) -extension MetricCard: ViewModifier { +extension MetricCard: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { SwiftUI.VStack(alignment: .leading) { @@ -43,8 +43,8 @@ extension MetricCard: ViewModifier { extension View { - public func metricCard(title: String, subtitle: String) -> some View { - modified(using: MetricCard(title: title, subtitle: subtitle)) + public func metricCard(title: String, subtitle: String) -> View { + modifier(MetricCard(title: title, subtitle: subtitle)) } } diff --git a/Sources/MetricPresenter/MetricPresenter.swift b/Sources/MetricPresenter/MetricPresenter.swift index 79728a0..4f12a43 100644 --- a/Sources/MetricPresenter/MetricPresenter.swift +++ b/Sources/MetricPresenter/MetricPresenter.swift @@ -3,13 +3,13 @@ public struct MetricPresenter: Plugin { public init() {} - public var views: [_CodableView.Type] { + public var views: [CodableView.Type] { [ Graph.self, ] } - public var viewModifiers: [AnyViewModifying.Type] { + public var viewModifiers: [CodableViewModifier.Type] { [ GaugeModifier.self, MetricCard.self, diff --git a/Sources/Presenter/Configuration/Configuration+Plugin.swift b/Sources/Presenter/Configuration/Configuration+Plugin.swift index 33bc94b..b60ca70 100644 --- a/Sources/Presenter/Configuration/Configuration+Plugin.swift +++ b/Sources/Presenter/Configuration/Configuration+Plugin.swift @@ -7,7 +7,7 @@ extension Presenter { // MARK: Plugins - static func usePlugins() { + internal static func usePlugins() { guard !didImportPlugins else { return } didImportPlugins = true use(plugin: DefaultPlugin()) @@ -33,25 +33,25 @@ extension Presenter { } -extension _View where Self: Codable { +extension View where Self: Codable { - static func use() { + fileprivate static func use() { Presenter.use(view: Self.self) } - static func remove() { + fileprivate static func remove() { Presenter.remove(view: Self.self) } } -extension AnyViewModifying { +extension ViewModifier where Self: Codable { - static func use() { + fileprivate static func use() { Presenter.use(modifier: Self.self) } - static func remove() { + fileprivate static func remove() { Presenter.remove(modifier: Self.self) } @@ -59,11 +59,11 @@ extension AnyViewModifying { extension Action { - static func use() { + fileprivate static func use() { Presenter.use(action: Self.self) } - static func remove() { + fileprivate static func remove() { Presenter.remove(action: Self.self) } @@ -71,11 +71,11 @@ extension Action { extension Plugin { - func use() { + fileprivate func use() { Presenter.use(plugin: self) } - func remove() { + fileprivate func remove() { Presenter.remove(plugin: self) } diff --git a/Sources/Presenter/Configuration/Configuration+Use.swift b/Sources/Presenter/Configuration/Configuration+Use.swift index c46d22a..1d1838a 100644 --- a/Sources/Presenter/Configuration/Configuration+Use.swift +++ b/Sources/Presenter/Configuration/Configuration+Use.swift @@ -3,21 +3,21 @@ extension Presenter { // MARK: View - public static func use(view: View.Type) { - CoderView.register(View.self) + public static func use(view: V.Type) { + CoderView.register(V.self) } - public static func remove(view: View.Type) { - CoderView.unregister(View.self) + public static func remove(view: V.Type) { + CoderView.unregister(V.self) } // MARK: View Modifier - public static func use(modifier: Modifier.Type) { + public static func use(modifier: Modifier.Type) { CoderViewModifier.register(Modifier.self) } - public static func remove(modifier: Modifier.Type) { + public static func remove(modifier: Modifier.Type) { CoderViewModifier.unregister(Modifier.self) } diff --git a/Sources/Presenter/Configuration/Configuration.swift b/Sources/Presenter/Configuration/Configuration.swift index f059666..f4ec8c3 100644 --- a/Sources/Presenter/Configuration/Configuration.swift +++ b/Sources/Presenter/Configuration/Configuration.swift @@ -6,7 +6,7 @@ public enum Presenter { public static func decode( from data: Data, decoder: JSONDecoder = .init() - ) throws -> some View { + ) throws -> View { try decoder.decode(CoderView.self, from: data) } @@ -16,7 +16,7 @@ public enum Presenter { public static func decode( from data: Decoder.Input, decoder: Decoder - ) throws -> some View { + ) throws -> View { try decoder.decode(CoderView.self, from: data) } @@ -25,8 +25,8 @@ public enum Presenter { // MARK: Encoding - public static func encode( - _ view: V, + public static func encode( + _ view: View, encoder: JSONEncoder = .init() ) throws -> Data { @@ -35,8 +35,8 @@ public enum Presenter { #if canImport(Combine) - public static func encode( - _ view: V, + public static func encode( + _ view: View, encoder: Encoder ) throws -> Encoder.Output { diff --git a/Sources/Presenter/Configuration/DefaultPlugin.swift b/Sources/Presenter/Configuration/DefaultPlugin.swift index c8a6bee..a63d58a 100644 --- a/Sources/Presenter/Configuration/DefaultPlugin.swift +++ b/Sources/Presenter/Configuration/DefaultPlugin.swift @@ -3,7 +3,7 @@ import Foundation struct DefaultPlugin: Plugin { - var views: [_CodableView.Type] { + var views: [CodableView.Type] { [ AngularGradient.self, Button.self, @@ -42,7 +42,7 @@ struct DefaultPlugin: Plugin { ] } - var viewModifiers: [AnyViewModifying.Type] { + var viewModifiers: [CodableViewModifier.Type] { [ AccentColor.self, AnimationModifier.self, diff --git a/Sources/Presenter/Configuration/NamedType.swift b/Sources/Presenter/Configuration/NamedType.swift index 5524c17..1130f81 100644 --- a/Sources/Presenter/Configuration/NamedType.swift +++ b/Sources/Presenter/Configuration/NamedType.swift @@ -1,6 +1,4 @@ -import Foundation - public protocol NamedType { static var type: String { get } } diff --git a/Sources/Presenter/Configuration/Plugin.swift b/Sources/Presenter/Configuration/Plugin.swift index e841802..8f0e005 100644 --- a/Sources/Presenter/Configuration/Plugin.swift +++ b/Sources/Presenter/Configuration/Plugin.swift @@ -7,8 +7,8 @@ public protocol Plugin { func willRemove() func didRemove() - var views: [_CodableView.Type] { get } - var viewModifiers: [AnyViewModifying.Type] { get } + var views: [CodableView.Type] { get } + var viewModifiers: [CodableViewModifier.Type] { get } var actions: [Action.Type] { get } var plugins: [Plugin] { get } @@ -22,8 +22,8 @@ extension Plugin { public func willRemove() {} public func didRemove() {} - public var views: [_CodableView.Type] { [] } - public var viewModifiers: [AnyViewModifying.Type] { [] } + public var views: [CodableView.Type] { [] } + public var viewModifiers: [CodableViewModifier.Type] { [] } public var actions: [Action.Type] { [] } public var plugins: [Plugin] { [] } diff --git a/Sources/Presenter/Model/CopyAction.swift b/Sources/Presenter/Model/CopyAction.swift index 28acbcb..5b7953a 100644 --- a/Sources/Presenter/Model/CopyAction.swift +++ b/Sources/Presenter/Model/CopyAction.swift @@ -18,7 +18,7 @@ public struct CopyAction: Action { #if canImport(SwiftUI) public func perform(on model: Model) { - model.state[to] = model.state[from] + model.set(to, to: model.get(from)) } #endif diff --git a/Sources/Presenter/Model/JavaScriptAction.swift b/Sources/Presenter/Model/JavaScriptAction.swift index 2747a65..8fb81b9 100644 --- a/Sources/Presenter/Model/JavaScriptAction.swift +++ b/Sources/Presenter/Model/JavaScriptAction.swift @@ -39,19 +39,20 @@ public struct JavaScriptAction: Action { } context.exceptionHandler = { context, value in - model.state[errorKey] = value?.toObject() + model.set(errorKey, to: value?.toObject()) } for (key, name) in zip(inputKeys, inputNames) { - context.setObject(model.state[key], forKeyedSubscript: name as NSString) + context.setObject(model.get(key), forKeyedSubscript: name as NSString) } let functionName = "$_xyz_abc_javascript_action_main_function_cba_xyz_$_$" context.evaluateScript("function " + functionName + "() {\n" + script + "\n}") - model.state[resultKey] = context + let result = context .objectForKeyedSubscript(functionName) .call(withArguments: []) .toObject() + model.set(resultKey, to: result) #else diff --git a/Sources/Presenter/Model/Model.swift b/Sources/Presenter/Model/Model.swift index fc8c842..5c76bc9 100644 --- a/Sources/Presenter/Model/Model.swift +++ b/Sources/Presenter/Model/Model.swift @@ -1,11 +1,11 @@ #if canImport(SwiftUI) -public final class Model: ObservableObject { +public class Model: ObservableObject { // MARK: Stored Properties - @Published public var state: [String: Any] = [:] + @Published private var state = [String: Any]() // MARK: Initialization @@ -36,12 +36,12 @@ public final class Model: ObservableObject { { _ in action?.perform(on: self) } } - func get(key: String, for object: AnyObject) -> Any? { - state["\(ObjectIdentifier(object))_\(key)"] + public func get(_ key: String) -> Any? { + state[key] } - func set(_ any: Any?, key: String, for object: AnyObject) { - state["\(ObjectIdentifier(object))_\(key)"] = any + public func set(_ key: String, to value: Any?) { + state[key] = value } } diff --git a/Sources/Presenter/Model/ModelView.swift b/Sources/Presenter/Model/ModelView.swift index e149aaa..f42cd7c 100644 --- a/Sources/Presenter/Model/ModelView.swift +++ b/Sources/Presenter/Model/ModelView.swift @@ -1,23 +1,23 @@ #if canImport(SwiftUI) -public struct ModelView: SwiftUI.View { +public struct ModelView: SwiftUI.View { // MARK: Stored Properties @EnvironmentObject var model: Model - let create: (Model) -> V + let create: (Model) -> Body // MARK: Initialization - public init(create: @escaping (Model) -> V) { + public init(@SwiftUI.ViewBuilder create: @escaping (Model) -> Body) { self.create = create } // MARK: Views - public var body: V { + public var body: Body { create(model) } diff --git a/Sources/Presenter/Model/SetAction.swift b/Sources/Presenter/Model/SetAction.swift index 36b27e3..9af3d57 100644 --- a/Sources/Presenter/Model/SetAction.swift +++ b/Sources/Presenter/Model/SetAction.swift @@ -18,7 +18,7 @@ public struct SetAction: Action { #if canImport(SwiftUI) public func perform(on model: Model) { - model.state[key] = value + model.set(key, to: value) } #endif diff --git a/Sources/Presenter/Model/Value.swift b/Sources/Presenter/Model/Value.swift index cf9a228..ab0971f 100644 --- a/Sources/Presenter/Model/Value.swift +++ b/Sources/Presenter/Model/Value.swift @@ -11,7 +11,7 @@ public struct Value: Codable { #if canImport(SwiftUI) public func get(from model: Model) -> Content { - key.flatMap { model.state[$0] as? Content } ?? self.default + key.flatMap { model.get($0) as? Content } ?? self.default } #endif diff --git a/Sources/Presenter/Types/Gradient.swift b/Sources/Presenter/Types/Gradient.swift index 0c0ca3b..769be32 100644 --- a/Sources/Presenter/Types/Gradient.swift +++ b/Sources/Presenter/Types/Gradient.swift @@ -61,7 +61,7 @@ extension Gradient { extension Gradient.Stop { var swiftUIValue: SwiftUI.Gradient.Stop { - .init(color: color.view, location: location) + .init(color: color.body, location: location) } } diff --git a/Sources/Presenter/View - General/CoderView.swift b/Sources/Presenter/View - General/CoderView.swift index 1fa8ac6..f8188b6 100644 --- a/Sources/Presenter/View - General/CoderView.swift +++ b/Sources/Presenter/View - General/CoderView.swift @@ -1,5 +1,5 @@ -public struct CoderView: Codable { +public struct CoderView: CodableView { // MARK: Nested Types @@ -10,32 +10,34 @@ public struct CoderView: Codable { private enum Error: Swift.Error { case unregisteredType(String) - case unexpectedType(_View.Type, expected: _View.Type) + case unexpectedType(View.Type, expected: View.Type) } // MARK: Stored Properties - public let element: _View + public let body: View // MARK: Initialization - public init(_ element: _CodableView) { - if let body = element.erasedCodableBody, - Self.registeredTypes[Swift.type(of: element).type] == nil { - self.init(body) + public init(_ element: View) { + if let coderView = element as? CoderView { + self.init(coderView.body) + } else if Self.registeredTypes[Swift.type(of: element).type] == nil, + let userView = element as? UserView { + self.init(userView.body) } else { self.init(last: element) } } - private init(last element: _CodableView) { - self.element = element + private init(last element: View) { + self.body = element } public init(from decoder: Decoder) throws { if let singleValueContainer = try? decoder.singleValueContainer() { guard !singleValueContainer.decodeNil() else { - self.element = Nil() + self.body = Nil() return } } @@ -45,7 +47,7 @@ public struct CoderView: Codable { while !unkeyedContainer.isAtEnd { content.append(try unkeyedContainer.decode(CoderView.self)) } - self.element = ArrayView(content: content) + self.body = ArrayView(content: content) return } @@ -60,18 +62,18 @@ public struct CoderView: Codable { if container.contains(.modifiers) { let modifiers = try container.decode([CoderViewModifier].self, forKey: .modifiers) - self.element = ComposedView(content: CoderView(element as! _CodableView), modifiers: modifiers) + self.body = ComposedView(content: CoderView(element), modifiers: modifiers) } else { - self.element = element + self.body = element } } // MARK: Methods public func encode(to encoder: Encoder) throws { - let typeDescription = Swift.type(of: element).type + let typeDescription = Swift.type(of: body).type - if let arrayView = element as? ArrayView { + if let arrayView = body as? ArrayView { var container = encoder.unkeyedContainer() for content in arrayView.content { try container.encode(content) @@ -88,12 +90,12 @@ public struct CoderView: Codable { try container.encode(typeDescription, forKey: .type) } - if let composedView = element as? ComposedView { + if let composedView = body as? ComposedView { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(composedView.modifiers, forKey: .modifiers) try composedView.content.encode(to: encoder) } else { - try coder.encode(element, encoder) + try coder.encode(body, encoder) } } @@ -107,8 +109,8 @@ extension CoderView { private struct Coder { var isOptional: Bool - var decode: (Decoder) throws -> _View - var encode: (_View, Encoder) throws -> Void + var decode: (Decoder) throws -> View + var encode: (View, Encoder) throws -> Void } // MARK: Static Properties @@ -131,26 +133,26 @@ extension CoderView { // MARK: Static Functions - internal static func register(_: View.Type) { - let isOptional = View.type.hasPrefix("Optional<") + internal static func register(_: V.Type) { + let isOptional = V.type.hasPrefix("Optional<") if !isOptional { - register(Optional.self) + register(Optional.self) } let coder = Coder( isOptional: isOptional, - decode: { decoder in try View(from: decoder) }, + decode: { decoder in try V(from: decoder) }, encode: { view, encoder in - guard let viewView = view as? View else { - throw Error.unexpectedType(Swift.type(of: view), expected: View.self) + guard let viewView = view as? V else { + throw Error.unexpectedType(Swift.type(of: view), expected: V.self) } try viewView.encode(to: encoder) } ) - registeredTypes.updateValue(coder, forKey: View.type) + registeredTypes.updateValue(coder, forKey: V.type) } - internal static func unregister(_: View.Type) { - registeredTypes.removeValue(forKey: View.type) + internal static func unregister(_: V.Type) { + registeredTypes.removeValue(forKey: V.type) } } @@ -160,21 +162,23 @@ extension CoderView { extension CoderView: CustomStringConvertible { public var description: String { - "\(element)" + "\(body)" } } -// MARK: - InternalView +#if canImport(SwiftUI) -extension CoderView: InternalView { - - #if canImport(SwiftUI) +extension CoderView { - public var view: _View { - element + public func eraseToAnyView() -> AnyView { + body.eraseToAnyView() } - #endif + public func apply(_ modifier: Modifier) -> View { + body.apply(modifier) + } } + +#endif diff --git a/Sources/Presenter/View - General/InternalView.swift b/Sources/Presenter/View - General/InternalView.swift deleted file mode 100644 index 103b350..0000000 --- a/Sources/Presenter/View - General/InternalView.swift +++ /dev/null @@ -1,32 +0,0 @@ - -public protocol InternalView: View where Body == Never { - - #if canImport(SwiftUI) - var view: _View { get } - #endif - -} - -extension InternalView { - - public var body: Never { - fatalError() - } - - #if canImport(SwiftUI) - - public func eraseToAnyView() -> AnyView { - view.eraseToAnyView() - } - - public func apply(_ modifier: M) -> _View { - view.apply(modifier) - } - - public func apply(_ modifier: AnyViewModifying) -> _View { - view.apply(modifier) - } - - #endif - -} diff --git a/Sources/Presenter/View - General/ServedView.swift b/Sources/Presenter/View - General/ServedView.swift index 19ba91b..ee61549 100644 --- a/Sources/Presenter/View - General/ServedView.swift +++ b/Sources/Presenter/View - General/ServedView.swift @@ -1,55 +1,146 @@ #if canImport(SwiftUI) && canImport(Combine) -public struct ServedView: SwiftUI.View { +public struct ServedView: SwiftUI.View { + + // MARK: Nested Types + + public enum PlaceholderState { + case empty + case loading + case failure(Error) + } + + private enum State { + case empty + case loading + case success(AnyView) + case failure(Error) + } // MARK: Stored Properties - public let url: URL? - @ObservedObject var model: Model + private let publisher: AnyPublisher? + private let placeholder: (PlaceholderState) -> Placeholder + @ObservedObject private var model: Model // MARK: State - @SwiftUI.State private var didStartLoading = false - @SwiftUI.State private var view: AnyView? + @SwiftUI.State private var state = State.empty @SwiftUI.State private var cancellables = Set() // MARK: Initialization - public init(url: URL?, model: Model) { - self.url = url + public init( + url: URL?, + session: URLSession = .shared, + model: Model, + @SwiftUI.ViewBuilder placeholder: @escaping (PlaceholderState) -> Placeholder + ) { + + guard let url = url else { + self.init( + dataPublisher: nil as AnyPublisher?, + model: model, + placeholder: placeholder + ) + return + } + + if url.isFileURL { + self.init( + dataPublisher: Just(url).tryMap { try Data(contentsOf: $0) }, + model: model, + placeholder: placeholder + ) + } else { + self.init( + dataPublisher: session.dataTaskPublisher(for: url) + .tryMap { data, response -> Data in + guard let httpResponse = response as? HTTPURLResponse, + httpResponse.statusCode == 200 else { + throw URLError(.badServerResponse) + } + return data + }, + model: model, + placeholder: placeholder + ) + } + } + + public init( + dataPublisher: P?, + model: Model, + @SwiftUI.ViewBuilder placeholder: @escaping (PlaceholderState) -> Placeholder + ) where P.Output == Data { + + let viewPublisher = dataPublisher? + .tryMap { try Presenter.decode(from: $0).eraseToAnyView() } + + self.init( + viewPublisher: viewPublisher, + model: model, + placeholder: placeholder + ) + } + + public init( + viewPublisher: P?, + model: Model, + @SwiftUI.ViewBuilder placeholder: @escaping (PlaceholderState) -> Placeholder + ) where P.Output == AnyView { + + self.publisher = viewPublisher? + .mapError { $0 as Error } + .eraseToAnyPublisher() + self.model = model + self.placeholder = placeholder } // MARK: Views public var body: some SwiftUI.View { - view - .environmentObject(model) - .onAppear(perform: load) + content + .environmentObject(model) + .onAppear(perform: load) + } + + @SwiftUI.ViewBuilder + private var content: some SwiftUI.View { + switch state { + case .empty: + placeholder(.empty) + case .loading: + placeholder(.loading) + case let .success(view): + view + case let .failure(error): + placeholder(.failure(error)) + } } // MARK: Helpers private func load() { - guard let url = url, !didStartLoading else { return } - didStartLoading = true - guard !url.isFileURL else { - if let data = try? Data(contentsOf: url), - let view = try? Presenter.decode(from: data) { - self.view = view.eraseToAnyView() - } + switch state { + case .success, .failure, .loading: return + case .empty: + guard let publisher = publisher else { + return + } + + state = .loading + + publisher + .map { State.success($0) } + .catch { Just(.failure($0)) } + .receive(on: DispatchQueue.main) + .assign(to: \.state, on: self) + .store(in: &cancellables) } - URLSession.shared.dataTaskPublisher(for: url) - .map(\.data) - .decode(type: CoderView.self, decoder: JSONDecoder()) - .map(Optional.some) - .replaceError(with: nil) - .map { $0?.eraseToAnyView() } - .receive(on: DispatchQueue.main) - .assign(to: \.view, on: self) - .store(in: &cancellables) } } diff --git a/Sources/Presenter/View - General/SwiftUIView.swift b/Sources/Presenter/View - General/SwiftUIView.swift deleted file mode 100644 index 4942666..0000000 --- a/Sources/Presenter/View - General/SwiftUIView.swift +++ /dev/null @@ -1,33 +0,0 @@ - -public protocol SwiftUIView: View where Body == Never { - - #if canImport(SwiftUI) - associatedtype SwiftUIBody: SwiftUI.View - var view: SwiftUIBody { get } - #endif - -} - -extension SwiftUIView { - - public var body: Never { - fatalError() - } - - #if canImport(SwiftUI) - - public func eraseToAnyView() -> AnyView { - AnyView(view) - } - - public func apply(_ modifier: M) -> _View { - view.modifier(modifier) - } - - public func apply(_ modifier: AnyViewModifying) -> _View { - modifier.apply(to: view) - } - - #endif - -} diff --git a/Sources/Presenter/View - General/View.swift b/Sources/Presenter/View - General/View.swift index de0d965..bd6a41f 100644 --- a/Sources/Presenter/View - General/View.swift +++ b/Sources/Presenter/View - General/View.swift @@ -1,88 +1,63 @@ -public typealias _CodableView = _View & Codable +public typealias CodableView = View & Decodable -public protocol _View: NamedType { - - var erasedCodableBody: _CodableView? { get } +public protocol View: NamedType, Encodable { #if canImport(SwiftUI) - func eraseToAnyView() -> AnyView - func apply(_ m: M) -> _View - func apply(_ modifier: AnyViewModifying) -> _View + func apply(_ modifier: Modifier) -> View + #endif + +} + +public typealias CodableWrapperView = WrapperView & Decodable +public protocol WrapperView: View { + + #if canImport(SwiftUI) + var body: View { get } #endif } -#if canImport(SwiftUI) +extension WrapperView { -extension _View where Self: SwiftUI.View { + #if canImport(SwiftUI) public func eraseToAnyView() -> AnyView { - AnyView(self) - } - - public func apply(_ m: M) -> _View { - modifier(m) + body.eraseToAnyView() } - public func apply(_ modifier: AnyViewModifying) -> _View { - modifier.apply(to: self) + public func apply(_ modifier: Modifier) -> View { + body.apply(modifier) } -} - -#endif - + #endif -public protocol View: _View, Codable { - associatedtype Body: View - var body: Body { get } } -extension Never: View { - - public var body: Never { - get { - fatalError("This can't happen.") - } - } - - public init(from decoder: Decoder) throws { - fatalError() - } +public protocol UserView: WrapperView { - public func encode(to encoder: Encoder) throws { - switch self {} - } + var body: View { get } } -extension View { +extension UserView { - public var erasedCodableBody: _CodableView? { - Body.self == Never.self ? nil : body + func encode(to encoder: Encoder) throws { + try body.encode(to: encoder) } } -#if canImport(SwiftUI) - -extension View { +extension View where Self: SwiftUI.View { public func eraseToAnyView() -> AnyView { - body.eraseToAnyView() - } - - public func apply(_ modifier: M) -> _View { - body.apply(modifier) + AnyView(self) } - public func apply(_ modifier: AnyViewModifying) -> _View { - body.apply(modifier) + public func apply(_ modifier: Modifier) -> View { + modifier.body(for: self) } } - -#endif diff --git a/Sources/Presenter/View - General/ViewBuilder.swift b/Sources/Presenter/View - General/ViewBuilder.swift index f63b545..e44444f 100644 --- a/Sources/Presenter/View - General/ViewBuilder.swift +++ b/Sources/Presenter/View - General/ViewBuilder.swift @@ -4,27 +4,27 @@ public struct ViewBuilder { // MARK: Static Functions - public static func buildBlock(_ item: V) -> some View { + public static func buildBlock(_ item: V) -> View { item } - public static func buildBlock(_ items: _CodableView...) -> some View { + public static func buildBlock(_ items: View...) -> View { ArrayView(content: items) } - public static func buildBlock(_ items: [_CodableView]) -> some View { + public static func buildBlock(_ items: [View]) -> View { ArrayView(content: items) } - public static func buildEither(first: V) -> V { + public static func buildEither(first: View) -> View { first } - public static func buildEither(second: V) -> V { + public static func buildEither(second: View) -> View { second } - static func buildIf(_ content: V?) -> V? { + static func buildIf(_ content: View?) -> View? { content } diff --git a/Sources/Presenter/ViewModifier - General/AnyViewModifying.swift b/Sources/Presenter/ViewModifier - General/AnyViewModifying.swift deleted file mode 100644 index 6eecb8e..0000000 --- a/Sources/Presenter/ViewModifier - General/AnyViewModifying.swift +++ /dev/null @@ -1,30 +0,0 @@ - -public protocol AnyViewModifying: Codable, NamedType { - - #if canImport(SwiftUI) - - func apply(to view: V) -> _View - - #endif - -} - -#if canImport(SwiftUI) - -extension AnyViewModifying where Self: ViewModifier { - - public func apply(to view: V) -> _View { - view.modifier(self) - } - -} - -extension ModifiedContent: _View, NamedType where Content: SwiftUI.View, Modifier: ViewModifier { - - public var erasedCodableBody: _CodableView? { - nil - } - -} - -#endif diff --git a/Sources/Presenter/ViewModifier - General/CoderViewModifier.swift b/Sources/Presenter/ViewModifier - General/CoderViewModifier.swift index bc394f3..752db2c 100644 --- a/Sources/Presenter/ViewModifier - General/CoderViewModifier.swift +++ b/Sources/Presenter/ViewModifier - General/CoderViewModifier.swift @@ -1,5 +1,5 @@ -public struct CoderViewModifier: Codable, AnyViewModifying { +public struct CoderViewModifier: CodableViewModifier { // MARK: Nested Types @@ -10,16 +10,16 @@ public struct CoderViewModifier: Codable, AnyViewModifying { private enum Error: Swift.Error { case unregisteredType(String) - case unexpectedType(AnyViewModifying.Type, expected: AnyViewModifying.Type) + case unexpectedType(ViewModifier.Type, expected: ViewModifier.Type) } // MARK: Stored Properties - let element: AnyViewModifying + let element: ViewModifier // MARK: Initialization - internal init(_ element: AnyViewModifying) { + internal init(_ element: ViewModifier) { self.element = element } @@ -65,8 +65,8 @@ extension CoderViewModifier { // MARK: Nested Types private struct Coder { - var decode: (Decoder) throws -> AnyViewModifying - var encode: (AnyViewModifying, Encoder) throws -> Void + var decode: (Decoder) throws -> ViewModifier + var encode: (ViewModifier, Encoder) throws -> Void } // MARK: Static Properties @@ -89,7 +89,7 @@ extension CoderViewModifier { // MARK: Static Functions - public static func register(_: Modifier.Type) { + public static func register(_: Modifier.Type) { let coder = Coder( decode: { decoder in try Modifier(from: decoder) }, encode: { modifier, encoder in @@ -102,7 +102,7 @@ extension CoderViewModifier { registeredTypes.updateValue(coder, forKey: Modifier.type) } - public static func unregister(_: Modifier.Type) { + public static func unregister(_: Modifier.Type) { registeredTypes.removeValue(forKey: Modifier.type) } @@ -114,8 +114,8 @@ extension CoderViewModifier { extension CoderViewModifier { - public func apply(to view: V) -> _View { - element.apply(to: view) + public func body(for content: Content) -> View { + element.body(for: content) } } diff --git a/Sources/Presenter/ViewModifier - General/ViewModifier.swift b/Sources/Presenter/ViewModifier - General/ViewModifier.swift new file mode 100644 index 0000000..5b14e03 --- /dev/null +++ b/Sources/Presenter/ViewModifier - General/ViewModifier.swift @@ -0,0 +1,48 @@ + +public typealias CodableViewModifier = Codable & ViewModifier + +public protocol ViewModifier: NamedType { + + #if canImport(SwiftUI) + + func body(for content: Content) -> View + + #endif + +} + +#if canImport(SwiftUI) + +extension ViewModifier where Self: SwiftUI.ViewModifier { + + public func body(for content: Content) -> View { + content.modifier(self) + } + +} + +extension ModifiedContent: View, Encodable, NamedType + where Content: SwiftUI.View, Modifier: SwiftUI.ViewModifier { + + public func encode(to encoder: Encoder) throws { + guard let content = content as? View, + let modifier = modifier as? ViewModifier else { + assertionFailure("Why?") + return + } + try modifier.encode(with: content, to: encoder) + } + +} + +extension ViewModifier { + + fileprivate func encode(with view: View, to encoder: Encoder) throws { + try CoderView(view) + .modifier(self) + .encode(to: encoder) + } + +} + +#endif diff --git a/Sources/Presenter/ViewModifiers/AccentColor.swift b/Sources/Presenter/ViewModifiers/AccentColor.swift index 993d4d2..0f0fc9d 100644 --- a/Sources/Presenter/ViewModifiers/AccentColor.swift +++ b/Sources/Presenter/ViewModifiers/AccentColor.swift @@ -1,5 +1,5 @@ -internal struct AccentColor: AnyViewModifying { +internal struct AccentColor: CodableViewModifier { // MARK: Stored Properties @@ -21,7 +21,7 @@ extension AccentColor: CustomStringConvertible { #if canImport(SwiftUI) -extension AccentColor: ViewModifier { +extension AccentColor: SwiftUI.ViewModifier { #if os(macOS) @@ -32,7 +32,7 @@ extension AccentColor: ViewModifier { #else func body(content: Content) -> some SwiftUI.View { - content.accentColor(color.color.view) + content.accentColor(color.color.body) } #endif @@ -44,8 +44,8 @@ extension AccentColor: ViewModifier { extension View { - public func accentColor(_ color: Color) -> some View { - modified(using: AccentColor(color: ColorCode(color))) + public func accentColor(_ color: Color) -> View { + modifier(AccentColor(color: ColorCode(color))) } } diff --git a/Sources/Presenter/ViewModifiers/AnimationModifier.swift b/Sources/Presenter/ViewModifiers/AnimationModifier.swift index 441591c..140cc5a 100644 --- a/Sources/Presenter/ViewModifiers/AnimationModifier.swift +++ b/Sources/Presenter/ViewModifiers/AnimationModifier.swift @@ -1,5 +1,5 @@ -internal struct AnimationModifier: AnyViewModifying { +internal struct AnimationModifier: CodableViewModifier { // MARK: Stored Properties @@ -21,7 +21,7 @@ extension AnimationModifier: CustomStringConvertible { #if canImport(SwiftUI) -extension AnimationModifier: ViewModifier { +extension AnimationModifier: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { content.animation(animation.animation) @@ -35,8 +35,8 @@ extension AnimationModifier: ViewModifier { extension View { - public func animation(_ animation: Animation?) -> some View { - modified(using: AnimationModifier(animation: animation ?? .none)) + public func animation(_ animation: Animation?) -> View { + modifier(AnimationModifier(animation: animation ?? .none)) } } diff --git a/Sources/Presenter/ViewModifiers/AspectRatio.swift b/Sources/Presenter/ViewModifiers/AspectRatio.swift index f3030a1..1471b5b 100644 --- a/Sources/Presenter/ViewModifiers/AspectRatio.swift +++ b/Sources/Presenter/ViewModifiers/AspectRatio.swift @@ -4,7 +4,7 @@ public enum ContentMode: String, Codable { case fill } -internal struct AspectRatio: AnyViewModifying { +internal struct AspectRatio: CodableViewModifier { // MARK: Stored Properties @@ -36,7 +36,7 @@ extension AspectRatio: CustomStringConvertible { #if canImport(SwiftUI) -extension AspectRatio: ViewModifier { +extension AspectRatio: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { content.aspectRatio(ratio, contentMode: contentMode.swiftUIValue) @@ -63,20 +63,20 @@ extension ContentMode { extension View { - public func aspectRatio(_ ratio: CGSize, contentMode: ContentMode) -> some View { - modified(using: AspectRatio(ratio: ratio.width / ratio.height, contentMode: contentMode)) + public func aspectRatio(_ ratio: CGSize, contentMode: ContentMode) -> View { + modifier(AspectRatio(ratio: ratio.width / ratio.height, contentMode: contentMode)) } - public func aspectRatio(_ ratio: CGFloat?, contentMode: ContentMode) -> some View { - modified(using: AspectRatio(ratio: ratio, contentMode: contentMode)) + public func aspectRatio(_ ratio: CGFloat?, contentMode: ContentMode) -> View { + modifier(AspectRatio(ratio: ratio, contentMode: contentMode)) } - public func scaledToFit() -> some View { - modified(using: AspectRatio(ratio: nil, contentMode: .fit)) + public func scaledToFit() -> View { + modifier(AspectRatio(ratio: nil, contentMode: .fit)) } - public func scaledToFill() -> some View { - modified(using: AspectRatio(ratio: nil, contentMode: .fill)) + public func scaledToFill() -> View { + modifier(AspectRatio(ratio: nil, contentMode: .fill)) } } diff --git a/Sources/Presenter/ViewModifiers/Background.swift b/Sources/Presenter/ViewModifiers/Background.swift index f924227..9efd2cb 100644 --- a/Sources/Presenter/ViewModifiers/Background.swift +++ b/Sources/Presenter/ViewModifiers/Background.swift @@ -1,9 +1,9 @@ -internal struct Background: AnyViewModifying { +internal struct Background: CodableViewModifier { // MARK: Stored Properties - let view: CoderView + let background: CoderView } @@ -12,7 +12,7 @@ internal struct Background: AnyViewModifying { extension Background: CustomStringConvertible { var description: String { - "background(\(view))" + "background(\(background))" } } @@ -21,10 +21,20 @@ extension Background: CustomStringConvertible { #if canImport(SwiftUI) -extension Background: ViewModifier { +extension Background { + + public func body(for content: Content) -> View { + background.modifier(Modifier(foreground: content)) + } + +} + +private struct Modifier: ViewModifier, SwiftUI.ViewModifier { + + let foreground: Foreground func body(content: Content) -> some SwiftUI.View { - content.background(view.eraseToAnyView()) + foreground.background(content) } } @@ -33,10 +43,10 @@ extension Background: ViewModifier { // MARK: - View Extensions -extension View where Self: Codable { +extension View { - public func background(_ view: V) -> some View { - modified(using: Background(view: CoderView(view))) + public func background(_ view: View) -> View { + modifier(Background(background: CoderView(view))) } } diff --git a/Sources/Presenter/ViewModifiers/Blur.swift b/Sources/Presenter/ViewModifiers/Blur.swift index e951586..fafadbf 100644 --- a/Sources/Presenter/ViewModifiers/Blur.swift +++ b/Sources/Presenter/ViewModifiers/Blur.swift @@ -1,5 +1,5 @@ -internal struct Blur: AnyViewModifying { +internal struct Blur: CodableViewModifier { // MARK: Stored Properties @@ -22,7 +22,7 @@ extension Blur: CustomStringConvertible { #if canImport(SwiftUI) -extension Blur: ViewModifier { +extension Blur: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { content.blur(radius: radius, opaque: opaque ?? false) @@ -35,8 +35,8 @@ extension Blur: ViewModifier { extension View { - public func blur(radius: CGFloat, opaque: Bool? = nil) -> some View { - modified(using: Blur(radius: radius, opaque: opaque)) + public func blur(radius: CGFloat, opaque: Bool? = nil) -> View { + modifier(Blur(radius: radius, opaque: opaque)) } } diff --git a/Sources/Presenter/ViewModifiers/Clipped.swift b/Sources/Presenter/ViewModifiers/Clipped.swift index 12a7e42..ddd1d9e 100644 --- a/Sources/Presenter/ViewModifiers/Clipped.swift +++ b/Sources/Presenter/ViewModifiers/Clipped.swift @@ -1,5 +1,5 @@ -internal struct Clipped: AnyViewModifying { +internal struct Clipped: CodableViewModifier { // MARK: Stored Properties @@ -21,7 +21,7 @@ extension Clipped: CustomStringConvertible { #if canImport(SwiftUI) -extension Clipped: ViewModifier { +extension Clipped: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { content.clipped(antialiased: antialiased ?? false) @@ -35,8 +35,8 @@ extension Clipped: ViewModifier { extension View { - public func clipped(antialiased: Bool? = nil) -> some View { - modified(using: Clipped(antialiased: antialiased)) + public func clipped(antialiased: Bool? = nil) -> View { + modifier(Clipped(antialiased: antialiased)) } } diff --git a/Sources/Presenter/ViewModifiers/CornerRadius.swift b/Sources/Presenter/ViewModifiers/CornerRadius.swift index 7ccc8e8..a44a175 100644 --- a/Sources/Presenter/ViewModifiers/CornerRadius.swift +++ b/Sources/Presenter/ViewModifiers/CornerRadius.swift @@ -1,5 +1,5 @@ -internal struct CornerRadius: AnyViewModifying { +internal struct CornerRadius: CodableViewModifier { // MARK: Stored Properties @@ -22,7 +22,7 @@ extension CornerRadius: CustomStringConvertible { #if canImport(SwiftUI) -extension CornerRadius: ViewModifier { +extension CornerRadius: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { content.cornerRadius(value, antialiased: antialiased ?? true) @@ -35,8 +35,8 @@ extension CornerRadius: ViewModifier { extension View { - public func cornerRadius(_ value: CGFloat, antialiased: Bool? = nil) -> some View { - modified(using: CornerRadius(value: value, antialiased: antialiased)) + public func cornerRadius(_ value: CGFloat, antialiased: Bool? = nil) -> View { + modifier(CornerRadius(value: value, antialiased: antialiased)) } } diff --git a/Sources/Presenter/ViewModifiers/DrawingGroup.swift b/Sources/Presenter/ViewModifiers/DrawingGroup.swift index edc735a..5b559c8 100644 --- a/Sources/Presenter/ViewModifiers/DrawingGroup.swift +++ b/Sources/Presenter/ViewModifiers/DrawingGroup.swift @@ -5,7 +5,7 @@ public enum ColorRenderingMode: String, Codable { case nonLinear } -internal struct DrawingGroup: AnyViewModifying { +internal struct DrawingGroup: CodableViewModifier { // MARK: Stored Properties @@ -28,7 +28,7 @@ extension DrawingGroup: CustomStringConvertible { #if canImport(SwiftUI) -extension DrawingGroup: ViewModifier { +extension DrawingGroup: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { content.drawingGroup(opaque: opaque ?? false, @@ -58,8 +58,8 @@ extension ColorRenderingMode { extension View { - public func drawingGroup(opaque: Bool? = nil, colorMode: ColorRenderingMode? = nil) -> some View { - modified(using: DrawingGroup(opaque: opaque, colorMode: colorMode)) + public func drawingGroup(opaque: Bool? = nil, colorMode: ColorRenderingMode? = nil) -> View { + modifier(DrawingGroup(opaque: opaque, colorMode: colorMode)) } } diff --git a/Sources/Presenter/ViewModifiers/DynamicFrame.swift b/Sources/Presenter/ViewModifiers/DynamicFrame.swift index c6d915a..9d41edf 100644 --- a/Sources/Presenter/ViewModifiers/DynamicFrame.swift +++ b/Sources/Presenter/ViewModifiers/DynamicFrame.swift @@ -1,5 +1,5 @@ -internal struct DynamicFrame: AnyViewModifying { +internal struct DynamicFrame: CodableViewModifier { // MARK: Stored Properties @@ -35,7 +35,7 @@ extension DynamicFrame: CustomStringConvertible { #if canImport(SwiftUI) -extension DynamicFrame: ViewModifier { +extension DynamicFrame: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { content.frame(minWidth: minWidth, @@ -61,8 +61,8 @@ extension View { minHeight: CGFloat? = nil, idealHeight: CGFloat? = nil, maxHeight: CGFloat? = nil, - alignment: Alignment? = nil) -> some View { - modified(using: + alignment: Alignment = .center) -> View { + modifier( DynamicFrame( minWidth: minWidth, idealWidth: idealWidth, maxWidth: maxWidth, minHeight: minHeight, idealHeight: idealHeight, maxHeight: maxHeight, diff --git a/Sources/Presenter/ViewModifiers/FontModifier.swift b/Sources/Presenter/ViewModifiers/FontModifier.swift index fcd8994..21154c8 100644 --- a/Sources/Presenter/ViewModifiers/FontModifier.swift +++ b/Sources/Presenter/ViewModifiers/FontModifier.swift @@ -1,5 +1,5 @@ -internal struct FontModifier: AnyViewModifying { +internal struct FontModifier: CodableViewModifier { // MARK: Stored Properties @@ -21,7 +21,7 @@ extension FontModifier: CustomStringConvertible { #if canImport(SwiftUI) -extension FontModifier: ViewModifier { +extension FontModifier: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { content.font(font?.swiftUIValue) @@ -35,8 +35,8 @@ extension FontModifier: ViewModifier { extension View { - public func font(_ font: Font?) -> some View { - modified(using: FontModifier(font: font)) + public func font(_ font: Font?) -> View { + modifier(FontModifier(font: font)) } } diff --git a/Sources/Presenter/ViewModifiers/ForegroundColor.swift b/Sources/Presenter/ViewModifiers/ForegroundColor.swift index b6610e1..8e4fe4b 100644 --- a/Sources/Presenter/ViewModifiers/ForegroundColor.swift +++ b/Sources/Presenter/ViewModifiers/ForegroundColor.swift @@ -1,5 +1,5 @@ -internal struct ForegroundColor: AnyViewModifying { +internal struct ForegroundColor: CodableViewModifier { // MARK: Stored Properties @@ -21,10 +21,10 @@ extension ForegroundColor: CustomStringConvertible { #if canImport(SwiftUI) -extension ForegroundColor: ViewModifier { +extension ForegroundColor: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { - content.foregroundColor(color.color.view) + content.foregroundColor(color.color.body) } } @@ -35,8 +35,8 @@ extension ForegroundColor: ViewModifier { extension View { - public func foregroundColor(_ color: Color) -> some View { - modified(using: ForegroundColor(color: ColorCode(color))) + public func foregroundColor(_ color: Color) -> View { + modifier(ForegroundColor(color: ColorCode(color))) } } diff --git a/Sources/Presenter/ViewModifiers/Frame.swift b/Sources/Presenter/ViewModifiers/Frame.swift index 87efc2e..9a1a6d1 100644 --- a/Sources/Presenter/ViewModifiers/Frame.swift +++ b/Sources/Presenter/ViewModifiers/Frame.swift @@ -1,5 +1,5 @@ -internal struct Frame: AnyViewModifying { +internal struct Frame: CodableViewModifier { // MARK: Stored Properties @@ -25,7 +25,7 @@ extension Frame: CustomStringConvertible { #if canImport(SwiftUI) -extension Frame: ViewModifier { +extension Frame: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { content.frame(width: width, height: height, @@ -40,8 +40,10 @@ extension Frame: ViewModifier { extension View { - public func frame(width: CGFloat? = nil, height: CGFloat? = nil, alignment: Alignment? = nil) -> some View { - modified(using: Frame(height: height, width: width, alignment: alignment)) + public func frame(width: CGFloat? = nil, + height: CGFloat? = nil, + alignment: Alignment? = nil) -> View { + modifier(Frame(height: height, width: width, alignment: alignment)) } } diff --git a/Sources/Presenter/ViewModifiers/LayoutPriority.swift b/Sources/Presenter/ViewModifiers/LayoutPriority.swift index 7dd6d15..d24d4bc 100644 --- a/Sources/Presenter/ViewModifiers/LayoutPriority.swift +++ b/Sources/Presenter/ViewModifiers/LayoutPriority.swift @@ -1,5 +1,5 @@ -internal struct LayoutPriority: AnyViewModifying { +internal struct LayoutPriority: CodableViewModifier { // MARK: Stored Properties @@ -21,7 +21,7 @@ extension LayoutPriority: CustomStringConvertible { #if canImport(SwiftUI) -extension LayoutPriority: ViewModifier { +extension LayoutPriority: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { content.layoutPriority(value) @@ -34,8 +34,8 @@ extension LayoutPriority: ViewModifier { extension View { - public func layoutPriority(_ value: Double) -> some View { - modified(using: LayoutPriority(value: value)) + public func layoutPriority(_ value: Double) -> View { + modifier(LayoutPriority(value: value)) } } diff --git a/Sources/Presenter/ViewModifiers/LifecycleModifier.swift b/Sources/Presenter/ViewModifiers/LifecycleModifier.swift index 7e6b633..7b3320e 100644 --- a/Sources/Presenter/ViewModifiers/LifecycleModifier.swift +++ b/Sources/Presenter/ViewModifiers/LifecycleModifier.swift @@ -1,5 +1,5 @@ -internal struct LifecycleModifier: AnyViewModifying { +internal struct LifecycleModifier: CodableViewModifier { // MARK: Stored Properties @@ -24,7 +24,7 @@ extension LifecycleModifier: CustomStringConvertible { #if canImport(SwiftUI) -extension LifecycleModifier: ViewModifier { +extension LifecycleModifier: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { ModelView { model in @@ -42,12 +42,12 @@ extension LifecycleModifier: ViewModifier { extension View { - public func onAppear(perform action: Action) -> some View { - modified(using: LifecycleModifier(onAppear: CoderAction(action), onDisappear: nil)) + public func onAppear(perform action: Action) -> View { + modifier(LifecycleModifier(onAppear: CoderAction(action), onDisappear: nil)) } - public func onDisappear(perform action: Action) -> some View { - modified(using: LifecycleModifier(onAppear: nil, onDisappear: CoderAction(action))) + public func onDisappear(perform action: Action) -> View { + modifier(LifecycleModifier(onAppear: nil, onDisappear: CoderAction(action))) } } diff --git a/Sources/Presenter/ViewModifiers/Mask.swift b/Sources/Presenter/ViewModifiers/Mask.swift index 32f6e9c..80a6a10 100644 --- a/Sources/Presenter/ViewModifiers/Mask.swift +++ b/Sources/Presenter/ViewModifiers/Mask.swift @@ -1,5 +1,5 @@ -internal struct Mask: AnyViewModifying { +internal struct Mask: CodableViewModifier { // MARK: Stored Properties @@ -21,11 +21,22 @@ extension Mask: CustomStringConvertible { #if canImport(SwiftUI) -extension Mask: ViewModifier { +extension Mask { + + public func body(for content: Content) -> View { + mask.modifier(Modifier(foreground: content)) + } + +} + +private struct Modifier: ViewModifier, SwiftUI.ViewModifier { + + let foreground: Foreground func body(content: Content) -> some SwiftUI.View { - content.mask(mask.eraseToAnyView()) + foreground.mask(content) } + } #endif @@ -34,8 +45,8 @@ extension Mask: ViewModifier { extension View { - public func mask(_ mask: M) -> some View { - modified(using: Mask(mask: CoderView(mask))) + public func mask(_ mask: View) -> View { + modifier(Mask(mask: CoderView(mask))) } } diff --git a/Sources/Presenter/ViewModifiers/NavigationBarTitle.swift b/Sources/Presenter/ViewModifiers/NavigationBarTitle.swift index c915637..1201aaf 100644 --- a/Sources/Presenter/ViewModifiers/NavigationBarTitle.swift +++ b/Sources/Presenter/ViewModifiers/NavigationBarTitle.swift @@ -5,7 +5,7 @@ public enum NavigationBarTitleDisplayMode: String, Codable { case large } -internal struct NavigationBarTitle: AnyViewModifying { +internal struct NavigationBarTitle: CodableViewModifier { // MARK: Stored Properties @@ -28,7 +28,7 @@ extension NavigationBarTitle: CustomStringConvertible { #if canImport(SwiftUI) -extension NavigationBarTitle: ViewModifier { +extension NavigationBarTitle: SwiftUI.ViewModifier { #if os(tvOS) || os(watchOS) || os(macOS) @@ -78,8 +78,8 @@ extension NavigationBarTitleDisplayMode { extension View { public func navigationBarTitle(_ title: Value, - displayMode: NavigationBarTitleDisplayMode? = nil) -> some View { - modified(using: NavigationBarTitle(title: title, displayMode: displayMode)) + displayMode: NavigationBarTitleDisplayMode? = nil) -> View { + modifier(NavigationBarTitle(title: title, displayMode: displayMode)) } } diff --git a/Sources/Presenter/ViewModifiers/Opacity.swift b/Sources/Presenter/ViewModifiers/Opacity.swift index c4d3d27..31fb077 100644 --- a/Sources/Presenter/ViewModifiers/Opacity.swift +++ b/Sources/Presenter/ViewModifiers/Opacity.swift @@ -1,5 +1,5 @@ -internal struct Opacity: AnyViewModifying { +internal struct Opacity: CodableViewModifier { // MARK: Stored Properties @@ -21,7 +21,7 @@ extension Opacity: CustomStringConvertible { #if canImport(SwiftUI) -extension Opacity: ViewModifier { +extension Opacity: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { content.opacity(value) @@ -34,8 +34,8 @@ extension Opacity: ViewModifier { extension View { - public func opacity(_ value: Double, antialiased: Bool? = nil) -> some View { - modified(using: Opacity(value: value)) + public func opacity(_ value: Double, antialiased: Bool? = nil) -> View { + modifier(Opacity(value: value)) } } diff --git a/Sources/Presenter/ViewModifiers/Overlay.swift b/Sources/Presenter/ViewModifiers/Overlay.swift index fb0378f..aeb07c6 100644 --- a/Sources/Presenter/ViewModifiers/Overlay.swift +++ b/Sources/Presenter/ViewModifiers/Overlay.swift @@ -1,5 +1,5 @@ -internal struct Overlay: AnyViewModifying { +internal struct Overlay: CodableViewModifier { // MARK: Stored Properties @@ -22,12 +22,26 @@ extension Overlay: CustomStringConvertible { #if canImport(SwiftUI) -extension Overlay: ViewModifier { +extension Overlay { + + public func body(for content: Content) -> View { + overlay.modifier( + Modifier(foreground: content, + alignment: alignment?.swiftUIValue ?? .center) + ) + } + +} + +private struct Modifier: ViewModifier, SwiftUI.ViewModifier { + + let foreground: Foreground + let alignment: SwiftUI.Alignment func body(content: Content) -> some SwiftUI.View { - content.overlay(overlay.eraseToAnyView(), - alignment: alignment?.swiftUIValue ?? .center) + foreground.overlay(content, alignment: alignment) } + } #endif @@ -36,8 +50,8 @@ extension Overlay: ViewModifier { extension View { - public func overlay(_ overlay: O, alignment: Alignment? = nil) -> some View { - modified(using: Overlay(overlay: CoderView(overlay), alignment: alignment)) + public func overlay(_ overlay: View, alignment: Alignment? = nil) -> View { + modifier(Overlay(overlay: CoderView(overlay), alignment: alignment)) } } diff --git a/Sources/Presenter/ViewModifiers/Padding.swift b/Sources/Presenter/ViewModifiers/Padding.swift index b41a73f..5de23fe 100644 --- a/Sources/Presenter/ViewModifiers/Padding.swift +++ b/Sources/Presenter/ViewModifiers/Padding.swift @@ -1,5 +1,5 @@ -internal struct Padding: AnyViewModifying { +internal struct Padding: CodableViewModifier { // MARK: Stored Properties @@ -26,7 +26,7 @@ extension Padding: CustomStringConvertible { #if canImport(SwiftUI) -extension Padding: ViewModifier { +extension Padding: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { let insets = EdgeInsets(top: top ?? 0, leading: leading ?? 0, bottom: bottom ?? 0, trailing: trailing ?? 0) @@ -42,12 +42,12 @@ extension Padding: ViewModifier { extension View { public func padding(top: CGFloat? = nil, leading: CGFloat? = nil, - bottom: CGFloat? = nil, trailing: CGFloat? = nil) -> some View { - modified(using: Padding(top: top, leading: leading, bottom: bottom, trailing: trailing)) + bottom: CGFloat? = nil, trailing: CGFloat? = nil) -> View { + modifier(Padding(top: top, leading: leading, bottom: bottom, trailing: trailing)) } - public func padding(_ value: CGFloat) -> some View { - modified(using: Padding(top: value, leading: value, bottom: value, trailing: value)) + public func padding(_ value: CGFloat) -> View { + modifier(Padding(top: value, leading: value, bottom: value, trailing: value)) } } diff --git a/Sources/Presenter/ViewModifiers/Shadow.swift b/Sources/Presenter/ViewModifiers/Shadow.swift index 390f953..5322f24 100644 --- a/Sources/Presenter/ViewModifiers/Shadow.swift +++ b/Sources/Presenter/ViewModifiers/Shadow.swift @@ -1,5 +1,5 @@ -internal struct Shadow: AnyViewModifying { +internal struct Shadow: CodableViewModifier { // MARK: Stored Properties @@ -28,11 +28,11 @@ extension Shadow: CustomStringConvertible { #if canImport(SwiftUI) -extension Shadow: ViewModifier { +extension Shadow: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { if let color = color { - return content.shadow(color: color.color.view, radius: radius, x: x ?? 0, y: y ?? 0) + return content.shadow(color: color.color.body, radius: radius, x: x ?? 0, y: y ?? 0) } else { return content.shadow(radius: radius, x: x ?? 0, y: y ?? 0) } @@ -45,8 +45,8 @@ extension Shadow: ViewModifier { extension View { - public func shadow(color: Color? = nil, radius: CGFloat, x: CGFloat? = nil, y: CGFloat? = nil) -> some View { - modified(using: Shadow(color: color.map(ColorCode.init), radius: radius, x: x, y: y)) + public func shadow(color: Color? = nil, radius: CGFloat, x: CGFloat? = nil, y: CGFloat? = nil) -> View { + modifier(Shadow(color: color.map(ColorCode.init), radius: radius, x: x, y: y)) } } diff --git a/Sources/Presenter/ViewModifiers/Sheet.swift b/Sources/Presenter/ViewModifiers/Sheet.swift index a899c50..395918b 100644 --- a/Sources/Presenter/ViewModifiers/Sheet.swift +++ b/Sources/Presenter/ViewModifiers/Sheet.swift @@ -1,5 +1,5 @@ -internal struct Sheet: AnyViewModifying { +internal struct Sheet: CodableViewModifier { // MARK: Stored Properties @@ -22,15 +22,26 @@ extension Sheet: CustomStringConvertible { #if canImport(SwiftUI) -extension Sheet: ViewModifier { +extension Sheet { + + func body(for caller: Caller) -> View { + content.modifier(Modifier(caller: caller, isPresented: isPresented)) + } + +} + +private struct Modifier: ViewModifier, SwiftUI.ViewModifier { + + let caller: Caller + let isPresented: Binding func body(content: Content) -> some SwiftUI.View { ModelView { model in - content - .sheet(isPresented: model.binding(for: self.isPresented)) { - self.content.eraseToAnyView() - .environmentObject(model) - } + caller + .sheet(isPresented: model.binding(for: self.isPresented)) { + content + .environmentObject(model) + } } } @@ -42,8 +53,8 @@ extension Sheet: ViewModifier { extension View { - public func sheet(isPresented: Binding, content: Content) -> some View { - modified(using: Sheet(isPresented: isPresented, content: CoderView(content))) + public func sheet(isPresented: Binding, content: View) -> View { + modifier(Sheet(isPresented: isPresented, content: CoderView(content))) } } diff --git a/Sources/Presenter/Views/AngularGradient.swift b/Sources/Presenter/Views/AngularGradient.swift index ec49a66..90beeae 100644 --- a/Sources/Presenter/Views/AngularGradient.swift +++ b/Sources/Presenter/Views/AngularGradient.swift @@ -1,5 +1,5 @@ -public struct AngularGradient: SwiftUIView { +public struct AngularGradient: CodableView { // MARK: Stored Properties @@ -47,9 +47,9 @@ extension AngularGradient: CustomStringConvertible { #if canImport(SwiftUI) -extension AngularGradient { +extension AngularGradient: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { SwiftUI.AngularGradient( gradient: gradient.swiftUIValue, center: center.unitPoint, diff --git a/Sources/Presenter/Views/ArrayView.swift b/Sources/Presenter/Views/ArrayView.swift index 7b7b031..09d1c94 100644 --- a/Sources/Presenter/Views/ArrayView.swift +++ b/Sources/Presenter/Views/ArrayView.swift @@ -1,5 +1,5 @@ -struct ArrayView: SwiftUIView { +struct ArrayView: CodableView { // MARK: Stored Properties @@ -7,7 +7,7 @@ struct ArrayView: SwiftUIView { // MARK: Initialization - public init(content: [_CodableView]) { + public init(content: [View]) { self.content = content.flatMap { contentView -> [CoderView] in if let arrayView = contentView as? ArrayView { return arrayView.content @@ -33,9 +33,9 @@ extension ArrayView: CustomStringConvertible { #if canImport(SwiftUI) -extension ArrayView { +extension ArrayView: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { ForEach(content.indices) { index in self.content[index].eraseToAnyView() } diff --git a/Sources/Presenter/Views/Button.swift b/Sources/Presenter/Views/Button.swift index d385fd6..17d2217 100644 --- a/Sources/Presenter/Views/Button.swift +++ b/Sources/Presenter/Views/Button.swift @@ -1,5 +1,5 @@ -public struct Button: SwiftUIView { +public struct Button: CodableWrapperView { // MARK: Stored Properties @@ -8,7 +8,7 @@ public struct Button: SwiftUIView { // MARK: Initialization - public init(_ label: Label, action: Action) { + public init(_ label: View, action: Action) { self.label = CoderView(label) self.action = CoderAction(action) } @@ -31,13 +31,13 @@ extension Button: CustomStringConvertible { extension Button { - public var view: some SwiftUI.View { - label.apply(Modifier1(action: action)).eraseToAnyView() + public var body: View { + label.modifier(Modifier(action: action)) } } -private struct Modifier1: ViewModifier { +private struct Modifier: ViewModifier, SwiftUI.ViewModifier { let action: CoderAction diff --git a/Sources/Presenter/Views/Capsule.swift b/Sources/Presenter/Views/Capsule.swift index 5e2fd62..686040d 100644 --- a/Sources/Presenter/Views/Capsule.swift +++ b/Sources/Presenter/Views/Capsule.swift @@ -1,5 +1,5 @@ -public struct Capsule: SwiftUIView { +public struct Capsule: CodableView { // MARK: Stored Properties @@ -27,9 +27,9 @@ extension Capsule: CustomStringConvertible { #if canImport(SwiftUI) -extension Capsule { +extension Capsule: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { SwiftUI.Capsule(style: style.swiftUIValue) } diff --git a/Sources/Presenter/Views/Circle.swift b/Sources/Presenter/Views/Circle.swift index cefcc36..6169d64 100644 --- a/Sources/Presenter/Views/Circle.swift +++ b/Sources/Presenter/Views/Circle.swift @@ -1,5 +1,5 @@ -public struct Circle: SwiftUIView { +public struct Circle: CodableView { // MARK: Initialization @@ -21,9 +21,9 @@ extension Circle: CustomStringConvertible { #if canImport(SwiftUI) -extension Circle { +extension Circle: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { SwiftUI.Circle() } diff --git a/Sources/Presenter/Views/Color.swift b/Sources/Presenter/Views/Color.swift index 663381a..c979d41 100644 --- a/Sources/Presenter/Views/Color.swift +++ b/Sources/Presenter/Views/Color.swift @@ -1,5 +1,5 @@ -public struct Color: SwiftUIView { +public struct Color: CodableView { // MARK: Nested Types @@ -49,7 +49,7 @@ public struct Color: SwiftUIView { extension Color: CustomStringConvertible { public var description: String { - "Color(\(ColorCode(self))" + "Color(\(ColorCode(self)))" } } @@ -58,9 +58,9 @@ extension Color: CustomStringConvertible { #if canImport(SwiftUI) -extension Color { +extension Color: SwiftUI.View { - public var view: SwiftUI.Color { + public var body: SwiftUI.Color { SwiftUI.Color(red: red, green: green, blue: blue, opacity: opacity) } diff --git a/Sources/Presenter/Views/ColorPicker.swift b/Sources/Presenter/Views/ColorPicker.swift index 0be84dc..b01f5af 100644 --- a/Sources/Presenter/Views/ColorPicker.swift +++ b/Sources/Presenter/Views/ColorPicker.swift @@ -1,18 +1,18 @@ -public struct ColorPicker: SwiftUIView { +public struct ColorPicker: CodableWrapperView { // MARK: Stored Properties - private let color: Binding + private let color: Binding private let supportsOpacity: Bool private let label: CoderView // MARK: Initialization - public init( + public init( color: Binding, supportsOpacity: Bool, - @ViewBuilder label: () -> Label + @ViewBuilder label: () -> View ) { self.color = color self.supportsOpacity = supportsOpacity @@ -39,29 +39,37 @@ extension ColorPicker { #if !os(macOS) && !os(tvOS) && !os(watchOS) && !targetEnvironment(macCatalyst) - @SwiftUI.ViewBuilder - public var view: some SwiftUI.View { + public var body: View { + label.modifier(Modifier(color: color, supportsOpacity: supportsOpacity)) + } + + #else + + public var body: View { + Nil() + } + + #endif + +} + +private struct Modifier: ViewModifier, SwiftUI.ViewModifier { + + let color: Binding + let supportsOpacity: Bool + + func body(content: Content) -> some SwiftUI.View { if #available(iOS 14.0, *) { ModelView { model in SwiftUI.ColorPicker( - selection: model.binding(for: color) { $0.view }, + selection: model.binding(for: color) { $0.body }, supportsOpacity: supportsOpacity) { - label.eraseToAnyView() + content } } - } else { - SwiftUI.EmptyView() } } - #else - - public var view: some SwiftUI.View { - SwiftUI.EmptyView() - } - - #endif - } #endif diff --git a/Sources/Presenter/Views/ComposedView.swift b/Sources/Presenter/Views/ComposedView.swift index 3bf3a97..6c3bdf1 100644 --- a/Sources/Presenter/Views/ComposedView.swift +++ b/Sources/Presenter/Views/ComposedView.swift @@ -1,5 +1,5 @@ -struct ComposedView: InternalView, Codable { +struct ComposedView: CodableWrapperView { // MARK: Stored Properties @@ -24,8 +24,8 @@ extension ComposedView: CustomStringConvertible { extension ComposedView { - var view: _View { - modifiers.reduce(content as _View) { $0.apply($1) } + public var body: View { + modifiers.reduce(content as View) { $0.apply($1) } } } @@ -36,7 +36,7 @@ extension ComposedView { extension View { - public func modified(using modifier: AnyViewModifying) -> some View { + public func modifier(_ modifier: Modifier) -> View { if let composition = self as? ComposedView { return ComposedView(content: composition.content, modifiers: composition.modifiers + [CoderViewModifier(modifier)]) diff --git a/Sources/Presenter/Views/DataView.swift b/Sources/Presenter/Views/DataView.swift index fe752d9..020fc40 100644 --- a/Sources/Presenter/Views/DataView.swift +++ b/Sources/Presenter/Views/DataView.swift @@ -1,5 +1,5 @@ -public struct DataView: SwiftUIView { +public struct DataView: CodableView { // MARK: Stored Properties @@ -43,16 +43,23 @@ private struct _DataView: SwiftUI.View { } private func decode() -> some SwiftUI.View { - didTryDecoding = true - view = try? Presenter.decode(from: data).eraseToAnyView() + DispatchQueue.main.async { + self.didTryDecoding = true + do { + let decodedView = try Presenter.decode(from: data) + self.view = decodedView.eraseToAnyView() + } catch { + self.view = AnyView(SwiftUI.Text(error.localizedDescription)) + } + } return view } } -extension DataView { +extension DataView: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { _DataView(data: data) } diff --git a/Sources/Presenter/Views/Divider.swift b/Sources/Presenter/Views/Divider.swift index f3f7dd5..9df6447 100644 --- a/Sources/Presenter/Views/Divider.swift +++ b/Sources/Presenter/Views/Divider.swift @@ -1,5 +1,5 @@ -public struct Divider: SwiftUIView { +public struct Divider: CodableView { // MARK: Initialization @@ -21,9 +21,9 @@ extension Divider: CustomStringConvertible { #if canImport(SwiftUI) -extension Divider { +extension Divider: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { SwiftUI.Divider() } diff --git a/Sources/Presenter/Views/HGrid.swift b/Sources/Presenter/Views/HGrid.swift index a503355..a5328dc 100644 --- a/Sources/Presenter/Views/HGrid.swift +++ b/Sources/Presenter/Views/HGrid.swift @@ -1,5 +1,5 @@ -public struct HGrid: SwiftUIView { +public struct HGrid: CodableWrapperView { // MARK: Stored Properties @@ -11,12 +11,12 @@ public struct HGrid: SwiftUIView { // MARK: Initialization - public init( + public init( rows: [GridItem], alignment: VerticalAlignment? = nil, spacing: CGFloat? = nil, pinnedViews: PinnedScrollableViews, - @ViewBuilder content: () -> Content + @ViewBuilder content: () -> View ) { self.rows = rows self.alignment = alignment @@ -45,26 +45,25 @@ extension HGrid { #if !os(macOS) && !targetEnvironment(macCatalyst) - @SwiftUI.ViewBuilder - public var view: some SwiftUI.View { + public var body: View { if #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) { - content.apply( + return content.modifier( Modifier( rows: rows.map(\.swiftUIValue), alignment: alignment?.swiftUIValue ?? .center, spacing: spacing, pinnedViews: pinnedViews.swiftUIValue ) - ).eraseToAnyView() + ) } else { - SwiftUI.EmptyView() + return Nil() } } #else - public var view: some SwiftUI.View { - SwiftUI.EmptyView() + public var body: View { + Nil() } #endif @@ -72,7 +71,7 @@ extension HGrid { } @available(iOS 14.0, macOS 11.0, *) -private struct Modifier: ViewModifier { +private struct Modifier: ViewModifier, SwiftUI.ViewModifier { let rows: [SwiftUI.GridItem] let alignment: SwiftUI.VerticalAlignment diff --git a/Sources/Presenter/Views/HStack.swift b/Sources/Presenter/Views/HStack.swift index 5701c12..af6311c 100644 --- a/Sources/Presenter/Views/HStack.swift +++ b/Sources/Presenter/Views/HStack.swift @@ -1,5 +1,5 @@ -public struct HStack: InternalView, Codable { +public struct HStack: CodableWrapperView { // MARK: Stored Properties @@ -9,10 +9,10 @@ public struct HStack: InternalView, Codable { // MARK: Initialization - public init( + public init( alignment: VerticalAlignment? = nil, spacing: CGFloat? = nil, - @ViewBuilder content: () -> Content + @ViewBuilder content: () -> View ) { self.alignment = alignment self.spacing = spacing @@ -37,14 +37,14 @@ extension HStack: CustomStringConvertible { extension HStack { - public var view: _View { + public var body: View { content - .apply(Modifier(alignment: alignment?.swiftUIValue ?? .center, spacing: spacing)) + .modifier(Modifier(alignment: alignment?.swiftUIValue ?? .center, spacing: spacing)) } } -private struct Modifier: ViewModifier { +private struct Modifier: ViewModifier, SwiftUI.ViewModifier { let alignment: SwiftUI.VerticalAlignment let spacing: CGFloat? diff --git a/Sources/Presenter/Views/If.swift b/Sources/Presenter/Views/If.swift index ae7e658..6a15b5e 100644 --- a/Sources/Presenter/Views/If.swift +++ b/Sources/Presenter/Views/If.swift @@ -1,5 +1,5 @@ -public struct If: SwiftUIView { +public struct If: CodableWrapperView { // MARK: Nested Types @@ -17,28 +17,28 @@ public struct If: SwiftUIView { // MARK: Initialization - public init( + public init( _ condition: Value, - then trueView: TrueView, - else falseView: FalseView + then trueView: View, + else falseView: View ) { self.condition = condition self.trueView = CoderView(trueView) self.falseView = CoderView(falseView) } - public init( + public init( _ condition: Value, - then trueView: TrueView + then trueView: View ) { self.condition = condition self.trueView = CoderView(trueView) self.falseView = CoderView(Nil()) } - public init( + public init( _ condition: Value, - else falseView: FalseView + else falseView: View ) { self.condition = condition self.trueView = CoderView(Nil()) @@ -80,12 +80,34 @@ extension If: CustomStringConvertible { extension If { - public var view: some SwiftUI.View { - ModelView { model in + public var body: View { + trueView.modifier(Modifier1(falseView: falseView, condition: condition)) + } + +} + +private struct Modifier1: ViewModifier { + + let falseView: CoderView + let condition: Value + + func body(for content: Content) -> View { + falseView.modifier(Modifier2(trueView: content, condition: condition)) + } + +} + +private struct Modifier2: ViewModifier, SwiftUI.ViewModifier { + + let trueView: TrueView + let condition: Value + + func body(content: Content) -> some SwiftUI.View { + ModelView { model in if self.condition.get(from: model) { - return self.trueView.eraseToAnyView() + trueView } else { - return self.falseView.eraseToAnyView() + content } } } diff --git a/Sources/Presenter/Views/Image.swift b/Sources/Presenter/Views/Image.swift index 2844143..862371d 100644 --- a/Sources/Presenter/Views/Image.swift +++ b/Sources/Presenter/Views/Image.swift @@ -1,5 +1,5 @@ -public struct Image: SwiftUIView { +public struct Image: CodableView { // MARK: Nested Types @@ -150,9 +150,9 @@ extension ImageView { #endif -extension Image { +extension Image: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { ImageView(image: self) } diff --git a/Sources/Presenter/Views/LinearGradient.swift b/Sources/Presenter/Views/LinearGradient.swift index d98047e..a1eb68c 100644 --- a/Sources/Presenter/Views/LinearGradient.swift +++ b/Sources/Presenter/Views/LinearGradient.swift @@ -1,5 +1,5 @@ -public struct LinearGradient: SwiftUIView { +public struct LinearGradient: CodableView { // MARK: Stored Properties @@ -31,9 +31,9 @@ extension LinearGradient: CustomStringConvertible { #if canImport(SwiftUI) -extension LinearGradient { +extension LinearGradient: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { SwiftUI.LinearGradient( gradient: gradient.swiftUIValue, startPoint: startPoint.unitPoint, diff --git a/Sources/Presenter/Views/Link.swift b/Sources/Presenter/Views/Link.swift index 5ec50d4..0113ad1 100644 --- a/Sources/Presenter/Views/Link.swift +++ b/Sources/Presenter/Views/Link.swift @@ -1,5 +1,5 @@ -public struct Link: SwiftUIView { +public struct Link: CodableWrapperView { // MARK: Stored Properties @@ -8,7 +8,7 @@ public struct Link: SwiftUIView { // MARK: Initialization - public init(label: Label, destination: String) { + public init(label: View, destination: String) { self.label = CoderView(label) self.destination = destination } @@ -31,24 +31,23 @@ extension Link: CustomStringConvertible { extension Link { - #if !os(macOS) && !targetEnvironment(macCatalyst) - - @SwiftUI.ViewBuilder - public var view: some SwiftUI.View { - if #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *), let url = URL(string: destination) { - SwiftUI.Link(destination: url, label: label.eraseToAnyView) - } else { - label.eraseToAnyView() - } + public var body: View { + label.modifier(Modifier(destination: destination)) } - #else +} - public var view: some SwiftUI.View { - label.eraseToAnyView() - } +private struct Modifier: ViewModifier, SwiftUI.ViewModifier { - #endif + let destination: String + + func body(content: Content) -> some SwiftUI.View { + if #available(iOS 14.0, *), let url = URL(string: destination) { + SwiftUI.Link(destination: url) { content } + } else { + content + } + } } diff --git a/Sources/Presenter/Views/Local.swift b/Sources/Presenter/Views/Local.swift index 3c72cba..245d40c 100644 --- a/Sources/Presenter/Views/Local.swift +++ b/Sources/Presenter/Views/Local.swift @@ -1,5 +1,5 @@ -public struct Local: SwiftUIView { +public struct Local: CodableView { // MARK: Stored Properties @@ -27,17 +27,17 @@ extension Local: CustomStringConvertible { #if canImport(SwiftUI) -extension Local { +extension Local: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { ModelView { model in - view(for: model.state[self.key]) + view(for: model.get(key)) } } @SwiftUI.ViewBuilder private func view(for value: Any?) -> some SwiftUI.View { - if let view = value as? _View { + if let view = value as? View { view.eraseToAnyView() } else if let view = value as? AnyView { view diff --git a/Sources/Presenter/Views/NavigationLink.swift b/Sources/Presenter/Views/NavigationLink.swift index 53b838e..59d0cab 100644 --- a/Sources/Presenter/Views/NavigationLink.swift +++ b/Sources/Presenter/Views/NavigationLink.swift @@ -1,5 +1,5 @@ -public struct NavigationLink: InternalView, Codable { +public struct NavigationLink: CodableWrapperView { // MARK: Stored Properties @@ -9,10 +9,10 @@ public struct NavigationLink: InternalView, Codable { // MARK: Initialization - public init( - destination: Destination, + public init( + destination: View, isActive: Binding, - label: Label + label: View ) { self.destination = CoderView(destination) self.isActive = isActive @@ -37,8 +37,8 @@ extension NavigationLink: CustomStringConvertible { extension NavigationLink { - public var view: _View { - destination.apply(Modifier1(label: label, isActive: isActive)) + public var body: View { + destination.modifier(Modifier1(label: label, isActive: isActive)) } } @@ -48,15 +48,13 @@ private struct Modifier1: ViewModifier { let label: CoderView let isActive: Binding - func body(content: Content) -> some SwiftUI.View { - label - .apply(Modifier2(destination: content, isActive: isActive)) - .eraseToAnyView() + public func body(for content: Content) -> View { + label.modifier(Modifier2(destination: content, isActive: isActive)) } } -private struct Modifier2: ViewModifier { +private struct Modifier2: ViewModifier, SwiftUI.ViewModifier { var destination: Destination let isActive: Binding @@ -68,11 +66,18 @@ private struct Modifier2: ViewModifier { func body(content: Content) -> some SwiftUI.View { ModelView { model in - SwiftUI.NavigationLink( - destination: destination, - isActive: model.binding(for: self.isActive), - label: { content } - ) + SwiftUI.ZStack { + SwiftUI.NavigationLink( + destination: destination, + isActive: model.binding(for: self.isActive), + label: { content } + ) + + SwiftUI.NavigationLink( + destination: EmptyView(), + label: { EmptyView() } + ) + } } } diff --git a/Sources/Presenter/Views/NavigationView.swift b/Sources/Presenter/Views/NavigationView.swift index 537cc46..67f4c7a 100644 --- a/Sources/Presenter/Views/NavigationView.swift +++ b/Sources/Presenter/Views/NavigationView.swift @@ -1,5 +1,5 @@ -public struct NavigationView: InternalView, Codable { +public struct NavigationView: CodableWrapperView { // MARK: Stored Properties @@ -7,8 +7,8 @@ public struct NavigationView: InternalView, Codable { // MARK: Initialization - public init( - @ViewBuilder content: () -> Content + public init( + @ViewBuilder content: () -> View ) { self.content = CoderView(content()) } @@ -31,13 +31,13 @@ extension NavigationView: CustomStringConvertible { extension NavigationView { - public var view: _View { - content.apply(Modifier()) + public var body: View { + content.modifier(Modifier()) } } -private struct Modifier: ViewModifier, AnyViewModifying { +private struct Modifier: ViewModifier, SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { SwiftUI.NavigationView { diff --git a/Sources/Presenter/Views/Nil.swift b/Sources/Presenter/Views/Nil.swift index f5ef186..edba64e 100644 --- a/Sources/Presenter/Views/Nil.swift +++ b/Sources/Presenter/Views/Nil.swift @@ -1,17 +1,22 @@ -extension Optional: InternalView, View, _View, NamedType where Wrapped: _CodableView { +extension Optional: View, NamedType, WrapperView where Wrapped: CodableView { #if canImport(SwiftUI) - public var view: _View { - self ?? Nil() + public var body: View { + switch self { + case let .some(view): + return view + case .none: + return Nil() + } } #endif } -struct Nil: InternalView, Codable { +struct Nil: CodableView { // MARK: Initialization @@ -36,34 +41,14 @@ struct Nil: InternalView, Codable { try container.encodeNil() } - #if canImport(SwiftUI) - - public var view: _View { - EmptyView() - } - - #endif - } #if canImport(SwiftUI) -extension SwiftUI.EmptyView: _View { +extension Nil: SwiftUI.View { - public var erasedCodableBody: _CodableView? { - nil - } - - public func eraseToAnyView() -> AnyView { - AnyView(self) - } - - public func apply(_ m: M) -> _View { - modifier(m) - } - - public func apply(_ modifier: AnyViewModifying) -> _View { - modifier.apply(to: self) + public var body: some SwiftUI.View { + EmptyView() } } diff --git a/Sources/Presenter/Views/Path.swift b/Sources/Presenter/Views/Path.swift index 5bacfc5..a1d3842 100644 --- a/Sources/Presenter/Views/Path.swift +++ b/Sources/Presenter/Views/Path.swift @@ -1,5 +1,5 @@ -public struct Path: SwiftUIView { +public struct Path: CodableView { // MARK: Nested Types @@ -70,9 +70,9 @@ extension Path: CustomStringConvertible { #if canImport(SwiftUI) -extension Path { +extension Path: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { SwiftUI.Path { path in for element in elements { switch element.kind { diff --git a/Sources/Presenter/Views/ScrollView.swift b/Sources/Presenter/Views/ScrollView.swift index c569f80..430fc0b 100644 --- a/Sources/Presenter/Views/ScrollView.swift +++ b/Sources/Presenter/Views/ScrollView.swift @@ -1,5 +1,5 @@ -public struct ScrollView: InternalView, Codable { +public struct ScrollView: CodableWrapperView { // MARK: Stored Properties @@ -9,10 +9,10 @@ public struct ScrollView: InternalView, Codable { // MARK: Initialization - public init( + public init( _ axis: AxisSet? = nil, showsIndicators: Bool? = nil, - @ViewBuilder content: () -> Content + @ViewBuilder content: () -> View ) { self.axis = axis self.showsIndicators = showsIndicators @@ -37,8 +37,8 @@ extension ScrollView: CustomStringConvertible { extension ScrollView { - public var view: _View { - content.apply( + public var body: View { + content.modifier( Modifier(axis: axis?.swiftUIValue ?? .vertical, showsIndicators: showsIndicators ?? true) ) @@ -46,7 +46,7 @@ extension ScrollView { } -private struct Modifier: ViewModifier { +private struct Modifier: ViewModifier, SwiftUI.ViewModifier { let axis: SwiftUI.Axis.Set let showsIndicators: Bool diff --git a/Sources/Presenter/Views/Section.swift b/Sources/Presenter/Views/Section.swift index 5443bbc..626e264 100644 --- a/Sources/Presenter/Views/Section.swift +++ b/Sources/Presenter/Views/Section.swift @@ -1,5 +1,5 @@ -public struct Section: SwiftUIView { +public struct Section: CodableWrapperView { // MARK: Stored Properties @@ -9,39 +9,13 @@ public struct Section: SwiftUIView { // MARK: Initialization - public init( - @ViewBuilder content: () -> Content + public init( + header: View? = nil, + footer: View? = nil, + @ViewBuilder content: () -> View ) { - self.header = nil - self.footer = nil - self.content = CoderView(content()) - } - - public init( - header: Header, - @ViewBuilder content: () -> Content - ) { - self.header = CoderView(header) - self.footer = nil - self.content = CoderView(content()) - } - - public init( - footer: Footer, - @ViewBuilder content: () -> Content - ) { - self.header = nil - self.footer = CoderView(footer) - self.content = CoderView(content()) - } - - public init( - header: Header, - footer: Footer, - @ViewBuilder content: () -> Content - ) { - self.header = CoderView(header) - self.footer = CoderView(footer) + self.header = header.map(CoderView.init) + self.footer = footer.map(CoderView.init) self.content = CoderView(content()) } @@ -63,22 +37,41 @@ extension Section: CustomStringConvertible { extension Section { - @SwiftUI.ViewBuilder - public var view: some SwiftUI.View { - switch (header, footer) { - case let (.some(header), .some(footer)): - SwiftUI.Section(header: header.eraseToAnyView(), - footer: footer.eraseToAnyView(), - content: content.eraseToAnyView) - case let (.none, .some(footer)): - SwiftUI.Section(footer: footer.eraseToAnyView(), - content: content.eraseToAnyView) - case let (.some(header), .none): - SwiftUI.Section(header: header.eraseToAnyView(), - content: content.eraseToAnyView) - case (.none, .none): - SwiftUI.Section(content: content.eraseToAnyView) - } + public var body: View { + content.modifier(Modifier1(header: header, footer: footer)) + } + +} + +private struct Modifier1: ViewModifier { + + let header: CoderView? + let footer: CoderView? + + func body(for content: Content) -> View { + (header?.body ?? Nil()).modifier(Modifier2(footer: footer, section: content)) + } + +} + +private struct Modifier2: ViewModifier { + + let footer: CoderView? + let section: Section + + func body(for header: Header) -> View { + (footer?.body ?? Nil()).modifier(Modifier3(header: header, section: section)) + } + +} + +private struct Modifier3: ViewModifier, SwiftUI.ViewModifier { + + let header: Header + let section: Section + + func body(content footer: Content) -> some SwiftUI.View { + SwiftUI.Section(header: header, footer: footer) { section } } } diff --git a/Sources/Presenter/Views/SecureField.swift b/Sources/Presenter/Views/SecureField.swift index 4a4fa04..5b092d7 100644 --- a/Sources/Presenter/Views/SecureField.swift +++ b/Sources/Presenter/Views/SecureField.swift @@ -1,5 +1,5 @@ -public struct SecureField: SwiftUIView { +public struct SecureField: CodableView { // MARK: Stored Properties @@ -37,9 +37,9 @@ extension SecureField: CustomStringConvertible { #if canImport(SwiftUI) -extension SecureField { +extension SecureField: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { ModelView { model in SwiftUI.SecureField( self.title.get(from: model), diff --git a/Sources/Presenter/Views/Slider.swift b/Sources/Presenter/Views/Slider.swift index 03f3de2..6404d2b 100644 --- a/Sources/Presenter/Views/Slider.swift +++ b/Sources/Presenter/Views/Slider.swift @@ -1,5 +1,5 @@ -public struct Slider: SwiftUIView { +public struct Slider: CodableView { // MARK: Stored Properties @@ -35,17 +35,17 @@ extension Slider: CustomStringConvertible { #if canImport(SwiftUI) -extension Slider { +extension Slider: SwiftUI.View { #if os(tvOS) - public var view: AnyView { - Nil().eraseToAnyView() + public var body: some SwiftUI.View { + SwiftUI.EmptyView() } #else - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { ModelView { model in SwiftUI.Slider( value: model.binding(for: self.value), diff --git a/Sources/Presenter/Views/Spacer.swift b/Sources/Presenter/Views/Spacer.swift index 65b0bce..870955d 100644 --- a/Sources/Presenter/Views/Spacer.swift +++ b/Sources/Presenter/Views/Spacer.swift @@ -1,5 +1,5 @@ -public struct Spacer: SwiftUIView { +public struct Spacer: CodableView { // MARK: Stored Properties @@ -31,9 +31,9 @@ extension Spacer: CustomStringConvertible { #if canImport(SwiftUI) -extension Spacer { +extension Spacer: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { ModelView { model in SwiftUI.Spacer( minLength: self.minLength.get(from: model) diff --git a/Sources/Presenter/Views/TabView.swift b/Sources/Presenter/Views/TabView.swift index cbebcba..89c854f 100644 --- a/Sources/Presenter/Views/TabView.swift +++ b/Sources/Presenter/Views/TabView.swift @@ -1,5 +1,5 @@ -public struct TabView: SwiftUIView { +public struct TabView: CodableView { // MARK: Stored Properties @@ -8,9 +8,9 @@ public struct TabView: SwiftUIView { // MARK: Initialization - public init( + public init( selection: Binding? = nil, - content: Content + content: View ) { self.selection = selection self.content = CoderView(content) @@ -32,11 +32,11 @@ extension TabView: CustomStringConvertible { #if canImport(SwiftUI) -extension TabView { +extension TabView: SwiftUI.View { #if !os(macOS) && !targetEnvironment(macCatalyst) && !os(watchOS) - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { ModelView { model in SwiftUI.TabView( selection: selection.map(model.binding), @@ -47,7 +47,7 @@ extension TabView { #elseif os(watchOS) - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { if #available(watchOS 7.0, *) { ModelView { model in SwiftUI.TabView( @@ -62,7 +62,7 @@ extension TabView { #else - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { SwiftUI.EmptyView() } diff --git a/Sources/Presenter/Views/Text.swift b/Sources/Presenter/Views/Text.swift index 54c2a97..332ec63 100644 --- a/Sources/Presenter/Views/Text.swift +++ b/Sources/Presenter/Views/Text.swift @@ -1,5 +1,5 @@ -public struct Text: SwiftUIView { +public struct Text: CodableView { // MARK: Stored Properties @@ -31,9 +31,9 @@ extension Text: CustomStringConvertible { #if canImport(SwiftUI) -extension Text { +extension Text: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { ModelView { model in SwiftUI.Text(self.text.get(from: model)) } diff --git a/Sources/Presenter/Views/TextEditor.swift b/Sources/Presenter/Views/TextEditor.swift index c16c87a..6940762 100644 --- a/Sources/Presenter/Views/TextEditor.swift +++ b/Sources/Presenter/Views/TextEditor.swift @@ -1,5 +1,5 @@ -public struct TextEditor: SwiftUIView { +public struct TextEditor: CodableView { // MARK: Stored Properties @@ -27,12 +27,12 @@ extension TextEditor: CustomStringConvertible { #if canImport(SwiftUI) -extension TextEditor { +extension TextEditor: SwiftUI.View { #if !os(watchOS) && !os(macOS) && !os(tvOS) && !targetEnvironment(macCatalyst) @SwiftUI.ViewBuilder - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { if #available(iOS 14.0, *) { ModelView { model in SwiftUI.TextEditor(text: model.binding(for: text)) @@ -45,7 +45,7 @@ extension TextEditor { #else - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { SwiftUI.EmptyView() } diff --git a/Sources/Presenter/Views/TextField.swift b/Sources/Presenter/Views/TextField.swift index 5720b13..23dcc3f 100644 --- a/Sources/Presenter/Views/TextField.swift +++ b/Sources/Presenter/Views/TextField.swift @@ -1,5 +1,5 @@ -public struct TextField: SwiftUIView { +public struct TextField: CodableView { // MARK: Stored Properties @@ -44,9 +44,9 @@ extension TextField: CustomStringConvertible { #if canImport(SwiftUI) -extension TextField { +extension TextField: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { ModelView { model in SwiftUI.TextField( self.title.get(from: model), diff --git a/Sources/Presenter/Views/Toggle.swift b/Sources/Presenter/Views/Toggle.swift index c5b1bb5..2ded570 100644 --- a/Sources/Presenter/Views/Toggle.swift +++ b/Sources/Presenter/Views/Toggle.swift @@ -1,5 +1,5 @@ -public struct Toggle: SwiftUIView { +public struct Toggle: CodableView { // MARK: Stored Properties @@ -8,9 +8,9 @@ public struct Toggle: SwiftUIView { // MARK: Initialization - public init( + public init( isOn: Binding, - label: Label + label: View ) { self.isOn = isOn self.label = CoderView(label) @@ -32,9 +32,9 @@ extension Toggle: CustomStringConvertible { #if canImport(SwiftUI) -extension Toggle { +extension Toggle: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { ModelView { model in SwiftUI.Toggle( isOn: model.binding(for: self.isOn), diff --git a/Sources/Presenter/Views/VGrid.swift b/Sources/Presenter/Views/VGrid.swift index 1080d31..1e8f472 100644 --- a/Sources/Presenter/Views/VGrid.swift +++ b/Sources/Presenter/Views/VGrid.swift @@ -1,5 +1,5 @@ -public struct VGrid: InternalView, Codable { +public struct VGrid: CodableWrapperView { // MARK: Stored Properties @@ -11,12 +11,12 @@ public struct VGrid: InternalView, Codable { // MARK: Initialization - public init( + public init( columns: [GridItem], alignment: HorizontalAlignment? = nil, spacing: CGFloat? = nil, pinnedViews: PinnedScrollableViews, - @ViewBuilder content: () -> Content + @ViewBuilder content: () -> View ) { self.columns = columns @@ -46,23 +46,23 @@ extension VGrid { #if !os(macOS) && !targetEnvironment(macCatalyst) - public var view: _View { + public var body: View { if #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) { - return content.apply( + return content.modifier( Modifier(columns: columns.map(\.swiftUIValue), alignment: alignment?.swiftUIValue ?? .center, spacing: spacing, pinnedViews: pinnedViews.swiftUIValue) ) } else { - return SwiftUI.EmptyView() + return Nil() } } #else - public var view: _View { - SwiftUI.EmptyView() + public var body: View { + Nil() } #endif @@ -70,7 +70,7 @@ extension VGrid { } @available(iOS 14.0, macOS 11.0, *) -private struct Modifier: ViewModifier { +private struct Modifier: ViewModifier, SwiftUI.ViewModifier { let columns: [SwiftUI.GridItem] let alignment: SwiftUI.HorizontalAlignment diff --git a/Sources/Presenter/Views/VStack.swift b/Sources/Presenter/Views/VStack.swift index 81d85df..53248b7 100644 --- a/Sources/Presenter/Views/VStack.swift +++ b/Sources/Presenter/Views/VStack.swift @@ -1,5 +1,5 @@ -public struct VStack: InternalView, Codable { +public struct VStack: CodableWrapperView { // MARK: Stored Properties @@ -9,10 +9,10 @@ public struct VStack: InternalView, Codable { // MARK: Initialization - public init( + public init( alignment: HorizontalAlignment? = nil, spacing: CGFloat? = nil, - @ViewBuilder content: () -> Content + @ViewBuilder content: () -> View ) { self.alignment = alignment @@ -38,18 +38,31 @@ extension VStack: CustomStringConvertible { extension VStack { - public var view: _View { + public var body: View { content - .apply(Modifier(alignment: alignment?.swiftUIValue ?? .center, spacing: spacing)) + .modifier(Modifier(alignment: alignment?.swiftUIValue ?? .center, spacing: spacing)) } } -private struct Modifier: ViewModifier { +private struct Modifier: ViewModifier, SwiftUI.ViewModifier { let alignment: SwiftUI.HorizontalAlignment let spacing: CGFloat? + internal init(alignment: SwiftUI.HorizontalAlignment, spacing: CGFloat?) { + self.alignment = alignment + self.spacing = spacing + } + + init(from decoder: Decoder) throws { + fatalError() // TODO + } + + func encode(to encoder: Encoder) throws { + // TODO + } + func body(content: Content) -> some SwiftUI.View { SwiftUI.VStack(alignment: alignment, spacing: spacing) { content diff --git a/Sources/Presenter/Views/ZStack.swift b/Sources/Presenter/Views/ZStack.swift index 60e78a5..4de563e 100644 --- a/Sources/Presenter/Views/ZStack.swift +++ b/Sources/Presenter/Views/ZStack.swift @@ -1,5 +1,5 @@ -public struct ZStack: InternalView, Codable { +public struct ZStack: CodableWrapperView { // MARK: Stored Properties @@ -8,9 +8,9 @@ public struct ZStack: InternalView, Codable { // MARK: Initialization - public init( + public init( alignment: Alignment? = nil, - @ViewBuilder content: () -> Content + @ViewBuilder content: () -> View ) { self.alignment = alignment @@ -35,13 +35,13 @@ extension ZStack: CustomStringConvertible { extension ZStack { - public var view: _View { - content.apply(Modifier(alignment: alignment?.swiftUIValue ?? .center)) + public var body: View { + content.modifier(Modifier(alignment: alignment?.swiftUIValue ?? .center)) } } -private struct Modifier: ViewModifier { +private struct Modifier: ViewModifier, SwiftUI.ViewModifier { let alignment: SwiftUI.Alignment diff --git a/Sources/TracePresenter/TraceGraph.swift b/Sources/TracePresenter/TraceGraph.swift index 6b4fbf0..060d38d 100644 --- a/Sources/TracePresenter/TraceGraph.swift +++ b/Sources/TracePresenter/TraceGraph.swift @@ -1,5 +1,5 @@ -public struct TraceGraph: SwiftUIView { +public struct TraceGraph: CodableView { // MARK: Stored Properties @@ -62,9 +62,9 @@ extension TraceGraph { #if canImport(SwiftUI) -extension TraceGraph { +extension TraceGraph: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { SwiftUI.VStack { SwiftUI.ForEach(spans.indices) { index in SpanRow(span: spans[index]) diff --git a/Sources/TracePresenter/TracePresenter.swift b/Sources/TracePresenter/TracePresenter.swift index c1307d1..d9de6b9 100644 --- a/Sources/TracePresenter/TracePresenter.swift +++ b/Sources/TracePresenter/TracePresenter.swift @@ -3,7 +3,7 @@ public struct TracePresenter: Plugin { public init() {} - public var views: [_CodableView.Type] { + public var views: [CodableView.Type] { [ TraceGraph.self, ] diff --git a/Tests/PresenterTests/PresenterTests.swift b/Tests/PresenterTests/PresenterTests.swift index 8d99cf6..0f77755 100644 --- a/Tests/PresenterTests/PresenterTests.swift +++ b/Tests/PresenterTests/PresenterTests.swift @@ -8,7 +8,7 @@ typealias _Model = Model struct TestAction: Action { func perform(on model: Model) { - model.state["login-title"] = "Success" + model.set("login-title", to: "Success") } } @@ -20,15 +20,15 @@ extension Color { } -struct MyCustomView: View { +struct MyCustomView: UserView { @State("text", default: "") var text - @Binding + @Binding var text2: Value - var body: some View { + var body: View { VStack { TextField(text2, text: $text) MyCustomView2() @@ -37,9 +37,9 @@ struct MyCustomView: View { } -struct MyCustomView2: View { +struct MyCustomView2: UserView { - var body: some View { + var body: View { Text("gallo") } @@ -53,45 +53,24 @@ final class PresenterTests: XCTestCase { print(String(data: data, encoding: .utf8) ?? "nil") } - func testInverseSquareRoot() { - func inverseSquareRoot(of value: Float) -> Float { - let x2 = value * 0.5 - var y = value - var i = withUnsafeBytes(of: value) { $0.load(as: UInt32.self) } - i = 0x5f3759df &- (i &>> 1) - y = withUnsafeBytes(of: i) { $0.load(as: Float.self) } - y = y * (1.5 - (x2 * y * y)) - y = y * (1.5 - (x2 * y * y)) - y = y * (1.5 - (x2 * y * y)) - return y - } - - for _ in 0..<1_000_000 { - let value = Float.random(in: 0...1_000) + .ulpOfOne - let expected = 1 / sqrt(value) - let actual = inverseSquareRoot(of: value) - XCTAssertEqual(expected, actual, accuracy: expected * 0.000_001) - } - } - func testExample() { let optional: Text? = nil let serverView = HStack(spacing: 8) { Text("Hallo") - .padding(8) - .frame(minWidth: 10, idealWidth: 30, maxWidth: 50, - minHeight: 100, idealHeight: 110, maxHeight: 120, - alignment: Alignment.center) + .padding(8) + .frame(minWidth: 10, idealWidth: 30, maxWidth: 50, + minHeight: 100, idealHeight: 110, maxHeight: 120, + alignment: .center) Text("Check") - .frame(width: 100) + .frame(width: 100) optional Text("What") - .padding(8) - .background(Color.gray) + .padding(8) + .background(Color.gray) } check(serverView) @@ -131,8 +110,8 @@ final class PresenterTests: XCTestCase { func testJSAction() { let model = Model() - model.state["two"] = Int(2) - model.state["three"] = Int(3) + model.set("two", to: Int(2)) + model.set("three", to: Int(3)) let action = JavaScriptAction( script: """ var five = two + three @@ -143,8 +122,9 @@ final class PresenterTests: XCTestCase { errorKey: "error" ) action.perform(on: model) - XCTAssert((model.state["error"] as AnyObject) is NSNull, "\(String(describing: model.state["error"]))") - XCTAssertEqual(model.state["five"] as? Int, 5) + XCTAssert((model.get("error") as AnyObject) is NSNull, + "\(String(describing: model.get("error")))") + XCTAssertEqual(model.get("five") as? Int, 5) } private func check(_ serverView: V) { @@ -159,10 +139,6 @@ final class PresenterTests: XCTestCase { } } - static var allTests = [ - ("testExample", testExample), - ] - } #endif From 20843e6274c5f3d6320b4e71ed9313f89288b6c3 Mon Sep 17 00:00:00 2001 From: Paul Kraft Date: Wed, 21 Jul 2021 00:11:38 +0200 Subject: [PATCH 02/10] Make it build on macOS --- Example/Shared/Views/LoginView.swift | 2 +- Sources/Presenter/Views/ColorPicker.swift | 2 +- Sources/Presenter/Views/Link.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Example/Shared/Views/LoginView.swift b/Example/Shared/Views/LoginView.swift index 74c7694..8bc386b 100644 --- a/Example/Shared/Views/LoginView.swift +++ b/Example/Shared/Views/LoginView.swift @@ -21,7 +21,7 @@ struct LoginView: UserView { Button(Text("Login"), action: LoginAction()) } .padding(16) - .background(Color(red: 1, green: 1, blue: 1)) + .background(Color(red: 0.6, green: 0.6, blue: 0.6)) .cornerRadius(8) .shadow(radius: 8) .padding(16) diff --git a/Sources/Presenter/Views/ColorPicker.swift b/Sources/Presenter/Views/ColorPicker.swift index b01f5af..ef21c70 100644 --- a/Sources/Presenter/Views/ColorPicker.swift +++ b/Sources/Presenter/Views/ColorPicker.swift @@ -59,7 +59,7 @@ private struct Modifier: ViewModifier, SwiftUI.ViewModifier { let supportsOpacity: Bool func body(content: Content) -> some SwiftUI.View { - if #available(iOS 14.0, *) { + if #available(iOS 14.0, macOS 11.0, *) { ModelView { model in SwiftUI.ColorPicker( selection: model.binding(for: color) { $0.body }, diff --git a/Sources/Presenter/Views/Link.swift b/Sources/Presenter/Views/Link.swift index 0113ad1..844989b 100644 --- a/Sources/Presenter/Views/Link.swift +++ b/Sources/Presenter/Views/Link.swift @@ -42,7 +42,7 @@ private struct Modifier: ViewModifier, SwiftUI.ViewModifier { let destination: String func body(content: Content) -> some SwiftUI.View { - if #available(iOS 14.0, *), let url = URL(string: destination) { + if #available(iOS 14.0, macOS 11.0, *), let url = URL(string: destination) { SwiftUI.Link(destination: url) { content } } else { content From fd83f373edad9537dfcc1aa6dce54e797010e5f0 Mon Sep 17 00:00:00 2001 From: Paul Kraft Date: Wed, 21 Jul 2021 00:16:50 +0200 Subject: [PATCH 03/10] Fix linux builds --- Sources/Presenter/View - General/View.swift | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Sources/Presenter/View - General/View.swift b/Sources/Presenter/View - General/View.swift index bd6a41f..9406040 100644 --- a/Sources/Presenter/View - General/View.swift +++ b/Sources/Presenter/View - General/View.swift @@ -20,9 +20,10 @@ public protocol WrapperView: View { } +#if canImport(SwiftUI) + extension WrapperView { - #if canImport(SwiftUI) public func eraseToAnyView() -> AnyView { body.eraseToAnyView() @@ -32,10 +33,10 @@ extension WrapperView { body.apply(modifier) } - #endif - } +#endif + public protocol UserView: WrapperView { var body: View { get } @@ -50,6 +51,8 @@ extension UserView { } +#if canImport(SwiftUI) + extension View where Self: SwiftUI.View { public func eraseToAnyView() -> AnyView { @@ -61,3 +64,5 @@ extension View where Self: SwiftUI.View { } } + +#endif From fbd213fb4723202b2257e093f0b4e7d1e2dc7285 Mon Sep 17 00:00:00 2001 From: Paul Kraft Date: Wed, 21 Jul 2021 00:19:13 +0200 Subject: [PATCH 04/10] Remove Example from Linux builds --- Package.swift | 8 -------- Sources/Presenter/View - General/View.swift | 1 - 2 files changed, 9 deletions(-) diff --git a/Package.swift b/Package.swift index c7c36a2..75abebe 100644 --- a/Package.swift +++ b/Package.swift @@ -81,10 +81,6 @@ let package = Package( .library( name: "TracePresenter", targets: ["TracePresenter"] - ), - .executable( - name: "Example", - targets: ["Example", "Presenter"] ) ], dependencies: [], @@ -108,10 +104,6 @@ let package = Package( .testTarget( name: "PresenterTests", dependencies: ["Presenter", "ChartPresenter", "MetricPresenter", "TracePresenter"] - ), - .executableTarget( - name: "Example", - dependencies: ["Presenter"] ) ] ) diff --git a/Sources/Presenter/View - General/View.swift b/Sources/Presenter/View - General/View.swift index 9406040..8e94322 100644 --- a/Sources/Presenter/View - General/View.swift +++ b/Sources/Presenter/View - General/View.swift @@ -24,7 +24,6 @@ public protocol WrapperView: View { extension WrapperView { - public func eraseToAnyView() -> AnyView { body.eraseToAnyView() } From cfc07c90140c4e24112b3ff7fa6cfffc7c8cb398 Mon Sep 17 00:00:00 2001 From: Paul Kraft Date: Wed, 21 Jul 2021 00:25:50 +0200 Subject: [PATCH 05/10] swiftlint autocorrect --- Example/Shared/Actions/LoadAction.swift | 2 -- Example/Shared/Actions/LoginAction.swift | 2 -- Example/Shared/Actions/LogoutAction.swift | 2 -- Example/Shared/App/AppPlugin.swift | 6 ++---- Example/Shared/App/ExampleApp.swift | 2 -- Example/Shared/App/Model+Key.swift | 6 ------ Example/Shared/Views/ContentView.swift | 2 -- Example/Shared/Views/HomeView.swift | 2 -- Example/Shared/Views/LoginView.swift | 2 -- Package.swift | 2 +- Sources/ChartPresenter/Chart+AreaStyle.swift | 3 --- Sources/ChartPresenter/Chart+Charts.swift | 13 ------------- Sources/ChartPresenter/Chart+ColumnStyle.swift | 5 ----- Sources/ChartPresenter/Chart+LineStyle.swift | 5 ----- .../ChartPresenter/Chart+StackedAreaStyle.swift | 5 ----- Sources/ChartPresenter/Chart+Style.swift | 5 ----- Sources/ChartPresenter/Chart.swift | 9 --------- Sources/ChartPresenter/Exports.swift | 1 - Sources/ChartPresenter/UIservCharts.swift | 5 +---- Sources/Example/App.swift | 2 -- Sources/Example/ContentView.swift | 3 --- Sources/Example/main.swift | 1 - Sources/MetricPresenter/Card.swift | 11 ----------- Sources/MetricPresenter/Exports.swift | 1 - Sources/MetricPresenter/Gauge.swift | 9 --------- Sources/MetricPresenter/Graph+Grid.swift | 7 ------- Sources/MetricPresenter/Graph+Labeling.swift | 10 ---------- Sources/MetricPresenter/Graph+LabelingEdge.swift | 9 --------- Sources/MetricPresenter/Graph.swift | 16 ---------------- Sources/MetricPresenter/MetricCard.swift | 7 ------- Sources/MetricPresenter/MetricPresenter.swift | 9 +++------ Sources/MetricPresenter/SizePreferenceKey.swift | 3 --- .../Configuration/Configuration+Plugin.swift | 11 ----------- .../Configuration/Configuration+Use.swift | 3 --- .../Presenter/Configuration/Configuration.swift | 7 ------- .../Presenter/Configuration/DefaultPlugin.swift | 9 +++------ Sources/Presenter/Configuration/Exports.swift | 1 - Sources/Presenter/Configuration/NamedType.swift | 3 --- Sources/Presenter/Configuration/Plugin.swift | 5 ----- Sources/Presenter/Model/Action.swift | 3 --- Sources/Presenter/Model/Binding.swift | 3 --- Sources/Presenter/Model/CoderAction.swift | 7 ------- Sources/Presenter/Model/ComposedAction.swift | 3 --- Sources/Presenter/Model/CopyAction.swift | 3 --- Sources/Presenter/Model/JavaScriptAction.swift | 11 +---------- Sources/Presenter/Model/Model.swift | 3 --- Sources/Presenter/Model/ModelView.swift | 3 --- Sources/Presenter/Model/SetAction.swift | 3 --- Sources/Presenter/Model/State.swift | 3 --- Sources/Presenter/Model/Value.swift | 3 --- Sources/Presenter/Types/Alignment.swift | 7 ------- Sources/Presenter/Types/Angle.swift | 7 ------- Sources/Presenter/Types/Animation.swift | 16 ---------------- Sources/Presenter/Types/AxisSet.swift | 4 ---- Sources/Presenter/Types/ColorCode.swift | 5 ----- Sources/Presenter/Types/Font.swift | 15 --------------- Sources/Presenter/Types/Gradient.swift | 9 --------- Sources/Presenter/Types/GridItem.swift | 11 ----------- .../Presenter/Types/PinnedScrollableViews.swift | 5 ----- Sources/Presenter/Types/RoundedCornerStyle.swift | 3 --- Sources/Presenter/Types/UnitPoint.swift | 5 ----- Sources/Presenter/View - General/CoderView.swift | 9 --------- .../Presenter/View - General/ServedView.swift | 6 ------ Sources/Presenter/View - General/View.swift | 13 ------------- .../Presenter/View - General/ViewBuilder.swift | 3 --- .../CoderViewModifier.swift | 10 ---------- .../ViewModifier - General/ViewModifier.swift | 9 --------- .../Presenter/ViewModifiers/AccentColor.swift | 8 -------- .../ViewModifiers/AnimationModifier.swift | 9 --------- .../Presenter/ViewModifiers/AspectRatio.swift | 11 ----------- Sources/Presenter/ViewModifiers/Background.swift | 11 ----------- Sources/Presenter/ViewModifiers/Blur.swift | 8 -------- Sources/Presenter/ViewModifiers/Clipped.swift | 9 --------- .../Presenter/ViewModifiers/CornerRadius.swift | 8 -------- .../Presenter/ViewModifiers/DrawingGroup.swift | 11 ----------- .../Presenter/ViewModifiers/DynamicFrame.swift | 9 --------- .../Presenter/ViewModifiers/FontModifier.swift | 9 --------- .../ViewModifiers/ForegroundColor.swift | 9 --------- Sources/Presenter/ViewModifiers/Frame.swift | 9 --------- .../Presenter/ViewModifiers/LayoutPriority.swift | 8 -------- .../ViewModifiers/LifecycleModifier.swift | 9 --------- Sources/Presenter/ViewModifiers/Mask.swift | 11 ----------- .../ViewModifiers/NavigationBarTitle.swift | 10 ---------- Sources/Presenter/ViewModifiers/Opacity.swift | 8 -------- Sources/Presenter/ViewModifiers/Overlay.swift | 11 ----------- Sources/Presenter/ViewModifiers/Padding.swift | 9 --------- Sources/Presenter/ViewModifiers/Shadow.swift | 8 -------- Sources/Presenter/ViewModifiers/Sheet.swift | 11 ----------- Sources/Presenter/Views/AngularGradient.swift | 10 ---------- Sources/Presenter/Views/ArrayView.swift | 7 ------- Sources/Presenter/Views/Button.swift | 9 --------- Sources/Presenter/Views/Capsule.swift | 7 ------- Sources/Presenter/Views/Circle.swift | 7 ------- Sources/Presenter/Views/Color.swift | 7 ------- Sources/Presenter/Views/ColorPicker.swift | 9 --------- Sources/Presenter/Views/ComposedView.swift | 9 --------- Sources/Presenter/Views/DataView.swift | 9 --------- Sources/Presenter/Views/Divider.swift | 7 ------- Sources/Presenter/Views/HGrid.swift | 16 +++------------- Sources/Presenter/Views/HStack.swift | 10 ---------- Sources/Presenter/Views/If.swift | 11 ----------- Sources/Presenter/Views/Image.swift | 13 ------------- Sources/Presenter/Views/LinearGradient.swift | 8 -------- Sources/Presenter/Views/Link.swift | 9 --------- Sources/Presenter/Views/Local.swift | 7 ------- Sources/Presenter/Views/NavigationLink.swift | 11 ----------- Sources/Presenter/Views/NavigationView.swift | 9 --------- Sources/Presenter/Views/Nil.swift | 9 --------- Sources/Presenter/Views/Path.swift | 7 ------- Sources/Presenter/Views/ScrollView.swift | 9 --------- Sources/Presenter/Views/Section.swift | 13 ------------- Sources/Presenter/Views/SecureField.swift | 7 ------- Sources/Presenter/Views/Slider.swift | 7 ------- Sources/Presenter/Views/Spacer.swift | 7 ------- Sources/Presenter/Views/TabView.swift | 7 ------- Sources/Presenter/Views/Text.swift | 7 ------- Sources/Presenter/Views/TextEditor.swift | 8 -------- Sources/Presenter/Views/TextField.swift | 7 ------- Sources/Presenter/Views/Toggle.swift | 7 ------- Sources/Presenter/Views/VGrid.swift | 15 ++------------- Sources/Presenter/Views/VStack.swift | 11 ----------- Sources/Presenter/Views/ZStack.swift | 11 ----------- Sources/TracePresenter/Exports.swift | 1 - Sources/TracePresenter/TraceGraph.swift | 11 ----------- Sources/TracePresenter/TracePresenter.swift | 5 +---- Tests/PresenterTests/PresenterTests.swift | 9 --------- Tests/PresenterTests/TracePresenterTests.swift | 9 ++------- 127 files changed, 19 insertions(+), 907 deletions(-) diff --git a/Example/Shared/Actions/LoadAction.swift b/Example/Shared/Actions/LoadAction.swift index 9ed9092..2002887 100644 --- a/Example/Shared/Actions/LoadAction.swift +++ b/Example/Shared/Actions/LoadAction.swift @@ -8,9 +8,7 @@ import Presenter struct LoadAction: Action { - func perform(on model: Model) { // TODO } - } diff --git a/Example/Shared/Actions/LoginAction.swift b/Example/Shared/Actions/LoginAction.swift index 566b9a0..0d5bfde 100644 --- a/Example/Shared/Actions/LoginAction.swift +++ b/Example/Shared/Actions/LoginAction.swift @@ -8,7 +8,6 @@ import Presenter struct LoginAction: Action { - func perform(on model: Model) { guard let username = model[.username], let password = model[.password] else { @@ -28,5 +27,4 @@ struct LoginAction: Action { model[.authenticationToken] = prefix + ":" + suffix model[.isAuthenticated] = true } - } diff --git a/Example/Shared/Actions/LogoutAction.swift b/Example/Shared/Actions/LogoutAction.swift index 6f1ec2e..35a63af 100644 --- a/Example/Shared/Actions/LogoutAction.swift +++ b/Example/Shared/Actions/LogoutAction.swift @@ -7,12 +7,10 @@ import Presenter struct LogoutAction: Action { - func perform(on model: Model) { model[.username] = nil model[.password] = nil model[.authenticationToken] = nil model[.isAuthenticated] = false } - } diff --git a/Example/Shared/App/AppPlugin.swift b/Example/Shared/App/AppPlugin.swift index 0c2232e..58c344b 100644 --- a/Example/Shared/App/AppPlugin.swift +++ b/Example/Shared/App/AppPlugin.swift @@ -10,11 +10,10 @@ import MetricPresenter import TracePresenter struct AppPlugin: Plugin { - var plugins: [Plugin] { [ MetricPresenter(), - TracePresenter(), + TracePresenter() ] } @@ -22,8 +21,7 @@ struct AppPlugin: Plugin { [ LoadAction.self, LoginAction.self, - LogoutAction.self, + LogoutAction.self ] } - } diff --git a/Example/Shared/App/ExampleApp.swift b/Example/Shared/App/ExampleApp.swift index 900b4df..eecdf27 100644 --- a/Example/Shared/App/ExampleApp.swift +++ b/Example/Shared/App/ExampleApp.swift @@ -10,7 +10,6 @@ import SwiftUI @main struct ExampleApp: App { - // MARK: Stored Properties @SwiftUI.StateObject private var model = Model() @@ -52,5 +51,4 @@ struct ExampleApp: App { } return nil } - } diff --git a/Example/Shared/App/Model+Key.swift b/Example/Shared/App/Model+Key.swift index 7067fa2..1a2643c 100644 --- a/Example/Shared/App/Model+Key.swift +++ b/Example/Shared/App/Model+Key.swift @@ -8,7 +8,6 @@ import Presenter extension Model.Key { - static var username: Model.Key { .init(rawValue: "login-username") } @@ -40,19 +39,15 @@ extension Model.Key { static var allRecipeIdentifiers: Model.Key<[String]> { .init(rawValue: "recipe-all-ids") } - } extension State { - init(_ key: Model.Key, default defaultValue: Content) { self.init(key.rawValue, default: defaultValue) } - } extension Model { - struct Key { let rawValue: String } @@ -61,5 +56,4 @@ extension Model { get { get(key.rawValue) as? Value } set { set(key.rawValue, to: newValue) } } - } diff --git a/Example/Shared/Views/ContentView.swift b/Example/Shared/Views/ContentView.swift index b256c84..c928695 100644 --- a/Example/Shared/Views/ContentView.swift +++ b/Example/Shared/Views/ContentView.swift @@ -11,7 +11,6 @@ typealias PresenterModel = Model typealias PresenterView = View struct ContentView: UserView { - @State(.isAuthenticated, default: false) var isAuthenticated var body: View { @@ -19,5 +18,4 @@ struct ContentView: UserView { then: HomeView(), else: LoginView()) } - } diff --git a/Example/Shared/Views/HomeView.swift b/Example/Shared/Views/HomeView.swift index 0bf0edd..2cb2b35 100644 --- a/Example/Shared/Views/HomeView.swift +++ b/Example/Shared/Views/HomeView.swift @@ -8,7 +8,6 @@ import Presenter struct HomeView: UserView { - var body: View { VStack(spacing: 8) { Text("You are logged in!") @@ -16,5 +15,4 @@ struct HomeView: UserView { } .onAppear(perform: LoadAction()) } - } diff --git a/Example/Shared/Views/LoginView.swift b/Example/Shared/Views/LoginView.swift index 8bc386b..87b961f 100644 --- a/Example/Shared/Views/LoginView.swift +++ b/Example/Shared/Views/LoginView.swift @@ -8,7 +8,6 @@ import Presenter struct LoginView: UserView { - @State(.username, default: "") var username @State(.password, default: "") var password @State(.showLoginError, default: false) var showLoginError @@ -27,5 +26,4 @@ struct LoginView: UserView { .padding(16) .sheet(isPresented: $showLoginError, content: Text(loginErrorMessage)) } - } diff --git a/Package.swift b/Package.swift index 75abebe..dbcbfe3 100644 --- a/Package.swift +++ b/Package.swift @@ -30,7 +30,7 @@ let package = Package( ) ], dependencies: [ - .package(name: "Charts", url: "https://github.com/spacenation/swiftui-charts.git", from: "1.0.0"), + .package(name: "Charts", url: "https://github.com/spacenation/swiftui-charts.git", from: "1.0.0") ], targets: [ .target( diff --git a/Sources/ChartPresenter/Chart+AreaStyle.swift b/Sources/ChartPresenter/Chart+AreaStyle.swift index d19feb1..e49d312 100644 --- a/Sources/ChartPresenter/Chart+AreaStyle.swift +++ b/Sources/ChartPresenter/Chart+AreaStyle.swift @@ -1,6 +1,4 @@ - extension Chart { - public struct AreaStyle: Codable { public internal(set) var lineType: LineType public internal(set) var fill: CoderView @@ -10,5 +8,4 @@ extension Chart { self.fill = CoderView(fill) } } - } diff --git a/Sources/ChartPresenter/Chart+Charts.swift b/Sources/ChartPresenter/Chart+Charts.swift index 4e11fcd..d37c722 100644 --- a/Sources/ChartPresenter/Chart+Charts.swift +++ b/Sources/ChartPresenter/Chart+Charts.swift @@ -1,8 +1,6 @@ - #if canImport(Charts) extension Chart.Style { - @SwiftUI.ViewBuilder func chart(for data: [[Double]]) -> some SwiftUI.View { switch self { @@ -25,46 +23,36 @@ extension Chart.Style { Charts.Chart(data: data) .chartStyle(style) } - } extension Chart.ColumnStyle { - fileprivate var chartsValue: ColumnChartStyle { .init(column: column.eraseToAnyView(), spacing: spacing) } - } extension Chart.StackedAreaStyle { - fileprivate var chartsValue: StackedAreaChartStyle { .init(lineType.chartsValue, colors: colors.map { $0.color.body }) } - } extension Chart.AreaStyle { - fileprivate var chartsValue: AreaChartStyle { .init(lineType.chartsValue, fill: fill.eraseToAnyView()) } - } extension Chart.LineStyle { - fileprivate var chartsValue: LineChartStyle { .init(lineType.chartsValue, lineColor: color.color.body, lineWidth: width) } - } extension Chart.LineType { - fileprivate var chartsValue: Charts.LineType { switch self { case .line: @@ -73,7 +61,6 @@ extension Chart.LineType { return .quadCurve } } - } #endif diff --git a/Sources/ChartPresenter/Chart+ColumnStyle.swift b/Sources/ChartPresenter/Chart+ColumnStyle.swift index 74f406e..b0dad6c 100644 --- a/Sources/ChartPresenter/Chart+ColumnStyle.swift +++ b/Sources/ChartPresenter/Chart+ColumnStyle.swift @@ -1,8 +1,5 @@ - extension Chart { - public struct ColumnStyle: Codable { - public internal(set) var column: CoderView public internal(set) var spacing: CGFloat @@ -10,7 +7,5 @@ extension Chart { self.column = CoderView(column) self.spacing = spacing } - } - } diff --git a/Sources/ChartPresenter/Chart+LineStyle.swift b/Sources/ChartPresenter/Chart+LineStyle.swift index f47edfe..c8ebe61 100644 --- a/Sources/ChartPresenter/Chart+LineStyle.swift +++ b/Sources/ChartPresenter/Chart+LineStyle.swift @@ -1,8 +1,5 @@ - extension Chart { - public struct LineStyle: Codable { - public internal(set) var lineType: LineType public internal(set) var color: ColorCode public internal(set) var width: CGFloat @@ -12,12 +9,10 @@ extension Chart { self.color = ColorCode(color) self.width = width } - } public enum LineType: String, Codable { case line case quadCurve } - } diff --git a/Sources/ChartPresenter/Chart+StackedAreaStyle.swift b/Sources/ChartPresenter/Chart+StackedAreaStyle.swift index 02f4a68..f333b16 100644 --- a/Sources/ChartPresenter/Chart+StackedAreaStyle.swift +++ b/Sources/ChartPresenter/Chart+StackedAreaStyle.swift @@ -1,8 +1,5 @@ - extension Chart { - public struct StackedAreaStyle: Codable { - public internal(set) var lineType: LineType public internal(set) var colors: [ColorCode] @@ -10,7 +7,5 @@ extension Chart { self.lineType = lineType self.colors = colors.map(ColorCode.init) } - } - } diff --git a/Sources/ChartPresenter/Chart+Style.swift b/Sources/ChartPresenter/Chart+Style.swift index fb67fd6..3a6c8c5 100644 --- a/Sources/ChartPresenter/Chart+Style.swift +++ b/Sources/ChartPresenter/Chart+Style.swift @@ -1,8 +1,5 @@ - extension Chart { - public enum Style: Codable { - // MARK: Nested Types private enum CodingKeys: String, CodingKey { @@ -80,7 +77,5 @@ extension Chart { try style.encode(to: encoder) } } - } - } diff --git a/Sources/ChartPresenter/Chart.swift b/Sources/ChartPresenter/Chart.swift index 717e14d..2d1140e 100644 --- a/Sources/ChartPresenter/Chart.swift +++ b/Sources/ChartPresenter/Chart.swift @@ -1,6 +1,4 @@ - public struct Chart: CodableView { - // MARK: Stored Properties public let data: [[Double]] @@ -17,37 +15,30 @@ public struct Chart: CodableView { self.data = data self.style = style } - } // MARK: - CustomStringConvertible extension Chart: CustomStringConvertible { - public var description: String { "Chart(data: \(data), style: \(style))" } - } #if canImport(Charts) extension Chart: SwiftUI.View { - public var body: some SwiftUI.View { style.chart(for: data) } - } #elseif canImport(SwiftUI) extension Chart: SwiftUI.View { - public var body: some SwiftUI.View { EmptyView() } - } #endif diff --git a/Sources/ChartPresenter/Exports.swift b/Sources/ChartPresenter/Exports.swift index 8c42ccd..50c83b3 100644 --- a/Sources/ChartPresenter/Exports.swift +++ b/Sources/ChartPresenter/Exports.swift @@ -1,4 +1,3 @@ - @_exported import Presenter #if canImport(Charts) diff --git a/Sources/ChartPresenter/UIservCharts.swift b/Sources/ChartPresenter/UIservCharts.swift index 9a26de7..e8883ae 100644 --- a/Sources/ChartPresenter/UIservCharts.swift +++ b/Sources/ChartPresenter/UIservCharts.swift @@ -1,12 +1,9 @@ - public struct ChartPresenter: Plugin { - public init() {} public var views: [CodableView.Type] { [ - Chart.self, + Chart.self ] } - } diff --git a/Sources/Example/App.swift b/Sources/Example/App.swift index c94e401..9234beb 100644 --- a/Sources/Example/App.swift +++ b/Sources/Example/App.swift @@ -1,4 +1,3 @@ - import SwiftUI @available(macOS 11.0, iOS 14.0, *) @@ -17,5 +16,4 @@ struct ExampleApp: App { .environmentObject(model) } } - } diff --git a/Sources/Example/ContentView.swift b/Sources/Example/ContentView.swift index c035e5a..4e0f274 100644 --- a/Sources/Example/ContentView.swift +++ b/Sources/Example/ContentView.swift @@ -1,14 +1,11 @@ - import Presenter typealias PresenterModel = Model struct ContentView: UserView { - @State("text", default: "") var text var body: View { TextField("hallo", text: $text) } - } diff --git a/Sources/Example/main.swift b/Sources/Example/main.swift index 0b8cbab..f9a3a29 100644 --- a/Sources/Example/main.swift +++ b/Sources/Example/main.swift @@ -1,4 +1,3 @@ - import Foundation if #available(OSX 11.0, iOS 14.0, *) { diff --git a/Sources/MetricPresenter/Card.swift b/Sources/MetricPresenter/Card.swift index c5482ed..69e1116 100644 --- a/Sources/MetricPresenter/Card.swift +++ b/Sources/MetricPresenter/Card.swift @@ -1,24 +1,18 @@ - struct Card: CodableViewModifier { - // MARK: Stored Properties var radius: CGFloat? - } extension Card: CustomStringConvertible { - var description: String { "card(cornerRadius: \(radius?.description ?? "nil"))" } - } #if canImport(SwiftUI) extension Card: SwiftUI.ViewModifier { - #if os(macOS) func body(content: Content) -> some SwiftUI.View { @@ -38,23 +32,18 @@ extension Card: SwiftUI.ViewModifier { } #endif - } extension SwiftUI.View { - public func card(cornerRadius: CGFloat? = nil) -> some SwiftUI.View { modifier(Card(radius: cornerRadius)) } - } #endif extension View { - public func card(cornerRadius: CGFloat? = nil) -> View { modifier(Card(radius: cornerRadius)) } - } diff --git a/Sources/MetricPresenter/Exports.swift b/Sources/MetricPresenter/Exports.swift index 01c342d..7d86cf7 100644 --- a/Sources/MetricPresenter/Exports.swift +++ b/Sources/MetricPresenter/Exports.swift @@ -1,2 +1 @@ - @_exported import ChartPresenter diff --git a/Sources/MetricPresenter/Gauge.swift b/Sources/MetricPresenter/Gauge.swift index b61ed50..51bd30a 100644 --- a/Sources/MetricPresenter/Gauge.swift +++ b/Sources/MetricPresenter/Gauge.swift @@ -1,6 +1,4 @@ - public struct Gauge: CodableWrapperView { - // MARK: Stored Properties private let value: CGFloat @@ -38,22 +36,18 @@ public struct Gauge: CodableWrapperView { ) ) } - } struct GaugeModifier: CodableViewModifier { - var value: CGFloat var thickness: CGFloat var scale: CGFloat var colors: [ColorCode] - } #if canImport(SwiftUI) private struct GaugeView: SwiftUI.View { - // MARK: Stored Properties let gauge: GaugeModifier @@ -107,15 +101,12 @@ private struct GaugeView: SwiftUI.View { } .foregroundColor(SwiftUI.Color.black) } - } extension GaugeModifier: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { GaugeView(gauge: self, content: content) } - } private struct GaugeSizePreferenceKey: SizePreferenceKey {} diff --git a/Sources/MetricPresenter/Graph+Grid.swift b/Sources/MetricPresenter/Graph+Grid.swift index bfb2bae..021bfef 100644 --- a/Sources/MetricPresenter/Graph+Grid.swift +++ b/Sources/MetricPresenter/Graph+Grid.swift @@ -1,18 +1,14 @@ - #if canImport(SwiftUI) extension Graph { - struct Grid { let axis: Axis let values: [CGFloat] let lineWidth: CGFloat } - } extension Graph.Grid: SwiftUI.View { - var body: some SwiftUI.View { GeometryReader { geometry in SwiftUI.ZStack(alignment: .topLeading) { @@ -56,11 +52,9 @@ extension Graph.Grid: SwiftUI.View { private var maxHeight: CGFloat? { axis == .vertical ? .infinity : nil } - } extension SwiftUI.View { - public func graphGrid(vertical: [CGFloat] = [], horizontal: [CGFloat] = [], width: CGFloat = 8) -> some SwiftUI.View { SwiftUI.ZStack { Group { @@ -71,7 +65,6 @@ extension SwiftUI.View { self } } - } #endif diff --git a/Sources/MetricPresenter/Graph+Labeling.swift b/Sources/MetricPresenter/Graph+Labeling.swift index f9f83e8..5b18a9d 100644 --- a/Sources/MetricPresenter/Graph+Labeling.swift +++ b/Sources/MetricPresenter/Graph+Labeling.swift @@ -1,10 +1,7 @@ - #if canImport(SwiftUI) extension Graph { - struct Labeling { - // MARK: Stored Properties var top: [Graph.Label] @@ -14,13 +11,10 @@ extension Graph { var spacing: CGFloat var borderWidth: CGFloat - } - } extension Graph.Labeling: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { GeometryReader { geometry in SwiftUI.HStack(spacing: 0) { @@ -62,11 +56,9 @@ extension Graph.Labeling: SwiftUI.ViewModifier { } } } - } extension SwiftUI.View { - public func graphLabeling( top: [Graph.Label] = [], trailing: [Graph.Label] = [], @@ -75,7 +67,6 @@ extension SwiftUI.View { spacing: CGFloat = 6, borderWidth: CGFloat = 36 ) -> some SwiftUI.View { - modifier( Graph.Labeling( top: top, @@ -87,7 +78,6 @@ extension SwiftUI.View { ) ) } - } #endif diff --git a/Sources/MetricPresenter/Graph+LabelingEdge.swift b/Sources/MetricPresenter/Graph+LabelingEdge.swift index d1c89ec..df6d655 100644 --- a/Sources/MetricPresenter/Graph+LabelingEdge.swift +++ b/Sources/MetricPresenter/Graph+LabelingEdge.swift @@ -1,8 +1,6 @@ - #if canImport(SwiftUI) extension Graph.Edge { - var axis: Axis { switch self { case .top, .bottom: @@ -22,22 +20,16 @@ extension Graph.Edge { return .leading } } - } extension Graph { - struct LabelingEdge { - var labels: [Graph.Label] var edge: Graph.Edge - } - } extension Graph.LabelingEdge: SwiftUI.View { - var body: some SwiftUI.View { GeometryReader { geometry in SwiftUI.ZStack(alignment: self.edge.alignment) { @@ -58,7 +50,6 @@ extension Graph.LabelingEdge: SwiftUI.View { return CGSize(width: value * size.width, height: 0) } } - } #endif diff --git a/Sources/MetricPresenter/Graph.swift b/Sources/MetricPresenter/Graph.swift index 472164e..77509b5 100644 --- a/Sources/MetricPresenter/Graph.swift +++ b/Sources/MetricPresenter/Graph.swift @@ -1,10 +1,7 @@ - public struct Graph: CodableView { - // MARK: Nested Types public struct Label: Codable { - // MARK: Stored Properties public var text: String @@ -16,7 +13,6 @@ public struct Graph: CodableView { self.text = text self.value = value } - } public enum Edge: String, Codable { @@ -27,7 +23,6 @@ public struct Graph: CodableView { } public struct DataSet: Codable { - // MARK: Stored Properties public var title: String @@ -43,7 +38,6 @@ public struct Graph: CodableView { self.data = data self.style = style } - } // MARK: Stored Properties @@ -62,7 +56,6 @@ public struct Graph: CodableView { data: [Graph.DataSet], gridWidth: CGFloat ) { - self.labels = [ .top: topLabels, .trailing: trailingLabels, @@ -74,37 +67,29 @@ public struct Graph: CodableView { self.data = data self.gridWidth = gridWidth } - } #if canImport(SwiftUI) extension Graph.Label: Identifiable { - public var id: CGFloat { value } - } extension Graph.DataSet: Identifiable { - public var id: String { title } - } extension Graph.DataSet { - public var chart: Chart { Chart(data: data, style: style) } - } extension Graph: SwiftUI.View { - public var body: some SwiftUI.View { content .graphGrid( @@ -135,7 +120,6 @@ extension Graph: SwiftUI.View { ForEach(data) { $0.chart.body } } } - } #endif diff --git a/Sources/MetricPresenter/MetricCard.swift b/Sources/MetricPresenter/MetricCard.swift index 0ca5c0e..4410353 100644 --- a/Sources/MetricPresenter/MetricCard.swift +++ b/Sources/MetricPresenter/MetricCard.swift @@ -1,17 +1,13 @@ - struct MetricCard: CodableViewModifier { - // MARK: Stored Properties var title: String var subtitle: String - } #if canImport(SwiftUI) extension MetricCard: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { SwiftUI.VStack(alignment: .leading) { SwiftUI.Text(title) @@ -36,15 +32,12 @@ extension MetricCard: SwiftUI.ViewModifier { .card() .padding(8) } - } #endif extension View { - public func metricCard(title: String, subtitle: String) -> View { modifier(MetricCard(title: title, subtitle: subtitle)) } - } diff --git a/Sources/MetricPresenter/MetricPresenter.swift b/Sources/MetricPresenter/MetricPresenter.swift index 4f12a43..79f2bab 100644 --- a/Sources/MetricPresenter/MetricPresenter.swift +++ b/Sources/MetricPresenter/MetricPresenter.swift @@ -1,11 +1,9 @@ - public struct MetricPresenter: Plugin { - public init() {} public var views: [CodableView.Type] { [ - Graph.self, + Graph.self ] } @@ -13,14 +11,13 @@ public struct MetricPresenter: Plugin { [ GaugeModifier.self, MetricCard.self, - Card.self, + Card.self ] } public var plugins: [Plugin.Type] { [ - ChartPresenter.self, + ChartPresenter.self ] } - } diff --git a/Sources/MetricPresenter/SizePreferenceKey.swift b/Sources/MetricPresenter/SizePreferenceKey.swift index 8dcab09..885d8a9 100644 --- a/Sources/MetricPresenter/SizePreferenceKey.swift +++ b/Sources/MetricPresenter/SizePreferenceKey.swift @@ -1,10 +1,8 @@ - #if canImport(SwiftUI) protocol SizePreferenceKey: PreferenceKey where Value == CGSize {} extension SizePreferenceKey { - static var defaultValue: CGSize { .zero } static func reduce(value: inout CGSize, nextValue: () -> CGSize) { @@ -12,7 +10,6 @@ extension SizePreferenceKey { guard next != .zero && next != value else { return } value = next } - } extension SwiftUI.View { diff --git a/Sources/Presenter/Configuration/Configuration+Plugin.swift b/Sources/Presenter/Configuration/Configuration+Plugin.swift index b60ca70..abd377f 100644 --- a/Sources/Presenter/Configuration/Configuration+Plugin.swift +++ b/Sources/Presenter/Configuration/Configuration+Plugin.swift @@ -1,8 +1,6 @@ - import Foundation extension Presenter { - private static var didImportPlugins = false // MARK: Plugins @@ -30,11 +28,9 @@ extension Presenter { plugin.plugins.forEach { $0.remove() } plugin.didRemove() } - } extension View where Self: Codable { - fileprivate static func use() { Presenter.use(view: Self.self) } @@ -42,11 +38,9 @@ extension View where Self: Codable { fileprivate static func remove() { Presenter.remove(view: Self.self) } - } extension ViewModifier where Self: Codable { - fileprivate static func use() { Presenter.use(modifier: Self.self) } @@ -54,11 +48,9 @@ extension ViewModifier where Self: Codable { fileprivate static func remove() { Presenter.remove(modifier: Self.self) } - } extension Action { - fileprivate static func use() { Presenter.use(action: Self.self) } @@ -66,11 +58,9 @@ extension Action { fileprivate static func remove() { Presenter.remove(action: Self.self) } - } extension Plugin { - fileprivate func use() { Presenter.use(plugin: self) } @@ -78,5 +68,4 @@ extension Plugin { fileprivate func remove() { Presenter.remove(plugin: self) } - } diff --git a/Sources/Presenter/Configuration/Configuration+Use.swift b/Sources/Presenter/Configuration/Configuration+Use.swift index 1d1838a..72e8839 100644 --- a/Sources/Presenter/Configuration/Configuration+Use.swift +++ b/Sources/Presenter/Configuration/Configuration+Use.swift @@ -1,6 +1,4 @@ - extension Presenter { - // MARK: View public static func use(view: V.Type) { @@ -30,5 +28,4 @@ extension Presenter { public static func remove(action: A.Type) { CoderAction.unregister(A.self) } - } diff --git a/Sources/Presenter/Configuration/Configuration.swift b/Sources/Presenter/Configuration/Configuration.swift index f4ec8c3..f100f2f 100644 --- a/Sources/Presenter/Configuration/Configuration.swift +++ b/Sources/Presenter/Configuration/Configuration.swift @@ -1,13 +1,10 @@ - public enum Presenter { - // MARK: Decoding public static func decode( from data: Data, decoder: JSONDecoder = .init() ) throws -> View { - try decoder.decode(CoderView.self, from: data) } @@ -17,7 +14,6 @@ public enum Presenter { from data: Decoder.Input, decoder: Decoder ) throws -> View { - try decoder.decode(CoderView.self, from: data) } @@ -29,7 +25,6 @@ public enum Presenter { _ view: View, encoder: JSONEncoder = .init() ) throws -> Data { - try encoder.encode(CoderView(view)) } @@ -39,10 +34,8 @@ public enum Presenter { _ view: View, encoder: Encoder ) throws -> Encoder.Output { - try encoder.encode(CoderView(view)) } #endif - } diff --git a/Sources/Presenter/Configuration/DefaultPlugin.swift b/Sources/Presenter/Configuration/DefaultPlugin.swift index a63d58a..9b64ec5 100644 --- a/Sources/Presenter/Configuration/DefaultPlugin.swift +++ b/Sources/Presenter/Configuration/DefaultPlugin.swift @@ -1,8 +1,6 @@ - import Foundation struct DefaultPlugin: Plugin { - var views: [CodableView.Type] { [ AngularGradient.self, @@ -38,7 +36,7 @@ struct DefaultPlugin: Plugin { Toggle.self, VGrid.self, VStack.self, - ZStack.self, + ZStack.self ] } @@ -63,7 +61,7 @@ struct DefaultPlugin: Plugin { Opacity.self, Padding.self, Shadow.self, - Sheet.self, + Sheet.self ] } @@ -86,8 +84,7 @@ struct DefaultPlugin: Plugin { SetAction.self, SetAction.self, SetAction.self, - SetAction.self, + SetAction.self ] } - } diff --git a/Sources/Presenter/Configuration/Exports.swift b/Sources/Presenter/Configuration/Exports.swift index 4094bd1..b95e2df 100644 --- a/Sources/Presenter/Configuration/Exports.swift +++ b/Sources/Presenter/Configuration/Exports.swift @@ -1,4 +1,3 @@ - @_exported import Foundation #if canImport(Combine) diff --git a/Sources/Presenter/Configuration/NamedType.swift b/Sources/Presenter/Configuration/NamedType.swift index 1130f81..6b887f1 100644 --- a/Sources/Presenter/Configuration/NamedType.swift +++ b/Sources/Presenter/Configuration/NamedType.swift @@ -1,12 +1,9 @@ - public protocol NamedType { static var type: String { get } } extension NamedType { - public static var type: String { String(describing: self) } - } diff --git a/Sources/Presenter/Configuration/Plugin.swift b/Sources/Presenter/Configuration/Plugin.swift index 8f0e005..d5fb227 100644 --- a/Sources/Presenter/Configuration/Plugin.swift +++ b/Sources/Presenter/Configuration/Plugin.swift @@ -1,6 +1,4 @@ - public protocol Plugin { - func willAdd() func didAdd() @@ -11,11 +9,9 @@ public protocol Plugin { var viewModifiers: [CodableViewModifier.Type] { get } var actions: [Action.Type] { get } var plugins: [Plugin] { get } - } extension Plugin { - public func willAdd() {} public func didAdd() {} @@ -26,5 +22,4 @@ extension Plugin { public var viewModifiers: [CodableViewModifier.Type] { [] } public var actions: [Action.Type] { [] } public var plugins: [Plugin] { [] } - } diff --git a/Sources/Presenter/Model/Action.swift b/Sources/Presenter/Model/Action.swift index 95e9caa..d79dfe3 100644 --- a/Sources/Presenter/Model/Action.swift +++ b/Sources/Presenter/Model/Action.swift @@ -1,4 +1,3 @@ - public protocol Action: Codable { static var type: String { get } @@ -8,9 +7,7 @@ public protocol Action: Codable { } extension Action { - public static var type: String { String(describing: Self.self) } - } diff --git a/Sources/Presenter/Model/Binding.swift b/Sources/Presenter/Model/Binding.swift index 978a28a..33c4e4f 100644 --- a/Sources/Presenter/Model/Binding.swift +++ b/Sources/Presenter/Model/Binding.swift @@ -1,7 +1,5 @@ - @propertyWrapper public struct Binding: Codable { - // MARK: Stored Properties let key: String @@ -18,5 +16,4 @@ public struct Binding: Codable { public static func at(_ key: String, default value: Content) -> Self { .init(key: key, default: value) } - } diff --git a/Sources/Presenter/Model/CoderAction.swift b/Sources/Presenter/Model/CoderAction.swift index afe0f2a..82fde7b 100644 --- a/Sources/Presenter/Model/CoderAction.swift +++ b/Sources/Presenter/Model/CoderAction.swift @@ -1,6 +1,4 @@ - public struct CoderAction { - // MARK: Nested Types private enum CodingKeys: String, CodingKey { @@ -46,13 +44,11 @@ public struct CoderAction { try container.encode(typeDescription, forKey: .type) try coder.encode(element, encoder) } - } // MARK: - Registration extension CoderAction { - // MARK: Nested Types private struct Coder { @@ -96,13 +92,11 @@ extension CoderAction { internal static func unregister(_: A.Type) { registeredTypes.removeValue(forKey: A.type) } - } // MARK: - ModelAction extension CoderAction: Action { - #if canImport(SwiftUI) public func perform(on model: Model) { @@ -110,5 +104,4 @@ extension CoderAction: Action { } #endif - } diff --git a/Sources/Presenter/Model/ComposedAction.swift b/Sources/Presenter/Model/ComposedAction.swift index 232e990..fef06f4 100644 --- a/Sources/Presenter/Model/ComposedAction.swift +++ b/Sources/Presenter/Model/ComposedAction.swift @@ -1,6 +1,4 @@ - public struct ComposedAction: Action { - // MARK: Stored Properties fileprivate var actions: [CoderAction] @@ -20,5 +18,4 @@ public struct ComposedAction: Action { } #endif - } diff --git a/Sources/Presenter/Model/CopyAction.swift b/Sources/Presenter/Model/CopyAction.swift index 5b7953a..62227ed 100644 --- a/Sources/Presenter/Model/CopyAction.swift +++ b/Sources/Presenter/Model/CopyAction.swift @@ -1,6 +1,4 @@ - public struct CopyAction: Action { - // MARK: Stored Properties private var from: String @@ -22,5 +20,4 @@ public struct CopyAction: Action { } #endif - } diff --git a/Sources/Presenter/Model/JavaScriptAction.swift b/Sources/Presenter/Model/JavaScriptAction.swift index 8fb81b9..dd365fa 100644 --- a/Sources/Presenter/Model/JavaScriptAction.swift +++ b/Sources/Presenter/Model/JavaScriptAction.swift @@ -1,10 +1,8 @@ - #if canImport(JavaScriptCore) import JavaScriptCore #endif public struct JavaScriptAction: Action { - // MARK: Stored Properties private var inputKeys: [String] @@ -31,14 +29,13 @@ public struct JavaScriptAction: Action { #if canImport(SwiftUI) public func perform(on model: Model) { - #if canImport(JavaScriptCore) guard let context = JSContext() else { return assertionFailure() } - context.exceptionHandler = { context, value in + context.exceptionHandler = { _, value in model.set(errorKey, to: value?.toObject()) } @@ -59,17 +56,13 @@ public struct JavaScriptAction: Action { // Not possible as of now - but is only relevant for watchOS #endif - } #endif - } extension JavaScriptAction { - public struct ScriptInput: ExpressibleByStringLiteral { - // MARK: Stored Properties public var stateKey: String @@ -86,7 +79,5 @@ extension JavaScriptAction { self.stateKey = value self.variableName = value } - } - } diff --git a/Sources/Presenter/Model/Model.swift b/Sources/Presenter/Model/Model.swift index 5c76bc9..e9506b8 100644 --- a/Sources/Presenter/Model/Model.swift +++ b/Sources/Presenter/Model/Model.swift @@ -1,8 +1,6 @@ - #if canImport(SwiftUI) public class Model: ObservableObject { - // MARK: Stored Properties @Published private var state = [String: Any]() @@ -43,7 +41,6 @@ public class Model: ObservableObject { public func set(_ key: String, to value: Any?) { state[key] = value } - } #endif diff --git a/Sources/Presenter/Model/ModelView.swift b/Sources/Presenter/Model/ModelView.swift index f42cd7c..77a38e6 100644 --- a/Sources/Presenter/Model/ModelView.swift +++ b/Sources/Presenter/Model/ModelView.swift @@ -1,8 +1,6 @@ - #if canImport(SwiftUI) public struct ModelView: SwiftUI.View { - // MARK: Stored Properties @EnvironmentObject var model: Model @@ -20,7 +18,6 @@ public struct ModelView: SwiftUI.View { public var body: Body { create(model) } - } #endif diff --git a/Sources/Presenter/Model/SetAction.swift b/Sources/Presenter/Model/SetAction.swift index 9af3d57..ee5acc8 100644 --- a/Sources/Presenter/Model/SetAction.swift +++ b/Sources/Presenter/Model/SetAction.swift @@ -1,6 +1,4 @@ - public struct SetAction: Action { - // MARK: Stored Properties private var key: String @@ -22,5 +20,4 @@ public struct SetAction: Action { } #endif - } diff --git a/Sources/Presenter/Model/State.swift b/Sources/Presenter/Model/State.swift index 2da069d..80f5a44 100644 --- a/Sources/Presenter/Model/State.swift +++ b/Sources/Presenter/Model/State.swift @@ -1,7 +1,5 @@ - @propertyWrapper public struct State: Codable { - // MARK: Stored Properties private let `default`: Content @@ -23,5 +21,4 @@ public struct State: Codable { self.key = key self.default = value } - } diff --git a/Sources/Presenter/Model/Value.swift b/Sources/Presenter/Model/Value.swift index ab0971f..63f946c 100644 --- a/Sources/Presenter/Model/Value.swift +++ b/Sources/Presenter/Model/Value.swift @@ -1,6 +1,4 @@ - public struct Value: Codable { - // MARK: Stored Properties let key: String? @@ -25,5 +23,4 @@ public struct Value: Codable { public static func at(_ key: String, default value: Content) -> Self { .init(key: key, default: value) } - } diff --git a/Sources/Presenter/Types/Alignment.swift b/Sources/Presenter/Types/Alignment.swift index a43ee55..cc46e45 100644 --- a/Sources/Presenter/Types/Alignment.swift +++ b/Sources/Presenter/Types/Alignment.swift @@ -1,4 +1,3 @@ - public enum HorizontalAlignment: String, Codable { case center, leading, trailing } @@ -16,7 +15,6 @@ public enum Alignment: String, Codable { #if canImport(SwiftUI) extension HorizontalAlignment { - var swiftUIValue: SwiftUI.HorizontalAlignment { switch self { case .center: @@ -27,11 +25,9 @@ extension HorizontalAlignment { return .trailing } } - } extension VerticalAlignment { - var swiftUIValue: SwiftUI.VerticalAlignment { switch self { case .center: @@ -42,11 +38,9 @@ extension VerticalAlignment { return .bottom } } - } extension Alignment { - var swiftUIValue: SwiftUI.Alignment { switch self { case .center: @@ -69,7 +63,6 @@ extension Alignment { return .bottomTrailing } } - } #endif diff --git a/Sources/Presenter/Types/Angle.swift b/Sources/Presenter/Types/Angle.swift index 05dff50..62bc30e 100644 --- a/Sources/Presenter/Types/Angle.swift +++ b/Sources/Presenter/Types/Angle.swift @@ -1,6 +1,4 @@ - public struct Angle { - // MARK: Stored Properties public var radians: Double @@ -31,11 +29,9 @@ public struct Angle { public static var zero: Angle { .init(radians: 0) } - } extension Angle: Codable { - public init(from decoder: Decoder) throws { self.init(radians: try .init(from: decoder)) } @@ -43,17 +39,14 @@ extension Angle: Codable { public func encode(to encoder: Encoder) throws { try radians.encode(to: encoder) } - } #if canImport(SwiftUI) extension Angle { - var swiftUIValue: SwiftUI.Angle { .init(radians: radians) } - } #endif diff --git a/Sources/Presenter/Types/Animation.swift b/Sources/Presenter/Types/Animation.swift index efb2b87..6efaebd 100644 --- a/Sources/Presenter/Types/Animation.swift +++ b/Sources/Presenter/Types/Animation.swift @@ -1,6 +1,4 @@ - public struct Animation: Codable { - // MARK: Stored Properties private var kind: Kind @@ -63,7 +61,6 @@ public struct Animation: Codable { public static func timingCurve(c0x: Double, c0y: Double, c1x: Double, c1y: Double, duration: Double? = nil) -> Animation { - Animation(kind: .timingCurve(c0x: c0x, c0y: c0y, c1x: c1x, c1y: c1y, duration: duration)) } @@ -89,11 +86,9 @@ public struct Animation: Codable { public func speed(_ speed: Double) -> Animation { Animation(kind: kind, delay: delay, speed: speed, repeatCount: repeatCount, autoreverses: autoreverses) } - } extension Animation: CustomStringConvertible { - public var description: String { if case .none = kind { return "nil" @@ -119,13 +114,10 @@ extension Animation: CustomStringConvertible { return "Animation.\(kind)" + operators } } - } extension Animation { - enum Kind: Codable { - // MARK: Cases case spring(response: Double?, damping: Double?, blendDuration: Double?) @@ -249,13 +241,10 @@ extension Animation { try container.encode(Name.none, forKey: .name) } } - } - } extension Animation.Kind: CustomStringConvertible { - var description: String { switch self { case let .spring(response, damping, blendDuration): @@ -288,13 +277,11 @@ extension Animation.Kind: CustomStringConvertible { return "none" } } - } #if canImport(SwiftUI) extension Animation { - internal var animation: SwiftUI.Animation? { guard var animation = kind.animation else { return nil @@ -316,11 +303,9 @@ extension Animation { } return animation } - } extension Animation.Kind { - var animation: SwiftUI.Animation? { switch self { case .none: @@ -348,7 +333,6 @@ extension Animation.Kind { return .timingCurve(c0x, c0y, c1x, c1y, duration: duration ?? 0.35) } } - } #endif diff --git a/Sources/Presenter/Types/AxisSet.swift b/Sources/Presenter/Types/AxisSet.swift index 331fa5f..78ee4af 100644 --- a/Sources/Presenter/Types/AxisSet.swift +++ b/Sources/Presenter/Types/AxisSet.swift @@ -1,6 +1,4 @@ - public enum AxisSet: String, Codable, ExpressibleByArrayLiteral { - // MARK: Cases case horizontal = "h" @@ -19,13 +17,11 @@ public enum AxisSet: String, Codable, ExpressibleByArrayLiteral { self = value.contains(.horizontal) ? .horizontal : .none } } - } #if canImport(SwiftUI) extension AxisSet { - var swiftUIValue: Axis.Set { switch self { case .horizontal: diff --git a/Sources/Presenter/Types/ColorCode.swift b/Sources/Presenter/Types/ColorCode.swift index 3028a3b..ad21c4a 100644 --- a/Sources/Presenter/Types/ColorCode.swift +++ b/Sources/Presenter/Types/ColorCode.swift @@ -1,6 +1,4 @@ - public struct ColorCode: Codable { - // MARK: Nested Types private enum Error: Swift.Error { @@ -54,13 +52,11 @@ public struct ColorCode: Codable { var container = encoder.singleValueContainer() try container.encode(description) } - } // MARK: - CustomStringConvertible extension ColorCode: CustomStringConvertible { - public var description: String { fullHex() } @@ -76,5 +72,4 @@ extension ColorCode: CustomStringConvertible { let value = Int(color * Double(UInt8.max)) return String(format: "%02x", value) } - } diff --git a/Sources/Presenter/Types/Font.swift b/Sources/Presenter/Types/Font.swift index 56c200d..8bb4dba 100644 --- a/Sources/Presenter/Types/Font.swift +++ b/Sources/Presenter/Types/Font.swift @@ -1,6 +1,4 @@ - public struct Font: Codable { - // MARK: Nested Types public enum Style: String, Codable { @@ -137,11 +135,9 @@ public struct Font: Codable { font.weight = weight return font } - } extension Font: CustomStringConvertible { - public var description: String { let styling = [weight.map { ".weight(\($0))" }].compactMap { $0 } + (self.styling ?? []).map { "." + $0.rawValue + "()" } @@ -170,13 +166,11 @@ extension Font: CustomStringConvertible { } } } - } #if canImport(SwiftUI) extension Font { - public var swiftUIValue: SwiftUI.Font { (styling ?? []) .reduce(swiftUIValueWithoutStyling.weight(weight?.swiftUIValue ?? .regular)) { $1.apply(to: $0) } @@ -194,11 +188,9 @@ extension Font { design: design?.swiftUIValue ?? .default) } } - } extension Font.Style { - fileprivate var swiftUIValue: SwiftUI.Font.TextStyle { switch self { case .body: @@ -219,11 +211,9 @@ extension Font.Style { return .title } } - } extension Font.Weight { - fileprivate var swiftUIValue: SwiftUI.Font.Weight { switch self { case .black: @@ -246,11 +236,9 @@ extension Font.Weight { return .ultraLight } } - } extension Font.Design { - fileprivate var swiftUIValue: SwiftUI.Font.Design { switch self { case .default: @@ -271,11 +259,9 @@ extension Font.Design { #endif } } - } extension Font.Styling { - fileprivate func apply(to font: SwiftUI.Font) -> SwiftUI.Font { switch self { case .italic: @@ -292,7 +278,6 @@ extension Font.Styling { return font.uppercaseSmallCaps() } } - } #endif diff --git a/Sources/Presenter/Types/Gradient.swift b/Sources/Presenter/Types/Gradient.swift index 769be32..28d12f6 100644 --- a/Sources/Presenter/Types/Gradient.swift +++ b/Sources/Presenter/Types/Gradient.swift @@ -1,10 +1,7 @@ - public struct Gradient: Codable { - // MARK: Nested Types public struct Stop: Codable { - // MARK: Stored Properties public var colorCode: ColorCode @@ -27,7 +24,6 @@ public struct Gradient: Codable { self.colorCode = ColorCode(color) self.location = location } - } // MARK: Stored Properties @@ -45,25 +41,20 @@ public struct Gradient: Codable { public init(stops: [Stop]) { self.stops = stops } - } #if canImport(SwiftUI) extension Gradient { - var swiftUIValue: SwiftUI.Gradient { .init(stops: stops.map(\.swiftUIValue)) } - } extension Gradient.Stop { - var swiftUIValue: SwiftUI.Gradient.Stop { .init(color: color.body, location: location) } - } #endif diff --git a/Sources/Presenter/Types/GridItem.swift b/Sources/Presenter/Types/GridItem.swift index 1f50489..420e5c7 100644 --- a/Sources/Presenter/Types/GridItem.swift +++ b/Sources/Presenter/Types/GridItem.swift @@ -1,16 +1,12 @@ - public struct GridItem: Codable { - // MARK: Nested Types public enum Size { - // MARK: Cases case adaptive(minimum: CGFloat, maximum: CGFloat) case fixed(CGFloat) case flexible(minimum: CGFloat, maximum: CGFloat) - } // MARK: Stored Properties @@ -26,13 +22,11 @@ public struct GridItem: Codable { self.spacing = spacing self.alignment = alignment } - } #if canImport(SwiftUI) extension GridItem { - #if !os(macOS) && !targetEnvironment(macCatalyst) @available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) @@ -41,11 +35,9 @@ extension GridItem { } #endif - } extension GridItem.Size { - #if !os(macOS) && !targetEnvironment(macCatalyst) @available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) @@ -61,13 +53,11 @@ extension GridItem.Size { } #endif - } #endif extension GridItem.Size: Codable { - // MARK: Nested Types enum CodingKeys: String, CodingKey { @@ -126,5 +116,4 @@ extension GridItem.Size: Codable { try container.encode(value, forKey: .value) } } - } diff --git a/Sources/Presenter/Types/PinnedScrollableViews.swift b/Sources/Presenter/Types/PinnedScrollableViews.swift index 60f61b3..cdb60db 100644 --- a/Sources/Presenter/Types/PinnedScrollableViews.swift +++ b/Sources/Presenter/Types/PinnedScrollableViews.swift @@ -1,6 +1,4 @@ - public struct PinnedScrollableViews: Codable, OptionSet { - // MARK: Stored Properties public var rawValue: UInt32 @@ -15,13 +13,11 @@ public struct PinnedScrollableViews: Codable, OptionSet { public static let sectionHeaders: PinnedScrollableViews = .init(rawValue: 1 << 1) public static let sectionFooters: PinnedScrollableViews = .init(rawValue: 1 << 0) - } #if canImport(SwiftUI) extension PinnedScrollableViews { - #if !os(macOS) && !targetEnvironment(macCatalyst) @available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) @@ -37,7 +33,6 @@ extension PinnedScrollableViews { } #endif - } #endif diff --git a/Sources/Presenter/Types/RoundedCornerStyle.swift b/Sources/Presenter/Types/RoundedCornerStyle.swift index 4d9881f..954a2ae 100644 --- a/Sources/Presenter/Types/RoundedCornerStyle.swift +++ b/Sources/Presenter/Types/RoundedCornerStyle.swift @@ -1,4 +1,3 @@ - public enum RoundedCornerStyle: String, Codable { case circular case continuous @@ -7,7 +6,6 @@ public enum RoundedCornerStyle: String, Codable { #if canImport(SwiftUI) extension RoundedCornerStyle { - var swiftUIValue: SwiftUI.RoundedCornerStyle { switch self { case .circular: @@ -16,7 +14,6 @@ extension RoundedCornerStyle { return .continuous } } - } #endif diff --git a/Sources/Presenter/Types/UnitPoint.swift b/Sources/Presenter/Types/UnitPoint.swift index 08769fc..9c44006 100644 --- a/Sources/Presenter/Types/UnitPoint.swift +++ b/Sources/Presenter/Types/UnitPoint.swift @@ -1,6 +1,4 @@ - public struct UnitPoint: Codable { - // MARK: Stored Properties public var x: CGFloat @@ -25,17 +23,14 @@ public struct UnitPoint: Codable { public static let topTrailing = UnitPoint(x: 1, y: 0) public static let trailing = UnitPoint(x: 1, y: 0.5) public static let zero = UnitPoint(x: 0, y: 0) - } #if canImport(SwiftUI) extension UnitPoint { - var unitPoint: SwiftUI.UnitPoint { .init(x: x, y: y) } - } #endif diff --git a/Sources/Presenter/View - General/CoderView.swift b/Sources/Presenter/View - General/CoderView.swift index f8188b6..481ac96 100644 --- a/Sources/Presenter/View - General/CoderView.swift +++ b/Sources/Presenter/View - General/CoderView.swift @@ -1,6 +1,4 @@ - public struct CoderView: CodableView { - // MARK: Nested Types private enum CodingKeys: String, CodingKey { @@ -98,13 +96,11 @@ public struct CoderView: CodableView { try coder.encode(body, encoder) } } - } // MARK: - View Registration extension CoderView { - // MARK: Nested Types private struct Coder { @@ -154,23 +150,19 @@ extension CoderView { internal static func unregister(_: V.Type) { registeredTypes.removeValue(forKey: V.type) } - } // MARK: - CustomStringConvertible extension CoderView: CustomStringConvertible { - public var description: String { "\(body)" } - } #if canImport(SwiftUI) extension CoderView { - public func eraseToAnyView() -> AnyView { body.eraseToAnyView() } @@ -178,7 +170,6 @@ extension CoderView { public func apply(_ modifier: Modifier) -> View { body.apply(modifier) } - } #endif diff --git a/Sources/Presenter/View - General/ServedView.swift b/Sources/Presenter/View - General/ServedView.swift index ee61549..de4c9a2 100644 --- a/Sources/Presenter/View - General/ServedView.swift +++ b/Sources/Presenter/View - General/ServedView.swift @@ -1,8 +1,6 @@ - #if canImport(SwiftUI) && canImport(Combine) public struct ServedView: SwiftUI.View { - // MARK: Nested Types public enum PlaceholderState { @@ -37,7 +35,6 @@ public struct ServedView: SwiftUI.View { model: Model, @SwiftUI.ViewBuilder placeholder: @escaping (PlaceholderState) -> Placeholder ) { - guard let url = url else { self.init( dataPublisher: nil as AnyPublisher?, @@ -74,7 +71,6 @@ public struct ServedView: SwiftUI.View { model: Model, @SwiftUI.ViewBuilder placeholder: @escaping (PlaceholderState) -> Placeholder ) where P.Output == Data { - let viewPublisher = dataPublisher? .tryMap { try Presenter.decode(from: $0).eraseToAnyView() } @@ -90,7 +86,6 @@ public struct ServedView: SwiftUI.View { model: Model, @SwiftUI.ViewBuilder placeholder: @escaping (PlaceholderState) -> Placeholder ) where P.Output == AnyView { - self.publisher = viewPublisher? .mapError { $0 as Error } .eraseToAnyPublisher() @@ -142,7 +137,6 @@ public struct ServedView: SwiftUI.View { .store(in: &cancellables) } } - } #endif diff --git a/Sources/Presenter/View - General/View.swift b/Sources/Presenter/View - General/View.swift index 8e94322..0d132a4 100644 --- a/Sources/Presenter/View - General/View.swift +++ b/Sources/Presenter/View - General/View.swift @@ -1,29 +1,23 @@ - public typealias CodableView = View & Decodable public protocol View: NamedType, Encodable { - #if canImport(SwiftUI) func eraseToAnyView() -> AnyView func apply(_ modifier: Modifier) -> View #endif - } public typealias CodableWrapperView = WrapperView & Decodable public protocol WrapperView: View { - #if canImport(SwiftUI) var body: View { get } #endif - } #if canImport(SwiftUI) extension WrapperView { - public func eraseToAnyView() -> AnyView { body.eraseToAnyView() } @@ -31,29 +25,23 @@ extension WrapperView { public func apply(_ modifier: Modifier) -> View { body.apply(modifier) } - } #endif public protocol UserView: WrapperView { - var body: View { get } - } extension UserView { - func encode(to encoder: Encoder) throws { try body.encode(to: encoder) } - } #if canImport(SwiftUI) extension View where Self: SwiftUI.View { - public func eraseToAnyView() -> AnyView { AnyView(self) } @@ -61,7 +49,6 @@ extension View where Self: SwiftUI.View { public func apply(_ modifier: Modifier) -> View { modifier.body(for: self) } - } #endif diff --git a/Sources/Presenter/View - General/ViewBuilder.swift b/Sources/Presenter/View - General/ViewBuilder.swift index e44444f..1073b4c 100644 --- a/Sources/Presenter/View - General/ViewBuilder.swift +++ b/Sources/Presenter/View - General/ViewBuilder.swift @@ -1,7 +1,5 @@ - @resultBuilder public struct ViewBuilder { - // MARK: Static Functions public static func buildBlock(_ item: V) -> View { @@ -27,5 +25,4 @@ public struct ViewBuilder { static func buildIf(_ content: View?) -> View? { content } - } diff --git a/Sources/Presenter/ViewModifier - General/CoderViewModifier.swift b/Sources/Presenter/ViewModifier - General/CoderViewModifier.swift index 752db2c..b223995 100644 --- a/Sources/Presenter/ViewModifier - General/CoderViewModifier.swift +++ b/Sources/Presenter/ViewModifier - General/CoderViewModifier.swift @@ -1,6 +1,4 @@ - public struct CoderViewModifier: CodableViewModifier { - // MARK: Nested Types private enum CodingKeys: String, CodingKey { @@ -45,23 +43,19 @@ public struct CoderViewModifier: CodableViewModifier { } try coder.encode(element, encoder) } - } // MARK: - CustomStringConvertible extension CoderViewModifier: CustomStringConvertible { - public var description: String { "\(element)" } - } // MARK: - Registration extension CoderViewModifier { - // MARK: Nested Types private struct Coder { @@ -105,7 +99,6 @@ extension CoderViewModifier { public static func unregister(_: Modifier.Type) { registeredTypes.removeValue(forKey: Modifier.type) } - } // MARK: - AnyViewModifying @@ -113,12 +106,9 @@ extension CoderViewModifier { #if canImport(SwiftUI) extension CoderViewModifier { - public func body(for content: Content) -> View { element.body(for: content) } - } #endif - diff --git a/Sources/Presenter/ViewModifier - General/ViewModifier.swift b/Sources/Presenter/ViewModifier - General/ViewModifier.swift index 5b14e03..b8e22ec 100644 --- a/Sources/Presenter/ViewModifier - General/ViewModifier.swift +++ b/Sources/Presenter/ViewModifier - General/ViewModifier.swift @@ -1,29 +1,23 @@ - public typealias CodableViewModifier = Codable & ViewModifier public protocol ViewModifier: NamedType { - #if canImport(SwiftUI) func body(for content: Content) -> View #endif - } #if canImport(SwiftUI) extension ViewModifier where Self: SwiftUI.ViewModifier { - public func body(for content: Content) -> View { content.modifier(self) } - } extension ModifiedContent: View, Encodable, NamedType where Content: SwiftUI.View, Modifier: SwiftUI.ViewModifier { - public func encode(to encoder: Encoder) throws { guard let content = content as? View, let modifier = modifier as? ViewModifier else { @@ -32,17 +26,14 @@ extension ModifiedContent: View, Encodable, NamedType } try modifier.encode(with: content, to: encoder) } - } extension ViewModifier { - fileprivate func encode(with view: View, to encoder: Encoder) throws { try CoderView(view) .modifier(self) .encode(to: encoder) } - } #endif diff --git a/Sources/Presenter/ViewModifiers/AccentColor.swift b/Sources/Presenter/ViewModifiers/AccentColor.swift index 0f0fc9d..2abbe3e 100644 --- a/Sources/Presenter/ViewModifiers/AccentColor.swift +++ b/Sources/Presenter/ViewModifiers/AccentColor.swift @@ -1,20 +1,15 @@ - internal struct AccentColor: CodableViewModifier { - // MARK: Stored Properties let color: ColorCode - } // MARK: - CustomStringConvertible extension AccentColor: CustomStringConvertible { - var description: String { "accentColor(\(color))" } - } // MARK: - ViewModifier @@ -22,7 +17,6 @@ extension AccentColor: CustomStringConvertible { #if canImport(SwiftUI) extension AccentColor: SwiftUI.ViewModifier { - #if os(macOS) func body(content: Content) -> some SwiftUI.View { @@ -43,9 +37,7 @@ extension AccentColor: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func accentColor(_ color: Color) -> View { modifier(AccentColor(color: ColorCode(color))) } - } diff --git a/Sources/Presenter/ViewModifiers/AnimationModifier.swift b/Sources/Presenter/ViewModifiers/AnimationModifier.swift index 140cc5a..a1d0faf 100644 --- a/Sources/Presenter/ViewModifiers/AnimationModifier.swift +++ b/Sources/Presenter/ViewModifiers/AnimationModifier.swift @@ -1,20 +1,15 @@ - internal struct AnimationModifier: CodableViewModifier { - // MARK: Stored Properties let animation: Animation - } // MARK: - CustomStringConvertible extension AnimationModifier: CustomStringConvertible { - var description: String { "animation(\(animation))" } - } // MARK: - ViewModifier @@ -22,11 +17,9 @@ extension AnimationModifier: CustomStringConvertible { #if canImport(SwiftUI) extension AnimationModifier: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { content.animation(animation.animation) } - } #endif @@ -34,9 +27,7 @@ extension AnimationModifier: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func animation(_ animation: Animation?) -> View { modifier(AnimationModifier(animation: animation ?? .none)) } - } diff --git a/Sources/Presenter/ViewModifiers/AspectRatio.swift b/Sources/Presenter/ViewModifiers/AspectRatio.swift index 1471b5b..34313ef 100644 --- a/Sources/Presenter/ViewModifiers/AspectRatio.swift +++ b/Sources/Presenter/ViewModifiers/AspectRatio.swift @@ -1,22 +1,18 @@ - public enum ContentMode: String, Codable { case fit case fill } internal struct AspectRatio: CodableViewModifier { - // MARK: Stored Properties var ratio: CGFloat? var contentMode: ContentMode - } // MARK: - CustomStringConvertible extension AspectRatio: CustomStringConvertible { - var description: String { if let ratio = ratio { return "aspectRatio(\(ratio), contentMode: \(contentMode))" @@ -29,7 +25,6 @@ extension AspectRatio: CustomStringConvertible { return "scaledToFill()" } } - } // MARK: - ViewModifier @@ -37,15 +32,12 @@ extension AspectRatio: CustomStringConvertible { #if canImport(SwiftUI) extension AspectRatio: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { content.aspectRatio(ratio, contentMode: contentMode.swiftUIValue) } - } extension ContentMode { - fileprivate var swiftUIValue: SwiftUI.ContentMode { switch self { case .fill: @@ -54,7 +46,6 @@ extension ContentMode { return .fit } } - } #endif @@ -62,7 +53,6 @@ extension ContentMode { // MARK: - View Extensions extension View { - public func aspectRatio(_ ratio: CGSize, contentMode: ContentMode) -> View { modifier(AspectRatio(ratio: ratio.width / ratio.height, contentMode: contentMode)) } @@ -78,5 +68,4 @@ extension View { public func scaledToFill() -> View { modifier(AspectRatio(ratio: nil, contentMode: .fill)) } - } diff --git a/Sources/Presenter/ViewModifiers/Background.swift b/Sources/Presenter/ViewModifiers/Background.swift index 9efd2cb..b755d83 100644 --- a/Sources/Presenter/ViewModifiers/Background.swift +++ b/Sources/Presenter/ViewModifiers/Background.swift @@ -1,20 +1,15 @@ - internal struct Background: CodableViewModifier { - // MARK: Stored Properties let background: CoderView - } // MARK: - CustomStringConvertible extension Background: CustomStringConvertible { - var description: String { "background(\(background))" } - } // MARK: - ViewModifier @@ -22,21 +17,17 @@ extension Background: CustomStringConvertible { #if canImport(SwiftUI) extension Background { - public func body(for content: Content) -> View { background.modifier(Modifier(foreground: content)) } - } private struct Modifier: ViewModifier, SwiftUI.ViewModifier { - let foreground: Foreground func body(content: Content) -> some SwiftUI.View { foreground.background(content) } - } #endif @@ -44,9 +35,7 @@ private struct Modifier: ViewModifier, SwiftUI.ViewMod // MARK: - View Extensions extension View { - public func background(_ view: View) -> View { modifier(Background(background: CoderView(view))) } - } diff --git a/Sources/Presenter/ViewModifiers/Blur.swift b/Sources/Presenter/ViewModifiers/Blur.swift index fafadbf..17612ff 100644 --- a/Sources/Presenter/ViewModifiers/Blur.swift +++ b/Sources/Presenter/ViewModifiers/Blur.swift @@ -1,21 +1,16 @@ - internal struct Blur: CodableViewModifier { - // MARK: Stored Properties let radius: CGFloat let opaque: Bool? - } // MARK: - CustomStringConvertible extension Blur: CustomStringConvertible { - var description: String { "blur(radius: \(radius), opaque: \(opaque ?? false))" } - } // MARK: - ViewModifier @@ -23,7 +18,6 @@ extension Blur: CustomStringConvertible { #if canImport(SwiftUI) extension Blur: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { content.blur(radius: radius, opaque: opaque ?? false) } @@ -34,9 +28,7 @@ extension Blur: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func blur(radius: CGFloat, opaque: Bool? = nil) -> View { modifier(Blur(radius: radius, opaque: opaque)) } - } diff --git a/Sources/Presenter/ViewModifiers/Clipped.swift b/Sources/Presenter/ViewModifiers/Clipped.swift index ddd1d9e..13fc1c6 100644 --- a/Sources/Presenter/ViewModifiers/Clipped.swift +++ b/Sources/Presenter/ViewModifiers/Clipped.swift @@ -1,20 +1,15 @@ - internal struct Clipped: CodableViewModifier { - // MARK: Stored Properties let antialiased: Bool? - } // MARK: - CustomStringConvertible extension Clipped: CustomStringConvertible { - var description: String { "clipped(antialiased: \(antialiased ?? false))" } - } // MARK: - ViewModifier @@ -22,11 +17,9 @@ extension Clipped: CustomStringConvertible { #if canImport(SwiftUI) extension Clipped: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { content.clipped(antialiased: antialiased ?? false) } - } #endif @@ -34,9 +27,7 @@ extension Clipped: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func clipped(antialiased: Bool? = nil) -> View { modifier(Clipped(antialiased: antialiased)) } - } diff --git a/Sources/Presenter/ViewModifiers/CornerRadius.swift b/Sources/Presenter/ViewModifiers/CornerRadius.swift index a44a175..ce8052b 100644 --- a/Sources/Presenter/ViewModifiers/CornerRadius.swift +++ b/Sources/Presenter/ViewModifiers/CornerRadius.swift @@ -1,21 +1,16 @@ - internal struct CornerRadius: CodableViewModifier { - // MARK: Stored Properties let value: CGFloat let antialiased: Bool? - } // MARK: - CustomStringConvertible extension CornerRadius: CustomStringConvertible { - var description: String { "cornerRadius(\(value), antialiased: \(antialiased ?? true))" } - } // MARK: - ViewModifier @@ -23,7 +18,6 @@ extension CornerRadius: CustomStringConvertible { #if canImport(SwiftUI) extension CornerRadius: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { content.cornerRadius(value, antialiased: antialiased ?? true) } @@ -34,9 +28,7 @@ extension CornerRadius: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func cornerRadius(_ value: CGFloat, antialiased: Bool? = nil) -> View { modifier(CornerRadius(value: value, antialiased: antialiased)) } - } diff --git a/Sources/Presenter/ViewModifiers/DrawingGroup.swift b/Sources/Presenter/ViewModifiers/DrawingGroup.swift index 5b559c8..d6ae2fa 100644 --- a/Sources/Presenter/ViewModifiers/DrawingGroup.swift +++ b/Sources/Presenter/ViewModifiers/DrawingGroup.swift @@ -1,4 +1,3 @@ - public enum ColorRenderingMode: String, Codable { case extendedLinear case linear @@ -6,22 +5,18 @@ public enum ColorRenderingMode: String, Codable { } internal struct DrawingGroup: CodableViewModifier { - // MARK: Stored Properties let opaque: Bool? let colorMode: ColorRenderingMode? - } // MARK: - CustomStringConvertible extension DrawingGroup: CustomStringConvertible { - var description: String { "drawingGroup(opaque: \(opaque ?? true), colorMode: \(colorMode ?? .nonLinear))" } - } // MARK: - ViewModifier @@ -29,16 +24,13 @@ extension DrawingGroup: CustomStringConvertible { #if canImport(SwiftUI) extension DrawingGroup: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { content.drawingGroup(opaque: opaque ?? false, colorMode: colorMode?.swiftUIValue ?? .nonLinear) } - } extension ColorRenderingMode { - var swiftUIValue: SwiftUI.ColorRenderingMode { switch self { case .extendedLinear: @@ -49,7 +41,6 @@ extension ColorRenderingMode { return .nonLinear } } - } #endif @@ -57,9 +48,7 @@ extension ColorRenderingMode { // MARK: - View Extensions extension View { - public func drawingGroup(opaque: Bool? = nil, colorMode: ColorRenderingMode? = nil) -> View { modifier(DrawingGroup(opaque: opaque, colorMode: colorMode)) } - } diff --git a/Sources/Presenter/ViewModifiers/DynamicFrame.swift b/Sources/Presenter/ViewModifiers/DynamicFrame.swift index 9d41edf..6af4f23 100644 --- a/Sources/Presenter/ViewModifiers/DynamicFrame.swift +++ b/Sources/Presenter/ViewModifiers/DynamicFrame.swift @@ -1,6 +1,4 @@ - internal struct DynamicFrame: CodableViewModifier { - // MARK: Stored Properties let minWidth: CGFloat? @@ -12,13 +10,11 @@ internal struct DynamicFrame: CodableViewModifier { let maxHeight: CGFloat? let alignment: Alignment? - } // MARK: - CustomStringConvertible extension DynamicFrame: CustomStringConvertible { - var description: String { let values: [(String, Any?)] = [ ("minWidth", minWidth), ("idealWidth", idealWidth), ("maxWidth", maxWidth), @@ -28,7 +24,6 @@ extension DynamicFrame: CustomStringConvertible { let nonOptionalValues = values.filter { $0.1 != nil } return "frame(\(nonOptionalValues.map { "\($0.0): \($0.1!)" }.joined(separator: ", ")))" } - } // MARK: - ViewModifier @@ -36,7 +31,6 @@ extension DynamicFrame: CustomStringConvertible { #if canImport(SwiftUI) extension DynamicFrame: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { content.frame(minWidth: minWidth, idealWidth: idealWidth, @@ -46,7 +40,6 @@ extension DynamicFrame: SwiftUI.ViewModifier { maxHeight: maxHeight, alignment: alignment?.swiftUIValue ?? .center) } - } #endif @@ -54,7 +47,6 @@ extension DynamicFrame: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func frame(minWidth: CGFloat? = nil, idealWidth: CGFloat? = nil, maxWidth: CGFloat? = nil, @@ -70,5 +62,4 @@ extension View { ) ) } - } diff --git a/Sources/Presenter/ViewModifiers/FontModifier.swift b/Sources/Presenter/ViewModifiers/FontModifier.swift index 21154c8..e16c795 100644 --- a/Sources/Presenter/ViewModifiers/FontModifier.swift +++ b/Sources/Presenter/ViewModifiers/FontModifier.swift @@ -1,20 +1,15 @@ - internal struct FontModifier: CodableViewModifier { - // MARK: Stored Properties let font: Font? - } // MARK: - CustomStringConvertible extension FontModifier: CustomStringConvertible { - var description: String { "font(\(font?.description ?? "nil"))" } - } // MARK: - ViewModifier @@ -22,11 +17,9 @@ extension FontModifier: CustomStringConvertible { #if canImport(SwiftUI) extension FontModifier: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { content.font(font?.swiftUIValue) } - } #endif @@ -34,9 +27,7 @@ extension FontModifier: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func font(_ font: Font?) -> View { modifier(FontModifier(font: font)) } - } diff --git a/Sources/Presenter/ViewModifiers/ForegroundColor.swift b/Sources/Presenter/ViewModifiers/ForegroundColor.swift index 8e4fe4b..03df6e2 100644 --- a/Sources/Presenter/ViewModifiers/ForegroundColor.swift +++ b/Sources/Presenter/ViewModifiers/ForegroundColor.swift @@ -1,20 +1,15 @@ - internal struct ForegroundColor: CodableViewModifier { - // MARK: Stored Properties let color: ColorCode - } // MARK: - CustomStringConvertible extension ForegroundColor: CustomStringConvertible { - var description: String { "foregroundColor(\(color))" } - } // MARK: - ViewModifier @@ -22,11 +17,9 @@ extension ForegroundColor: CustomStringConvertible { #if canImport(SwiftUI) extension ForegroundColor: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { content.foregroundColor(color.color.body) } - } #endif @@ -34,9 +27,7 @@ extension ForegroundColor: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func foregroundColor(_ color: Color) -> View { modifier(ForegroundColor(color: ColorCode(color))) } - } diff --git a/Sources/Presenter/ViewModifiers/Frame.swift b/Sources/Presenter/ViewModifiers/Frame.swift index 9a1a6d1..35de215 100644 --- a/Sources/Presenter/ViewModifiers/Frame.swift +++ b/Sources/Presenter/ViewModifiers/Frame.swift @@ -1,24 +1,19 @@ - internal struct Frame: CodableViewModifier { - // MARK: Stored Properties let height: CGFloat? let width: CGFloat? let alignment: Alignment? - } // MARK: - CustomStringConvertible extension Frame: CustomStringConvertible { - var description: String { let values: [(String, Any?)] = [("height", height), ("width", width), ("alignment", alignment)] let nonOptionalValues = values.filter { $0.1 != nil } return "frame(\(nonOptionalValues.map { "\($0.0): \($0.1!)" }.joined(separator: ", ")))" } - } // MARK: - ViewModifier @@ -26,12 +21,10 @@ extension Frame: CustomStringConvertible { #if canImport(SwiftUI) extension Frame: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { content.frame(width: width, height: height, alignment: alignment?.swiftUIValue ?? .center) } - } #endif @@ -39,11 +32,9 @@ extension Frame: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func frame(width: CGFloat? = nil, height: CGFloat? = nil, alignment: Alignment? = nil) -> View { modifier(Frame(height: height, width: width, alignment: alignment)) } - } diff --git a/Sources/Presenter/ViewModifiers/LayoutPriority.swift b/Sources/Presenter/ViewModifiers/LayoutPriority.swift index d24d4bc..bc7771f 100644 --- a/Sources/Presenter/ViewModifiers/LayoutPriority.swift +++ b/Sources/Presenter/ViewModifiers/LayoutPriority.swift @@ -1,20 +1,15 @@ - internal struct LayoutPriority: CodableViewModifier { - // MARK: Stored Properties let value: Double - } // MARK: - CustomStringConvertible extension LayoutPriority: CustomStringConvertible { - var description: String { "layoutPriority(\(value))" } - } // MARK: - ViewModifier @@ -22,7 +17,6 @@ extension LayoutPriority: CustomStringConvertible { #if canImport(SwiftUI) extension LayoutPriority: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { content.layoutPriority(value) } @@ -33,9 +27,7 @@ extension LayoutPriority: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func layoutPriority(_ value: Double) -> View { modifier(LayoutPriority(value: value)) } - } diff --git a/Sources/Presenter/ViewModifiers/LifecycleModifier.swift b/Sources/Presenter/ViewModifiers/LifecycleModifier.swift index 7b3320e..b277b8e 100644 --- a/Sources/Presenter/ViewModifiers/LifecycleModifier.swift +++ b/Sources/Presenter/ViewModifiers/LifecycleModifier.swift @@ -1,23 +1,18 @@ - internal struct LifecycleModifier: CodableViewModifier { - // MARK: Stored Properties let onAppear: CoderAction? let onDisappear: CoderAction? - } // MARK: - CustomStringConvertible extension LifecycleModifier: CustomStringConvertible { - var description: String { onAppear != nil ? "onAppear(...)" : "onDisappear(...)" } - } // MARK: - ViewModifier @@ -25,7 +20,6 @@ extension LifecycleModifier: CustomStringConvertible { #if canImport(SwiftUI) extension LifecycleModifier: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { ModelView { model in content @@ -33,7 +27,6 @@ extension LifecycleModifier: SwiftUI.ViewModifier { .onDisappear(perform: model.action(for: self.onDisappear)) } } - } #endif @@ -41,7 +34,6 @@ extension LifecycleModifier: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func onAppear(perform action: Action) -> View { modifier(LifecycleModifier(onAppear: CoderAction(action), onDisappear: nil)) } @@ -49,5 +41,4 @@ extension View { public func onDisappear(perform action: Action) -> View { modifier(LifecycleModifier(onAppear: nil, onDisappear: CoderAction(action))) } - } diff --git a/Sources/Presenter/ViewModifiers/Mask.swift b/Sources/Presenter/ViewModifiers/Mask.swift index 80a6a10..2a67ded 100644 --- a/Sources/Presenter/ViewModifiers/Mask.swift +++ b/Sources/Presenter/ViewModifiers/Mask.swift @@ -1,20 +1,15 @@ - internal struct Mask: CodableViewModifier { - // MARK: Stored Properties let mask: CoderView - } // MARK: - CustomStringConvertible extension Mask: CustomStringConvertible { - var description: String { "mask(\(mask))" } - } // MARK: - ViewModifier @@ -22,21 +17,17 @@ extension Mask: CustomStringConvertible { #if canImport(SwiftUI) extension Mask { - public func body(for content: Content) -> View { mask.modifier(Modifier(foreground: content)) } - } private struct Modifier: ViewModifier, SwiftUI.ViewModifier { - let foreground: Foreground func body(content: Content) -> some SwiftUI.View { foreground.mask(content) } - } #endif @@ -44,9 +35,7 @@ private struct Modifier: ViewModifier, SwiftUI.ViewMod // MARK: - View Extensions extension View { - public func mask(_ mask: View) -> View { modifier(Mask(mask: CoderView(mask))) } - } diff --git a/Sources/Presenter/ViewModifiers/NavigationBarTitle.swift b/Sources/Presenter/ViewModifiers/NavigationBarTitle.swift index 1201aaf..f3afc0c 100644 --- a/Sources/Presenter/ViewModifiers/NavigationBarTitle.swift +++ b/Sources/Presenter/ViewModifiers/NavigationBarTitle.swift @@ -1,4 +1,3 @@ - public enum NavigationBarTitleDisplayMode: String, Codable { case inline case automatic @@ -6,22 +5,18 @@ public enum NavigationBarTitleDisplayMode: String, Codable { } internal struct NavigationBarTitle: CodableViewModifier { - // MARK: Stored Properties let title: Value let displayMode: NavigationBarTitleDisplayMode? - } // MARK: - CustomStringConvertible extension NavigationBarTitle: CustomStringConvertible { - var description: String { "navigationBarTitle(\(title), displayMode: \(displayMode ?? .automatic))" } - } // MARK: - ViewModifier @@ -29,7 +24,6 @@ extension NavigationBarTitle: CustomStringConvertible { #if canImport(SwiftUI) extension NavigationBarTitle: SwiftUI.ViewModifier { - #if os(tvOS) || os(watchOS) || os(macOS) func body(content: Content) -> some SwiftUI.View { @@ -46,13 +40,11 @@ extension NavigationBarTitle: SwiftUI.ViewModifier { } #endif - } #if canImport(UIKit) extension NavigationBarTitleDisplayMode { - fileprivate var swiftUIValue: NavigationBarItem.TitleDisplayMode { switch self { case .automatic: @@ -76,10 +68,8 @@ extension NavigationBarTitleDisplayMode { // MARK: - View Extensions extension View { - public func navigationBarTitle(_ title: Value, displayMode: NavigationBarTitleDisplayMode? = nil) -> View { modifier(NavigationBarTitle(title: title, displayMode: displayMode)) } - } diff --git a/Sources/Presenter/ViewModifiers/Opacity.swift b/Sources/Presenter/ViewModifiers/Opacity.swift index 31fb077..5a8a2df 100644 --- a/Sources/Presenter/ViewModifiers/Opacity.swift +++ b/Sources/Presenter/ViewModifiers/Opacity.swift @@ -1,20 +1,15 @@ - internal struct Opacity: CodableViewModifier { - // MARK: Stored Properties let value: Double - } // MARK: - CustomStringConvertible extension Opacity: CustomStringConvertible { - var description: String { "opacity(\(value))" } - } // MARK: - ViewModifier @@ -22,7 +17,6 @@ extension Opacity: CustomStringConvertible { #if canImport(SwiftUI) extension Opacity: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { content.opacity(value) } @@ -33,9 +27,7 @@ extension Opacity: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func opacity(_ value: Double, antialiased: Bool? = nil) -> View { modifier(Opacity(value: value)) } - } diff --git a/Sources/Presenter/ViewModifiers/Overlay.swift b/Sources/Presenter/ViewModifiers/Overlay.swift index aeb07c6..ac84b38 100644 --- a/Sources/Presenter/ViewModifiers/Overlay.swift +++ b/Sources/Presenter/ViewModifiers/Overlay.swift @@ -1,21 +1,16 @@ - internal struct Overlay: CodableViewModifier { - // MARK: Stored Properties let overlay: CoderView let alignment: Alignment? - } // MARK: - CustomStringConvertible extension Overlay: CustomStringConvertible { - var description: String { "overlay(\(overlay), alignment: \(alignment ?? .center))" } - } // MARK: - ViewModifier @@ -23,25 +18,21 @@ extension Overlay: CustomStringConvertible { #if canImport(SwiftUI) extension Overlay { - public func body(for content: Content) -> View { overlay.modifier( Modifier(foreground: content, alignment: alignment?.swiftUIValue ?? .center) ) } - } private struct Modifier: ViewModifier, SwiftUI.ViewModifier { - let foreground: Foreground let alignment: SwiftUI.Alignment func body(content: Content) -> some SwiftUI.View { foreground.overlay(content, alignment: alignment) } - } #endif @@ -49,9 +40,7 @@ private struct Modifier: ViewModifier, SwiftUI.ViewMod // MARK: - View Extensions extension View { - public func overlay(_ overlay: View, alignment: Alignment? = nil) -> View { modifier(Overlay(overlay: CoderView(overlay), alignment: alignment)) } - } diff --git a/Sources/Presenter/ViewModifiers/Padding.swift b/Sources/Presenter/ViewModifiers/Padding.swift index 5de23fe..39f3d50 100644 --- a/Sources/Presenter/ViewModifiers/Padding.swift +++ b/Sources/Presenter/ViewModifiers/Padding.swift @@ -1,25 +1,20 @@ - internal struct Padding: CodableViewModifier { - // MARK: Stored Properties let top: CGFloat? let leading: CGFloat? let bottom: CGFloat? let trailing: CGFloat? - } // MARK: - CustomStringConvertible extension Padding: CustomStringConvertible { - var description: String { let values = [("top", top), ("leading", leading), ("bottom", bottom), ("trailing", trailing)] let nonOptionalValues = values.filter { $0.1 != nil } return "padding(\(nonOptionalValues.map { "\($0.0): \($0.1 ?? 0)" }.joined(separator: ", ")))" } - } // MARK: - ViewModifier @@ -27,12 +22,10 @@ extension Padding: CustomStringConvertible { #if canImport(SwiftUI) extension Padding: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { let insets = EdgeInsets(top: top ?? 0, leading: leading ?? 0, bottom: bottom ?? 0, trailing: trailing ?? 0) return content.padding(insets) } - } #endif @@ -40,7 +33,6 @@ extension Padding: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func padding(top: CGFloat? = nil, leading: CGFloat? = nil, bottom: CGFloat? = nil, trailing: CGFloat? = nil) -> View { modifier(Padding(top: top, leading: leading, bottom: bottom, trailing: trailing)) @@ -49,5 +41,4 @@ extension View { public func padding(_ value: CGFloat) -> View { modifier(Padding(top: value, leading: value, bottom: value, trailing: value)) } - } diff --git a/Sources/Presenter/ViewModifiers/Shadow.swift b/Sources/Presenter/ViewModifiers/Shadow.swift index 5322f24..2240126 100644 --- a/Sources/Presenter/ViewModifiers/Shadow.swift +++ b/Sources/Presenter/ViewModifiers/Shadow.swift @@ -1,19 +1,15 @@ - internal struct Shadow: CodableViewModifier { - // MARK: Stored Properties let color: ColorCode? let radius: CGFloat let x: CGFloat? let y: CGFloat? - } // MARK: - CustomStringConvertible extension Shadow: CustomStringConvertible { - var description: String { if let color = color { return "shadow(color: \(color), radius: \(radius), x: \(x ?? 0), y: \(y ?? 0)" @@ -21,7 +17,6 @@ extension Shadow: CustomStringConvertible { return "shadow(radius: \(radius), x: \(x ?? 0), y: \(y ?? 0)" } } - } // MARK: - ViewModifier @@ -29,7 +24,6 @@ extension Shadow: CustomStringConvertible { #if canImport(SwiftUI) extension Shadow: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { if let color = color { return content.shadow(color: color.color.body, radius: radius, x: x ?? 0, y: y ?? 0) @@ -44,9 +38,7 @@ extension Shadow: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func shadow(color: Color? = nil, radius: CGFloat, x: CGFloat? = nil, y: CGFloat? = nil) -> View { modifier(Shadow(color: color.map(ColorCode.init), radius: radius, x: x, y: y)) } - } diff --git a/Sources/Presenter/ViewModifiers/Sheet.swift b/Sources/Presenter/ViewModifiers/Sheet.swift index 395918b..4b18e08 100644 --- a/Sources/Presenter/ViewModifiers/Sheet.swift +++ b/Sources/Presenter/ViewModifiers/Sheet.swift @@ -1,21 +1,16 @@ - internal struct Sheet: CodableViewModifier { - // MARK: Stored Properties let isPresented: Binding let content: CoderView - } // MARK: - CustomStringConvertible extension Sheet: CustomStringConvertible { - var description: String { "sheet(isPresented: \(isPresented), content: \(content))" } - } // MARK: - ViewModifier @@ -23,15 +18,12 @@ extension Sheet: CustomStringConvertible { #if canImport(SwiftUI) extension Sheet { - func body(for caller: Caller) -> View { content.modifier(Modifier(caller: caller, isPresented: isPresented)) } - } private struct Modifier: ViewModifier, SwiftUI.ViewModifier { - let caller: Caller let isPresented: Binding @@ -44,7 +36,6 @@ private struct Modifier: ViewModifier, SwiftUI.ViewModifie } } } - } #endif @@ -52,9 +43,7 @@ private struct Modifier: ViewModifier, SwiftUI.ViewModifie // MARK: - View Extensions extension View { - public func sheet(isPresented: Binding, content: View) -> View { modifier(Sheet(isPresented: isPresented, content: CoderView(content))) } - } diff --git a/Sources/Presenter/Views/AngularGradient.swift b/Sources/Presenter/Views/AngularGradient.swift index 90beeae..2458d4a 100644 --- a/Sources/Presenter/Views/AngularGradient.swift +++ b/Sources/Presenter/Views/AngularGradient.swift @@ -1,6 +1,4 @@ - public struct AngularGradient: CodableView { - // MARK: Stored Properties private let gradient: Gradient @@ -14,7 +12,6 @@ public struct AngularGradient: CodableView { center: UnitPoint, startAngle: Angle = .zero, endAngle: Angle = .zero) { - self.gradient = gradient self.center = center self.startAngle = startAngle @@ -24,23 +21,19 @@ public struct AngularGradient: CodableView { public init(gradient: Gradient, center: UnitPoint, angle: Angle) { - self.gradient = gradient self.center = center self.startAngle = angle self.endAngle = angle } - } // MARK: - CustomStringConvertible extension AngularGradient: CustomStringConvertible { - public var description: String { "AngularGradient(gradient: \(gradient), center: \(center), startAngle: \(startAngle), endAngle: \(endAngle))" } - } // MARK: - View @@ -48,7 +41,6 @@ extension AngularGradient: CustomStringConvertible { #if canImport(SwiftUI) extension AngularGradient: SwiftUI.View { - public var body: some SwiftUI.View { SwiftUI.AngularGradient( gradient: gradient.swiftUIValue, @@ -57,8 +49,6 @@ extension AngularGradient: SwiftUI.View { endAngle: endAngle.swiftUIValue ) } - } #endif - diff --git a/Sources/Presenter/Views/ArrayView.swift b/Sources/Presenter/Views/ArrayView.swift index 09d1c94..7c91ac8 100644 --- a/Sources/Presenter/Views/ArrayView.swift +++ b/Sources/Presenter/Views/ArrayView.swift @@ -1,6 +1,4 @@ - struct ArrayView: CodableView { - // MARK: Stored Properties let content: [CoderView] @@ -16,17 +14,14 @@ struct ArrayView: CodableView { } } } - } // MARK: - CustomStringConvertible extension ArrayView: CustomStringConvertible { - public var description: String { content.description } - } // MARK: - View @@ -34,13 +29,11 @@ extension ArrayView: CustomStringConvertible { #if canImport(SwiftUI) extension ArrayView: SwiftUI.View { - public var body: some SwiftUI.View { ForEach(content.indices) { index in self.content[index].eraseToAnyView() } } - } #endif diff --git a/Sources/Presenter/Views/Button.swift b/Sources/Presenter/Views/Button.swift index 17d2217..c20c998 100644 --- a/Sources/Presenter/Views/Button.swift +++ b/Sources/Presenter/Views/Button.swift @@ -1,6 +1,4 @@ - public struct Button: CodableWrapperView { - // MARK: Stored Properties let label: CoderView @@ -12,17 +10,14 @@ public struct Button: CodableWrapperView { self.label = CoderView(label) self.action = CoderAction(action) } - } // MARK: - CustomStringConvertible extension Button: CustomStringConvertible { - public var description: String { "Button(\(label))" } - } // MARK: - View @@ -30,15 +25,12 @@ extension Button: CustomStringConvertible { #if canImport(SwiftUI) extension Button { - public var body: View { label.modifier(Modifier(action: action)) } - } private struct Modifier: ViewModifier, SwiftUI.ViewModifier { - let action: CoderAction func body(content: Content) -> some SwiftUI.View { @@ -49,7 +41,6 @@ private struct Modifier: ViewModifier, SwiftUI.ViewModifier { ) } } - } #endif diff --git a/Sources/Presenter/Views/Capsule.swift b/Sources/Presenter/Views/Capsule.swift index 686040d..441dcca 100644 --- a/Sources/Presenter/Views/Capsule.swift +++ b/Sources/Presenter/Views/Capsule.swift @@ -1,6 +1,4 @@ - public struct Capsule: CodableView { - // MARK: Stored Properties private let style: RoundedCornerStyle @@ -10,17 +8,14 @@ public struct Capsule: CodableView { public init(style: RoundedCornerStyle) { self.style = style } - } // MARK: - CustomStringConvertible extension Capsule: CustomStringConvertible { - public var description: String { "Capsule(style: \(style))" } - } // MARK: - View @@ -28,11 +23,9 @@ extension Capsule: CustomStringConvertible { #if canImport(SwiftUI) extension Capsule: SwiftUI.View { - public var body: some SwiftUI.View { SwiftUI.Capsule(style: style.swiftUIValue) } - } #endif diff --git a/Sources/Presenter/Views/Circle.swift b/Sources/Presenter/Views/Circle.swift index 6169d64..add26a9 100644 --- a/Sources/Presenter/Views/Circle.swift +++ b/Sources/Presenter/Views/Circle.swift @@ -1,20 +1,15 @@ - public struct Circle: CodableView { - // MARK: Initialization public init() {} - } // MARK: - CustomStringConvertible extension Circle: CustomStringConvertible { - public var description: String { "Circle()" } - } // MARK: - View @@ -22,11 +17,9 @@ extension Circle: CustomStringConvertible { #if canImport(SwiftUI) extension Circle: SwiftUI.View { - public var body: some SwiftUI.View { SwiftUI.Circle() } - } #endif diff --git a/Sources/Presenter/Views/Color.swift b/Sources/Presenter/Views/Color.swift index c979d41..145380a 100644 --- a/Sources/Presenter/Views/Color.swift +++ b/Sources/Presenter/Views/Color.swift @@ -1,6 +1,4 @@ - public struct Color: CodableView { - // MARK: Nested Types private enum CodingKeys: String, CodingKey { @@ -41,17 +39,14 @@ public struct Color: CodableView { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(ColorCode(self).description, forKey: .code) } - } // MARK: - CustomStringConvertible extension Color: CustomStringConvertible { - public var description: String { "Color(\(ColorCode(self)))" } - } // MARK: - View @@ -59,11 +54,9 @@ extension Color: CustomStringConvertible { #if canImport(SwiftUI) extension Color: SwiftUI.View { - public var body: SwiftUI.Color { SwiftUI.Color(red: red, green: green, blue: blue, opacity: opacity) } - } #endif diff --git a/Sources/Presenter/Views/ColorPicker.swift b/Sources/Presenter/Views/ColorPicker.swift index ef21c70..cea2c01 100644 --- a/Sources/Presenter/Views/ColorPicker.swift +++ b/Sources/Presenter/Views/ColorPicker.swift @@ -1,6 +1,4 @@ - public struct ColorPicker: CodableWrapperView { - // MARK: Stored Properties private let color: Binding @@ -18,17 +16,14 @@ public struct ColorPicker: CodableWrapperView { self.supportsOpacity = supportsOpacity self.label = CoderView(label()) } - } // MARK: - CustomStringConvertible extension ColorPicker: CustomStringConvertible { - public var description: String { "ColorPicker(color: \(color), supportsOpacity: \(supportsOpacity), label: \(label))" } - } // MARK: - View @@ -36,7 +31,6 @@ extension ColorPicker: CustomStringConvertible { #if canImport(SwiftUI) extension ColorPicker { - #if !os(macOS) && !os(tvOS) && !os(watchOS) && !targetEnvironment(macCatalyst) public var body: View { @@ -50,11 +44,9 @@ extension ColorPicker { } #endif - } private struct Modifier: ViewModifier, SwiftUI.ViewModifier { - let color: Binding let supportsOpacity: Bool @@ -69,7 +61,6 @@ private struct Modifier: ViewModifier, SwiftUI.ViewModifier { } } } - } #endif diff --git a/Sources/Presenter/Views/ComposedView.swift b/Sources/Presenter/Views/ComposedView.swift index 6c3bdf1..f5639b0 100644 --- a/Sources/Presenter/Views/ComposedView.swift +++ b/Sources/Presenter/Views/ComposedView.swift @@ -1,21 +1,16 @@ - struct ComposedView: CodableWrapperView { - // MARK: Stored Properties let content: CoderView let modifiers: [CoderViewModifier] - } // MARK: - CustomStringConvertible extension ComposedView: CustomStringConvertible { - public var description: String { "\(content)" + modifiers.reduce("") { $0 + ".\($1)" } } - } // MARK: - View @@ -23,11 +18,9 @@ extension ComposedView: CustomStringConvertible { #if canImport(SwiftUI) extension ComposedView { - public var body: View { modifiers.reduce(content as View) { $0.apply($1) } } - } #endif @@ -35,7 +28,6 @@ extension ComposedView { // MARK: - View Extensions extension View { - public func modifier(_ modifier: Modifier) -> View { if let composition = self as? ComposedView { return ComposedView(content: composition.content, @@ -44,5 +36,4 @@ extension View { return ComposedView(content: CoderView(self), modifiers: [CoderViewModifier(modifier)]) } - } diff --git a/Sources/Presenter/Views/DataView.swift b/Sources/Presenter/Views/DataView.swift index 020fc40..e732b69 100644 --- a/Sources/Presenter/Views/DataView.swift +++ b/Sources/Presenter/Views/DataView.swift @@ -1,6 +1,4 @@ - public struct DataView: CodableView { - // MARK: Stored Properties let data: Data @@ -10,17 +8,14 @@ public struct DataView: CodableView { public init(_ data: Data) { self.data = data } - } // MARK: - CustomStringConvertible extension DataView: CustomStringConvertible { - public var description: String { "DataView(\(String(data: data, encoding: .utf8) ?? "nil"))" } - } // MARK: - View @@ -28,7 +23,6 @@ extension DataView: CustomStringConvertible { #if canImport(SwiftUI) private struct _DataView: SwiftUI.View { - let data: Data @SwiftUI.State private var view: AnyView? @@ -54,15 +48,12 @@ private struct _DataView: SwiftUI.View { } return view } - } extension DataView: SwiftUI.View { - public var body: some SwiftUI.View { _DataView(data: data) } - } #endif diff --git a/Sources/Presenter/Views/Divider.swift b/Sources/Presenter/Views/Divider.swift index 9df6447..84aaa20 100644 --- a/Sources/Presenter/Views/Divider.swift +++ b/Sources/Presenter/Views/Divider.swift @@ -1,20 +1,15 @@ - public struct Divider: CodableView { - // MARK: Initialization public init() {} - } // MARK: - CustomStringConvertible extension Divider: CustomStringConvertible { - public var description: String { "Divider()" } - } // MARK: - View @@ -22,11 +17,9 @@ extension Divider: CustomStringConvertible { #if canImport(SwiftUI) extension Divider: SwiftUI.View { - public var body: some SwiftUI.View { SwiftUI.Divider() } - } #endif diff --git a/Sources/Presenter/Views/HGrid.swift b/Sources/Presenter/Views/HGrid.swift index a5328dc..e244e77 100644 --- a/Sources/Presenter/Views/HGrid.swift +++ b/Sources/Presenter/Views/HGrid.swift @@ -1,6 +1,4 @@ - public struct HGrid: CodableWrapperView { - // MARK: Stored Properties private let rows: [GridItem] @@ -24,17 +22,14 @@ public struct HGrid: CodableWrapperView { self.pinnedViews = pinnedViews self.content = CoderView(content()) } - } // MARK: - CustomStringConvertible extension HGrid: CustomStringConvertible { - public var description: String { "HGrid(rows: \(rows), alignment: \(alignment.map { "\($0)" } ?? "nil"), spacing: \(spacing.map(\.description) ?? "nil"), pinnedViews: \(pinnedViews), content: \(content))" } - } // MARK: - View @@ -42,12 +37,11 @@ extension HGrid: CustomStringConvertible { #if canImport(SwiftUI) extension HGrid { - #if !os(macOS) && !targetEnvironment(macCatalyst) public var body: View { if #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) { - return content.modifier( + content.modifier( Modifier( rows: rows.map(\.swiftUIValue), alignment: alignment?.swiftUIValue ?? .center, @@ -56,23 +50,21 @@ extension HGrid { ) ) } else { - return Nil() + Nil() } } #else - public var body: View { + public var body: View { Nil() } #endif - } @available(iOS 14.0, macOS 11.0, *) private struct Modifier: ViewModifier, SwiftUI.ViewModifier { - let rows: [SwiftUI.GridItem] let alignment: SwiftUI.VerticalAlignment let spacing: CGFloat? @@ -87,8 +79,6 @@ private struct Modifier: ViewModifier, SwiftUI.ViewModifier { content: { content } ) } - } #endif - diff --git a/Sources/Presenter/Views/HStack.swift b/Sources/Presenter/Views/HStack.swift index af6311c..cc7c6fd 100644 --- a/Sources/Presenter/Views/HStack.swift +++ b/Sources/Presenter/Views/HStack.swift @@ -1,6 +1,4 @@ - public struct HStack: CodableWrapperView { - // MARK: Stored Properties private let alignment: VerticalAlignment? @@ -18,17 +16,14 @@ public struct HStack: CodableWrapperView { self.spacing = spacing self.content = CoderView(content()) } - } // MARK: - CustomStringConvertible extension HStack: CustomStringConvertible { - public var description: String { "HStack(alignment: .\((alignment ?? .center).rawValue), spacing: \(spacing.map { $0.description } ?? "nil"), content: \(content))" } - } // MARK: - View @@ -36,16 +31,13 @@ extension HStack: CustomStringConvertible { #if canImport(SwiftUI) extension HStack { - public var body: View { content .modifier(Modifier(alignment: alignment?.swiftUIValue ?? .center, spacing: spacing)) } - } private struct Modifier: ViewModifier, SwiftUI.ViewModifier { - let alignment: SwiftUI.VerticalAlignment let spacing: CGFloat? @@ -54,8 +46,6 @@ private struct Modifier: ViewModifier, SwiftUI.ViewModifier { content } } - } #endif - diff --git a/Sources/Presenter/Views/If.swift b/Sources/Presenter/Views/If.swift index 6a15b5e..d9907c5 100644 --- a/Sources/Presenter/Views/If.swift +++ b/Sources/Presenter/Views/If.swift @@ -1,6 +1,4 @@ - public struct If: CodableWrapperView { - // MARK: Nested Types private enum CodingKeys: String, CodingKey { @@ -61,17 +59,14 @@ public struct If: CodableWrapperView { try container.encode(falseView, forKey: .falseView) } } - } // MARK: - CustomStringConvertible extension If: CustomStringConvertible { - public var description: String { "If(\(condition), then: \(trueView), else: \(falseView))" } - } // MARK: - View @@ -79,26 +74,21 @@ extension If: CustomStringConvertible { #if canImport(SwiftUI) extension If { - public var body: View { trueView.modifier(Modifier1(falseView: falseView, condition: condition)) } - } private struct Modifier1: ViewModifier { - let falseView: CoderView let condition: Value func body(for content: Content) -> View { falseView.modifier(Modifier2(trueView: content, condition: condition)) } - } private struct Modifier2: ViewModifier, SwiftUI.ViewModifier { - let trueView: TrueView let condition: Value @@ -111,7 +101,6 @@ private struct Modifier2: ViewModifier, SwiftUI.ViewModi } } } - } #endif diff --git a/Sources/Presenter/Views/Image.swift b/Sources/Presenter/Views/Image.swift index 862371d..737357d 100644 --- a/Sources/Presenter/Views/Image.swift +++ b/Sources/Presenter/Views/Image.swift @@ -1,6 +1,4 @@ - public struct Image: CodableView { - // MARK: Nested Types fileprivate enum Kind: String, Codable { @@ -46,18 +44,15 @@ public struct Image: CodableView { public func resizable() -> Image { Image(kind: kind, identifier: identifier, isResizable: true) } - } // MARK: - CustomStringConvertible extension Image: CustomStringConvertible { - public var description: String { "Image(\(kind): \(identifier))" + (isResizable ? ".resizable()" : "") } - } // MARK: - View @@ -65,7 +60,6 @@ extension Image: CustomStringConvertible { #if canImport(SwiftUI) && canImport(Combine) private struct ImageView: SwiftUI.View { - // MARK: Stored Properties var image: Image @@ -109,13 +103,11 @@ private struct ImageView: SwiftUI.View { private func set(_ img: SwiftUI.Image) { loadedImage = image.isResizable ? img.resizable() : img } - } #if canImport(UIKit) extension ImageView { - private func loadExternalImage(at url: URL) -> AnyPublisher { URLSession.shared.dataTaskPublisher(for: url) .map { response -> SwiftUI.Image? in @@ -127,13 +119,11 @@ extension ImageView { .replaceError(with: nil) .eraseToAnyPublisher() } - } #elseif canImport(AppKit) extension ImageView { - private func loadExternalImage(at url: URL) -> AnyPublisher { URLSession.shared.dataTaskPublisher(for: url) .map { response -> SwiftUI.Image? in @@ -145,17 +135,14 @@ extension ImageView { .replaceError(with: nil) .eraseToAnyPublisher() } - } #endif extension Image: SwiftUI.View { - public var body: some SwiftUI.View { ImageView(image: self) } - } #endif diff --git a/Sources/Presenter/Views/LinearGradient.swift b/Sources/Presenter/Views/LinearGradient.swift index a1eb68c..975fbcf 100644 --- a/Sources/Presenter/Views/LinearGradient.swift +++ b/Sources/Presenter/Views/LinearGradient.swift @@ -1,6 +1,4 @@ - public struct LinearGradient: CodableView { - // MARK: Stored Properties private let gradient: Gradient @@ -14,17 +12,14 @@ public struct LinearGradient: CodableView { self.startPoint = startPoint self.endPoint = endPoint } - } // MARK: - CustomStringConvertible extension LinearGradient: CustomStringConvertible { - public var description: String { "LinearGradient(gradient: \(gradient), startPoint: \(startPoint), endPoint: \(endPoint))" } - } // MARK: - View @@ -32,7 +27,6 @@ extension LinearGradient: CustomStringConvertible { #if canImport(SwiftUI) extension LinearGradient: SwiftUI.View { - public var body: some SwiftUI.View { SwiftUI.LinearGradient( gradient: gradient.swiftUIValue, @@ -40,8 +34,6 @@ extension LinearGradient: SwiftUI.View { endPoint: endPoint.unitPoint ) } - } #endif - diff --git a/Sources/Presenter/Views/Link.swift b/Sources/Presenter/Views/Link.swift index 844989b..d46cd12 100644 --- a/Sources/Presenter/Views/Link.swift +++ b/Sources/Presenter/Views/Link.swift @@ -1,6 +1,4 @@ - public struct Link: CodableWrapperView { - // MARK: Stored Properties private let label: CoderView @@ -12,17 +10,14 @@ public struct Link: CodableWrapperView { self.label = CoderView(label) self.destination = destination } - } // MARK: - CustomStringConvertible extension Link: CustomStringConvertible { - public var description: String { "Link(\(label), destination: \(destination))" } - } // MARK: - View @@ -30,15 +25,12 @@ extension Link: CustomStringConvertible { #if canImport(SwiftUI) extension Link { - public var body: View { label.modifier(Modifier(destination: destination)) } - } private struct Modifier: ViewModifier, SwiftUI.ViewModifier { - let destination: String func body(content: Content) -> some SwiftUI.View { @@ -48,7 +40,6 @@ private struct Modifier: ViewModifier, SwiftUI.ViewModifier { content } } - } #endif diff --git a/Sources/Presenter/Views/Local.swift b/Sources/Presenter/Views/Local.swift index 245d40c..b4d868d 100644 --- a/Sources/Presenter/Views/Local.swift +++ b/Sources/Presenter/Views/Local.swift @@ -1,6 +1,4 @@ - public struct Local: CodableView { - // MARK: Stored Properties private let key: String @@ -10,17 +8,14 @@ public struct Local: CodableView { public init(key: String) { self.key = key } - } // MARK: - CustomStringConvertible extension Local: CustomStringConvertible { - public var description: String { "Local(key: \(key))" } - } // MARK: - View @@ -28,7 +23,6 @@ extension Local: CustomStringConvertible { #if canImport(SwiftUI) extension Local: SwiftUI.View { - public var body: some SwiftUI.View { ModelView { model in view(for: model.get(key)) @@ -43,7 +37,6 @@ extension Local: SwiftUI.View { view } } - } #endif diff --git a/Sources/Presenter/Views/NavigationLink.swift b/Sources/Presenter/Views/NavigationLink.swift index 59d0cab..fa8fb5d 100644 --- a/Sources/Presenter/Views/NavigationLink.swift +++ b/Sources/Presenter/Views/NavigationLink.swift @@ -1,6 +1,4 @@ - public struct NavigationLink: CodableWrapperView { - // MARK: Stored Properties private let destination: CoderView @@ -18,17 +16,14 @@ public struct NavigationLink: CodableWrapperView { self.isActive = isActive self.label = CoderView(label) } - } // MARK: - CustomStringConvertible extension NavigationLink: CustomStringConvertible { - public var description: String { "NavigationLink(destination: \(destination), isActive: \(isActive), label: \(label))" } - } // MARK: - View @@ -36,26 +31,21 @@ extension NavigationLink: CustomStringConvertible { #if canImport(SwiftUI) extension NavigationLink { - public var body: View { destination.modifier(Modifier1(label: label, isActive: isActive)) } - } private struct Modifier1: ViewModifier { - let label: CoderView let isActive: Binding public func body(for content: Content) -> View { label.modifier(Modifier2(destination: content, isActive: isActive)) } - } private struct Modifier2: ViewModifier, SwiftUI.ViewModifier { - var destination: Destination let isActive: Binding @@ -80,7 +70,6 @@ private struct Modifier2: ViewModifier, SwiftUI.ViewM } } } - } #endif diff --git a/Sources/Presenter/Views/NavigationView.swift b/Sources/Presenter/Views/NavigationView.swift index 67f4c7a..d0d3017 100644 --- a/Sources/Presenter/Views/NavigationView.swift +++ b/Sources/Presenter/Views/NavigationView.swift @@ -1,6 +1,4 @@ - public struct NavigationView: CodableWrapperView { - // MARK: Stored Properties private let content: CoderView @@ -12,17 +10,14 @@ public struct NavigationView: CodableWrapperView { ) { self.content = CoderView(content()) } - } // MARK: - CustomStringConvertible extension NavigationView: CustomStringConvertible { - public var description: String { "NavigationView(content: \(content))" } - } // MARK: - View @@ -30,21 +25,17 @@ extension NavigationView: CustomStringConvertible { #if canImport(SwiftUI) extension NavigationView { - public var body: View { content.modifier(Modifier()) } - } private struct Modifier: ViewModifier, SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { SwiftUI.NavigationView { content } } - } #endif diff --git a/Sources/Presenter/Views/Nil.swift b/Sources/Presenter/Views/Nil.swift index edba64e..d79f4f2 100644 --- a/Sources/Presenter/Views/Nil.swift +++ b/Sources/Presenter/Views/Nil.swift @@ -1,6 +1,4 @@ - extension Optional: View, NamedType, WrapperView where Wrapped: CodableView { - #if canImport(SwiftUI) public var body: View { @@ -13,11 +11,9 @@ extension Optional: View, NamedType, WrapperView where Wrapped: CodableView { } #endif - } struct Nil: CodableView { - // MARK: Initialization init() {} @@ -40,17 +36,14 @@ struct Nil: CodableView { var container = encoder.singleValueContainer() try container.encodeNil() } - } #if canImport(SwiftUI) extension Nil: SwiftUI.View { - public var body: some SwiftUI.View { EmptyView() } - } #endif @@ -58,9 +51,7 @@ extension Nil: SwiftUI.View { // MARK: - CustomStringConvertible extension Nil: CustomStringConvertible { - var description: String { "nil" } - } diff --git a/Sources/Presenter/Views/Path.swift b/Sources/Presenter/Views/Path.swift index a1d3842..91776b4 100644 --- a/Sources/Presenter/Views/Path.swift +++ b/Sources/Presenter/Views/Path.swift @@ -1,6 +1,4 @@ - public struct Path: CodableView { - // MARK: Nested Types private enum ElementKind: String, Codable { @@ -53,17 +51,14 @@ public struct Path: CodableView { public mutating func closeSubpath() { elements.append(.init(kind: .closeSubpath, points: [])) } - } // MARK: - CustomStringConvertible extension Path: CustomStringConvertible { - public var description: String { "Path(elements: \(elements))" } - } // MARK: - View @@ -71,7 +66,6 @@ extension Path: CustomStringConvertible { #if canImport(SwiftUI) extension Path: SwiftUI.View { - public var body: some SwiftUI.View { SwiftUI.Path { path in for element in elements { @@ -93,7 +87,6 @@ extension Path: SwiftUI.View { } } } - } #endif diff --git a/Sources/Presenter/Views/ScrollView.swift b/Sources/Presenter/Views/ScrollView.swift index 430fc0b..4d3b61a 100644 --- a/Sources/Presenter/Views/ScrollView.swift +++ b/Sources/Presenter/Views/ScrollView.swift @@ -1,6 +1,4 @@ - public struct ScrollView: CodableWrapperView { - // MARK: Stored Properties private let axis: AxisSet? @@ -18,17 +16,14 @@ public struct ScrollView: CodableWrapperView { self.showsIndicators = showsIndicators self.content = CoderView(content()) } - } // MARK: - CustomStringConvertible extension ScrollView: CustomStringConvertible { - public var description: String { "ScrollView(content: \(content))" } - } // MARK: - View @@ -36,18 +31,15 @@ extension ScrollView: CustomStringConvertible { #if canImport(SwiftUI) extension ScrollView { - public var body: View { content.modifier( Modifier(axis: axis?.swiftUIValue ?? .vertical, showsIndicators: showsIndicators ?? true) ) } - } private struct Modifier: ViewModifier, SwiftUI.ViewModifier { - let axis: SwiftUI.Axis.Set let showsIndicators: Bool @@ -56,7 +48,6 @@ private struct Modifier: ViewModifier, SwiftUI.ViewModifier { content } } - } #endif diff --git a/Sources/Presenter/Views/Section.swift b/Sources/Presenter/Views/Section.swift index 626e264..d9c319c 100644 --- a/Sources/Presenter/Views/Section.swift +++ b/Sources/Presenter/Views/Section.swift @@ -1,6 +1,4 @@ - public struct Section: CodableWrapperView { - // MARK: Stored Properties private let header: CoderView? @@ -18,17 +16,14 @@ public struct Section: CodableWrapperView { self.footer = footer.map(CoderView.init) self.content = CoderView(content()) } - } // MARK: - CustomStringConvertible extension Section: CustomStringConvertible { - public var description: String { "Section(header: \(header.map { "\($0)" } ?? "nil")), footer: \(footer.map { "\($0)" } ?? "nil"), content: \(content))" } - } // MARK: - View @@ -36,44 +31,36 @@ extension Section: CustomStringConvertible { #if canImport(SwiftUI) extension Section { - public var body: View { content.modifier(Modifier1(header: header, footer: footer)) } - } private struct Modifier1: ViewModifier { - let header: CoderView? let footer: CoderView? func body(for content: Content) -> View { (header?.body ?? Nil()).modifier(Modifier2(footer: footer, section: content)) } - } private struct Modifier2: ViewModifier { - let footer: CoderView? let section: Section func body(for header: Header) -> View { (footer?.body ?? Nil()).modifier(Modifier3(header: header, section: section)) } - } private struct Modifier3: ViewModifier, SwiftUI.ViewModifier { - let header: Header let section: Section func body(content footer: Content) -> some SwiftUI.View { SwiftUI.Section(header: header, footer: footer) { section } } - } #endif diff --git a/Sources/Presenter/Views/SecureField.swift b/Sources/Presenter/Views/SecureField.swift index 5b092d7..8bfca49 100644 --- a/Sources/Presenter/Views/SecureField.swift +++ b/Sources/Presenter/Views/SecureField.swift @@ -1,6 +1,4 @@ - public struct SecureField: CodableView { - // MARK: Stored Properties private let title: Value @@ -20,17 +18,14 @@ public struct SecureField: CodableView { self.text = text self.onCommit = onCommit.map(CoderAction.init) } - } // MARK: - CustomStringConvertible extension SecureField: CustomStringConvertible { - public var description: String { "SecureField(\"\(title)\", text: \(text))" } - } // MARK: - View @@ -38,7 +33,6 @@ extension SecureField: CustomStringConvertible { #if canImport(SwiftUI) extension SecureField: SwiftUI.View { - public var body: some SwiftUI.View { ModelView { model in SwiftUI.SecureField( @@ -48,7 +42,6 @@ extension SecureField: SwiftUI.View { ) } } - } #endif diff --git a/Sources/Presenter/Views/Slider.swift b/Sources/Presenter/Views/Slider.swift index 6404d2b..0d606d0 100644 --- a/Sources/Presenter/Views/Slider.swift +++ b/Sources/Presenter/Views/Slider.swift @@ -1,6 +1,4 @@ - public struct Slider: CodableView { - // MARK: Stored Properties private let value: Binding @@ -18,17 +16,14 @@ public struct Slider: CodableView { self.maxValue = range.upperBound self.onEditingChanged = onEditingChanged.map(CoderAction.init) } - } // MARK: - CustomStringConvertible extension Slider: CustomStringConvertible { - public var description: String { "Slider(value: \(value), in: \(minValue...maxValue))" } - } // MARK: - View @@ -36,7 +31,6 @@ extension Slider: CustomStringConvertible { #if canImport(SwiftUI) extension Slider: SwiftUI.View { - #if os(tvOS) public var body: some SwiftUI.View { @@ -56,7 +50,6 @@ extension Slider: SwiftUI.View { } #endif - } #endif diff --git a/Sources/Presenter/Views/Spacer.swift b/Sources/Presenter/Views/Spacer.swift index 870955d..ba6502c 100644 --- a/Sources/Presenter/Views/Spacer.swift +++ b/Sources/Presenter/Views/Spacer.swift @@ -1,6 +1,4 @@ - public struct Spacer: CodableView { - // MARK: Stored Properties private let minLength: Value @@ -14,17 +12,14 @@ public struct Spacer: CodableView { public init(minLength: Value) { self.minLength = minLength } - } // MARK: - CustomStringConvertible extension Spacer: CustomStringConvertible { - public var description: String { "Spacer(minLength: \(minLength))" } - } // MARK: - View @@ -32,7 +27,6 @@ extension Spacer: CustomStringConvertible { #if canImport(SwiftUI) extension Spacer: SwiftUI.View { - public var body: some SwiftUI.View { ModelView { model in SwiftUI.Spacer( @@ -40,7 +34,6 @@ extension Spacer: SwiftUI.View { ) } } - } #endif diff --git a/Sources/Presenter/Views/TabView.swift b/Sources/Presenter/Views/TabView.swift index 89c854f..7b2bc79 100644 --- a/Sources/Presenter/Views/TabView.swift +++ b/Sources/Presenter/Views/TabView.swift @@ -1,6 +1,4 @@ - public struct TabView: CodableView { - // MARK: Stored Properties private let selection: Binding? @@ -15,17 +13,14 @@ public struct TabView: CodableView { self.selection = selection self.content = CoderView(content) } - } // MARK: - CustomStringConvertible extension TabView: CustomStringConvertible { - public var description: String { "TabView(selection: \(selection.map { "\($0)" } ?? "nil"), content: \(content))" } - } // MARK: - View @@ -33,7 +28,6 @@ extension TabView: CustomStringConvertible { #if canImport(SwiftUI) extension TabView: SwiftUI.View { - #if !os(macOS) && !targetEnvironment(macCatalyst) && !os(watchOS) public var body: some SwiftUI.View { @@ -67,7 +61,6 @@ extension TabView: SwiftUI.View { } #endif - } #endif diff --git a/Sources/Presenter/Views/Text.swift b/Sources/Presenter/Views/Text.swift index 332ec63..28225de 100644 --- a/Sources/Presenter/Views/Text.swift +++ b/Sources/Presenter/Views/Text.swift @@ -1,6 +1,4 @@ - public struct Text: CodableView { - // MARK: Stored Properties private let text: Value @@ -14,17 +12,14 @@ public struct Text: CodableView { public init(_ text: Value) { self.text = text } - } // MARK: - CustomStringConvertible extension Text: CustomStringConvertible { - public var description: String { "Text(\(text))" } - } // MARK: - View @@ -32,13 +27,11 @@ extension Text: CustomStringConvertible { #if canImport(SwiftUI) extension Text: SwiftUI.View { - public var body: some SwiftUI.View { ModelView { model in SwiftUI.Text(self.text.get(from: model)) } } - } #endif diff --git a/Sources/Presenter/Views/TextEditor.swift b/Sources/Presenter/Views/TextEditor.swift index 6940762..b462cad 100644 --- a/Sources/Presenter/Views/TextEditor.swift +++ b/Sources/Presenter/Views/TextEditor.swift @@ -1,6 +1,4 @@ - public struct TextEditor: CodableView { - // MARK: Stored Properties private let text: Binding @@ -10,17 +8,14 @@ public struct TextEditor: CodableView { public init(text: Binding) { self.text = text } - } // MARK: - CustomStringConvertible extension TextEditor: CustomStringConvertible { - public var description: String { "TextEditor(text: \(text))" } - } // MARK: - View @@ -28,7 +23,6 @@ extension TextEditor: CustomStringConvertible { #if canImport(SwiftUI) extension TextEditor: SwiftUI.View { - #if !os(watchOS) && !os(macOS) && !os(tvOS) && !targetEnvironment(macCatalyst) @SwiftUI.ViewBuilder @@ -40,7 +34,6 @@ extension TextEditor: SwiftUI.View { } else { SwiftUI.EmptyView() } - } #else @@ -50,7 +43,6 @@ extension TextEditor: SwiftUI.View { } #endif - } #endif diff --git a/Sources/Presenter/Views/TextField.swift b/Sources/Presenter/Views/TextField.swift index 23dcc3f..86b477a 100644 --- a/Sources/Presenter/Views/TextField.swift +++ b/Sources/Presenter/Views/TextField.swift @@ -1,6 +1,4 @@ - public struct TextField: CodableView { - // MARK: Stored Properties private let title: Value @@ -27,17 +25,14 @@ public struct TextField: CodableView { self.onCommit = onCommit.map(CoderAction.init) self.onEditingChanged = onEditingChanged.map(CoderAction.init) } - } // MARK: - CustomStringConvertible extension TextField: CustomStringConvertible { - public var description: String { "TextField(\"\(title)\", text: \(text))" } - } // MARK: - View @@ -45,7 +40,6 @@ extension TextField: CustomStringConvertible { #if canImport(SwiftUI) extension TextField: SwiftUI.View { - public var body: some SwiftUI.View { ModelView { model in SwiftUI.TextField( @@ -56,7 +50,6 @@ extension TextField: SwiftUI.View { ) } } - } #endif diff --git a/Sources/Presenter/Views/Toggle.swift b/Sources/Presenter/Views/Toggle.swift index 2ded570..f6a98e2 100644 --- a/Sources/Presenter/Views/Toggle.swift +++ b/Sources/Presenter/Views/Toggle.swift @@ -1,6 +1,4 @@ - public struct Toggle: CodableView { - // MARK: Stored Properties private let isOn: Binding @@ -15,17 +13,14 @@ public struct Toggle: CodableView { self.isOn = isOn self.label = CoderView(label) } - } // MARK: - CustomStringConvertible extension Toggle: CustomStringConvertible { - public var description: String { "Toggle(isOn: \(isOn), label: \(label))" } - } // MARK: - View @@ -33,7 +28,6 @@ extension Toggle: CustomStringConvertible { #if canImport(SwiftUI) extension Toggle: SwiftUI.View { - public var body: some SwiftUI.View { ModelView { model in SwiftUI.Toggle( @@ -42,7 +36,6 @@ extension Toggle: SwiftUI.View { ) } } - } #endif diff --git a/Sources/Presenter/Views/VGrid.swift b/Sources/Presenter/Views/VGrid.swift index 1e8f472..d122f20 100644 --- a/Sources/Presenter/Views/VGrid.swift +++ b/Sources/Presenter/Views/VGrid.swift @@ -1,6 +1,4 @@ - public struct VGrid: CodableWrapperView { - // MARK: Stored Properties private let columns: [GridItem] @@ -18,24 +16,20 @@ public struct VGrid: CodableWrapperView { pinnedViews: PinnedScrollableViews, @ViewBuilder content: () -> View ) { - self.columns = columns self.alignment = alignment self.spacing = spacing self.pinnedViews = pinnedViews self.content = CoderView(content()) } - } // MARK: - CustomStringConvertible extension VGrid: CustomStringConvertible { - public var description: String { "VGrid(columns: \(columns), alignment: \(alignment.map { "\($0)" } ?? "nil"), spacing: \(spacing.map(\.description) ?? "nil"), pinnedViews: \(pinnedViews), content: \(content))" } - } // MARK: - View @@ -43,19 +37,18 @@ extension VGrid: CustomStringConvertible { #if canImport(SwiftUI) extension VGrid { - #if !os(macOS) && !targetEnvironment(macCatalyst) public var body: View { if #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) { - return content.modifier( + content.modifier( Modifier(columns: columns.map(\.swiftUIValue), alignment: alignment?.swiftUIValue ?? .center, spacing: spacing, pinnedViews: pinnedViews.swiftUIValue) ) } else { - return Nil() + Nil() } } @@ -66,12 +59,10 @@ extension VGrid { } #endif - } @available(iOS 14.0, macOS 11.0, *) private struct Modifier: ViewModifier, SwiftUI.ViewModifier { - let columns: [SwiftUI.GridItem] let alignment: SwiftUI.HorizontalAlignment let spacing: CGFloat? @@ -86,8 +77,6 @@ private struct Modifier: ViewModifier, SwiftUI.ViewModifier { content: { content } ) } - } #endif - diff --git a/Sources/Presenter/Views/VStack.swift b/Sources/Presenter/Views/VStack.swift index 53248b7..de7f7b9 100644 --- a/Sources/Presenter/Views/VStack.swift +++ b/Sources/Presenter/Views/VStack.swift @@ -1,6 +1,4 @@ - public struct VStack: CodableWrapperView { - // MARK: Stored Properties private let alignment: HorizontalAlignment? @@ -14,22 +12,18 @@ public struct VStack: CodableWrapperView { spacing: CGFloat? = nil, @ViewBuilder content: () -> View ) { - self.alignment = alignment self.spacing = spacing self.content = CoderView(content()) } - } // MARK: - CustomStringConvertible extension VStack: CustomStringConvertible { - public var description: String { "VStack(alignment: .\((alignment ?? .center).rawValue), spacing: \(spacing.map { $0.description } ?? "nil"), content: \(content))" } - } // MARK: - View @@ -37,16 +31,13 @@ extension VStack: CustomStringConvertible { #if canImport(SwiftUI) extension VStack { - public var body: View { content .modifier(Modifier(alignment: alignment?.swiftUIValue ?? .center, spacing: spacing)) } - } private struct Modifier: ViewModifier, SwiftUI.ViewModifier { - let alignment: SwiftUI.HorizontalAlignment let spacing: CGFloat? @@ -68,8 +59,6 @@ private struct Modifier: ViewModifier, SwiftUI.ViewModifier { content } } - } #endif - diff --git a/Sources/Presenter/Views/ZStack.swift b/Sources/Presenter/Views/ZStack.swift index 4de563e..775cf80 100644 --- a/Sources/Presenter/Views/ZStack.swift +++ b/Sources/Presenter/Views/ZStack.swift @@ -1,6 +1,4 @@ - public struct ZStack: CodableWrapperView { - // MARK: Stored Properties private let alignment: Alignment? @@ -12,21 +10,17 @@ public struct ZStack: CodableWrapperView { alignment: Alignment? = nil, @ViewBuilder content: () -> View ) { - self.alignment = alignment self.content = CoderView(content()) } - } // MARK: - CustomStringConvertible extension ZStack: CustomStringConvertible { - public var description: String { "ZStack(alignment: .\((alignment ?? .center).rawValue), content: \(content))" } - } // MARK: - View @@ -34,15 +28,12 @@ extension ZStack: CustomStringConvertible { #if canImport(SwiftUI) extension ZStack { - public var body: View { content.modifier(Modifier(alignment: alignment?.swiftUIValue ?? .center)) } - } private struct Modifier: ViewModifier, SwiftUI.ViewModifier { - let alignment: SwiftUI.Alignment func body(content: Content) -> some SwiftUI.View { @@ -50,8 +41,6 @@ private struct Modifier: ViewModifier, SwiftUI.ViewModifier { content } } - } #endif - diff --git a/Sources/TracePresenter/Exports.swift b/Sources/TracePresenter/Exports.swift index 3456567..605e2ec 100644 --- a/Sources/TracePresenter/Exports.swift +++ b/Sources/TracePresenter/Exports.swift @@ -1,2 +1 @@ - @_exported import Presenter diff --git a/Sources/TracePresenter/TraceGraph.swift b/Sources/TracePresenter/TraceGraph.swift index 060d38d..c7598a6 100644 --- a/Sources/TracePresenter/TraceGraph.swift +++ b/Sources/TracePresenter/TraceGraph.swift @@ -1,6 +1,4 @@ - public struct TraceGraph: CodableView { - // MARK: Stored Properties public var spans: [Span] @@ -26,13 +24,10 @@ public struct TraceGraph: CodableView { currentIndex += 1 } } - } extension TraceGraph { - public struct Span: Codable { - public let service: String public let operation: String @@ -55,15 +50,12 @@ extension TraceGraph { self.parentService = parentService self.parentOperation = parentOperation } - } - } #if canImport(SwiftUI) extension TraceGraph: SwiftUI.View { - public var body: some SwiftUI.View { SwiftUI.VStack { SwiftUI.ForEach(spans.indices) { index in @@ -74,7 +66,6 @@ extension TraceGraph: SwiftUI.View { } private struct SpanRow: SwiftUI.View { - let span: Span var body: some SwiftUI.View { @@ -86,9 +77,7 @@ extension TraceGraph: SwiftUI.View { .offset(x: span.start) } } - } - } #endif diff --git a/Sources/TracePresenter/TracePresenter.swift b/Sources/TracePresenter/TracePresenter.swift index d9de6b9..ddfb17e 100644 --- a/Sources/TracePresenter/TracePresenter.swift +++ b/Sources/TracePresenter/TracePresenter.swift @@ -1,12 +1,9 @@ - public struct TracePresenter: Plugin { - public init() {} public var views: [CodableView.Type] { [ - TraceGraph.self, + TraceGraph.self ] } - } diff --git a/Tests/PresenterTests/PresenterTests.swift b/Tests/PresenterTests/PresenterTests.swift index 0f77755..4fdf48f 100644 --- a/Tests/PresenterTests/PresenterTests.swift +++ b/Tests/PresenterTests/PresenterTests.swift @@ -1,4 +1,3 @@ - #if !os(watchOS) && canImport(XCTest) && canImport(SwiftUI) import XCTest @@ -13,15 +12,12 @@ struct TestAction: Action { } extension Color { - static var gray: Color { Color(red: 0.5, green: 0.5, blue: 0.5) } - } struct MyCustomView: UserView { - @State("text", default: "") var text @@ -34,19 +30,15 @@ struct MyCustomView: UserView { MyCustomView2() } } - } struct MyCustomView2: UserView { - var body: View { Text("gallo") } - } final class PresenterTests: XCTestCase { - func testCustom() throws { let view = MyCustomView(text2: .at("test", default: "")) let data = try Presenter.encode(view) @@ -138,7 +130,6 @@ final class PresenterTests: XCTestCase { XCTFail("\(error)") } } - } #endif diff --git a/Tests/PresenterTests/TracePresenterTests.swift b/Tests/PresenterTests/TracePresenterTests.swift index ce6495a..46d5fb7 100644 --- a/Tests/PresenterTests/TracePresenterTests.swift +++ b/Tests/PresenterTests/TracePresenterTests.swift @@ -1,4 +1,3 @@ - #if !os(watchOS) && canImport(XCTest) && canImport(UIKit) import XCTest @@ -7,7 +6,6 @@ import TracePresenter import UIKit final class TracePresenterTests: XCTestCase { - func testTracePresenter() { let view = TraceGraph(spans: [ .init( @@ -49,25 +47,22 @@ final class TracePresenterTests: XCTestCase { end: 0.5, parentService: "processing", parentOperation: "locations" - ), + ) ])! let image = view.eraseToAnyView().image(in: CGSize(width: 200, height: 200)) print(image) } - } extension SwiftUI.View { - func image(in size: CGSize) -> UIImage { let view = UIHostingController(rootView: self).view! view.frame = CGRect(origin: .zero, size: size) - return UIGraphicsImageRenderer(size: size).image { context in + return UIGraphicsImageRenderer(size: size).image { _ in view.drawHierarchy(in: view.frame, afterScreenUpdates: true) } } - } #endif From 64a871900c524a08d35d9591843d5b5dce01984c Mon Sep 17 00:00:00 2001 From: Paul Kraft Date: Wed, 21 Jul 2021 00:51:24 +0200 Subject: [PATCH 06/10] Resolve SwiftLint issues --- .swiftlint.yml | 2 +- Example/Shared/Actions/LoginAction.swift | 2 +- Sources/MetricPresenter/Graph.swift | 8 +-- .../MetricPresenter/SizePreferenceKey.swift | 4 +- .../Configuration/Configuration+Plugin.swift | 4 +- Sources/Presenter/Model/CoderAction.swift | 1 + Sources/Presenter/Model/CopyAction.swift | 12 ++--- Sources/Presenter/Types/Animation.swift | 49 ++++++++++++------- Sources/Presenter/Types/Font.swift | 2 +- Sources/Presenter/Types/UnitPoint.swift | 2 + .../Presenter/View - General/CoderView.swift | 1 + .../View - General/ViewBuilder.swift | 2 +- .../CoderViewModifier.swift | 1 + Sources/Presenter/ViewModifiers/Blur.swift | 11 +++-- Sources/Presenter/ViewModifiers/Clipped.swift | 6 ++- .../ViewModifiers/CornerRadius.swift | 7 ++- .../ViewModifiers/DrawingGroup.swift | 5 +- .../ViewModifiers/DynamicFrame.swift | 8 ++- Sources/Presenter/ViewModifiers/Frame.swift | 3 +- Sources/Presenter/ViewModifiers/Opacity.swift | 2 +- Sources/Presenter/ViewModifiers/Padding.swift | 6 ++- Sources/Presenter/ViewModifiers/Shadow.swift | 13 +++-- Sources/Presenter/Views/ArrayView.swift | 2 +- Sources/Presenter/Views/ComposedView.swift | 2 +- Sources/Presenter/Views/HGrid.swift | 4 +- Sources/Presenter/Views/If.swift | 2 +- Sources/Presenter/Views/Image.swift | 5 +- Sources/Presenter/Views/NavigationLink.swift | 2 +- Sources/Presenter/Views/ScrollView.swift | 4 +- Sources/Presenter/Views/SecureField.swift | 6 ++- Sources/Presenter/Views/TextField.swift | 12 +++-- Sources/Presenter/Views/VGrid.swift | 4 +- Sources/Presenter/Views/VStack.swift | 10 +--- Tests/PresenterTests/PresenterTests.swift | 10 ++-- 34 files changed, 131 insertions(+), 83 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index d35f42c..a3f5f41 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -152,7 +152,7 @@ only_rules: # Ensure definitions have a lower access control level than their enclosing parent - mark # MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...' - - missing_docs +# - missing_docs # Declarations should be documented. - modifier_order # Modifier order should be consistent. diff --git a/Example/Shared/Actions/LoginAction.swift b/Example/Shared/Actions/LoginAction.swift index 0d5bfde..1c3c306 100644 --- a/Example/Shared/Actions/LoginAction.swift +++ b/Example/Shared/Actions/LoginAction.swift @@ -16,7 +16,7 @@ struct LoginAction: Action { return } - guard username.count > 0 && password.count > 0 else { + guard !username.isEmpty && !password.isEmpty else { model[.loginErrorMessage] = "Please enter username and password." model[.showLoginError] = true return diff --git a/Sources/MetricPresenter/Graph.swift b/Sources/MetricPresenter/Graph.swift index 77509b5..0eec40f 100644 --- a/Sources/MetricPresenter/Graph.swift +++ b/Sources/MetricPresenter/Graph.swift @@ -49,10 +49,10 @@ public struct Graph: CodableView { // MARK: Initialization public init( - topLabels: [Graph.Label]? = nil, - trailingLabels: [Graph.Label]? = nil, - bottomLabels: [Graph.Label]? = nil, - leadingLabels: [Graph.Label]? = nil, + topLabels: [Graph.Label]? = nil, // swiftlint:disable:this discouraged_optional_collection + trailingLabels: [Graph.Label]? = nil, // swiftlint:disable:this discouraged_optional_collection + bottomLabels: [Graph.Label]? = nil, // swiftlint:disable:this discouraged_optional_collection + leadingLabels: [Graph.Label]? = nil, // swiftlint:disable:this discouraged_optional_collection data: [Graph.DataSet], gridWidth: CGFloat ) { diff --git a/Sources/MetricPresenter/SizePreferenceKey.swift b/Sources/MetricPresenter/SizePreferenceKey.swift index 885d8a9..cf9c312 100644 --- a/Sources/MetricPresenter/SizePreferenceKey.swift +++ b/Sources/MetricPresenter/SizePreferenceKey.swift @@ -7,7 +7,9 @@ extension SizePreferenceKey { static func reduce(value: inout CGSize, nextValue: () -> CGSize) { let next = nextValue() - guard next != .zero && next != value else { return } + guard next != .zero && next != value else { + return + } value = next } } diff --git a/Sources/Presenter/Configuration/Configuration+Plugin.swift b/Sources/Presenter/Configuration/Configuration+Plugin.swift index abd377f..ad53eb6 100644 --- a/Sources/Presenter/Configuration/Configuration+Plugin.swift +++ b/Sources/Presenter/Configuration/Configuration+Plugin.swift @@ -6,7 +6,9 @@ extension Presenter { // MARK: Plugins internal static func usePlugins() { - guard !didImportPlugins else { return } + guard !didImportPlugins else { + return + } didImportPlugins = true use(plugin: DefaultPlugin()) } diff --git a/Sources/Presenter/Model/CoderAction.swift b/Sources/Presenter/Model/CoderAction.swift index 82fde7b..2907332 100644 --- a/Sources/Presenter/Model/CoderAction.swift +++ b/Sources/Presenter/Model/CoderAction.swift @@ -58,6 +58,7 @@ extension CoderAction { // MARK: Static Properties + // swiftlint:disable:next discouraged_optional_collection private static var _registeredTypes: [String: Coder]? private static var registeredTypes: [String: Coder] { diff --git a/Sources/Presenter/Model/CopyAction.swift b/Sources/Presenter/Model/CopyAction.swift index 62227ed..57ecfd1 100644 --- a/Sources/Presenter/Model/CopyAction.swift +++ b/Sources/Presenter/Model/CopyAction.swift @@ -1,14 +1,14 @@ public struct CopyAction: Action { // MARK: Stored Properties - private var from: String - private var to: String + private let fromKey: String + private let toKey: String // MARK: Initialization - public init(from: String, to: String) { - self.from = from - self.to = to + public init(from fromKey: String, to toKey: String) { + self.fromKey = fromKey + self.toKey = toKey } // MARK: Methods @@ -16,7 +16,7 @@ public struct CopyAction: Action { #if canImport(SwiftUI) public func perform(on model: Model) { - model.set(to, to: model.get(from)) + model.set(toKey, to: model.get(fromKey)) } #endif diff --git a/Sources/Presenter/Types/Animation.swift b/Sources/Presenter/Types/Animation.swift index 6efaebd..c2afa85 100644 --- a/Sources/Presenter/Types/Animation.swift +++ b/Sources/Presenter/Types/Animation.swift @@ -5,7 +5,7 @@ public struct Animation: Codable { private var delay: Double? private var speed: Double? private var repeatCount: Int? - private var autoreverses: Bool? + private var autoreverses: Bool? // swiftlint:disable:this discouraged_optional_boolean // MARK: Static Functions @@ -15,11 +15,15 @@ public struct Animation: Codable { ) } - public static func interpolatingSpring(mass: Double? = nil, stiffness: Double, - damping: Double, initialVelocity: Double? = nil) -> Animation { + public static func interpolatingSpring(mass: Double? = nil, + stiffness: Double, + damping: Double, + initialVelocity: Double? = nil) -> Animation { Animation(kind: - .interpolatingSpring(mass: mass, stiffness: stiffness, - damping: damping, initialVelocity: initialVelocity) + .interpolatingSpring(mass: mass, + stiffness: stiffness, + damping: damping, + initialVelocity: initialVelocity) ) } @@ -59,8 +63,11 @@ public struct Animation: Codable { Animation(kind: .linear(duration: nil)) } - public static func timingCurve(c0x: Double, c0y: Double, - c1x: Double, c1y: Double, duration: Double? = nil) -> Animation { + public static func timingCurve(c0x: Double, + c0y: Double, + c1x: Double, + c1y: Double, + duration: Double? = nil) -> Animation { Animation(kind: .timingCurve(c0x: c0x, c0y: c0y, c1x: c1x, c1y: c1y, duration: duration)) } @@ -71,8 +78,11 @@ public struct Animation: Codable { // MARK: Methods public func delay(_ interval: Double) -> Animation { - Animation(kind: kind, delay: (delay ?? 0) + interval, speed: speed, - repeatCount: repeatCount, autoreverses: autoreverses) + Animation(kind: kind, + delay: (delay ?? 0) + interval, + speed: speed, + repeatCount: repeatCount, + autoreverses: autoreverses) } public func repeatCount(_ count: Int, autoreverses: Bool = true) -> Animation { @@ -94,13 +104,13 @@ extension Animation: CustomStringConvertible { return "nil" } - let repeating: String = repeatCount.flatMap { count -> String? in - if count < 0 { + let repeating: String = repeatCount.flatMap { repeatCount -> String? in + if repeatCount < 0 { return ".repeatForever(autoreverses: \(autoreverses ?? true))" - } else if count == 0 { + } else if repeatCount == 0 { return nil } else { - return ".repeatCount(\(count), autoreverses: \(autoreverses ?? true))" + return ".repeatCount(\(repeatCount), autoreverses: \(autoreverses ?? true))" } } ?? "" @@ -127,8 +137,9 @@ extension Animation { case easeOut(duration: Double?) case easeInOut(duration: Double?) case linear(duration: Double?) - case timingCurve(c0x: Double, c0y: Double, c1x: Double, c1y: Double, duration: Double?) case none + case timingCurve(c0x: Double, c0y: Double, c1x: Double, c1y: Double, duration: Double?) + // swiftlint:disable:previous enum_case_associated_values_count // MARK: Nested Types @@ -191,8 +202,10 @@ extension Animation { let c0y = try container.decode(Double.self, forKey: .c0y) let c1x = try container.decode(Double.self, forKey: .c1x) let c1y = try container.decode(Double.self, forKey: .c1y) - self = .timingCurve(c0x: c0x, c0y: c0y, - c1x: c1x, c1y: c1y, + self = .timingCurve(c0x: c0x, + c0y: c0y, + c1x: c1x, + c1y: c1y, duration: duration) case .none: self = .none @@ -329,8 +342,8 @@ extension Animation.Kind { return duration.map { .easeInOut(duration: $0) } ?? .easeInOut case .linear(duration: let duration): return duration.map { .linear(duration: $0) } ?? .linear - case .timingCurve(c0x: let c0x, c0y: let c0y, c1x: let c1x, c1y: let c1y, duration: let duration): - return .timingCurve(c0x, c0y, c1x, c1y, duration: duration ?? 0.35) + case let .timingCurve(c0x: c0x, c0y: c0y, c1x: c1x, c1y: c1y, duration: duration): + return .timingCurve(c0x, c0y, c1x, c1y, duration: duration ?? 0.35) } } } diff --git a/Sources/Presenter/Types/Font.swift b/Sources/Presenter/Types/Font.swift index 8bb4dba..6c7690d 100644 --- a/Sources/Presenter/Types/Font.swift +++ b/Sources/Presenter/Types/Font.swift @@ -42,7 +42,7 @@ public struct Font: Codable { private var size: CGFloat? private var weight: Weight? private var design: Design? - private var styling: [Styling]? + private var styling: [Styling]? // swiftlint:disable:this discouraged_optional_collection // MARK: Factory Functions - Style diff --git a/Sources/Presenter/Types/UnitPoint.swift b/Sources/Presenter/Types/UnitPoint.swift index 9c44006..ceb5a96 100644 --- a/Sources/Presenter/Types/UnitPoint.swift +++ b/Sources/Presenter/Types/UnitPoint.swift @@ -1,3 +1,5 @@ +// swiftlint:disable identifier_name + public struct UnitPoint: Codable { // MARK: Stored Properties diff --git a/Sources/Presenter/View - General/CoderView.swift b/Sources/Presenter/View - General/CoderView.swift index 481ac96..352bfb2 100644 --- a/Sources/Presenter/View - General/CoderView.swift +++ b/Sources/Presenter/View - General/CoderView.swift @@ -111,6 +111,7 @@ extension CoderView { // MARK: Static Properties + // swiftlint:disable:next discouraged_optional_collection private static var _registeredTypes: [String: Coder]? private static var registeredTypes: [String: Coder] { diff --git a/Sources/Presenter/View - General/ViewBuilder.swift b/Sources/Presenter/View - General/ViewBuilder.swift index 1073b4c..2d86541 100644 --- a/Sources/Presenter/View - General/ViewBuilder.swift +++ b/Sources/Presenter/View - General/ViewBuilder.swift @@ -1,5 +1,5 @@ @resultBuilder -public struct ViewBuilder { +public enum ViewBuilder { // MARK: Static Functions public static func buildBlock(_ item: V) -> View { diff --git a/Sources/Presenter/ViewModifier - General/CoderViewModifier.swift b/Sources/Presenter/ViewModifier - General/CoderViewModifier.swift index b223995..994440c 100644 --- a/Sources/Presenter/ViewModifier - General/CoderViewModifier.swift +++ b/Sources/Presenter/ViewModifier - General/CoderViewModifier.swift @@ -65,6 +65,7 @@ extension CoderViewModifier { // MARK: Static Properties + // swiftlint:disable:next discouraged_optional_collection private static var _registeredTypes: [String: Coder]? private static var registeredTypes: [String: Coder] { diff --git a/Sources/Presenter/ViewModifiers/Blur.swift b/Sources/Presenter/ViewModifiers/Blur.swift index 17612ff..d463f54 100644 --- a/Sources/Presenter/ViewModifiers/Blur.swift +++ b/Sources/Presenter/ViewModifiers/Blur.swift @@ -2,7 +2,7 @@ internal struct Blur: CodableViewModifier { // MARK: Stored Properties let radius: CGFloat - let opaque: Bool? + let opaque: Bool? // swiftlint:disable:this discouraged_optional_boolean } // MARK: - CustomStringConvertible @@ -19,7 +19,11 @@ extension Blur: CustomStringConvertible { extension Blur: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { - content.blur(radius: radius, opaque: opaque ?? false) + if let opaque = opaque { + content.blur(radius: radius, opaque: opaque) + } else { + content.blur(radius: radius) + } } } @@ -28,7 +32,8 @@ extension Blur: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func blur(radius: CGFloat, opaque: Bool? = nil) -> View { + public func blur(radius: CGFloat, + opaque: Bool? = nil) -> View { // swiftlint:disable:this discouraged_optional_boolean modifier(Blur(radius: radius, opaque: opaque)) } } diff --git a/Sources/Presenter/ViewModifiers/Clipped.swift b/Sources/Presenter/ViewModifiers/Clipped.swift index 13fc1c6..0c11ef6 100644 --- a/Sources/Presenter/ViewModifiers/Clipped.swift +++ b/Sources/Presenter/ViewModifiers/Clipped.swift @@ -1,7 +1,7 @@ internal struct Clipped: CodableViewModifier { // MARK: Stored Properties - let antialiased: Bool? + let antialiased: Bool? // swiftlint:disable:this discouraged_optional_boolean } // MARK: - CustomStringConvertible @@ -27,7 +27,9 @@ extension Clipped: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func clipped(antialiased: Bool? = nil) -> View { + public func clipped( + antialiased: Bool? = nil // swiftlint:disable:this discouraged_optional_boolean + ) -> View { modifier(Clipped(antialiased: antialiased)) } } diff --git a/Sources/Presenter/ViewModifiers/CornerRadius.swift b/Sources/Presenter/ViewModifiers/CornerRadius.swift index ce8052b..f0f47dc 100644 --- a/Sources/Presenter/ViewModifiers/CornerRadius.swift +++ b/Sources/Presenter/ViewModifiers/CornerRadius.swift @@ -2,7 +2,7 @@ internal struct CornerRadius: CodableViewModifier { // MARK: Stored Properties let value: CGFloat - let antialiased: Bool? + let antialiased: Bool? // swiftlint:disable:this discouraged_optional_boolean } // MARK: - CustomStringConvertible @@ -28,7 +28,10 @@ extension CornerRadius: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func cornerRadius(_ value: CGFloat, antialiased: Bool? = nil) -> View { + public func cornerRadius( + _ value: CGFloat, + antialiased: Bool? = nil // swiftlint:disable:this discouraged_optional_boolean + ) -> View { modifier(CornerRadius(value: value, antialiased: antialiased)) } } diff --git a/Sources/Presenter/ViewModifiers/DrawingGroup.swift b/Sources/Presenter/ViewModifiers/DrawingGroup.swift index d6ae2fa..92e52c4 100644 --- a/Sources/Presenter/ViewModifiers/DrawingGroup.swift +++ b/Sources/Presenter/ViewModifiers/DrawingGroup.swift @@ -7,7 +7,7 @@ public enum ColorRenderingMode: String, Codable { internal struct DrawingGroup: CodableViewModifier { // MARK: Stored Properties - let opaque: Bool? + let opaque: Bool? // swiftlint:disable:this discouraged_optional_boolean let colorMode: ColorRenderingMode? } @@ -48,7 +48,8 @@ extension ColorRenderingMode { // MARK: - View Extensions extension View { - public func drawingGroup(opaque: Bool? = nil, colorMode: ColorRenderingMode? = nil) -> View { + public func drawingGroup(opaque: Bool? = nil, // swiftlint:disable:this discouraged_optional_boolean + colorMode: ColorRenderingMode? = nil) -> View { modifier(DrawingGroup(opaque: opaque, colorMode: colorMode)) } } diff --git a/Sources/Presenter/ViewModifiers/DynamicFrame.swift b/Sources/Presenter/ViewModifiers/DynamicFrame.swift index 6af4f23..120d57a 100644 --- a/Sources/Presenter/ViewModifiers/DynamicFrame.swift +++ b/Sources/Presenter/ViewModifiers/DynamicFrame.swift @@ -56,8 +56,12 @@ extension View { alignment: Alignment = .center) -> View { modifier( DynamicFrame( - minWidth: minWidth, idealWidth: idealWidth, maxWidth: maxWidth, - minHeight: minHeight, idealHeight: idealHeight, maxHeight: maxHeight, + minWidth: minWidth, + idealWidth: idealWidth, + maxWidth: maxWidth, + minHeight: minHeight, + idealHeight: idealHeight, + maxHeight: maxHeight, alignment: alignment ) ) diff --git a/Sources/Presenter/ViewModifiers/Frame.swift b/Sources/Presenter/ViewModifiers/Frame.swift index 35de215..c9a931a 100644 --- a/Sources/Presenter/ViewModifiers/Frame.swift +++ b/Sources/Presenter/ViewModifiers/Frame.swift @@ -22,7 +22,8 @@ extension Frame: CustomStringConvertible { extension Frame: SwiftUI.ViewModifier { func body(content: Content) -> some SwiftUI.View { - content.frame(width: width, height: height, + content.frame(width: width, + height: height, alignment: alignment?.swiftUIValue ?? .center) } } diff --git a/Sources/Presenter/ViewModifiers/Opacity.swift b/Sources/Presenter/ViewModifiers/Opacity.swift index 5a8a2df..17d0068 100644 --- a/Sources/Presenter/ViewModifiers/Opacity.swift +++ b/Sources/Presenter/ViewModifiers/Opacity.swift @@ -27,7 +27,7 @@ extension Opacity: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func opacity(_ value: Double, antialiased: Bool? = nil) -> View { + public func opacity(_ value: Double) -> View { modifier(Opacity(value: value)) } } diff --git a/Sources/Presenter/ViewModifiers/Padding.swift b/Sources/Presenter/ViewModifiers/Padding.swift index 39f3d50..5da53ae 100644 --- a/Sources/Presenter/ViewModifiers/Padding.swift +++ b/Sources/Presenter/ViewModifiers/Padding.swift @@ -33,8 +33,10 @@ extension Padding: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func padding(top: CGFloat? = nil, leading: CGFloat? = nil, - bottom: CGFloat? = nil, trailing: CGFloat? = nil) -> View { + public func padding(top: CGFloat? = nil, + leading: CGFloat? = nil, + bottom: CGFloat? = nil, + trailing: CGFloat? = nil) -> View { modifier(Padding(top: top, leading: leading, bottom: bottom, trailing: trailing)) } diff --git a/Sources/Presenter/ViewModifiers/Shadow.swift b/Sources/Presenter/ViewModifiers/Shadow.swift index 2240126..4cc9634 100644 --- a/Sources/Presenter/ViewModifiers/Shadow.swift +++ b/Sources/Presenter/ViewModifiers/Shadow.swift @@ -3,8 +3,8 @@ internal struct Shadow: CodableViewModifier { let color: ColorCode? let radius: CGFloat - let x: CGFloat? - let y: CGFloat? + let x: CGFloat? // swiftlint:disable:this identifier_name + let y: CGFloat? // swiftlint:disable:this identifier_name } // MARK: - CustomStringConvertible @@ -38,7 +38,12 @@ extension Shadow: SwiftUI.ViewModifier { // MARK: - View Extensions extension View { - public func shadow(color: Color? = nil, radius: CGFloat, x: CGFloat? = nil, y: CGFloat? = nil) -> View { - modifier(Shadow(color: color.map(ColorCode.init), radius: radius, x: x, y: y)) + public func shadow( + color: Color? = nil, + radius: CGFloat, + x xValue: CGFloat? = nil, + y yValue: CGFloat? = nil + ) -> View { + modifier(Shadow(color: color.map(ColorCode.init), radius: radius, x: xValue, y: yValue)) } } diff --git a/Sources/Presenter/Views/ArrayView.swift b/Sources/Presenter/Views/ArrayView.swift index 7c91ac8..9b2cf99 100644 --- a/Sources/Presenter/Views/ArrayView.swift +++ b/Sources/Presenter/Views/ArrayView.swift @@ -5,7 +5,7 @@ struct ArrayView: CodableView { // MARK: Initialization - public init(content: [View]) { + init(content: [View]) { self.content = content.flatMap { contentView -> [CoderView] in if let arrayView = contentView as? ArrayView { return arrayView.content diff --git a/Sources/Presenter/Views/ComposedView.swift b/Sources/Presenter/Views/ComposedView.swift index f5639b0..2583803 100644 --- a/Sources/Presenter/Views/ComposedView.swift +++ b/Sources/Presenter/Views/ComposedView.swift @@ -9,7 +9,7 @@ struct ComposedView: CodableWrapperView { extension ComposedView: CustomStringConvertible { public var description: String { - "\(content)" + modifiers.reduce("") { $0 + ".\($1)" } + "\(content)" + modifiers.reduce(into: "") { $0 += ".\($1)" } } } diff --git a/Sources/Presenter/Views/HGrid.swift b/Sources/Presenter/Views/HGrid.swift index e244e77..7bf2ea3 100644 --- a/Sources/Presenter/Views/HGrid.swift +++ b/Sources/Presenter/Views/HGrid.swift @@ -41,7 +41,7 @@ extension HGrid { public var body: View { if #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) { - content.modifier( + return content.modifier( Modifier( rows: rows.map(\.swiftUIValue), alignment: alignment?.swiftUIValue ?? .center, @@ -50,7 +50,7 @@ extension HGrid { ) ) } else { - Nil() + return Nil() } } diff --git a/Sources/Presenter/Views/If.swift b/Sources/Presenter/Views/If.swift index d9907c5..990bd0c 100644 --- a/Sources/Presenter/Views/If.swift +++ b/Sources/Presenter/Views/If.swift @@ -1,4 +1,4 @@ -public struct If: CodableWrapperView { +public struct If: CodableWrapperView { // swiftlint:disable:this type_name // MARK: Nested Types private enum CodingKeys: String, CodingKey { diff --git a/Sources/Presenter/Views/Image.swift b/Sources/Presenter/Views/Image.swift index 737357d..819d928 100644 --- a/Sources/Presenter/Views/Image.swift +++ b/Sources/Presenter/Views/Image.swift @@ -80,7 +80,10 @@ private struct ImageView: SwiftUI.View { // MARK: Helpers private func load() { - guard !didStartLoading else { return } + guard !didStartLoading else { + return + } + didStartLoading = true switch image.kind { diff --git a/Sources/Presenter/Views/NavigationLink.swift b/Sources/Presenter/Views/NavigationLink.swift index fa8fb5d..947db52 100644 --- a/Sources/Presenter/Views/NavigationLink.swift +++ b/Sources/Presenter/Views/NavigationLink.swift @@ -40,7 +40,7 @@ private struct Modifier1: ViewModifier { let label: CoderView let isActive: Binding - public func body(for content: Content) -> View { + func body(for content: Content) -> View { label.modifier(Modifier2(destination: content, isActive: isActive)) } } diff --git a/Sources/Presenter/Views/ScrollView.swift b/Sources/Presenter/Views/ScrollView.swift index 4d3b61a..713c09d 100644 --- a/Sources/Presenter/Views/ScrollView.swift +++ b/Sources/Presenter/Views/ScrollView.swift @@ -2,14 +2,14 @@ public struct ScrollView: CodableWrapperView { // MARK: Stored Properties private let axis: AxisSet? - private let showsIndicators: Bool? + private let showsIndicators: Bool? // swiftlint:disable:this discouraged_optional_boolean private let content: CoderView // MARK: Initialization public init( _ axis: AxisSet? = nil, - showsIndicators: Bool? = nil, + showsIndicators: Bool? = nil, // swiftlint:disable:this discouraged_optional_boolean @ViewBuilder content: () -> View ) { self.axis = axis diff --git a/Sources/Presenter/Views/SecureField.swift b/Sources/Presenter/Views/SecureField.swift index 8bfca49..a0cfd64 100644 --- a/Sources/Presenter/Views/SecureField.swift +++ b/Sources/Presenter/Views/SecureField.swift @@ -7,12 +7,14 @@ public struct SecureField: CodableView { // MARK: Initialization - public init(_ title: String, text: Binding, + public init(_ title: String, + text: Binding, onCommit: Action? = nil) { self.init(.static(title), text: text, onCommit: onCommit) } - public init(_ title: Value, text: Binding, + public init(_ title: Value, + text: Binding, onCommit: Action? = nil) { self.title = title self.text = text diff --git a/Sources/Presenter/Views/TextField.swift b/Sources/Presenter/Views/TextField.swift index 86b477a..069fdac 100644 --- a/Sources/Presenter/Views/TextField.swift +++ b/Sources/Presenter/Views/TextField.swift @@ -8,8 +8,10 @@ public struct TextField: CodableView { // MARK: Initialization - public init(_ title: String, text: Binding, - onCommit: Action? = nil, onEditingChanged: Action? = nil) { + public init(_ title: String, + text: Binding, + onCommit: Action? = nil, + onEditingChanged: Action? = nil) { self.init( .static(title), text: text, @@ -18,8 +20,10 @@ public struct TextField: CodableView { ) } - public init(_ title: Value, text: Binding, - onCommit: Action? = nil, onEditingChanged: Action? = nil) { + public init(_ title: Value, + text: Binding, + onCommit: Action? = nil, + onEditingChanged: Action? = nil) { self.title = title self.text = text self.onCommit = onCommit.map(CoderAction.init) diff --git a/Sources/Presenter/Views/VGrid.swift b/Sources/Presenter/Views/VGrid.swift index d122f20..67e371f 100644 --- a/Sources/Presenter/Views/VGrid.swift +++ b/Sources/Presenter/Views/VGrid.swift @@ -41,14 +41,14 @@ extension VGrid { public var body: View { if #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) { - content.modifier( + return content.modifier( Modifier(columns: columns.map(\.swiftUIValue), alignment: alignment?.swiftUIValue ?? .center, spacing: spacing, pinnedViews: pinnedViews.swiftUIValue) ) } else { - Nil() + return Nil() } } diff --git a/Sources/Presenter/Views/VStack.swift b/Sources/Presenter/Views/VStack.swift index de7f7b9..449bf98 100644 --- a/Sources/Presenter/Views/VStack.swift +++ b/Sources/Presenter/Views/VStack.swift @@ -41,19 +41,11 @@ private struct Modifier: ViewModifier, SwiftUI.ViewModifier { let alignment: SwiftUI.HorizontalAlignment let spacing: CGFloat? - internal init(alignment: SwiftUI.HorizontalAlignment, spacing: CGFloat?) { + init(alignment: SwiftUI.HorizontalAlignment, spacing: CGFloat?) { self.alignment = alignment self.spacing = spacing } - init(from decoder: Decoder) throws { - fatalError() // TODO - } - - func encode(to encoder: Encoder) throws { - // TODO - } - func body(content: Content) -> some SwiftUI.View { SwiftUI.VStack(alignment: alignment, spacing: spacing) { content diff --git a/Tests/PresenterTests/PresenterTests.swift b/Tests/PresenterTests/PresenterTests.swift index 4fdf48f..963b2c5 100644 --- a/Tests/PresenterTests/PresenterTests.swift +++ b/Tests/PresenterTests/PresenterTests.swift @@ -3,8 +3,6 @@ import XCTest import Presenter -typealias _Model = Model - struct TestAction: Action { func perform(on model: Model) { model.set("login-title", to: "Success") @@ -51,8 +49,12 @@ final class PresenterTests: XCTestCase { let serverView = HStack(spacing: 8) { Text("Hallo") .padding(8) - .frame(minWidth: 10, idealWidth: 30, maxWidth: 50, - minHeight: 100, idealHeight: 110, maxHeight: 120, + .frame(minWidth: 10, + idealWidth: 30, + maxWidth: 50, + minHeight: 100, + idealHeight: 110, + maxHeight: 120, alignment: .center) Text("Check") From 2861b9948e42deabf2d18294918a61165be129c9 Mon Sep 17 00:00:00 2001 From: Paul Kraft Date: Sun, 5 Dec 2021 18:29:32 +0100 Subject: [PATCH 07/10] Remove ChartPresenter, TracePresenter, MetricPresenter --- Package.swift | 79 ++--------- Sources/ChartPresenter/Chart+AreaStyle.swift | 11 -- Sources/ChartPresenter/Chart+Charts.swift | 66 --------- .../ChartPresenter/Chart+ColumnStyle.swift | 11 -- Sources/ChartPresenter/Chart+LineStyle.swift | 18 --- .../Chart+StackedAreaStyle.swift | 11 -- Sources/ChartPresenter/Chart+Style.swift | 81 ------------ Sources/ChartPresenter/Chart.swift | 44 ------ Sources/ChartPresenter/Exports.swift | 5 - Sources/ChartPresenter/UIservCharts.swift | 9 -- Sources/MetricPresenter/Card.swift | 49 ------- Sources/MetricPresenter/Exports.swift | 1 - Sources/MetricPresenter/Gauge.swift | 114 ---------------- Sources/MetricPresenter/Graph+Grid.swift | 70 ---------- Sources/MetricPresenter/Graph+Labeling.swift | 83 ------------ .../MetricPresenter/Graph+LabelingEdge.swift | 55 -------- Sources/MetricPresenter/Graph.swift | 125 ------------------ Sources/MetricPresenter/MetricCard.swift | 43 ------ Sources/MetricPresenter/MetricPresenter.swift | 23 ---- .../MetricPresenter/SizePreferenceKey.swift | 27 ---- .../Configuration/Configuration+Plugin.swift | 2 +- Sources/TracePresenter/Exports.swift | 1 - Sources/TracePresenter/TraceGraph.swift | 83 ------------ Sources/TracePresenter/TracePresenter.swift | 9 -- .../PresenterTests/TracePresenterTests.swift | 2 +- 25 files changed, 12 insertions(+), 1010 deletions(-) delete mode 100644 Sources/ChartPresenter/Chart+AreaStyle.swift delete mode 100644 Sources/ChartPresenter/Chart+Charts.swift delete mode 100644 Sources/ChartPresenter/Chart+ColumnStyle.swift delete mode 100644 Sources/ChartPresenter/Chart+LineStyle.swift delete mode 100644 Sources/ChartPresenter/Chart+StackedAreaStyle.swift delete mode 100644 Sources/ChartPresenter/Chart+Style.swift delete mode 100644 Sources/ChartPresenter/Chart.swift delete mode 100644 Sources/ChartPresenter/Exports.swift delete mode 100644 Sources/ChartPresenter/UIservCharts.swift delete mode 100644 Sources/MetricPresenter/Card.swift delete mode 100644 Sources/MetricPresenter/Exports.swift delete mode 100644 Sources/MetricPresenter/Gauge.swift delete mode 100644 Sources/MetricPresenter/Graph+Grid.swift delete mode 100644 Sources/MetricPresenter/Graph+Labeling.swift delete mode 100644 Sources/MetricPresenter/Graph+LabelingEdge.swift delete mode 100644 Sources/MetricPresenter/Graph.swift delete mode 100644 Sources/MetricPresenter/MetricCard.swift delete mode 100644 Sources/MetricPresenter/MetricPresenter.swift delete mode 100644 Sources/MetricPresenter/SizePreferenceKey.swift delete mode 100644 Sources/TracePresenter/Exports.swift delete mode 100644 Sources/TracePresenter/TraceGraph.swift delete mode 100644 Sources/TracePresenter/TracePresenter.swift diff --git a/Package.swift b/Package.swift index dbcbfe3..aa42b24 100644 --- a/Package.swift +++ b/Package.swift @@ -10,53 +10,21 @@ let package = Package( products: [ .library( name: "Presenter", - targets: ["Presenter"] - ), - .library( - name: "ChartPresenter", - targets: ["ChartPresenter"] - ), - .library( - name: "MetricPresenter", - targets: ["MetricPresenter"] - ), - .library( - name: "TracePresenter", - targets: ["TracePresenter"] - ), + targets: ["Presenter"]), .executable( name: "Example", - targets: ["Example", "Presenter"] - ) - ], - dependencies: [ - .package(name: "Charts", url: "https://github.com/spacenation/swiftui-charts.git", from: "1.0.0") + targets: ["Example"]) ], targets: [ .target( name: "Presenter", - dependencies: [] - ), - .target( - name: "ChartPresenter", - dependencies: ["Presenter", "Charts"] - ), - .target( - name: "MetricPresenter", - dependencies: ["ChartPresenter"] - ), - .target( - name: "TracePresenter", - dependencies: ["Presenter"] - ), - .testTarget( - name: "PresenterTests", - dependencies: ["Presenter", "ChartPresenter", "MetricPresenter", "TracePresenter"] - ), + dependencies: []), .executableTarget( name: "Example", - dependencies: ["Presenter"] - ) + dependencies: ["Presenter"]), + .testTarget( + name: "PresenterTests", + dependencies: ["Presenter"]), ] ) @@ -68,43 +36,16 @@ let package = Package( products: [ .library( name: "Presenter", - targets: ["Presenter"] - ), - .library( - name: "ChartPresenter", - targets: ["ChartPresenter"] - ), - .library( - name: "MetricPresenter", - targets: ["MetricPresenter"] - ), - .library( - name: "TracePresenter", - targets: ["TracePresenter"] - ) + targets: ["Presenter"]), ], dependencies: [], targets: [ .target( name: "Presenter", - dependencies: [] - ), - .target( - name: "ChartPresenter", - dependencies: ["Presenter"] - ), - .target( - name: "MetricPresenter", - dependencies: ["ChartPresenter"] - ), - .target( - name: "TracePresenter", - dependencies: ["Presenter"] - ), + dependencies: []), .testTarget( name: "PresenterTests", - dependencies: ["Presenter", "ChartPresenter", "MetricPresenter", "TracePresenter"] - ) + dependencies: ["Presenter"]), ] ) diff --git a/Sources/ChartPresenter/Chart+AreaStyle.swift b/Sources/ChartPresenter/Chart+AreaStyle.swift deleted file mode 100644 index e49d312..0000000 --- a/Sources/ChartPresenter/Chart+AreaStyle.swift +++ /dev/null @@ -1,11 +0,0 @@ -extension Chart { - public struct AreaStyle: Codable { - public internal(set) var lineType: LineType - public internal(set) var fill: CoderView - - public init(_ lineType: LineType, fill: View) { - self.lineType = lineType - self.fill = CoderView(fill) - } - } -} diff --git a/Sources/ChartPresenter/Chart+Charts.swift b/Sources/ChartPresenter/Chart+Charts.swift deleted file mode 100644 index d37c722..0000000 --- a/Sources/ChartPresenter/Chart+Charts.swift +++ /dev/null @@ -1,66 +0,0 @@ -#if canImport(Charts) - -extension Chart.Style { - @SwiftUI.ViewBuilder - func chart(for data: [[Double]]) -> some SwiftUI.View { - switch self { - case let .line(style): - Charts.Chart(data: data) - .chartStyle(style.chartsValue) - case let .area(style): - Charts.Chart(data: data) - .chartStyle(style.chartsValue) - case let .stackedArea(style): - Charts.Chart(data: data) - .chartStyle(style.chartsValue) - case let .column(style): - Charts.Chart(data: data) - .chartStyle(style.chartsValue) - } - } - - private func chart(data: [[Double]], style: Style) -> some SwiftUI.View { - Charts.Chart(data: data) - .chartStyle(style) - } -} - -extension Chart.ColumnStyle { - fileprivate var chartsValue: ColumnChartStyle { - .init(column: column.eraseToAnyView(), spacing: spacing) - } -} - -extension Chart.StackedAreaStyle { - fileprivate var chartsValue: StackedAreaChartStyle { - .init(lineType.chartsValue, colors: colors.map { $0.color.body }) - } -} - - -extension Chart.AreaStyle { - fileprivate var chartsValue: AreaChartStyle { - .init(lineType.chartsValue, fill: fill.eraseToAnyView()) - } -} - -extension Chart.LineStyle { - fileprivate var chartsValue: LineChartStyle { - .init(lineType.chartsValue, - lineColor: color.color.body, - lineWidth: width) - } -} - -extension Chart.LineType { - fileprivate var chartsValue: Charts.LineType { - switch self { - case .line: - return .line - case .quadCurve: - return .quadCurve - } - } -} - -#endif diff --git a/Sources/ChartPresenter/Chart+ColumnStyle.swift b/Sources/ChartPresenter/Chart+ColumnStyle.swift deleted file mode 100644 index b0dad6c..0000000 --- a/Sources/ChartPresenter/Chart+ColumnStyle.swift +++ /dev/null @@ -1,11 +0,0 @@ -extension Chart { - public struct ColumnStyle: Codable { - public internal(set) var column: CoderView - public internal(set) var spacing: CGFloat - - public init(column: View, spacing: CGFloat) { - self.column = CoderView(column) - self.spacing = spacing - } - } -} diff --git a/Sources/ChartPresenter/Chart+LineStyle.swift b/Sources/ChartPresenter/Chart+LineStyle.swift deleted file mode 100644 index c8ebe61..0000000 --- a/Sources/ChartPresenter/Chart+LineStyle.swift +++ /dev/null @@ -1,18 +0,0 @@ -extension Chart { - public struct LineStyle: Codable { - public internal(set) var lineType: LineType - public internal(set) var color: ColorCode - public internal(set) var width: CGFloat - - public init(_ lineType: LineType, color: Color, width: CGFloat) { - self.lineType = lineType - self.color = ColorCode(color) - self.width = width - } - } - - public enum LineType: String, Codable { - case line - case quadCurve - } -} diff --git a/Sources/ChartPresenter/Chart+StackedAreaStyle.swift b/Sources/ChartPresenter/Chart+StackedAreaStyle.swift deleted file mode 100644 index f333b16..0000000 --- a/Sources/ChartPresenter/Chart+StackedAreaStyle.swift +++ /dev/null @@ -1,11 +0,0 @@ -extension Chart { - public struct StackedAreaStyle: Codable { - public internal(set) var lineType: LineType - public internal(set) var colors: [ColorCode] - - public init(_ lineType: LineType, colors: [Color]) { - self.lineType = lineType - self.colors = colors.map(ColorCode.init) - } - } -} diff --git a/Sources/ChartPresenter/Chart+Style.swift b/Sources/ChartPresenter/Chart+Style.swift deleted file mode 100644 index 3a6c8c5..0000000 --- a/Sources/ChartPresenter/Chart+Style.swift +++ /dev/null @@ -1,81 +0,0 @@ -extension Chart { - public enum Style: Codable { - // MARK: Nested Types - - private enum CodingKeys: String, CodingKey { - case type - } - - private enum StyleKind: String, Codable { - case line - case area - case stackedArea - case column - } - - // MARK: Cases - - case line(LineStyle) - case area(AreaStyle) - case stackedArea(StackedAreaStyle) - case column(ColumnStyle) - - // MARK: Computed Properties - - private var kind: StyleKind { - switch self { - case .line: - return .line - case .area: - return .area - case .column: - return .column - case .stackedArea: - return .stackedArea - } - } - - // MARK: Initialization - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let type = try container.decode(String.self, forKey: .type) - guard let kind = StyleKind(rawValue: type) else { - throw DecodingError - .keyNotFound( - CodingKeys.type, - .init(codingPath: decoder.codingPath, - debugDescription: "Could not find chart style \(type).") - ) - } - switch kind { - case .line: - self = try .line(LineStyle(from: decoder)) - case .area: - self = try .area(AreaStyle(from: decoder)) - case .column: - self = try .column(ColumnStyle(from: decoder)) - case .stackedArea: - self = try .stackedArea(StackedAreaStyle(from: decoder)) - } - } - - // MARK: Methods - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(kind, forKey: .type) - - switch self { - case let .line(style): - try style.encode(to: encoder) - case let .area(style): - try style.encode(to: encoder) - case let .stackedArea(style): - try style.encode(to: encoder) - case let .column(style): - try style.encode(to: encoder) - } - } - } -} diff --git a/Sources/ChartPresenter/Chart.swift b/Sources/ChartPresenter/Chart.swift deleted file mode 100644 index 2d1140e..0000000 --- a/Sources/ChartPresenter/Chart.swift +++ /dev/null @@ -1,44 +0,0 @@ -public struct Chart: CodableView { - // MARK: Stored Properties - - public let data: [[Double]] - public let style: Style - - // MARK: Initialization - - public init(data: [Double], style: Style) { - self.data = data.map { [$0] } - self.style = style - } - - public init(data: [[Double]], style: Style) { - self.data = data - self.style = style - } -} - -// MARK: - CustomStringConvertible - -extension Chart: CustomStringConvertible { - public var description: String { - "Chart(data: \(data), style: \(style))" - } -} - -#if canImport(Charts) - -extension Chart: SwiftUI.View { - public var body: some SwiftUI.View { - style.chart(for: data) - } -} - -#elseif canImport(SwiftUI) - -extension Chart: SwiftUI.View { - public var body: some SwiftUI.View { - EmptyView() - } -} - -#endif diff --git a/Sources/ChartPresenter/Exports.swift b/Sources/ChartPresenter/Exports.swift deleted file mode 100644 index 50c83b3..0000000 --- a/Sources/ChartPresenter/Exports.swift +++ /dev/null @@ -1,5 +0,0 @@ -@_exported import Presenter - -#if canImport(Charts) -@_exported import Charts -#endif diff --git a/Sources/ChartPresenter/UIservCharts.swift b/Sources/ChartPresenter/UIservCharts.swift deleted file mode 100644 index e8883ae..0000000 --- a/Sources/ChartPresenter/UIservCharts.swift +++ /dev/null @@ -1,9 +0,0 @@ -public struct ChartPresenter: Plugin { - public init() {} - - public var views: [CodableView.Type] { - [ - Chart.self - ] - } -} diff --git a/Sources/MetricPresenter/Card.swift b/Sources/MetricPresenter/Card.swift deleted file mode 100644 index 69e1116..0000000 --- a/Sources/MetricPresenter/Card.swift +++ /dev/null @@ -1,49 +0,0 @@ -struct Card: CodableViewModifier { - // MARK: Stored Properties - - var radius: CGFloat? -} - -extension Card: CustomStringConvertible { - var description: String { - "card(cornerRadius: \(radius?.description ?? "nil"))" - } -} - -#if canImport(SwiftUI) - -extension Card: SwiftUI.ViewModifier { - #if os(macOS) - - func body(content: Content) -> some SwiftUI.View { - content - .background(SwiftUI.Color(.textBackgroundColor)) - .cornerRadius(radius ?? 8) - .shadow(color: SwiftUI.Color.primary.opacity(0.2), radius: 4) - } - - #else - - func body(content: Content) -> some SwiftUI.View { - content - .background(SwiftUI.Color(.systemBackground)) - .cornerRadius(radius ?? 8) - .shadow(color: SwiftUI.Color.primary.opacity(0.2), radius: 4) - } - - #endif -} - -extension SwiftUI.View { - public func card(cornerRadius: CGFloat? = nil) -> some SwiftUI.View { - modifier(Card(radius: cornerRadius)) - } -} - -#endif - -extension View { - public func card(cornerRadius: CGFloat? = nil) -> View { - modifier(Card(radius: cornerRadius)) - } -} diff --git a/Sources/MetricPresenter/Exports.swift b/Sources/MetricPresenter/Exports.swift deleted file mode 100644 index 7d86cf7..0000000 --- a/Sources/MetricPresenter/Exports.swift +++ /dev/null @@ -1 +0,0 @@ -@_exported import ChartPresenter diff --git a/Sources/MetricPresenter/Gauge.swift b/Sources/MetricPresenter/Gauge.swift deleted file mode 100644 index 51bd30a..0000000 --- a/Sources/MetricPresenter/Gauge.swift +++ /dev/null @@ -1,114 +0,0 @@ -public struct Gauge: CodableWrapperView { - // MARK: Stored Properties - - private let value: CGFloat - private let thickness: CGFloat - private let scale: CGFloat - private let colors: [ColorCode] - private let content: CoderView - - // MARK: Initialization - - public init( - value: CGFloat, - thickness: CGFloat = 6, - scale: CGFloat = 1.777, - colors: [ColorCode], - @ViewBuilder content: () -> View - ) { - self.value = value - self.thickness = thickness - self.scale = scale - self.colors = colors - self.content = CoderView(content()) - } - - // MARK: Views - - public var body: View { - content - .modifier( - GaugeModifier( - value: value, - thickness: thickness, - scale: scale, - colors: colors - ) - ) - } -} - -struct GaugeModifier: CodableViewModifier { - var value: CGFloat - var thickness: CGFloat - var scale: CGFloat - var colors: [ColorCode] -} - -#if canImport(SwiftUI) - -private struct GaugeView: SwiftUI.View { - // MARK: Stored Properties - - let gauge: GaugeModifier - let content: Content - - // MARK: Computed Properties - - var gradient: SwiftUI.AngularGradient { - .init( - gradient: .init(colors: gauge.colors.map { $0.color.body }), - center: .center, - startAngle: .degrees(0), - endAngle: .degrees(270) - ) - } - - var circleOffset: CGSize { - let ratio = -(gauge.value * 0.75) * 2 * .pi + CGFloat.pi / 2 - let radius = diameter / 2 - gauge.thickness / 2 - return CGSize(width: sin(ratio) * radius, - height: cos(ratio) * radius) - } - - // MARK: State - - @SwiftUI.State private var diameter = CGFloat.zero - - // MARK: Views - - var body: some SwiftUI.View { - SwiftUI.ZStack { - content - .size(in: GaugeSizePreferenceKey.self) - - SwiftUI.ZStack { - SwiftUI.Circle() - .trim(from: 0, to: 0.75) - .stroke(gradient, style: .init(lineWidth: gauge.thickness, lineCap: .round)) - - SwiftUI.Circle() - .stroke(SwiftUI.Color.white, style: .init(lineWidth: gauge.thickness / 2)) - .frame(width: gauge.thickness * 1.5, height: gauge.thickness * 1.5) - .offset(circleOffset) - } - .padding(gauge.thickness / 2) - .rotationEffect(.degrees(135)) - .frame(width: diameter, height: diameter) - } - .onPreferenceChange(GaugeSizePreferenceKey.self) { size in - self.diameter = size.width * self.gauge.scale - } - .foregroundColor(SwiftUI.Color.black) - } -} - -extension GaugeModifier: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { - GaugeView(gauge: self, content: content) - } -} - -private struct GaugeSizePreferenceKey: SizePreferenceKey {} - -#endif diff --git a/Sources/MetricPresenter/Graph+Grid.swift b/Sources/MetricPresenter/Graph+Grid.swift deleted file mode 100644 index 021bfef..0000000 --- a/Sources/MetricPresenter/Graph+Grid.swift +++ /dev/null @@ -1,70 +0,0 @@ -#if canImport(SwiftUI) - -extension Graph { - struct Grid { - let axis: Axis - let values: [CGFloat] - let lineWidth: CGFloat - } -} - -extension Graph.Grid: SwiftUI.View { - var body: some SwiftUI.View { - GeometryReader { geometry in - SwiftUI.ZStack(alignment: .topLeading) { - ForEach(self.values, id: \.self) { value in - self.line - .offset(self.offset(at: value, size: geometry.size)) - } - } - } - } - - // MARK: Helpers - - private var line: some SwiftUI.View { - SwiftUI.Color.gray - .frame(width: requiredWidth, height: requiredHeight) - .frame(maxWidth: maxWidth, maxHeight: maxHeight) - } - - private func offset(at percentage: CGFloat, size: CGSize) -> CGSize { - switch axis { - case .vertical: - return CGSize(width: percentage * size.width, height: 0) - case .horizontal: - return CGSize(width: 0, height: (1 - percentage) * size.height) - } - } - - private var requiredWidth: CGFloat? { - axis == .vertical ? lineWidth : nil - } - - private var requiredHeight: CGFloat? { - axis == .horizontal ? lineWidth : nil - } - - private var maxWidth: CGFloat? { - axis == .horizontal ? .infinity : nil - } - - private var maxHeight: CGFloat? { - axis == .vertical ? .infinity : nil - } -} - -extension SwiftUI.View { - public func graphGrid(vertical: [CGFloat] = [], horizontal: [CGFloat] = [], width: CGFloat = 8) -> some SwiftUI.View { - SwiftUI.ZStack { - Group { - Graph.Grid(axis: .vertical, values: vertical, lineWidth: width) - Graph.Grid(axis: .horizontal, values: horizontal, lineWidth: width) - } - - self - } - } -} - -#endif diff --git a/Sources/MetricPresenter/Graph+Labeling.swift b/Sources/MetricPresenter/Graph+Labeling.swift deleted file mode 100644 index 5b18a9d..0000000 --- a/Sources/MetricPresenter/Graph+Labeling.swift +++ /dev/null @@ -1,83 +0,0 @@ -#if canImport(SwiftUI) - -extension Graph { - struct Labeling { - // MARK: Stored Properties - - var top: [Graph.Label] - var trailing: [Graph.Label] - var bottom: [Graph.Label] - var leading: [Graph.Label] - - var spacing: CGFloat - var borderWidth: CGFloat - } -} - -extension Graph.Labeling: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { - GeometryReader { geometry in - SwiftUI.HStack(spacing: 0) { - self.horizontalLabels(isLeading: true, size: geometry.size) - SwiftUI.VStack(spacing: 0) { - self.verticalLabels(isTop: true, size: geometry.size) - content - self.verticalLabels(isTop: false, size: geometry.size) - } - self.horizontalLabels(isLeading: false, size: geometry.size) - } - } - } - - // MARK: Helpers - - private func horizontalLabels(isLeading: Bool, size: CGSize) -> some SwiftUI.View { - labeling(isLeading ? leading : trailing, - at: isLeading ? .leading : .trailing) - .frame(width: borderWidth, - height: size.height - (spacing + borderWidth) * 2) - .padding(isLeading ? .trailing : .leading, spacing) - } - - private func verticalLabels(isTop: Bool, size: CGSize) -> some SwiftUI.View { - labeling(isTop ? top : bottom, - at: isTop ? .top : .bottom) - .frame(width: size.width - (spacing + borderWidth) * 2, - height: borderWidth) - .padding(isTop ? .bottom : .top, spacing) - } - - private func labeling(_ labels: [Graph.Label], at edge: Graph.Edge) -> some SwiftUI.View { - Group { - if labels.isEmpty { - SwiftUI.Color.clear - } else { - Graph.LabelingEdge(labels: labels, edge: edge) - } - } - } -} - -extension SwiftUI.View { - public func graphLabeling( - top: [Graph.Label] = [], - trailing: [Graph.Label] = [], - bottom: [Graph.Label] = [], - leading: [Graph.Label] = [], - spacing: CGFloat = 6, - borderWidth: CGFloat = 36 - ) -> some SwiftUI.View { - modifier( - Graph.Labeling( - top: top, - trailing: trailing, - bottom: bottom, - leading: leading, - spacing: spacing, - borderWidth: borderWidth - ) - ) - } -} - -#endif diff --git a/Sources/MetricPresenter/Graph+LabelingEdge.swift b/Sources/MetricPresenter/Graph+LabelingEdge.swift deleted file mode 100644 index df6d655..0000000 --- a/Sources/MetricPresenter/Graph+LabelingEdge.swift +++ /dev/null @@ -1,55 +0,0 @@ -#if canImport(SwiftUI) - -extension Graph.Edge { - var axis: Axis { - switch self { - case .top, .bottom: - return .horizontal - case .leading, .trailing: - return .vertical - } - } - - var alignment: SwiftUI.Alignment { - switch self { - case .top, .bottom: - return .center - case .leading: - return .trailing - case .trailing: - return .leading - } - } -} - -extension Graph { - struct LabelingEdge { - var labels: [Graph.Label] - var edge: Graph.Edge - } -} - -extension Graph.LabelingEdge: SwiftUI.View { - var body: some SwiftUI.View { - GeometryReader { geometry in - SwiftUI.ZStack(alignment: self.edge.alignment) { - ForEach(self.labels) { label in - SwiftUI.Text(label.text) - .offset(self.offset(value: label.value, size: geometry.size)) - } - } - } - .font(.caption) - } - - private func offset(value: CGFloat, size: CGSize) -> CGSize { - switch edge.axis { - case .vertical: - return CGSize(width: 0, height: (1 - value) * size.height) - case .horizontal: - return CGSize(width: value * size.width, height: 0) - } - } -} - -#endif diff --git a/Sources/MetricPresenter/Graph.swift b/Sources/MetricPresenter/Graph.swift deleted file mode 100644 index 0eec40f..0000000 --- a/Sources/MetricPresenter/Graph.swift +++ /dev/null @@ -1,125 +0,0 @@ -public struct Graph: CodableView { - // MARK: Nested Types - - public struct Label: Codable { - // MARK: Stored Properties - - public var text: String - public var value: CGFloat - - // MARK: Initialization - - public init(text: String, value: CGFloat) { - self.text = text - self.value = value - } - } - - public enum Edge: String, Codable { - case top = "t" - case trailing = "r" - case bottom = "b" - case leading = "l" - } - - public struct DataSet: Codable { - // MARK: Stored Properties - - public var title: String - public var color: ColorCode? - public var data: [Double] - public var style: Chart.Style - - // MARK: Initialization - - public init(title: String, color: ColorCode? = nil, data: [Double], style: Chart.Style) { - self.title = title - self.color = color - self.data = data - self.style = style - } - } - - // MARK: Stored Properties - - public var labels: [Edge: [Label]] - public var data: [DataSet] - public var gridWidth: CGFloat - - // MARK: Initialization - - public init( - topLabels: [Graph.Label]? = nil, // swiftlint:disable:this discouraged_optional_collection - trailingLabels: [Graph.Label]? = nil, // swiftlint:disable:this discouraged_optional_collection - bottomLabels: [Graph.Label]? = nil, // swiftlint:disable:this discouraged_optional_collection - leadingLabels: [Graph.Label]? = nil, // swiftlint:disable:this discouraged_optional_collection - data: [Graph.DataSet], - gridWidth: CGFloat - ) { - self.labels = [ - .top: topLabels, - .trailing: trailingLabels, - .bottom: bottomLabels, - .leading: leadingLabels - ] - .compactMapValues { ($0 ?? []).isEmpty ? nil : $0 } - - self.data = data - self.gridWidth = gridWidth - } -} - -#if canImport(SwiftUI) - -extension Graph.Label: Identifiable { - public var id: CGFloat { - value - } -} - -extension Graph.DataSet: Identifiable { - public var id: String { - title - } -} - -extension Graph.DataSet { - public var chart: Chart { - Chart(data: data, style: style) - } -} - -extension Graph: SwiftUI.View { - public var body: some SwiftUI.View { - content - .graphGrid( - vertical: verticalGridValues, - horizontal: horizontalGridValues, - width: gridWidth - ) - .graphLabeling( - top: labels[.top] ?? [], - trailing: labels[.trailing] ?? [], - bottom: labels[.bottom] ?? [], - leading: labels[.leading] ?? [] - ) - } - - private var horizontalGridValues: [CGFloat] { - let horizontalLabels = (labels[.leading] ?? []) + (labels[.trailing] ?? []) - return Set(horizontalLabels.map { $0.value }).sorted() - } - - private var verticalGridValues: [CGFloat] { - let verticalLabels = (labels[.top] ?? []) + (labels[.bottom] ?? []) - return Set(verticalLabels.map { $0.value }).sorted() - } - - private var content: some SwiftUI.View { - SwiftUI.ZStack { - ForEach(data) { $0.chart.body } - } - } -} - -#endif diff --git a/Sources/MetricPresenter/MetricCard.swift b/Sources/MetricPresenter/MetricCard.swift deleted file mode 100644 index 4410353..0000000 --- a/Sources/MetricPresenter/MetricCard.swift +++ /dev/null @@ -1,43 +0,0 @@ -struct MetricCard: CodableViewModifier { - // MARK: Stored Properties - - var title: String - var subtitle: String -} - -#if canImport(SwiftUI) - -extension MetricCard: SwiftUI.ViewModifier { - func body(content: Content) -> some SwiftUI.View { - SwiftUI.VStack(alignment: .leading) { - SwiftUI.Text(title) - .font(.headline) - SwiftUI.Text(subtitle) - .font(.caption) - .opacity(0.5) - - SwiftUI.HStack { - SwiftUI.Spacer() - SwiftUI.VStack { - SwiftUI.Spacer() - content - SwiftUI.Spacer() - } - SwiftUI.Spacer() - } - .aspectRatio(2, contentMode: .fit) - .frame(maxWidth: .infinity) - } - .padding(16) - .card() - .padding(8) - } -} - -#endif - -extension View { - public func metricCard(title: String, subtitle: String) -> View { - modifier(MetricCard(title: title, subtitle: subtitle)) - } -} diff --git a/Sources/MetricPresenter/MetricPresenter.swift b/Sources/MetricPresenter/MetricPresenter.swift deleted file mode 100644 index 79f2bab..0000000 --- a/Sources/MetricPresenter/MetricPresenter.swift +++ /dev/null @@ -1,23 +0,0 @@ -public struct MetricPresenter: Plugin { - public init() {} - - public var views: [CodableView.Type] { - [ - Graph.self - ] - } - - public var viewModifiers: [CodableViewModifier.Type] { - [ - GaugeModifier.self, - MetricCard.self, - Card.self - ] - } - - public var plugins: [Plugin.Type] { - [ - ChartPresenter.self - ] - } -} diff --git a/Sources/MetricPresenter/SizePreferenceKey.swift b/Sources/MetricPresenter/SizePreferenceKey.swift deleted file mode 100644 index cf9c312..0000000 --- a/Sources/MetricPresenter/SizePreferenceKey.swift +++ /dev/null @@ -1,27 +0,0 @@ -#if canImport(SwiftUI) - -protocol SizePreferenceKey: PreferenceKey where Value == CGSize {} - -extension SizePreferenceKey { - static var defaultValue: CGSize { .zero } - - static func reduce(value: inout CGSize, nextValue: () -> CGSize) { - let next = nextValue() - guard next != .zero && next != value else { - return - } - value = next - } -} - -extension SwiftUI.View { - func size(in key: Key.Type) -> some SwiftUI.View { - background( - GeometryReader { geometry in - SwiftUI.Color.clear.preference(key: Key.self, value: geometry.size) - } - ) - } -} - -#endif diff --git a/Sources/Presenter/Configuration/Configuration+Plugin.swift b/Sources/Presenter/Configuration/Configuration+Plugin.swift index ad53eb6..a61c709 100644 --- a/Sources/Presenter/Configuration/Configuration+Plugin.swift +++ b/Sources/Presenter/Configuration/Configuration+Plugin.swift @@ -32,7 +32,7 @@ extension Presenter { } } -extension View where Self: Codable { +extension View where Self: Decodable { fileprivate static func use() { Presenter.use(view: Self.self) } diff --git a/Sources/TracePresenter/Exports.swift b/Sources/TracePresenter/Exports.swift deleted file mode 100644 index 605e2ec..0000000 --- a/Sources/TracePresenter/Exports.swift +++ /dev/null @@ -1 +0,0 @@ -@_exported import Presenter diff --git a/Sources/TracePresenter/TraceGraph.swift b/Sources/TracePresenter/TraceGraph.swift deleted file mode 100644 index c7598a6..0000000 --- a/Sources/TracePresenter/TraceGraph.swift +++ /dev/null @@ -1,83 +0,0 @@ -public struct TraceGraph: CodableView { - // MARK: Stored Properties - - public var spans: [Span] - - // MARK: Initialization - - public init?(spans: [Span]) { - let children = Dictionary(grouping: spans) { $0.parentService ?? "_" } - .mapValues { Dictionary(grouping: $0) { $0.parentOperation ?? "_" } } - - guard let rootSpan = spans.first(where: { $0.parentService == nil }) else { - return nil - } - - self.spans = [rootSpan] - var currentIndex = 0 - - while currentIndex < self.spans.count { - let currentSpan = spans[currentIndex] - if let spanChildren = children[currentSpan.service]?[currentSpan.operation] { - self.spans.append(contentsOf: spanChildren.sorted { $0.start < $1.start }) - } - currentIndex += 1 - } - } -} - -extension TraceGraph { - public struct Span: Codable { - public let service: String - public let operation: String - - public let start: CGFloat - public let end: CGFloat - - public let parentService: String? - public let parentOperation: String? - - public init(service: String, - operation: String, - start: CGFloat, - end: CGFloat, - parentService: String?, - parentOperation: String? ) { - self.service = service - self.operation = operation - self.start = start - self.end = end - self.parentService = parentService - self.parentOperation = parentOperation - } - } -} - -#if canImport(SwiftUI) - -extension TraceGraph: SwiftUI.View { - public var body: some SwiftUI.View { - SwiftUI.VStack { - SwiftUI.ForEach(spans.indices) { index in - SpanRow(span: spans[index]) - .frame(height: 8) - } - } - } - - private struct SpanRow: SwiftUI.View { - let span: Span - - var body: some SwiftUI.View { - GeometryReader { geometry in - SwiftUI.Capsule() - .frame(width: (span.end - span.start) * geometry.size.width, - height: geometry.size.width, - alignment: .leading) - .offset(x: span.start) - } - } - } -} - -#endif diff --git a/Sources/TracePresenter/TracePresenter.swift b/Sources/TracePresenter/TracePresenter.swift deleted file mode 100644 index ddfb17e..0000000 --- a/Sources/TracePresenter/TracePresenter.swift +++ /dev/null @@ -1,9 +0,0 @@ -public struct TracePresenter: Plugin { - public init() {} - - public var views: [CodableView.Type] { - [ - TraceGraph.self - ] - } -} diff --git a/Tests/PresenterTests/TracePresenterTests.swift b/Tests/PresenterTests/TracePresenterTests.swift index 46d5fb7..ced7387 100644 --- a/Tests/PresenterTests/TracePresenterTests.swift +++ b/Tests/PresenterTests/TracePresenterTests.swift @@ -1,4 +1,4 @@ -#if !os(watchOS) && canImport(XCTest) && canImport(UIKit) +#if !os(watchOS) && canImport(XCTest) && canImport(UIKit) && canImport(TracePresenter) import XCTest import Presenter From 9bbf2c7aabd37d09ef681b35d66982c8ecb66943 Mon Sep 17 00:00:00 2001 From: Paul Kraft Date: Sun, 5 Dec 2021 18:37:35 +0100 Subject: [PATCH 08/10] Add ChartPresenter back --- Package.swift | 44 ++++------ Sources/ChartPresenter/Chart+AreaStyle.swift | 14 +++ Sources/ChartPresenter/Chart+Charts.swift | 83 ++++++++++++++++++ .../ChartPresenter/Chart+ColumnStyle.swift | 14 +++ Sources/ChartPresenter/Chart+LineStyle.swift | 21 +++++ .../Chart+StackedAreaStyle.swift | 14 +++ Sources/ChartPresenter/Chart+Style.swift | 86 +++++++++++++++++++ Sources/ChartPresenter/Chart.swift | 53 ++++++++++++ Sources/ChartPresenter/ChartPresenter.swift | 12 +++ Sources/ChartPresenter/Exports.swift | 6 ++ 10 files changed, 318 insertions(+), 29 deletions(-) create mode 100644 Sources/ChartPresenter/Chart+AreaStyle.swift create mode 100644 Sources/ChartPresenter/Chart+Charts.swift create mode 100644 Sources/ChartPresenter/Chart+ColumnStyle.swift create mode 100644 Sources/ChartPresenter/Chart+LineStyle.swift create mode 100644 Sources/ChartPresenter/Chart+StackedAreaStyle.swift create mode 100644 Sources/ChartPresenter/Chart+Style.swift create mode 100644 Sources/ChartPresenter/Chart.swift create mode 100644 Sources/ChartPresenter/ChartPresenter.swift create mode 100644 Sources/ChartPresenter/Exports.swift diff --git a/Package.swift b/Package.swift index aa42b24..c9beeae 100644 --- a/Package.swift +++ b/Package.swift @@ -1,9 +1,7 @@ -// swift-tools-version:5.4 +// swift-tools-version:5.5 import PackageDescription -#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) - let package = Package( name: "Presenter", platforms: [.iOS(.v13), .macOS(.v10_15), .tvOS(.v13), .watchOS(.v6)], @@ -11,42 +9,30 @@ let package = Package( .library( name: "Presenter", targets: ["Presenter"]), + .library( + name: "ChartPresenter", + targets: ["ChartPresenter"]), .executable( name: "Example", - targets: ["Example"]) + targets: ["Example"]), + ], + dependencies: [ + .package(url: "https://github.com/spacenation/swiftui-charts", from: "1.0.0"), ], targets: [ .target( name: "Presenter", dependencies: []), + .target( + name: "ChartPresenter", + dependencies: [ + .product(name: "Charts", package: "swiftui-charts"), + .target(name: "Presenter"), + ]), .executableTarget( name: "Example", dependencies: ["Presenter"]), .testTarget( name: "PresenterTests", dependencies: ["Presenter"]), - ] -) - -#else - -let package = Package( - name: "Presenter", - platforms: [.iOS(.v13), .macOS(.v10_15), .tvOS(.v13), .watchOS(.v6)], - products: [ - .library( - name: "Presenter", - targets: ["Presenter"]), - ], - dependencies: [], - targets: [ - .target( - name: "Presenter", - dependencies: []), - .testTarget( - name: "PresenterTests", - dependencies: ["Presenter"]), - ] -) - -#endif + ]) diff --git a/Sources/ChartPresenter/Chart+AreaStyle.swift b/Sources/ChartPresenter/Chart+AreaStyle.swift new file mode 100644 index 0000000..40bb640 --- /dev/null +++ b/Sources/ChartPresenter/Chart+AreaStyle.swift @@ -0,0 +1,14 @@ + +extension Chart { + + public struct AreaStyle: Codable { + public internal(set) var lineType: LineType + public internal(set) var fill: CoderView + + public init(_ lineType: LineType, fill: Fill) { + self.lineType = lineType + self.fill = CoderView(fill) + } + } + +} diff --git a/Sources/ChartPresenter/Chart+Charts.swift b/Sources/ChartPresenter/Chart+Charts.swift new file mode 100644 index 0000000..f039ecc --- /dev/null +++ b/Sources/ChartPresenter/Chart+Charts.swift @@ -0,0 +1,83 @@ + +#if canImport(Charts) + +extension Chart.Style { + + func chart(for data: [[Double]]) -> AnyView { + switch self { + case let .line(style): + return chart(data: data, style: style.chartsValue) + case let .area(style): + return chart(data: data, style: style.chartsValue) + case let .stackedArea(style): + return chart(data: data, style: style.chartsValue) + case let .column(style): + return chart(data: data, style: style.chartsValue) + } + } + + private func chart(data: [[Double]], style: Style) -> AnyView { + Charts.Chart(data: data) + .chartStyle(style) + .eraseToAnyView() + } + +} + +extension Chart.ColumnStyle { + + fileprivate var chartsValue: ColumnChartStyle { + .init(column: column.eraseToAnyView(), spacing: spacing) + } + +} + +extension Chart.StackedAreaStyle { + + fileprivate var chartsValue: StackedAreaChartStyle { + .init(lineType.chartsValue, colors: colors.map { $0.color.body }) + } + +} + + +extension Chart.AreaStyle { + + fileprivate var chartsValue: AreaChartStyle { + .init(lineType.chartsValue, fill: fill.eraseToAnyView()) + } + +} + +extension Chart.LineStyle { + + fileprivate var chartsValue: LineChartStyle { + .init(lineType.chartsValue, + lineColor: color.color.body, + lineWidth: width) + } + +} + +extension Chart.LineType { + + fileprivate var chartsValue: Charts.LineType { + switch self { + case .line: + return .line + case .quadCurve: + return .quadCurve + } + } + +} + +extension SwiftUI.View { + + fileprivate func eraseToAnyView() -> AnyView { + AnyView(self) + } + +} + +#endif diff --git a/Sources/ChartPresenter/Chart+ColumnStyle.swift b/Sources/ChartPresenter/Chart+ColumnStyle.swift new file mode 100644 index 0000000..002216b --- /dev/null +++ b/Sources/ChartPresenter/Chart+ColumnStyle.swift @@ -0,0 +1,14 @@ + +extension Chart { + + public struct ColumnStyle: Codable { + public internal(set) var column: CoderView + public internal(set) var spacing: CGFloat + + public init(column: Column, spacing: CGFloat) { + self.column = CoderView(column) + self.spacing = spacing + } + } + +} diff --git a/Sources/ChartPresenter/Chart+LineStyle.swift b/Sources/ChartPresenter/Chart+LineStyle.swift new file mode 100644 index 0000000..cfbd24e --- /dev/null +++ b/Sources/ChartPresenter/Chart+LineStyle.swift @@ -0,0 +1,21 @@ + +extension Chart { + + public struct LineStyle: Codable { + public internal(set) var lineType: LineType + public internal(set) var color: ColorCode + public internal(set) var width: CGFloat + + public init(_ lineType: LineType, color: Color, width: CGFloat) { + self.lineType = lineType + self.color = ColorCode(color) + self.width = width + } + } + + public enum LineType: String, Codable { + case line + case quadCurve + } + +} diff --git a/Sources/ChartPresenter/Chart+StackedAreaStyle.swift b/Sources/ChartPresenter/Chart+StackedAreaStyle.swift new file mode 100644 index 0000000..e0cb673 --- /dev/null +++ b/Sources/ChartPresenter/Chart+StackedAreaStyle.swift @@ -0,0 +1,14 @@ + +extension Chart { + + public struct StackedAreaStyle: Codable { + public internal(set) var lineType: LineType + public internal(set) var colors: [ColorCode] + + public init(_ lineType: LineType, colors: [Color]) { + self.lineType = lineType + self.colors = colors.map(ColorCode.init) + } + } + +} diff --git a/Sources/ChartPresenter/Chart+Style.swift b/Sources/ChartPresenter/Chart+Style.swift new file mode 100644 index 0000000..519b491 --- /dev/null +++ b/Sources/ChartPresenter/Chart+Style.swift @@ -0,0 +1,86 @@ + +extension Chart { + + public enum Style: Codable { + + // MARK: Nested Types + + private enum CodingKeys: String, CodingKey { + case type + } + + // MARK: Cases + + case line(LineStyle) + case area(AreaStyle) + case stackedArea(StackedAreaStyle) + case column(ColumnStyle) + + // MARK: Computed Properties + + private var kind: StyleKind { + switch self { + case .line: + return .line + case .area: + return .area + case .column: + return .column + case .stackedArea: + return .stackedArea + } + } + + // MARK: Initialization + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + let type = try container.decode(String.self, forKey: .type) + guard let kind = StyleKind(rawValue: type) else { + throw DecodingError + .keyNotFound( + CodingKeys.type, + .init(codingPath: decoder.codingPath, + debugDescription: "Could not find chart style \(type).") + ) + } + switch kind { + case .line: + self = .line(try LineStyle(from: decoder)) + case .area: + self = .area(try AreaStyle(from: decoder)) + case .column: + self = .column(try ColumnStyle(from: decoder)) + case .stackedArea: + self = .stackedArea(try StackedAreaStyle(from: decoder)) + } + } + + // MARK: Methods + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(kind, forKey: .type) + + switch self { + case let .line(style): + try style.encode(to: encoder) + case let .area(style): + try style.encode(to: encoder) + case let .stackedArea(style): + try style.encode(to: encoder) + case let .column(style): + try style.encode(to: encoder) + } + } + + } + + private enum StyleKind: String, Codable { + case line + case area + case stackedArea + case column + } + +} diff --git a/Sources/ChartPresenter/Chart.swift b/Sources/ChartPresenter/Chart.swift new file mode 100644 index 0000000..3d1840b --- /dev/null +++ b/Sources/ChartPresenter/Chart.swift @@ -0,0 +1,53 @@ + +public struct Chart: SwiftUIView { + + // MARK: Stored Properties + + public let data: [[Double]] + public let style: Style + + // MARK: Initialization + + public init(data: [Double], style: Style) { + self.data = data.map { [$0] } + self.style = style + } + + public init(data: [[Double]], style: Style) { + self.data = data + self.style = style + } + +} + +// MARK: - CustomStringConvertible + +extension Chart: CustomStringConvertible { + + public var description: String { + "Chart(data: \(data), style: \(style))" + } + +} + +#if canImport(Charts) + +extension Chart: SwiftUI.View { + + public var body: some SwiftUI.View { + style.chart(for: data) + } + +} + +#elseif canImport(SwiftUI) + +extension Chart { + + public var view: some SwiftUI.View { + EmptyView() + } + +} + +#endif diff --git a/Sources/ChartPresenter/ChartPresenter.swift b/Sources/ChartPresenter/ChartPresenter.swift new file mode 100644 index 0000000..ed9f9e1 --- /dev/null +++ b/Sources/ChartPresenter/ChartPresenter.swift @@ -0,0 +1,12 @@ + +public struct ChartPresenter: Plugin { + + public init() {} + + public var views: [_CodableView.Type] { + [ + Chart.self, + ] + } + +} diff --git a/Sources/ChartPresenter/Exports.swift b/Sources/ChartPresenter/Exports.swift new file mode 100644 index 0000000..8c42ccd --- /dev/null +++ b/Sources/ChartPresenter/Exports.swift @@ -0,0 +1,6 @@ + +@_exported import Presenter + +#if canImport(Charts) +@_exported import Charts +#endif From 3c6b7d6bd50f0f7d935718320d8d71b159cb823a Mon Sep 17 00:00:00 2001 From: Paul Kraft Date: Sun, 5 Dec 2021 18:38:39 +0100 Subject: [PATCH 09/10] Add ChartPresenter condition --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index c9beeae..fbbd625 100644 --- a/Package.swift +++ b/Package.swift @@ -26,7 +26,7 @@ let package = Package( .target( name: "ChartPresenter", dependencies: [ - .product(name: "Charts", package: "swiftui-charts"), + .product(name: "Charts", package: "swiftui-charts", condition: .when(platforms: [.macOS, .macCatalyst, .iOS, .watchOS, .tvOS])), .target(name: "Presenter"), ]), .executableTarget( From fcbea6b4b6882cdaf7a7623022226618af6b3625 Mon Sep 17 00:00:00 2001 From: Paul Kraft Date: Sun, 5 Dec 2021 18:49:18 +0100 Subject: [PATCH 10/10] Fix ChartPresenter --- Sources/ChartPresenter/Chart.swift | 6 +++--- Sources/ChartPresenter/ChartPresenter.swift | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/ChartPresenter/Chart.swift b/Sources/ChartPresenter/Chart.swift index 3d1840b..6164d54 100644 --- a/Sources/ChartPresenter/Chart.swift +++ b/Sources/ChartPresenter/Chart.swift @@ -1,5 +1,5 @@ -public struct Chart: SwiftUIView { +public struct Chart: View { // MARK: Stored Properties @@ -42,9 +42,9 @@ extension Chart: SwiftUI.View { #elseif canImport(SwiftUI) -extension Chart { +extension Chart: SwiftUI.View { - public var view: some SwiftUI.View { + public var body: some SwiftUI.View { EmptyView() } diff --git a/Sources/ChartPresenter/ChartPresenter.swift b/Sources/ChartPresenter/ChartPresenter.swift index ed9f9e1..1441419 100644 --- a/Sources/ChartPresenter/ChartPresenter.swift +++ b/Sources/ChartPresenter/ChartPresenter.swift @@ -3,7 +3,7 @@ public struct ChartPresenter: Plugin { public init() {} - public var views: [_CodableView.Type] { + public var views: [View.Type] { [ Chart.self, ]