diff --git a/secant/Dependencies/ZCashSDKEnvironment.swift b/secant/Dependencies/ZCashSDKEnvironment.swift index 5be5b47..323bfc7 100644 --- a/secant/Dependencies/ZCashSDKEnvironment.swift +++ b/secant/Dependencies/ZCashSDKEnvironment.swift @@ -10,42 +10,46 @@ import ZcashLightClientKit // swiftlint:disable:next private_over_fileprivate strict_fileprivate fileprivate enum ZcashSDKConstants { + static let defaultBlockHeight = 1_629_724 static let endpointMainnetAddress = "lightwalletd.electriccoin.co" static let endpointTestnetAddress = "lightwalletd.testnet.electriccoin.co" static let endpointPort = 9067 - static let defaultBlockHeight = 1_629_724 static let mnemonicWordsMaxCount = 24 + static let requiredTransactionConfirmations = 10 } struct ZCashSDKEnvironment { let defaultBirthday: BlockHeight let endpoint: LightWalletEndpoint - let lightWalletService: LightWalletService - let network: ZcashNetwork - let mnemonicWordsMaxCount: Int let isMainnet: () -> Bool + let lightWalletService: LightWalletService + let mnemonicWordsMaxCount: Int + let network: ZcashNetwork + let requiredTransactionConfirmations: Int } extension ZCashSDKEnvironment { static let mainnet = ZCashSDKEnvironment( defaultBirthday: BlockHeight(ZcashSDKConstants.defaultBlockHeight), endpoint: LightWalletEndpoint(address: ZcashSDKConstants.endpointMainnetAddress, port: ZcashSDKConstants.endpointPort), + isMainnet: { true }, lightWalletService: LightWalletGRPCService( endpoint: LightWalletEndpoint(address: ZcashSDKConstants.endpointMainnetAddress, port: ZcashSDKConstants.endpointPort) ), - network: ZcashNetworkBuilder.network(for: .mainnet), mnemonicWordsMaxCount: ZcashSDKConstants.mnemonicWordsMaxCount, - isMainnet: { true } + network: ZcashNetworkBuilder.network(for: .mainnet), + requiredTransactionConfirmations: ZcashSDKConstants.requiredTransactionConfirmations ) static let testnet = ZCashSDKEnvironment( defaultBirthday: BlockHeight(ZcashSDKConstants.defaultBlockHeight), endpoint: LightWalletEndpoint(address: ZcashSDKConstants.endpointTestnetAddress, port: ZcashSDKConstants.endpointPort), + isMainnet: { false }, lightWalletService: LightWalletGRPCService( endpoint: LightWalletEndpoint(address: ZcashSDKConstants.endpointTestnetAddress, port: ZcashSDKConstants.endpointPort) ), - network: ZcashNetworkBuilder.network(for: .testnet), mnemonicWordsMaxCount: ZcashSDKConstants.mnemonicWordsMaxCount, - isMainnet: { false } + network: ZcashNetworkBuilder.network(for: .testnet), + requiredTransactionConfirmations: ZcashSDKConstants.requiredTransactionConfirmations ) } diff --git a/secant/Features/App/AppStore.swift b/secant/Features/App/AppStore.swift index 87e7854..be6b24d 100644 --- a/secant/Features/App/AppStore.swift +++ b/secant/Features/App/AppStore.swift @@ -367,7 +367,8 @@ extension AppReducer { mnemonic: environment.mnemonic, scheduler: environment.scheduler, SDKSynchronizer: environment.SDKSynchronizer, - walletStorage: environment.walletStorage + walletStorage: environment.walletStorage, + zcashSDKEnvironment: environment.zcashSDKEnvironment ) } ) diff --git a/secant/Features/Home/HomeStore.swift b/secant/Features/Home/HomeStore.swift index d01d38d..85872aa 100644 --- a/secant/Features/Home/HomeStore.swift +++ b/secant/Features/Home/HomeStore.swift @@ -61,6 +61,7 @@ struct HomeEnvironment { let scheduler: AnySchedulerOf let SDKSynchronizer: WrappedSDKSynchronizer let walletStorage: WrappedWalletStorage + let zcashSDKEnvironment: ZCashSDKEnvironment } extension HomeEnvironment { @@ -71,7 +72,8 @@ extension HomeEnvironment { mnemonic: .mock, scheduler: DispatchQueue.main.eraseToAnyScheduler(), SDKSynchronizer: MockWrappedSDKSynchronizer(), - walletStorage: .throwing + walletStorage: .throwing, + zcashSDKEnvironment: .testnet ) } @@ -180,9 +182,10 @@ extension HomeReducer { action: /HomeAction.walletEvents, environment: { environment in WalletEventsFlowEnvironment( + pasteboard: .live, scheduler: environment.scheduler, SDKSynchronizer: environment.SDKSynchronizer, - pasteboard: .live + zcashSDKEnvironment: environment.zcashSDKEnvironment ) } ) @@ -315,7 +318,8 @@ extension HomeStore { mnemonic: .live, scheduler: DispatchQueue.main.eraseToAnyScheduler(), SDKSynchronizer: LiveWrappedSDKSynchronizer(), - walletStorage: .live() + walletStorage: .live(), + zcashSDKEnvironment: .testnet ) ) } diff --git a/secant/Features/Sandbox/SandboxStore.swift b/secant/Features/Sandbox/SandboxStore.swift index a104843..34f5472 100644 --- a/secant/Features/Sandbox/SandboxStore.swift +++ b/secant/Features/Sandbox/SandboxStore.swift @@ -49,9 +49,10 @@ extension SandboxReducer { &state.walletEventsState, walletEventsAction, WalletEventsFlowEnvironment( + pasteboard: .live, scheduler: DispatchQueue.main.eraseToAnyScheduler(), SDKSynchronizer: LiveWrappedSDKSynchronizer(), - pasteboard: .live + zcashSDKEnvironment: .testnet ) ) .map(SandboxAction.walletEvents) diff --git a/secant/Features/SendFlow/SendFlowStore.swift b/secant/Features/SendFlow/SendFlowStore.swift index c47dd9f..9d4be38 100644 --- a/secant/Features/SendFlow/SendFlowStore.swift +++ b/secant/Features/SendFlow/SendFlowStore.swift @@ -121,6 +121,7 @@ extension SendFlowReducer { case .updateRoute(.confirmation): state.amount = Zatoshi(amount: state.transactionAmountInputState.amount) state.address = state.transactionAddressInputState.textFieldState.text + state.route = .confirmation return .none case let .updateRoute(route): diff --git a/secant/Features/WalletEventsFlow/Views/TransactionDetailView.swift b/secant/Features/WalletEventsFlow/Views/TransactionDetailView.swift index 1b1fd21..fb3a6e0 100644 --- a/secant/Features/WalletEventsFlow/Views/TransactionDetailView.swift +++ b/secant/Features/WalletEventsFlow/Views/TransactionDetailView.swift @@ -2,72 +2,160 @@ import SwiftUI import ComposableArchitecture struct TransactionDetailView: View { + enum RowMark { + case neutral + case success + case fail + case inactive + case highlight + } + var transaction: TransactionState var viewStore: WalletEventsFlowViewStore var body: some View { ScrollView { - HStack { + header + + switch transaction.status { + case .paid(success: _): + plainText("You sent \(transaction.zecAmount.decimalString()) ZEC") + plainText("fee \(transaction.fee.decimalString()) ZEC", mark: .inactive) + plainText("total amount \(transaction.totalAmount.decimalString()) ZEC", mark: .inactive) + address(mark: .inactive) + if let text = transaction.memo { memo(text, viewStore, mark: .highlight) } + confirmed(mark: .success) + case .pending: + plainText("You are sending \(transaction.zecAmount.decimalString()) ZEC") + plainText("Includes network fee \(transaction.fee.decimalString()) ZEC", mark: .inactive) + plainText("total amount \(transaction.totalAmount.decimalString()) ZEC", mark: .inactive) + if let text = transaction.memo { memo(text, viewStore, mark: .inactive) } + confirming(mark: .highlight) + case .received: + plainText("You received \(transaction.zecAmount.decimalString()) ZEC") + plainText("fee \(transaction.fee.decimalString()) ZEC") + plainText("total amount \(transaction.totalAmount.decimalString()) ZEC") + address(mark: .inactive) + if let text = transaction.memo { memo(text, viewStore, mark: .highlight) } + confirmed(mark: .success) + case .failed: + plainText("You DID NOT send \(transaction.zecAmount.decimalString()) ZEC", mark: .fail) + plainText("Includes network fee \(transaction.fee.decimalString()) ZEC", mark: .inactive) + plainText("total amount \(transaction.totalAmount.decimalString()) ZEC", mark: .inactive) + if let text = transaction.memo { memo(text, viewStore, mark: .inactive) } + if let errorMessage = transaction.errorMessage { + plainTwoColumnText(left: "Failed", right: errorMessage, mark: .fail) + } + } + + Spacer() + + footer + } + .applyScreenBackground() + .navigationTitle("Transaction detail") + } +} + +extension TransactionDetailView { + var header: some View { + HStack { + switch transaction.status { + case .pending: + Text("PENDING") + Spacer() + case .failed: + Text("\(transaction.date.asHumanReadable())") + Spacer() + Text("FAILED") + default: Text("\(transaction.date.asHumanReadable())") Spacer() Text("HEIGHT \(heightText)") } - .padding() + } + .padding() + } + + func plainText(_ text: String, mark: RowMark = .neutral) -> some View { + Text(text) + .transactionDetailRow(mark: mark) + } - Text("\(amountPrefixText) \(transaction.zecAmount.decimalString()) ZEC") - .transactionDetailRow() - - Text("fee \(transaction.fee.decimalString()) ZEC") - .transactionDetailRow() + func plainTwoColumnText(left: String, right: String, mark: RowMark = .neutral) -> some View { + HStack { + Text(left) + Spacer() + Text(right) + } + .transactionDetailRow(mark: mark) + } - Text("total amount \(transaction.totalAmount.decimalString()) ZEC") - .transactionDetailRow() - - Button { - viewStore.send(.copyToPastboard(transaction.address)) - } label: { - Text("\(addressPrefixText) \(transaction.address)") - .lineLimit(1) - .truncationMode(.middle) - .transactionDetailRow() - } - - if let memo = transaction.memo { - Button { - viewStore.send(.copyToPastboard(memo)) - } label: { - VStack { - Text("\(memo)") - .multilineTextAlignment(.leading) - - HStack { - Text("reply-to address included") - Spacer() - Button { - viewStore.send(.replyTo(transaction.address)) - } label: { - Text("reply now") - .padding(5) - .overlay( - RoundedRectangle(cornerRadius: 6) - .stroke(Asset.Colors.Text.transactionDetailText.color, lineWidth: 1) - ) - } - } + func address(mark: RowMark = .neutral) -> some View { + Button { + viewStore.send(.copyToPastboard(transaction.address)) + } label: { + Text("\(addressPrefixText) \(transaction.address)") + .lineLimit(1) + .truncationMode(.middle) + .transactionDetailRow(mark: mark) + } + } + + func memo( + _ memo: String, + _ viewStore: WalletEventsFlowViewStore, + mark: RowMark = .neutral + ) -> some View { + Button { + viewStore.send(.copyToPastboard(memo)) + } label: { + VStack { + HStack { + Text("\(memo)") + .multilineTextAlignment(.leading) + Spacer() + } + + HStack { + Text("reply-to address included") + Spacer() + Button { + viewStore.send(.replyTo(transaction.address)) + } label: { + Text("reply now") + .padding(5) + .overlay( + RoundedRectangle(cornerRadius: 6) + .stroke(Asset.Colors.Text.transactionDetailText.color, lineWidth: 1) + ) } - .transactionDetailRow() } } - - HStack { - Text("Confirmed") - Spacer() - Text("\(transaction.confirmations) times") - } - .transactionDetailRow() - + .transactionDetailRow(mark: mark) + } + } + + func confirmed(mark: RowMark = .neutral) -> some View { + HStack { + Text("Confirmed") Spacer() - + Text("\(transaction.confirmationsWith(viewStore.latestMinedHeight)) times") + } + .transactionDetailRow(mark: mark) + } + + func confirming(mark: RowMark = .neutral) -> some View { + HStack { + Text("Confirming ~\(viewStore.requiredTransactionConfirmations)mins") + Spacer() + Text("\(transaction.confirmationsWith(viewStore.latestMinedHeight))/\(viewStore.requiredTransactionConfirmations)") + } + .transactionDetailRow(mark: mark) + } + + var footer: some View { + VStack { Button { viewStore.send(.copyToPastboard(transaction.id)) } label: { @@ -81,7 +169,7 @@ struct TransactionDetailView: View { .background(Asset.Colors.BackgroundColors.numberedChip.color) .padding(.vertical, 30) } - + Button { } label: { // TODO: Warn users that they will leave the App when they follow a Block explorer // https://github.com/zcash/secant-ios-wallet/issues/379 @@ -93,16 +181,10 @@ struct TransactionDetailView: View { .frame(height: 50) .padding(.horizontal, 30) } - .applyScreenBackground() - .navigationTitle("Transaction detail") } } extension TransactionDetailView { - var amountPrefixText: String { - transaction.status == .received ? "You received" : "You sent" - } - var addressPrefixText: String { transaction.status == .received ? "from" : "to" } @@ -112,11 +194,13 @@ extension TransactionDetailView { } } +// MARK: - Row modifier + struct TransactionDetailRow: ViewModifier { - let tint: Color + let mark: TransactionDetailView.RowMark let textColor: Color let backgroundColor: Color - + func body(content: Content) -> some View { content .foregroundColor(textColor) @@ -124,21 +208,35 @@ struct TransactionDetailRow: ViewModifier { .padding() .background(backgroundColor) .padding(.leading, 20) - .background(tint) + .background(markColor(mark)) + } + + private func markColor(_ mark: TransactionDetailView.RowMark) -> Color { + let markColor: Color + + switch mark { + case .neutral: markColor = Asset.Colors.TransactionDetail.neutralMark.color + case .success: markColor = Asset.Colors.TransactionDetail.succeededMark.color + case .fail: markColor = Asset.Colors.TransactionDetail.failedMark.color + case .inactive: markColor = Asset.Colors.TransactionDetail.inactiveMark.color + case .highlight: markColor = Asset.Colors.TransactionDetail.highlightMark.color + } + + return markColor } } extension View { func transactionDetailRow( - _ tint: Color = Asset.Colors.BackgroundColors.red.color, - _ textColor: Color = Asset.Colors.Text.transactionDetailText.color, - _ backgroundColor: Color = Asset.Colors.BackgroundColors.numberedChip.color + mark: TransactionDetailView.RowMark = .neutral ) -> some View { modifier( TransactionDetailRow( - tint: tint, - textColor: textColor, - backgroundColor: backgroundColor + mark: mark, + textColor: mark == .inactive ? + Asset.Colors.TransactionDetail.inactiveMark.color : + Asset.Colors.Text.transactionDetailText.color, + backgroundColor: Asset.Colors.BackgroundColors.numberedChip.color ) ) } @@ -152,6 +250,7 @@ struct TransactionDetail_Previews: PreviewProvider { TransactionDetailView( transaction: TransactionState( + errorMessage: "possible roll back", memo: """ Testing some long memo so I can see many lines of text \ @@ -163,7 +262,6 @@ struct TransactionDetail_Previews: PreviewProvider { fee: Zatoshi(amount: 1_000_000), id: "ff3927e1f83df9b1b0dc75540ddc59ee435eecebae914d2e6dfe8576fbedc9a8", status: .paid(success: true), - subtitle: "", timestamp: 1234567, zecAmount: Zatoshi(amount: 25_000_000) ), @@ -173,9 +271,10 @@ struct TransactionDetail_Previews: PreviewProvider { reducer: .default, environment: WalletEventsFlowEnvironment( + pasteboard: .test, scheduler: DispatchQueue.main.eraseToAnyScheduler(), SDKSynchronizer: MockWrappedSDKSynchronizer(), - pasteboard: .test + zcashSDKEnvironment: .testnet ) ) ) diff --git a/secant/Features/WalletEventsFlow/WalletEventsFlowStore.swift b/secant/Features/WalletEventsFlow/WalletEventsFlowStore.swift index 6b432ba..91f3642 100644 --- a/secant/Features/WalletEventsFlow/WalletEventsFlowStore.swift +++ b/secant/Features/WalletEventsFlow/WalletEventsFlowStore.swift @@ -1,5 +1,6 @@ import ComposableArchitecture import SwiftUI +import ZcashLightClientKit typealias WalletEventsFlowReducer = Reducer typealias WalletEventsFlowStore = Store @@ -16,7 +17,9 @@ struct WalletEventsFlowState: Equatable { var route: Route? + var latestMinedHeight: BlockHeight? var isScrollable = false + var requiredTransactionConfirmations = 0 var walletEvents = IdentifiedArrayOf.placeholder } @@ -35,9 +38,10 @@ enum WalletEventsFlowAction: Equatable { // MARK: - Environment struct WalletEventsFlowEnvironment { + let pasteboard: WrappedPasteboard let scheduler: AnySchedulerOf let SDKSynchronizer: WrappedSDKSynchronizer - let pasteboard: WrappedPasteboard + let zcashSDKEnvironment: ZCashSDKEnvironment } // MARK: - Reducer @@ -48,6 +52,7 @@ extension WalletEventsFlowReducer { static let `default` = WalletEventsFlowReducer { state, action, environment in switch action { case .onAppear: + state.requiredTransactionConfirmations = environment.zcashSDKEnvironment.requiredTransactionConfirmations return environment.SDKSynchronizer.stateChanged .map(WalletEventsFlowAction.synchronizerStateChanged) .eraseToEffect() @@ -57,6 +62,9 @@ extension WalletEventsFlowReducer { return Effect.cancel(id: CancelId()) case .synchronizerStateChanged(.synced): + if let latestMinedHeight = environment.SDKSynchronizer.synchronizer?.latestScannedHeight { + state.latestMinedHeight = latestMinedHeight + } return environment.SDKSynchronizer.getAllTransactions() .receive(on: environment.scheduler) .map(WalletEventsFlowAction.updateWalletEvents) @@ -110,7 +118,6 @@ extension TransactionState { fee: Zatoshi(amount: 10), id: "2", status: .paid(success: true), - subtitle: "", timestamp: 1234567, zecAmount: Zatoshi(amount: 25) ) @@ -133,9 +140,10 @@ extension WalletEventsFlowStore { initialState: .placeHolder, reducer: .default, environment: WalletEventsFlowEnvironment( + pasteboard: .live, scheduler: DispatchQueue.main.eraseToAnyScheduler(), SDKSynchronizer: LiveWrappedSDKSynchronizer(), - pasteboard: .live + zcashSDKEnvironment: .testnet ) ) } @@ -149,7 +157,6 @@ extension IdentifiedArrayOf where Element == TransactionState { fee: Zatoshi(amount: 10), id: String($0), status: .paid(success: true), - subtitle: "", timestamp: 1234567, zecAmount: Zatoshi(amount: 25) ) diff --git a/secant/Models/TransactionState.swift b/secant/Models/TransactionState.swift index d486bfa..c17020e 100644 --- a/secant/Models/TransactionState.swift +++ b/secant/Models/TransactionState.swift @@ -14,9 +14,10 @@ struct TransactionState: Equatable, Identifiable { case paid(success: Bool) case received case failed + case pending } - var confirmations = 0 + var errorMessage: String? var expirationHeight = -1 var memo: String? var minedHeight = -1 @@ -26,7 +27,6 @@ struct TransactionState: Equatable, Identifiable { var fee: Zatoshi var id: String var status: Status - var subtitle: String var timestamp: TimeInterval var zecAmount: Zatoshi @@ -36,6 +36,14 @@ struct TransactionState: Equatable, Identifiable { var viewOnlineURL: URL? { URL(string: "https://blockchair.com/zcash/transaction/\(id)") } + + func confirmationsWith(_ latestMinedHeight: BlockHeight?) -> BlockHeight { + guard let latestMinedHeight = latestMinedHeight, minedHeight > 0, latestMinedHeight > 0 else { + return 0 + } + + return latestMinedHeight - minedHeight + } } extension TransactionState { @@ -44,7 +52,6 @@ extension TransactionState { id = confirmedTransaction.transactionEntity.transactionId.toHexStringTxId() shielded = true status = sent ? .paid(success: confirmedTransaction.minedHeight > 0) : .received - subtitle = "sent" zAddress = confirmedTransaction.toAddress zecAmount = sent ? Zatoshi(amount: -Int64(confirmedTransaction.value)) : Zatoshi(amount: Int64(confirmedTransaction.value)) fee = Zatoshi(amount: 10) @@ -58,9 +65,11 @@ extension TransactionState { timestamp = pendingTransaction.createTime id = pendingTransaction.rawTransactionId?.toHexStringTxId() ?? String(pendingTransaction.createTime) shielded = true - status = .paid(success: pendingTransaction.isSubmitSuccess) + status = pendingTransaction.errorMessage != nil ? .failed : + pendingTransaction.minedHeight > 0 ? + .paid(success: pendingTransaction.isSubmitSuccess) : + .pending expirationHeight = pendingTransaction.expiryHeight - subtitle = "pending" zAddress = pendingTransaction.toAddress zecAmount = Zatoshi(amount: -Int64(pendingTransaction.value)) fee = Zatoshi(amount: 10) @@ -68,6 +77,7 @@ extension TransactionState { self.memo = memo.asZcashTransactionMemo() } minedHeight = pendingTransaction.minedHeight + errorMessage = pendingTransaction.errorMessage } } @@ -79,7 +89,6 @@ extension TransactionState { fee: Zatoshi, shielded: Bool = true, status: Status = .received, - subtitle: String = "", timestamp: TimeInterval, uuid: String = UUID().debugDescription ) -> TransactionState { @@ -92,7 +101,6 @@ extension TransactionState { fee: fee, id: uuid, status: status, - subtitle: subtitle, timestamp: timestamp, zecAmount: status == .received ? amount : Zatoshi(amount: -amount.amount) ) @@ -104,6 +112,5 @@ struct TransactionStateMockHelper { var amount: Zatoshi var shielded = true var status: TransactionState.Status = .received - var subtitle = "cleared" var uuid = "" } diff --git a/secant/Models/WalletEvent.swift b/secant/Models/WalletEvent.swift index dd1173b..93260aa 100644 --- a/secant/Models/WalletEvent.swift +++ b/secant/Models/WalletEvent.swift @@ -32,14 +32,11 @@ struct WalletEvent: Equatable, Identifiable { extension WalletEvent { @ViewBuilder func rowView(_ viewStore: WalletEventsFlowViewStore) -> some View { switch state { - case .send(let transaction): + case .send(let transaction), + .pending(let transaction), + .received(let transaction), + .failed(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: @@ -53,14 +50,11 @@ extension WalletEvent { extension WalletEvent { @ViewBuilder func detailView(_ viewStore: WalletEventsFlowViewStore) -> some View { switch state { - case .send(let transaction): + case .send(let transaction), + .pending(let transaction), + .received(let transaction), + .failed(let transaction): TransactionDetailView(transaction: transaction, viewStore: viewStore) - 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: diff --git a/secant/Resources/Colors.xcassets/BackgroundColors/red.colorset/Contents.json b/secant/Resources/Colors.xcassets/BackgroundColors/red.colorset/Contents.json index 76ae429..a4abec1 100644 --- a/secant/Resources/Colors.xcassets/BackgroundColors/red.colorset/Contents.json +++ b/secant/Resources/Colors.xcassets/BackgroundColors/red.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0.173", - "green" : "0.047", - "red" : "0.780" + "blue" : "0x2C", + "green" : "0x0B", + "red" : "0xC6" } }, "idiom" : "universal" diff --git a/secant/Resources/Colors.xcassets/Cursor/Bar.colorset/Contents.json b/secant/Resources/Colors.xcassets/Cursor/Bar.colorset/Contents.json index 970dc26..7bf51f4 100644 --- a/secant/Resources/Colors.xcassets/Cursor/Bar.colorset/Contents.json +++ b/secant/Resources/Colors.xcassets/Cursor/Bar.colorset/Contents.json @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0.000", - "green" : "0.810", - "red" : "1.000" + "blue" : "0x00", + "green" : "0xCE", + "red" : "0xFF" } }, "idiom" : "universal" diff --git a/secant/Resources/Colors.xcassets/ScreenBackground/greenGradientStart.colorset/Contents.json b/secant/Resources/Colors.xcassets/ScreenBackground/greenGradientStart.colorset/Contents.json index 2592546..bdc748c 100644 --- a/secant/Resources/Colors.xcassets/ScreenBackground/greenGradientStart.colorset/Contents.json +++ b/secant/Resources/Colors.xcassets/ScreenBackground/greenGradientStart.colorset/Contents.json @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "97", - "green" : "172", - "red" : "42" + "blue" : "0x61", + "green" : "0xAC", + "red" : "0x2A" } }, "idiom" : "universal" diff --git a/secant/Resources/Colors.xcassets/TransactionDetail/Contents.json b/secant/Resources/Colors.xcassets/TransactionDetail/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/secant/Resources/Colors.xcassets/TransactionDetail/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/secant/Resources/Colors.xcassets/TransactionDetail/FailedMark.colorset/Contents.json b/secant/Resources/Colors.xcassets/TransactionDetail/FailedMark.colorset/Contents.json new file mode 100644 index 0000000..1d22992 --- /dev/null +++ b/secant/Resources/Colors.xcassets/TransactionDetail/FailedMark.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x2C", + "green" : "0x0B", + "red" : "0xC6" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.173", + "green" : "0.043", + "red" : "0.776" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/secant/Resources/Colors.xcassets/TransactionDetail/HighlightMark.colorset/Contents.json b/secant/Resources/Colors.xcassets/TransactionDetail/HighlightMark.colorset/Contents.json new file mode 100644 index 0000000..df4adf2 --- /dev/null +++ b/secant/Resources/Colors.xcassets/TransactionDetail/HighlightMark.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x00", + "green" : "0xCE", + "red" : "0xFF" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x00", + "green" : "0xCE", + "red" : "0xFF" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/secant/Resources/Colors.xcassets/TransactionDetail/InactiveMark.colorset/Contents.json b/secant/Resources/Colors.xcassets/TransactionDetail/InactiveMark.colorset/Contents.json new file mode 100644 index 0000000..657fc42 --- /dev/null +++ b/secant/Resources/Colors.xcassets/TransactionDetail/InactiveMark.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xAA", + "green" : "0xAA", + "red" : "0xAA" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xAA", + "green" : "0xAA", + "red" : "0xAA" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/secant/Resources/Colors.xcassets/TransactionDetail/NeutralMark.colorset/Contents.json b/secant/Resources/Colors.xcassets/TransactionDetail/NeutralMark.colorset/Contents.json new file mode 100644 index 0000000..22c4bb0 --- /dev/null +++ b/secant/Resources/Colors.xcassets/TransactionDetail/NeutralMark.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/secant/Resources/Colors.xcassets/TransactionDetail/SucceededMark.colorset/Contents.json b/secant/Resources/Colors.xcassets/TransactionDetail/SucceededMark.colorset/Contents.json new file mode 100644 index 0000000..09b9901 --- /dev/null +++ b/secant/Resources/Colors.xcassets/TransactionDetail/SucceededMark.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x61", + "green" : "0xAC", + "red" : "0x2A" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x61", + "green" : "0xAC", + "red" : "0x2A" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/secant/Resources/Generated/XCAssets+Generated.swift b/secant/Resources/Generated/XCAssets+Generated.swift index 1d40ec4..0dba425 100644 --- a/secant/Resources/Generated/XCAssets+Generated.swift +++ b/secant/Resources/Generated/XCAssets+Generated.swift @@ -125,6 +125,13 @@ internal enum Asset { internal static let purple = ColorAsset(name: "Purple") } } + internal enum TransactionDetail { + internal static let failedMark = ColorAsset(name: "FailedMark") + internal static let highlightMark = ColorAsset(name: "HighlightMark") + internal static let inactiveMark = ColorAsset(name: "InactiveMark") + internal static let neutralMark = ColorAsset(name: "NeutralMark") + internal static let succeededMark = ColorAsset(name: "SucceededMark") + } internal enum ZcashBadge { internal static let zcashLogoFill = ColorAsset(name: "ZcashLogoFill") internal static let innerCircle = ColorAsset(name: "innerCircle") diff --git a/secant/Wrappers/WrappedSDKSynchronizer.swift b/secant/Wrappers/WrappedSDKSynchronizer.swift index 12cb09a..7e7d605 100644 --- a/secant/Wrappers/WrappedSDKSynchronizer.swift +++ b/secant/Wrappers/WrappedSDKSynchronizer.swift @@ -310,7 +310,6 @@ class MockWrappedSDKSynchronizer: WrappedSDKSynchronizer { fee: Zatoshi(amount: 10), shielded: $0.shielded, status: $0.status, - subtitle: $0.subtitle, timestamp: $0.date, uuid: $0.uuid ) @@ -321,10 +320,10 @@ class MockWrappedSDKSynchronizer: WrappedSDKSynchronizer { 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"), - TransactionStateMockHelper(date: 1651039707, amount: Zatoshi(amount: 8), status: .paid(success: true), subtitle: "pending"), - TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(amount: 9), subtitle: "pending") + TransactionStateMockHelper(date: 1651039606, amount: Zatoshi(amount: 6), status: .paid(success: false)), + TransactionStateMockHelper(date: 1651039303, amount: Zatoshi(amount: 7)), + TransactionStateMockHelper(date: 1651039707, amount: Zatoshi(amount: 8), status: .paid(success: true)), + TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(amount: 9)) ] return Effect( @@ -335,7 +334,6 @@ class MockWrappedSDKSynchronizer: WrappedSDKSynchronizer { fee: Zatoshi(amount: 10), shielded: $0.shielded, status: $0.status, - subtitle: $0.subtitle, timestamp: $0.date ) return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp) @@ -373,7 +371,6 @@ class MockWrappedSDKSynchronizer: WrappedSDKSynchronizer { fee: Zatoshi(amount: 10), id: "id", status: .paid(success: true), - subtitle: "sub", timestamp: 1234567, zecAmount: Zatoshi(amount: 10) ) @@ -423,7 +420,6 @@ class TestWrappedSDKSynchronizer: WrappedSDKSynchronizer { fee: Zatoshi(amount: 10), shielded: $0.shielded, status: $0.status, - subtitle: $0.subtitle, timestamp: $0.date, uuid: $0.uuid ) @@ -438,12 +434,11 @@ class TestWrappedSDKSynchronizer: WrappedSDKSynchronizer { date: 1651039606, amount: Zatoshi(amount: 6), status: .paid(success: false), - subtitle: "pending", uuid: "ff66" ), - TransactionStateMockHelper(date: 1651039303, amount: Zatoshi(amount: 7), subtitle: "pending", uuid: "gg77"), - TransactionStateMockHelper(date: 1651039707, amount: Zatoshi(amount: 8), status: .paid(success: true), subtitle: "pending", uuid: "hh88"), - TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(amount: 9), subtitle: "pending", uuid: "ii99") + TransactionStateMockHelper(date: 1651039303, amount: Zatoshi(amount: 7), uuid: "gg77"), + TransactionStateMockHelper(date: 1651039707, amount: Zatoshi(amount: 8), status: .paid(success: true), uuid: "hh88"), + TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(amount: 9), uuid: "ii99") ] return Effect( @@ -453,8 +448,7 @@ class TestWrappedSDKSynchronizer: WrappedSDKSynchronizer { amount: $0.amount, fee: Zatoshi(amount: 10), shielded: $0.shielded, - status: $0.status, - subtitle: $0.subtitle, + status: $0.amount.amount > 5 ? .pending : $0.status, timestamp: $0.date, uuid: $0.uuid ) diff --git a/secantTests/HomeTests/HomeTests.swift b/secantTests/HomeTests/HomeTests.swift index 609f527..9a2b97c 100644 --- a/secantTests/HomeTests/HomeTests.swift +++ b/secantTests/HomeTests/HomeTests.swift @@ -21,7 +21,8 @@ class HomeTests: XCTestCase { mnemonic: .mock, scheduler: testScheduler.eraseToAnyScheduler(), SDKSynchronizer: MockWrappedSDKSynchronizer(), - walletStorage: .throwing + walletStorage: .throwing, + zcashSDKEnvironment: .testnet ) let store = TestStore( @@ -50,7 +51,8 @@ class HomeTests: XCTestCase { mnemonic: .mock, scheduler: testScheduler.eraseToAnyScheduler(), SDKSynchronizer: MockWrappedSDKSynchronizer(), - walletStorage: .throwing + walletStorage: .throwing, + zcashSDKEnvironment: .testnet ) let store = TestStore( @@ -80,7 +82,6 @@ class HomeTests: XCTestCase { fee: Zatoshi(amount: 10), shielded: $0.shielded, status: $0.status, - subtitle: $0.subtitle, timestamp: $0.date, uuid: $0.uuid ) @@ -109,7 +110,8 @@ class HomeTests: XCTestCase { mnemonic: .mock, scheduler: testScheduler.eraseToAnyScheduler(), SDKSynchronizer: MockWrappedSDKSynchronizer(), - walletStorage: .throwing + walletStorage: .throwing, + zcashSDKEnvironment: .testnet ) let homeState = HomeState( @@ -151,7 +153,8 @@ class HomeTests: XCTestCase { mnemonic: .mock, scheduler: testScheduler.eraseToAnyScheduler(), SDKSynchronizer: MockWrappedSDKSynchronizer(), - walletStorage: .throwing + walletStorage: .throwing, + zcashSDKEnvironment: .testnet ) let homeState = HomeState( @@ -195,7 +198,8 @@ class HomeTests: XCTestCase { mnemonic: .mock, scheduler: testScheduler.eraseToAnyScheduler(), SDKSynchronizer: MockWrappedSDKSynchronizer(), - walletStorage: .throwing + walletStorage: .throwing, + zcashSDKEnvironment: .testnet ) let store = TestStore( diff --git a/secantTests/SendTests/SendTests.swift b/secantTests/SendTests/SendTests.swift index dbdbebe..0968514 100644 --- a/secantTests/SendTests/SendTests.swift +++ b/secantTests/SendTests/SendTests.swift @@ -67,7 +67,6 @@ class SendTests: XCTestCase { fee: Zatoshi(amount: 10), id: "id", status: .paid(success: true), - subtitle: "sub", timestamp: 1234567, zecAmount: Zatoshi(amount: 10) ) diff --git a/secantTests/SnapshotTests/HomeSnapshotTests/HomeSnapshotTests.swift b/secantTests/SnapshotTests/HomeSnapshotTests/HomeSnapshotTests.swift index d5b3999..0ce7d5d 100644 --- a/secantTests/SnapshotTests/HomeSnapshotTests/HomeSnapshotTests.swift +++ b/secantTests/SnapshotTests/HomeSnapshotTests/HomeSnapshotTests.swift @@ -25,7 +25,6 @@ class HomeSnapshotTests: XCTestCase { fee: Zatoshi(amount: 10), shielded: $0.shielded, status: $0.status, - subtitle: $0.subtitle, timestamp: $0.date, uuid: $0.uuid ) @@ -77,7 +76,6 @@ class HomeSnapshotTests: XCTestCase { fee: Zatoshi(amount: 1_000_000), id: "ff3927e1f83df9b1b0dc75540ddc59ee435eecebae914d2e6dfe8576fbedc9a8", status: .paid(success: true), - subtitle: "", timestamp: 1234567, zecAmount: Zatoshi(amount: 25_000_000) ) @@ -103,9 +101,10 @@ class HomeSnapshotTests: XCTestCase { // wallet event detail let testEnvironment = WalletEventsFlowEnvironment( + pasteboard: .test, scheduler: DispatchQueue.test.eraseToAnyScheduler(), SDKSynchronizer: TestWrappedSDKSynchronizer(), - pasteboard: .test + zcashSDKEnvironment: .testnet ) ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent)))) diff --git a/secantTests/SnapshotTests/WalletEventsSnapshotTests/WalletEventsSnapshotTests.swift b/secantTests/SnapshotTests/WalletEventsSnapshotTests/WalletEventsSnapshotTests.swift index fc35c07..be5ad6c 100644 --- a/secantTests/SnapshotTests/WalletEventsSnapshotTests/WalletEventsSnapshotTests.swift +++ b/secantTests/SnapshotTests/WalletEventsSnapshotTests/WalletEventsSnapshotTests.swift @@ -10,7 +10,7 @@ import XCTest import ComposableArchitecture class WalletEventsSnapshotTests: XCTestCase { - func testWalletEventDetailSnapshot() throws { + func testWalletEventDetailSnapshot_sent() throws { let transaction = TransactionState( memo: """ @@ -23,7 +23,6 @@ class WalletEventsSnapshotTests: XCTestCase { fee: Zatoshi(amount: 1_000_000), id: "ff3927e1f83df9b1b0dc75540ddc59ee435eecebae914d2e6dfe8576fbedc9a8", status: .paid(success: true), - subtitle: "", timestamp: 1234567, zecAmount: Zatoshi(amount: 25_000_000) ) @@ -49,9 +48,187 @@ class WalletEventsSnapshotTests: XCTestCase { // wallet event detail let testEnvironment = WalletEventsFlowEnvironment( + pasteboard: .test, scheduler: DispatchQueue.test.eraseToAnyScheduler(), SDKSynchronizer: TestWrappedSDKSynchronizer(), - pasteboard: .test + zcashSDKEnvironment: .testnet + ) + + ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent)))) + let walletEventsStore = WalletEventsFlowStore( + initialState: .placeHolder, + reducer: .default, + environment: testEnvironment + ) + + addAttachments( + name: "\(#function)_WalletEventDetail", + TransactionDetailView(transaction: transaction, viewStore: ViewStore(walletEventsStore)) + ) + } + + func testWalletEventDetailSnapshot_received() throws { + let transaction = TransactionState( + memo: + """ + Testing some long memo so I can see many lines of text \ + instead of just one. This can take some time and I'm \ + bored to write all this stuff. + """, + minedHeight: 1_875_256, + zAddress: "t1gXqfSSQt6WfpwyuCU3Wi7sSVZ66DYQ3Po", + fee: Zatoshi(amount: 1_000_000), + id: "ff3927e1f83df9b1b0dc75540ddc59ee435eecebae914d2e6dfe8576fbedc9a8", + status: .received, + timestamp: 1234567, + zecAmount: Zatoshi(amount: 25_000_000) + ) + + let walletEvent = WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp) + + let balance = Balance(verified: 12_345_000, total: 12_345_000) + let store = HomeStore( + initialState: .init( + drawerOverlay: .partial, + profileState: .placeholder, + requestState: .placeholder, + sendState: .placeholder, + scanState: .placeholder, + synchronizerStatus: "", + totalBalance: Zatoshi(amount: balance.total), + walletEventsState: .init(walletEvents: IdentifiedArrayOf(uniqueElements: [walletEvent])), + verifiedBalance: Zatoshi(amount: balance.verified) + ), + reducer: .default, + environment: .demo + ) + + // wallet event detail + let testEnvironment = WalletEventsFlowEnvironment( + pasteboard: .test, + scheduler: DispatchQueue.test.eraseToAnyScheduler(), + SDKSynchronizer: TestWrappedSDKSynchronizer(), + zcashSDKEnvironment: .testnet + ) + + ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent)))) + let walletEventsStore = WalletEventsFlowStore( + initialState: .placeHolder, + reducer: .default, + environment: testEnvironment + ) + + addAttachments( + name: "\(#function)_WalletEventDetail", + TransactionDetailView(transaction: transaction, viewStore: ViewStore(walletEventsStore)) + ) + } + + func testWalletEventDetailSnapshot_pending() throws { + let transaction = TransactionState( + memo: + """ + Testing some long memo so I can see many lines of text \ + instead of just one. This can take some time and I'm \ + bored to write all this stuff. + """, + minedHeight: 1_875_256, + zAddress: "t1gXqfSSQt6WfpwyuCU3Wi7sSVZ66DYQ3Po", + fee: Zatoshi(amount: 1_000_000), + id: "ff3927e1f83df9b1b0dc75540ddc59ee435eecebae914d2e6dfe8576fbedc9a8", + status: .pending, + timestamp: 1234567, + zecAmount: Zatoshi(amount: 25_000_000) + ) + + let walletEvent = WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp) + + let balance = Balance(verified: 12_345_000, total: 12_345_000) + let store = HomeStore( + initialState: .init( + drawerOverlay: .partial, + profileState: .placeholder, + requestState: .placeholder, + sendState: .placeholder, + scanState: .placeholder, + synchronizerStatus: "", + totalBalance: Zatoshi(amount: balance.total), + walletEventsState: .init(walletEvents: IdentifiedArrayOf(uniqueElements: [walletEvent])), + verifiedBalance: Zatoshi(amount: balance.verified) + ), + reducer: .default, + environment: .demo + ) + + // wallet event detail + let testEnvironment = WalletEventsFlowEnvironment( + pasteboard: .test, + scheduler: DispatchQueue.test.eraseToAnyScheduler(), + SDKSynchronizer: TestWrappedSDKSynchronizer(), + zcashSDKEnvironment: .testnet + ) + + let walletEventsState = WalletEventsFlowState( + requiredTransactionConfirmations: 10, + walletEvents: .placeholder + ) + + ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent)))) + let walletEventsStore = WalletEventsFlowStore( + initialState: walletEventsState, + reducer: .default, + environment: testEnvironment + ) + + addAttachments( + name: "\(#function)_WalletEventDetail", + TransactionDetailView(transaction: transaction, viewStore: ViewStore(walletEventsStore)) + ) + } + + func testWalletEventDetailSnapshot_failed() throws { + let transaction = TransactionState( + errorMessage: "possible roll back", + memo: + """ + Testing some long memo so I can see many lines of text \ + instead of just one. This can take some time and I'm \ + bored to write all this stuff. + """, + minedHeight: 1_875_256, + zAddress: "t1gXqfSSQt6WfpwyuCU3Wi7sSVZ66DYQ3Po", + fee: Zatoshi(amount: 1_000_000), + id: "ff3927e1f83df9b1b0dc75540ddc59ee435eecebae914d2e6dfe8576fbedc9a8", + status: .failed, + timestamp: 1234567, + zecAmount: Zatoshi(amount: 25_000_000) + ) + + let walletEvent = WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp) + + let balance = Balance(verified: 12_345_000, total: 12_345_000) + let store = HomeStore( + initialState: .init( + drawerOverlay: .partial, + profileState: .placeholder, + requestState: .placeholder, + sendState: .placeholder, + scanState: .placeholder, + synchronizerStatus: "", + totalBalance: Zatoshi(amount: balance.total), + walletEventsState: .init(walletEvents: IdentifiedArrayOf(uniqueElements: [walletEvent])), + verifiedBalance: Zatoshi(amount: balance.verified) + ), + reducer: .default, + environment: .demo + ) + + // wallet event detail + let testEnvironment = WalletEventsFlowEnvironment( + pasteboard: .test, + scheduler: DispatchQueue.test.eraseToAnyScheduler(), + SDKSynchronizer: TestWrappedSDKSynchronizer(), + zcashSDKEnvironment: .testnet ) ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent)))) diff --git a/secantTests/WalletEventsTests/WalletEventsTests.swift b/secantTests/WalletEventsTests/WalletEventsTests.swift index 401ea4f..d4a85fa 100644 --- a/secantTests/WalletEventsTests/WalletEventsTests.swift +++ b/secantTests/WalletEventsTests/WalletEventsTests.swift @@ -13,9 +13,10 @@ class WalletEventsTests: XCTestCase { static let testScheduler = DispatchQueue.test let testEnvironment = WalletEventsFlowEnvironment( + pasteboard: .test, scheduler: testScheduler.eraseToAnyScheduler(), SDKSynchronizer: TestWrappedSDKSynchronizer(), - pasteboard: .test + zcashSDKEnvironment: .testnet ) func testSynchronizerSubscription() throws { @@ -48,12 +49,11 @@ class WalletEventsTests: XCTestCase { date: 1651039606, amount: Zatoshi(amount: 6), status: .paid(success: false), - subtitle: "pending", uuid: "ff66" ), - TransactionStateMockHelper(date: 1651039303, amount: Zatoshi(amount: 7), subtitle: "pending", uuid: "gg77"), - TransactionStateMockHelper(date: 1651039707, amount: Zatoshi(amount: 8), status: .paid(success: true), subtitle: "pending", uuid: "hh88"), - TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(amount: 9), subtitle: "pending", uuid: "ii99") + TransactionStateMockHelper(date: 1651039303, amount: Zatoshi(amount: 7), uuid: "gg77"), + TransactionStateMockHelper(date: 1651039707, amount: Zatoshi(amount: 8), status: .paid(success: true), uuid: "hh88"), + TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(amount: 9), uuid: "ii99") ] let walletEvents: [WalletEvent] = mocked.map { @@ -61,14 +61,13 @@ class WalletEventsTests: XCTestCase { amount: $0.amount, fee: Zatoshi(amount: 10), shielded: $0.shielded, - status: $0.status, - subtitle: $0.subtitle, + status: $0.amount.amount > 5 ? .pending : $0.status, timestamp: $0.date, uuid: $0.uuid ) return WalletEvent( id: transaction.id, - state: transaction.subtitle == "pending" ? .pending(transaction) : .send(transaction), + state: transaction.status == .pending ? .pending(transaction) : .send(transaction), timestamp: transaction.timestamp ) } @@ -106,9 +105,10 @@ class WalletEventsTests: XCTestCase { let pasteboard = WrappedPasteboard.test let testEnvironment = WalletEventsFlowEnvironment( + pasteboard: pasteboard, scheduler: DispatchQueue.test.eraseToAnyScheduler(), SDKSynchronizer: TestWrappedSDKSynchronizer(), - pasteboard: pasteboard + zcashSDKEnvironment: .testnet ) let store = TestStore(