Issue #145 - Single Line Text Field
* Single Line Text Field * add TODO comment to secant/Util/Strings.swift Issue #245 comments the changes needed Co-authored-by: Francisco Gindre <francisco.gindre@gmail.com>
|
@ -57,10 +57,20 @@
|
|||
0DFE93E1272C9ECB000FCCA5 /* RecoveryPhraseBackupValidationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DFE93E0272C9ECB000FCCA5 /* RecoveryPhraseBackupValidationView.swift */; };
|
||||
0DFE93E3272CA1AA000FCCA5 /* RecoveryPhraseValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DFE93E2272CA1AA000FCCA5 /* RecoveryPhraseValidation.swift */; };
|
||||
0DFE93E6272CB6F7000FCCA5 /* RecoveryPhraseValidationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DFE93E5272CB6F7000FCCA5 /* RecoveryPhraseValidationTests.swift */; };
|
||||
2E35F99227B28E7600EB79CD /* SingleLineTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E35F99127B28E7600EB79CD /* SingleLineTextField.swift */; };
|
||||
2E35F99A27B3E99C00EB79CD /* TextFieldTitleAccessoryButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E35F99927B3E99C00EB79CD /* TextFieldTitleAccessoryButtonStyle.swift */; };
|
||||
2E58E73B274679F000B2B84B /* OnboardingHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E58E73A274679F000B2B84B /* OnboardingHeaderView.swift */; };
|
||||
2E6CF8DD27D78319004DCD7A /* CurrencySelectionStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E6CF8DC27D78319004DCD7A /* CurrencySelectionStore.swift */; };
|
||||
2E8719CB27FB09990082C926 /* TransactionTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E8719CA27FB09990082C926 /* TransactionTextField.swift */; };
|
||||
2E8719CD27FB0D3B0082C926 /* TransactionCurrencySelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E8719CC27FB0D3B0082C926 /* TransactionCurrencySelector.swift */; };
|
||||
2EA11F5B27467EF800709571 /* OnboardingFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EA11F5A27467EF800709571 /* OnboardingFooterView.swift */; };
|
||||
2EA11F5D27467F7700709571 /* OnboardingContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EA11F5C27467F7700709571 /* OnboardingContentView.swift */; };
|
||||
2EB1C5E827D77F6100BC43D7 /* TextFieldStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EB1C5E727D77F6100BC43D7 /* TextFieldStore.swift */; };
|
||||
2EB660E02747EAB900A06A07 /* OnboardingScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E5C03802738C570008BFFD3 /* OnboardingScreen.swift */; };
|
||||
2EB7758727FC67FD00269373 /* TransactionInputStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EB7758627FC67FD00269373 /* TransactionInputStore.swift */; };
|
||||
2EDA07A027EDE18C00D6F09B /* TextFieldInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EDA079F27EDE18C00D6F09B /* TextFieldInput.swift */; };
|
||||
2EDA07A227EDE1AE00D6F09B /* TextFieldFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EDA07A127EDE1AE00D6F09B /* TextFieldFooter.swift */; };
|
||||
2EDA07A427EDE2A900D6F09B /* DebugFrame.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EDA07A327EDE2A900D6F09B /* DebugFrame.swift */; };
|
||||
660558E9270C7A54009D6954 /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 660558E8270C7A54009D6954 /* Colors.xcassets */; };
|
||||
660558F7270C862F009D6954 /* Fonts+Generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660558F5270C862F009D6954 /* Fonts+Generated.swift */; };
|
||||
660558F8270C862F009D6954 /* XCAssets+Generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660558F6270C862F009D6954 /* XCAssets+Generated.swift */; };
|
||||
|
@ -92,9 +102,9 @@
|
|||
9EF8135C27ECC25E0075AF48 /* WalletStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EF8135A27ECC25E0075AF48 /* WalletStorageTests.swift */; };
|
||||
9EF8135D27ECC25E0075AF48 /* UserPreferencesStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EF8135B27ECC25E0075AF48 /* UserPreferencesStorageTests.swift */; };
|
||||
9EF8136027F043CC0075AF48 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EF8135F27F043CC0075AF48 /* AppDelegate.swift */; };
|
||||
9EF8139C27F47AED0075AF48 /* InitializationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EF8139B27F47AED0075AF48 /* InitializationState.swift */; };
|
||||
9EF8139127F191BF0075AF48 /* WalletStorageInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EF8139027F191BF0075AF48 /* WalletStorageInteractor.swift */; };
|
||||
9EF8139827F1FAEC0075AF48 /* ZcashLightClientKit in Frameworks */ = {isa = PBXBuildFile; productRef = 9EF8139727F1FAEC0075AF48 /* ZcashLightClientKit */; };
|
||||
9EF8139C27F47AED0075AF48 /* InitializationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EF8139B27F47AED0075AF48 /* InitializationState.swift */; };
|
||||
F9322DC0273B555C00C105B5 /* NavigationLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9322DBF273B555C00C105B5 /* NavigationLinks.swift */; };
|
||||
F93673D62742CB840099C6AF /* Previews.swift in Sources */ = {isa = PBXBuildFile; fileRef = F93673D52742CB840099C6AF /* Previews.swift */; };
|
||||
F93874F0273C4DE200F0E875 /* HomeStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F93874ED273C4DE200F0E875 /* HomeStore.swift */; };
|
||||
|
@ -198,10 +208,20 @@
|
|||
0DFE93E0272C9ECB000FCCA5 /* RecoveryPhraseBackupValidationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoveryPhraseBackupValidationView.swift; sourceTree = "<group>"; };
|
||||
0DFE93E2272CA1AA000FCCA5 /* RecoveryPhraseValidation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoveryPhraseValidation.swift; sourceTree = "<group>"; };
|
||||
0DFE93E5272CB6F7000FCCA5 /* RecoveryPhraseValidationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoveryPhraseValidationTests.swift; sourceTree = "<group>"; };
|
||||
2E35F99127B28E7600EB79CD /* SingleLineTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleLineTextField.swift; sourceTree = "<group>"; };
|
||||
2E35F99927B3E99C00EB79CD /* TextFieldTitleAccessoryButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldTitleAccessoryButtonStyle.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>"; };
|
||||
2E6CF8DC27D78319004DCD7A /* CurrencySelectionStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencySelectionStore.swift; sourceTree = "<group>"; };
|
||||
2E8719CA27FB09990082C926 /* TransactionTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionTextField.swift; sourceTree = "<group>"; };
|
||||
2E8719CC27FB0D3B0082C926 /* TransactionCurrencySelector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionCurrencySelector.swift; sourceTree = "<group>"; };
|
||||
2EA11F5A27467EF800709571 /* OnboardingFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingFooterView.swift; sourceTree = "<group>"; };
|
||||
2EA11F5C27467F7700709571 /* OnboardingContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingContentView.swift; sourceTree = "<group>"; };
|
||||
2EB1C5E727D77F6100BC43D7 /* TextFieldStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldStore.swift; sourceTree = "<group>"; };
|
||||
2EB7758627FC67FD00269373 /* TransactionInputStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionInputStore.swift; sourceTree = "<group>"; };
|
||||
2EDA079F27EDE18C00D6F09B /* TextFieldInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldInput.swift; sourceTree = "<group>"; };
|
||||
2EDA07A127EDE1AE00D6F09B /* TextFieldFooter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldFooter.swift; sourceTree = "<group>"; };
|
||||
2EDA07A327EDE2A900D6F09B /* DebugFrame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugFrame.swift; sourceTree = "<group>"; };
|
||||
660558E8270C7A54009D6954 /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = "<group>"; };
|
||||
660558F5270C862F009D6954 /* Fonts+Generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Fonts+Generated.swift"; sourceTree = "<group>"; };
|
||||
660558F6270C862F009D6954 /* XCAssets+Generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "XCAssets+Generated.swift"; sourceTree = "<group>"; };
|
||||
|
@ -232,8 +252,8 @@
|
|||
9EF8135A27ECC25E0075AF48 /* WalletStorageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletStorageTests.swift; sourceTree = "<group>"; };
|
||||
9EF8135B27ECC25E0075AF48 /* UserPreferencesStorageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserPreferencesStorageTests.swift; sourceTree = "<group>"; };
|
||||
9EF8135F27F043CC0075AF48 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
9EF8139B27F47AED0075AF48 /* InitializationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitializationState.swift; sourceTree = "<group>"; };
|
||||
9EF8139027F191BF0075AF48 /* WalletStorageInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletStorageInteractor.swift; sourceTree = "<group>"; };
|
||||
9EF8139B27F47AED0075AF48 /* InitializationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitializationState.swift; sourceTree = "<group>"; };
|
||||
F9322DBF273B555C00C105B5 /* NavigationLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationLinks.swift; sourceTree = "<group>"; };
|
||||
F93673D52742CB840099C6AF /* Previews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Previews.swift; sourceTree = "<group>"; };
|
||||
F93874ED273C4DE200F0E875 /* HomeStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeStore.swift; sourceTree = "<group>"; };
|
||||
|
@ -391,6 +411,8 @@
|
|||
0D4E7A0726B364170058B01E /* secant */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D4E7A0826B364170058B01E /* SecantApp.swift */,
|
||||
0D4E7A0A26B364170058B01E /* ContentView.swift */,
|
||||
0DACFA7D27208CC80039EEA5 /* Util */,
|
||||
6654C73B2715A3F000901167 /* Features */,
|
||||
660558F4270C85F7009D6954 /* Generated */,
|
||||
|
@ -481,6 +503,7 @@
|
|||
0DA13C9126C15E1900E3B610 /* UIComponents */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2E35F99027B28E6800EB79CD /* TextFields */,
|
||||
0D0781C5278776B90083ACD7 /* Shapes */,
|
||||
0D8A43C2272AEEA7005A6414 /* FontStyles */,
|
||||
669FDAE7272C239D007B9422 /* CircularFrame */,
|
||||
|
@ -513,6 +536,7 @@
|
|||
F9EEB8152742C2210032EEB8 /* WithStateBinding.swift */,
|
||||
F93673D52742CB840099C6AF /* Previews.swift */,
|
||||
0D35CC45277A36E00074316A /* ScrollableWhenScaled.swift */,
|
||||
2EDA07A327EDE2A900D6F09B /* DebugFrame.swift */,
|
||||
9E2AC10027D8EF0B0042AA47 /* MnemonicSeedPhraseProvider.swift */,
|
||||
9E2AC10227DA28200042AA47 /* WalletStorage.swift */,
|
||||
9E80B47127E4B34B008FF493 /* UserPreferencesStorage.swift */,
|
||||
|
@ -567,6 +591,18 @@
|
|||
path = RecoveryPhraseValidationTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2E35F99027B28E6800EB79CD /* TextFields */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2E8719CA27FB09990082C926 /* TransactionTextField.swift */,
|
||||
2E8719CC27FB0D3B0082C926 /* TransactionCurrencySelector.swift */,
|
||||
2EB7758627FC67FD00269373 /* TransactionInputStore.swift */,
|
||||
2E6CF8DC27D78319004DCD7A /* CurrencySelectionStore.swift */,
|
||||
2EDA07A527EDE31100D6F09B /* Components */,
|
||||
);
|
||||
path = TextFields;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2E5C037F2738C55F008BFFD3 /* Onboarding */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -578,6 +614,18 @@
|
|||
path = Onboarding;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2EDA07A527EDE31100D6F09B /* Components */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2E35F99127B28E7600EB79CD /* SingleLineTextField.swift */,
|
||||
2EDA079F27EDE18C00D6F09B /* TextFieldInput.swift */,
|
||||
2EDA07A127EDE1AE00D6F09B /* TextFieldFooter.swift */,
|
||||
2E35F99927B3E99C00EB79CD /* TextFieldTitleAccessoryButtonStyle.swift */,
|
||||
2EB1C5E727D77F6100BC43D7 /* TextFieldStore.swift */,
|
||||
);
|
||||
path = Components;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
660558F4270C85F7009D6954 /* Generated */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1078,12 +1126,15 @@
|
|||
660558F8270C862F009D6954 /* XCAssets+Generated.swift in Sources */,
|
||||
0D35CC46277A36E00074316A /* ScrollableWhenScaled.swift in Sources */,
|
||||
F96B41E9273B501F0021B49A /* TransactionHistoryView.swift in Sources */,
|
||||
2EDA07A027EDE18C00D6F09B /* TextFieldInput.swift in Sources */,
|
||||
2EB7758727FC67FD00269373 /* TransactionInputStore.swift in Sources */,
|
||||
669FDAE9272C23B3007B9422 /* CircularFrame.swift in Sources */,
|
||||
9EF8136027F043CC0075AF48 /* AppDelegate.swift in Sources */,
|
||||
9E80B47227E4B34B008FF493 /* UserPreferencesStorage.swift in Sources */,
|
||||
F96B41E8273B501F0021B49A /* TransactionDetailView.swift in Sources */,
|
||||
663FABA2271D876C00E495F8 /* SecondaryButton.swift in Sources */,
|
||||
0DC487C32772574C00BE6A63 /* ValidationSucceededView.swift in Sources */,
|
||||
2EB1C5E827D77F6100BC43D7 /* TextFieldStore.swift in Sources */,
|
||||
0D8A43C4272AEEDE005A6414 /* SecantTextStyles.swift in Sources */,
|
||||
0D1922F226BDE29300052649 /* ZcashSDKStubs.swift in Sources */,
|
||||
9E4DC6E027C409A100E657F4 /* NeumorphicDesignModifier.swift in Sources */,
|
||||
|
@ -1092,6 +1143,7 @@
|
|||
9E2DF99E27CF704D00649636 /* ImportWalletView.swift in Sources */,
|
||||
0D535FE2271F9476009A9E3E /* EnumeratedChip.swift in Sources */,
|
||||
6654C73E2715A41300901167 /* OnboardingStore.swift in Sources */,
|
||||
2E6CF8DD27D78319004DCD7A /* CurrencySelectionStore.swift in Sources */,
|
||||
9EBEF87A27CE369800B4F343 /* RecoveryPhraseTestPreambleView.swift in Sources */,
|
||||
9E4DC6E227C4C6B700E657F4 /* SecantButtonStyles.swift in Sources */,
|
||||
0DDB6A5127737D4A0012A410 /* ValidationFailedView.swift in Sources */,
|
||||
|
@ -1100,6 +1152,7 @@
|
|||
F9971A5327680DD000A2DB75 /* Profile.swift in Sources */,
|
||||
F93874F0273C4DE200F0E875 /* HomeStore.swift in Sources */,
|
||||
669FDAEB272C23C2007B9422 /* CircularFrameBadge.swift in Sources */,
|
||||
2E8719CD27FB0D3B0082C926 /* TransactionCurrencySelector.swift in Sources */,
|
||||
F9971A6C27680E1000A2DB75 /* WalletInfoView.swift in Sources */,
|
||||
F9EEB8162742C2210032EEB8 /* WithStateBinding.swift in Sources */,
|
||||
F93673D62742CB840099C6AF /* Previews.swift in Sources */,
|
||||
|
@ -1118,6 +1171,7 @@
|
|||
0DA13CA526C1963000E3B610 /* Balance.swift in Sources */,
|
||||
2EA11F5B27467EF800709571 /* OnboardingFooterView.swift in Sources */,
|
||||
66D50668271D9B6100E51F0D /* NavigationButtonStyle.swift in Sources */,
|
||||
2EDA07A427EDE2A900D6F09B /* DebugFrame.swift in Sources */,
|
||||
0D3D040A2728B3A10032ABC1 /* RecoveryPhraseDisplayStore.swift in Sources */,
|
||||
9E2AC10127D8EF0B0042AA47 /* MnemonicSeedPhraseProvider.swift in Sources */,
|
||||
0D354A0926D5A9D000315F45 /* Services.swift in Sources */,
|
||||
|
@ -1138,14 +1192,17 @@
|
|||
0D185819272723FF0046B928 /* ColoredChip.swift in Sources */,
|
||||
2EA11F5D27467F7700709571 /* OnboardingContentView.swift in Sources */,
|
||||
2E58E73B274679F000B2B84B /* OnboardingHeaderView.swift in Sources */,
|
||||
2E35F99227B28E7600EB79CD /* SingleLineTextField.swift in Sources */,
|
||||
0D8A43C6272B129C005A6414 /* WordChipGrid.swift in Sources */,
|
||||
66A0807B271993C500118B79 /* OnboardingProgressIndicator.swift in Sources */,
|
||||
0D7DF08C271DCC0E00530046 /* ScreenBackground.swift in Sources */,
|
||||
F9C165C22740403600592F76 /* CreateView.swift in Sources */,
|
||||
F9C165B4274031F600592F76 /* Bindings.swift in Sources */,
|
||||
2E35F99A27B3E99C00EB79CD /* TextFieldTitleAccessoryButtonStyle.swift in Sources */,
|
||||
9E2DF99C27CF704D00649636 /* ImportWalletStore.swift in Sources */,
|
||||
F9971A6627680DFE00A2DB75 /* SettingsView.swift in Sources */,
|
||||
F96B41EB273B50520021B49A /* Strings.swift in Sources */,
|
||||
2EDA07A227EDE1AE00D6F09B /* TextFieldFooter.swift in Sources */,
|
||||
F9971A5427680DD000A2DB75 /* ProfileView.swift in Sources */,
|
||||
F9971A6027680DF600A2DB75 /* Scan.swift in Sources */,
|
||||
9EF8139127F191BF0075AF48 /* WalletStorageInteractor.swift in Sources */,
|
||||
|
@ -1156,6 +1213,7 @@
|
|||
F9971A6527680DFE00A2DB75 /* Settings.swift in Sources */,
|
||||
9EF8139C27F47AED0075AF48 /* InitializationState.swift in Sources */,
|
||||
0D0781C9278776D20083ACD7 /* ZcashSymbol.swift in Sources */,
|
||||
2E8719CB27FB09990082C926 /* TransactionTextField.swift in Sources */,
|
||||
6654C7412715A47300901167 /* Onboarding.swift in Sources */,
|
||||
F9C165C42740403600592F76 /* SentView.swift in Sources */,
|
||||
F9971A5927680DDE00A2DB75 /* Request.swift in Sources */,
|
||||
|
|
|
@ -69,8 +69,8 @@
|
|||
"repositoryURL": "https://github.com/apple/swift-crypto.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "a8911e0fadc25aef1071d582355bd1037a176060",
|
||||
"version": "2.0.4"
|
||||
"revision": "067254c79435de759aeef4a6a03e43d087d61312",
|
||||
"version": "2.0.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "qr_lighttheme.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "qr_darktheme.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "qr_lighttheme@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "qr_darktheme@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "qr_lighttheme@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "qr_darktheme@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 494 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 546 B |
After Width: | Height: | Size: 715 B |
After Width: | Height: | Size: 770 B |
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "swapicon_lighttheme.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "swapicon_darktheme.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "swapicon_lighttheme@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "swapicon_darktheme@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "swapicon_lighttheme@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "swapicon_darktheme@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 271 B |
After Width: | Height: | Size: 424 B |
After Width: | Height: | Size: 552 B |
After Width: | Height: | Size: 298 B |
After Width: | Height: | Size: 463 B |
After Width: | Height: | Size: 599 B |
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.171",
|
||||
"green" : "0.138",
|
||||
"red" : "0.126"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.000",
|
||||
"green" : "0.810",
|
||||
"red" : "1.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.110",
|
||||
"green" : "0.110",
|
||||
"red" : "0.110"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.110",
|
||||
"green" : "0.110",
|
||||
"red" : "0.110"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.226",
|
||||
"green" : "0.226",
|
||||
"red" : "0.226"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.226",
|
||||
"green" : "0.226",
|
||||
"red" : "0.226"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "0.827",
|
||||
"blue" : "0.623",
|
||||
"green" : "0.589",
|
||||
"red" : "0.560"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.290",
|
||||
"green" : "0.275",
|
||||
"red" : "0.259"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.678",
|
||||
"green" : "0.459",
|
||||
"red" : "0.557"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.678",
|
||||
"green" : "0.459",
|
||||
"red" : "0.557"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ struct HomeView: View {
|
|||
reducer: SendReducer.default(
|
||||
whenDone: { HomeViewStore(store).send(.updateRoute(nil)) }
|
||||
)
|
||||
.debug(),
|
||||
.debug(),
|
||||
environment: ()
|
||||
)
|
||||
)
|
||||
|
|
|
@ -37,7 +37,9 @@ internal enum Asset {
|
|||
internal static let bank = ImageAsset(name: "bank")
|
||||
internal static let list = ImageAsset(name: "list")
|
||||
internal static let profile = ImageAsset(name: "profile")
|
||||
internal static let qrCode = ImageAsset(name: "qr-code")
|
||||
internal static let shield = ImageAsset(name: "shield")
|
||||
internal static let swap = ImageAsset(name: "swap")
|
||||
}
|
||||
}
|
||||
internal enum Colors {
|
||||
|
@ -61,6 +63,9 @@ internal enum Asset {
|
|||
internal static let secondaryButton = ColorAsset(name: "SecondaryButton")
|
||||
internal static let secondaryButtonPressed = ColorAsset(name: "SecondaryButtonPressed")
|
||||
}
|
||||
internal enum Cursor {
|
||||
internal static let bar = ColorAsset(name: "Bar")
|
||||
}
|
||||
internal enum Onboarding {
|
||||
internal static let badgeShadow = ColorAsset(name: "BadgeShadow")
|
||||
internal static let circularFrameDarkOutlineGradientEnd = ColorAsset(name: "CircularFrameDarkOutlineGradientEnd")
|
||||
|
@ -104,6 +109,14 @@ internal enum Asset {
|
|||
internal static let captionTextShadow = ColorAsset(name: "captionTextShadow")
|
||||
internal static let highlightedSuperscriptText = ColorAsset(name: "highlightedSuperscriptText")
|
||||
}
|
||||
internal enum TextField {
|
||||
internal static let titleAccessoryButton = ColorAsset(name: "TitleAccessoryButton")
|
||||
internal static let titleAccessoryButtonPressed = ColorAsset(name: "TitleAccessoryButtonPressed")
|
||||
internal enum Underline {
|
||||
internal static let gray = ColorAsset(name: "Gray")
|
||||
internal static let purple = ColorAsset(name: "Purple")
|
||||
}
|
||||
}
|
||||
internal enum ZcashBadge {
|
||||
internal static let zcashLogoFill = ColorAsset(name: "ZcashLogoFill")
|
||||
internal static let innerCircle = ColorAsset(name: "innerCircle")
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
//
|
||||
// SingleLineTextField.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Adam Stener on 2/8/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import ComposableArchitecture
|
||||
|
||||
struct SingleLineTextField<TitleAccessoryContent, InputAccessoryContent>: View
|
||||
where TitleAccessoryContent: View, InputAccessoryContent: View {
|
||||
let placeholderText: String
|
||||
let title: String
|
||||
let store: TextFieldStore
|
||||
|
||||
@ViewBuilder let titleAccessoryView: TitleAccessoryContent
|
||||
@ViewBuilder let inputAccessoryView: InputAccessoryContent
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
HStack {
|
||||
Text(title)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.middle)
|
||||
|
||||
Spacer()
|
||||
|
||||
titleAccessoryView
|
||||
}
|
||||
|
||||
HStack {
|
||||
TextFieldInput(
|
||||
placeholder: placeholderText,
|
||||
store: store
|
||||
)
|
||||
|
||||
Spacer()
|
||||
|
||||
inputAccessoryView
|
||||
}
|
||||
.frame(maxHeight: 50)
|
||||
|
||||
TextFieldFooter()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SingleLineTextField_Previews: PreviewProvider {
|
||||
struct TransactionPreview: View {
|
||||
let store: TextFieldStore
|
||||
let maxTransactionValue = 500.0
|
||||
|
||||
var body: some View {
|
||||
WithViewStore(store) { viewStore in
|
||||
VStack {
|
||||
SingleLineTextField(
|
||||
placeholderText: "$0",
|
||||
title: "How much?",
|
||||
store: store,
|
||||
titleAccessoryView: {
|
||||
Button(
|
||||
action: {
|
||||
viewStore.send(.set("\(500)"))
|
||||
},
|
||||
label: { Text("Max") }
|
||||
)
|
||||
.textFieldTitleAccessoryButtonStyle
|
||||
},
|
||||
inputAccessoryView: { EmptyView() }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct UserPreview: View {
|
||||
let store: TextFieldStore
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
SingleLineTextField(
|
||||
placeholderText: "",
|
||||
title: "Who would you like to deal with really long text today?",
|
||||
store: store,
|
||||
titleAccessoryView: { EmptyView() },
|
||||
inputAccessoryView: { EmptyView() }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static var previews: some View {
|
||||
TransactionPreview(
|
||||
store: TextFieldStore(
|
||||
initialState: .init(
|
||||
validationType: .floatingPoint,
|
||||
text: ""
|
||||
),
|
||||
reducer: .default,
|
||||
environment: .init()
|
||||
)
|
||||
)
|
||||
.preferredColorScheme(.dark)
|
||||
.padding(.horizontal, 50)
|
||||
.applyScreenBackground()
|
||||
.previewLayout(.fixed(width: 500, height: 200))
|
||||
|
||||
UserPreview(
|
||||
store: TextFieldStore(
|
||||
initialState: .init(
|
||||
validationType: .email,
|
||||
text: ""
|
||||
),
|
||||
reducer: .default,
|
||||
environment: .init()
|
||||
)
|
||||
)
|
||||
.preferredColorScheme(.light)
|
||||
.padding(.horizontal, 50)
|
||||
.applyScreenBackground()
|
||||
.previewLayout(.fixed(width: 500, height: 200))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// TextFieldFooter.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Adam Stener on 3/25/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import ComposableArchitecture
|
||||
|
||||
struct TextFieldFooter: View {
|
||||
var body: some View {
|
||||
HStack(spacing: 0) {
|
||||
Rectangle()
|
||||
.frame(height: 1.5)
|
||||
.foregroundColor(Asset.Colors.TextField.Underline.purple.color)
|
||||
|
||||
Rectangle()
|
||||
.frame(height: 1.5)
|
||||
.foregroundColor(Asset.Colors.TextField.Underline.gray.color)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// TextFieldInput.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Adam Stener on 3/25/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import ComposableArchitecture
|
||||
|
||||
struct TextFieldInput: View {
|
||||
let placeholder: String
|
||||
let store: TextFieldStore
|
||||
|
||||
var body: some View {
|
||||
WithViewStore(store) { viewStore in
|
||||
TextField(
|
||||
placeholder,
|
||||
text: Binding(
|
||||
get: { viewStore.state.text },
|
||||
set: { viewStore.send(.set($0)) }
|
||||
)
|
||||
)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.middle)
|
||||
.accentColor(Asset.Colors.Cursor.bar.color)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
// TextFieldStore.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Adam Stener on 3/8/22.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
typealias TextFieldReducer = Reducer<TextFieldState, TextFieldAction, TextFieldEnvironment>
|
||||
typealias TextFieldStore = Store<TextFieldState, TextFieldAction>
|
||||
|
||||
struct TextFieldState: Equatable {
|
||||
var validationType: String.ValidationType?
|
||||
var text: String
|
||||
var valid = false
|
||||
|
||||
init(validationType: String.ValidationType?, text: String) {
|
||||
self.validationType = validationType
|
||||
self.text = text
|
||||
}
|
||||
}
|
||||
|
||||
enum TextFieldAction {
|
||||
case apply((String) -> String)
|
||||
case set(String)
|
||||
}
|
||||
|
||||
struct TextFieldEnvironment: Equatable { }
|
||||
|
||||
extension TextFieldReducer {
|
||||
static let `default` = TextFieldReducer { state, action, _ in
|
||||
switch action {
|
||||
case .apply(let action):
|
||||
state.text = action(state.text)
|
||||
state.valid = state.text.isValid(for: state.validationType)
|
||||
|
||||
case .set(let text):
|
||||
state.text = text
|
||||
state.valid = state.text.isValid(for: state.validationType)
|
||||
}
|
||||
return .none
|
||||
}
|
||||
}
|
||||
|
||||
extension TextFieldStore {
|
||||
static var transaction: Self {
|
||||
.init(
|
||||
initialState: .init(validationType: .floatingPoint, text: ""),
|
||||
reducer: .default,
|
||||
environment: .init()
|
||||
)
|
||||
}
|
||||
|
||||
static var address: Self {
|
||||
.init(
|
||||
initialState: .init(validationType: .email, text: ""),
|
||||
reducer: .default,
|
||||
environment: .init()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// TextFieldTitleAccessoryButtonStyle.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Adam Stener on 2/9/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct TextFieldTitleAccessoryButtonStyle: ButtonStyle {
|
||||
func makeBody(configuration: Configuration) -> some View {
|
||||
configuration.label
|
||||
.padding(.horizontal, 10)
|
||||
.padding(.vertical, 3)
|
||||
.foregroundColor(.white)
|
||||
.background(
|
||||
configuration.isPressed ?
|
||||
Asset.Colors.TextField.titleAccessoryButtonPressed.color :
|
||||
Asset.Colors.TextField.titleAccessoryButton.color
|
||||
)
|
||||
.cornerRadius(6)
|
||||
}
|
||||
}
|
||||
|
||||
extension Button {
|
||||
var textFieldTitleAccessoryButtonStyle: some View {
|
||||
buttonStyle(TextFieldTitleAccessoryButtonStyle())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
//
|
||||
// ExchangeStore.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Adam Stener on 3/8/22.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
typealias CurrencySelectionReducer = Reducer<
|
||||
CurrencySelectionState,
|
||||
CurrencySelectionAction,
|
||||
CurrencySelectionEnvironment
|
||||
>
|
||||
|
||||
typealias CurrencySelectionStore = Store<CurrencySelectionState, CurrencySelectionAction>
|
||||
|
||||
struct CurrencySelectionState: Equatable {
|
||||
enum Currency: Equatable {
|
||||
case usd
|
||||
case zec
|
||||
|
||||
var acronym: String {
|
||||
switch self {
|
||||
case .usd: return "USD"
|
||||
case .zec: return "ZEC"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var currencyType: Currency = .zec
|
||||
}
|
||||
|
||||
enum CurrencySelectionAction: Equatable {
|
||||
case swapCurrencyType
|
||||
}
|
||||
|
||||
struct CurrencySelectionEnvironment: Equatable { }
|
||||
|
||||
extension CurrencySelectionReducer {
|
||||
static var `default`: Self {
|
||||
.init { state, action, _ in
|
||||
switch action {
|
||||
case .swapCurrencyType:
|
||||
switch state.currencyType {
|
||||
case .usd: state.currencyType = .zec
|
||||
case .zec: state.currencyType = .usd
|
||||
}
|
||||
}
|
||||
return .none
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// TransactionCurrencySelector.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Adam Stener on 4/4/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import ComposableArchitecture
|
||||
|
||||
struct TransactionCurrencySelector: View {
|
||||
let store: CurrencySelectionStore
|
||||
|
||||
var body: some View {
|
||||
WithViewStore(store) { viewStore in
|
||||
Button(
|
||||
action: { viewStore.send(.swapCurrencyType) },
|
||||
label: {
|
||||
HStack {
|
||||
Text(CurrencySelectionState.Currency.usd.acronym)
|
||||
.foregroundColor(
|
||||
viewStore.currencyType == .usd ? .yellow : .white
|
||||
)
|
||||
|
||||
Asset.Assets.Icons.swap.image
|
||||
|
||||
Text(CurrencySelectionState.Currency.zec.acronym)
|
||||
.foregroundColor(
|
||||
viewStore.currencyType == .zec ? .yellow : .white
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
//
|
||||
// TransactionInputStore.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Adam Stener on 4/5/22.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
typealias TransactionInputReducer = Reducer<
|
||||
TransactionInputState,
|
||||
TransactionInputAction,
|
||||
TransactionInputEnvironment
|
||||
>
|
||||
typealias TransactionReducerData = (inout TransactionInputState, TransactionInputAction) -> Void
|
||||
typealias TransactionInputStore = Store<TransactionInputState, TransactionInputAction>
|
||||
|
||||
struct TransactionInputState: Equatable {
|
||||
var textFieldState: TextFieldState
|
||||
var currencySelectionState: CurrencySelectionState
|
||||
}
|
||||
|
||||
enum TransactionInputAction {
|
||||
case setMax(Double)
|
||||
case textField(TextFieldAction)
|
||||
case currencySelection(CurrencySelectionAction)
|
||||
}
|
||||
|
||||
struct TransactionInputEnvironment: Equatable {}
|
||||
|
||||
func maxOverride(_ reducer: @escaping (TransactionReducerData)) -> TransactionReducerData {
|
||||
return { state, action in
|
||||
switch action {
|
||||
case .setMax(let value):
|
||||
state.textFieldState.text = "\(value)"
|
||||
state.currencySelectionState.currencyType = .usd
|
||||
|
||||
default: break
|
||||
}
|
||||
|
||||
reducer(&state, action)
|
||||
}
|
||||
}
|
||||
|
||||
extension TransactionInputReducer {
|
||||
static let `default` = TransactionInputReducer.combine(
|
||||
[
|
||||
textFieldReducer,
|
||||
currencySelectionReducer,
|
||||
maxOverride,
|
||||
currencyUpdate
|
||||
]
|
||||
)
|
||||
|
||||
static let maxOverride = TransactionInputReducer { state, action, _ in
|
||||
switch action {
|
||||
case .setMax(let value):
|
||||
state.currencySelectionState.currencyType = .zec
|
||||
state.textFieldState.text = "\(value)"
|
||||
|
||||
default: break
|
||||
}
|
||||
|
||||
return .none
|
||||
}
|
||||
|
||||
static let currencyUpdate = TransactionInputReducer { state, action, _ in
|
||||
switch action {
|
||||
case .currencySelection:
|
||||
guard let currentDoubleValue = Double(state.textFieldState.text) else {
|
||||
return .none
|
||||
}
|
||||
|
||||
let currencyType = state.currencySelectionState.currencyType
|
||||
|
||||
// The 2100 is another hard coded value (🚀🌒) but the store could
|
||||
// have a dependency injected that would be responsible for
|
||||
// providing the current exchange rate.
|
||||
let newValue = currencyType == .zec ?
|
||||
currentDoubleValue / 2100 :
|
||||
currentDoubleValue * 2100
|
||||
state.textFieldState.text = "\(newValue)"
|
||||
|
||||
default: break
|
||||
}
|
||||
|
||||
return .none
|
||||
}
|
||||
|
||||
private static let textFieldReducer: TransactionInputReducer = TextFieldReducer.default.pullback(
|
||||
state: \TransactionInputState.textFieldState,
|
||||
action: /TransactionInputAction.textField,
|
||||
environment: { _ in return .init() }
|
||||
)
|
||||
|
||||
private static let currencySelectionReducer: TransactionInputReducer = CurrencySelectionReducer.default.pullback(
|
||||
state: \TransactionInputState.currencySelectionState,
|
||||
action: /TransactionInputAction.currencySelection,
|
||||
environment: { _ in return .init() }
|
||||
)
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// TransactionTextField.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Adam Stener on 4/4/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import ComposableArchitecture
|
||||
|
||||
struct TransactionTextField: View {
|
||||
let store: TransactionInputStore
|
||||
|
||||
// Constant example used here, this could be injected by a dependency
|
||||
// Access to this value could also be injected into the store as a dependency
|
||||
// with a function to prouce this value.
|
||||
let maxTransactionValue = 500.0
|
||||
|
||||
var body: some View {
|
||||
WithViewStore(store) { viewStore in
|
||||
VStack {
|
||||
SingleLineTextField(
|
||||
placeholderText: "$0",
|
||||
title: "How much?",
|
||||
store: store.scope(
|
||||
state: \.textFieldState,
|
||||
action: TransactionInputAction.textField
|
||||
),
|
||||
titleAccessoryView: {
|
||||
Button(
|
||||
action: {
|
||||
viewStore.send(.setMax(maxTransactionValue))
|
||||
},
|
||||
label: { Text("Max") }
|
||||
)
|
||||
.textFieldTitleAccessoryButtonStyle
|
||||
},
|
||||
inputAccessoryView: {
|
||||
TransactionCurrencySelector(
|
||||
store: store.scope(
|
||||
state: \.currencySelectionState,
|
||||
action: TransactionInputAction.currencySelection
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TransactionTextField_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
TransactionTextField(
|
||||
store: TransactionInputStore(
|
||||
initialState: .init(
|
||||
textFieldState: .init(
|
||||
validationType: .floatingPoint,
|
||||
text: ""
|
||||
),
|
||||
currencySelectionState: .init(currencyType: .usd)
|
||||
),
|
||||
reducer: .default,
|
||||
environment: .init()
|
||||
)
|
||||
)
|
||||
.preferredColorScheme(.dark)
|
||||
.padding(.horizontal, 50)
|
||||
.applyScreenBackground()
|
||||
.previewLayout(.fixed(width: 500, height: 200))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// DebugFrame.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Adam Stener on 3/25/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct DebugFrame: ViewModifier {
|
||||
let color: Color
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.overlay(
|
||||
Rectangle()
|
||||
.strokeBorder(
|
||||
style: StrokeStyle(
|
||||
lineWidth: 0.5,
|
||||
dash: [3]
|
||||
)
|
||||
)
|
||||
)
|
||||
.foregroundColor(color)
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
func debug(_ color: Color) -> some View {
|
||||
modifier(DebugFrame(color: color))
|
||||
}
|
||||
}
|
|
@ -8,3 +8,57 @@ extension String {
|
|||
self.init(stringLiteral: output)
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
// TODO: Issue #245 Add Validation Regex that support localization
|
||||
private static let floatingPointRegex = "^[0-9]*.?[0-9]+"
|
||||
private static let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}"
|
||||
private static let phoneRegex = "^^\\+(?:[0-9]?){6,14}[0-9]$"
|
||||
|
||||
public enum ValidationType: Equatable {
|
||||
case custom(String)
|
||||
case email
|
||||
case floatingPoint
|
||||
case maxLength(Int)
|
||||
case minLength(Int)
|
||||
case phoneNumber
|
||||
|
||||
func isValid(text: String) -> Bool {
|
||||
switch self {
|
||||
case .custom(let regex):
|
||||
return text.validate(using: regex)
|
||||
|
||||
case .email:
|
||||
return text.validate(using: .emailRegex)
|
||||
|
||||
case .floatingPoint:
|
||||
return text.validate(using: .floatingPointRegex)
|
||||
|
||||
case .maxLength(let length):
|
||||
return text.count <= length && !text.isEmpty
|
||||
|
||||
case .minLength(let length):
|
||||
return text.count >= length
|
||||
|
||||
case .phoneNumber:
|
||||
return text.validate(using: .phoneRegex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func validate(using regex: String) -> Bool {
|
||||
guard let regex = try? NSRegularExpression(pattern: regex) else { return false }
|
||||
|
||||
return regex.firstMatch(
|
||||
in: self,
|
||||
options: [],
|
||||
range: NSRange(location: 0, length: self.utf16.count)
|
||||
) != nil
|
||||
}
|
||||
|
||||
public func isValid(for validationType: ValidationType?) -> Bool {
|
||||
guard let validationType = validationType else { return true }
|
||||
|
||||
return validationType.isValid(text: self)
|
||||
}
|
||||
}
|
||||
|
|