[Experiment] Move `Send` routing into a parent `SendView`
This is to demonstrate having something like a 'Coordinator' that handles the routing logic of the feature. It is done as a seperate commit to compare against the original implementation that has the routing logic encoded explicitely in each view.
This commit is contained in:
parent
a8fc8d79f7
commit
780dd0fafa
|
@ -103,6 +103,7 @@
|
|||
F9C165C22740403600592F76 /* CreateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9C165BB2740403600592F76 /* CreateView.swift */; };
|
||||
F9C165C42740403600592F76 /* SentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9C165BD2740403600592F76 /* SentView.swift */; };
|
||||
F9EEB8162742C2210032EEB8 /* WithStateBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9EEB8152742C2210032EEB8 /* WithStateBinding.swift */; };
|
||||
F9C165CB2741AB5D00592F76 /* SendView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9C165CA2741AB5D00592F76 /* SendView.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
@ -224,6 +225,7 @@
|
|||
F9C165BB2740403600592F76 /* CreateView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateView.swift; sourceTree = "<group>"; };
|
||||
F9C165BD2740403600592F76 /* SentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SentView.swift; sourceTree = "<group>"; };
|
||||
F9EEB8152742C2210032EEB8 /* WithStateBinding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WithStateBinding.swift; sourceTree = "<group>"; };
|
||||
F9C165CA2741AB5D00592F76 /* SendView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendView.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -720,6 +722,7 @@
|
|||
F9C165B82740403600592F76 /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F9C165CA2741AB5D00592F76 /* SendView.swift */,
|
||||
F9C165BB2740403600592F76 /* CreateView.swift */,
|
||||
F9C165B92740403600592F76 /* ApproveView.swift */,
|
||||
F9C165BD2740403600592F76 /* SentView.swift */,
|
||||
|
@ -994,6 +997,7 @@
|
|||
0DA13CA226C1955600E3B610 /* HomeScreenViewModel.swift in Sources */,
|
||||
0D32282926C586E000262533 /* RequestZcashScreenViewModel.swift in Sources */,
|
||||
0D32281926C5864B00262533 /* ProfileScreen.swift in Sources */,
|
||||
F9C165CB2741AB5D00592F76 /* SendView.swift in Sources */,
|
||||
6654C7412715A47300901167 /* Onboarding.swift in Sources */,
|
||||
0D32282426C586A800262533 /* HistoryScreenViewModel.swift in Sources */,
|
||||
F9C165C42740403600592F76 /* SentView.swift in Sources */,
|
||||
|
|
|
@ -46,7 +46,7 @@ struct HomeView: View {
|
|||
.navigationLinkEmpty(
|
||||
isActive: viewStore.showSendBinding,
|
||||
destination: {
|
||||
Create(
|
||||
SendView(
|
||||
store: .init(
|
||||
initialState: .init(
|
||||
transaction: .demo,
|
||||
|
|
|
@ -3,12 +3,12 @@ import ComposableArchitecture
|
|||
|
||||
struct SendState: Equatable {
|
||||
var transaction: Transaction
|
||||
var route: Create.Route?
|
||||
var route: SendView.Route?
|
||||
}
|
||||
|
||||
enum SendAction: Equatable {
|
||||
case updateTransaction(Transaction)
|
||||
case updateRoute(Create.Route?)
|
||||
case updateRoute(SendView.Route?)
|
||||
}
|
||||
|
||||
// Mark: - SendReducer
|
||||
|
@ -32,7 +32,7 @@ extension SendReducer {
|
|||
static func `default`(whenDone: @escaping () -> Void) -> SendReducer {
|
||||
SendReducer { state, action, _ in
|
||||
switch action {
|
||||
case let .updateRoute(route) where route == .showApprove(route: .showSent(route: .done)):
|
||||
case let .updateRoute(route) where route == .done:
|
||||
return Effect.fireAndForget(whenDone)
|
||||
default:
|
||||
return Self.default.run(&state, action, ())
|
||||
|
@ -58,11 +58,32 @@ extension SendViewStore {
|
|||
)
|
||||
}
|
||||
|
||||
var routeBinding: Binding<Create.Route?> {
|
||||
var routeBinding: Binding<SendView.Route?> {
|
||||
self.binding(
|
||||
get: \.route,
|
||||
send: SendAction.updateRoute
|
||||
)
|
||||
}
|
||||
|
||||
var bindingForApprove: Binding<Bool> {
|
||||
self.routeBinding.map(
|
||||
extract: { $0 == .showApprove || self.bindingForSent.wrappedValue },
|
||||
embed: { $0 ? SendView.Route.showApprove : nil }
|
||||
)
|
||||
}
|
||||
|
||||
var bindingForSent: Binding<Bool> {
|
||||
self.routeBinding.map(
|
||||
extract: { $0 == .showSent || self.bindingForDone.wrappedValue },
|
||||
embed: { $0 ? SendView.Route.showSent : SendView.Route.showApprove }
|
||||
)
|
||||
}
|
||||
|
||||
var bindingForDone: Binding<Bool> {
|
||||
self.routeBinding.map(
|
||||
extract: { $0 == .done },
|
||||
embed: { $0 ? SendView.Route.done : SendView.Route.showSent }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,17 +2,13 @@ import SwiftUI
|
|||
import ComposableArchitecture
|
||||
|
||||
struct Approve: View {
|
||||
enum Route: Equatable {
|
||||
case showSent(route: Sent.Route?)
|
||||
}
|
||||
|
||||
let transaction: Transaction
|
||||
@Binding var route: Route?
|
||||
@Binding var isComplete: Bool
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Button(
|
||||
action: { route = .showSent(route: nil) },
|
||||
action: { isComplete = true },
|
||||
label: { Text("Go to sent") }
|
||||
)
|
||||
.primaryButtonStyle
|
||||
|
@ -20,42 +16,21 @@ struct Approve: View {
|
|||
.padding()
|
||||
|
||||
Text("\(String(dumping: transaction))")
|
||||
Text("\(String(dumping: route))")
|
||||
Text("\(String(dumping: isComplete))")
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.navigationTitle(Text("2. Approve"))
|
||||
.navigationLinkEmpty(
|
||||
isActive: $route.map(
|
||||
extract: {
|
||||
if case .showSent = $0 {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
embed: { $0 ? .showSent(route: (/Route.showSent).extract(from: route)) : nil }
|
||||
),
|
||||
destination: {
|
||||
Sent(
|
||||
transaction: transaction,
|
||||
route: $route.map(
|
||||
extract: /Route.showSent,
|
||||
embed: Route.showSent
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct Approve_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationView {
|
||||
StateContainer(initialState: (Transaction.demo, Approve.Route?.none)) {
|
||||
StateContainer(initialState: (Transaction.demo, false)) {
|
||||
Approve(
|
||||
transaction: $0.0.wrappedValue,
|
||||
route: $0.1
|
||||
isComplete: $0.1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,63 +2,42 @@ import SwiftUI
|
|||
import ComposableArchitecture
|
||||
|
||||
struct Create: View {
|
||||
enum Route: Equatable {
|
||||
case showApprove(route: Approve.Route?)
|
||||
}
|
||||
|
||||
let store: Store<SendState, SendAction>
|
||||
@Binding var transaction: Transaction
|
||||
@Binding var isComplete: Bool
|
||||
|
||||
var body: some View {
|
||||
WithViewStore(store) { viewStore in
|
||||
VStack {
|
||||
Button(
|
||||
action: { viewStore.send(.updateRoute(.showApprove(route: nil))) },
|
||||
label: { Text("Go To Approve") }
|
||||
)
|
||||
.primaryButtonStyle
|
||||
.frame(height: 50)
|
||||
.padding()
|
||||
|
||||
TextField(
|
||||
"Amount",
|
||||
text: viewStore
|
||||
.bindingForTransaction
|
||||
.amount
|
||||
.compactMap(
|
||||
extract: String.init,
|
||||
embed: UInt.init
|
||||
)
|
||||
)
|
||||
.padding()
|
||||
|
||||
TextField(
|
||||
"Address",
|
||||
text: viewStore.bindingForTransaction.toAddress
|
||||
)
|
||||
|
||||
Text("\(String(dumping: viewStore.transaction))")
|
||||
Text("\(String(dumping: viewStore.route))")
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
.navigationTitle(Text("1. Create"))
|
||||
.navigationLinkEmpty(
|
||||
isActive: viewStore.routeBinding.map(
|
||||
extract: { $0.map(/Route.showApprove) != nil },
|
||||
embed: { $0 ? .showApprove(route: (/Route.showApprove).extract(from: viewStore.route)) : nil }
|
||||
),
|
||||
destination: {
|
||||
Approve(
|
||||
transaction: viewStore.transaction,
|
||||
route: viewStore.routeBinding.map(
|
||||
extract: /Route.showApprove,
|
||||
embed: Route.showApprove
|
||||
)
|
||||
)
|
||||
}
|
||||
VStack {
|
||||
Button(
|
||||
action: { isComplete = true },
|
||||
label: { Text("Go To Approve") }
|
||||
)
|
||||
.primaryButtonStyle
|
||||
.frame(height: 50)
|
||||
.padding()
|
||||
|
||||
TextField(
|
||||
"Amount",
|
||||
text: $transaction
|
||||
.amount
|
||||
.compactMap(
|
||||
extract: String.init,
|
||||
embed: UInt.init
|
||||
)
|
||||
)
|
||||
.padding()
|
||||
|
||||
TextField(
|
||||
"Address",
|
||||
text: $transaction.toAddress
|
||||
)
|
||||
|
||||
Text("\(String(dumping: transaction))")
|
||||
Text("\(String(dumping: isComplete))")
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
.navigationTitle(Text("1. Create"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,7 +46,12 @@ struct Create: View {
|
|||
struct Create_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationView {
|
||||
Create(store: .demo)
|
||||
StateContainer(initialState: (Transaction.demo, false)) {
|
||||
Create(
|
||||
transaction: $0.0,
|
||||
isComplete: $0.1
|
||||
)
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import SwiftUI
|
||||
import ComposableArchitecture
|
||||
|
||||
struct SendView: View {
|
||||
enum Route: Equatable {
|
||||
case showApprove
|
||||
case showSent
|
||||
case done
|
||||
}
|
||||
|
||||
let store: Store<SendState, SendAction>
|
||||
|
||||
var body: some View {
|
||||
WithViewStore(store) { viewStore in
|
||||
Create(
|
||||
transaction: viewStore.bindingForTransaction,
|
||||
isComplete: viewStore.bindingForApprove
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: viewStore.bindingForApprove,
|
||||
destination: {
|
||||
Approve(
|
||||
transaction: viewStore.transaction,
|
||||
isComplete: viewStore.bindingForSent
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: viewStore.bindingForSent,
|
||||
destination: {
|
||||
Sent(
|
||||
transaction: viewStore.transaction,
|
||||
isComplete: viewStore.bindingForDone
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SendView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationView {
|
||||
SendView(
|
||||
store: .init(
|
||||
initialState: .init(
|
||||
transaction: .demo,
|
||||
route: nil
|
||||
),
|
||||
reducer: .default,
|
||||
environment: ()
|
||||
)
|
||||
)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationViewStyle(StackNavigationViewStyle())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,17 +2,14 @@ import SwiftUI
|
|||
import ComposableArchitecture
|
||||
|
||||
struct Sent: View {
|
||||
enum Route {
|
||||
case done
|
||||
}
|
||||
@State var transaction: Transaction
|
||||
@Binding var route: Route?
|
||||
var transaction: Transaction
|
||||
@Binding var isComplete: Bool
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Button(
|
||||
action: {
|
||||
route = .done
|
||||
isComplete = true
|
||||
},
|
||||
label: { Text("Done") }
|
||||
)
|
||||
|
@ -22,7 +19,7 @@ struct Sent: View {
|
|||
|
||||
|
||||
Text("\(String(dumping: transaction))")
|
||||
Text("\(String(dumping: route))")
|
||||
Text("\(String(dumping: isComplete))")
|
||||
|
||||
Spacer()
|
||||
}
|
||||
|
@ -32,6 +29,6 @@ struct Sent: View {
|
|||
|
||||
struct Done_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Sent(transaction: .demo, route: .constant(nil))
|
||||
Sent(transaction: .demo, isComplete: .constant(false))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue