- async adaptations of the latest sdk - review request TCA dependency added - set of rules for the triggering the app rating dialog - unit tests fixed - unit tests for the review request client - app review request logic disconnected from the production for now (added the TODO for the triggering)
This commit is contained in:
parent
36d2090654
commit
a727f49817
|
@ -363,6 +363,9 @@
|
|||
9E153A7529216EFB00112F41 /* UserDefaultsLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E153A7229216EFB00112F41 /* UserDefaultsLiveKey.swift */; };
|
||||
9E153A7629216EFB00112F41 /* UserDefaultsInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E153A7329216EFB00112F41 /* UserDefaultsInterface.swift */; };
|
||||
9E153A7729216EFB00112F41 /* UserDefaultsTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E153A7429216EFB00112F41 /* UserDefaultsTestKey.swift */; };
|
||||
9E2A07B729DAE0A900F2B086 /* ReviewRequestTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2A07B429DAE0A900F2B086 /* ReviewRequestTestKey.swift */; };
|
||||
9E2A07B829DAE0A900F2B086 /* ReviewRequestLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2A07B529DAE0A900F2B086 /* ReviewRequestLiveKey.swift */; };
|
||||
9E2A07B929DAE0A900F2B086 /* ReviewRequestInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2A07B629DAE0A900F2B086 /* ReviewRequestInterface.swift */; };
|
||||
9E2AC0FF27D8EC120042AA47 /* MnemonicSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 9E2AC0FE27D8EC120042AA47 /* MnemonicSwift */; };
|
||||
9E2DF99C27CF704D00649636 /* ImportWalletStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2DF99827CF704D00649636 /* ImportWalletStore.swift */; };
|
||||
9E2DF99D27CF704D00649636 /* ImportSeedEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2DF99A27CF704D00649636 /* ImportSeedEditor.swift */; };
|
||||
|
@ -456,6 +459,16 @@
|
|||
9E69A24D27FB002800A55317 /* WelcomeStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E69A24C27FB002800A55317 /* WelcomeStore.swift */; };
|
||||
9E7225F3288AB6DD00DF7F17 /* MultipleLineTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7225F2288AB6DD00DF7F17 /* MultipleLineTextField.swift */; };
|
||||
9E7225F6288AC71A00DF7F17 /* MultiLineTextFieldStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7225F5288AC71A00DF7F17 /* MultiLineTextFieldStore.swift */; };
|
||||
9E74CCC529DC04E8003D6E32 /* DateTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E74CCC229DC04E8003D6E32 /* DateTestKey.swift */; };
|
||||
9E74CCC629DC04E8003D6E32 /* DateTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E74CCC229DC04E8003D6E32 /* DateTestKey.swift */; };
|
||||
9E74CCC729DC04E8003D6E32 /* DateInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E74CCC329DC04E8003D6E32 /* DateInterface.swift */; };
|
||||
9E74CCC829DC04E8003D6E32 /* DateInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E74CCC329DC04E8003D6E32 /* DateInterface.swift */; };
|
||||
9E74CCC929DC04E8003D6E32 /* DateLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E74CCC429DC04E8003D6E32 /* DateLiveKey.swift */; };
|
||||
9E74CCCA29DC04E8003D6E32 /* DateLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E74CCC429DC04E8003D6E32 /* DateLiveKey.swift */; };
|
||||
9E74CCCB29DC04ED003D6E32 /* ReviewRequestInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2A07B629DAE0A900F2B086 /* ReviewRequestInterface.swift */; };
|
||||
9E74CCCC29DC04ED003D6E32 /* ReviewRequestLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2A07B529DAE0A900F2B086 /* ReviewRequestLiveKey.swift */; };
|
||||
9E74CCCD29DC04ED003D6E32 /* ReviewRequestTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2A07B429DAE0A900F2B086 /* ReviewRequestTestKey.swift */; };
|
||||
9E74CCD029DC0628003D6E32 /* ReviewRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E74CCCF29DC0628003D6E32 /* ReviewRequestTests.swift */; };
|
||||
9E7CB6152869E8C300A02233 /* CircularProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7CB6142869E8C300A02233 /* CircularProgress.swift */; };
|
||||
9E7CB61A287310EC00A02233 /* QRCodeGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7CB619287310EC00A02233 /* QRCodeGenerator.swift */; };
|
||||
9E7CB6202874143800A02233 /* AddressDetailsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7CB61F2874143800A02233 /* AddressDetailsStore.swift */; };
|
||||
|
@ -713,6 +726,9 @@
|
|||
9E153A7429216EFB00112F41 /* UserDefaultsTestKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefaultsTestKey.swift; sourceTree = "<group>"; };
|
||||
9E207C352966EC77003E2C9B /* AddressDetailsSnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressDetailsSnapshotTests.swift; sourceTree = "<group>"; };
|
||||
9E207C382966EF87003E2C9B /* AddressDetailsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressDetailsTests.swift; sourceTree = "<group>"; };
|
||||
9E2A07B429DAE0A900F2B086 /* ReviewRequestTestKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReviewRequestTestKey.swift; sourceTree = "<group>"; };
|
||||
9E2A07B529DAE0A900F2B086 /* ReviewRequestLiveKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReviewRequestLiveKey.swift; sourceTree = "<group>"; };
|
||||
9E2A07B629DAE0A900F2B086 /* ReviewRequestInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReviewRequestInterface.swift; sourceTree = "<group>"; };
|
||||
9E2DF99827CF704D00649636 /* ImportWalletStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportWalletStore.swift; sourceTree = "<group>"; };
|
||||
9E2DF99A27CF704D00649636 /* ImportSeedEditor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportSeedEditor.swift; sourceTree = "<group>"; };
|
||||
9E2DF99B27CF704D00649636 /* ImportWalletView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportWalletView.swift; sourceTree = "<group>"; };
|
||||
|
@ -759,6 +775,10 @@
|
|||
9E7225F02889539300DF7F17 /* SettingsSnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSnapshotTests.swift; sourceTree = "<group>"; };
|
||||
9E7225F2288AB6DD00DF7F17 /* MultipleLineTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultipleLineTextField.swift; sourceTree = "<group>"; };
|
||||
9E7225F5288AC71A00DF7F17 /* MultiLineTextFieldStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiLineTextFieldStore.swift; sourceTree = "<group>"; };
|
||||
9E74CCC229DC04E8003D6E32 /* DateTestKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateTestKey.swift; sourceTree = "<group>"; };
|
||||
9E74CCC329DC04E8003D6E32 /* DateInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateInterface.swift; sourceTree = "<group>"; };
|
||||
9E74CCC429DC04E8003D6E32 /* DateLiveKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateLiveKey.swift; sourceTree = "<group>"; };
|
||||
9E74CCCF29DC0628003D6E32 /* ReviewRequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewRequestTests.swift; sourceTree = "<group>"; };
|
||||
9E7CB6112869882D00A02233 /* WalletEventsSnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletEventsSnapshotTests.swift; sourceTree = "<group>"; };
|
||||
9E7CB6142869E8C300A02233 /* CircularProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircularProgress.swift; sourceTree = "<group>"; };
|
||||
9E7CB619287310EC00A02233 /* QRCodeGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeGenerator.swift; sourceTree = "<group>"; };
|
||||
|
@ -1030,6 +1050,7 @@
|
|||
6654C7422715A48E00901167 /* OnboardingTests */,
|
||||
9E7CB6222874245400A02233 /* ProfileTests */,
|
||||
0DFE93E4272CB6D0000FCCA5 /* RecoveryPhraseValidationTests */,
|
||||
9E74CCCE29DC060B003D6E32 /* ReviewRequestTests */,
|
||||
9EAFEB802805791400199FC9 /* RootTests */,
|
||||
9E01F8262833CD84000EFC57 /* ScanTests */,
|
||||
9E5BF642281FEC8700BA3F17 /* SendTests */,
|
||||
|
@ -1416,6 +1437,16 @@
|
|||
path = AddressDetailsTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E2A07B329DAE07E00F2B086 /* ReviewRequest */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E2A07B629DAE0A900F2B086 /* ReviewRequestInterface.swift */,
|
||||
9E2A07B529DAE0A900F2B086 /* ReviewRequestLiveKey.swift */,
|
||||
9E2A07B429DAE0A900F2B086 /* ReviewRequestTestKey.swift */,
|
||||
);
|
||||
path = ReviewRequest;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E2DF99727CF704D00649636 /* ImportWallet */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1603,6 +1634,24 @@
|
|||
path = MultiLineTextField;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E74CCC129DC0476003D6E32 /* Date */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E74CCC329DC04E8003D6E32 /* DateInterface.swift */,
|
||||
9E74CCC429DC04E8003D6E32 /* DateLiveKey.swift */,
|
||||
9E74CCC229DC04E8003D6E32 /* DateTestKey.swift */,
|
||||
);
|
||||
path = Date;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E74CCCE29DC060B003D6E32 /* ReviewRequestTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E74CCCF29DC0628003D6E32 /* ReviewRequestTests.swift */,
|
||||
);
|
||||
path = ReviewRequestTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E7CB6102869881300A02233 /* WalletEventsSnapshotTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1700,6 +1749,7 @@
|
|||
9E7FE0BD282D1DE100C374E8 /* Dependencies */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E74CCC129DC0476003D6E32 /* Date */,
|
||||
9EBDF978291F7E85000A1A05 /* AppVersion */,
|
||||
9EBDF962291ECD42000A1A05 /* AudioServices */,
|
||||
9EBDF969291ECEAC000A1A05 /* CaptureDevice */,
|
||||
|
@ -1716,6 +1766,7 @@
|
|||
9EB8638F2922D000003D0F8B /* NumberFormatter */,
|
||||
9E153A6329210AF800112F41 /* Pasteboard */,
|
||||
9EB863A329239D95003D0F8B /* RecoveryPhraseRandomizer */,
|
||||
9E2A07B329DAE07E00F2B086 /* ReviewRequest */,
|
||||
9EB863B62923C539003D0F8B /* SDKSynchronizer */,
|
||||
9EB863B32923C465003D0F8B /* SecItem */,
|
||||
3467319729AE36F000974482 /* SupportDataGenerator */,
|
||||
|
@ -2638,6 +2689,7 @@
|
|||
0D26AEB8299E8196005260EE /* FileManagerInterface.swift in Sources */,
|
||||
0D26AEBA299E8196005260EE /* AddressDetailsStore.swift in Sources */,
|
||||
0D26AEBB299E8196005260EE /* RecoveryPhraseBackupSucceededView.swift in Sources */,
|
||||
9E74CCCA29DC04E8003D6E32 /* DateLiveKey.swift in Sources */,
|
||||
0D26AEBC299E8196005260EE /* TCATextFieldStore.swift in Sources */,
|
||||
0D26AEBE299E8196005260EE /* SecantTextStyles.swift in Sources */,
|
||||
0D26AEBF299E8196005260EE /* TransactionFailedView.swift in Sources */,
|
||||
|
@ -2648,8 +2700,10 @@
|
|||
0D26AEC5299E8196005260EE /* RecoveryPhraseValidationFlowStore.swift in Sources */,
|
||||
9E486DFA29BA09C2003E6945 /* UIKit+Extensions.swift in Sources */,
|
||||
9E33ECDA29D5E30700708DE4 /* OnChangeReducer.swift in Sources */,
|
||||
9E74CCC629DC04E8003D6E32 /* DateTestKey.swift in Sources */,
|
||||
0D26AEC6299E8196005260EE /* ImportWalletView.swift in Sources */,
|
||||
0D26AEC7299E8196005260EE /* RootInitialization.swift in Sources */,
|
||||
9E74CCCC29DC04ED003D6E32 /* ReviewRequestLiveKey.swift in Sources */,
|
||||
0D26AEC8299E8196005260EE /* LogsHandlerLive.swift in Sources */,
|
||||
0D26AEC9299E8196005260EE /* AudioServicesTestKey.swift in Sources */,
|
||||
0D26AECA299E8196005260EE /* EnumeratedChip.swift in Sources */,
|
||||
|
@ -2692,6 +2746,7 @@
|
|||
0D26AEEB299E8196005260EE /* Previews.swift in Sources */,
|
||||
0D26AEEC299E8196005260EE /* FeedbackGeneratorInterface.swift in Sources */,
|
||||
0D26AEED299E8196005260EE /* PhraseChip.swift in Sources */,
|
||||
9E74CCCD29DC04ED003D6E32 /* ReviewRequestTestKey.swift in Sources */,
|
||||
0D26AEEE299E8196005260EE /* QRCodeScanView.swift in Sources */,
|
||||
0D26AEEF299E8196005260EE /* ZcashSDKEnvironmentTestKey.swift in Sources */,
|
||||
0D26AEF0299E8196005260EE /* TCALoggerReducer.swift in Sources */,
|
||||
|
@ -2707,6 +2762,7 @@
|
|||
0D26AEFA299E8196005260EE /* DesignGuide.swift in Sources */,
|
||||
0D26AEFB299E8196005260EE /* SensitiveData.swift in Sources */,
|
||||
0D26AEFC299E8196005260EE /* RootStore.swift in Sources */,
|
||||
9E74CCCB29DC04ED003D6E32 /* ReviewRequestInterface.swift in Sources */,
|
||||
0D26AEFD299E8196005260EE /* HomeView.swift in Sources */,
|
||||
0D26AEFE299E8196005260EE /* NavigationLinks.swift in Sources */,
|
||||
0D26AEFF299E8196005260EE /* SandboxView.swift in Sources */,
|
||||
|
@ -2816,6 +2872,7 @@
|
|||
0D26AF65299E8196005260EE /* InitializationState.swift in Sources */,
|
||||
0D26AF66299E8196005260EE /* ZcashSymbol.swift in Sources */,
|
||||
0D26AF67299E8196005260EE /* UserPreferencesStorageLive.swift in Sources */,
|
||||
9E74CCC829DC04E8003D6E32 /* DateInterface.swift in Sources */,
|
||||
9E486DF429B9EEC4003E6945 /* UIResponder+Current.swift in Sources */,
|
||||
0D26AF68299E8196005260EE /* TransactionAmountTextField.swift in Sources */,
|
||||
0D26AF69299E8196005260EE /* AddressDetailsView.swift in Sources */,
|
||||
|
@ -2836,6 +2893,7 @@
|
|||
9E7FE0DF282D2DD600C374E8 /* ZcashBadge.swift in Sources */,
|
||||
34F682F229A764120022C079 /* WalletConfigProviderLiveKey.swift in Sources */,
|
||||
0D261040298C406F00CC9DE9 /* CrashReporterTestKey.swift in Sources */,
|
||||
9E74CCC929DC04E8003D6E32 /* DateLiveKey.swift in Sources */,
|
||||
9EBDF975291F79F9000A1A05 /* DerivationToolInterface.swift in Sources */,
|
||||
660558F8270C862F009D6954 /* XCAssets+Generated.swift in Sources */,
|
||||
9EAFEB902808183D00199FC9 /* SandboxStore.swift in Sources */,
|
||||
|
@ -2844,6 +2902,7 @@
|
|||
9E39114A2848EEB90073DD9A /* UserPreferencesStorage.swift in Sources */,
|
||||
9E153A612920CE2700112F41 /* MnemonicMocks.swift in Sources */,
|
||||
34DA414728E4385800F8CC61 /* TransactionSendingView.swift in Sources */,
|
||||
9E74CCC729DC04E8003D6E32 /* DateInterface.swift in Sources */,
|
||||
F96B41E9273B501F0021B49A /* WalletEventsFlowView.swift in Sources */,
|
||||
9E4AA4F829BF76BB00752BB3 /* About.swift in Sources */,
|
||||
9E33ECD429D5D99000708DE4 /* AlertRequest.swift in Sources */,
|
||||
|
@ -2876,6 +2935,7 @@
|
|||
9EAB467A2861EA6A002904A0 /* TransactionRowView.swift in Sources */,
|
||||
9EB8638C2922CD4A003D0F8B /* FeedbackGeneratorTestKey.swift in Sources */,
|
||||
9E0F5741297E7F1D005304FA /* TCALogging.swift in Sources */,
|
||||
9E74CCC529DC04E8003D6E32 /* DateTestKey.swift in Sources */,
|
||||
0DFE93E3272CA1AA000FCCA5 /* RecoveryPhraseValidationFlowStore.swift in Sources */,
|
||||
9E9CEA3E29D47BE000599DF5 /* OnChangeReducer.swift in Sources */,
|
||||
9E486DF929BA09C2003E6945 /* UIKit+Extensions.swift in Sources */,
|
||||
|
@ -2885,6 +2945,7 @@
|
|||
9EBDF967291ECDA2000A1A05 /* AudioServicesTestKey.swift in Sources */,
|
||||
0D535FE2271F9476009A9E3E /* EnumeratedChip.swift in Sources */,
|
||||
9EBDF97E291F7EB0000A1A05 /* AppVersionInterface.swift in Sources */,
|
||||
9E2A07B829DAE0A900F2B086 /* ReviewRequestLiveKey.swift in Sources */,
|
||||
6654C73E2715A41300901167 /* OnboardingFlowStore.swift in Sources */,
|
||||
9EB863CB2923CA20003D0F8B /* SDKSynchronizerLive.swift in Sources */,
|
||||
9EB863A1292398A8003D0F8B /* URIParserInterface.swift in Sources */,
|
||||
|
@ -2938,6 +2999,7 @@
|
|||
0DB8AA81271DC7520035BC9D /* DesignGuide.swift in Sources */,
|
||||
9E612C7E2991491200D09B09 /* SensitiveData.swift in Sources */,
|
||||
F9971A4D27680DC400A2DB75 /* RootStore.swift in Sources */,
|
||||
9E2A07B729DAE0A900F2B086 /* ReviewRequestTestKey.swift in Sources */,
|
||||
9EAFEB9228081E9400199FC9 /* HomeView.swift in Sources */,
|
||||
F9322DC0273B555C00C105B5 /* NavigationLinks.swift in Sources */,
|
||||
9EAFEB8F2808183D00199FC9 /* SandboxView.swift in Sources */,
|
||||
|
@ -3024,6 +3086,7 @@
|
|||
9E612C7629880FC900D09B09 /* LogsHandlerTest.swift in Sources */,
|
||||
2EDA07A227EDE1AE00D6F09B /* TextFieldFooter.swift in Sources */,
|
||||
0D26103C298C3E4800CC9DE9 /* CrashReportingInterface.swift in Sources */,
|
||||
9E2A07B929DAE0A900F2B086 /* ReviewRequestInterface.swift in Sources */,
|
||||
346731A229AE3A5100974482 /* UIMailDialog.swift in Sources */,
|
||||
F9971A5427680DD000A2DB75 /* ProfileView.swift in Sources */,
|
||||
F9971A6027680DF600A2DB75 /* ScanStore.swift in Sources */,
|
||||
|
@ -3090,6 +3153,7 @@
|
|||
9E3451A729C84E9900177D16 /* AppInitializationTests.swift in Sources */,
|
||||
9E3451B029C855E600177D16 /* SettingsTests.swift in Sources */,
|
||||
9E34519F29C849D300177D16 /* ImportWalletTests.swift in Sources */,
|
||||
9E74CCD029DC0628003D6E32 /* ReviewRequestTests.swift in Sources */,
|
||||
9E3451A029C84A2D00177D16 /* MultiLineTextFieldTests.swift in Sources */,
|
||||
9E3451B729C8565500177D16 /* DatabaseFilesTests.swift in Sources */,
|
||||
9E3451B129C8565500177D16 /* UserPreferencesStorageTests.swift in Sources */,
|
||||
|
@ -3579,7 +3643,7 @@
|
|||
repositoryURL = "https://github.com/pointfreeco/swift-url-routing";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 0.3.1;
|
||||
minimumVersion = 0.5.0;
|
||||
};
|
||||
};
|
||||
34CE032929C0938600A6626B /* XCRemoteSwiftPackageReference "ZcashLightClientKit" */ = {
|
||||
|
@ -3587,7 +3651,7 @@
|
|||
repositoryURL = "https://github.com/zcash/ZcashLightClientKit.git";
|
||||
requirement = {
|
||||
kind = revision;
|
||||
revision = 52d5e0085094002fb64d5042b191f106bfbe710c;
|
||||
revision = 16d70cfead166ae214bc813fd245d3eb62588cfd;
|
||||
};
|
||||
};
|
||||
6654C7382715A38000901167 /* XCRemoteSwiftPackageReference "swift-composable-architecture" */ = {
|
||||
|
@ -3619,7 +3683,7 @@
|
|||
repositoryURL = "https://github.com/pointfreeco/swift-parsing";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 0.9.2;
|
||||
minimumVersion = 0.12.0;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
|
|
@ -284,8 +284,8 @@
|
|||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pointfreeco/swift-parsing",
|
||||
"state" : {
|
||||
"revision" : "4bb9192468c1a8be57f46b7d6fd4f561c88b2195",
|
||||
"version" : "0.11.0"
|
||||
"revision" : "c6e2241daa46e5c6e5027a93b161bca6ba692bcc",
|
||||
"version" : "0.12.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -302,8 +302,8 @@
|
|||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pointfreeco/swift-url-routing",
|
||||
"state" : {
|
||||
"revision" : "f54c4f74e7884f7930560c08387817ce28271770",
|
||||
"version" : "0.4.0"
|
||||
"revision" : "2f4f0404b3de0a0711feb7190f724d8a80bc1cfd",
|
||||
"version" : "0.5.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -338,7 +338,7 @@
|
|||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/zcash/ZcashLightClientKit.git",
|
||||
"state" : {
|
||||
"revision" : "52d5e0085094002fb64d5042b191f106bfbe710c"
|
||||
"revision" : "16d70cfead166ae214bc813fd245d3eb62588cfd"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// DateClient.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 04.04.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
|
||||
extension DependencyValues {
|
||||
var date: DateClient {
|
||||
get { self[DateClient.self] }
|
||||
set { self[DateClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct DateClient {
|
||||
let now: () -> Date
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// DateLiveKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 04.04.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
|
||||
extension DateClient: DependencyKey {
|
||||
static let liveValue = Self(
|
||||
now: { Date.now }
|
||||
)
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// DateTestKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension DateClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
now: XCTUnimplemented("\(Self.self).now", placeholder: Date.now)
|
||||
)
|
||||
}
|
|
@ -13,7 +13,7 @@ import ZcashLightClientKit
|
|||
struct Deeplink {
|
||||
enum Destination: Equatable {
|
||||
case home
|
||||
case send(amount: Int64, address: String, memo: String)
|
||||
case send(amount: Int, address: String, memo: String)
|
||||
}
|
||||
|
||||
func resolveDeeplinkURL(_ url: URL, isValidZcashAddress: (String) throws -> Bool) throws -> Destination {
|
||||
|
@ -25,7 +25,7 @@ struct Deeplink {
|
|||
return .send(amount: 0, address: address, memo: "")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// regular URL format zcash://
|
||||
let appRouter = OneOf {
|
||||
// GET /home
|
||||
|
@ -37,7 +37,7 @@ struct Deeplink {
|
|||
Route(.case(Destination.send(amount:address:memo:))) {
|
||||
Path { "home"; "send" }
|
||||
Query {
|
||||
Field("amount", default: 0) { Int64.parser() }
|
||||
Field("amount", default: 0) { Digits() }
|
||||
Field("address", .string, default: "")
|
||||
Field("memo", .string, default: "")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// ReviewRequestInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 3.4.2023.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
extension DependencyValues {
|
||||
var reviewRequest: ReviewRequestClient {
|
||||
get { self[ReviewRequestClient.self] }
|
||||
set { self[ReviewRequestClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct ReviewRequestClient {
|
||||
let canRequestReview: () -> Bool
|
||||
let foundTransactions: () async -> Void
|
||||
let reviewRequested: () async -> Void
|
||||
let syncFinished: () async -> Void
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// ReviewRequestLiveKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 3.4.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
|
||||
extension ReviewRequestClient: DependencyKey {
|
||||
static let liveValue = ReviewRequestClient.live()
|
||||
|
||||
static func live(
|
||||
appVersion: AppVersionClient = .liveValue,
|
||||
date: DateClient = .liveValue,
|
||||
userDefaults: UserDefaultsClient = .live()
|
||||
) -> Self {
|
||||
Self(
|
||||
canRequestReview: {
|
||||
// set of conditions that must be fulfilled in order to trigger review request
|
||||
|
||||
// the wallet must be synced
|
||||
guard userDefaults.objectForKey(Constants.latestSyncKey) != nil else { return false }
|
||||
|
||||
// the version is ether nil or latest review is from some older version
|
||||
let currentVersion = appVersion.appVersion()
|
||||
if let storedVersion = userDefaults.objectForKey(Constants.versionKey) as? String {
|
||||
guard currentVersion.compare(storedVersion, options: .numeric) == .orderedDescending else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// there has been at least one found transaction since the very first sync
|
||||
guard userDefaults.objectForKey(Constants.foundTransactionsKey) != nil else { return false }
|
||||
|
||||
return true
|
||||
},
|
||||
foundTransactions: {
|
||||
// only if there's the very first sync stored
|
||||
guard userDefaults.objectForKey(Constants.latestSyncKey) != nil else { return }
|
||||
await userDefaults.setValue(date.now().timeIntervalSince1970, Constants.foundTransactionsKey)
|
||||
},
|
||||
reviewRequested: {
|
||||
// the review has been requested, update the version and timestamp
|
||||
await userDefaults.setValue(date.now().timeIntervalSince1970, Constants.reviewRequestedKey)
|
||||
await userDefaults.setValue(appVersion.appVersion(), Constants.versionKey)
|
||||
},
|
||||
syncFinished: {
|
||||
// synchronizer's sync has been finished successfuly
|
||||
await userDefaults.setValue(date.now().timeIntervalSince1970, Constants.latestSyncKey)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal extension ReviewRequestClient {
|
||||
enum Constants: CaseIterable {
|
||||
static let foundTransactionsKey = "ReviewRequestClient.foundTransactions"
|
||||
static let latestSyncKey = "ReviewRequestClient.latestSyncKey"
|
||||
static let reviewRequestedKey = "ReviewRequestClient.reviewRequestedKey"
|
||||
static let versionKey = "ReviewRequestClient.versionKey"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// ReviewRequestTestKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 3.4.2023.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension ReviewRequestClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
canRequestReview: XCTUnimplemented("\(Self.self).canRequestReview", placeholder: false),
|
||||
foundTransactions: XCTUnimplemented("\(Self.self).foundTransactions"),
|
||||
reviewRequested: XCTUnimplemented("\(Self.self).reviewRequested"),
|
||||
syncFinished: XCTUnimplemented("\(Self.self).syncFinished")
|
||||
)
|
||||
}
|
||||
|
||||
extension ReviewRequestClient {
|
||||
static let noOp = Self(
|
||||
canRequestReview: { false },
|
||||
foundTransactions: { },
|
||||
reviewRequested: { },
|
||||
syncFinished: { }
|
||||
)
|
||||
}
|
|
@ -33,15 +33,15 @@ struct SDKSynchronizerClient {
|
|||
|
||||
let getShieldedBalance: () -> WalletBalance?
|
||||
let getTransparentBalance: () -> WalletBalance?
|
||||
let getAllSentTransactions: () -> EffectTask<[WalletEvent]>
|
||||
let getAllReceivedTransactions: () -> EffectTask<[WalletEvent]>
|
||||
let getAllClearedTransactions: () -> EffectTask<[WalletEvent]>
|
||||
let getAllPendingTransactions: () -> EffectTask<[WalletEvent]>
|
||||
let getAllTransactions: () -> EffectTask<[WalletEvent]>
|
||||
let getAllSentTransactions: () async throws -> [WalletEvent]
|
||||
let getAllReceivedTransactions: () async throws -> [WalletEvent]
|
||||
let getAllClearedTransactions: () async throws -> [WalletEvent]
|
||||
let getAllPendingTransactions: () async throws -> [WalletEvent]
|
||||
let getAllTransactions: () async throws -> [WalletEvent]
|
||||
|
||||
let getUnifiedAddress: (_ account: Int) -> UnifiedAddress?
|
||||
let getTransparentAddress: (_ account: Int) -> TransparentAddress?
|
||||
let getSaplingAddress: (_ accountIndex: Int) async -> SaplingAddress?
|
||||
let getUnifiedAddress: (_ account: Int) async throws -> UnifiedAddress?
|
||||
let getTransparentAddress: (_ account: Int) async throws -> TransparentAddress?
|
||||
let getSaplingAddress: (_ accountIndex: Int) async throws -> SaplingAddress?
|
||||
|
||||
let sendTransaction: (UnifiedSpendingKey, Zatoshi, Recipient, Memo?) -> EffectTask<Result<TransactionState, NSError>>
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ extension SDKSynchronizerClient: DependencyKey {
|
|||
spendParamsURL: databaseFiles.spendParamsURLFor(network),
|
||||
outputParamsURL: databaseFiles.outputParamsURLFor(network),
|
||||
saplingParamsSourceURL: SaplingParamsSourceURL.default,
|
||||
loggerProxy: OSLogger(logLevel: .debug, category: LoggerConstants.sdkLogs)
|
||||
logLevel: .debug
|
||||
)
|
||||
|
||||
let synchronizer = SDKSynchronizer(initializer: initializer)
|
||||
|
@ -53,79 +53,75 @@ extension SDKSynchronizerClient: DependencyKey {
|
|||
getShieldedBalance: { synchronizer.latestState.shieldedBalance },
|
||||
getTransparentBalance: { synchronizer.latestState.transparentBalance },
|
||||
getAllSentTransactions: {
|
||||
if let transactions = try? synchronizer.allSentTransactions() {
|
||||
return EffectTask(value: transactions.map {
|
||||
let memos = try? synchronizer.getMemos(for: $0)
|
||||
let transaction = TransactionState.init(transaction: $0, memos: memos)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
})
|
||||
let transactions = try await synchronizer.allSentTransactions()
|
||||
var walletEvents: [WalletEvent] = []
|
||||
for sentTransaction in transactions {
|
||||
let memos = try await synchronizer.getMemos(for: sentTransaction)
|
||||
let transaction = TransactionState.init(transaction: sentTransaction, memos: memos)
|
||||
walletEvents.append(WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp))
|
||||
}
|
||||
|
||||
return .none
|
||||
|
||||
return walletEvents
|
||||
},
|
||||
getAllReceivedTransactions: {
|
||||
if let transactions = try? synchronizer.allReceivedTransactions() {
|
||||
return EffectTask(value: transactions.map {
|
||||
let memos = try? synchronizer.getMemos(for: $0)
|
||||
let transaction = TransactionState.init(transaction: $0, memos: memos)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
})
|
||||
let transactions = try await synchronizer.allReceivedTransactions()
|
||||
var walletEvents: [WalletEvent] = []
|
||||
for receivedTransaction in transactions {
|
||||
let memos = try await synchronizer.getMemos(for: receivedTransaction)
|
||||
let transaction = TransactionState.init(transaction: receivedTransaction, memos: memos)
|
||||
walletEvents.append(WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp))
|
||||
}
|
||||
|
||||
return .none
|
||||
|
||||
return walletEvents
|
||||
},
|
||||
getAllClearedTransactions: {
|
||||
if let transactions = try? synchronizer.allClearedTransactions() {
|
||||
return EffectTask(value: transactions.map {
|
||||
let memos = try? synchronizer.getMemos(for: $0)
|
||||
let transaction = TransactionState.init(transaction: $0, memos: memos)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
})
|
||||
let transactions = try await synchronizer.allClearedTransactions()
|
||||
var walletEvents: [WalletEvent] = []
|
||||
for clearedTransaction in transactions {
|
||||
let memos = try await synchronizer.getMemos(for: clearedTransaction)
|
||||
let transaction = TransactionState.init(transaction: clearedTransaction, memos: memos)
|
||||
walletEvents.append(WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp))
|
||||
}
|
||||
|
||||
return .none
|
||||
|
||||
return walletEvents
|
||||
},
|
||||
getAllPendingTransactions: {
|
||||
if let transactions = try? synchronizer.allPendingTransactions() {
|
||||
return EffectTask(value: transactions.map {
|
||||
let transaction = TransactionState.init(pendingTransaction: $0, latestBlockHeight: synchronizer.latestScannedHeight)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
})
|
||||
let transactions = try await synchronizer.allPendingTransactions()
|
||||
var walletEvents: [WalletEvent] = []
|
||||
for pendingTransaction in transactions {
|
||||
let transaction = TransactionState.init(
|
||||
pendingTransaction: pendingTransaction,
|
||||
latestBlockHeight: synchronizer.latestScannedHeight
|
||||
)
|
||||
walletEvents.append(WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp))
|
||||
}
|
||||
|
||||
return .none
|
||||
|
||||
return walletEvents
|
||||
},
|
||||
getAllTransactions: {
|
||||
if let pendingTransactions = try? synchronizer.allPendingTransactions(),
|
||||
let clearedTransactions = try? synchronizer.allClearedTransactions() {
|
||||
let clearedTxs: [WalletEvent] = clearedTransactions.map {
|
||||
let transaction = TransactionState.init(transaction: $0)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
let pendingTxs: [WalletEvent] = pendingTransactions.map {
|
||||
let transaction = TransactionState.init(pendingTransaction: $0, latestBlockHeight: synchronizer.latestScannedHeight)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
let cTxs = clearedTxs.filter { transaction in
|
||||
pendingTxs.first { pending in
|
||||
pending.id == transaction.id
|
||||
} == nil
|
||||
}
|
||||
let pendingTransactions = try await synchronizer.allPendingTransactions()
|
||||
let clearedTransactions = try await synchronizer.allClearedTransactions()
|
||||
|
||||
return .merge(
|
||||
EffectTask(value: cTxs),
|
||||
EffectTask(value: pendingTxs)
|
||||
)
|
||||
.flatMap(Publishers.Sequence.init(sequence:))
|
||||
.collect()
|
||||
.eraseToEffect()
|
||||
let clearedTxs: [WalletEvent] = clearedTransactions.map {
|
||||
let transaction = TransactionState.init(transaction: $0)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
|
||||
return .none
|
||||
let pendingTxs: [WalletEvent] = pendingTransactions.map {
|
||||
let transaction = TransactionState.init(pendingTransaction: $0, latestBlockHeight: synchronizer.latestScannedHeight)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
var cTxs = clearedTxs.filter { transaction in
|
||||
pendingTxs.first { pending in
|
||||
pending.id == transaction.id
|
||||
} == nil
|
||||
}
|
||||
cTxs.append(contentsOf: pendingTxs)
|
||||
|
||||
return cTxs
|
||||
},
|
||||
getUnifiedAddress: { synchronizer.getUnifiedAddress(accountIndex: $0) },
|
||||
getTransparentAddress: { synchronizer.getTransparentAddress(accountIndex: $0) },
|
||||
getSaplingAddress: { await synchronizer.getSaplingAddress(accountIndex: $0) },
|
||||
getUnifiedAddress: { try await synchronizer.getUnifiedAddress(accountIndex: $0) },
|
||||
getTransparentAddress: { try await synchronizer.getTransparentAddress(accountIndex: $0) },
|
||||
getSaplingAddress: { try await synchronizer.getSaplingAddress(accountIndex: $0) },
|
||||
sendTransaction: { spendingKey, amount, recipient, memo in
|
||||
return .run { send in
|
||||
do {
|
||||
|
|
|
@ -24,11 +24,11 @@ extension SDKSynchronizerClient: TestDependencyKey {
|
|||
rewind: XCTUnimplemented("\(Self.self).rewind", placeholder: Fail(error: "Error").eraseToAnyPublisher()),
|
||||
getShieldedBalance: XCTUnimplemented("\(Self.self).getShieldedBalance", placeholder: WalletBalance.zero),
|
||||
getTransparentBalance: XCTUnimplemented("\(Self.self).getTransparentBalance", placeholder: WalletBalance.zero),
|
||||
getAllSentTransactions: XCTUnimplemented("\(Self.self).getAllSentTransactions", placeholder: .none),
|
||||
getAllReceivedTransactions: XCTUnimplemented("\(Self.self).getAllReceivedTransactions", placeholder: .none),
|
||||
getAllClearedTransactions: XCTUnimplemented("\(Self.self).getAllClearedTransactions", placeholder: .none),
|
||||
getAllPendingTransactions: XCTUnimplemented("\(Self.self).getAllPendingTransactions", placeholder: .none),
|
||||
getAllTransactions: XCTUnimplemented("\(Self.self).getAllTransactions", placeholder: .none),
|
||||
getAllSentTransactions: XCTUnimplemented("\(Self.self).getAllSentTransactions", placeholder: []),
|
||||
getAllReceivedTransactions: XCTUnimplemented("\(Self.self).getAllReceivedTransactions", placeholder: []),
|
||||
getAllClearedTransactions: XCTUnimplemented("\(Self.self).getAllClearedTransactions", placeholder: []),
|
||||
getAllPendingTransactions: XCTUnimplemented("\(Self.self).getAllPendingTransactions", placeholder: []),
|
||||
getAllTransactions: XCTUnimplemented("\(Self.self).getAllTransactions", placeholder: []),
|
||||
getUnifiedAddress: XCTUnimplemented("\(Self.self).getUnifiedAddress", placeholder: nil),
|
||||
getTransparentAddress: XCTUnimplemented("\(Self.self).getTransparentAddress", placeholder: nil),
|
||||
getSaplingAddress: XCTUnimplemented("\(Self.self).getSaplingAddress", placeholder: nil),
|
||||
|
@ -52,11 +52,11 @@ extension SDKSynchronizerClient {
|
|||
rewind: { _ in return Empty<Void, Error>().eraseToAnyPublisher() },
|
||||
getShieldedBalance: { .zero },
|
||||
getTransparentBalance: { .zero },
|
||||
getAllSentTransactions: { EffectTask(value: []) },
|
||||
getAllReceivedTransactions: { EffectTask(value: []) },
|
||||
getAllClearedTransactions: { EffectTask(value: []) },
|
||||
getAllPendingTransactions: { EffectTask(value: []) },
|
||||
getAllTransactions: { EffectTask(value: []) },
|
||||
getAllSentTransactions: { [] },
|
||||
getAllReceivedTransactions: { [] },
|
||||
getAllClearedTransactions: { [] },
|
||||
getAllPendingTransactions: { [] },
|
||||
getAllTransactions: { [] },
|
||||
getUnifiedAddress: { _ in return nil },
|
||||
getTransparentAddress: { _ in return nil },
|
||||
getSaplingAddress: { _ in return nil },
|
||||
|
@ -82,7 +82,7 @@ extension SDKSynchronizerClient {
|
|||
rewind: @escaping (RewindPolicy) -> AnyPublisher<Void, Error> = { _ in return Empty<Void, Error>().eraseToAnyPublisher() },
|
||||
getShieldedBalance: @escaping () -> WalletBalance? = { WalletBalance(verified: Zatoshi(12345000), total: Zatoshi(12345000)) },
|
||||
getTransparentBalance: @escaping () -> WalletBalance? = { WalletBalance(verified: Zatoshi(12345000), total: Zatoshi(12345000)) },
|
||||
getAllSentTransactions: @escaping () -> EffectTask<[WalletEvent]> = {
|
||||
getAllSentTransactions: @escaping () -> [WalletEvent] = {
|
||||
let mocked: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(date: 1651039202, amount: Zatoshi(1), status: .paid(success: false), uuid: "aa11"),
|
||||
TransactionStateMockHelper(date: 1651039101, amount: Zatoshi(2), uuid: "bb22"),
|
||||
|
@ -91,22 +91,20 @@ extension SDKSynchronizerClient {
|
|||
TransactionStateMockHelper(date: 1651039404, amount: Zatoshi(5), uuid: "ee55")
|
||||
]
|
||||
|
||||
return EffectTask(
|
||||
value:
|
||||
mocked.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp ?? 0)
|
||||
}
|
||||
)
|
||||
return mocked
|
||||
.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp ?? 0)
|
||||
}
|
||||
},
|
||||
getAllReceivedTransactions: @escaping () -> EffectTask<[WalletEvent]> = {
|
||||
getAllReceivedTransactions: @escaping () -> [WalletEvent] = {
|
||||
let mocked: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(date: 1651039202, amount: Zatoshi(1), status: .paid(success: false), uuid: "aa11"),
|
||||
TransactionStateMockHelper(date: 1651039101, amount: Zatoshi(2), uuid: "bb22"),
|
||||
|
@ -115,22 +113,20 @@ extension SDKSynchronizerClient {
|
|||
TransactionStateMockHelper(date: 1651039404, amount: Zatoshi(5), uuid: "ee55")
|
||||
]
|
||||
|
||||
return EffectTask(
|
||||
value:
|
||||
mocked.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp ?? 0)
|
||||
}
|
||||
)
|
||||
return mocked
|
||||
.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp ?? 0)
|
||||
}
|
||||
},
|
||||
getAllClearedTransactions: @escaping () -> EffectTask<[WalletEvent]> = {
|
||||
getAllClearedTransactions: @escaping () -> [WalletEvent] = {
|
||||
let mocked: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(date: 1651039202, amount: Zatoshi(1), status: .paid(success: false), uuid: "aa11"),
|
||||
TransactionStateMockHelper(date: 1651039101, amount: Zatoshi(2), uuid: "bb22"),
|
||||
|
@ -139,22 +135,20 @@ extension SDKSynchronizerClient {
|
|||
TransactionStateMockHelper(date: 1651039404, amount: Zatoshi(5), uuid: "ee55")
|
||||
]
|
||||
|
||||
return EffectTask(
|
||||
value:
|
||||
mocked.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp ?? 0)
|
||||
}
|
||||
)
|
||||
return mocked
|
||||
.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp ?? 0)
|
||||
}
|
||||
},
|
||||
getAllPendingTransactions: @escaping () -> EffectTask<[WalletEvent]> = {
|
||||
getAllPendingTransactions: @escaping () -> [WalletEvent] = {
|
||||
let mocked: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(
|
||||
date: 1651039606,
|
||||
|
@ -167,23 +161,21 @@ extension SDKSynchronizerClient {
|
|||
TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(9), uuid: "ii99")
|
||||
]
|
||||
|
||||
return EffectTask(
|
||||
value:
|
||||
mocked.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.amount.amount > 5 ? .pending : $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
)
|
||||
return mocked
|
||||
.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.amount.amount > 5 ? .pending : $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
},
|
||||
getAllTransactions: @escaping () -> EffectTask<[WalletEvent]> = {
|
||||
let mockerCleared: [TransactionStateMockHelper] = [
|
||||
getAllTransactions: @escaping () -> [WalletEvent] = {
|
||||
let mockedCleared: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(date: 1651039202, amount: Zatoshi(1), status: .paid(success: false), uuid: "aa11"),
|
||||
TransactionStateMockHelper(date: 1651039101, amount: Zatoshi(2), uuid: "bb22"),
|
||||
TransactionStateMockHelper(date: 1651039000, amount: Zatoshi(3), status: .paid(success: true), uuid: "cc33"),
|
||||
|
@ -191,21 +183,19 @@ extension SDKSynchronizerClient {
|
|||
TransactionStateMockHelper(date: 1651039404, amount: Zatoshi(5), uuid: "ee55")
|
||||
]
|
||||
|
||||
let clearedTransactionsEffect = EffectTask(
|
||||
value:
|
||||
mockerCleared.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp ?? 0)
|
||||
}
|
||||
)
|
||||
|
||||
var clearedTransactions = mockedCleared
|
||||
.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp ?? 0)
|
||||
}
|
||||
|
||||
let mockedPending: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(
|
||||
date: 1651039606,
|
||||
|
@ -218,28 +208,22 @@ extension SDKSynchronizerClient {
|
|||
TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(9), uuid: "ii99")
|
||||
]
|
||||
|
||||
let pendingTransactionsEffect = EffectTask(
|
||||
value:
|
||||
mockedPending.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.amount.amount > 5 ? .pending : $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
)
|
||||
let pendingTransactions = mockedPending
|
||||
.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.amount.amount > 5 ? .pending : $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
|
||||
clearedTransactions.append(contentsOf: pendingTransactions)
|
||||
|
||||
return .merge(
|
||||
clearedTransactionsEffect,
|
||||
pendingTransactionsEffect
|
||||
)
|
||||
.flatMap(Publishers.Sequence.init(sequence:))
|
||||
.collect()
|
||||
.eraseToEffect()
|
||||
return clearedTransactions
|
||||
},
|
||||
getUnifiedAddress: @escaping (_ account: Int) -> UnifiedAddress? = { _ in
|
||||
// swiftlint:disable force_try
|
||||
|
|
|
@ -20,11 +20,21 @@ struct AddressDetailsReducer: ReducerProtocol {
|
|||
}
|
||||
|
||||
var transparentAddress: String {
|
||||
uAddress?.transparentReceiver()?.stringEncoded ?? L10n.AddressDetails.Error.cantExtractTransparentAddress
|
||||
do {
|
||||
let address = try uAddress?.transparentReceiver().stringEncoded ?? L10n.AddressDetails.Error.cantExtractTransparentAddress
|
||||
return address
|
||||
} catch {
|
||||
return L10n.AddressDetails.Error.cantExtractTransparentAddress
|
||||
}
|
||||
}
|
||||
|
||||
var saplingAddress: String {
|
||||
uAddress?.saplingReceiver()?.stringEncoded ?? L10n.AddressDetails.Error.cantExtractSaplingAddress
|
||||
do {
|
||||
let address = try uAddress?.saplingReceiver().stringEncoded ?? L10n.AddressDetails.Error.cantExtractSaplingAddress
|
||||
return address
|
||||
} catch {
|
||||
return L10n.AddressDetails.Error.cantExtractSaplingAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ typealias HomeViewStore = ViewStore<HomeReducer.State, HomeReducer.Action>
|
|||
|
||||
struct HomeReducer: ReducerProtocol {
|
||||
private enum CancelId {}
|
||||
private enum CancelEventsId {}
|
||||
|
||||
struct State: Equatable {
|
||||
enum Destination: Equatable {
|
||||
|
@ -23,6 +24,7 @@ struct HomeReducer: ReducerProtocol {
|
|||
|
||||
var balanceBreakdownState: BalanceBreakdownReducer.State
|
||||
var destination: Destination?
|
||||
var canRequestReview = false
|
||||
var profileState: ProfileReducer.State
|
||||
var requiredTransactionConfirmations = 0
|
||||
var scanState: ScanReducer.State
|
||||
|
@ -67,9 +69,12 @@ struct HomeReducer: ReducerProtocol {
|
|||
case onAppear
|
||||
case onDisappear
|
||||
case profile(ProfileReducer.Action)
|
||||
case resolveReviewRequest
|
||||
case reviewRequestFinished
|
||||
case send(SendFlowReducer.Action)
|
||||
case settings(SettingsReducer.Action)
|
||||
case syncFailed(String)
|
||||
case foundTransactions
|
||||
case synchronizerStateChanged(SynchronizerState)
|
||||
case walletEvents(WalletEventsFlowReducer.Action)
|
||||
case updateDestination(HomeReducer.State.Destination?)
|
||||
|
@ -81,6 +86,7 @@ struct HomeReducer: ReducerProtocol {
|
|||
@Dependency(\.audioServices) var audioServices
|
||||
@Dependency(\.diskSpaceChecker) var diskSpaceChecker
|
||||
@Dependency(\.mainQueue) var mainQueue
|
||||
@Dependency(\.reviewRequest) var reviewRequest
|
||||
@Dependency(\.sdkSynchronizer) var sdkSynchronizer
|
||||
@Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment
|
||||
|
||||
|
@ -109,20 +115,37 @@ struct HomeReducer: ReducerProtocol {
|
|||
switch action {
|
||||
case .onAppear:
|
||||
state.requiredTransactionConfirmations = zcashSDKEnvironment.requiredTransactionConfirmations
|
||||
|
||||
|
||||
if diskSpaceChecker.hasEnoughFreeSpaceForSync() {
|
||||
let syncEffect = sdkSynchronizer.stateStream()
|
||||
.throttle(for: .seconds(0.2), scheduler: mainQueue, latest: true)
|
||||
.map(HomeReducer.Action.synchronizerStateChanged)
|
||||
.eraseToEffect()
|
||||
.cancellable(id: CancelId.self, cancelInFlight: true)
|
||||
return .concatenate(EffectTask(value: .updateDestination(nil)), syncEffect)
|
||||
return .merge(
|
||||
EffectTask(value: .updateDestination(nil)),
|
||||
syncEffect
|
||||
)
|
||||
} else {
|
||||
return EffectTask(value: .updateDestination(.notEnoughFreeDiskSpace))
|
||||
}
|
||||
|
||||
|
||||
case .onDisappear:
|
||||
return .cancel(id: CancelId.self)
|
||||
return .merge(
|
||||
.cancel(id: CancelId.self),
|
||||
.cancel(id: CancelEventsId.self)
|
||||
)
|
||||
|
||||
case .resolveReviewRequest:
|
||||
if reviewRequest.canRequestReview() {
|
||||
state.canRequestReview = true
|
||||
return .fireAndForget { await reviewRequest.reviewRequested() }
|
||||
}
|
||||
return .none
|
||||
|
||||
case .reviewRequestFinished:
|
||||
state.canRequestReview = false
|
||||
return .none
|
||||
|
||||
case .updateWalletEvents:
|
||||
return .none
|
||||
|
@ -140,10 +163,17 @@ struct HomeReducer: ReducerProtocol {
|
|||
switch snapshot.syncStatus {
|
||||
case .error:
|
||||
return EffectTask(value: .showSynchronizerErrorAlert(snapshot))
|
||||
|
||||
case .synced:
|
||||
return .fireAndForget { await reviewRequest.syncFinished() }
|
||||
|
||||
default:
|
||||
return .none
|
||||
}
|
||||
|
||||
case .foundTransactions:
|
||||
return .fireAndForget { await reviewRequest.foundTransactions() }
|
||||
|
||||
case .updateDestination(.profile):
|
||||
state.profileState.destination = nil
|
||||
state.destination = .profile
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import SwiftUI
|
||||
import ComposableArchitecture
|
||||
import StoreKit
|
||||
|
||||
struct HomeView: View {
|
||||
let store: Store<HomeReducer.State, HomeReducer.Action>
|
||||
|
||||
|
||||
var body: some View {
|
||||
WithViewStore(store) { viewStore in
|
||||
VStack {
|
||||
|
@ -27,8 +28,18 @@ struct HomeView: View {
|
|||
.navigationTitle(L10n.Home.title)
|
||||
.navigationBarItems(trailing: settingsButton(viewStore))
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.onAppear(perform: { viewStore.send(.onAppear) })
|
||||
.onDisappear(perform: { viewStore.send(.onDisappear) })
|
||||
.onAppear {
|
||||
viewStore.send(.onAppear)
|
||||
}
|
||||
.onChange(of: viewStore.canRequestReview) { canRequestReview in
|
||||
if canRequestReview {
|
||||
if let currentScene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
|
||||
SKStoreReviewController.requestReview(in: currentScene)
|
||||
}
|
||||
viewStore.send(.reviewRequestFinished)
|
||||
}
|
||||
}
|
||||
.onDisappear { viewStore.send(.onDisappear) }
|
||||
.navigationLinkEmpty(
|
||||
isActive: viewStore.bindingForDestination(.balanceBreakdown),
|
||||
destination: { BalanceBreakdownView(store: store.balanceBreakdownStore()) }
|
||||
|
|
|
@ -27,6 +27,7 @@ struct ProfileReducer: ReducerProtocol {
|
|||
case back
|
||||
case copyUnifiedAddressToPastboard
|
||||
case onAppear
|
||||
case uAddressChanged(UnifiedAddress?)
|
||||
case updateDestination(ProfileReducer.State.Destination?)
|
||||
}
|
||||
|
||||
|
@ -43,12 +44,17 @@ struct ProfileReducer: ReducerProtocol {
|
|||
Reduce { state, action in
|
||||
switch action {
|
||||
case .onAppear:
|
||||
state.addressDetailsState.uAddress = self.sdkSynchronizer.getUnifiedAddress(0)
|
||||
state.appBuild = appVersion.appBuild()
|
||||
state.appVersion = appVersion.appVersion()
|
||||
state.sdkVersion = zcashSDKEnvironment.sdkVersion
|
||||
return .none
|
||||
return .task {
|
||||
return .uAddressChanged(try? await sdkSynchronizer.getUnifiedAddress(0))
|
||||
}
|
||||
|
||||
case .uAddressChanged(let uAddress):
|
||||
state.addressDetailsState.uAddress = uAddress
|
||||
return .none
|
||||
|
||||
case .back:
|
||||
return .none
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ extension RootReducer {
|
|||
case flagUpdated
|
||||
case fullRescan
|
||||
case quickRescan
|
||||
case rateTheApp
|
||||
case rescanBlockchain
|
||||
case rewindDone(String?, RootReducer.Action)
|
||||
case testCrashReporter // this will crash the app if live.
|
||||
|
@ -95,6 +96,9 @@ extension RootReducer {
|
|||
case .debug(.cantStartSync(let errorMessage)):
|
||||
return EffectTask(value: .alert(.root(.cantStartSync(errorMessage))))
|
||||
|
||||
case .debug(.rateTheApp):
|
||||
return .none
|
||||
|
||||
default: return .none
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ private extension RootReducer {
|
|||
case .home:
|
||||
return .destination(.deeplinkHome)
|
||||
case let .send(amount, address, memo):
|
||||
return .destination(.deeplinkSend(Zatoshi(amount), address, memo))
|
||||
return .destination(.deeplinkSend(Zatoshi(Int64(amount)), address, memo))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ extension RootReducer {
|
|||
Reduce { state, action in
|
||||
switch action {
|
||||
case .initialization(.appDelegate(.didFinishLaunching)):
|
||||
// TODO: [#704], trigger the review request logic when approved by the team,
|
||||
// https://github.com/zcash/secant-ios-wallet/issues/704
|
||||
return EffectTask(value: .initialization(.checkWalletConfig))
|
||||
.delay(for: 0.02, scheduler: mainQueue)
|
||||
.eraseToEffect()
|
||||
|
|
|
@ -164,6 +164,13 @@ private extension RootView {
|
|||
}
|
||||
.disabled(viewStore.exportLogsState.exportLogsDisabled)
|
||||
|
||||
Button(L10n.Root.Debug.Option.appReview) {
|
||||
viewStore.send(.debug(.rateTheApp))
|
||||
if let currentScene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
|
||||
SKStoreReviewController.requestReview(in: currentScene)
|
||||
}
|
||||
}
|
||||
|
||||
Button(L10n.Root.Debug.Option.rescanBlockchain) {
|
||||
viewStore.send(.debug(.rescanBlockchain))
|
||||
}
|
||||
|
|
|
@ -58,10 +58,9 @@ struct WalletEventsFlowReducer: ReducerProtocol {
|
|||
|
||||
case .synchronizerStateChanged(.synced):
|
||||
state.latestMinedHeight = sdkSynchronizer.latestScannedHeight()
|
||||
return sdkSynchronizer.getAllTransactions()
|
||||
.receive(on: mainQueue)
|
||||
.map(WalletEventsFlowReducer.Action.updateWalletEvents)
|
||||
.eraseToEffect()
|
||||
return .task {
|
||||
return .updateWalletEvents(try await sdkSynchronizer.getAllTransactions())
|
||||
}
|
||||
|
||||
case .synchronizerStateChanged:
|
||||
return .none
|
||||
|
|
|
@ -353,6 +353,8 @@ internal enum L10n {
|
|||
}
|
||||
}
|
||||
internal enum Option {
|
||||
/// Rate the app
|
||||
internal static let appReview = L10n.tr("Localizable", "root.debug.option.appReview", fallback: "Rate the app")
|
||||
/// Export logs
|
||||
internal static let exportLogs = L10n.tr("Localizable", "root.debug.option.exportLogs", fallback: "Export logs")
|
||||
/// Go To Onboarding
|
||||
|
|
|
@ -242,6 +242,7 @@
|
|||
"root.debug.option.rescanBlockchain" = "Rescan Blockchain";
|
||||
"root.debug.option.nukeWallet" = "[Be careful] Nuke Wallet";
|
||||
"root.debug.option.exportLogs" = "Export logs";
|
||||
"root.debug.option.appReview" = "Rate the app";
|
||||
"root.debug.featureFlags" = "Feature flags";
|
||||
"root.debug.dialog.rescan.title" = "Rescan";
|
||||
"root.debug.dialog.rescan.message" = "Select the rescan you want";
|
||||
|
|
|
@ -27,7 +27,7 @@ class AddressDetailsTests: XCTestCase {
|
|||
|
||||
store.send(.copySaplingAddressToPastboard)
|
||||
|
||||
let expectedAddress = uAddress.saplingReceiver()?.stringEncoded ?? "could not extract sapling receiver from UA"
|
||||
let expectedAddress = try uAddress.saplingReceiver().stringEncoded
|
||||
|
||||
XCTAssertEqual(
|
||||
testPasteboard.getString()?.data,
|
||||
|
@ -49,7 +49,7 @@ class AddressDetailsTests: XCTestCase {
|
|||
|
||||
store.send(.copyTransparentAddressToPastboard)
|
||||
|
||||
let expectedAddress = uAddress.transparentReceiver()?.stringEncoded ?? "could not extract transparent receiver from UA"
|
||||
let expectedAddress = try uAddress.transparentReceiver().stringEncoded
|
||||
|
||||
XCTAssertEqual(
|
||||
testPasteboard.getString()?.data,
|
||||
|
|
|
@ -53,6 +53,7 @@ class HomeTests: XCTestCase {
|
|||
store.dependencies.mainQueue = .immediate
|
||||
store.dependencies.diskSpaceChecker = .mockEmptyDisk
|
||||
store.dependencies.sdkSynchronizer = .mocked()
|
||||
store.dependencies.reviewRequest = .noOp
|
||||
|
||||
store.send(.onAppear) { state in
|
||||
state.requiredTransactionConfirmations = 10
|
||||
|
@ -60,6 +61,7 @@ class HomeTests: XCTestCase {
|
|||
|
||||
// expected side effects as a result of .onAppear registration
|
||||
store.receive(.updateDestination(nil))
|
||||
store.receive(.resolveReviewRequest)
|
||||
store.receive(.synchronizerStateChanged(.zero)) { state in
|
||||
state.synchronizerStatusSnapshot = SyncStatusSnapshot.snapshotFor(state: .unprepared)
|
||||
}
|
||||
|
@ -76,6 +78,7 @@ class HomeTests: XCTestCase {
|
|||
)
|
||||
|
||||
store.dependencies.diskSpaceChecker = .mockFullDisk
|
||||
store.dependencies.reviewRequest = .noOp
|
||||
|
||||
store.send(.onAppear) { state in
|
||||
state.requiredTransactionConfirmations = 10
|
||||
|
@ -86,6 +89,8 @@ class HomeTests: XCTestCase {
|
|||
state.destination = .notEnoughFreeDiskSpace
|
||||
}
|
||||
|
||||
store.receive(.resolveReviewRequest)
|
||||
|
||||
// long-living (cancelable) effects need to be properly canceled.
|
||||
// the .onDisappear action cancels the observer of the synchronizer status change.
|
||||
store.send(.onDisappear)
|
||||
|
|
|
@ -29,11 +29,14 @@ class ProfileTests: XCTestCase {
|
|||
)
|
||||
|
||||
await store.send(.onAppear) { state in
|
||||
state.addressDetailsState.uAddress = uAddress
|
||||
state.appVersion = "0.0.1"
|
||||
state.appBuild = "31"
|
||||
state.sdkVersion = "0.18.1-beta"
|
||||
}
|
||||
|
||||
await store.receive(.uAddressChanged(uAddress)) { state in
|
||||
state.addressDetailsState.uAddress = uAddress
|
||||
}
|
||||
}
|
||||
|
||||
func testCopyUnifiedAddressToPasteboard() throws {
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
//
|
||||
// ReviewRequestTests.swift
|
||||
// secantTests
|
||||
//
|
||||
// Created by Lukáš Korba on 04.04.2023.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import ComposableArchitecture
|
||||
import ZcashLightClientKit
|
||||
@testable import secant_testnet
|
||||
|
||||
@MainActor
|
||||
final class ReviewRequestTests: XCTestCase {
|
||||
func testSyncFinishedPersistency() async throws {
|
||||
guard let userDefaults = UserDefaults.init(suiteName: "testSyncFinishedPersistency") else {
|
||||
XCTFail("Review Request: UserDefaults failed to initialize")
|
||||
return
|
||||
}
|
||||
|
||||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: HomeReducer()
|
||||
)
|
||||
|
||||
let now = Date.now
|
||||
let userDefaultsClient: UserDefaultsClient = .live(userDefaults: userDefaults)
|
||||
|
||||
store.dependencies.reviewRequest =
|
||||
.live(
|
||||
appVersion: .mock,
|
||||
date: DateClient(
|
||||
now: { now }
|
||||
),
|
||||
userDefaults: userDefaultsClient
|
||||
)
|
||||
|
||||
var syncState: SynchronizerState = .zero
|
||||
syncState.syncStatus = .synced
|
||||
let snapshot = SyncStatusSnapshot.snapshotFor(state: syncState.syncStatus)
|
||||
|
||||
await store.send(.synchronizerStateChanged(syncState)) { state in
|
||||
state.synchronizerStatusSnapshot = snapshot
|
||||
}
|
||||
|
||||
let storedDate = userDefaultsClient.objectForKey(ReviewRequestClient.Constants.latestSyncKey) as? TimeInterval
|
||||
XCTAssertEqual(now.timeIntervalSince1970, storedDate, "Review Request: stored date doesn't match the input.")
|
||||
}
|
||||
|
||||
func testFoundTransactionsPersistency() async throws {
|
||||
guard let userDefaults = UserDefaults.init(suiteName: "testFoundTransactionsPersistency") else {
|
||||
XCTFail("Review Request: UserDefaults failed to initialize")
|
||||
return
|
||||
}
|
||||
|
||||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: HomeReducer()
|
||||
)
|
||||
|
||||
let now = Date.now
|
||||
let userDefaultsClient: UserDefaultsClient = .live(userDefaults: userDefaults)
|
||||
|
||||
await userDefaultsClient.setValue("any value", ReviewRequestClient.Constants.latestSyncKey)
|
||||
|
||||
store.dependencies.reviewRequest =
|
||||
.live(
|
||||
appVersion: .mock,
|
||||
date: DateClient(
|
||||
now: { now }
|
||||
),
|
||||
userDefaults: userDefaultsClient
|
||||
)
|
||||
|
||||
await store.send(.foundTransactions)
|
||||
|
||||
let storedDate = userDefaultsClient.objectForKey(ReviewRequestClient.Constants.foundTransactionsKey) as? TimeInterval
|
||||
XCTAssertEqual(now.timeIntervalSince1970, storedDate, "Review Request: stored date doesn't match the input.")
|
||||
}
|
||||
|
||||
func testCanRequestReview_FirstTime() async throws {
|
||||
guard let userDefaults = UserDefaults.init(suiteName: "testCanRequestReview_FirstTime") else {
|
||||
XCTFail("Review Request: UserDefaults failed to initialize")
|
||||
return
|
||||
}
|
||||
|
||||
let now = Date.now
|
||||
let userDefaultsClient: UserDefaultsClient = .live(userDefaults: userDefaults)
|
||||
|
||||
await userDefaultsClient.setValue("any value", ReviewRequestClient.Constants.latestSyncKey)
|
||||
await userDefaultsClient.setValue("any value", ReviewRequestClient.Constants.foundTransactionsKey)
|
||||
|
||||
let reviewRequest = ReviewRequestClient.live(
|
||||
appVersion: .mock,
|
||||
date: DateClient(
|
||||
now: { now }
|
||||
),
|
||||
userDefaults: userDefaultsClient
|
||||
)
|
||||
|
||||
XCTAssertTrue(reviewRequest.canRequestReview())
|
||||
}
|
||||
|
||||
func testCanRequestReview_NewerVersion() async throws {
|
||||
guard let userDefaults = UserDefaults.init(suiteName: "testCanRequestReview_NewerVersion") else {
|
||||
XCTFail("Review Request: UserDefaults failed to initialize")
|
||||
return
|
||||
}
|
||||
|
||||
let now = Date.now
|
||||
let userDefaultsClient: UserDefaultsClient = .live(userDefaults: userDefaults)
|
||||
|
||||
await userDefaultsClient.setValue("any value", ReviewRequestClient.Constants.latestSyncKey)
|
||||
await userDefaultsClient.setValue("any value", ReviewRequestClient.Constants.foundTransactionsKey)
|
||||
await userDefaultsClient.setValue("0.0.1", ReviewRequestClient.Constants.versionKey)
|
||||
|
||||
let reviewRequest = ReviewRequestClient.live(
|
||||
appVersion: AppVersionClient(
|
||||
appVersion: { "0.0.2" },
|
||||
appBuild: { "1" }
|
||||
),
|
||||
date: DateClient(
|
||||
now: { now }
|
||||
),
|
||||
userDefaults: userDefaultsClient
|
||||
)
|
||||
|
||||
XCTAssertTrue(reviewRequest.canRequestReview())
|
||||
}
|
||||
|
||||
func testCanRequestReview_OlderVersion() async throws {
|
||||
guard let userDefaults = UserDefaults.init(suiteName: "testCanRequestReview_OlderVersion") else {
|
||||
XCTFail("Review Request: UserDefaults failed to initialize")
|
||||
return
|
||||
}
|
||||
|
||||
let now = Date.now
|
||||
let userDefaultsClient: UserDefaultsClient = .live(userDefaults: userDefaults)
|
||||
|
||||
await userDefaultsClient.setValue("any value", ReviewRequestClient.Constants.latestSyncKey)
|
||||
await userDefaultsClient.setValue("any value", ReviewRequestClient.Constants.foundTransactionsKey)
|
||||
await userDefaultsClient.setValue("0.0.2", ReviewRequestClient.Constants.versionKey)
|
||||
|
||||
let reviewRequest = ReviewRequestClient.live(
|
||||
appVersion: AppVersionClient(
|
||||
appVersion: { "0.0.1" },
|
||||
appBuild: { "1" }
|
||||
),
|
||||
date: DateClient(
|
||||
now: { now }
|
||||
),
|
||||
userDefaults: userDefaultsClient
|
||||
)
|
||||
|
||||
XCTAssertFalse(reviewRequest.canRequestReview())
|
||||
}
|
||||
|
||||
func testCanRequestReview_MissingSync() async throws {
|
||||
guard let userDefaults = UserDefaults.init(suiteName: "testCanRequestReview_MissingSync") else {
|
||||
XCTFail("Review Request: UserDefaults failed to initialize")
|
||||
return
|
||||
}
|
||||
|
||||
let now = Date.now
|
||||
let userDefaultsClient: UserDefaultsClient = .live(userDefaults: userDefaults)
|
||||
|
||||
let reviewRequest = ReviewRequestClient.live(
|
||||
appVersion: .mock,
|
||||
date: DateClient(
|
||||
now: { now }
|
||||
),
|
||||
userDefaults: userDefaultsClient
|
||||
)
|
||||
|
||||
XCTAssertFalse(reviewRequest.canRequestReview())
|
||||
}
|
||||
|
||||
func testCanRequestReview_MissingTransaction() async throws {
|
||||
guard let userDefaults = UserDefaults.init(suiteName: "testCanRequestReview_MissingTransaction") else {
|
||||
XCTFail("Review Request: UserDefaults failed to initialize")
|
||||
return
|
||||
}
|
||||
|
||||
let now = Date.now
|
||||
let userDefaultsClient: UserDefaultsClient = .live(userDefaults: userDefaults)
|
||||
|
||||
await userDefaultsClient.setValue("any value", ReviewRequestClient.Constants.latestSyncKey)
|
||||
await userDefaultsClient.setValue("0.0.1", ReviewRequestClient.Constants.versionKey)
|
||||
|
||||
let reviewRequest = ReviewRequestClient.live(
|
||||
appVersion: AppVersionClient(
|
||||
appVersion: { "0.0.2" },
|
||||
appBuild: { "1" }
|
||||
),
|
||||
date: DateClient(
|
||||
now: { now }
|
||||
),
|
||||
userDefaults: userDefaultsClient
|
||||
)
|
||||
|
||||
XCTAssertFalse(reviewRequest.canRequestReview())
|
||||
}
|
||||
}
|
|
@ -51,6 +51,7 @@ class HomeSnapshotTests: XCTestCase {
|
|||
.dependency(\.diskSpaceChecker, .mockEmptyDisk)
|
||||
.dependency(\.sdkSynchronizer, .noOp)
|
||||
.dependency(\.mainQueue, .immediate)
|
||||
.dependency(\.reviewRequest, .noOp)
|
||||
)
|
||||
|
||||
// landing home screen
|
||||
|
|
|
@ -11,8 +11,6 @@ import ComposableArchitecture
|
|||
import ZcashLightClientKit
|
||||
|
||||
class WalletEventsTests: XCTestCase {
|
||||
static let testScheduler = DispatchQueue.test
|
||||
|
||||
func testSynchronizerSubscription() throws {
|
||||
let store = TestStore(
|
||||
initialState: WalletEventsFlowReducer.State(
|
||||
|
@ -36,7 +34,7 @@ class WalletEventsTests: XCTestCase {
|
|||
store.send(.onDisappear)
|
||||
}
|
||||
|
||||
func testSynchronizerStateChanged2Synced() throws {
|
||||
@MainActor func testSynchronizerStateChanged2Synced() async throws {
|
||||
let mocked: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(date: 1651039202, amount: Zatoshi(1), status: .paid(success: false), uuid: "aa11"),
|
||||
TransactionStateMockHelper(date: 1651039101, amount: Zatoshi(2), uuid: "bb22"),
|
||||
|
@ -81,16 +79,14 @@ class WalletEventsTests: XCTestCase {
|
|||
reducer: WalletEventsFlowReducer()
|
||||
)
|
||||
|
||||
store.dependencies.mainQueue = Self.testScheduler.eraseToAnyScheduler()
|
||||
store.dependencies.mainQueue = .immediate
|
||||
store.dependencies.sdkSynchronizer = .mocked()
|
||||
|
||||
store.send(.synchronizerStateChanged(.synced)) { state in
|
||||
await store.send(.synchronizerStateChanged(.synced)) { state in
|
||||
state.latestMinedHeight = 0
|
||||
}
|
||||
|
||||
Self.testScheduler.advance(by: 0.01)
|
||||
|
||||
store.receive(.updateWalletEvents(walletEvents)) { state in
|
||||
await store.receive(.updateWalletEvents(walletEvents)) { state in
|
||||
let receivedWalletEvents = IdentifiedArrayOf(
|
||||
uniqueElements:
|
||||
walletEvents
|
||||
|
@ -104,6 +100,8 @@ class WalletEventsTests: XCTestCase {
|
|||
|
||||
state.walletEvents = receivedWalletEvents
|
||||
}
|
||||
|
||||
await store.finish()
|
||||
}
|
||||
|
||||
func testCopyToPasteboard() throws {
|
||||
|
|
Loading…
Reference in New Issue