Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[fix-204] - Fixes #204 - TT #205

Merged
merged 3 commits into from Jun 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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