Skip to content

Commit

Permalink
Merge pull request #205 from wwt/fix-204
Browse files Browse the repository at this point in the history
[fix-204] - Fixes #204 - TT
  • Loading branch information
Tyler-Keith-Thompson committed Jun 12, 2022
2 parents b4d4a09 + e516ddc commit 5618a23
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 304 deletions.
Expand Up @@ -48,6 +48,7 @@ public struct WorkflowItemWrapper<WI: _WorkflowItemProtocol, Wrapped: _WorkflowI
.onReceive(model.$body, perform: activateIfNeeded)
.onReceive(model.$body, perform: proceedInWorkflow)
.onReceive(model.onBackUpPublisher, perform: backUpInWorkflow)
.onReceive(model.onAbandonPublisher) { isActive = false }
.onReceive(inspection.notice) { inspection.visit(self, $0) }
}

Expand Down
28 changes: 12 additions & 16 deletions Sources/SwiftCurrent_SwiftUI/Views/WorkflowLauncher.swift
Expand Up @@ -14,7 +14,7 @@ import SwiftCurrent
public struct WorkflowLauncher<Content: _WorkflowItemProtocol>: View {
public typealias WorkflowInput = Content.FlowRepresentableType.WorkflowInput

@State private var content: Content
@WorkflowBuilder private var content: Content
@State private var onFinish = [(AnyWorkflow.PassedArgs) -> Void]()
@State private var onAbandon = [() -> Void]()
@State private var shouldEmbedInNavView = false
Expand Down Expand Up @@ -49,32 +49,28 @@ public struct WorkflowLauncher<Content: _WorkflowItemProtocol>: View {
.onReceive(inspection.notice) { inspection.visit(self, $0) }
}

init(isLaunched: Binding<Bool>, startingArgs: AnyWorkflow.PassedArgs, content: () -> Content) {
self.init(isLaunched: isLaunched, startingArgs: startingArgs, content: content())
init(isLaunched: Binding<Bool>, startingArgs: AnyWorkflow.PassedArgs, @WorkflowBuilder content: () -> Content) {
_isLaunched = isLaunched
let wf = AnyWorkflow.empty
content().modify(workflow: wf)
let model = WorkflowViewModel(isLaunched: isLaunched, launchArgs: startingArgs)
_model = StateObject(wrappedValue: model)
_launcher = StateObject(wrappedValue: Launcher(workflow: wf,
responder: model,
launchArgs: startingArgs))
self.content = content()
}

private init(current: Self, shouldEmbedInNavView: Bool, onFinish: [(AnyWorkflow.PassedArgs) -> Void], onAbandon: [() -> Void]) {
_model = current._model
_launcher = current._launcher
_content = current._content
content = current.content
_isLaunched = current._isLaunched
_shouldEmbedInNavView = State(initialValue: shouldEmbedInNavView)
_onFinish = State(initialValue: onFinish)
_onAbandon = State(initialValue: onAbandon)
}

private init(isLaunched: Binding<Bool>, startingArgs: AnyWorkflow.PassedArgs, content: Content) {
_isLaunched = isLaunched
let wf = AnyWorkflow.empty
content.modify(workflow: wf)
let model = WorkflowViewModel(isLaunched: isLaunched, launchArgs: startingArgs)
_model = StateObject(wrappedValue: model)
_launcher = StateObject(wrappedValue: Launcher(workflow: wf,
responder: model,
launchArgs: startingArgs))
_content = State(wrappedValue: content)
}

private func resetWorkflow() {
launcher.workflow.launch(withOrchestrationResponder: model, passedArgs: launcher.launchArgs)
}
Expand Down
24 changes: 13 additions & 11 deletions Sources/SwiftCurrent_SwiftUI/Views/WorkflowView.swift
Expand Up @@ -78,7 +78,7 @@ public struct WorkflowView<Content: View>: View {
*/
public init<WI: _WorkflowItemProtocol>(isLaunched: Binding<Bool> = .constant(true),
@WorkflowBuilder content: () -> WI) where Content == WorkflowLauncher<WI>, WI.FlowRepresentableType.WorkflowInput == Never {
self.init(isLaunched: isLaunched, startingArgs: .none, content: content())
self.init(isLaunched: isLaunched, startingArgs: .none, content: content)
}

/**
Expand All @@ -90,7 +90,7 @@ public struct WorkflowView<Content: View>: View {
public init<WI: _WorkflowItemProtocol>(isLaunched: Binding<Bool> = .constant(true),
launchingWith args: WI.FlowRepresentableType.WorkflowInput,
@WorkflowBuilder content: () -> WI) where Content == WorkflowLauncher<WI> {
self.init(isLaunched: isLaunched, startingArgs: .args(args), content: content())
self.init(isLaunched: isLaunched, startingArgs: .args(args), content: content)
}

/**
Expand All @@ -102,7 +102,7 @@ public struct WorkflowView<Content: View>: View {
public init<WI: _WorkflowItemProtocol>(isLaunched: Binding<Bool> = .constant(true),
launchingWith args: AnyWorkflow.PassedArgs,
@WorkflowBuilder content: () -> WI) where Content == WorkflowLauncher<WI>, WI.FlowRepresentableType.WorkflowInput == AnyWorkflow.PassedArgs {
self.init(isLaunched: isLaunched, startingArgs: args, content: content())
self.init(isLaunched: isLaunched, startingArgs: args, content: content)
}

/**
Expand All @@ -114,7 +114,7 @@ public struct WorkflowView<Content: View>: View {
public init<WI: _WorkflowItemProtocol>(isLaunched: Binding<Bool> = .constant(true),
launchingWith args: AnyWorkflow.PassedArgs,
@WorkflowBuilder content: () -> WI) where Content == WorkflowLauncher<WI> {
self.init(isLaunched: isLaunched, startingArgs: args, content: content())
self.init(isLaunched: isLaunched, startingArgs: args, content: content)
}

/**
Expand All @@ -126,7 +126,7 @@ public struct WorkflowView<Content: View>: View {
public init<A, WI: _WorkflowItemProtocol>(isLaunched: Binding<Bool> = .constant(true),
launchingWith args: A,
@WorkflowBuilder content: () -> WI) where Content == WorkflowLauncher<WI>, WI.FlowRepresentableType.WorkflowInput == AnyWorkflow.PassedArgs {
self.init(isLaunched: isLaunched, startingArgs: .args(args), content: content())
self.init(isLaunched: isLaunched, startingArgs: .args(args), content: content)
}

/**
Expand All @@ -138,7 +138,7 @@ public struct WorkflowView<Content: View>: View {
public init<A, WI: _WorkflowItemProtocol>(isLaunched: Binding<Bool> = .constant(true),
launchingWith args: A,
@WorkflowBuilder content: () -> WI) where Content == WorkflowLauncher<WI>, WI.FlowRepresentableType.WorkflowInput == Never {
self.init(isLaunched: isLaunched, startingArgs: .args(args), content: content())
self.init(isLaunched: isLaunched, startingArgs: .args(args), content: content)
}

/**
Expand All @@ -148,7 +148,7 @@ public struct WorkflowView<Content: View>: View {
*/
public init<WI: _WorkflowItemProtocol>(isLaunched: Binding<Bool> = .constant(true),
@WorkflowBuilder content: () -> WI) where Content == WorkflowLauncher<WI>, WI.FlowRepresentableType.WorkflowInput == AnyWorkflow.PassedArgs {
self.init(isLaunched: isLaunched, startingArgs: .none, content: content())
self.init(isLaunched: isLaunched, startingArgs: .none, content: content)
}

/**
Expand All @@ -157,7 +157,9 @@ public struct WorkflowView<Content: View>: View {
- Parameter startingArgs: arguments passed to the first loaded `FlowRepresentable` in the underlying `Workflow`.
- Parameter workflow: workflow to be launched; must contain `FlowRepresentable`s of type `View`
*/
public init(isLaunched: Binding<Bool> = .constant(true), launchingWith startingArgs: AnyWorkflow.PassedArgs = .none, workflow: AnyWorkflow) where Content == WorkflowLauncher<AnyWorkflowItem> {
public init(isLaunched: Binding<Bool> = .constant(true),
launchingWith startingArgs: AnyWorkflow.PassedArgs = .none,
workflow: AnyWorkflow) where Content == WorkflowLauncher<WorkflowItemWrapper<AnyWorkflowItem, Never>> {
workflow.forEach {
assert($0.value.metadata is ExtendedFlowRepresentableMetadata, "It is possible the workflow was constructed incorrectly. This represents an internal error, please file a bug at https://github.com/wwt/SwiftCurrent/issues") // swiftlint:disable:this line_length
}
Expand All @@ -171,7 +173,7 @@ public struct WorkflowView<Content: View>: View {
- Parameter startingArgs: arguments passed to the first loaded `FlowRepresentable` in the underlying `Workflow`.
- Parameter workflow: workflow to be launched; must contain `FlowRepresentable`s of type `View`
*/
public init<A>(isLaunched: Binding<Bool> = .constant(true), launchingWith startingArgs: A, workflow: AnyWorkflow) where Content == WorkflowLauncher<AnyWorkflowItem> {
public init<A>(isLaunched: Binding<Bool> = .constant(true), launchingWith startingArgs: A, workflow: AnyWorkflow) where Content == WorkflowLauncher<WorkflowItemWrapper<AnyWorkflowItem, Never>> {
workflow.forEach {
assert($0.value.metadata is ExtendedFlowRepresentableMetadata, "It is possible the workflow was constructed incorrectly. This represents an internal error, please file a bug at https://github.com/wwt/SwiftCurrent/issues") // swiftlint:disable:this line_length
}
Expand All @@ -181,8 +183,8 @@ public struct WorkflowView<Content: View>: View {

private init<WI: _WorkflowItemProtocol>(isLaunched: Binding<Bool>,
startingArgs: AnyWorkflow.PassedArgs,
content: WI) where Content == WorkflowLauncher<WI> {
_content = State(wrappedValue: WorkflowLauncher(isLaunched: isLaunched, startingArgs: startingArgs) { content })
@WorkflowBuilder content: () -> WI) where Content == WorkflowLauncher<WI> {
_content = State(wrappedValue: WorkflowLauncher(isLaunched: isLaunched, startingArgs: startingArgs, content: content))
}

private init<WI: _WorkflowItemProtocol>(_ other: WorkflowView<Content>,
Expand Down
Expand Up @@ -57,7 +57,7 @@
},
{
"package": "swift-algorithms",
"repositoryURL": "https://github.com/apple/swift-algorithms",
"repositoryURL": "https://github.com/apple/swift-algorithms.git",
"state": {
"branch": null,
"revision": "b14b7f4c528c942f121c8b860b9410b2bf57825e",
Expand Down Expand Up @@ -87,8 +87,8 @@
"repositoryURL": "https://github.com/apple/swift-syntax.git",
"state": {
"branch": null,
"revision": "75e60475d9d8fd5bbc16a12e0eaa2cb01b0c322e",
"version": "0.50500.0"
"revision": "0b6c22b97f8e9320bca62e82cdbee601cf37ad3f",
"version": "0.50600.1"
}
},
{
Expand Down
Expand Up @@ -33,6 +33,7 @@ final class SwiftCurrent_NavigationLinkTests: XCTestCase, View {
.onFinish { _ in
expectOnFinish.fulfill()
}
.embedInNavigationView()
}
.hostAndInspect(with: \.inspection)
.extractWorkflowLauncher()
Expand Down Expand Up @@ -71,6 +72,7 @@ final class SwiftCurrent_NavigationLinkTests: XCTestCase, View {
.onFinish { _ in
expectOnFinish.fulfill()
}
.embedInNavigationView()
}
.hostAndInspect(with: \.inspection)
.extractWorkflowLauncher()
Expand Down Expand Up @@ -109,6 +111,7 @@ final class SwiftCurrent_NavigationLinkTests: XCTestCase, View {
.onFinish { _ in
expectOnFinish.fulfill()
}
.embedInNavigationView()
}
.hostAndInspect(with: \.inspection)
.extractWorkflowLauncher()
Expand Down Expand Up @@ -152,6 +155,7 @@ final class SwiftCurrent_NavigationLinkTests: XCTestCase, View {
.onFinish { _ in
expectOnFinish.fulfill()
}
.embedInNavigationView()
}
.hostAndInspect(with: \.inspection)
.extractWorkflowLauncher()
Expand Down Expand Up @@ -196,6 +200,7 @@ final class SwiftCurrent_NavigationLinkTests: XCTestCase, View {
.onFinish { _ in
expectOnFinish.fulfill()
}
.embedInNavigationView()
}
.hostAndInspect(with: \.inspection)
.extractWorkflowLauncher()
Expand Down Expand Up @@ -240,6 +245,7 @@ final class SwiftCurrent_NavigationLinkTests: XCTestCase, View {
.onFinish { _ in
expectOnFinish.fulfill()
}
.embedInNavigationView()
}
.hostAndInspect(with: \.inspection)
.extractWorkflowLauncher()
Expand Down Expand Up @@ -269,7 +275,7 @@ final class SwiftCurrent_NavigationLinkTests: XCTestCase, View {
WorkflowItem(FR1.self).presentationType(.navigationLink)
WorkflowItem(FR1.self).presentationType(.navigationLink)
WorkflowItem(FR1.self)
}
}.embedInNavigationView()
}
.hostAndInspect(with: \.inspection)
.extractWorkflowLauncher()
Expand Down Expand Up @@ -337,7 +343,7 @@ final class SwiftCurrent_NavigationLinkTests: XCTestCase, View {
WorkflowItem(FR5.self).presentationType(.navigationLink)
WorkflowItem(FR6.self).presentationType(.navigationLink)
WorkflowItem(FR7.self).presentationType(.navigationLink)
}
}.embedInNavigationView()
}
.hostAndInspect(with: \.inspection)
.extractWorkflowLauncher()
Expand All @@ -364,6 +370,49 @@ final class SwiftCurrent_NavigationLinkTests: XCTestCase, View {
try await wfr7.find(FR7.self).proceedInWorkflow()
}

func testWorkflowCanBeAbandoned() async throws {
struct FR1: View, FlowRepresentable, Inspectable {
var _workflowPointer: AnyFlowRepresentable?
var body: some View { Text("FR1 type") }
}
struct FR2: View, FlowRepresentable, Inspectable {
var _workflowPointer: AnyFlowRepresentable?
var body: some View { Text("FR2 type") }
}
struct FR3: View, FlowRepresentable, Inspectable {
var _workflowPointer: AnyFlowRepresentable?
var body: some View {
Button("continue") {
workflow?.abandon()
}
}
}

let wfr1 = try await MainActor.run {
WorkflowView {
WorkflowItem(FR1.self).presentationType(.navigationLink)
WorkflowItem(FR2.self).presentationType(.navigationLink)
WorkflowItem(FR3.self).presentationType(.navigationLink)
}.embedInNavigationView()
}
.hostAndInspect(with: \.inspection)
.extractWorkflowLauncher()
.extractWorkflowItemWrapper()

try await wfr1.proceedAndCheckNavLink(on: FR1.self)

let wfr2 = try await wfr1.extractWrappedWrapper()
try await wfr2.proceedAndCheckNavLink(on: FR2.self)

let wfr3 = try await wfr2.extractWrappedWrapper()
XCTAssertNoThrow(try wfr3.find(button: "continue").tap())

XCTAssertNoThrow(try wfr1.find(FR1.self))
XCTAssertEqual(try wfr1.find(ViewType.NavigationLink.self).isActive(), false)
XCTAssertThrowsError(try wfr2.find(FR2.self))
XCTAssertThrowsError(try wfr3.find(FR3.self))
}

func testNavLinkWorkflowsCanSkipTheFirstItem() async throws {
struct FR1: View, FlowRepresentable, Inspectable {
var _workflowPointer: AnyFlowRepresentable?
Expand All @@ -384,6 +433,7 @@ final class SwiftCurrent_NavigationLinkTests: XCTestCase, View {
WorkflowItem(FR2.self).presentationType(.navigationLink)
WorkflowItem(FR3.self)
}
.embedInNavigationView()
}
.hostAndInspect(with: \.inspection)
.extractWorkflowLauncher()
Expand Down Expand Up @@ -418,6 +468,7 @@ final class SwiftCurrent_NavigationLinkTests: XCTestCase, View {
WorkflowItem(FR2.self).presentationType(.navigationLink)
WorkflowItem(FR3.self)
}
.embedInNavigationView()
}
.hostAndInspect(with: \.inspection)
.extractWorkflowLauncher()
Expand Down Expand Up @@ -458,6 +509,7 @@ final class SwiftCurrent_NavigationLinkTests: XCTestCase, View {
WorkflowItem(FR3.self)
WorkflowItem(FR4.self)
}
.embedInNavigationView()
}
.hostAndInspect(with: \.inspection)
.extractWorkflowLauncher()
Expand Down Expand Up @@ -500,6 +552,7 @@ final class SwiftCurrent_NavigationLinkTests: XCTestCase, View {
.onFinish { _ in
expectOnFinish.fulfill()
}
.embedInNavigationView()
}
.hostAndInspect(with: \.inspection)
.extractWorkflowLauncher()
Expand Down

0 comments on commit 5618a23

Please sign in to comment.