- Added `WalletConfigProvider` object which handles loading and caching of feature flags. - Added `WalletConfig` which represents one configuration of all feature flags.
This commit is contained in:
parent
1988d30540
commit
a1104163f3
|
@ -13,6 +13,7 @@ disabled_rules:
|
|||
- nesting # allow for types to be nested, common pattern in Swift
|
||||
- multiple_closures_with_trailing_closure
|
||||
- generic_type_name # allow for arbitrarily long generic type names
|
||||
- empty_parentheses_with_trailing_closure
|
||||
|
||||
opt_in_rules:
|
||||
- mark
|
||||
|
|
|
@ -330,6 +330,19 @@
|
|||
34E0AF0F28DEE4C70034CF37 /* HoldToSendButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34E0AF0E28DEE4C70034CF37 /* HoldToSendButton.swift */; };
|
||||
34E0AF1128DEE5220034CF37 /* Wedge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34E0AF1028DEE5220034CF37 /* Wedge.swift */; };
|
||||
34E5F2F328E46DB700C17E5F /* DiskSpaceChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34E5F2F228E46DB700C17E5F /* DiskSpaceChecker.swift */; };
|
||||
34F682E529A75EB60022C079 /* WalletConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F682E429A75EB60022C079 /* WalletConfig.swift */; };
|
||||
34F682E629A75EB60022C079 /* WalletConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F682E429A75EB60022C079 /* WalletConfig.swift */; };
|
||||
34F682EC29A763FD0022C079 /* WalletConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F682EB29A763FD0022C079 /* WalletConfigProvider.swift */; };
|
||||
34F682ED29A763FD0022C079 /* WalletConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F682EB29A763FD0022C079 /* WalletConfigProvider.swift */; };
|
||||
34F682EF29A7640A0022C079 /* WalletConfigProviderInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F682EE29A7640A0022C079 /* WalletConfigProviderInterface.swift */; };
|
||||
34F682F029A7640A0022C079 /* WalletConfigProviderInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F682EE29A7640A0022C079 /* WalletConfigProviderInterface.swift */; };
|
||||
34F682F229A764120022C079 /* WalletConfigProviderLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F682F129A764120022C079 /* WalletConfigProviderLiveKey.swift */; };
|
||||
34F682F329A764120022C079 /* WalletConfigProviderLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F682F129A764120022C079 /* WalletConfigProviderLiveKey.swift */; };
|
||||
34F682F529A7641B0022C079 /* WalletConfigProviderTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F682F429A7641B0022C079 /* WalletConfigProviderTestKey.swift */; };
|
||||
34F682F629A7641B0022C079 /* WalletConfigProviderTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F682F429A7641B0022C079 /* WalletConfigProviderTestKey.swift */; };
|
||||
34F682F829A775C10022C079 /* UserDefaultsWalletConfigStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F682F729A775C10022C079 /* UserDefaultsWalletConfigStorage.swift */; };
|
||||
34F682F929A775C10022C079 /* UserDefaultsWalletConfigStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F682F729A775C10022C079 /* UserDefaultsWalletConfigStorage.swift */; };
|
||||
34F682FC29A784660022C079 /* WalletConfigProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F682FB29A784660022C079 /* WalletConfigProviderTests.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 */; };
|
||||
|
@ -644,6 +657,13 @@
|
|||
34E0AF0E28DEE4C70034CF37 /* HoldToSendButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HoldToSendButton.swift; sourceTree = "<group>"; };
|
||||
34E0AF1028DEE5220034CF37 /* Wedge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wedge.swift; sourceTree = "<group>"; };
|
||||
34E5F2F228E46DB700C17E5F /* DiskSpaceChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiskSpaceChecker.swift; sourceTree = "<group>"; };
|
||||
34F682E429A75EB60022C079 /* WalletConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletConfig.swift; sourceTree = "<group>"; };
|
||||
34F682EB29A763FD0022C079 /* WalletConfigProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletConfigProvider.swift; sourceTree = "<group>"; };
|
||||
34F682EE29A7640A0022C079 /* WalletConfigProviderInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletConfigProviderInterface.swift; sourceTree = "<group>"; };
|
||||
34F682F129A764120022C079 /* WalletConfigProviderLiveKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletConfigProviderLiveKey.swift; sourceTree = "<group>"; };
|
||||
34F682F429A7641B0022C079 /* WalletConfigProviderTestKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletConfigProviderTestKey.swift; sourceTree = "<group>"; };
|
||||
34F682F729A775C10022C079 /* UserDefaultsWalletConfigStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsWalletConfigStorage.swift; sourceTree = "<group>"; };
|
||||
34F682FB29A784660022C079 /* WalletConfigProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletConfigProviderTests.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>"; };
|
||||
|
@ -983,26 +1003,27 @@
|
|||
0D4E7A1926B364180058B01E /* secantTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E391162284E3ECF0073DD9A /* SnapshotTests */,
|
||||
0D4E7A1C26B364180058B01E /* Info.plist */,
|
||||
0D4E7A1A26B364180058B01E /* secantTests.swift */,
|
||||
9E207C372966EF6E003E2C9B /* AddressDetailsTests */,
|
||||
0DFE93DD272C6D4B000FCCA5 /* BackupFlowTests */,
|
||||
9E94C61E28AA7DD5008256E9 /* BalanceBreakdownTests */,
|
||||
9E6713EF2897F80A00A6796F /* MultiLineTextFieldTests */,
|
||||
9E7CB6222874245400A02233 /* ProfileTests */,
|
||||
9EAB4674285B5C68002904A0 /* DeeplinkTests */,
|
||||
34F682FA29A784580022C079 /* WalletConfigProvider */,
|
||||
9E3911372848AD3A0073DD9A /* HomeTests */,
|
||||
9E391122283E4C970073DD9A /* ImportWalletTests */,
|
||||
9E612C7729913F2300D09B09 /* SensitiveDataTests */,
|
||||
9E66129C2889388C00C75B70 /* SettingsTests */,
|
||||
9E6713EF2897F80A00A6796F /* MultiLineTextFieldTests */,
|
||||
6654C7422715A48E00901167 /* OnboardingTests */,
|
||||
9E7CB6222874245400A02233 /* ProfileTests */,
|
||||
0DFE93E4272CB6D0000FCCA5 /* RecoveryPhraseValidationTests */,
|
||||
9EAFEB802805791400199FC9 /* RootTests */,
|
||||
9E01F8262833CD84000EFC57 /* ScanTests */,
|
||||
9E5BF642281FEC8700BA3F17 /* SendTests */,
|
||||
9E5BF63D281953F900BA3F17 /* WalletEventsTests */,
|
||||
9EAFEB802805791400199FC9 /* RootTests */,
|
||||
9E612C7729913F2300D09B09 /* SensitiveDataTests */,
|
||||
9E66129C2889388C00C75B70 /* SettingsTests */,
|
||||
9E391162284E3ECF0073DD9A /* SnapshotTests */,
|
||||
9EF8135927ECC25E0075AF48 /* UtilTests */,
|
||||
0DFE93E4272CB6D0000FCCA5 /* RecoveryPhraseValidationTests */,
|
||||
0DFE93DD272C6D4B000FCCA5 /* BackupFlowTests */,
|
||||
6654C7422715A48E00901167 /* OnboardingTests */,
|
||||
0D4E7A1A26B364180058B01E /* secantTests.swift */,
|
||||
0D4E7A1C26B364180058B01E /* Info.plist */,
|
||||
9E5BF63D281953F900BA3F17 /* WalletEventsTests */,
|
||||
);
|
||||
path = secantTests;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1060,15 +1081,16 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
9EF8135F27F043CC0075AF48 /* AppDelegate.swift */,
|
||||
9EF8139B27F47AED0075AF48 /* InitializationState.swift */,
|
||||
0D6D628A276A528D002FB4CC /* DropDelegate.swift */,
|
||||
9E5BF63B2818305D00BA3F17 /* TransactionState.swift */,
|
||||
34F682E429A75EB60022C079 /* WalletConfig.swift */,
|
||||
9EF8139B27F47AED0075AF48 /* InitializationState.swift */,
|
||||
9E7FE0D6282D286500C374E8 /* RecoveryPhrase.swift */,
|
||||
9E7FE0DC282D298900C374E8 /* ValidationWord.swift */,
|
||||
9E612C7C2991476F00D09B09 /* SensitiveData.swift */,
|
||||
9E7FE0E5282E7B1100C374E8 /* StoredWallet.swift */,
|
||||
9EAB46772860A1D2002904A0 /* WalletEvent.swift */,
|
||||
9E66122B2877188700C75B70 /* SyncStatusSnapshot.swift */,
|
||||
9E5BF63B2818305D00BA3F17 /* TransactionState.swift */,
|
||||
9E7FE0DC282D298900C374E8 /* ValidationWord.swift */,
|
||||
9EAB46772860A1D2002904A0 /* WalletEvent.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1167,6 +1189,26 @@
|
|||
path = CheckCircle;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
34F682EA29A763F00022C079 /* FeatureFlagsManager */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
34F682EB29A763FD0022C079 /* WalletConfigProvider.swift */,
|
||||
34F682F729A775C10022C079 /* UserDefaultsWalletConfigStorage.swift */,
|
||||
34F682EE29A7640A0022C079 /* WalletConfigProviderInterface.swift */,
|
||||
34F682F129A764120022C079 /* WalletConfigProviderLiveKey.swift */,
|
||||
34F682F429A7641B0022C079 /* WalletConfigProviderTestKey.swift */,
|
||||
);
|
||||
path = FeatureFlagsManager;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
34F682FA29A784580022C079 /* WalletConfigProvider */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
34F682FB29A784660022C079 /* WalletConfigProviderTests.swift */,
|
||||
);
|
||||
path = WalletConfigProvider;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
663FAB9A271D873300E495F8 /* Buttons */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1602,6 +1644,7 @@
|
|||
9EBDF959291E654F000A1A05 /* Deeplink */,
|
||||
9EBDF971291F79C9000A1A05 /* DerivationTool */,
|
||||
9EBDF945291D759B000A1A05 /* DiskSpaceChecker */,
|
||||
34F682EA29A763F00022C079 /* FeatureFlagsManager */,
|
||||
9EB863882922CC0E003D0F8B /* FeedbackGenerator */,
|
||||
9EB863B52923C4ED003D0F8B /* FileManager */,
|
||||
9EBDF981291F91B1000A1A05 /* LocalAuthentication */,
|
||||
|
@ -1990,13 +2033,13 @@
|
|||
9EF8135927ECC25E0075AF48 /* UtilTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9EF8135A27ECC25E0075AF48 /* WalletStorageTests.swift */,
|
||||
9E02B56B27FED475005B809B /* DatabaseFilesTests.swift */,
|
||||
9E0F574A2980260D005304FA /* LoggerTests.swift */,
|
||||
9EAFEB852805A23100199FC9 /* SecItemClientTests.swift */,
|
||||
9EF8135B27ECC25E0075AF48 /* UserPreferencesStorageTests.swift */,
|
||||
9E02B56B27FED475005B809B /* DatabaseFilesTests.swift */,
|
||||
9E39112D283F91600073DD9A /* ZatoshiTests.swift */,
|
||||
0DB4E0B02881F2DB00947B78 /* WalletBalance+testing.swift */,
|
||||
9E0F574A2980260D005304FA /* LoggerTests.swift */,
|
||||
9EF8135A27ECC25E0075AF48 /* WalletStorageTests.swift */,
|
||||
9E39112D283F91600073DD9A /* ZatoshiTests.swift */,
|
||||
);
|
||||
path = UtilTests;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2510,6 +2553,7 @@
|
|||
files = (
|
||||
0D26AE9B299E8196005260EE /* OnboardingFlowView.swift in Sources */,
|
||||
0D26AE9C299E8196005260EE /* ZcashBadge.swift in Sources */,
|
||||
34F682F329A764120022C079 /* WalletConfigProviderLiveKey.swift in Sources */,
|
||||
0D26AE9D299E8196005260EE /* CrashReporterTestKey.swift in Sources */,
|
||||
0D26AE9E299E8196005260EE /* DerivationToolInterface.swift in Sources */,
|
||||
0D26AE9F299E8196005260EE /* XCAssets+Generated.swift in Sources */,
|
||||
|
@ -2526,6 +2570,7 @@
|
|||
0D26AEAA299E8196005260EE /* CrashReporterLiveKey.swift in Sources */,
|
||||
0D26AEAB299E8196005260EE /* RecoveryPhraseRandomizerLiveKey.swift in Sources */,
|
||||
0D26AEAC299E8196005260EE /* TCATextField.swift in Sources */,
|
||||
34F682F029A7640A0022C079 /* WalletConfigProviderInterface.swift in Sources */,
|
||||
0D26AEAD299E8196005260EE /* DeeplinkInterface.swift in Sources */,
|
||||
0D26AEAE299E8196005260EE /* DerivationToolTestKey.swift in Sources */,
|
||||
0D26AEAF299E8196005260EE /* TransactionAmountTextFieldStore.swift in Sources */,
|
||||
|
@ -2533,6 +2578,7 @@
|
|||
0D26AEB1299E8196005260EE /* AppDelegate.swift in Sources */,
|
||||
0D26AEB2299E8196005260EE /* LogsHandlerInterface.swift in Sources */,
|
||||
0D26AEB3299E8196005260EE /* DeeplinkTestKey.swift in Sources */,
|
||||
34F682F929A775C10022C079 /* UserDefaultsWalletConfigStorage.swift in Sources */,
|
||||
0D26AEB4299E8196005260EE /* Wedge.swift in Sources */,
|
||||
0D26AEB5299E8196005260EE /* TransactionDetailView.swift in Sources */,
|
||||
0D26AEB6299E8196005260EE /* NumberFormatterLiveKey.swift in Sources */,
|
||||
|
@ -2613,6 +2659,7 @@
|
|||
0D26AF01299E8196005260EE /* RecoveryPhraseDisplayView.swift in Sources */,
|
||||
0D26AF02299E8196005260EE /* URIParser.swift in Sources */,
|
||||
0D26AF03299E8196005260EE /* URIParserLive.swift in Sources */,
|
||||
34F682ED29A763FD0022C079 /* WalletConfigProvider.swift in Sources */,
|
||||
0D26AF04299E8196005260EE /* LocalAuthenticationTestKey.swift in Sources */,
|
||||
0D26AF05299E8196005260EE /* ScanView.swift in Sources */,
|
||||
0D26AF06299E8196005260EE /* DatabaseFiles.swift in Sources */,
|
||||
|
@ -2636,6 +2683,7 @@
|
|||
0D26AF18299E8196005260EE /* WalletEventsFlowStore.swift in Sources */,
|
||||
0D26AF19299E8196005260EE /* StoredWallet.swift in Sources */,
|
||||
0D26AF1A299E8196005260EE /* UserDefaultsInterface.swift in Sources */,
|
||||
34F682E629A75EB60022C079 /* WalletConfig.swift in Sources */,
|
||||
0D26AF1B299E8196005260EE /* HomeStore.swift in Sources */,
|
||||
0D26AF1C299E8196005260EE /* AppVersionMocks.swift in Sources */,
|
||||
0D26AF1D299E8196005260EE /* RequestView.swift in Sources */,
|
||||
|
@ -2664,6 +2712,7 @@
|
|||
0D26AF34299E8196005260EE /* SecItemInterface.swift in Sources */,
|
||||
0D26AF35299E8196005260EE /* WalletInfoStore.swift in Sources */,
|
||||
0D26AF36299E8196005260EE /* DatabaseFilesTestKey.swift in Sources */,
|
||||
34F682F629A7641B0022C079 /* WalletConfigProviderTestKey.swift in Sources */,
|
||||
0D26AF37299E8196005260EE /* ScanUIView.swift in Sources */,
|
||||
0D26AF38299E8196005260EE /* AppVersionLiveKey.swift in Sources */,
|
||||
0D26AF39299E8196005260EE /* ColoredChip.swift in Sources */,
|
||||
|
@ -2730,6 +2779,7 @@
|
|||
files = (
|
||||
2EB660E02747EAB900A06A07 /* OnboardingFlowView.swift in Sources */,
|
||||
9E7FE0DF282D2DD600C374E8 /* ZcashBadge.swift in Sources */,
|
||||
34F682F229A764120022C079 /* WalletConfigProviderLiveKey.swift in Sources */,
|
||||
0D261040298C406F00CC9DE9 /* CrashReporterTestKey.swift in Sources */,
|
||||
9EBDF975291F79F9000A1A05 /* DerivationToolInterface.swift in Sources */,
|
||||
660558F8270C862F009D6954 /* XCAssets+Generated.swift in Sources */,
|
||||
|
@ -2746,6 +2796,7 @@
|
|||
0D26103E298C3FA600CC9DE9 /* CrashReporterLiveKey.swift in Sources */,
|
||||
9EB863A829239DCB003D0F8B /* RecoveryPhraseRandomizerLiveKey.swift in Sources */,
|
||||
2EDA07A027EDE18C00D6F09B /* TCATextField.swift in Sources */,
|
||||
34F682EF29A7640A0022C079 /* WalletConfigProviderInterface.swift in Sources */,
|
||||
9EBDF961291E657B000A1A05 /* DeeplinkInterface.swift in Sources */,
|
||||
9EBDF977291F79F9000A1A05 /* DerivationToolTestKey.swift in Sources */,
|
||||
2EB7758727FC67FD00269373 /* TransactionAmountTextFieldStore.swift in Sources */,
|
||||
|
@ -2753,6 +2804,7 @@
|
|||
9EF8136027F043CC0075AF48 /* AppDelegate.swift in Sources */,
|
||||
9E612C7229880E9200D09B09 /* LogsHandlerInterface.swift in Sources */,
|
||||
9EBDF960291E657B000A1A05 /* DeeplinkTestKey.swift in Sources */,
|
||||
34F682F829A775C10022C079 /* UserDefaultsWalletConfigStorage.swift in Sources */,
|
||||
34E0AF1128DEE5220034CF37 /* Wedge.swift in Sources */,
|
||||
F96B41E8273B501F0021B49A /* TransactionDetailView.swift in Sources */,
|
||||
9EB863942922D036003D0F8B /* NumberFormatterLiveKey.swift in Sources */,
|
||||
|
@ -2833,6 +2885,7 @@
|
|||
0D3D04082728B3440032ABC1 /* RecoveryPhraseDisplayView.swift in Sources */,
|
||||
9EB863A2292398A8003D0F8B /* URIParser.swift in Sources */,
|
||||
9EB863C12923C779003D0F8B /* URIParserLive.swift in Sources */,
|
||||
34F682EC29A763FD0022C079 /* WalletConfigProvider.swift in Sources */,
|
||||
9EBDF987291F91EF000A1A05 /* LocalAuthenticationTestKey.swift in Sources */,
|
||||
F9971A5F27680DF600A2DB75 /* ScanView.swift in Sources */,
|
||||
9E39114C2848EEB90073DD9A /* DatabaseFiles.swift in Sources */,
|
||||
|
@ -2856,6 +2909,7 @@
|
|||
F96B41E7273B501F0021B49A /* WalletEventsFlowStore.swift in Sources */,
|
||||
9E7FE0E6282E7B1100C374E8 /* StoredWallet.swift in Sources */,
|
||||
9E153A7629216EFB00112F41 /* UserDefaultsInterface.swift in Sources */,
|
||||
34F682E529A75EB60022C079 /* WalletConfig.swift in Sources */,
|
||||
9EAFEB9128081E9400199FC9 /* HomeStore.swift in Sources */,
|
||||
9EBDF980291F8261000A1A05 /* AppVersionMocks.swift in Sources */,
|
||||
F9971A5A27680DDE00A2DB75 /* RequestView.swift in Sources */,
|
||||
|
@ -2884,6 +2938,7 @@
|
|||
9EAFEB84280597B700199FC9 /* SecItemInterface.swift in Sources */,
|
||||
F9971A6B27680E1000A2DB75 /* WalletInfoStore.swift in Sources */,
|
||||
9EBDF953291E5E86000A1A05 /* DatabaseFilesTestKey.swift in Sources */,
|
||||
34F682F529A7641B0022C079 /* WalletConfigProviderTestKey.swift in Sources */,
|
||||
9E7FE0F628327F6F00C374E8 /* ScanUIView.swift in Sources */,
|
||||
9EBDF97D291F7EB0000A1A05 /* AppVersionLiveKey.swift in Sources */,
|
||||
0D185819272723FF0046B928 /* ColoredChip.swift in Sources */,
|
||||
|
@ -2991,6 +3046,7 @@
|
|||
9E02B56C27FED475005B809B /* DatabaseFilesTests.swift in Sources */,
|
||||
9E612C7929913F3600D09B09 /* SensitiveDataTests.swift in Sources */,
|
||||
9EF8135D27ECC25E0075AF48 /* UserPreferencesStorageTests.swift in Sources */,
|
||||
34F682FC29A784660022C079 /* WalletConfigProviderTests.swift in Sources */,
|
||||
9E94C62028AA7DEE008256E9 /* BalanceBreakdownTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
//
|
||||
// UserDefaultsWalletConfigStorage.swift
|
||||
// secant
|
||||
//
|
||||
// Created by Michal Fousek on 23.02.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
typealias UserDefaultsWalletConfigProvider = UserDefaultsWalletConfigStorage
|
||||
typealias UserDefaultsWalletConfigProviderCache = UserDefaultsWalletConfigStorage
|
||||
|
||||
struct UserDefaultsWalletConfigStorage {
|
||||
private let userDefaults = UserDefaults.standard
|
||||
|
||||
enum InternalError: Error {
|
||||
case noValueStored
|
||||
case unableToDeserializeData
|
||||
}
|
||||
|
||||
enum Constants {
|
||||
static let providerKey = "feature_flags_ud_config_provider"
|
||||
static let cacheKey = "feature_flags_ud_config_cache"
|
||||
}
|
||||
|
||||
private func load(key: String) async throws -> WalletConfig {
|
||||
guard let data = userDefaults.data(forKey: key) else { throw InternalError.noValueStored }
|
||||
do {
|
||||
let rawFlags = try PropertyListDecoder().decode(WalletConfig.RawFlags.self, from: data)
|
||||
return WalletConfig(flags: rawFlags)
|
||||
} catch {
|
||||
LoggerProxy.debug("Error when deocding feature flags from user defaults: \(error)")
|
||||
throw InternalError.unableToDeserializeData
|
||||
}
|
||||
}
|
||||
|
||||
private func store(flags: WalletConfig.RawFlags, key: String) async {
|
||||
do {
|
||||
let data = try PropertyListEncoder().encode(flags)
|
||||
userDefaults.set(data, forKey: key)
|
||||
} catch {
|
||||
LoggerProxy.debug("Can't store/encode feature flags when updating user defaults: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
// This is used only in debug menu to change configuration for specific flag
|
||||
func store(featureFlag: FeatureFlag, isEnabled: Bool) async {
|
||||
let currentConfig = (try? await load(key: Constants.providerKey)) ?? WalletConfig.default
|
||||
var rawFlags = currentConfig.flags
|
||||
rawFlags[featureFlag] = isEnabled
|
||||
|
||||
await store(flags: rawFlags, key: Constants.providerKey)
|
||||
}
|
||||
}
|
||||
|
||||
extension UserDefaultsWalletConfigStorage: WalletConfigSourceProvider {
|
||||
func load() async throws -> WalletConfig {
|
||||
return try await load(key: Constants.providerKey)
|
||||
}
|
||||
}
|
||||
|
||||
extension UserDefaultsWalletConfigStorage: WalletConfigProviderCache {
|
||||
func load() async -> WalletConfig? {
|
||||
do {
|
||||
return try await load(key: Constants.cacheKey)
|
||||
} catch {
|
||||
LoggerProxy.debug("Can't load feature flags from cache: \(error)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func store(_ configuration: WalletConfig) async {
|
||||
await store(flags: configuration.flags, key: Constants.cacheKey)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
//
|
||||
// WalletConfigProvider.swift
|
||||
// secant
|
||||
//
|
||||
// Created by Michal Fousek on 23.02.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct WalletConfigProvider {
|
||||
/// Objects that fetches flags configuration from some source. It can be fetched from user defaults or some backend API for example. It depends
|
||||
/// on implementation.
|
||||
private let configSourceProvider: WalletConfigSourceProvider
|
||||
/// Object that caches provided flags configuration.
|
||||
private let cache: WalletConfigProviderCache
|
||||
|
||||
init(configSourceProvider: WalletConfigSourceProvider, cache: WalletConfigProviderCache) {
|
||||
self.configSourceProvider = configSourceProvider
|
||||
self.cache = cache
|
||||
}
|
||||
|
||||
/// Loads flags configuration.
|
||||
///
|
||||
/// First `configurationProvider` is used to fetch flags configuration. If that fails then `cache` is used to load flags configuration. And if
|
||||
/// that fails `WalletConfig.default` is used.
|
||||
///
|
||||
/// Loaded configuration is merged with with `WalletConfig.default` to be sure that all recognized flags are always returned in
|
||||
/// configuration.
|
||||
///
|
||||
/// Merged configuration is stored in cache.
|
||||
func load() async -> WalletConfig {
|
||||
let configuration: WalletConfig
|
||||
do {
|
||||
configuration = try await configSourceProvider.load()
|
||||
} catch {
|
||||
LoggerProxy.debug("Error when loading feature flags from configuration provider: \(error)")
|
||||
if let cachedConfiguration = await cache.load() {
|
||||
configuration = cachedConfiguration
|
||||
} else {
|
||||
configuration = WalletConfig.default
|
||||
}
|
||||
}
|
||||
|
||||
let finalConfiguration = merge(configuration: configuration, withDefaultConfiguration: WalletConfig.default)
|
||||
|
||||
await cache.store(finalConfiguration)
|
||||
|
||||
return finalConfiguration
|
||||
}
|
||||
|
||||
// This is used only in debug menu to change configuration for specific flag
|
||||
func update(featureFlag: FeatureFlag, isEnabled: Bool) async {
|
||||
guard let provider = configSourceProvider as? UserDefaultsWalletConfigStorage else {
|
||||
LoggerProxy.debug("This is now only support with UserDefaultsWalletConfigStorage as configurationProvider.")
|
||||
return
|
||||
}
|
||||
|
||||
await provider.store(featureFlag: featureFlag, isEnabled: isEnabled)
|
||||
}
|
||||
|
||||
private func merge(
|
||||
configuration: WalletConfig,
|
||||
withDefaultConfiguration defaultConfiguration: WalletConfig
|
||||
) -> WalletConfig {
|
||||
var rawDefaultFlags = defaultConfiguration.flags
|
||||
rawDefaultFlags.merge(configuration.flags, uniquingKeysWith: { $1 })
|
||||
return WalletConfig(flags: rawDefaultFlags)
|
||||
}
|
||||
}
|
||||
|
||||
protocol WalletConfigSourceProvider {
|
||||
func load() async throws -> WalletConfig
|
||||
}
|
||||
|
||||
protocol WalletConfigProviderCache {
|
||||
func load() async -> WalletConfig?
|
||||
func store(_ configuration: WalletConfig) async
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// WalletConfigProviderInterface.swift
|
||||
// secant
|
||||
//
|
||||
// Created by Michal Fousek on 23.02.2023.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import Foundation
|
||||
|
||||
extension DependencyValues {
|
||||
var walletConfigProvider: WalletConfigProviderClient {
|
||||
get { self[WalletConfigProviderClient.self] }
|
||||
set { self[WalletConfigProviderClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct WalletConfigProviderClient {
|
||||
let load: () async -> WalletConfig
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// WalletConfigProviderLiveKey.swift
|
||||
// secant
|
||||
//
|
||||
// Created by Michal Fousek on 23.02.2023.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import Foundation
|
||||
|
||||
extension WalletConfigProviderClient: DependencyKey {
|
||||
static let liveValue = WalletConfigProviderClient.live()
|
||||
|
||||
private static var defaultWalletConfigProvider: WalletConfigProvider {
|
||||
WalletConfigProvider(
|
||||
configSourceProvider: UserDefaultsWalletConfigProvider(),
|
||||
cache: UserDefaultsWalletConfigProviderCache()
|
||||
)
|
||||
}
|
||||
|
||||
static func live(walletConfigProvider: WalletConfigProvider = WalletConfigProviderClient.defaultWalletConfigProvider) -> Self {
|
||||
Self(load: { return await walletConfigProvider.load() })
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// WalletConfigProviderTestKey.swift
|
||||
// secant
|
||||
//
|
||||
// Created by Michal Fousek on 23.02.2023.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import Foundation
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension WalletConfigProviderClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
load: XCTUnimplemented("\(Self.self).load", placeholder: WalletConfig.default)
|
||||
)
|
||||
}
|
||||
|
||||
extension WalletConfigProviderClient {
|
||||
static let `default` = Self(
|
||||
load: { WalletConfig.default }
|
||||
)
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// WalletConfig.swift
|
||||
// secant
|
||||
//
|
||||
// Created by Michal Fousek on 23.02.2023.
|
||||
//
|
||||
|
||||
enum FeatureFlag: String, CaseIterable, Codable {
|
||||
// These two flags should stay here because those are used in tests. It's not super nice but there is probably no other way.
|
||||
case testFlag1
|
||||
case testFlag2
|
||||
|
||||
var enabledByDefault: Bool {
|
||||
switch self {
|
||||
case .testFlag1, .testFlag2:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct WalletConfig: Equatable {
|
||||
typealias RawFlags = [FeatureFlag: Bool]
|
||||
|
||||
let flags: RawFlags
|
||||
|
||||
func isEnabled(_ featureFlag: FeatureFlag) -> Bool {
|
||||
return flags[featureFlag, default: false]
|
||||
}
|
||||
|
||||
static var `default`: WalletConfig = {
|
||||
let defaultSettings = FeatureFlag.allCases.map { ($0, $0.enabledByDefault) }
|
||||
return WalletConfig(flags: Dictionary(uniqueKeysWithValues: defaultSettings))
|
||||
}()
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
//
|
||||
// WalletConfigProviderTests.swift
|
||||
// secantTests
|
||||
//
|
||||
// Created by Michal Fousek on 23.02.2023.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import secant_testnet
|
||||
|
||||
class WalletConfigProviderTests: XCTestCase {
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
UserDefaultsWalletConfigStorage().clearAll()
|
||||
}
|
||||
|
||||
func testLoadFlagsFromProvider() async {
|
||||
XCTAssertFalse(WalletConfig.default.isEnabled(.testFlag1))
|
||||
XCTAssertFalse(WalletConfig.default.isEnabled(.testFlag2))
|
||||
|
||||
let provider = WalletConfigSourceProviderMock() {
|
||||
return WalletConfig(flags: [.testFlag1: true, .testFlag2: false])
|
||||
}
|
||||
|
||||
let manager = WalletConfigProvider(configSourceProvider: provider, cache: UserDefaultsWalletConfigStorage())
|
||||
let configuration = await manager.load()
|
||||
|
||||
XCTAssertTrue(configuration.isEnabled(.testFlag1))
|
||||
XCTAssertFalse(configuration.isEnabled(.testFlag2))
|
||||
}
|
||||
|
||||
func testLoadFlagsFromCache() async {
|
||||
XCTAssertFalse(WalletConfig.default.isEnabled(.testFlag1))
|
||||
XCTAssertFalse(WalletConfig.default.isEnabled(.testFlag2))
|
||||
|
||||
let provider = WalletConfigSourceProviderMock() { throw NSError(domain: "whatever", code: 21) }
|
||||
let cache = WalletConfigProviderCacheMock(cachedFlags: [.testFlag1: false, .testFlag2: true])
|
||||
|
||||
let manager = WalletConfigProvider(configSourceProvider: provider, cache: cache)
|
||||
let configuration = await manager.load()
|
||||
|
||||
XCTAssertFalse(configuration.isEnabled(.testFlag1))
|
||||
XCTAssertTrue(configuration.isEnabled(.testFlag2))
|
||||
}
|
||||
|
||||
func testLoadDefaultFlags() async {
|
||||
XCTAssertFalse(WalletConfig.default.isEnabled(.testFlag1))
|
||||
XCTAssertFalse(WalletConfig.default.isEnabled(.testFlag2))
|
||||
|
||||
let provider = WalletConfigSourceProviderMock() { throw NSError(domain: "whatever", code: 21) }
|
||||
let cache = WalletConfigProviderCacheMock(cachedFlags: [:])
|
||||
|
||||
let manager = WalletConfigProvider(configSourceProvider: provider, cache: cache)
|
||||
let configuration = await manager.load()
|
||||
|
||||
XCTAssertFalse(WalletConfig.default.isEnabled(.testFlag1))
|
||||
XCTAssertFalse(WalletConfig.default.isEnabled(.testFlag2))
|
||||
}
|
||||
|
||||
func testAllTheFlagsAreAlwaysReturned() async {
|
||||
XCTAssertFalse(WalletConfig.default.isEnabled(.testFlag1))
|
||||
XCTAssertFalse(WalletConfig.default.isEnabled(.testFlag2))
|
||||
|
||||
let provider = WalletConfigSourceProviderMock() {
|
||||
return WalletConfig(flags: [.testFlag1: true])
|
||||
}
|
||||
|
||||
let manager = WalletConfigProvider(configSourceProvider: provider, cache: UserDefaultsWalletConfigStorage())
|
||||
let configuration = await manager.load()
|
||||
|
||||
XCTAssertTrue(configuration.isEnabled(.testFlag1))
|
||||
XCTAssertFalse(configuration.isEnabled(.testFlag2))
|
||||
}
|
||||
|
||||
func testProvidedFlagsAreCached() async {
|
||||
XCTAssertFalse(WalletConfig.default.isEnabled(.testFlag1))
|
||||
XCTAssertFalse(WalletConfig.default.isEnabled(.testFlag2))
|
||||
|
||||
let provider = WalletConfigSourceProviderMock() {
|
||||
return WalletConfig(flags: [.testFlag1: true, .testFlag2: false])
|
||||
}
|
||||
let cache: WalletConfigProviderCache = UserDefaultsWalletConfigProviderCache()
|
||||
|
||||
let manager = WalletConfigProvider(configSourceProvider: provider, cache: cache)
|
||||
_ = await manager.load()
|
||||
|
||||
guard let cachedConfiguration = await cache.load() else {
|
||||
return XCTFail("No cached configuration.")
|
||||
}
|
||||
|
||||
XCTAssertTrue(cachedConfiguration.isEnabled(.testFlag1))
|
||||
XCTAssertFalse(cachedConfiguration.isEnabled(.testFlag2))
|
||||
}
|
||||
}
|
||||
|
||||
struct WalletConfigSourceProviderMock: WalletConfigSourceProvider {
|
||||
let provider: () async throws -> WalletConfig
|
||||
|
||||
func load() async throws -> WalletConfig {
|
||||
return try await provider()
|
||||
}
|
||||
}
|
||||
|
||||
class WalletConfigProviderCacheMock: WalletConfigProviderCache {
|
||||
var cachedFlags: WalletConfig.RawFlags = [:]
|
||||
|
||||
init(cachedFlags: WalletConfig.RawFlags) {
|
||||
self.cachedFlags = cachedFlags
|
||||
}
|
||||
|
||||
func load() async -> WalletConfig? {
|
||||
guard !cachedFlags.isEmpty else { return nil }
|
||||
return WalletConfig(flags: cachedFlags)
|
||||
}
|
||||
|
||||
func store(_ configuration: WalletConfig) async {
|
||||
cachedFlags = configuration.flags
|
||||
}
|
||||
}
|
||||
|
||||
extension UserDefaultsWalletConfigStorage {
|
||||
func clearAll() {
|
||||
let userdef = UserDefaults.standard
|
||||
userdef.removeObject(forKey: Constants.cacheKey)
|
||||
userdef.removeObject(forKey: Constants.providerKey)
|
||||
userdef.synchronize()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue