From 7ad8e6cd762a84cbb57c6e79d3eea15de6450dbb Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Sat, 27 Aug 2022 21:25:25 -0600 Subject: [PATCH 1/3] [fix-212] - Add UIKit views to play with in sample app and fix #212 - TT --- .../SwiftUIExample/TestViews/TestView.swift | 193 ++++++++++++++++++ .../Views/ViewControllerWrapper.swift | 41 ++-- 2 files changed, 222 insertions(+), 12 deletions(-) diff --git a/ExampleApps/SwiftUIExample/SwiftUIExample/TestViews/TestView.swift b/ExampleApps/SwiftUIExample/SwiftUIExample/TestViews/TestView.swift index 54731b7c4..7028cd618 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExample/TestViews/TestView.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExample/TestViews/TestView.swift @@ -8,6 +8,7 @@ import SwiftUI import SwiftCurrent_SwiftUI +import SwiftCurrent_UIKit struct TestView: View { var body: some View { @@ -206,3 +207,195 @@ struct FR4: View, FlowRepresentable { return shouldLoad } } + +final class FRUI1: UIWorkflowItem, FlowRepresentable { + private lazy var text: UITextField = { + let textField = UITextField() + textField.text = "This is: \(String(describing: Self.self))" + textField.translatesAutoresizingMaskIntoConstraints = false + return textField + }() + + private lazy var navigateForwardButton: UIButton = { + let button = UIButton(primaryAction: UIAction(title: "Navigate foward", handler: { [self] _ in + proceedInWorkflow() + })) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + private lazy var navigateBackwardButton: UIButton = { + let button = UIButton(primaryAction: UIAction(title: "Navigate backward", handler: { [self] _ in + try? backUpInWorkflow() + })) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .systemBackground + + view.addSubview(text) + view.addSubview(navigateForwardButton) + view.addSubview(navigateBackwardButton) + + NSLayoutConstraint.activate([ + text.centerXAnchor.constraint(equalTo: view.centerXAnchor), + text.centerYAnchor.constraint(equalTo: view.centerYAnchor), + text.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + text.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + navigateForwardButton.topAnchor.constraint(equalTo: text.bottomAnchor, constant: 10), + navigateForwardButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + navigateForwardButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + navigateBackwardButton.topAnchor.constraint(equalTo: navigateForwardButton.bottomAnchor, constant: 10), + navigateBackwardButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + navigateBackwardButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + ]) + } +} + +final class FRUI2: UIWorkflowItem, FlowRepresentable { + private lazy var text: UITextField = { + let textField = UITextField() + textField.text = "This is: \(String(describing: Self.self))" + textField.translatesAutoresizingMaskIntoConstraints = false + return textField + }() + + private lazy var navigateForwardButton: UIButton = { + let button = UIButton(primaryAction: UIAction(title: "Navigate foward", handler: { [self] _ in + proceedInWorkflow() + })) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + private lazy var navigateBackwardButton: UIButton = { + let button = UIButton(primaryAction: UIAction(title: "Navigate backward", handler: { [self] _ in + try? backUpInWorkflow() + })) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .systemBackground + + view.addSubview(text) + view.addSubview(navigateForwardButton) + view.addSubview(navigateBackwardButton) + + NSLayoutConstraint.activate([ + text.centerXAnchor.constraint(equalTo: view.centerXAnchor), + text.centerYAnchor.constraint(equalTo: view.centerYAnchor), + text.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + text.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + navigateForwardButton.topAnchor.constraint(equalTo: text.bottomAnchor, constant: 10), + navigateForwardButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + navigateForwardButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + navigateBackwardButton.topAnchor.constraint(equalTo: navigateForwardButton.bottomAnchor, constant: 10), + navigateBackwardButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + navigateBackwardButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + ]) + } +} + +final class FRUI3: UIWorkflowItem, FlowRepresentable { + private lazy var text: UITextField = { + let textField = UITextField() + textField.text = "This is: \(String(describing: Self.self))" + textField.translatesAutoresizingMaskIntoConstraints = false + return textField + }() + + private lazy var navigateForwardButton: UIButton = { + let button = UIButton(primaryAction: UIAction(title: "Navigate foward", handler: { [self] _ in + proceedInWorkflow() + })) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + private lazy var navigateBackwardButton: UIButton = { + let button = UIButton(primaryAction: UIAction(title: "Navigate backward", handler: { [self] _ in + try? backUpInWorkflow() + })) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .systemBackground + + view.addSubview(text) + view.addSubview(navigateForwardButton) + view.addSubview(navigateBackwardButton) + + NSLayoutConstraint.activate([ + text.centerXAnchor.constraint(equalTo: view.centerXAnchor), + text.centerYAnchor.constraint(equalTo: view.centerYAnchor), + text.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + text.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + navigateForwardButton.topAnchor.constraint(equalTo: text.bottomAnchor, constant: 10), + navigateForwardButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + navigateForwardButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + navigateBackwardButton.topAnchor.constraint(equalTo: navigateForwardButton.bottomAnchor, constant: 10), + navigateBackwardButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + navigateBackwardButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + ]) + } +} + +final class FRUI4: UIWorkflowItem, FlowRepresentable { + private lazy var text: UITextField = { + let textField = UITextField() + textField.text = "This is: \(String(describing: Self.self))" + textField.translatesAutoresizingMaskIntoConstraints = false + return textField + }() + + private lazy var navigateForwardButton: UIButton = { + let button = UIButton(primaryAction: UIAction(title: "Navigate foward", handler: { [self] _ in + proceedInWorkflow() + })) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + private lazy var navigateBackwardButton: UIButton = { + let button = UIButton(primaryAction: UIAction(title: "Navigate backward", handler: { [self] _ in + try? backUpInWorkflow() + })) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .systemBackground + + view.addSubview(text) + view.addSubview(navigateForwardButton) + view.addSubview(navigateBackwardButton) + + NSLayoutConstraint.activate([ + text.centerXAnchor.constraint(equalTo: view.centerXAnchor), + text.centerYAnchor.constraint(equalTo: view.centerYAnchor), + text.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + text.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + navigateForwardButton.topAnchor.constraint(equalTo: text.bottomAnchor, constant: 10), + navigateForwardButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + navigateForwardButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + navigateBackwardButton.topAnchor.constraint(equalTo: navigateForwardButton.bottomAnchor, constant: 10), + navigateBackwardButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + navigateBackwardButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + ]) + } +} diff --git a/Sources/SwiftCurrent_SwiftUI/Views/ViewControllerWrapper.swift b/Sources/SwiftCurrent_SwiftUI/Views/ViewControllerWrapper.swift index fc5a2fcbb..cb9fb4f66 100644 --- a/Sources/SwiftCurrent_SwiftUI/Views/ViewControllerWrapper.swift +++ b/Sources/SwiftCurrent_SwiftUI/Views/ViewControllerWrapper.swift @@ -18,28 +18,45 @@ public struct ViewControllerWrapper: Vi public typealias WorkflowInput = F.WorkflowInput public typealias WorkflowOutput = F.WorkflowOutput - public weak var _workflowPointer: AnyFlowRepresentable? { - didSet { - vc._workflowPointer = _workflowPointer - } - } + public weak var _workflowPointer: AnyFlowRepresentable? private var vc: F - private let args: WorkflowInput? + + @StateObject private var model: Model + public init(with args: F.WorkflowInput) { - self.args = args - vc = F._factory(F.self, with: args) + let vc = F._factory(F.self, with: args) + self.vc = vc + _model = StateObject(wrappedValue: Model(vc: vc)) } public init() { - args = nil - vc = F._factory(F.self) + let vc = F._factory(F.self) + self.vc = vc + _model = StateObject(wrappedValue: Model(vc: vc)) } - public func makeUIViewController(context: Context) -> F { vc } + public func makeUIViewController(context: Context) -> F { + model.vc._workflowPointer = _workflowPointer + return model.vc + } - public func updateUIViewController(_ uiViewController: F, context: Context) { } + public func updateUIViewController(_ uiViewController: F, context: Context) { + model.vc._workflowPointer = _workflowPointer + } public func shouldLoad() -> Bool { vc.shouldLoad() } } + +@available(iOS 14.0, macOS 11, tvOS 14.0, *) +extension ViewControllerWrapper { + @available(iOS 14.0, macOS 11, tvOS 14.0, *) + final class Model: ObservableObject { + var vc: F + + init(vc: F) { + self.vc = vc + } + } +} #endif From e228160a10bcc4c2b8d3a988253c4496eacbc921 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Sat, 27 Aug 2022 21:39:40 -0600 Subject: [PATCH 2/3] [fix-212] - Fix linker issue with UI tests - TT --- .../SwiftUIExample.xcodeproj/project.pbxproj | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ExampleApps/SwiftUIExample/SwiftUIExample.xcodeproj/project.pbxproj b/ExampleApps/SwiftUIExample/SwiftUIExample.xcodeproj/project.pbxproj index 2988d1589..d6b0965d4 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExample.xcodeproj/project.pbxproj +++ b/ExampleApps/SwiftUIExample/SwiftUIExample.xcodeproj/project.pbxproj @@ -34,6 +34,7 @@ CA84D8E726A0E72A006CF964 /* MapFeatureViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA84D8E626A0E72A006CF964 /* MapFeatureViewTests.swift */; }; CA84D8E926A0ED66006CF964 /* ChangePasswordViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA84D8E826A0ED66006CF964 /* ChangePasswordViewTests.swift */; }; CA971D2226D593150083821A /* XCTestCaseExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA971D2126D593150083821A /* XCTestCaseExtensions.swift */; }; + CAA4DE0228BB1A740059324B /* SwiftCurrent_UIKit in Frameworks */ = {isa = PBXBuildFile; productRef = CAA4DE0128BB1A740059324B /* SwiftCurrent_UIKit */; }; CABEC41726E13BC900F1BF53 /* TestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7A6CE7D26E039C300599824 /* TestView.swift */; }; CABEC41926E1899000F1BF53 /* SwiftCurrent_SwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = CABEC41826E1899000F1BF53 /* SwiftCurrent_SwiftUI */; }; CABEC41B26E1899000F1BF53 /* SwiftCurrent in Frameworks */ = {isa = PBXBuildFile; productRef = CABEC41A26E1899000F1BF53 /* SwiftCurrent */; }; @@ -227,6 +228,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + CAA4DE0228BB1A740059324B /* SwiftCurrent_UIKit in Frameworks */, CABEC41B26E1899000F1BF53 /* SwiftCurrent in Frameworks */, CABEC41926E1899000F1BF53 /* SwiftCurrent_SwiftUI in Frameworks */, ); @@ -587,6 +589,7 @@ packageProductDependencies = ( CABEC41826E1899000F1BF53 /* SwiftCurrent_SwiftUI */, CABEC41A26E1899000F1BF53 /* SwiftCurrent */, + CAA4DE0128BB1A740059324B /* SwiftCurrent_UIKit */, ); productName = SwiftCurrent_SwiftUI_UITests; productReference = D7A6CE7226E0316C00599824 /* SwiftCurrent_SwiftUI_UITests.xctest */; @@ -1111,6 +1114,10 @@ package = CA6FB0E526C6ADCD00FB3285 /* XCRemoteSwiftPackageReference "UIUTest" */; productName = UIUTest; }; + CAA4DE0128BB1A740059324B /* SwiftCurrent_UIKit */ = { + isa = XCSwiftPackageProductDependency; + productName = SwiftCurrent_UIKit; + }; CABEC41826E1899000F1BF53 /* SwiftCurrent_SwiftUI */ = { isa = XCSwiftPackageProductDependency; productName = SwiftCurrent_SwiftUI; From 2f547e0b894b86739a0573b8e96cf2532e4df9d5 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Sat, 27 Aug 2022 22:08:38 -0600 Subject: [PATCH 3/3] [fix-212] - Set up workflow pointer on both references - TT --- .../SwiftCurrent_SwiftUI/Views/ViewControllerWrapper.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sources/SwiftCurrent_SwiftUI/Views/ViewControllerWrapper.swift b/Sources/SwiftCurrent_SwiftUI/Views/ViewControllerWrapper.swift index cb9fb4f66..3ba7bd774 100644 --- a/Sources/SwiftCurrent_SwiftUI/Views/ViewControllerWrapper.swift +++ b/Sources/SwiftCurrent_SwiftUI/Views/ViewControllerWrapper.swift @@ -18,7 +18,11 @@ public struct ViewControllerWrapper: Vi public typealias WorkflowInput = F.WorkflowInput public typealias WorkflowOutput = F.WorkflowOutput - public weak var _workflowPointer: AnyFlowRepresentable? + public weak var _workflowPointer: AnyFlowRepresentable? { + didSet { + vc._workflowPointer = _workflowPointer + } + } private var vc: F