Merge pull request #123 from zcash/feature/recovery-phrase-display
[Scaffold] Recovery Phrase Display
This commit is contained in:
commit
afdd071341
|
@ -14,6 +14,7 @@
|
|||
0D1922ED26BDE0C600052649 /* AppRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1922EC26BDE0C600052649 /* AppRouter.swift */; };
|
||||
0D1922F226BDE29300052649 /* ZcashSDKStubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1922F126BDE29300052649 /* ZcashSDKStubs.swift */; };
|
||||
0D1922F826BDEB3500052649 /* MockServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1922F726BDEB3500052649 /* MockServices.swift */; };
|
||||
0D1C1AA327611EFD0004AF6A /* RecoveryPhraseDisplayReducerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1C1AA227611EFD0004AF6A /* RecoveryPhraseDisplayReducerTests.swift */; };
|
||||
0D2ACE8026C2C67100D62E3C /* Zboto.otf in Resources */ = {isa = PBXBuildFile; fileRef = 0D2ACE7F26C2C67100D62E3C /* Zboto.otf */; };
|
||||
0D32281926C5864B00262533 /* ProfileScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D32281726C5864B00262533 /* ProfileScreen.swift */; };
|
||||
0D32281A26C5864B00262533 /* ProfileScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D32281826C5864B00262533 /* ProfileScreenViewModel.swift */; };
|
||||
|
@ -30,6 +31,8 @@
|
|||
0D354A0926D5A9D000315F45 /* Services.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D354A0626D5A9D000315F45 /* Services.swift */; };
|
||||
0D354A0A26D5A9D000315F45 /* KeyStoring.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D354A0726D5A9D000315F45 /* KeyStoring.swift */; };
|
||||
0D354A0B26D5A9D000315F45 /* MnemonicSeedPhraseHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D354A0826D5A9D000315F45 /* MnemonicSeedPhraseHandling.swift */; };
|
||||
0D3D04082728B3440032ABC1 /* RecoveryPhraseDisplayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D3D04072728B3440032ABC1 /* RecoveryPhraseDisplayView.swift */; };
|
||||
0D3D040A2728B3A10032ABC1 /* RecoveryPhraseDisplayStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D3D04092728B3A10032ABC1 /* RecoveryPhraseDisplayStore.swift */; };
|
||||
0D4E7A0926B364170058B01E /* SecantApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D4E7A0826B364170058B01E /* SecantApp.swift */; };
|
||||
0D4E7A0B26B364170058B01E /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D4E7A0A26B364170058B01E /* ContentView.swift */; };
|
||||
0D4E7A0D26B364180058B01E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0D4E7A0C26B364180058B01E /* Assets.xcassets */; };
|
||||
|
@ -46,6 +49,8 @@
|
|||
0D864A0A26E154FD00A61879 /* InitFailedScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D864A0826E154FD00A61879 /* InitFailedScreenViewModel.swift */; };
|
||||
0D864A0E26E1583000A61879 /* LoadingScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D864A0C26E1583000A61879 /* LoadingScreen.swift */; };
|
||||
0D864A0F26E1583000A61879 /* LoadingScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D864A0D26E1583000A61879 /* LoadingScreenViewModel.swift */; };
|
||||
0D8A43C4272AEEDE005A6414 /* SecantTextStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D8A43C3272AEEDE005A6414 /* SecantTextStyles.swift */; };
|
||||
0D8A43C6272B129C005A6414 /* WordChipGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D8A43C5272B129C005A6414 /* WordChipGrid.swift */; };
|
||||
0DA13C8F26C15D1D00E3B610 /* WelcomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DA13C8D26C15D1D00E3B610 /* WelcomeScreen.swift */; };
|
||||
0DA13C9026C15D1D00E3B610 /* WelcomeScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DA13C8E26C15D1D00E3B610 /* WelcomeScreenViewModel.swift */; };
|
||||
0DA13C9726C186FF00E3B610 /* RestoreWalletScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DA13C9526C186FF00E3B610 /* RestoreWalletScreen.swift */; };
|
||||
|
@ -72,6 +77,7 @@
|
|||
0DB8AA81271DC7520035BC9D /* DesignGuide.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DB8AA80271DC7520035BC9D /* DesignGuide.swift */; };
|
||||
0DF2DC51272344E400FA31E2 /* EmptyChip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DF2DC50272344E400FA31E2 /* EmptyChip.swift */; };
|
||||
0DF2DC5427235E3E00FA31E2 /* View+InnerShadow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DF2DC5327235E3E00FA31E2 /* View+InnerShadow.swift */; };
|
||||
0DFE93DF272C6D4B000FCCA5 /* RecoveryFlowTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DFE93DE272C6D4B000FCCA5 /* RecoveryFlowTests.swift */; };
|
||||
2E58E73B274679F000B2B84B /* OnboardingHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E58E73A274679F000B2B84B /* OnboardingHeaderView.swift */; };
|
||||
2EA11F5B27467EF800709571 /* OnboardingFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EA11F5A27467EF800709571 /* OnboardingFooterView.swift */; };
|
||||
2EA11F5D27467F7700709571 /* OnboardingContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EA11F5C27467F7700709571 /* OnboardingContentView.swift */; };
|
||||
|
@ -135,6 +141,7 @@
|
|||
0D1922EC26BDE0C600052649 /* AppRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouter.swift; sourceTree = "<group>"; };
|
||||
0D1922F126BDE29300052649 /* ZcashSDKStubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZcashSDKStubs.swift; sourceTree = "<group>"; };
|
||||
0D1922F726BDEB3500052649 /* MockServices.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockServices.swift; sourceTree = "<group>"; };
|
||||
0D1C1AA227611EFD0004AF6A /* RecoveryPhraseDisplayReducerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoveryPhraseDisplayReducerTests.swift; sourceTree = "<group>"; };
|
||||
0D2ACE7F26C2C67100D62E3C /* Zboto.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Zboto.otf; sourceTree = "<group>"; };
|
||||
0D32281726C5864B00262533 /* ProfileScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileScreen.swift; sourceTree = "<group>"; };
|
||||
0D32281826C5864B00262533 /* ProfileScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
|
@ -151,6 +158,8 @@
|
|||
0D354A0626D5A9D000315F45 /* Services.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Services.swift; sourceTree = "<group>"; };
|
||||
0D354A0726D5A9D000315F45 /* KeyStoring.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyStoring.swift; sourceTree = "<group>"; };
|
||||
0D354A0826D5A9D000315F45 /* MnemonicSeedPhraseHandling.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MnemonicSeedPhraseHandling.swift; sourceTree = "<group>"; };
|
||||
0D3D04072728B3440032ABC1 /* RecoveryPhraseDisplayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoveryPhraseDisplayView.swift; sourceTree = "<group>"; };
|
||||
0D3D04092728B3A10032ABC1 /* RecoveryPhraseDisplayStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoveryPhraseDisplayStore.swift; sourceTree = "<group>"; };
|
||||
0D4E7A0526B364170058B01E /* secant-testnet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "secant-testnet.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0D4E7A0826B364170058B01E /* SecantApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecantApp.swift; sourceTree = "<group>"; };
|
||||
0D4E7A0A26B364170058B01E /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
|
@ -173,6 +182,8 @@
|
|||
0D864A0826E154FD00A61879 /* InitFailedScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitFailedScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
0D864A0C26E1583000A61879 /* LoadingScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingScreen.swift; sourceTree = "<group>"; };
|
||||
0D864A0D26E1583000A61879 /* LoadingScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
0D8A43C3272AEEDE005A6414 /* SecantTextStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecantTextStyles.swift; sourceTree = "<group>"; };
|
||||
0D8A43C5272B129C005A6414 /* WordChipGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordChipGrid.swift; sourceTree = "<group>"; };
|
||||
0DA13C8D26C15D1D00E3B610 /* WelcomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeScreen.swift; sourceTree = "<group>"; };
|
||||
0DA13C8E26C15D1D00E3B610 /* WelcomeScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
0DA13C9526C186FF00E3B610 /* RestoreWalletScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestoreWalletScreen.swift; sourceTree = "<group>"; };
|
||||
|
@ -199,6 +210,7 @@
|
|||
0DB8AA80271DC7520035BC9D /* DesignGuide.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DesignGuide.swift; sourceTree = "<group>"; };
|
||||
0DF2DC50272344E400FA31E2 /* EmptyChip.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyChip.swift; sourceTree = "<group>"; };
|
||||
0DF2DC5327235E3E00FA31E2 /* View+InnerShadow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+InnerShadow.swift"; sourceTree = "<group>"; };
|
||||
0DFE93DE272C6D4B000FCCA5 /* RecoveryFlowTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecoveryFlowTests.swift; sourceTree = "<group>"; };
|
||||
2E58E73A274679F000B2B84B /* OnboardingHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingHeaderView.swift; sourceTree = "<group>"; };
|
||||
2E5C03802738C570008BFFD3 /* OnboardingScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingScreen.swift; sourceTree = "<group>"; };
|
||||
2EA11F5A27467EF800709571 /* OnboardingFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingFooterView.swift; sourceTree = "<group>"; };
|
||||
|
@ -271,14 +283,14 @@
|
|||
path = Routers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0D170A7426BC9B7500EB6A46 /* Mocked Dependencies */ = {
|
||||
0D170A7426BC9B7500EB6A46 /* MockedDependencies */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D354A0726D5A9D000315F45 /* KeyStoring.swift */,
|
||||
0D354A0826D5A9D000315F45 /* MnemonicSeedPhraseHandling.swift */,
|
||||
0D354A0626D5A9D000315F45 /* Services.swift */,
|
||||
);
|
||||
path = "Mocked Dependencies";
|
||||
path = MockedDependencies;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0D1922E826BDD95000052649 /* Base */ = {
|
||||
|
@ -383,6 +395,24 @@
|
|||
path = Balance;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0D3D04052728B2D70032ABC1 /* BackupFlow */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D3D04062728B2EC0032ABC1 /* Views */,
|
||||
0D3D04092728B3A10032ABC1 /* RecoveryPhraseDisplayStore.swift */,
|
||||
);
|
||||
path = BackupFlow;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0D3D04062728B2EC0032ABC1 /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D3D04072728B3440032ABC1 /* RecoveryPhraseDisplayView.swift */,
|
||||
0D8A43C5272B129C005A6414 /* WordChipGrid.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0D4E79FC26B364170058B01E = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -410,14 +440,14 @@
|
|||
0DACFA7D27208CC80039EEA5 /* Util */,
|
||||
6654C73B2715A3F000901167 /* Features */,
|
||||
660558F4270C85F7009D6954 /* Generated */,
|
||||
0D5D16F326E24CB900AD33D1 /* App Errors */,
|
||||
0D5D16F326E24CB900AD33D1 /* AppErrors */,
|
||||
0D2ACE7E26C2C65E00D62E3C /* Fonts */,
|
||||
0DA13CA326C1960A00E3B610 /* Models */,
|
||||
0DA13C9126C15E1900E3B610 /* UI Components */,
|
||||
0DA13C9126C15E1900E3B610 /* UIComponents */,
|
||||
0D1922F026BDE27D00052649 /* Stubs */,
|
||||
0D1922EB26BDD9A500052649 /* Screens */,
|
||||
0D1922E826BDD95000052649 /* Base */,
|
||||
0D170A7426BC9B7500EB6A46 /* Mocked Dependencies */,
|
||||
0D170A7426BC9B7500EB6A46 /* MockedDependencies */,
|
||||
0D4E7A0826B364170058B01E /* SecantApp.swift */,
|
||||
0D4E7A0A26B364170058B01E /* ContentView.swift */,
|
||||
0D4E7A0C26B364180058B01E /* Assets.xcassets */,
|
||||
|
@ -440,6 +470,7 @@
|
|||
0D4E7A1926B364180058B01E /* secantTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0DFE93DD272C6D4B000FCCA5 /* BackupFlowTests */,
|
||||
6654C7422715A48E00901167 /* OnboardingTests */,
|
||||
0D4E7A1A26B364180058B01E /* secantTests.swift */,
|
||||
0D4E7A1C26B364180058B01E /* Info.plist */,
|
||||
|
@ -477,12 +508,12 @@
|
|||
path = Chips;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0D5D16F326E24CB900AD33D1 /* App Errors */ = {
|
||||
0D5D16F326E24CB900AD33D1 /* AppErrors */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D5D16F426E24CCF00AD33D1 /* AppError.swift */,
|
||||
);
|
||||
path = "App Errors";
|
||||
path = AppErrors;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0D864A0626E154D100A61879 /* Error */ = {
|
||||
|
@ -503,6 +534,14 @@
|
|||
path = Loading;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0D8A43C2272AEEA7005A6414 /* FontStyles */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D8A43C3272AEEDE005A6414 /* SecantTextStyles.swift */,
|
||||
);
|
||||
path = FontStyles;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0DA13C8C26C15CBE00E3B610 /* Welcome Screen */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -512,9 +551,10 @@
|
|||
path = "Welcome Screen";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0DA13C9126C15E1900E3B610 /* UI Components */ = {
|
||||
0DA13C9126C15E1900E3B610 /* UIComponents */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D8A43C2272AEEA7005A6414 /* FontStyles */,
|
||||
669FDAE7272C239D007B9422 /* CircularFrame */,
|
||||
0DB8AA80271DC7520035BC9D /* DesignGuide.swift */,
|
||||
0DF2DC5227235E1F00FA31E2 /* Extensions */,
|
||||
|
@ -523,7 +563,7 @@
|
|||
669FDAE5272C2371007B9422 /* ProgressIndicators */,
|
||||
669FDAE6272C2380007B9422 /* Backgrounds */,
|
||||
);
|
||||
path = "UI Components";
|
||||
path = UIComponents;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0DA13C9426C186B100E3B610 /* Restore Wallet */ = {
|
||||
|
@ -602,6 +642,15 @@
|
|||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0DFE93DD272C6D4B000FCCA5 /* BackupFlowTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0DFE93DE272C6D4B000FCCA5 /* RecoveryFlowTests.swift */,
|
||||
0D1C1AA227611EFD0004AF6A /* RecoveryPhraseDisplayReducerTests.swift */,
|
||||
);
|
||||
path = BackupFlowTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2E5C037F2738C55F008BFFD3 /* Onboarding */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -649,6 +698,7 @@
|
|||
F93874EC273C4DE200F0E875 /* Home */,
|
||||
F9C165B62740403600592F76 /* Send */,
|
||||
F96B41E2273B501F0021B49A /* TransactionHistory */,
|
||||
0D3D04052728B2D70032ABC1 /* BackupFlow */,
|
||||
6654C73C2715A3FA00901167 /* Onboarding */,
|
||||
);
|
||||
path = Features;
|
||||
|
@ -967,6 +1017,7 @@
|
|||
0D32282D26C5870B00262533 /* SendScreen.swift in Sources */,
|
||||
663FABA2271D876C00E495F8 /* SecondaryButton.swift in Sources */,
|
||||
0D1922ED26BDE0C600052649 /* AppRouter.swift in Sources */,
|
||||
0D8A43C4272AEEDE005A6414 /* SecantTextStyles.swift in Sources */,
|
||||
0D1922F226BDE29300052649 /* ZcashSDKStubs.swift in Sources */,
|
||||
0DA13C9D26C1942100E3B610 /* BackupWalletScreenViewModel.swift in Sources */,
|
||||
0DACFA7F27208CE00039EEA5 /* Clamped.swift in Sources */,
|
||||
|
@ -989,11 +1040,13 @@
|
|||
F9322DC0273B555C00C105B5 /* NavigationLinks.swift in Sources */,
|
||||
F93874F1273C4DE200F0E875 /* HomeView.swift in Sources */,
|
||||
0D32282326C586A800262533 /* HistoryScreen.swift in Sources */,
|
||||
0D3D04082728B3440032ABC1 /* RecoveryPhraseDisplayView.swift in Sources */,
|
||||
0D864A0A26E154FD00A61879 /* InitFailedScreenViewModel.swift in Sources */,
|
||||
0DA13CA526C1963000E3B610 /* Balance.swift in Sources */,
|
||||
2EA11F5B27467EF800709571 /* OnboardingFooterView.swift in Sources */,
|
||||
66D50668271D9B6100E51F0D /* NavigationButtonStyle.swift in Sources */,
|
||||
0D1922F826BDEB3500052649 /* MockServices.swift in Sources */,
|
||||
0D3D040A2728B3A10032ABC1 /* RecoveryPhraseDisplayStore.swift in Sources */,
|
||||
0D4E7A0B26B364170058B01E /* ContentView.swift in Sources */,
|
||||
0D170A7226BC802800EB6A46 /* Router.swift in Sources */,
|
||||
0D354A0926D5A9D000315F45 /* Services.swift in Sources */,
|
||||
|
@ -1018,6 +1071,7 @@
|
|||
0DA13CA126C1955600E3B610 /* HomeScreen.swift in Sources */,
|
||||
0DA13C9026C15D1D00E3B610 /* WelcomeScreenViewModel.swift in Sources */,
|
||||
2E58E73B274679F000B2B84B /* OnboardingHeaderView.swift in Sources */,
|
||||
0D8A43C6272B129C005A6414 /* WordChipGrid.swift in Sources */,
|
||||
66A0807B271993C500118B79 /* OnboardingProgressIndicator.swift in Sources */,
|
||||
663FAB9E271D875700E495F8 /* CreateButton.swift in Sources */,
|
||||
0D7DF08C271DCC0E00530046 /* ScreenBackground.swift in Sources */,
|
||||
|
@ -1042,8 +1096,10 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0DFE93DF272C6D4B000FCCA5 /* RecoveryFlowTests.swift in Sources */,
|
||||
0D864A0526E1546000A61879 /* LoadingScreenTests.swift in Sources */,
|
||||
6654C7442715A4AC00901167 /* OnboardingStoreTests.swift in Sources */,
|
||||
0D1C1AA327611EFD0004AF6A /* RecoveryPhraseDisplayReducerTests.swift in Sources */,
|
||||
0D4E7A1B26B364180058B01E /* secantTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -1194,9 +1250,9 @@
|
|||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 5;
|
||||
CURRENT_PROJECT_VERSION = 7;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"secant/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = RLPRR8CPQG;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
INFOPLIST_FILE = secant/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
|
@ -1218,9 +1274,9 @@
|
|||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 5;
|
||||
CURRENT_PROJECT_VERSION = 7;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"secant/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = RLPRR8CPQG;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
INFOPLIST_FILE = secant/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
|
|
|
@ -7,6 +7,6 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
enum AppError: Error {
|
||||
case failedToInitialize(Error)
|
||||
enum AppError: Error, Equatable {
|
||||
case failedToInitialize
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0xFB",
|
||||
"green" : "0xF5",
|
||||
"red" : "0xEE"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x62",
|
||||
"green" : "0x3D",
|
||||
"red" : "0x30"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -23,9 +23,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x57",
|
||||
"green" : "0x33",
|
||||
"red" : "0x26"
|
||||
"blue" : "0.000",
|
||||
"green" : "0.725",
|
||||
"red" : "1.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "1.000",
|
||||
"green" : "1.000",
|
||||
"red" : "1.000"
|
||||
"blue" : "0.341",
|
||||
"green" : "0.200",
|
||||
"red" : "0.149"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "1.000",
|
||||
"green" : "1.000",
|
||||
"red" : "1.000"
|
||||
"blue" : "0.333",
|
||||
"green" : "0.192",
|
||||
"red" : "0.141"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.000",
|
||||
"green" : "0.000",
|
||||
"red" : "0.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "1.000",
|
||||
"green" : "1.000",
|
||||
"red" : "1.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -23,9 +23,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x41",
|
||||
"green" : "0x23",
|
||||
"red" : "0x0F"
|
||||
"blue" : "1.000",
|
||||
"green" : "1.000",
|
||||
"red" : "1.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
|
|
|
@ -19,6 +19,15 @@
|
|||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.000",
|
||||
"green" : "0.725",
|
||||
"red" : "1.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
//
|
||||
// RecoveryPhraseDisplayStore.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Francisco Gindre on 10/26/21.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import UIKit
|
||||
|
||||
enum RecoveryPhraseError: Error {
|
||||
/// This error is thrown then the Recovery Phrase can't be generated
|
||||
case unableToGeneratePhrase
|
||||
}
|
||||
|
||||
struct Pasteboard {
|
||||
let setString: (String) -> Void
|
||||
let getString: () -> String?
|
||||
}
|
||||
|
||||
extension Pasteboard {
|
||||
private struct TestPasteboard {
|
||||
static var general = TestPasteboard()
|
||||
var string: String?
|
||||
}
|
||||
|
||||
static let live = Pasteboard(
|
||||
setString: { UIPasteboard.general.string = $0 },
|
||||
getString: { UIPasteboard.general.string }
|
||||
)
|
||||
|
||||
static let test = Pasteboard(
|
||||
setString: { TestPasteboard.general.string = $0 },
|
||||
getString: { TestPasteboard.general.string }
|
||||
)
|
||||
}
|
||||
|
||||
struct BackupPhraseEnvironment {
|
||||
let mainQueue: AnySchedulerOf<DispatchQueue>
|
||||
let newPhrase: () -> Effect<RecoveryPhrase, RecoveryPhraseError>
|
||||
let pasteboard: Pasteboard
|
||||
}
|
||||
|
||||
extension BackupPhraseEnvironment {
|
||||
private struct DemoPasteboard {
|
||||
static var general = Self()
|
||||
var string: String?
|
||||
}
|
||||
|
||||
static let demo = Self(
|
||||
mainQueue: DispatchQueue.main.eraseToAnyScheduler(),
|
||||
newPhrase: { Effect(value: .init(words: RecoveryPhrase.demo.words)) },
|
||||
pasteboard: .test
|
||||
)
|
||||
|
||||
static let live = Self(
|
||||
mainQueue: DispatchQueue.main.eraseToAnyScheduler(),
|
||||
newPhrase: { Effect(value: .init(words: RecoveryPhrase.demo.words)) },
|
||||
pasteboard: .live
|
||||
)
|
||||
}
|
||||
|
||||
typealias RecoveryPhraseDisplayStore = Store<RecoveryPhraseDisplayState, RecoveryPhraseDisplayAction>
|
||||
|
||||
struct RecoveryPhrase: Equatable {
|
||||
struct Chunk: Hashable {
|
||||
var startIndex: Int
|
||||
var words: [String]
|
||||
}
|
||||
|
||||
let words: [String]
|
||||
|
||||
private let chunkSize = 6
|
||||
|
||||
func toChunks() -> [Chunk] {
|
||||
let chunks = words.count / chunkSize
|
||||
return zip(0 ..< chunks, words.chunked(into: chunkSize)).map {
|
||||
Chunk(startIndex: $0 * chunkSize + 1, words: $1)
|
||||
}
|
||||
}
|
||||
|
||||
func toString() -> String {
|
||||
words.joined(separator: " ")
|
||||
}
|
||||
}
|
||||
|
||||
struct RecoveryPhraseDisplayState: Equatable {
|
||||
var phrase: RecoveryPhrase?
|
||||
var showCopyToBufferAlert = false
|
||||
}
|
||||
|
||||
enum RecoveryPhraseDisplayAction: Equatable {
|
||||
case createPhrase
|
||||
case copyToBufferPressed
|
||||
case finishedPressed
|
||||
case phraseResponse(Result<RecoveryPhrase, RecoveryPhraseError>)
|
||||
}
|
||||
|
||||
typealias RecoveryPhraseDisplayReducer = Reducer<RecoveryPhraseDisplayState, RecoveryPhraseDisplayAction, BackupPhraseEnvironment>
|
||||
|
||||
extension RecoveryPhraseDisplayReducer {
|
||||
static let `default` = RecoveryPhraseDisplayReducer { state, action, environment in
|
||||
switch action {
|
||||
case .createPhrase:
|
||||
return environment.newPhrase()
|
||||
.receive(on: environment.mainQueue)
|
||||
.catchToEffect(RecoveryPhraseDisplayAction.phraseResponse)
|
||||
case .copyToBufferPressed:
|
||||
guard let phrase = state.phrase?.toString() else { return .none }
|
||||
environment.pasteboard.setString(phrase)
|
||||
state.showCopyToBufferAlert = true
|
||||
return .none
|
||||
case .finishedPressed:
|
||||
// TODO: remove this when feature is implemented in https://github.com/zcash/secant-ios-wallet/issues/47
|
||||
return .none
|
||||
case let .phraseResponse(.success(phrase)):
|
||||
state.phrase = phrase
|
||||
return .none
|
||||
case .phraseResponse(.failure):
|
||||
// TODO: remove this when feature is implemented in https://github.com/zcash/secant-ios-wallet/issues/129
|
||||
return .none
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Array {
|
||||
func chunked(into size: Int) -> [[Element]] {
|
||||
return stride(from: 0, to: count, by: size).map {
|
||||
Array(self[$0 ..< Swift.min($0 + size, count)])
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
//
|
||||
// RecoveryPhraseDisplayView.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Francisco Gindre on 10/26/21.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import ComposableArchitecture
|
||||
|
||||
struct RecoveryPhraseDisplayView: View {
|
||||
let store: RecoveryPhraseDisplayStore
|
||||
|
||||
var body: some View {
|
||||
WithViewStore(self.store) { viewStore in
|
||||
ScrollView {
|
||||
VStack {
|
||||
if let chunks = viewStore.phrase?.toChunks() {
|
||||
VStack(spacing: 20) {
|
||||
Text("Your Secret Recovery Phrase")
|
||||
.titleText()
|
||||
.multilineTextAlignment(.center)
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text("The following 24 words represent your funds and the security used to protect them.")
|
||||
.bodyText()
|
||||
|
||||
Text("Back them up now! There will be a test.")
|
||||
.bodyText()
|
||||
}
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 20) {
|
||||
ForEach(chunks, id: \.startIndex) { chunk in
|
||||
WordChipGrid(words: chunk.words, startingAt: chunk.startIndex)
|
||||
}
|
||||
}
|
||||
|
||||
VStack {
|
||||
Button(
|
||||
action: { viewStore.send(.finishedPressed) },
|
||||
label: { Text("Finished!") }
|
||||
)
|
||||
.activeButtonStyle
|
||||
.frame(height: 60)
|
||||
|
||||
Button(
|
||||
action: {
|
||||
viewStore.send(.copyToBufferPressed)
|
||||
},
|
||||
label: {
|
||||
Text("Copy To Buffer")
|
||||
.bodyText()
|
||||
}
|
||||
)
|
||||
.frame(height: 60)
|
||||
}
|
||||
.padding()
|
||||
} else {
|
||||
Text("Oops no words")
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.padding(.horizontal)
|
||||
}
|
||||
|
||||
// TODO: NavigationBar Style
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.applyScreenBackground()
|
||||
}
|
||||
}
|
||||
// TODO: This should have a #DEBUG tag, but if so, it's not possible to compile this on release mode and submit it to testflight
|
||||
extension RecoveryPhraseDisplayStore {
|
||||
static var demo: RecoveryPhraseDisplayStore {
|
||||
RecoveryPhraseDisplayStore(
|
||||
initialState: .init(phrase: .demo),
|
||||
reducer: .default,
|
||||
environment: .demo
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This should have a #DEBUG tag, but if so, it's not possible to compile this on release mode and submit it to testflight
|
||||
extension RecoveryPhrase {
|
||||
static let testPhrase = [
|
||||
// 1
|
||||
"bring", "salute", "thank",
|
||||
"require", "spirit", "toe",
|
||||
// 7
|
||||
"boil", "hill", "casino",
|
||||
"trophy", "drink", "frown",
|
||||
// 13
|
||||
"bird", "grit", "close",
|
||||
"morning", "bind", "cancel",
|
||||
// 19
|
||||
"daughter", "salon", "quit",
|
||||
"pizza", "just", "garlic"
|
||||
]
|
||||
|
||||
static let demo = RecoveryPhrase(words: testPhrase)
|
||||
static let empty = RecoveryPhrase(words: [])
|
||||
}
|
||||
|
||||
struct RecoveryPhraseDisplayView_Previews: PreviewProvider {
|
||||
static let scheduler = DispatchQueue.main
|
||||
|
||||
static let store = RecoveryPhraseDisplayStore.demo
|
||||
|
||||
static var previews: some View {
|
||||
NavigationView {
|
||||
RecoveryPhraseDisplayView(store: store)
|
||||
}
|
||||
|
||||
NavigationView {
|
||||
RecoveryPhraseDisplayView(store: store)
|
||||
}
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
//
|
||||
// WordChipGrid.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Francisco Gindre on 10/28/21.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
/**
|
||||
A 3x2 grid of numbered or empty chips.
|
||||
*/
|
||||
struct WordChipGrid: View {
|
||||
static let spacing: CGFloat = 10
|
||||
var chips: [PhraseChip.Kind]
|
||||
|
||||
var threeColumnGrid = Array(
|
||||
repeating: GridItem(
|
||||
.flexible(minimum: 60, maximum: 120),
|
||||
spacing: Self.spacing,
|
||||
alignment: .topLeading
|
||||
),
|
||||
count: 3
|
||||
)
|
||||
|
||||
var body: some View {
|
||||
LazyVGrid(
|
||||
columns: threeColumnGrid,
|
||||
alignment: .leading,
|
||||
spacing: Self.spacing
|
||||
) {
|
||||
ForEach(chips, id: \.self) { wordChip in
|
||||
chipView(for: wordChip)
|
||||
.frame(
|
||||
minWidth: 0,
|
||||
maxWidth: .infinity,
|
||||
minHeight: 30
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init(words: [String], startingAt index: Int) {
|
||||
self.chips = zip(words, index..<index + words.count).map({ word, index in
|
||||
word.isEmpty ? .empty : .ordered(position: index, word: word)
|
||||
})
|
||||
}
|
||||
|
||||
@ViewBuilder func chipView(for chipKind: PhraseChip.Kind) -> some View {
|
||||
switch chipKind {
|
||||
case .empty:
|
||||
EmptyChip()
|
||||
|
||||
case let .ordered(position, word):
|
||||
EnumeratedChip(index: position, text: word)
|
||||
|
||||
case .unassigned(let word):
|
||||
BlueChip(word: word)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct WordChipGrid_Previews: PreviewProvider {
|
||||
private static var words = [
|
||||
"pyramid", "negative", "page",
|
||||
"crown", "", "zebra"
|
||||
]
|
||||
|
||||
static var previews: some View {
|
||||
VStack {
|
||||
WordChipGrid(words: words, startingAt: 1)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ struct HomeState: Equatable {
|
|||
case history
|
||||
case send
|
||||
case onboarding
|
||||
case recoveryPhraseDisplay
|
||||
}
|
||||
var transactionHistoryState: TransactionHistoryState
|
||||
var route: Route?
|
||||
|
@ -91,6 +92,15 @@ extension HomeViewStore {
|
|||
)
|
||||
}
|
||||
|
||||
var showPhraseDisplayBinding: Binding<Bool> {
|
||||
self.binding(
|
||||
get: { $0.route == .recoveryPhraseDisplay },
|
||||
send: { isActive in
|
||||
return .updateRoute(isActive ? .send : nil)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
var showSendBinding: Binding<Bool> {
|
||||
self.binding(
|
||||
get: { $0.route == .send },
|
||||
|
@ -102,7 +112,7 @@ extension HomeViewStore {
|
|||
|
||||
var showOnboardingBinding: Binding<Bool> {
|
||||
self.binding(
|
||||
get: {$0.route == .onboarding },
|
||||
get: { $0.route == .onboarding },
|
||||
send: { isActive in
|
||||
return .updateRoute(isActive ? .onboarding : nil)
|
||||
}
|
||||
|
|
|
@ -21,6 +21,13 @@ struct HomeView: View {
|
|||
.primaryButtonStyle
|
||||
.frame(height: 50)
|
||||
|
||||
Button(
|
||||
action: { viewStore.send(.updateRoute(.recoveryPhraseDisplay)) },
|
||||
label: { Text("Show Recovery Phrase Demo") }
|
||||
)
|
||||
.primaryButtonStyle
|
||||
.frame(height: 50)
|
||||
|
||||
Button(
|
||||
action: { viewStore.send(.updateRoute(.send)) },
|
||||
label: { Text("Go to Send") }
|
||||
|
@ -53,6 +60,12 @@ struct HomeView: View {
|
|||
}
|
||||
.padding(.horizontal, 30)
|
||||
.navigationBarTitle("Home", displayMode: .inline)
|
||||
.navigationLinkEmpty(
|
||||
isActive: viewStore.showPhraseDisplayBinding,
|
||||
destination: {
|
||||
RecoveryPhraseDisplayView(store: .demo)
|
||||
}
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: viewStore.showSendBinding,
|
||||
destination: {
|
||||
|
@ -100,9 +113,6 @@ struct HomeView: View {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - Previews
|
||||
|
||||
#if DEBUG
|
||||
extension HomeStore {
|
||||
static var demo: HomeStore {
|
||||
HomeStore(
|
||||
|
@ -118,7 +128,8 @@ extension HomeStore {
|
|||
)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// MARK: - Previews
|
||||
|
||||
struct HomeView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
|
|
|
@ -11,7 +11,7 @@ enum SendAction: Equatable {
|
|||
case updateRoute(SendView.Route?)
|
||||
}
|
||||
|
||||
// Mark: - SendReducer
|
||||
// MARK: - SendReducer
|
||||
|
||||
typealias SendReducer = Reducer<SendState, SendAction, Void>
|
||||
|
||||
|
@ -41,16 +41,15 @@ extension SendReducer {
|
|||
}
|
||||
}
|
||||
|
||||
// Mark: - SendStore
|
||||
// MARK: - SendStore
|
||||
|
||||
typealias SendStore = Store<SendState, SendAction>
|
||||
|
||||
// Mark: - SendViewStore
|
||||
// MARK: - SendViewStore
|
||||
|
||||
typealias SendViewStore = ViewStore<SendState, SendAction>
|
||||
|
||||
extension SendViewStore {
|
||||
|
||||
var bindingForTransaction: Binding<Transaction> {
|
||||
self.binding(
|
||||
get: \.transaction,
|
||||
|
@ -86,4 +85,3 @@ extension SendViewStore {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ struct Sent: View {
|
|||
.frame(height: 50)
|
||||
.padding()
|
||||
|
||||
|
||||
Text("\(String(dumping: transaction))")
|
||||
Text("\(String(dumping: isComplete))")
|
||||
|
||||
|
|
|
@ -9,15 +9,6 @@ struct TransactionDetailView: View {
|
|||
}
|
||||
}
|
||||
|
||||
struct TransactionDetail_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationView {
|
||||
TransactionDetailView(transaction: .demo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
extension Transaction {
|
||||
static var demo: Self {
|
||||
.init(
|
||||
|
@ -29,4 +20,13 @@ extension Transaction {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct TransactionDetail_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationView {
|
||||
TransactionDetailView(transaction: .demo)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -22,21 +22,6 @@ struct TransactionHistoryView: View {
|
|||
}
|
||||
}
|
||||
|
||||
struct TransactionView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationView {
|
||||
TransactionHistoryView(store: .demo)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
|
||||
NavigationView {
|
||||
TransactionHistoryView(store: .demoWithSelectedTransaction)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
extension TransactionHistoryStore {
|
||||
static var demo: Store<TransactionHistoryState, TransactionHistoryAction> {
|
||||
return Store(
|
||||
|
@ -77,4 +62,17 @@ extension IdentifiedArrayOf where Element == Transaction {
|
|||
)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
struct TransactionView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationView {
|
||||
TransactionHistoryView(store: .demo)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
|
||||
NavigationView {
|
||||
TransactionHistoryView(store: .demoWithSelectedTransaction)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ internal enum Asset {
|
|||
}
|
||||
internal enum Colors {
|
||||
internal enum BackgroundColors {
|
||||
internal static let numberedChip = ColorAsset(name: "numberedChip")
|
||||
internal static let phraseGridDarkGray = ColorAsset(name: "phraseGridDarkGray")
|
||||
}
|
||||
internal enum Buttons {
|
||||
|
@ -73,6 +74,7 @@ internal enum Asset {
|
|||
}
|
||||
internal enum Text {
|
||||
internal static let activeButtonText = ColorAsset(name: "ActiveButtonText")
|
||||
internal static let body = ColorAsset(name: "Body")
|
||||
internal static let button = ColorAsset(name: "Button")
|
||||
internal static let heading = ColorAsset(name: "Heading")
|
||||
internal static let medium = ColorAsset(name: "Medium")
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UIAppFonts</key>
|
||||
|
|
|
@ -15,7 +15,7 @@ struct SecantApp: App {
|
|||
NavigationView {
|
||||
HomeView(store: homeStore)
|
||||
}
|
||||
.navigationViewStyle(StackNavigationViewStyle())
|
||||
.navigationViewStyle(StackNavigationViewStyle())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ struct ButtonModifier_Previews: PreviewProvider {
|
|||
Button("Example Button") { dump("Example button") }
|
||||
.exampleButtonStyle
|
||||
.padding(.horizontal, 25)
|
||||
.frame(height: 75)
|
||||
.frame(height: 60)
|
||||
.previewLayout(.fixed(width: 300, height: 100))
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
|
@ -19,14 +19,14 @@ struct EnumeratedChip: View {
|
|||
minWidth: 0,
|
||||
maxWidth: .infinity,
|
||||
minHeight: 30,
|
||||
idealHeight: 40,
|
||||
maxHeight: .infinity,
|
||||
alignment: .leading
|
||||
)
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.leading, 14)
|
||||
.padding(.vertical, 4)
|
||||
.background(Asset.Colors.Buttons.primaryButtonPressed.color)
|
||||
.background(Asset.Colors.BackgroundColors.numberedChip.color)
|
||||
.cornerRadius(6)
|
||||
.shadow(color: Asset.Colors.Shadow.numberedTextShadow.color, radius: 3, x: 0, y: 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,24 +35,30 @@ struct NumberedText: View {
|
|||
var text: String
|
||||
|
||||
@ViewBuilder var numberedText: some View {
|
||||
Text(number.superscriptRepresentation)
|
||||
GeometryReader { geometry in
|
||||
(Text("\(number)")
|
||||
.baselineOffset(geometry.size.height / 4)
|
||||
.foregroundColor(Asset.Colors.Text.highlightedSuperscriptText.color)
|
||||
.font(.custom(FontFamily.Roboto.bold.name, size: 20)) +
|
||||
.font(.custom(FontFamily.Roboto.bold.name, size: 12)) +
|
||||
|
||||
Text(" \(text)")
|
||||
.foregroundColor(Asset.Colors.Text.button.color)
|
||||
.font(.custom(FontFamily.Rubik.medium.name, size: 16))
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
numberedText
|
||||
.font(.custom(FontFamily.Rubik.regular.name, size: 14))
|
||||
)
|
||||
.shadow(
|
||||
color: Asset.Colors.Shadow.numberedTextShadow.color,
|
||||
radius: 1,
|
||||
x: 0,
|
||||
y: 1
|
||||
)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.frame(height: geometry.size.height, alignment: .center)
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
numberedText
|
||||
.layoutPriority(1)
|
||||
.fixedSize(horizontal: false, vertical: false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,8 +89,8 @@ struct EnumeratedChip_Previews: PreviewProvider {
|
|||
.frame(
|
||||
minWidth: 0,
|
||||
maxWidth: .infinity,
|
||||
minHeight: 30,
|
||||
idealHeight: 40
|
||||
minHeight: 40,
|
||||
maxHeight: .infinity
|
||||
)
|
||||
} else {
|
||||
EnumeratedChip(index: (i + 1), text: word)
|
||||
|
@ -92,7 +98,7 @@ struct EnumeratedChip_Previews: PreviewProvider {
|
|||
minWidth: 0,
|
||||
maxWidth: .infinity,
|
||||
minHeight: 30,
|
||||
idealHeight: 40
|
||||
maxHeight: .infinity
|
||||
)
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
import SwiftUI
|
||||
|
||||
struct PhraseChip: View {
|
||||
enum Kind {
|
||||
enum Kind: Hashable {
|
||||
case empty
|
||||
case unassigned(word: String)
|
||||
case ordered(position: Int, word: String)
|
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// SecantTextStyles.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Francisco Gindre on 10/28/21.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
extension Text {
|
||||
func bodyText() -> some View {
|
||||
self.modifier(BodyTextStyle())
|
||||
}
|
||||
|
||||
func titleText() -> some View {
|
||||
self.modifier(TitleTextStyle())
|
||||
}
|
||||
/// Body text style. Used for content. Roboto-Regular 18pt
|
||||
private struct BodyTextStyle: ViewModifier {
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.foregroundColor(Asset.Colors.Text.body.color)
|
||||
.font(.custom(FontFamily.Rubik.regular.name, size: 18))
|
||||
}
|
||||
}
|
||||
|
||||
private struct TitleTextStyle: ViewModifier {
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.foregroundColor(Asset.Colors.Text.body.color)
|
||||
.font(.custom(FontFamily.Roboto.medium.name, size: 24))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import SwiftUI
|
||||
|
||||
#if DEBUG
|
||||
// TODO: This should have a #DEBUG tag, but if so, it's not possible to compile this on release mode and submit it to testflight
|
||||
struct StateContainer<T, Content: View>: View {
|
||||
@State private var state: T
|
||||
private var content: (Binding<T>) -> Content
|
||||
|
@ -14,4 +14,3 @@ struct StateContainer<T, Content: View>: View {
|
|||
content($state)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Foundation
|
||||
|
||||
#if DEBUG
|
||||
// TODO: This should have a #DEBUG tag, but if so, it's not possible to compile this on release mode and submit it to testflight
|
||||
extension String {
|
||||
init<T>(dumping value: T) {
|
||||
var output = String()
|
||||
|
@ -8,4 +8,3 @@ extension String {
|
|||
self.init(stringLiteral: output)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import SwiftUI
|
||||
import ComposableArchitecture
|
||||
|
||||
struct WithStateBinding<T: Equatable, Content: View>: View {
|
||||
@State var localState: T
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// RecoveryFlowTests.swift
|
||||
// secantTests
|
||||
//
|
||||
// Created by Francisco Gindre on 10/29/21.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import secant_testnet
|
||||
|
||||
class RecoveryFlowTests: XCTestCase {
|
||||
func testGiven24WordsBIP39ChunkItIntoQuarters() throws {
|
||||
let words = [
|
||||
"bring", "salute", "thank",
|
||||
"require", "spirit", "toe",
|
||||
// second chunk
|
||||
"boil", "hill", "casino",
|
||||
"trophy", "drink", "frown",
|
||||
// third chunk
|
||||
"bird", "grit", "close",
|
||||
"morning", "bind", "cancel",
|
||||
// Fourth chunk
|
||||
"daughter", "salon", "quit",
|
||||
"pizza", "just", "garlic"
|
||||
]
|
||||
let phrase = RecoveryPhrase(words: words)
|
||||
|
||||
let chunks = phrase.toChunks()
|
||||
|
||||
XCTAssertEqual(chunks.count, 4)
|
||||
XCTAssertEqual(chunks[0].startIndex, 1)
|
||||
XCTAssertEqual(chunks[0].words, ["bring", "salute", "thank", "require", "spirit", "toe"])
|
||||
XCTAssertEqual(chunks[1].startIndex, 7)
|
||||
XCTAssertEqual(chunks[2].startIndex, 13)
|
||||
XCTAssertEqual(chunks[3].startIndex, 19)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// RecoveryPhraseDisplayStoreTests.swift
|
||||
// secantTests
|
||||
//
|
||||
// Created by Francisco Gindre on 12/8/21.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import ComposableArchitecture
|
||||
@testable import secant_testnet
|
||||
|
||||
class RecoveryPhraseDisplayReducerTests: XCTestCase {
|
||||
func testCopyToBuffer() {
|
||||
let store = TestStore(
|
||||
initialState: .test,
|
||||
reducer: .default,
|
||||
environment: .demo
|
||||
)
|
||||
|
||||
store.send(.copyToBufferPressed) {
|
||||
$0.phrase = .demo
|
||||
$0.showCopyToBufferAlert = true
|
||||
}
|
||||
|
||||
XCTAssertEqual(
|
||||
store.environment.pasteboard.getString(),
|
||||
RecoveryPhrase.demo.toString()
|
||||
)
|
||||
}
|
||||
|
||||
func testNewPhrase() {
|
||||
let store = TestStore(
|
||||
initialState: .empty,
|
||||
reducer: .default,
|
||||
environment: .demo
|
||||
)
|
||||
|
||||
store.send(.phraseResponse(.success(.demo))) {
|
||||
$0.phrase = .demo
|
||||
$0.showCopyToBufferAlert = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension RecoveryPhraseDisplayState {
|
||||
static let test = RecoveryPhraseDisplayState(
|
||||
phrase: .demo,
|
||||
showCopyToBufferAlert: false
|
||||
)
|
||||
|
||||
static let empty = RecoveryPhraseDisplayState(
|
||||
phrase: .empty,
|
||||
showCopyToBufferAlert: false
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue