debugging the navigation
code cleanup I reimplemented preamble screen so it's not "a feature" but it's a simple view with the set of bindings
This commit is contained in:
parent
28c7cf98b5
commit
d3e0f4f1e5
|
@ -82,6 +82,9 @@
|
|||
66A0807B271993C500118B79 /* OnboardingProgressIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66A0807A271993C500118B79 /* OnboardingProgressIndicator.swift */; };
|
||||
66D50668271D9B6100E51F0D /* NavigationButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D50667271D9B6100E51F0D /* NavigationButtonStyle.swift */; };
|
||||
66DC733F271D88CC0053CBB6 /* StandardButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66DC733E271D88CC0053CBB6 /* StandardButtonStyle.swift */; };
|
||||
9E2DF99C27CF704D00649636 /* ImportWalletStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2DF99827CF704D00649636 /* ImportWalletStore.swift */; };
|
||||
9E2DF99D27CF704D00649636 /* ImportSeedEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2DF99A27CF704D00649636 /* ImportSeedEditor.swift */; };
|
||||
9E2DF99E27CF704D00649636 /* ImportWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2DF99B27CF704D00649636 /* ImportWalletView.swift */; };
|
||||
9E37A2B827C8F59F00AE57B3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9E37A2B727C8F59F00AE57B3 /* Localizable.strings */; };
|
||||
9E4DC6E027C409A100E657F4 /* NeumorphicDesignModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E4DC6DF27C409A100E657F4 /* NeumorphicDesignModifier.swift */; };
|
||||
9E4DC6E227C4C6B700E657F4 /* SecantButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E4DC6E127C4C6B700E657F4 /* SecantButtonStyles.swift */; };
|
||||
|
@ -213,6 +216,9 @@
|
|||
66A0807A271993C500118B79 /* OnboardingProgressIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingProgressIndicator.swift; sourceTree = "<group>"; };
|
||||
66D50667271D9B6100E51F0D /* NavigationButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationButtonStyle.swift; sourceTree = "<group>"; };
|
||||
66DC733E271D88CC0053CBB6 /* StandardButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandardButtonStyle.swift; sourceTree = "<group>"; };
|
||||
9E2DF99827CF704D00649636 /* ImportWalletStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportWalletStore.swift; sourceTree = "<group>"; };
|
||||
9E2DF99A27CF704D00649636 /* ImportSeedEditor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportSeedEditor.swift; sourceTree = "<group>"; };
|
||||
9E2DF99B27CF704D00649636 /* ImportWalletView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportWalletView.swift; sourceTree = "<group>"; };
|
||||
9E37A2B727C8F59F00AE57B3 /* Localizable.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
9E4DC6DF27C409A100E657F4 /* NeumorphicDesignModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NeumorphicDesignModifier.swift; sourceTree = "<group>"; };
|
||||
9E4DC6E127C4C6B700E657F4 /* SecantButtonStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecantButtonStyles.swift; sourceTree = "<group>"; };
|
||||
|
@ -593,6 +599,7 @@
|
|||
0D3D04052728B2D70032ABC1 /* BackupFlow */,
|
||||
6654C73C2715A3FA00901167 /* Onboarding */,
|
||||
F9971A6727680E1000A2DB75 /* WalletInfo */,
|
||||
9E2DF99727CF704D00649636 /* ImportWallet */,
|
||||
);
|
||||
path = Features;
|
||||
sourceTree = "<group>";
|
||||
|
@ -648,6 +655,24 @@
|
|||
path = CircularFrame;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E2DF99727CF704D00649636 /* ImportWallet */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E2DF99827CF704D00649636 /* ImportWalletStore.swift */,
|
||||
9E2DF99927CF704D00649636 /* Views */,
|
||||
);
|
||||
path = ImportWallet;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E2DF99927CF704D00649636 /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E2DF99A27CF704D00649636 /* ImportSeedEditor.swift */,
|
||||
9E2DF99B27CF704D00649636 /* ImportWalletView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9EBEF87827CE365D00B4F343 /* Preamble */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1024,6 +1049,7 @@
|
|||
9E4DC6E027C409A100E657F4 /* NeumorphicDesignModifier.swift in Sources */,
|
||||
0DACFA7F27208CE00039EEA5 /* Clamped.swift in Sources */,
|
||||
0DFE93E3272CA1AA000FCCA5 /* RecoveryPhraseValidation.swift in Sources */,
|
||||
9E2DF99E27CF704D00649636 /* ImportWalletView.swift in Sources */,
|
||||
0D354A0B26D5A9D000315F45 /* MnemonicSeedPhraseHandling.swift in Sources */,
|
||||
0D535FE2271F9476009A9E3E /* EnumeratedChip.swift in Sources */,
|
||||
6654C73E2715A41300901167 /* OnboardingStore.swift in Sources */,
|
||||
|
@ -1031,6 +1057,7 @@
|
|||
9E4DC6E227C4C6B700E657F4 /* SecantButtonStyles.swift in Sources */,
|
||||
0DDB6A5127737D4A0012A410 /* ValidationFailedView.swift in Sources */,
|
||||
0D6D628B276A528E002FB4CC /* DropDelegate.swift in Sources */,
|
||||
9E2DF99D27CF704D00649636 /* ImportSeedEditor.swift in Sources */,
|
||||
F9971A5327680DD000A2DB75 /* Profile.swift in Sources */,
|
||||
F93874F0273C4DE200F0E875 /* HomeStore.swift in Sources */,
|
||||
669FDAEB272C23C2007B9422 /* CircularFrameBadge.swift in Sources */,
|
||||
|
@ -1078,6 +1105,7 @@
|
|||
0D7DF08C271DCC0E00530046 /* ScreenBackground.swift in Sources */,
|
||||
F9C165C22740403600592F76 /* CreateView.swift in Sources */,
|
||||
F9C165B4274031F600592F76 /* Bindings.swift in Sources */,
|
||||
9E2DF99C27CF704D00649636 /* ImportWalletStore.swift in Sources */,
|
||||
F9971A6627680DFE00A2DB75 /* SettingsView.swift in Sources */,
|
||||
F96B41EB273B50520021B49A /* Strings.swift in Sources */,
|
||||
0D354A0A26D5A9D000315F45 /* KeyStoring.swift in Sources */,
|
||||
|
|
|
@ -37,10 +37,11 @@ extension AppReducer {
|
|||
routeReducer,
|
||||
homeReducer,
|
||||
onboardingReducer,
|
||||
phraseValidationReducer.debug(),
|
||||
phraseDisplayReducer.debug()
|
||||
phraseValidationReducer,
|
||||
phraseDisplayReducer
|
||||
]
|
||||
)
|
||||
.debug()
|
||||
|
||||
private static let routeReducer = AppReducer { state, action, _ in
|
||||
switch action {
|
||||
|
|
|
@ -38,8 +38,6 @@ struct AppView: View {
|
|||
|
||||
case .phraseValidation:
|
||||
NavigationView {
|
||||
// RecoveryPhraseTestPreambleView
|
||||
// RecoveryPhraseBackupValidationView
|
||||
RecoveryPhraseTestPreambleView(
|
||||
store: store.scope(
|
||||
state: \.phraseValidationState,
|
||||
|
|
|
@ -55,7 +55,7 @@ struct RecoveryPhraseTestPreambleView: View {
|
|||
}
|
||||
|
||||
Button(
|
||||
action: { viewStore.send(.recoveryBackupPhraseValidation) },
|
||||
action: { viewStore.send(.updateRoute(.validation)) },
|
||||
label: { Text("recoveryPhraseTestPreamble.button.goNext") }
|
||||
)
|
||||
.activeButtonStyle
|
||||
|
@ -75,8 +75,10 @@ struct RecoveryPhraseTestPreambleView: View {
|
|||
.frame(width: proxy.size.width)
|
||||
.scrollableWhenScaledUp()
|
||||
.navigationLinkEmpty(
|
||||
isActive: viewStore.bindingForRoute(.recoveryBackupPhraseValidation),
|
||||
destination: { RecoveryPhraseBackupValidationView(store: store) }
|
||||
isActive: viewStore.bindingForValidation,
|
||||
destination: {
|
||||
RecoveryPhraseBackupValidationView(store: store)
|
||||
}
|
||||
)
|
||||
}
|
||||
.padding()
|
||||
|
@ -105,7 +107,9 @@ extension RecoveryPhraseTestPreambleView {
|
|||
struct RecoveryPhraseTestPreambleView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
RecoveryPhraseTestPreambleView(store: .demo)
|
||||
NavigationView {
|
||||
RecoveryPhraseTestPreambleView(store: .demo)
|
||||
}
|
||||
|
||||
RecoveryPhraseTestPreambleView(store: .demo)
|
||||
.preferredColorScheme(.dark)
|
||||
|
|
|
@ -19,9 +19,11 @@ struct ValidationWord: Equatable {
|
|||
var word: String
|
||||
}
|
||||
|
||||
// MARK: - State
|
||||
|
||||
struct RecoveryPhraseValidationState: Equatable {
|
||||
enum Route: Equatable, CaseIterable {
|
||||
case recoveryBackupPhraseValidation
|
||||
case validation
|
||||
case success
|
||||
case failure
|
||||
}
|
||||
|
@ -45,17 +47,6 @@ struct RecoveryPhraseValidationState: Equatable {
|
|||
}
|
||||
}
|
||||
|
||||
extension RecoveryPhraseValidationViewStore {
|
||||
func bindingForRoute(_ route: RecoveryPhraseValidationState.Route) -> Binding<Bool> {
|
||||
self.binding(
|
||||
get: { $0.route == route },
|
||||
send: { isActive in
|
||||
return .updateRoute(isActive ? route : nil)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension RecoveryPhraseValidationState {
|
||||
/// creates an initial `RecoveryPhraseValidationState` with no completions and random missing indices.
|
||||
/// - Note: Use this function to create a random validation puzzle for a given phrase.
|
||||
|
@ -128,8 +119,9 @@ extension RecoveryPhrase.Group {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - Action
|
||||
|
||||
enum RecoveryPhraseValidationAction: Equatable {
|
||||
case recoveryBackupPhraseValidation
|
||||
case updateRoute(RecoveryPhraseValidationState.Route?)
|
||||
case reset
|
||||
case move(wordChip: PhraseChip.Kind, intoGroup: Int)
|
||||
|
@ -140,6 +132,8 @@ enum RecoveryPhraseValidationAction: Equatable {
|
|||
case displayBackedUpPhrase
|
||||
}
|
||||
|
||||
// MARK: - Reducer
|
||||
|
||||
typealias RecoveryPhraseValidationReducer = Reducer<RecoveryPhraseValidationState, RecoveryPhraseValidationAction, BackupPhraseEnvironment>
|
||||
|
||||
extension RecoveryPhraseValidationReducer {
|
||||
|
@ -147,6 +141,7 @@ extension RecoveryPhraseValidationReducer {
|
|||
switch action {
|
||||
case .reset:
|
||||
state = RecoveryPhraseValidationState.random(phrase: state.phrase)
|
||||
state.route = .validation
|
||||
|
||||
case let .move(wordChip, group):
|
||||
guard
|
||||
|
@ -162,7 +157,7 @@ extension RecoveryPhraseValidationReducer {
|
|||
let effect = Effect<RecoveryPhraseValidationAction, Never>(value: value)
|
||||
.delay(for: 1, scheduler: environment.mainQueue)
|
||||
.eraseToEffect()
|
||||
|
||||
|
||||
if value == .succeed {
|
||||
return effect
|
||||
} else {
|
||||
|
@ -184,6 +179,10 @@ extension RecoveryPhraseValidationReducer {
|
|||
environment.feedbackGenerator.generateFeedback()
|
||||
|
||||
case .updateRoute(let route):
|
||||
guard let route = route else {
|
||||
state = RecoveryPhraseValidationState.random(phrase: state.phrase)
|
||||
return .none
|
||||
}
|
||||
state.route = route
|
||||
|
||||
case .proceedToHome:
|
||||
|
@ -191,10 +190,49 @@ extension RecoveryPhraseValidationReducer {
|
|||
|
||||
case .displayBackedUpPhrase:
|
||||
break
|
||||
|
||||
case .recoveryBackupPhraseValidation:
|
||||
state.route = .recoveryBackupPhraseValidation
|
||||
}
|
||||
return .none
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ViewStore
|
||||
|
||||
extension RecoveryPhraseValidationViewStore {
|
||||
func bindingForRoute(_ route: RecoveryPhraseValidationState.Route) -> Binding<Bool> {
|
||||
self.binding(
|
||||
get: { $0.route == route },
|
||||
send: { isActive in
|
||||
return .updateRoute(isActive ? route : nil)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension RecoveryPhraseValidationViewStore {
|
||||
var bindingForValidation: Binding<Bool> {
|
||||
self.binding(
|
||||
get: { $0.route != nil },
|
||||
send: { isActive in
|
||||
return .updateRoute(isActive ? .validation : nil)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
var bindingForSuccess: Binding<Bool> {
|
||||
self.binding(
|
||||
get: { $0.route == .success },
|
||||
send: { isActive in
|
||||
return .updateRoute(isActive ? .success : .validation)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
var bindingForFailure: Binding<Bool> {
|
||||
self.binding(
|
||||
get: { $0.route == .failure },
|
||||
send: { isActive in
|
||||
return .updateRoute(isActive ? .failure : .validation)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,28 +11,31 @@ import ComposableArchitecture
|
|||
struct RecoveryPhraseBackupValidationView: View {
|
||||
let store: RecoveryPhraseValidationStore
|
||||
|
||||
var viewStore: RecoveryPhraseValidationViewStore {
|
||||
ViewStore(store)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
WithViewStore(self.store) { viewStore in
|
||||
VStack(alignment: .center) {
|
||||
header(for: viewStore)
|
||||
.padding(.horizontal)
|
||||
.padding(.bottom, 10)
|
||||
|
||||
ZStack {
|
||||
Asset.Colors.BackgroundColors.phraseGridDarkGray.color
|
||||
.edgesIgnoringSafeArea(.bottom)
|
||||
|
||||
VStack(alignment: .center, spacing: 35) {
|
||||
let state = viewStore.state
|
||||
let groups = state.phrase.toGroups()
|
||||
|
||||
ForEach(Array(zip(groups.indices, groups)), id: \.0) { index, group in
|
||||
WordChipGrid(
|
||||
state: state,
|
||||
groupIndex: index,
|
||||
wordGroup: group,
|
||||
misingIndex: index
|
||||
)
|
||||
VStack(alignment: .center) {
|
||||
header(for: viewStore)
|
||||
.padding(.horizontal)
|
||||
.padding(.bottom, 10)
|
||||
|
||||
ZStack {
|
||||
Asset.Colors.BackgroundColors.phraseGridDarkGray.color
|
||||
.edgesIgnoringSafeArea(.bottom)
|
||||
|
||||
VStack(alignment: .center, spacing: 35) {
|
||||
let state = viewStore.state
|
||||
let groups = state.phrase.toGroups()
|
||||
|
||||
ForEach(Array(zip(groups.indices, groups)), id: \.0) { index, group in
|
||||
WordChipGrid(
|
||||
state: state,
|
||||
groupIndex: index,
|
||||
wordGroup: group,
|
||||
misingIndex: index
|
||||
)
|
||||
.frame(alignment: .center)
|
||||
.background(Asset.Colors.BackgroundColors.phraseGridDarkGray.color)
|
||||
.whenIsDroppable(
|
||||
|
@ -41,28 +44,27 @@ struct RecoveryPhraseBackupValidationView: View {
|
|||
viewStore.send(.move(wordChip: chipKind, intoGroup: index))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
.padding(.top, 0)
|
||||
.navigationLinkEmpty(
|
||||
isActive: viewStore.bindingForRoute(.success),
|
||||
destination: { ValidationSucceededView(store: store) }
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: viewStore.bindingForRoute(.failure),
|
||||
destination: { ValidationFailedView(store: store) }
|
||||
)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.frame(alignment: .top)
|
||||
.padding()
|
||||
.padding(.top, 0)
|
||||
.navigationLinkEmpty(
|
||||
isActive: viewStore.bindingForSuccess,
|
||||
destination: { ValidationSucceededView(store: store) }
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: viewStore.bindingForFailure,
|
||||
destination: { ValidationFailedView(store: store) }
|
||||
)
|
||||
}
|
||||
.applyScreenBackground()
|
||||
.scrollableWhenScaledUp()
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationTitle(Text("recoveryPhraseBackupValidation.title"))
|
||||
.frame(alignment: .top)
|
||||
}
|
||||
.applyScreenBackground()
|
||||
.scrollableWhenScaledUp()
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationTitle(Text("recoveryPhraseBackupValidation.title"))
|
||||
}
|
||||
|
||||
@ViewBuilder func header(for viewStore: RecoveryPhraseValidationViewStore) -> some View {
|
||||
|
|
|
@ -41,7 +41,14 @@
|
|||
"validationFailed.description" = "Your placed words did not match your secret recovery phrase.";
|
||||
"validationFailed.incorrectBackupDescription" = "Remember, you can't recover your funds if you lose (or incorrectly save) these 24 words.";
|
||||
"validationFailed.button.tryAgain" = "I'm ready to try again";
|
||||
|
||||
|
||||
// MARK: - Recovery Phrase Test Preamble
|
||||
"recoveryPhraseTestPreamble.title" = "First things first";
|
||||
"recoveryPhraseTestPreamble.paragraph1" = "It is important to understand that you are in charge here. Great, right? YOU get to be the bank!";
|
||||
"recoveryPhraseTestPreamble.paragraph2" = "But it also means that YOU are the customer, and you need to be self-reliant.";
|
||||
"recoveryPhraseTestPreamble.paragraph3" = "So how do you recover funds that you've hidden on a completely decentralized and private block-chain?";
|
||||
"recoveryPhraseTestPreamble.button.goNext" = "By understanding and preparing";
|
||||
|
||||
// MARK: - Import Wallet Screen
|
||||
"importWallet.title" = "Wallet Import";
|
||||
"importWallet.description" = "You can import your backed up wallet by entering your backup recovery phrase (aka seed phrase) now.";
|
||||
|
|
Loading…
Reference in New Issue