[98] [Scaffold] Full Wallet History (#376)
- concept of activities instead of transactions - the drawer is now fully universal and data driven, rendering some View, going to some detail View - unit tests work again - refactor of Activity -> WalletEvent - WalletEvent view builders simplified - transactions & wallet events timestamps instead of Date type - review comments resolved - missing 'Transactions' terms updated to 'WalletEvents'
This commit is contained in:
parent
675a067437
commit
e321114214
|
@ -112,7 +112,7 @@
|
|||
9E39115E284E3E350073DD9A /* secantUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D4E7A2526B364180058B01E /* secantUITests.swift */; };
|
||||
9E4DC6E027C409A100E657F4 /* NeumorphicDesignModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E4DC6DF27C409A100E657F4 /* NeumorphicDesignModifier.swift */; };
|
||||
9E4DC6E227C4C6B700E657F4 /* SecantButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E4DC6E127C4C6B700E657F4 /* SecantButtonStyles.swift */; };
|
||||
9E5BF63F2819542C00BA3F17 /* TransactionHistoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5BF63E2819542C00BA3F17 /* TransactionHistoryTests.swift */; };
|
||||
9E5BF63F2819542C00BA3F17 /* WalletEventsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5BF63E2819542C00BA3F17 /* WalletEventsTests.swift */; };
|
||||
9E5BF641281FD7B600BA3F17 /* TransactionFailedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5BF640281FD7B600BA3F17 /* TransactionFailedView.swift */; };
|
||||
9E5BF644281FEC9900BA3F17 /* SendTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5BF643281FEC9900BA3F17 /* SendTests.swift */; };
|
||||
9E5BF6462821028C00BA3F17 /* WrappedUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5BF6452821028C00BA3F17 /* WrappedUserDefaults.swift */; };
|
||||
|
@ -146,6 +146,8 @@
|
|||
9EAB466F285A0468002904A0 /* _URLRouting in Frameworks */ = {isa = PBXBuildFile; productRef = 9EAB466E285A0468002904A0 /* _URLRouting */; };
|
||||
9EAB4671285A1C77002904A0 /* DeeplinkHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAB4670285A1C77002904A0 /* DeeplinkHandler.swift */; };
|
||||
9EAB4676285B5C7C002904A0 /* DeeplinkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAB4675285B5C7C002904A0 /* DeeplinkTests.swift */; };
|
||||
9EAB46782860A1D2002904A0 /* WalletEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAB46772860A1D2002904A0 /* WalletEvent.swift */; };
|
||||
9EAB467A2861EA6A002904A0 /* TransactionRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAB46792861EA6A002904A0 /* TransactionRowView.swift */; };
|
||||
9EAFEB822805793200199FC9 /* AppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAFEB812805793200199FC9 /* AppTests.swift */; };
|
||||
9EAFEB84280597B700199FC9 /* WrappedSecItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAFEB83280597B700199FC9 /* WrappedSecItem.swift */; };
|
||||
9EAFEB862805A23100199FC9 /* WrappedSecItemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAFEB852805A23100199FC9 /* WrappedSecItemTests.swift */; };
|
||||
|
@ -166,9 +168,9 @@
|
|||
9EF8139C27F47AED0075AF48 /* InitializationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EF8139B27F47AED0075AF48 /* InitializationState.swift */; };
|
||||
F9322DC0273B555C00C105B5 /* NavigationLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9322DBF273B555C00C105B5 /* NavigationLinks.swift */; };
|
||||
F93673D62742CB840099C6AF /* Previews.swift in Sources */ = {isa = PBXBuildFile; fileRef = F93673D52742CB840099C6AF /* Previews.swift */; };
|
||||
F96B41E7273B501F0021B49A /* TransactionHistoryFlowStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F96B41E3273B501F0021B49A /* TransactionHistoryFlowStore.swift */; };
|
||||
F96B41E7273B501F0021B49A /* WalletEventsFlowStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F96B41E3273B501F0021B49A /* WalletEventsFlowStore.swift */; };
|
||||
F96B41E8273B501F0021B49A /* TransactionDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F96B41E5273B501F0021B49A /* TransactionDetailView.swift */; };
|
||||
F96B41E9273B501F0021B49A /* TransactionHistoryFlowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F96B41E6273B501F0021B49A /* TransactionHistoryFlowView.swift */; };
|
||||
F96B41E9273B501F0021B49A /* WalletEventsFlowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F96B41E6273B501F0021B49A /* WalletEventsFlowView.swift */; };
|
||||
F96B41EB273B50520021B49A /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = F96B41EA273B50520021B49A /* Strings.swift */; };
|
||||
F9971A4D27680DC400A2DB75 /* AppStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9971A4A27680DC400A2DB75 /* AppStore.swift */; };
|
||||
F9971A4E27680DC400A2DB75 /* AppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9971A4C27680DC400A2DB75 /* AppView.swift */; };
|
||||
|
@ -319,7 +321,7 @@
|
|||
9E4DC6DF27C409A100E657F4 /* NeumorphicDesignModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NeumorphicDesignModifier.swift; sourceTree = "<group>"; };
|
||||
9E4DC6E127C4C6B700E657F4 /* SecantButtonStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecantButtonStyles.swift; sourceTree = "<group>"; };
|
||||
9E5BF63B2818305D00BA3F17 /* TransactionState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionState.swift; sourceTree = "<group>"; };
|
||||
9E5BF63E2819542C00BA3F17 /* TransactionHistoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionHistoryTests.swift; sourceTree = "<group>"; };
|
||||
9E5BF63E2819542C00BA3F17 /* WalletEventsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletEventsTests.swift; sourceTree = "<group>"; };
|
||||
9E5BF640281FD7B600BA3F17 /* TransactionFailedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionFailedView.swift; sourceTree = "<group>"; };
|
||||
9E5BF643281FEC9900BA3F17 /* SendTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendTests.swift; sourceTree = "<group>"; };
|
||||
9E5BF6452821028C00BA3F17 /* WrappedUserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappedUserDefaults.swift; sourceTree = "<group>"; };
|
||||
|
@ -350,6 +352,8 @@
|
|||
9EAB46692859F42E002904A0 /* WrappedDeeplinkHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappedDeeplinkHandler.swift; sourceTree = "<group>"; };
|
||||
9EAB4670285A1C77002904A0 /* DeeplinkHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeeplinkHandler.swift; sourceTree = "<group>"; };
|
||||
9EAB4675285B5C7C002904A0 /* DeeplinkTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeeplinkTests.swift; sourceTree = "<group>"; };
|
||||
9EAB46772860A1D2002904A0 /* WalletEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletEvent.swift; sourceTree = "<group>"; };
|
||||
9EAB46792861EA6A002904A0 /* TransactionRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionRowView.swift; sourceTree = "<group>"; };
|
||||
9EAFEB812805793200199FC9 /* AppTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTests.swift; sourceTree = "<group>"; };
|
||||
9EAFEB83280597B700199FC9 /* WrappedSecItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappedSecItem.swift; sourceTree = "<group>"; };
|
||||
9EAFEB852805A23100199FC9 /* WrappedSecItemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappedSecItemTests.swift; sourceTree = "<group>"; };
|
||||
|
@ -369,9 +373,9 @@
|
|||
F93673D52742CB840099C6AF /* Previews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Previews.swift; sourceTree = "<group>"; };
|
||||
F93874ED273C4DE200F0E875 /* HomeStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeStore.swift; sourceTree = "<group>"; };
|
||||
F93874EF273C4DE200F0E875 /* HomeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = "<group>"; };
|
||||
F96B41E3273B501F0021B49A /* TransactionHistoryFlowStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionHistoryFlowStore.swift; sourceTree = "<group>"; };
|
||||
F96B41E3273B501F0021B49A /* WalletEventsFlowStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletEventsFlowStore.swift; sourceTree = "<group>"; };
|
||||
F96B41E5273B501F0021B49A /* TransactionDetailView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionDetailView.swift; sourceTree = "<group>"; };
|
||||
F96B41E6273B501F0021B49A /* TransactionHistoryFlowView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionHistoryFlowView.swift; sourceTree = "<group>"; };
|
||||
F96B41E6273B501F0021B49A /* WalletEventsFlowView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletEventsFlowView.swift; sourceTree = "<group>"; };
|
||||
F96B41EA273B50520021B49A /* Strings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = "<group>"; };
|
||||
F9971A4A27680DC400A2DB75 /* AppStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppStore.swift; sourceTree = "<group>"; };
|
||||
F9971A4C27680DC400A2DB75 /* AppView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppView.swift; sourceTree = "<group>"; };
|
||||
|
@ -516,7 +520,7 @@
|
|||
9E391122283E4C970073DD9A /* ImportWalletTests */,
|
||||
9E01F8262833CD84000EFC57 /* ScanTests */,
|
||||
9E5BF642281FEC8700BA3F17 /* SendTests */,
|
||||
9E5BF63D281953F900BA3F17 /* TransactionHistoryTests */,
|
||||
9E5BF63D281953F900BA3F17 /* WalletEventsTests */,
|
||||
9EAFEB802805791400199FC9 /* AppTests */,
|
||||
9EF8135927ECC25E0075AF48 /* UtilTests */,
|
||||
0DFE93E4272CB6D0000FCCA5 /* RecoveryPhraseValidationTests */,
|
||||
|
@ -577,6 +581,7 @@
|
|||
9E7FE0D6282D286500C374E8 /* RecoveryPhrase.swift */,
|
||||
9E7FE0DC282D298900C374E8 /* ValidationWord.swift */,
|
||||
9E7FE0E5282E7B1100C374E8 /* StoredWallet.swift */,
|
||||
9EAB46772860A1D2002904A0 /* WalletEvent.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
|
@ -673,7 +678,7 @@
|
|||
F9971A5B27680DF600A2DB75 /* Scan */,
|
||||
F9C165B62740403600592F76 /* SendFlow */,
|
||||
F9971A6127680DFE00A2DB75 /* Settings */,
|
||||
F96B41E2273B501F0021B49A /* TransactionHistoryFlow */,
|
||||
F96B41E2273B501F0021B49A /* WalletEventsFlow */,
|
||||
9E7FE0E4282E753700C374E8 /* RecoveryPhraseDisplay */,
|
||||
9E7FE0E3282E751A00C374E8 /* RecoveryPhraseValidationFlow */,
|
||||
6654C73C2715A3FA00901167 /* OnboardingFlow */,
|
||||
|
@ -816,12 +821,12 @@
|
|||
path = SnapshotTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E5BF63D281953F900BA3F17 /* TransactionHistoryTests */ = {
|
||||
9E5BF63D281953F900BA3F17 /* WalletEventsTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E5BF63E2819542C00BA3F17 /* TransactionHistoryTests.swift */,
|
||||
9E5BF63E2819542C00BA3F17 /* WalletEventsTests.swift */,
|
||||
);
|
||||
path = TransactionHistoryTests;
|
||||
path = WalletEventsTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E5BF642281FEC8700BA3F17 /* SendTests */ = {
|
||||
|
@ -1087,20 +1092,21 @@
|
|||
path = Home;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F96B41E2273B501F0021B49A /* TransactionHistoryFlow */ = {
|
||||
F96B41E2273B501F0021B49A /* WalletEventsFlow */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F96B41E3273B501F0021B49A /* TransactionHistoryFlowStore.swift */,
|
||||
F96B41E6273B501F0021B49A /* TransactionHistoryFlowView.swift */,
|
||||
F96B41E3273B501F0021B49A /* WalletEventsFlowStore.swift */,
|
||||
F96B41E6273B501F0021B49A /* WalletEventsFlowView.swift */,
|
||||
F96B41E4273B501F0021B49A /* Views */,
|
||||
);
|
||||
path = TransactionHistoryFlow;
|
||||
path = WalletEventsFlow;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F96B41E4273B501F0021B49A /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F96B41E5273B501F0021B49A /* TransactionDetailView.swift */,
|
||||
9EAB46792861EA6A002904A0 /* TransactionRowView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1396,7 +1402,7 @@
|
|||
0D35CC46277A36E00074316A /* ScrollableWhenScaled.swift in Sources */,
|
||||
9E39114A2848EEB90073DD9A /* UserPreferencesStorage.swift in Sources */,
|
||||
9EAB466A2859F42E002904A0 /* WrappedDeeplinkHandler.swift in Sources */,
|
||||
F96B41E9273B501F0021B49A /* TransactionHistoryFlowView.swift in Sources */,
|
||||
F96B41E9273B501F0021B49A /* WalletEventsFlowView.swift in Sources */,
|
||||
9E01F8202833861A000EFC57 /* WrappedCaptureDevice.swift in Sources */,
|
||||
2EDA07A027EDE18C00D6F09B /* TCATextField.swift in Sources */,
|
||||
9E7FE0DB282D28F100C374E8 /* WrappedPasteboard.swift in Sources */,
|
||||
|
@ -1414,6 +1420,7 @@
|
|||
9E7FE0CF282D257400C374E8 /* SDKSynchronizer+SyncStatus.swift in Sources */,
|
||||
9E4DC6E027C409A100E657F4 /* NeumorphicDesignModifier.swift in Sources */,
|
||||
0DACFA7F27208CE00039EEA5 /* Clamped.swift in Sources */,
|
||||
9EAB467A2861EA6A002904A0 /* TransactionRowView.swift in Sources */,
|
||||
0DFE93E3272CA1AA000FCCA5 /* RecoveryPhraseValidationFlowStore.swift in Sources */,
|
||||
9E2DF99E27CF704D00649636 /* ImportWalletView.swift in Sources */,
|
||||
0D535FE2271F9476009A9E3E /* EnumeratedChip.swift in Sources */,
|
||||
|
@ -1465,7 +1472,7 @@
|
|||
9E2AC10127D8EF0B0042AA47 /* WrappedMnemonic.swift in Sources */,
|
||||
9E7FE0D7282D286500C374E8 /* RecoveryPhrase.swift in Sources */,
|
||||
660558F7270C862F009D6954 /* Fonts+Generated.swift in Sources */,
|
||||
F96B41E7273B501F0021B49A /* TransactionHistoryFlowStore.swift in Sources */,
|
||||
F96B41E7273B501F0021B49A /* WalletEventsFlowStore.swift in Sources */,
|
||||
9E7FE0E6282E7B1100C374E8 /* StoredWallet.swift in Sources */,
|
||||
9EAFEB9128081E9400199FC9 /* HomeStore.swift in Sources */,
|
||||
F9971A5A27680DDE00A2DB75 /* RequestView.swift in Sources */,
|
||||
|
@ -1505,6 +1512,7 @@
|
|||
F9971A5427680DD000A2DB75 /* ProfileView.swift in Sources */,
|
||||
F9971A6027680DF600A2DB75 /* ScanStore.swift in Sources */,
|
||||
9EF8139127F191BF0075AF48 /* WrappedWalletStorage.swift in Sources */,
|
||||
9EAB46782860A1D2002904A0 /* WalletEvent.swift in Sources */,
|
||||
0DFE93E1272C9ECB000FCCA5 /* RecoveryPhraseBackupView.swift in Sources */,
|
||||
9E69A24D27FB002800A55317 /* WelcomeStore.swift in Sources */,
|
||||
F9C165CB2741AB5D00592F76 /* SendFlowView.swift in Sources */,
|
||||
|
@ -1542,7 +1550,7 @@
|
|||
9E391132284644580073DD9A /* AppInitializationTests.swift in Sources */,
|
||||
9E9ECC9928589E150099D5A2 /* RecoveryPhraseDisplaySnapshotTests.swift in Sources */,
|
||||
9E391124283E4CAC0073DD9A /* ImportWalletTests.swift in Sources */,
|
||||
9E5BF63F2819542C00BA3F17 /* TransactionHistoryTests.swift in Sources */,
|
||||
9E5BF63F2819542C00BA3F17 /* WalletEventsTests.swift in Sources */,
|
||||
0D4E7A1B26B364180058B01E /* secantTests.swift in Sources */,
|
||||
0DFE93E6272CB6F7000FCCA5 /* RecoveryPhraseValidationTests.swift in Sources */,
|
||||
9EAB4676285B5C7C002904A0 /* DeeplinkTests.swift in Sources */,
|
||||
|
|
|
@ -28,7 +28,7 @@ struct HomeState: Equatable {
|
|||
var scanState: ScanState
|
||||
var synchronizerStatus: String
|
||||
var totalBalance: Zatoshi
|
||||
var transactionHistoryState: TransactionHistoryFlowState
|
||||
var walletEventsState: WalletEventsFlowState
|
||||
var verifiedBalance: Zatoshi
|
||||
}
|
||||
|
||||
|
@ -43,12 +43,12 @@ enum HomeAction: Equatable {
|
|||
case send(SendFlowAction)
|
||||
case scan(ScanAction)
|
||||
case synchronizerStateChanged(WrappedSDKSynchronizerState)
|
||||
case transactionHistory(TransactionHistoryFlowAction)
|
||||
case walletEvents(WalletEventsFlowAction)
|
||||
case updateBalance(Balance)
|
||||
case updateDrawer(DrawerOverlay)
|
||||
case updateRoute(HomeState.Route?)
|
||||
case updateSynchronizerStatus
|
||||
case updateTransactions([TransactionState])
|
||||
case updateWalletEvents([WalletEvent])
|
||||
}
|
||||
|
||||
// MARK: Environment
|
||||
|
@ -106,7 +106,7 @@ extension HomeReducer {
|
|||
return .merge(
|
||||
environment.SDKSynchronizer.getAllClearedTransactions()
|
||||
.receive(on: environment.scheduler)
|
||||
.map(HomeAction.updateTransactions)
|
||||
.map(HomeAction.updateWalletEvents)
|
||||
.eraseToEffect(),
|
||||
|
||||
environment.SDKSynchronizer.getShieldedBalance()
|
||||
|
@ -128,10 +128,10 @@ extension HomeReducer {
|
|||
|
||||
case .updateDrawer(let drawerOverlay):
|
||||
state.drawerOverlay = drawerOverlay
|
||||
state.transactionHistoryState.isScrollable = drawerOverlay == .full ? true : false
|
||||
state.walletEventsState.isScrollable = drawerOverlay == .full ? true : false
|
||||
return .none
|
||||
|
||||
case .updateTransactions(let transactions):
|
||||
case .updateWalletEvents(let walletEvents):
|
||||
return .none
|
||||
|
||||
case .updateSynchronizerStatus:
|
||||
|
@ -148,13 +148,13 @@ extension HomeReducer {
|
|||
case .request(let action):
|
||||
return .none
|
||||
|
||||
case .transactionHistory(.updateRoute(.all)):
|
||||
case .walletEvents(.updateRoute(.all)):
|
||||
return state.drawerOverlay != .full ? Effect(value: .updateDrawer(.full)) : .none
|
||||
|
||||
case .transactionHistory(.updateRoute(.latest)):
|
||||
case .walletEvents(.updateRoute(.latest)):
|
||||
return state.drawerOverlay != .partial ? Effect(value: .updateDrawer(.partial)) : .none
|
||||
|
||||
case .transactionHistory(let historyAction):
|
||||
case .walletEvents(let historyAction):
|
||||
return .none
|
||||
|
||||
case .send(.updateRoute(.done)):
|
||||
|
@ -175,11 +175,11 @@ extension HomeReducer {
|
|||
}
|
||||
}
|
||||
|
||||
private static let historyReducer: HomeReducer = TransactionHistoryFlowReducer.default.pullback(
|
||||
state: \HomeState.transactionHistoryState,
|
||||
action: /HomeAction.transactionHistory,
|
||||
private static let historyReducer: HomeReducer = WalletEventsFlowReducer.default.pullback(
|
||||
state: \HomeState.walletEventsState,
|
||||
action: /HomeAction.walletEvents,
|
||||
environment: { environment in
|
||||
TransactionHistoryFlowEnvironment(
|
||||
WalletEventsFlowEnvironment(
|
||||
scheduler: environment.scheduler,
|
||||
SDKSynchronizer: environment.SDKSynchronizer
|
||||
)
|
||||
|
@ -228,10 +228,10 @@ extension HomeReducer {
|
|||
// MARK: - Store
|
||||
|
||||
extension HomeStore {
|
||||
func historyStore() -> TransactionHistoryFlowStore {
|
||||
func historyStore() -> WalletEventsFlowStore {
|
||||
self.scope(
|
||||
state: \.transactionHistoryState,
|
||||
action: HomeAction.transactionHistory
|
||||
state: \.walletEventsState,
|
||||
action: HomeAction.walletEvents
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -296,7 +296,7 @@ extension HomeState {
|
|||
scanState: .placeholder,
|
||||
synchronizerStatus: "",
|
||||
totalBalance: Zatoshi.zero,
|
||||
transactionHistoryState: .emptyPlaceHolder,
|
||||
walletEventsState: .emptyPlaceHolder,
|
||||
verifiedBalance: Zatoshi.zero
|
||||
)
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ struct HomeView: View {
|
|||
if proxy.size.height > 0 {
|
||||
Drawer(overlay: viewStore.bindingForDrawer(), maxHeight: proxy.size.height) {
|
||||
VStack {
|
||||
TransactionHistoryFlowView(store: store.historyStore())
|
||||
WalletEventsFlowView(store: store.historyStore())
|
||||
.padding(.top, 10)
|
||||
|
||||
Spacer()
|
||||
|
|
|
@ -16,7 +16,7 @@ struct SandboxState: Equatable {
|
|||
case scan
|
||||
case request
|
||||
}
|
||||
var transactionHistoryState: TransactionHistoryFlowState
|
||||
var walletEventsState: WalletEventsFlowState
|
||||
var profileState: ProfileState
|
||||
var route: Route?
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ struct SandboxState: Equatable {
|
|||
|
||||
enum SandboxAction: Equatable {
|
||||
case updateRoute(SandboxState.Route?)
|
||||
case transactionHistory(TransactionHistoryFlowAction)
|
||||
case walletEvents(WalletEventsFlowAction)
|
||||
case profile(ProfileAction)
|
||||
case reset
|
||||
}
|
||||
|
@ -42,18 +42,18 @@ extension SandboxReducer {
|
|||
case let .updateRoute(route):
|
||||
state.route = route
|
||||
return .none
|
||||
case let .transactionHistory(transactionHistoryAction):
|
||||
return TransactionHistoryFlowReducer
|
||||
case let .walletEvents(walletEventsAction):
|
||||
return WalletEventsFlowReducer
|
||||
.default
|
||||
.run(
|
||||
&state.transactionHistoryState,
|
||||
transactionHistoryAction,
|
||||
TransactionHistoryFlowEnvironment(
|
||||
&state.walletEventsState,
|
||||
walletEventsAction,
|
||||
WalletEventsFlowEnvironment(
|
||||
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
||||
SDKSynchronizer: LiveWrappedSDKSynchronizer()
|
||||
)
|
||||
)
|
||||
.map(SandboxAction.transactionHistory)
|
||||
.map(SandboxAction.walletEvents)
|
||||
case let .profile(profileAction):
|
||||
return ProfileReducer
|
||||
.default
|
||||
|
@ -72,10 +72,10 @@ extension SandboxReducer {
|
|||
// MARK: - Store
|
||||
|
||||
extension SandboxStore {
|
||||
func historyStore() -> TransactionHistoryFlowStore {
|
||||
func historyStore() -> WalletEventsFlowStore {
|
||||
self.scope(
|
||||
state: \.transactionHistoryState,
|
||||
action: SandboxAction.transactionHistory
|
||||
state: \.walletEventsState,
|
||||
action: SandboxAction.walletEvents
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -92,15 +92,15 @@ extension SandboxStore {
|
|||
extension SandboxViewStore {
|
||||
func toggleSelectedTransaction() {
|
||||
let isAlreadySelected = (self.selectedTranactionID != nil)
|
||||
let transcation = self.transactionHistoryState.transactions[5]
|
||||
let newRoute = isAlreadySelected ? nil : TransactionHistoryFlowState.Route.showTransaction(transcation)
|
||||
send(.transactionHistory(.updateRoute(newRoute)))
|
||||
let walletEvent = self.walletEventsState.walletEvents[5]
|
||||
let newRoute = isAlreadySelected ? nil : WalletEventsFlowState.Route.showWalletEvent(walletEvent)
|
||||
send(.walletEvents(.updateRoute(newRoute)))
|
||||
}
|
||||
|
||||
var selectedTranactionID: String? {
|
||||
self.transactionHistoryState
|
||||
self.walletEventsState
|
||||
.route
|
||||
.flatMap(/TransactionHistoryFlowState.Route.showTransaction)
|
||||
.flatMap(/WalletEventsFlowState.Route.showWalletEvent)
|
||||
.map(\.id)
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,7 @@ extension SandboxViewStore {
|
|||
extension SandboxState {
|
||||
static var placeholder: Self {
|
||||
.init(
|
||||
transactionHistoryState: .placeHolder,
|
||||
walletEventsState: .placeHolder,
|
||||
profileState: .placeholder,
|
||||
route: nil
|
||||
)
|
||||
|
@ -130,7 +130,7 @@ extension SandboxStore {
|
|||
static var placeholder: SandboxStore {
|
||||
SandboxStore(
|
||||
initialState: SandboxState(
|
||||
transactionHistoryState: .placeHolder,
|
||||
walletEventsState: .placeHolder,
|
||||
profileState: .placeholder,
|
||||
route: nil
|
||||
),
|
||||
|
|
|
@ -22,7 +22,7 @@ struct SandboxView: View {
|
|||
@ViewBuilder func view(for route: SandboxState.Route) -> some View {
|
||||
switch route {
|
||||
case .history:
|
||||
TransactionHistoryFlowView(store: store.historyStore())
|
||||
WalletEventsFlowView(store: store.historyStore())
|
||||
case .send:
|
||||
SendFlowView(
|
||||
store: .init(
|
||||
|
@ -94,7 +94,7 @@ struct SandboxView: View {
|
|||
isPresented: viewStore.bindingForRoute(.history),
|
||||
content: {
|
||||
NavigationView {
|
||||
TransactionHistoryFlowView(store: store.historyStore())
|
||||
WalletEventsFlowView(store: store.historyStore())
|
||||
.toolbar {
|
||||
ToolbarItem {
|
||||
Button("Done") { viewStore.send(.updateRoute(nil)) }
|
||||
|
|
|
@ -1,161 +0,0 @@
|
|||
import ComposableArchitecture
|
||||
import SwiftUI
|
||||
|
||||
typealias TransactionHistoryFlowReducer = Reducer<TransactionHistoryFlowState, TransactionHistoryFlowAction, TransactionHistoryFlowEnvironment>
|
||||
typealias TransactionHistoryFlowStore = Store<TransactionHistoryFlowState, TransactionHistoryFlowAction>
|
||||
typealias TransactionHistoryFlowViewStore = ViewStore<TransactionHistoryFlowState, TransactionHistoryFlowAction>
|
||||
|
||||
// MARK: - State
|
||||
|
||||
struct TransactionHistoryFlowState: Equatable {
|
||||
enum Route: Equatable {
|
||||
case latest
|
||||
case all
|
||||
case showTransaction(TransactionState)
|
||||
}
|
||||
|
||||
var route: Route?
|
||||
|
||||
var isScrollable = false
|
||||
var transactions: IdentifiedArrayOf<TransactionState>
|
||||
}
|
||||
|
||||
// MARK: - Action
|
||||
|
||||
enum TransactionHistoryFlowAction: Equatable {
|
||||
case onAppear
|
||||
case onDisappear
|
||||
case updateRoute(TransactionHistoryFlowState.Route?)
|
||||
case synchronizerStateChanged(WrappedSDKSynchronizerState)
|
||||
case updateTransactions([TransactionState])
|
||||
}
|
||||
|
||||
// MARK: - Environment
|
||||
|
||||
struct TransactionHistoryFlowEnvironment {
|
||||
let scheduler: AnySchedulerOf<DispatchQueue>
|
||||
let SDKSynchronizer: WrappedSDKSynchronizer
|
||||
}
|
||||
|
||||
// MARK: - Reducer
|
||||
|
||||
extension TransactionHistoryFlowReducer {
|
||||
private struct CancelId: Hashable {}
|
||||
|
||||
static let `default` = TransactionHistoryFlowReducer { state, action, environment in
|
||||
switch action {
|
||||
case .onAppear:
|
||||
return environment.SDKSynchronizer.stateChanged
|
||||
.map(TransactionHistoryFlowAction.synchronizerStateChanged)
|
||||
.eraseToEffect()
|
||||
.cancellable(id: CancelId(), cancelInFlight: true)
|
||||
|
||||
case .onDisappear:
|
||||
return Effect.cancel(id: CancelId())
|
||||
|
||||
case .synchronizerStateChanged(.synced):
|
||||
return environment.SDKSynchronizer.getAllTransactions()
|
||||
.receive(on: environment.scheduler)
|
||||
.map(TransactionHistoryFlowAction.updateTransactions)
|
||||
.eraseToEffect()
|
||||
|
||||
case .synchronizerStateChanged(let synchronizerState):
|
||||
return .none
|
||||
|
||||
case .updateTransactions(let transactions):
|
||||
let sortedTransactions = transactions
|
||||
.sorted(by: { lhs, rhs in
|
||||
lhs.date > rhs.date
|
||||
})
|
||||
state.transactions = IdentifiedArrayOf(uniqueElements: sortedTransactions)
|
||||
return .none
|
||||
|
||||
case let .updateRoute(route):
|
||||
state.route = route
|
||||
return .none
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ViewStore
|
||||
|
||||
extension TransactionHistoryFlowViewStore {
|
||||
private typealias Route = TransactionHistoryFlowState.Route
|
||||
|
||||
func bindingForSelectingTransaction(_ transaction: TransactionState) -> Binding<Bool> {
|
||||
self.binding(
|
||||
get: { $0.route.map(/TransactionHistoryFlowState.Route.showTransaction) == transaction },
|
||||
send: { isActive in
|
||||
TransactionHistoryFlowAction.updateRoute( isActive ? TransactionHistoryFlowState.Route.showTransaction(transaction) : nil)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Placeholders
|
||||
|
||||
extension TransactionState {
|
||||
static var placeholder: Self {
|
||||
.init(
|
||||
date: Date.init(timeIntervalSince1970: 1234567),
|
||||
id: "2",
|
||||
status: .paid(success: true),
|
||||
subtitle: "",
|
||||
zecAmount: Zatoshi(amount: 25)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension TransactionHistoryFlowState {
|
||||
static var placeHolder: Self {
|
||||
.init(transactions: .placeholder)
|
||||
}
|
||||
|
||||
static var emptyPlaceHolder: Self {
|
||||
.init(transactions: [])
|
||||
}
|
||||
}
|
||||
|
||||
extension TransactionHistoryFlowStore {
|
||||
static var placeholder: Store<TransactionHistoryFlowState, TransactionHistoryFlowAction> {
|
||||
return Store(
|
||||
initialState: .placeHolder,
|
||||
reducer: .default,
|
||||
environment: TransactionHistoryFlowEnvironment(
|
||||
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
||||
SDKSynchronizer: LiveWrappedSDKSynchronizer()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
static var demoWithSelectedTransaction: Store<TransactionHistoryFlowState, TransactionHistoryFlowAction> {
|
||||
let transactions = IdentifiedArrayOf<TransactionState>.placeholder
|
||||
return Store(
|
||||
initialState: TransactionHistoryFlowState(
|
||||
route: .showTransaction(transactions[3]),
|
||||
transactions: transactions
|
||||
),
|
||||
reducer: .default.debug(),
|
||||
environment: TransactionHistoryFlowEnvironment(
|
||||
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
||||
SDKSynchronizer: LiveWrappedSDKSynchronizer()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension IdentifiedArrayOf where Element == TransactionState {
|
||||
static var placeholder: IdentifiedArrayOf<TransactionState> {
|
||||
return .init(
|
||||
uniqueElements: (0..<30).map {
|
||||
TransactionState(
|
||||
date: Date.init(timeIntervalSince1970: 1234567),
|
||||
id: String($0),
|
||||
status: .paid(success: true),
|
||||
subtitle: "",
|
||||
zecAmount: Zatoshi(amount: 25)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// TransactionRowView.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 21.06.2022.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct TransactionRowView: View {
|
||||
var transaction: TransactionState
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Circle()
|
||||
.foregroundColor(.white)
|
||||
.frame(width: 30, height: 30, alignment: .center)
|
||||
|
||||
VStack {
|
||||
HStack {
|
||||
Text(transaction.status == .received ? "Unknown paid you" : "You sent to")
|
||||
.font(.system(size: 14))
|
||||
.fontWeight(.bold)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text(transaction.status == .received ? "+" : "")
|
||||
+ Text("\(transaction.zecAmount.decimalString()) ZEC")
|
||||
}
|
||||
HStack {
|
||||
Text(transaction.address)
|
||||
.font(.system(size: 14))
|
||||
.fontWeight(.thin)
|
||||
.truncationMode(.middle)
|
||||
.lineLimit(1)
|
||||
|
||||
Spacer(minLength: 80)
|
||||
|
||||
Text("$145")
|
||||
.font(.system(size: 14))
|
||||
.fontWeight(.thin)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SendTransactionRowView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
VStack {
|
||||
TransactionRowView(transaction: .placeholder)
|
||||
}
|
||||
.padding()
|
||||
.preferredColorScheme(.dark)
|
||||
.previewLayout(.fixed(width: 428, height: 60))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
import ComposableArchitecture
|
||||
import SwiftUI
|
||||
|
||||
typealias WalletEventsFlowReducer = Reducer<WalletEventsFlowState, WalletEventsFlowAction, WalletEventsFlowEnvironment>
|
||||
typealias WalletEventsFlowStore = Store<WalletEventsFlowState, WalletEventsFlowAction>
|
||||
typealias WalletEventsFlowViewStore = ViewStore<WalletEventsFlowState, WalletEventsFlowAction>
|
||||
|
||||
// MARK: - State
|
||||
|
||||
struct WalletEventsFlowState: Equatable {
|
||||
enum Route: Equatable {
|
||||
case latest
|
||||
case all
|
||||
case showWalletEvent(WalletEvent)
|
||||
}
|
||||
|
||||
var route: Route?
|
||||
|
||||
var isScrollable = false
|
||||
var walletEvents = IdentifiedArrayOf<WalletEvent>.placeholder
|
||||
}
|
||||
|
||||
// MARK: - Action
|
||||
|
||||
enum WalletEventsFlowAction: Equatable {
|
||||
case onAppear
|
||||
case onDisappear
|
||||
case updateRoute(WalletEventsFlowState.Route?)
|
||||
case synchronizerStateChanged(WrappedSDKSynchronizerState)
|
||||
case updateWalletEvents([WalletEvent])
|
||||
}
|
||||
|
||||
// MARK: - Environment
|
||||
|
||||
struct WalletEventsFlowEnvironment {
|
||||
let scheduler: AnySchedulerOf<DispatchQueue>
|
||||
let SDKSynchronizer: WrappedSDKSynchronizer
|
||||
}
|
||||
|
||||
// MARK: - Reducer
|
||||
|
||||
extension WalletEventsFlowReducer {
|
||||
private struct CancelId: Hashable {}
|
||||
|
||||
static let `default` = WalletEventsFlowReducer { state, action, environment in
|
||||
switch action {
|
||||
case .onAppear:
|
||||
return environment.SDKSynchronizer.stateChanged
|
||||
.map(WalletEventsFlowAction.synchronizerStateChanged)
|
||||
.eraseToEffect()
|
||||
.cancellable(id: CancelId(), cancelInFlight: true)
|
||||
|
||||
case .onDisappear:
|
||||
return Effect.cancel(id: CancelId())
|
||||
|
||||
case .synchronizerStateChanged(.synced):
|
||||
return environment.SDKSynchronizer.getAllTransactions()
|
||||
.receive(on: environment.scheduler)
|
||||
.map(WalletEventsFlowAction.updateWalletEvents)
|
||||
.eraseToEffect()
|
||||
|
||||
case .synchronizerStateChanged(let synchronizerState):
|
||||
return .none
|
||||
|
||||
case .updateWalletEvents(let walletEvents):
|
||||
let sortedWalletEvents = walletEvents
|
||||
.sorted(by: { lhs, rhs in
|
||||
lhs.timestamp > rhs.timestamp
|
||||
})
|
||||
state.walletEvents = IdentifiedArrayOf(uniqueElements: sortedWalletEvents)
|
||||
return .none
|
||||
|
||||
case let .updateRoute(route):
|
||||
state.route = route
|
||||
return .none
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ViewStore
|
||||
|
||||
extension WalletEventsFlowViewStore {
|
||||
private typealias Route = WalletEventsFlowState.Route
|
||||
|
||||
func bindingForSelectingWalletEvent(_ walletEvent: WalletEvent) -> Binding<Bool> {
|
||||
self.binding(
|
||||
get: { $0.route.map(/WalletEventsFlowState.Route.showWalletEvent) == walletEvent },
|
||||
send: { isActive in
|
||||
WalletEventsFlowAction.updateRoute( isActive ? WalletEventsFlowState.Route.showWalletEvent(walletEvent) : nil)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Placeholders
|
||||
|
||||
extension TransactionState {
|
||||
static var placeholder: Self {
|
||||
.init(
|
||||
id: "2",
|
||||
status: .paid(success: true),
|
||||
subtitle: "",
|
||||
timestamp: 1234567,
|
||||
zecAmount: Zatoshi(amount: 25)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension WalletEventsFlowState {
|
||||
static var placeHolder: Self {
|
||||
.init(walletEvents: .placeholder)
|
||||
}
|
||||
|
||||
static var emptyPlaceHolder: Self {
|
||||
.init(walletEvents: [])
|
||||
}
|
||||
}
|
||||
|
||||
extension WalletEventsFlowStore {
|
||||
static var placeholder: Store<WalletEventsFlowState, WalletEventsFlowAction> {
|
||||
return Store(
|
||||
initialState: .placeHolder,
|
||||
reducer: .default,
|
||||
environment: WalletEventsFlowEnvironment(
|
||||
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
||||
SDKSynchronizer: LiveWrappedSDKSynchronizer()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension IdentifiedArrayOf where Element == TransactionState {
|
||||
static var placeholder: IdentifiedArrayOf<TransactionState> {
|
||||
return .init(
|
||||
uniqueElements: (0..<30).map {
|
||||
TransactionState(
|
||||
id: String($0),
|
||||
status: .paid(success: true),
|
||||
subtitle: "",
|
||||
timestamp: 1234567,
|
||||
zecAmount: Zatoshi(amount: 25)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
import SwiftUI
|
||||
import ComposableArchitecture
|
||||
|
||||
struct TransactionHistoryFlowView: View {
|
||||
let store: TransactionHistoryFlowStore
|
||||
struct WalletEventsFlowView: View {
|
||||
let store: WalletEventsFlowStore
|
||||
|
||||
var body: some View {
|
||||
UITableView.appearance().backgroundColor = .clear
|
||||
|
@ -14,11 +14,11 @@ struct TransactionHistoryFlowView: View {
|
|||
|
||||
if viewStore.isScrollable {
|
||||
List {
|
||||
transactionsList(with: viewStore)
|
||||
walletEventsList(with: viewStore)
|
||||
}
|
||||
.listStyle(.sidebar)
|
||||
} else {
|
||||
transactionsList(with: viewStore)
|
||||
walletEventsList(with: viewStore)
|
||||
.padding(.horizontal, 32)
|
||||
}
|
||||
}
|
||||
|
@ -28,36 +28,16 @@ struct TransactionHistoryFlowView: View {
|
|||
}
|
||||
}
|
||||
|
||||
extension TransactionHistoryFlowView {
|
||||
func transactionsList(with viewStore: TransactionHistoryFlowViewStore) -> some View {
|
||||
ForEach(viewStore.transactions) { transaction in
|
||||
WithStateBinding(binding: viewStore.bindingForSelectingTransaction(transaction)) { active in
|
||||
extension WalletEventsFlowView {
|
||||
func walletEventsList(with viewStore: WalletEventsFlowViewStore) -> some View {
|
||||
ForEach(viewStore.walletEvents) { walletEvent in
|
||||
WithStateBinding(binding: viewStore.bindingForSelectingWalletEvent(walletEvent)) { active in
|
||||
VStack {
|
||||
HStack {
|
||||
Text(transaction.date.asHumanReadable())
|
||||
.font(.system(size: 12))
|
||||
.fontWeight(.thin)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text(transaction.subtitle)
|
||||
.font(.system(size: 12))
|
||||
.fontWeight(.thin)
|
||||
.foregroundColor(transaction.subtitle == "pending" ? .red : .green)
|
||||
}
|
||||
|
||||
HStack {
|
||||
Text(transaction.status == .received ? "Recevied" : "Sent")
|
||||
|
||||
Spacer()
|
||||
|
||||
Text(transaction.status == .received ? "+" : "")
|
||||
+ Text("\(transaction.zecAmount.decimalString()) ZEC")
|
||||
}
|
||||
walletEvent.rowView()
|
||||
}
|
||||
.navigationLink(
|
||||
isActive: active,
|
||||
destination: { TransactionDetailView(transaction: transaction) }
|
||||
destination: { walletEvent.detailView() }
|
||||
)
|
||||
.foregroundColor(Asset.Colors.Text.body.color)
|
||||
.listRowBackground(Color.clear)
|
||||
|
@ -65,7 +45,7 @@ extension TransactionHistoryFlowView {
|
|||
}
|
||||
}
|
||||
|
||||
func header(with viewStore: TransactionHistoryFlowViewStore) -> some View {
|
||||
func header(with viewStore: WalletEventsFlowViewStore) -> some View {
|
||||
HStack(spacing: 0) {
|
||||
VStack {
|
||||
Button("Latest") {
|
||||
|
@ -95,7 +75,7 @@ extension TransactionHistoryFlowView {
|
|||
struct TransactionView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationView {
|
||||
TransactionHistoryFlowView(store: .placeholder)
|
||||
WalletEventsFlowView(store: .placeholder)
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ struct TransactionState: Equatable, Identifiable {
|
|||
enum Status: Equatable {
|
||||
case paid(success: Bool)
|
||||
case received
|
||||
case failed
|
||||
}
|
||||
|
||||
var expirationHeight = -1
|
||||
|
@ -21,16 +22,18 @@ struct TransactionState: Equatable, Identifiable {
|
|||
var shielded = true
|
||||
var zAddress: String?
|
||||
|
||||
var date: Date
|
||||
var id: String
|
||||
var status: Status
|
||||
var subtitle: String
|
||||
var timestamp: TimeInterval
|
||||
var zecAmount: Zatoshi
|
||||
|
||||
var address: String { zAddress ?? "" }
|
||||
}
|
||||
|
||||
extension TransactionState {
|
||||
init(confirmedTransaction: ConfirmedTransactionEntity, sent: Bool = false) {
|
||||
date = Date(timeIntervalSince1970: confirmedTransaction.blockTimeInSeconds)
|
||||
timestamp = confirmedTransaction.blockTimeInSeconds
|
||||
id = confirmedTransaction.transactionEntity.transactionId.toHexStringTxId()
|
||||
shielded = true
|
||||
status = sent ? .paid(success: confirmedTransaction.minedHeight > 0) : .received
|
||||
|
@ -44,7 +47,7 @@ extension TransactionState {
|
|||
}
|
||||
|
||||
init(pendingTransaction: PendingTransactionEntity, latestBlockHeight: BlockHeight? = nil) {
|
||||
date = Date(timeIntervalSince1970: pendingTransaction.createTime)
|
||||
timestamp = pendingTransaction.createTime
|
||||
id = pendingTransaction.rawTransactionId?.toHexStringTxId() ?? String(pendingTransaction.createTime)
|
||||
shielded = true
|
||||
status = .paid(success: pendingTransaction.isSubmitSuccess)
|
||||
|
@ -63,11 +66,11 @@ extension TransactionState {
|
|||
|
||||
extension TransactionState {
|
||||
static func placeholder(
|
||||
date: Date,
|
||||
amount: Zatoshi,
|
||||
shielded: Bool = true,
|
||||
status: Status = .received,
|
||||
subtitle: String = "",
|
||||
timestamp: TimeInterval,
|
||||
uuid: String = UUID().debugDescription
|
||||
) -> TransactionState {
|
||||
.init(
|
||||
|
@ -76,10 +79,10 @@ extension TransactionState {
|
|||
minedHeight: -1,
|
||||
shielded: shielded,
|
||||
zAddress: nil,
|
||||
date: date,
|
||||
id: uuid,
|
||||
status: status,
|
||||
subtitle: subtitle,
|
||||
timestamp: timestamp,
|
||||
zecAmount: status == .received ? amount : Zatoshi(amount: -amount.amount)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
//
|
||||
// WalletEvent.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 20.06.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import SwiftUI
|
||||
import ZcashLightClientKit
|
||||
|
||||
// MARK: - Model
|
||||
|
||||
struct WalletEvent: Equatable, Identifiable {
|
||||
enum WalletEventState: Equatable {
|
||||
case send(TransactionState)
|
||||
case pending(TransactionState)
|
||||
case received(TransactionState)
|
||||
case failed(TransactionState)
|
||||
case shielded(Zatoshi)
|
||||
case walletImport(BlockHeight)
|
||||
}
|
||||
|
||||
let id: String
|
||||
let state: WalletEventState
|
||||
var timestamp: TimeInterval
|
||||
}
|
||||
|
||||
// MARK: - Rows
|
||||
|
||||
extension WalletEvent {
|
||||
@ViewBuilder func rowView() -> some View {
|
||||
switch state {
|
||||
case .send(let transaction):
|
||||
TransactionRowView(transaction: transaction)
|
||||
case .pending:
|
||||
Text("pending wallet event")
|
||||
case .received:
|
||||
Text("received wallet event")
|
||||
case .failed:
|
||||
Text("failed wallet event")
|
||||
case .shielded(let zatoshi):
|
||||
Text("shielded wallet event \(zatoshi.decimalString())")
|
||||
case .walletImport:
|
||||
Text("wallet import wallet event")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Details
|
||||
|
||||
extension WalletEvent {
|
||||
@ViewBuilder func detailView() -> some View {
|
||||
switch state {
|
||||
case .send(let transaction):
|
||||
TransactionDetailView(transaction: transaction)
|
||||
case .pending:
|
||||
Text("pending transaction detail")
|
||||
case .received:
|
||||
Text("received transaction detail")
|
||||
case .failed:
|
||||
Text("failed transaction detail")
|
||||
case .shielded(let zatoshi):
|
||||
Text("shielded \(zatoshi.decimalString()) detail")
|
||||
case .walletImport:
|
||||
Text("wallet import wallet event")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Placeholders
|
||||
|
||||
private extension WalletEvent {
|
||||
static func randomWalletEventState() -> WalletEvent.WalletEventState {
|
||||
switch Int.random(in: 0..<5) {
|
||||
case 1: return .received(.placeholder)
|
||||
case 2: return .failed(.placeholder)
|
||||
case 3: return .shielded(Zatoshi(amount: 234_000_000))
|
||||
case 4: return .walletImport(BlockHeight(1_629_724))
|
||||
default: return .send(.placeholder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension IdentifiedArrayOf where Element == WalletEvent {
|
||||
static var placeholder: IdentifiedArrayOf<WalletEvent> {
|
||||
return .init(
|
||||
uniqueElements: (0..<30).map {
|
||||
WalletEvent(
|
||||
id: String($0),
|
||||
state: WalletEvent.randomWalletEventState(),
|
||||
timestamp: 1234567
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -48,9 +48,9 @@ protocol WrappedSDKSynchronizer {
|
|||
func status() -> String
|
||||
|
||||
func getShieldedBalance() -> Effect<Balance, Never>
|
||||
func getAllClearedTransactions() -> Effect<[TransactionState], Never>
|
||||
func getAllPendingTransactions() -> Effect<[TransactionState], Never>
|
||||
func getAllTransactions() -> Effect<[TransactionState], Never>
|
||||
func getAllClearedTransactions() -> Effect<[WalletEvent], Never>
|
||||
func getAllPendingTransactions() -> Effect<[WalletEvent], Never>
|
||||
func getAllTransactions() -> Effect<[WalletEvent], Never>
|
||||
|
||||
func getTransparentAddress(account: Int) -> TransparentAddress?
|
||||
func getShieldedAddress(account: Int) -> SaplingShieldedAddress?
|
||||
|
@ -160,37 +160,40 @@ class LiveWrappedSDKSynchronizer: WrappedSDKSynchronizer {
|
|||
return .none
|
||||
}
|
||||
|
||||
func getAllClearedTransactions() -> Effect<[TransactionState], Never> {
|
||||
func getAllClearedTransactions() -> Effect<[WalletEvent], Never> {
|
||||
if let clearedTransactions = try? synchronizer?.allClearedTransactions() {
|
||||
return Effect(value: clearedTransactions.map {
|
||||
TransactionState.init(confirmedTransaction: $0, sent: ($0.toAddress != nil))
|
||||
let transaction = TransactionState.init(confirmedTransaction: $0, sent: ($0.toAddress != nil))
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
})
|
||||
}
|
||||
|
||||
return .none
|
||||
}
|
||||
|
||||
func getAllPendingTransactions() -> Effect<[TransactionState], Never> {
|
||||
func getAllPendingTransactions() -> Effect<[WalletEvent], Never> {
|
||||
if let pendingTransactions = try? synchronizer?.allPendingTransactions(),
|
||||
let syncedBlockHeight = synchronizer?.latestScannedHeight {
|
||||
return Effect(value: pendingTransactions.map {
|
||||
// TODO: - can we initialize it with latestBlockHeight: = nil?
|
||||
TransactionState.init(pendingTransaction: $0, latestBlockHeight: syncedBlockHeight)
|
||||
let transaction = TransactionState.init(pendingTransaction: $0, latestBlockHeight: syncedBlockHeight)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
})
|
||||
}
|
||||
|
||||
return .none
|
||||
}
|
||||
|
||||
func getAllTransactions() -> Effect<[TransactionState], Never> {
|
||||
func getAllTransactions() -> Effect<[WalletEvent], Never> {
|
||||
if let pendingTransactions = try? synchronizer?.allPendingTransactions(),
|
||||
let clearedTransactions = try? synchronizer?.allClearedTransactions(),
|
||||
let syncedBlockHeight = synchronizer?.latestScannedHeight {
|
||||
let clearedTxs = clearedTransactions.map {
|
||||
TransactionState.init(confirmedTransaction: $0, sent: ($0.toAddress != nil))
|
||||
let clearedTxs: [WalletEvent] = clearedTransactions.map {
|
||||
let transaction = TransactionState.init(confirmedTransaction: $0, sent: ($0.toAddress != nil))
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
let pendingTxs = pendingTransactions.map {
|
||||
TransactionState.init(pendingTransaction: $0, latestBlockHeight: syncedBlockHeight)
|
||||
let pendingTxs: [WalletEvent] = pendingTransactions.map {
|
||||
let transaction = TransactionState.init(pendingTransaction: $0, latestBlockHeight: syncedBlockHeight)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
|
||||
let txs = clearedTxs.filter { cleared in
|
||||
|
@ -290,7 +293,7 @@ class MockWrappedSDKSynchronizer: WrappedSDKSynchronizer {
|
|||
return Effect(value: Balance(verified: 12345000, total: 12345000))
|
||||
}
|
||||
|
||||
func getAllClearedTransactions() -> Effect<[TransactionState], Never> {
|
||||
func getAllClearedTransactions() -> Effect<[WalletEvent], Never> {
|
||||
let mocked: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(date: 1651039202, amount: Zatoshi(amount: 1), status: .paid(success: false), uuid: "1"),
|
||||
TransactionStateMockHelper(date: 1651039101, amount: Zatoshi(amount: 2), uuid: "2"),
|
||||
|
@ -302,19 +305,20 @@ class MockWrappedSDKSynchronizer: WrappedSDKSynchronizer {
|
|||
return Effect(
|
||||
value:
|
||||
mocked.map {
|
||||
TransactionState.placeholder(
|
||||
date: Date.init(timeIntervalSince1970: $0.date),
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
subtitle: $0.subtitle,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func getAllPendingTransactions() -> Effect<[TransactionState], Never> {
|
||||
func getAllPendingTransactions() -> Effect<[WalletEvent], Never> {
|
||||
let mocked: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(date: 1651039606, amount: Zatoshi(amount: 6), status: .paid(success: false), subtitle: "pending"),
|
||||
TransactionStateMockHelper(date: 1651039303, amount: Zatoshi(amount: 7), subtitle: "pending"),
|
||||
|
@ -325,18 +329,19 @@ class MockWrappedSDKSynchronizer: WrappedSDKSynchronizer {
|
|||
return Effect(
|
||||
value:
|
||||
mocked.map {
|
||||
TransactionState.placeholder(
|
||||
date: Date.init(timeIntervalSince1970: $0.date),
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
subtitle: $0.subtitle
|
||||
subtitle: $0.subtitle,
|
||||
timestamp: $0.date
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func getAllTransactions() -> Effect<[TransactionState], Never> {
|
||||
func getAllTransactions() -> Effect<[WalletEvent], Never> {
|
||||
return .merge(
|
||||
getAllClearedTransactions(),
|
||||
getAllPendingTransactions()
|
||||
|
@ -363,10 +368,10 @@ class MockWrappedSDKSynchronizer: WrappedSDKSynchronizer {
|
|||
minedHeight: 50,
|
||||
shielded: true,
|
||||
zAddress: "tteafadlamnelkqe",
|
||||
date: Date.init(timeIntervalSince1970: 1234567),
|
||||
id: "id",
|
||||
status: .paid(success: true),
|
||||
subtitle: "sub",
|
||||
timestamp: 1234567,
|
||||
zecAmount: Zatoshi(amount: 10)
|
||||
)
|
||||
|
||||
|
@ -398,7 +403,7 @@ class TestWrappedSDKSynchronizer: WrappedSDKSynchronizer {
|
|||
return .none
|
||||
}
|
||||
|
||||
func getAllClearedTransactions() -> Effect<[TransactionState], Never> {
|
||||
func getAllClearedTransactions() -> Effect<[WalletEvent], Never> {
|
||||
let mocked: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(date: 1651039202, amount: Zatoshi(amount: 1), status: .paid(success: false), uuid: "aa11"),
|
||||
TransactionStateMockHelper(date: 1651039101, amount: Zatoshi(amount: 2), uuid: "bb22"),
|
||||
|
@ -410,19 +415,20 @@ class TestWrappedSDKSynchronizer: WrappedSDKSynchronizer {
|
|||
return Effect(
|
||||
value:
|
||||
mocked.map {
|
||||
TransactionState.placeholder(
|
||||
date: Date.init(timeIntervalSince1970: $0.date),
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
subtitle: $0.subtitle,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func getAllPendingTransactions() -> Effect<[TransactionState], Never> {
|
||||
func getAllPendingTransactions() -> Effect<[WalletEvent], Never> {
|
||||
let mocked: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(
|
||||
date: 1651039606,
|
||||
|
@ -439,19 +445,20 @@ class TestWrappedSDKSynchronizer: WrappedSDKSynchronizer {
|
|||
return Effect(
|
||||
value:
|
||||
mocked.map {
|
||||
TransactionState.placeholder(
|
||||
date: Date.init(timeIntervalSince1970: $0.date),
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
subtitle: $0.subtitle,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func getAllTransactions() -> Effect<[TransactionState], Never> {
|
||||
func getAllTransactions() -> Effect<[WalletEvent], Never> {
|
||||
return .merge(
|
||||
getAllClearedTransactions(),
|
||||
getAllPendingTransactions()
|
||||
|
|
|
@ -74,18 +74,19 @@ class HomeTests: XCTestCase {
|
|||
TransactionStateMockHelper(date: 1651039505, amount: Zatoshi(amount: 4), uuid: "4"),
|
||||
TransactionStateMockHelper(date: 1651039404, amount: Zatoshi(amount: 5), uuid: "5")
|
||||
]
|
||||
let transactions = transactionsHelper.map {
|
||||
TransactionState.placeholder(
|
||||
date: Date.init(timeIntervalSince1970: $0.date),
|
||||
let walletEvents: [WalletEvent] = transactionsHelper.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
subtitle: $0.subtitle,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
|
||||
store.receive(.updateTransactions(transactions))
|
||||
store.receive(.updateWalletEvents(walletEvents))
|
||||
|
||||
// ad 3.
|
||||
let balance = Balance(verified: 12_345_000, total: 12_345_000)
|
||||
|
@ -96,7 +97,7 @@ class HomeTests: XCTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
func testTransactionHistoryPartial_to_FullDrawer() throws {
|
||||
func testWalletEventsPartial_to_FullDrawer() throws {
|
||||
// setup the store and environment to be fully mocked
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
|
@ -118,7 +119,7 @@ class HomeTests: XCTestCase {
|
|||
scanState: .placeholder,
|
||||
synchronizerStatus: "",
|
||||
totalBalance: Zatoshi.zero,
|
||||
transactionHistoryState: .emptyPlaceHolder,
|
||||
walletEventsState: .emptyPlaceHolder,
|
||||
verifiedBalance: Zatoshi.zero
|
||||
)
|
||||
|
||||
|
@ -128,17 +129,17 @@ class HomeTests: XCTestCase {
|
|||
environment: testEnvironment
|
||||
)
|
||||
|
||||
store.send(.transactionHistory(.updateRoute(.all))) { state in
|
||||
state.transactionHistoryState.route = .all
|
||||
store.send(.walletEvents(.updateRoute(.all))) { state in
|
||||
state.walletEventsState.route = .all
|
||||
}
|
||||
|
||||
store.receive(.updateDrawer(.full)) { state in
|
||||
state.drawerOverlay = .full
|
||||
state.transactionHistoryState.isScrollable = true
|
||||
state.walletEventsState.isScrollable = true
|
||||
}
|
||||
}
|
||||
|
||||
func testTransactionHistoryFull_to_PartialDrawer() throws {
|
||||
func testWalletEventsFull_to_PartialDrawer() throws {
|
||||
// setup the store and environment to be fully mocked
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
|
@ -160,7 +161,7 @@ class HomeTests: XCTestCase {
|
|||
scanState: .placeholder,
|
||||
synchronizerStatus: "",
|
||||
totalBalance: Zatoshi.zero,
|
||||
transactionHistoryState: .emptyPlaceHolder,
|
||||
walletEventsState: .emptyPlaceHolder,
|
||||
verifiedBalance: Zatoshi.zero
|
||||
)
|
||||
|
||||
|
@ -170,13 +171,13 @@ class HomeTests: XCTestCase {
|
|||
environment: testEnvironment
|
||||
)
|
||||
|
||||
store.send(.transactionHistory(.updateRoute(.latest))) { state in
|
||||
state.transactionHistoryState.route = .latest
|
||||
store.send(.walletEvents(.updateRoute(.latest))) { state in
|
||||
state.walletEventsState.route = .latest
|
||||
}
|
||||
|
||||
store.receive(.updateDrawer(.partial)) { state in
|
||||
state.drawerOverlay = .partial
|
||||
state.transactionHistoryState.isScrollable = false
|
||||
state.walletEventsState.isScrollable = false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -64,10 +64,10 @@ class SendTests: XCTestCase {
|
|||
minedHeight: 50,
|
||||
shielded: true,
|
||||
zAddress: "tteafadlamnelkqe",
|
||||
date: Date.init(timeIntervalSince1970: 1234567),
|
||||
id: "id",
|
||||
status: .paid(success: true),
|
||||
subtitle: "sub",
|
||||
timestamp: 1234567,
|
||||
zecAmount: Zatoshi(amount: 10)
|
||||
)
|
||||
|
||||
|
|
|
@ -18,15 +18,16 @@ class HomeSnapshotTests: XCTestCase {
|
|||
TransactionStateMockHelper(date: 1651039505, amount: Zatoshi(amount: 4), uuid: "4"),
|
||||
TransactionStateMockHelper(date: 1651039404, amount: Zatoshi(amount: 5), uuid: "5")
|
||||
]
|
||||
let transactions = transactionsHelper.map {
|
||||
TransactionState.placeholder(
|
||||
date: Date.init(timeIntervalSince1970: $0.date),
|
||||
let transactions: [WalletEvent] = transactionsHelper.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
subtitle: $0.subtitle,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
|
||||
let balance = Balance(verified: 12_345_000, total: 12_345_000)
|
||||
|
@ -40,7 +41,7 @@ class HomeSnapshotTests: XCTestCase {
|
|||
scanState: .placeholder,
|
||||
synchronizerStatus: "",
|
||||
totalBalance: Zatoshi(amount: balance.total),
|
||||
transactionHistoryState: .init(transactions: IdentifiedArrayOf(uniqueElements: transactions)),
|
||||
walletEventsState: .init(walletEvents: IdentifiedArrayOf(uniqueElements: transactions)),
|
||||
verifiedBalance: Zatoshi(amount: balance.verified)
|
||||
),
|
||||
reducer: .default,
|
||||
|
@ -56,7 +57,7 @@ class HomeSnapshotTests: XCTestCase {
|
|||
// all transactions
|
||||
ViewStore(store).send(.updateDrawer(.full))
|
||||
addAttachments(
|
||||
name: "\(#function)_fullTransactionHistory",
|
||||
name: "\(#function)_fullWalletEvents",
|
||||
HomeView(store: store)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// TransactionHistoryTests.swift
|
||||
// WalletEventsTests.swift
|
||||
// secantTests
|
||||
//
|
||||
// Created by Lukáš Korba on 27.04.2022.
|
||||
|
@ -9,22 +9,22 @@ import XCTest
|
|||
@testable import secant_testnet
|
||||
import ComposableArchitecture
|
||||
|
||||
class TransactionHistoryTests: XCTestCase {
|
||||
class WalletEventsTests: XCTestCase {
|
||||
static let testScheduler = DispatchQueue.test
|
||||
|
||||
let testEnvironment = TransactionHistoryFlowEnvironment(
|
||||
let testEnvironment = WalletEventsFlowEnvironment(
|
||||
scheduler: testScheduler.eraseToAnyScheduler(),
|
||||
SDKSynchronizer: TestWrappedSDKSynchronizer()
|
||||
)
|
||||
|
||||
func testSynchronizerSubscription() throws {
|
||||
let store = TestStore(
|
||||
initialState: TransactionHistoryFlowState(
|
||||
initialState: WalletEventsFlowState(
|
||||
route: .latest,
|
||||
isScrollable: true,
|
||||
transactions: []
|
||||
walletEvents: []
|
||||
),
|
||||
reducer: TransactionHistoryFlowReducer.default,
|
||||
reducer: WalletEventsFlowReducer.default,
|
||||
environment: testEnvironment
|
||||
)
|
||||
|
||||
|
@ -55,26 +55,31 @@ class TransactionHistoryTests: XCTestCase {
|
|||
TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(amount: 9), subtitle: "pending", uuid: "ii99")
|
||||
]
|
||||
|
||||
let transactions = mocked.map {
|
||||
TransactionState.placeholder(
|
||||
date: Date.init(timeIntervalSince1970: $0.date),
|
||||
let walletEvents: [WalletEvent] = mocked.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
subtitle: $0.subtitle,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(
|
||||
id: transaction.id,
|
||||
state: transaction.subtitle == "pending" ? .pending(transaction) : .send(transaction),
|
||||
timestamp: transaction.timestamp
|
||||
)
|
||||
}
|
||||
|
||||
let identifiedTransactions = IdentifiedArrayOf(uniqueElements: transactions)
|
||||
let identifiedTransactions = IdentifiedArrayOf(uniqueElements: walletEvents)
|
||||
|
||||
let store = TestStore(
|
||||
initialState: TransactionHistoryFlowState(
|
||||
initialState: WalletEventsFlowState(
|
||||
route: .latest,
|
||||
isScrollable: true,
|
||||
transactions: identifiedTransactions
|
||||
walletEvents: identifiedTransactions
|
||||
),
|
||||
reducer: TransactionHistoryFlowReducer.default,
|
||||
reducer: WalletEventsFlowReducer.default,
|
||||
environment: testEnvironment
|
||||
)
|
||||
|
||||
|
@ -82,16 +87,16 @@ class TransactionHistoryTests: XCTestCase {
|
|||
|
||||
Self.testScheduler.advance(by: 0.01)
|
||||
|
||||
store.receive(.updateTransactions(transactions)) { state in
|
||||
store.receive(.updateWalletEvents(walletEvents)) { state in
|
||||
let receivedTransactions = IdentifiedArrayOf(
|
||||
uniqueElements:
|
||||
transactions
|
||||
walletEvents
|
||||
.sorted(by: { lhs, rhs in
|
||||
lhs.date > rhs.date
|
||||
lhs.timestamp > rhs.timestamp
|
||||
})
|
||||
)
|
||||
|
||||
state.transactions = receivedTransactions
|
||||
state.walletEvents = receivedTransactions
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue