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>
This commit is contained in:
Adam 2022-04-07 07:06:47 -05:00 committed by GitHub
parent e2d973b984
commit b665a18fe2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 1010 additions and 5 deletions

View File

@ -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 */,

View File

@ -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"
}
},
{

View File

@ -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
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 770 B

View File

@ -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
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 552 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 B

View File

@ -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
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -25,7 +25,7 @@ struct HomeView: View {
reducer: SendReducer.default(
whenDone: { HomeViewStore(store).send(.updateRoute(nil)) }
)
.debug(),
.debug(),
environment: ()
)
)

View File

@ -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")

View File

@ -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))
}
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}

View File

@ -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()
)
}
}

View File

@ -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())
}
}

View File

@ -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
}
}
}

View File

@ -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
)
}
}
)
}
}
}

View File

@ -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() }
)
}

View File

@ -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))
}
}

View File

@ -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))
}
}

View File

@ -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)
}
}