-
Notifications
You must be signed in to change notification settings - Fork 47
/
Copy pathRootWorkflow.swift
119 lines (104 loc) · 3.62 KB
/
RootWorkflow.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/*
* Copyright 2023 Square Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import MarketWorkflowUI
import Workflow
import WorkflowUI
struct RootWorkflow: Workflow {
enum Output {
case close
}
struct State {
var backStack: BackStack
var isPresentingModal: Bool
struct BackStack {
let root: Screen
var other: [Screen] = []
}
enum Screen {
case main(id: UUID = UUID())
}
}
func makeInitialState() -> State {
State(
backStack: .init(root: .main()),
isPresentingModal: false
)
}
enum Action: WorkflowAction {
typealias WorkflowType = RootWorkflow
case main(MainWorkflow.Output)
case popScreen
case dismissScreen
func apply(toState state: inout WorkflowType.State) -> WorkflowType.Output? {
switch self {
case .main(.pushScreen):
state.backStack.other.append(.main())
case .main(.presentScreen):
state.isPresentingModal = true
case .main(.close):
return .close
case .popScreen:
state.backStack.other.removeLast()
case .dismissScreen:
state.isPresentingModal = false
}
return nil
}
}
typealias Rendering = ModalContainer<BackStack, AnyScreen>
typealias BackStack = MarketBackStack<AnyMarketBackStackContentScreen>
func render(state: State, context: RenderContext<Self>) -> Rendering {
let sink = context.makeSink(of: Action.self)
func rendering(_ screen: State.Screen, isRoot: Bool) -> AnyMarketBackStackContentScreen {
switch screen {
case .main(let id):
return MainWorkflow(canClose: isRoot)
.mapOutput(Action.main)
.mapRendering(AnyMarketBackStackContentScreen.init)
.rendered(in: context, key: id.uuidString)
}
}
func backStackContent(_ screen: State.Screen, isRoot: Bool) -> BackStack.Content {
rendering(screen, isRoot: isRoot)
.asContent(onPop: { sink.send(.popScreen) })
}
let backStack = MarketBackStack(
root: backStackContent(state.backStack.root, isRoot: true),
other: state.backStack.other.map { backStackContent($0, isRoot: false) }
)
return Rendering(
base: backStack,
modals: {
guard state.isPresentingModal else { return [] }
let screen = RootWorkflow()
.mapOutput { output in
switch output {
case .close:
return Action.dismissScreen
}
}
.rendered(in: context)
.asAnyScreen()
let modal = Modal(
key: "",
style: .full(),
content: screen
)
return [modal]
}()
)
}
}