- transaction detail has been cut into pieces that can be composed to various versions of the detail - handling all 4 cases (sent, received, pending, failed) [362] [scaffold] Pending Transaction Details - confirmations counting - pending transaction status fixed [362] [scaffold] Pending Transaction Details - tests fixed [362] [scaffold] Pending Transaction Details - failed transactions [362] [scaffold] Pending Transaction Details (381) - snapshot tests [362] [scaffold] Pending Transaction Details (381) - comments resolved
This commit is contained in:
parent
df2c721d32
commit
3d615a32d8
|
@ -10,42 +10,46 @@ import ZcashLightClientKit
|
||||||
|
|
||||||
// swiftlint:disable:next private_over_fileprivate strict_fileprivate
|
// swiftlint:disable:next private_over_fileprivate strict_fileprivate
|
||||||
fileprivate enum ZcashSDKConstants {
|
fileprivate enum ZcashSDKConstants {
|
||||||
|
static let defaultBlockHeight = 1_629_724
|
||||||
static let endpointMainnetAddress = "lightwalletd.electriccoin.co"
|
static let endpointMainnetAddress = "lightwalletd.electriccoin.co"
|
||||||
static let endpointTestnetAddress = "lightwalletd.testnet.electriccoin.co"
|
static let endpointTestnetAddress = "lightwalletd.testnet.electriccoin.co"
|
||||||
static let endpointPort = 9067
|
static let endpointPort = 9067
|
||||||
static let defaultBlockHeight = 1_629_724
|
|
||||||
static let mnemonicWordsMaxCount = 24
|
static let mnemonicWordsMaxCount = 24
|
||||||
|
static let requiredTransactionConfirmations = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ZCashSDKEnvironment {
|
struct ZCashSDKEnvironment {
|
||||||
let defaultBirthday: BlockHeight
|
let defaultBirthday: BlockHeight
|
||||||
let endpoint: LightWalletEndpoint
|
let endpoint: LightWalletEndpoint
|
||||||
let lightWalletService: LightWalletService
|
|
||||||
let network: ZcashNetwork
|
|
||||||
let mnemonicWordsMaxCount: Int
|
|
||||||
let isMainnet: () -> Bool
|
let isMainnet: () -> Bool
|
||||||
|
let lightWalletService: LightWalletService
|
||||||
|
let mnemonicWordsMaxCount: Int
|
||||||
|
let network: ZcashNetwork
|
||||||
|
let requiredTransactionConfirmations: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ZCashSDKEnvironment {
|
extension ZCashSDKEnvironment {
|
||||||
static let mainnet = ZCashSDKEnvironment(
|
static let mainnet = ZCashSDKEnvironment(
|
||||||
defaultBirthday: BlockHeight(ZcashSDKConstants.defaultBlockHeight),
|
defaultBirthday: BlockHeight(ZcashSDKConstants.defaultBlockHeight),
|
||||||
endpoint: LightWalletEndpoint(address: ZcashSDKConstants.endpointMainnetAddress, port: ZcashSDKConstants.endpointPort),
|
endpoint: LightWalletEndpoint(address: ZcashSDKConstants.endpointMainnetAddress, port: ZcashSDKConstants.endpointPort),
|
||||||
|
isMainnet: { true },
|
||||||
lightWalletService: LightWalletGRPCService(
|
lightWalletService: LightWalletGRPCService(
|
||||||
endpoint: LightWalletEndpoint(address: ZcashSDKConstants.endpointMainnetAddress, port: ZcashSDKConstants.endpointPort)
|
endpoint: LightWalletEndpoint(address: ZcashSDKConstants.endpointMainnetAddress, port: ZcashSDKConstants.endpointPort)
|
||||||
),
|
),
|
||||||
network: ZcashNetworkBuilder.network(for: .mainnet),
|
|
||||||
mnemonicWordsMaxCount: ZcashSDKConstants.mnemonicWordsMaxCount,
|
mnemonicWordsMaxCount: ZcashSDKConstants.mnemonicWordsMaxCount,
|
||||||
isMainnet: { true }
|
network: ZcashNetworkBuilder.network(for: .mainnet),
|
||||||
|
requiredTransactionConfirmations: ZcashSDKConstants.requiredTransactionConfirmations
|
||||||
)
|
)
|
||||||
|
|
||||||
static let testnet = ZCashSDKEnvironment(
|
static let testnet = ZCashSDKEnvironment(
|
||||||
defaultBirthday: BlockHeight(ZcashSDKConstants.defaultBlockHeight),
|
defaultBirthday: BlockHeight(ZcashSDKConstants.defaultBlockHeight),
|
||||||
endpoint: LightWalletEndpoint(address: ZcashSDKConstants.endpointTestnetAddress, port: ZcashSDKConstants.endpointPort),
|
endpoint: LightWalletEndpoint(address: ZcashSDKConstants.endpointTestnetAddress, port: ZcashSDKConstants.endpointPort),
|
||||||
|
isMainnet: { false },
|
||||||
lightWalletService: LightWalletGRPCService(
|
lightWalletService: LightWalletGRPCService(
|
||||||
endpoint: LightWalletEndpoint(address: ZcashSDKConstants.endpointTestnetAddress, port: ZcashSDKConstants.endpointPort)
|
endpoint: LightWalletEndpoint(address: ZcashSDKConstants.endpointTestnetAddress, port: ZcashSDKConstants.endpointPort)
|
||||||
),
|
),
|
||||||
network: ZcashNetworkBuilder.network(for: .testnet),
|
|
||||||
mnemonicWordsMaxCount: ZcashSDKConstants.mnemonicWordsMaxCount,
|
mnemonicWordsMaxCount: ZcashSDKConstants.mnemonicWordsMaxCount,
|
||||||
isMainnet: { false }
|
network: ZcashNetworkBuilder.network(for: .testnet),
|
||||||
|
requiredTransactionConfirmations: ZcashSDKConstants.requiredTransactionConfirmations
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -367,7 +367,8 @@ extension AppReducer {
|
||||||
mnemonic: environment.mnemonic,
|
mnemonic: environment.mnemonic,
|
||||||
scheduler: environment.scheduler,
|
scheduler: environment.scheduler,
|
||||||
SDKSynchronizer: environment.SDKSynchronizer,
|
SDKSynchronizer: environment.SDKSynchronizer,
|
||||||
walletStorage: environment.walletStorage
|
walletStorage: environment.walletStorage,
|
||||||
|
zcashSDKEnvironment: environment.zcashSDKEnvironment
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -61,6 +61,7 @@ struct HomeEnvironment {
|
||||||
let scheduler: AnySchedulerOf<DispatchQueue>
|
let scheduler: AnySchedulerOf<DispatchQueue>
|
||||||
let SDKSynchronizer: WrappedSDKSynchronizer
|
let SDKSynchronizer: WrappedSDKSynchronizer
|
||||||
let walletStorage: WrappedWalletStorage
|
let walletStorage: WrappedWalletStorage
|
||||||
|
let zcashSDKEnvironment: ZCashSDKEnvironment
|
||||||
}
|
}
|
||||||
|
|
||||||
extension HomeEnvironment {
|
extension HomeEnvironment {
|
||||||
|
@ -71,7 +72,8 @@ extension HomeEnvironment {
|
||||||
mnemonic: .mock,
|
mnemonic: .mock,
|
||||||
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
||||||
SDKSynchronizer: MockWrappedSDKSynchronizer(),
|
SDKSynchronizer: MockWrappedSDKSynchronizer(),
|
||||||
walletStorage: .throwing
|
walletStorage: .throwing,
|
||||||
|
zcashSDKEnvironment: .testnet
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,9 +182,10 @@ extension HomeReducer {
|
||||||
action: /HomeAction.walletEvents,
|
action: /HomeAction.walletEvents,
|
||||||
environment: { environment in
|
environment: { environment in
|
||||||
WalletEventsFlowEnvironment(
|
WalletEventsFlowEnvironment(
|
||||||
|
pasteboard: .live,
|
||||||
scheduler: environment.scheduler,
|
scheduler: environment.scheduler,
|
||||||
SDKSynchronizer: environment.SDKSynchronizer,
|
SDKSynchronizer: environment.SDKSynchronizer,
|
||||||
pasteboard: .live
|
zcashSDKEnvironment: environment.zcashSDKEnvironment
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -315,7 +318,8 @@ extension HomeStore {
|
||||||
mnemonic: .live,
|
mnemonic: .live,
|
||||||
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
||||||
SDKSynchronizer: LiveWrappedSDKSynchronizer(),
|
SDKSynchronizer: LiveWrappedSDKSynchronizer(),
|
||||||
walletStorage: .live()
|
walletStorage: .live(),
|
||||||
|
zcashSDKEnvironment: .testnet
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,9 +49,10 @@ extension SandboxReducer {
|
||||||
&state.walletEventsState,
|
&state.walletEventsState,
|
||||||
walletEventsAction,
|
walletEventsAction,
|
||||||
WalletEventsFlowEnvironment(
|
WalletEventsFlowEnvironment(
|
||||||
|
pasteboard: .live,
|
||||||
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
||||||
SDKSynchronizer: LiveWrappedSDKSynchronizer(),
|
SDKSynchronizer: LiveWrappedSDKSynchronizer(),
|
||||||
pasteboard: .live
|
zcashSDKEnvironment: .testnet
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.map(SandboxAction.walletEvents)
|
.map(SandboxAction.walletEvents)
|
||||||
|
|
|
@ -121,6 +121,7 @@ extension SendFlowReducer {
|
||||||
case .updateRoute(.confirmation):
|
case .updateRoute(.confirmation):
|
||||||
state.amount = Zatoshi(amount: state.transactionAmountInputState.amount)
|
state.amount = Zatoshi(amount: state.transactionAmountInputState.amount)
|
||||||
state.address = state.transactionAddressInputState.textFieldState.text
|
state.address = state.transactionAddressInputState.textFieldState.text
|
||||||
|
state.route = .confirmation
|
||||||
return .none
|
return .none
|
||||||
|
|
||||||
case let .updateRoute(route):
|
case let .updateRoute(route):
|
||||||
|
|
|
@ -2,72 +2,160 @@ import SwiftUI
|
||||||
import ComposableArchitecture
|
import ComposableArchitecture
|
||||||
|
|
||||||
struct TransactionDetailView: View {
|
struct TransactionDetailView: View {
|
||||||
|
enum RowMark {
|
||||||
|
case neutral
|
||||||
|
case success
|
||||||
|
case fail
|
||||||
|
case inactive
|
||||||
|
case highlight
|
||||||
|
}
|
||||||
|
|
||||||
var transaction: TransactionState
|
var transaction: TransactionState
|
||||||
var viewStore: WalletEventsFlowViewStore
|
var viewStore: WalletEventsFlowViewStore
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
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())")
|
Text("\(transaction.date.asHumanReadable())")
|
||||||
Spacer()
|
Spacer()
|
||||||
Text("HEIGHT \(heightText)")
|
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")
|
func plainTwoColumnText(left: String, right: String, mark: RowMark = .neutral) -> some View {
|
||||||
.transactionDetailRow()
|
HStack {
|
||||||
|
Text(left)
|
||||||
Text("fee \(transaction.fee.decimalString()) ZEC")
|
Spacer()
|
||||||
.transactionDetailRow()
|
Text(right)
|
||||||
|
}
|
||||||
|
.transactionDetailRow(mark: mark)
|
||||||
|
}
|
||||||
|
|
||||||
Text("total amount \(transaction.totalAmount.decimalString()) ZEC")
|
func address(mark: RowMark = .neutral) -> some View {
|
||||||
.transactionDetailRow()
|
Button {
|
||||||
|
viewStore.send(.copyToPastboard(transaction.address))
|
||||||
Button {
|
} label: {
|
||||||
viewStore.send(.copyToPastboard(transaction.address))
|
Text("\(addressPrefixText) \(transaction.address)")
|
||||||
} label: {
|
.lineLimit(1)
|
||||||
Text("\(addressPrefixText) \(transaction.address)")
|
.truncationMode(.middle)
|
||||||
.lineLimit(1)
|
.transactionDetailRow(mark: mark)
|
||||||
.truncationMode(.middle)
|
}
|
||||||
.transactionDetailRow()
|
}
|
||||||
}
|
|
||||||
|
func memo(
|
||||||
if let memo = transaction.memo {
|
_ memo: String,
|
||||||
Button {
|
_ viewStore: WalletEventsFlowViewStore,
|
||||||
viewStore.send(.copyToPastboard(memo))
|
mark: RowMark = .neutral
|
||||||
} label: {
|
) -> some View {
|
||||||
VStack {
|
Button {
|
||||||
Text("\(memo)")
|
viewStore.send(.copyToPastboard(memo))
|
||||||
.multilineTextAlignment(.leading)
|
} label: {
|
||||||
|
VStack {
|
||||||
HStack {
|
HStack {
|
||||||
Text("reply-to address included")
|
Text("\(memo)")
|
||||||
Spacer()
|
.multilineTextAlignment(.leading)
|
||||||
Button {
|
Spacer()
|
||||||
viewStore.send(.replyTo(transaction.address))
|
}
|
||||||
} label: {
|
|
||||||
Text("reply now")
|
HStack {
|
||||||
.padding(5)
|
Text("reply-to address included")
|
||||||
.overlay(
|
Spacer()
|
||||||
RoundedRectangle(cornerRadius: 6)
|
Button {
|
||||||
.stroke(Asset.Colors.Text.transactionDetailText.color, lineWidth: 1)
|
viewStore.send(.replyTo(transaction.address))
|
||||||
)
|
} label: {
|
||||||
}
|
Text("reply now")
|
||||||
}
|
.padding(5)
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 6)
|
||||||
|
.stroke(Asset.Colors.Text.transactionDetailText.color, lineWidth: 1)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
.transactionDetailRow()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.transactionDetailRow(mark: mark)
|
||||||
HStack {
|
}
|
||||||
Text("Confirmed")
|
}
|
||||||
Spacer()
|
|
||||||
Text("\(transaction.confirmations) times")
|
func confirmed(mark: RowMark = .neutral) -> some View {
|
||||||
}
|
HStack {
|
||||||
.transactionDetailRow()
|
Text("Confirmed")
|
||||||
|
|
||||||
Spacer()
|
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 {
|
Button {
|
||||||
viewStore.send(.copyToPastboard(transaction.id))
|
viewStore.send(.copyToPastboard(transaction.id))
|
||||||
} label: {
|
} label: {
|
||||||
|
@ -81,7 +169,7 @@ struct TransactionDetailView: View {
|
||||||
.background(Asset.Colors.BackgroundColors.numberedChip.color)
|
.background(Asset.Colors.BackgroundColors.numberedChip.color)
|
||||||
.padding(.vertical, 30)
|
.padding(.vertical, 30)
|
||||||
}
|
}
|
||||||
|
|
||||||
Button { } label: {
|
Button { } label: {
|
||||||
// TODO: Warn users that they will leave the App when they follow a Block explorer
|
// TODO: Warn users that they will leave the App when they follow a Block explorer
|
||||||
// https://github.com/zcash/secant-ios-wallet/issues/379
|
// https://github.com/zcash/secant-ios-wallet/issues/379
|
||||||
|
@ -93,16 +181,10 @@ struct TransactionDetailView: View {
|
||||||
.frame(height: 50)
|
.frame(height: 50)
|
||||||
.padding(.horizontal, 30)
|
.padding(.horizontal, 30)
|
||||||
}
|
}
|
||||||
.applyScreenBackground()
|
|
||||||
.navigationTitle("Transaction detail")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TransactionDetailView {
|
extension TransactionDetailView {
|
||||||
var amountPrefixText: String {
|
|
||||||
transaction.status == .received ? "You received" : "You sent"
|
|
||||||
}
|
|
||||||
|
|
||||||
var addressPrefixText: String {
|
var addressPrefixText: String {
|
||||||
transaction.status == .received ? "from" : "to"
|
transaction.status == .received ? "from" : "to"
|
||||||
}
|
}
|
||||||
|
@ -112,11 +194,13 @@ extension TransactionDetailView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Row modifier
|
||||||
|
|
||||||
struct TransactionDetailRow: ViewModifier {
|
struct TransactionDetailRow: ViewModifier {
|
||||||
let tint: Color
|
let mark: TransactionDetailView.RowMark
|
||||||
let textColor: Color
|
let textColor: Color
|
||||||
let backgroundColor: Color
|
let backgroundColor: Color
|
||||||
|
|
||||||
func body(content: Content) -> some View {
|
func body(content: Content) -> some View {
|
||||||
content
|
content
|
||||||
.foregroundColor(textColor)
|
.foregroundColor(textColor)
|
||||||
|
@ -124,21 +208,35 @@ struct TransactionDetailRow: ViewModifier {
|
||||||
.padding()
|
.padding()
|
||||||
.background(backgroundColor)
|
.background(backgroundColor)
|
||||||
.padding(.leading, 20)
|
.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 {
|
extension View {
|
||||||
func transactionDetailRow(
|
func transactionDetailRow(
|
||||||
_ tint: Color = Asset.Colors.BackgroundColors.red.color,
|
mark: TransactionDetailView.RowMark = .neutral
|
||||||
_ textColor: Color = Asset.Colors.Text.transactionDetailText.color,
|
|
||||||
_ backgroundColor: Color = Asset.Colors.BackgroundColors.numberedChip.color
|
|
||||||
) -> some View {
|
) -> some View {
|
||||||
modifier(
|
modifier(
|
||||||
TransactionDetailRow(
|
TransactionDetailRow(
|
||||||
tint: tint,
|
mark: mark,
|
||||||
textColor: textColor,
|
textColor: mark == .inactive ?
|
||||||
backgroundColor: backgroundColor
|
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(
|
TransactionDetailView(
|
||||||
transaction:
|
transaction:
|
||||||
TransactionState(
|
TransactionState(
|
||||||
|
errorMessage: "possible roll back",
|
||||||
memo:
|
memo:
|
||||||
"""
|
"""
|
||||||
Testing some long memo so I can see many lines of text \
|
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),
|
fee: Zatoshi(amount: 1_000_000),
|
||||||
id: "ff3927e1f83df9b1b0dc75540ddc59ee435eecebae914d2e6dfe8576fbedc9a8",
|
id: "ff3927e1f83df9b1b0dc75540ddc59ee435eecebae914d2e6dfe8576fbedc9a8",
|
||||||
status: .paid(success: true),
|
status: .paid(success: true),
|
||||||
subtitle: "",
|
|
||||||
timestamp: 1234567,
|
timestamp: 1234567,
|
||||||
zecAmount: Zatoshi(amount: 25_000_000)
|
zecAmount: Zatoshi(amount: 25_000_000)
|
||||||
),
|
),
|
||||||
|
@ -173,9 +271,10 @@ struct TransactionDetail_Previews: PreviewProvider {
|
||||||
reducer: .default,
|
reducer: .default,
|
||||||
environment:
|
environment:
|
||||||
WalletEventsFlowEnvironment(
|
WalletEventsFlowEnvironment(
|
||||||
|
pasteboard: .test,
|
||||||
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
||||||
SDKSynchronizer: MockWrappedSDKSynchronizer(),
|
SDKSynchronizer: MockWrappedSDKSynchronizer(),
|
||||||
pasteboard: .test
|
zcashSDKEnvironment: .testnet
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import ComposableArchitecture
|
import ComposableArchitecture
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import ZcashLightClientKit
|
||||||
|
|
||||||
typealias WalletEventsFlowReducer = Reducer<WalletEventsFlowState, WalletEventsFlowAction, WalletEventsFlowEnvironment>
|
typealias WalletEventsFlowReducer = Reducer<WalletEventsFlowState, WalletEventsFlowAction, WalletEventsFlowEnvironment>
|
||||||
typealias WalletEventsFlowStore = Store<WalletEventsFlowState, WalletEventsFlowAction>
|
typealias WalletEventsFlowStore = Store<WalletEventsFlowState, WalletEventsFlowAction>
|
||||||
|
@ -16,7 +17,9 @@ struct WalletEventsFlowState: Equatable {
|
||||||
|
|
||||||
var route: Route?
|
var route: Route?
|
||||||
|
|
||||||
|
var latestMinedHeight: BlockHeight?
|
||||||
var isScrollable = false
|
var isScrollable = false
|
||||||
|
var requiredTransactionConfirmations = 0
|
||||||
var walletEvents = IdentifiedArrayOf<WalletEvent>.placeholder
|
var walletEvents = IdentifiedArrayOf<WalletEvent>.placeholder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,9 +38,10 @@ enum WalletEventsFlowAction: Equatable {
|
||||||
// MARK: - Environment
|
// MARK: - Environment
|
||||||
|
|
||||||
struct WalletEventsFlowEnvironment {
|
struct WalletEventsFlowEnvironment {
|
||||||
|
let pasteboard: WrappedPasteboard
|
||||||
let scheduler: AnySchedulerOf<DispatchQueue>
|
let scheduler: AnySchedulerOf<DispatchQueue>
|
||||||
let SDKSynchronizer: WrappedSDKSynchronizer
|
let SDKSynchronizer: WrappedSDKSynchronizer
|
||||||
let pasteboard: WrappedPasteboard
|
let zcashSDKEnvironment: ZCashSDKEnvironment
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Reducer
|
// MARK: - Reducer
|
||||||
|
@ -48,6 +52,7 @@ extension WalletEventsFlowReducer {
|
||||||
static let `default` = WalletEventsFlowReducer { state, action, environment in
|
static let `default` = WalletEventsFlowReducer { state, action, environment in
|
||||||
switch action {
|
switch action {
|
||||||
case .onAppear:
|
case .onAppear:
|
||||||
|
state.requiredTransactionConfirmations = environment.zcashSDKEnvironment.requiredTransactionConfirmations
|
||||||
return environment.SDKSynchronizer.stateChanged
|
return environment.SDKSynchronizer.stateChanged
|
||||||
.map(WalletEventsFlowAction.synchronizerStateChanged)
|
.map(WalletEventsFlowAction.synchronizerStateChanged)
|
||||||
.eraseToEffect()
|
.eraseToEffect()
|
||||||
|
@ -57,6 +62,9 @@ extension WalletEventsFlowReducer {
|
||||||
return Effect.cancel(id: CancelId())
|
return Effect.cancel(id: CancelId())
|
||||||
|
|
||||||
case .synchronizerStateChanged(.synced):
|
case .synchronizerStateChanged(.synced):
|
||||||
|
if let latestMinedHeight = environment.SDKSynchronizer.synchronizer?.latestScannedHeight {
|
||||||
|
state.latestMinedHeight = latestMinedHeight
|
||||||
|
}
|
||||||
return environment.SDKSynchronizer.getAllTransactions()
|
return environment.SDKSynchronizer.getAllTransactions()
|
||||||
.receive(on: environment.scheduler)
|
.receive(on: environment.scheduler)
|
||||||
.map(WalletEventsFlowAction.updateWalletEvents)
|
.map(WalletEventsFlowAction.updateWalletEvents)
|
||||||
|
@ -110,7 +118,6 @@ extension TransactionState {
|
||||||
fee: Zatoshi(amount: 10),
|
fee: Zatoshi(amount: 10),
|
||||||
id: "2",
|
id: "2",
|
||||||
status: .paid(success: true),
|
status: .paid(success: true),
|
||||||
subtitle: "",
|
|
||||||
timestamp: 1234567,
|
timestamp: 1234567,
|
||||||
zecAmount: Zatoshi(amount: 25)
|
zecAmount: Zatoshi(amount: 25)
|
||||||
)
|
)
|
||||||
|
@ -133,9 +140,10 @@ extension WalletEventsFlowStore {
|
||||||
initialState: .placeHolder,
|
initialState: .placeHolder,
|
||||||
reducer: .default,
|
reducer: .default,
|
||||||
environment: WalletEventsFlowEnvironment(
|
environment: WalletEventsFlowEnvironment(
|
||||||
|
pasteboard: .live,
|
||||||
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
||||||
SDKSynchronizer: LiveWrappedSDKSynchronizer(),
|
SDKSynchronizer: LiveWrappedSDKSynchronizer(),
|
||||||
pasteboard: .live
|
zcashSDKEnvironment: .testnet
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -149,7 +157,6 @@ extension IdentifiedArrayOf where Element == TransactionState {
|
||||||
fee: Zatoshi(amount: 10),
|
fee: Zatoshi(amount: 10),
|
||||||
id: String($0),
|
id: String($0),
|
||||||
status: .paid(success: true),
|
status: .paid(success: true),
|
||||||
subtitle: "",
|
|
||||||
timestamp: 1234567,
|
timestamp: 1234567,
|
||||||
zecAmount: Zatoshi(amount: 25)
|
zecAmount: Zatoshi(amount: 25)
|
||||||
)
|
)
|
||||||
|
|
|
@ -14,9 +14,10 @@ struct TransactionState: Equatable, Identifiable {
|
||||||
case paid(success: Bool)
|
case paid(success: Bool)
|
||||||
case received
|
case received
|
||||||
case failed
|
case failed
|
||||||
|
case pending
|
||||||
}
|
}
|
||||||
|
|
||||||
var confirmations = 0
|
var errorMessage: String?
|
||||||
var expirationHeight = -1
|
var expirationHeight = -1
|
||||||
var memo: String?
|
var memo: String?
|
||||||
var minedHeight = -1
|
var minedHeight = -1
|
||||||
|
@ -26,7 +27,6 @@ struct TransactionState: Equatable, Identifiable {
|
||||||
var fee: Zatoshi
|
var fee: Zatoshi
|
||||||
var id: String
|
var id: String
|
||||||
var status: Status
|
var status: Status
|
||||||
var subtitle: String
|
|
||||||
var timestamp: TimeInterval
|
var timestamp: TimeInterval
|
||||||
var zecAmount: Zatoshi
|
var zecAmount: Zatoshi
|
||||||
|
|
||||||
|
@ -36,6 +36,14 @@ struct TransactionState: Equatable, Identifiable {
|
||||||
var viewOnlineURL: URL? {
|
var viewOnlineURL: URL? {
|
||||||
URL(string: "https://blockchair.com/zcash/transaction/\(id)")
|
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 {
|
extension TransactionState {
|
||||||
|
@ -44,7 +52,6 @@ extension TransactionState {
|
||||||
id = confirmedTransaction.transactionEntity.transactionId.toHexStringTxId()
|
id = confirmedTransaction.transactionEntity.transactionId.toHexStringTxId()
|
||||||
shielded = true
|
shielded = true
|
||||||
status = sent ? .paid(success: confirmedTransaction.minedHeight > 0) : .received
|
status = sent ? .paid(success: confirmedTransaction.minedHeight > 0) : .received
|
||||||
subtitle = "sent"
|
|
||||||
zAddress = confirmedTransaction.toAddress
|
zAddress = confirmedTransaction.toAddress
|
||||||
zecAmount = sent ? Zatoshi(amount: -Int64(confirmedTransaction.value)) : Zatoshi(amount: Int64(confirmedTransaction.value))
|
zecAmount = sent ? Zatoshi(amount: -Int64(confirmedTransaction.value)) : Zatoshi(amount: Int64(confirmedTransaction.value))
|
||||||
fee = Zatoshi(amount: 10)
|
fee = Zatoshi(amount: 10)
|
||||||
|
@ -58,9 +65,11 @@ extension TransactionState {
|
||||||
timestamp = pendingTransaction.createTime
|
timestamp = pendingTransaction.createTime
|
||||||
id = pendingTransaction.rawTransactionId?.toHexStringTxId() ?? String(pendingTransaction.createTime)
|
id = pendingTransaction.rawTransactionId?.toHexStringTxId() ?? String(pendingTransaction.createTime)
|
||||||
shielded = true
|
shielded = true
|
||||||
status = .paid(success: pendingTransaction.isSubmitSuccess)
|
status = pendingTransaction.errorMessage != nil ? .failed :
|
||||||
|
pendingTransaction.minedHeight > 0 ?
|
||||||
|
.paid(success: pendingTransaction.isSubmitSuccess) :
|
||||||
|
.pending
|
||||||
expirationHeight = pendingTransaction.expiryHeight
|
expirationHeight = pendingTransaction.expiryHeight
|
||||||
subtitle = "pending"
|
|
||||||
zAddress = pendingTransaction.toAddress
|
zAddress = pendingTransaction.toAddress
|
||||||
zecAmount = Zatoshi(amount: -Int64(pendingTransaction.value))
|
zecAmount = Zatoshi(amount: -Int64(pendingTransaction.value))
|
||||||
fee = Zatoshi(amount: 10)
|
fee = Zatoshi(amount: 10)
|
||||||
|
@ -68,6 +77,7 @@ extension TransactionState {
|
||||||
self.memo = memo.asZcashTransactionMemo()
|
self.memo = memo.asZcashTransactionMemo()
|
||||||
}
|
}
|
||||||
minedHeight = pendingTransaction.minedHeight
|
minedHeight = pendingTransaction.minedHeight
|
||||||
|
errorMessage = pendingTransaction.errorMessage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +89,6 @@ extension TransactionState {
|
||||||
fee: Zatoshi,
|
fee: Zatoshi,
|
||||||
shielded: Bool = true,
|
shielded: Bool = true,
|
||||||
status: Status = .received,
|
status: Status = .received,
|
||||||
subtitle: String = "",
|
|
||||||
timestamp: TimeInterval,
|
timestamp: TimeInterval,
|
||||||
uuid: String = UUID().debugDescription
|
uuid: String = UUID().debugDescription
|
||||||
) -> TransactionState {
|
) -> TransactionState {
|
||||||
|
@ -92,7 +101,6 @@ extension TransactionState {
|
||||||
fee: fee,
|
fee: fee,
|
||||||
id: uuid,
|
id: uuid,
|
||||||
status: status,
|
status: status,
|
||||||
subtitle: subtitle,
|
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
zecAmount: status == .received ? amount : Zatoshi(amount: -amount.amount)
|
zecAmount: status == .received ? amount : Zatoshi(amount: -amount.amount)
|
||||||
)
|
)
|
||||||
|
@ -104,6 +112,5 @@ struct TransactionStateMockHelper {
|
||||||
var amount: Zatoshi
|
var amount: Zatoshi
|
||||||
var shielded = true
|
var shielded = true
|
||||||
var status: TransactionState.Status = .received
|
var status: TransactionState.Status = .received
|
||||||
var subtitle = "cleared"
|
|
||||||
var uuid = ""
|
var uuid = ""
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,14 +32,11 @@ struct WalletEvent: Equatable, Identifiable {
|
||||||
extension WalletEvent {
|
extension WalletEvent {
|
||||||
@ViewBuilder func rowView(_ viewStore: WalletEventsFlowViewStore) -> some View {
|
@ViewBuilder func rowView(_ viewStore: WalletEventsFlowViewStore) -> some View {
|
||||||
switch state {
|
switch state {
|
||||||
case .send(let transaction):
|
case .send(let transaction),
|
||||||
|
.pending(let transaction),
|
||||||
|
.received(let transaction),
|
||||||
|
.failed(let transaction):
|
||||||
TransactionRowView(transaction: 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):
|
case .shielded(let zatoshi):
|
||||||
Text("shielded wallet event \(zatoshi.decimalString())")
|
Text("shielded wallet event \(zatoshi.decimalString())")
|
||||||
case .walletImport:
|
case .walletImport:
|
||||||
|
@ -53,14 +50,11 @@ extension WalletEvent {
|
||||||
extension WalletEvent {
|
extension WalletEvent {
|
||||||
@ViewBuilder func detailView(_ viewStore: WalletEventsFlowViewStore) -> some View {
|
@ViewBuilder func detailView(_ viewStore: WalletEventsFlowViewStore) -> some View {
|
||||||
switch state {
|
switch state {
|
||||||
case .send(let transaction):
|
case .send(let transaction),
|
||||||
|
.pending(let transaction),
|
||||||
|
.received(let transaction),
|
||||||
|
.failed(let transaction):
|
||||||
TransactionDetailView(transaction: transaction, viewStore: viewStore)
|
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):
|
case .shielded(let zatoshi):
|
||||||
Text("shielded \(zatoshi.decimalString()) detail")
|
Text("shielded \(zatoshi.decimalString()) detail")
|
||||||
case .walletImport:
|
case .walletImport:
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
"color-space" : "srgb",
|
"color-space" : "srgb",
|
||||||
"components" : {
|
"components" : {
|
||||||
"alpha" : "1.000",
|
"alpha" : "1.000",
|
||||||
"blue" : "0.173",
|
"blue" : "0x2C",
|
||||||
"green" : "0.047",
|
"green" : "0x0B",
|
||||||
"red" : "0.780"
|
"red" : "0xC6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"idiom" : "universal"
|
"idiom" : "universal"
|
||||||
|
|
|
@ -23,9 +23,9 @@
|
||||||
"color-space" : "srgb",
|
"color-space" : "srgb",
|
||||||
"components" : {
|
"components" : {
|
||||||
"alpha" : "1.000",
|
"alpha" : "1.000",
|
||||||
"blue" : "0.000",
|
"blue" : "0x00",
|
||||||
"green" : "0.810",
|
"green" : "0xCE",
|
||||||
"red" : "1.000"
|
"red" : "0xFF"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"idiom" : "universal"
|
"idiom" : "universal"
|
||||||
|
|
|
@ -23,9 +23,9 @@
|
||||||
"color-space" : "srgb",
|
"color-space" : "srgb",
|
||||||
"components" : {
|
"components" : {
|
||||||
"alpha" : "1.000",
|
"alpha" : "1.000",
|
||||||
"blue" : "97",
|
"blue" : "0x61",
|
||||||
"green" : "172",
|
"green" : "0xAC",
|
||||||
"red" : "42"
|
"red" : "0x2A"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"idiom" : "universal"
|
"idiom" : "universal"
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -125,6 +125,13 @@ internal enum Asset {
|
||||||
internal static let purple = ColorAsset(name: "Purple")
|
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 enum ZcashBadge {
|
||||||
internal static let zcashLogoFill = ColorAsset(name: "ZcashLogoFill")
|
internal static let zcashLogoFill = ColorAsset(name: "ZcashLogoFill")
|
||||||
internal static let innerCircle = ColorAsset(name: "innerCircle")
|
internal static let innerCircle = ColorAsset(name: "innerCircle")
|
||||||
|
|
|
@ -310,7 +310,6 @@ class MockWrappedSDKSynchronizer: WrappedSDKSynchronizer {
|
||||||
fee: Zatoshi(amount: 10),
|
fee: Zatoshi(amount: 10),
|
||||||
shielded: $0.shielded,
|
shielded: $0.shielded,
|
||||||
status: $0.status,
|
status: $0.status,
|
||||||
subtitle: $0.subtitle,
|
|
||||||
timestamp: $0.date,
|
timestamp: $0.date,
|
||||||
uuid: $0.uuid
|
uuid: $0.uuid
|
||||||
)
|
)
|
||||||
|
@ -321,10 +320,10 @@ class MockWrappedSDKSynchronizer: WrappedSDKSynchronizer {
|
||||||
|
|
||||||
func getAllPendingTransactions() -> Effect<[WalletEvent], Never> {
|
func getAllPendingTransactions() -> Effect<[WalletEvent], Never> {
|
||||||
let mocked: [TransactionStateMockHelper] = [
|
let mocked: [TransactionStateMockHelper] = [
|
||||||
TransactionStateMockHelper(date: 1651039606, amount: Zatoshi(amount: 6), status: .paid(success: false), subtitle: "pending"),
|
TransactionStateMockHelper(date: 1651039606, amount: Zatoshi(amount: 6), status: .paid(success: false)),
|
||||||
TransactionStateMockHelper(date: 1651039303, amount: Zatoshi(amount: 7), subtitle: "pending"),
|
TransactionStateMockHelper(date: 1651039303, amount: Zatoshi(amount: 7)),
|
||||||
TransactionStateMockHelper(date: 1651039707, amount: Zatoshi(amount: 8), status: .paid(success: true), subtitle: "pending"),
|
TransactionStateMockHelper(date: 1651039707, amount: Zatoshi(amount: 8), status: .paid(success: true)),
|
||||||
TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(amount: 9), subtitle: "pending")
|
TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(amount: 9))
|
||||||
]
|
]
|
||||||
|
|
||||||
return Effect(
|
return Effect(
|
||||||
|
@ -335,7 +334,6 @@ class MockWrappedSDKSynchronizer: WrappedSDKSynchronizer {
|
||||||
fee: Zatoshi(amount: 10),
|
fee: Zatoshi(amount: 10),
|
||||||
shielded: $0.shielded,
|
shielded: $0.shielded,
|
||||||
status: $0.status,
|
status: $0.status,
|
||||||
subtitle: $0.subtitle,
|
|
||||||
timestamp: $0.date
|
timestamp: $0.date
|
||||||
)
|
)
|
||||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||||
|
@ -373,7 +371,6 @@ class MockWrappedSDKSynchronizer: WrappedSDKSynchronizer {
|
||||||
fee: Zatoshi(amount: 10),
|
fee: Zatoshi(amount: 10),
|
||||||
id: "id",
|
id: "id",
|
||||||
status: .paid(success: true),
|
status: .paid(success: true),
|
||||||
subtitle: "sub",
|
|
||||||
timestamp: 1234567,
|
timestamp: 1234567,
|
||||||
zecAmount: Zatoshi(amount: 10)
|
zecAmount: Zatoshi(amount: 10)
|
||||||
)
|
)
|
||||||
|
@ -423,7 +420,6 @@ class TestWrappedSDKSynchronizer: WrappedSDKSynchronizer {
|
||||||
fee: Zatoshi(amount: 10),
|
fee: Zatoshi(amount: 10),
|
||||||
shielded: $0.shielded,
|
shielded: $0.shielded,
|
||||||
status: $0.status,
|
status: $0.status,
|
||||||
subtitle: $0.subtitle,
|
|
||||||
timestamp: $0.date,
|
timestamp: $0.date,
|
||||||
uuid: $0.uuid
|
uuid: $0.uuid
|
||||||
)
|
)
|
||||||
|
@ -438,12 +434,11 @@ class TestWrappedSDKSynchronizer: WrappedSDKSynchronizer {
|
||||||
date: 1651039606,
|
date: 1651039606,
|
||||||
amount: Zatoshi(amount: 6),
|
amount: Zatoshi(amount: 6),
|
||||||
status: .paid(success: false),
|
status: .paid(success: false),
|
||||||
subtitle: "pending",
|
|
||||||
uuid: "ff66"
|
uuid: "ff66"
|
||||||
),
|
),
|
||||||
TransactionStateMockHelper(date: 1651039303, amount: Zatoshi(amount: 7), subtitle: "pending", uuid: "gg77"),
|
TransactionStateMockHelper(date: 1651039303, amount: Zatoshi(amount: 7), uuid: "gg77"),
|
||||||
TransactionStateMockHelper(date: 1651039707, amount: Zatoshi(amount: 8), status: .paid(success: true), subtitle: "pending", uuid: "hh88"),
|
TransactionStateMockHelper(date: 1651039707, amount: Zatoshi(amount: 8), status: .paid(success: true), uuid: "hh88"),
|
||||||
TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(amount: 9), subtitle: "pending", uuid: "ii99")
|
TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(amount: 9), uuid: "ii99")
|
||||||
]
|
]
|
||||||
|
|
||||||
return Effect(
|
return Effect(
|
||||||
|
@ -453,8 +448,7 @@ class TestWrappedSDKSynchronizer: WrappedSDKSynchronizer {
|
||||||
amount: $0.amount,
|
amount: $0.amount,
|
||||||
fee: Zatoshi(amount: 10),
|
fee: Zatoshi(amount: 10),
|
||||||
shielded: $0.shielded,
|
shielded: $0.shielded,
|
||||||
status: $0.status,
|
status: $0.amount.amount > 5 ? .pending : $0.status,
|
||||||
subtitle: $0.subtitle,
|
|
||||||
timestamp: $0.date,
|
timestamp: $0.date,
|
||||||
uuid: $0.uuid
|
uuid: $0.uuid
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,7 +21,8 @@ class HomeTests: XCTestCase {
|
||||||
mnemonic: .mock,
|
mnemonic: .mock,
|
||||||
scheduler: testScheduler.eraseToAnyScheduler(),
|
scheduler: testScheduler.eraseToAnyScheduler(),
|
||||||
SDKSynchronizer: MockWrappedSDKSynchronizer(),
|
SDKSynchronizer: MockWrappedSDKSynchronizer(),
|
||||||
walletStorage: .throwing
|
walletStorage: .throwing,
|
||||||
|
zcashSDKEnvironment: .testnet
|
||||||
)
|
)
|
||||||
|
|
||||||
let store = TestStore(
|
let store = TestStore(
|
||||||
|
@ -50,7 +51,8 @@ class HomeTests: XCTestCase {
|
||||||
mnemonic: .mock,
|
mnemonic: .mock,
|
||||||
scheduler: testScheduler.eraseToAnyScheduler(),
|
scheduler: testScheduler.eraseToAnyScheduler(),
|
||||||
SDKSynchronizer: MockWrappedSDKSynchronizer(),
|
SDKSynchronizer: MockWrappedSDKSynchronizer(),
|
||||||
walletStorage: .throwing
|
walletStorage: .throwing,
|
||||||
|
zcashSDKEnvironment: .testnet
|
||||||
)
|
)
|
||||||
|
|
||||||
let store = TestStore(
|
let store = TestStore(
|
||||||
|
@ -80,7 +82,6 @@ class HomeTests: XCTestCase {
|
||||||
fee: Zatoshi(amount: 10),
|
fee: Zatoshi(amount: 10),
|
||||||
shielded: $0.shielded,
|
shielded: $0.shielded,
|
||||||
status: $0.status,
|
status: $0.status,
|
||||||
subtitle: $0.subtitle,
|
|
||||||
timestamp: $0.date,
|
timestamp: $0.date,
|
||||||
uuid: $0.uuid
|
uuid: $0.uuid
|
||||||
)
|
)
|
||||||
|
@ -109,7 +110,8 @@ class HomeTests: XCTestCase {
|
||||||
mnemonic: .mock,
|
mnemonic: .mock,
|
||||||
scheduler: testScheduler.eraseToAnyScheduler(),
|
scheduler: testScheduler.eraseToAnyScheduler(),
|
||||||
SDKSynchronizer: MockWrappedSDKSynchronizer(),
|
SDKSynchronizer: MockWrappedSDKSynchronizer(),
|
||||||
walletStorage: .throwing
|
walletStorage: .throwing,
|
||||||
|
zcashSDKEnvironment: .testnet
|
||||||
)
|
)
|
||||||
|
|
||||||
let homeState = HomeState(
|
let homeState = HomeState(
|
||||||
|
@ -151,7 +153,8 @@ class HomeTests: XCTestCase {
|
||||||
mnemonic: .mock,
|
mnemonic: .mock,
|
||||||
scheduler: testScheduler.eraseToAnyScheduler(),
|
scheduler: testScheduler.eraseToAnyScheduler(),
|
||||||
SDKSynchronizer: MockWrappedSDKSynchronizer(),
|
SDKSynchronizer: MockWrappedSDKSynchronizer(),
|
||||||
walletStorage: .throwing
|
walletStorage: .throwing,
|
||||||
|
zcashSDKEnvironment: .testnet
|
||||||
)
|
)
|
||||||
|
|
||||||
let homeState = HomeState(
|
let homeState = HomeState(
|
||||||
|
@ -195,7 +198,8 @@ class HomeTests: XCTestCase {
|
||||||
mnemonic: .mock,
|
mnemonic: .mock,
|
||||||
scheduler: testScheduler.eraseToAnyScheduler(),
|
scheduler: testScheduler.eraseToAnyScheduler(),
|
||||||
SDKSynchronizer: MockWrappedSDKSynchronizer(),
|
SDKSynchronizer: MockWrappedSDKSynchronizer(),
|
||||||
walletStorage: .throwing
|
walletStorage: .throwing,
|
||||||
|
zcashSDKEnvironment: .testnet
|
||||||
)
|
)
|
||||||
|
|
||||||
let store = TestStore(
|
let store = TestStore(
|
||||||
|
|
|
@ -67,7 +67,6 @@ class SendTests: XCTestCase {
|
||||||
fee: Zatoshi(amount: 10),
|
fee: Zatoshi(amount: 10),
|
||||||
id: "id",
|
id: "id",
|
||||||
status: .paid(success: true),
|
status: .paid(success: true),
|
||||||
subtitle: "sub",
|
|
||||||
timestamp: 1234567,
|
timestamp: 1234567,
|
||||||
zecAmount: Zatoshi(amount: 10)
|
zecAmount: Zatoshi(amount: 10)
|
||||||
)
|
)
|
||||||
|
|
|
@ -25,7 +25,6 @@ class HomeSnapshotTests: XCTestCase {
|
||||||
fee: Zatoshi(amount: 10),
|
fee: Zatoshi(amount: 10),
|
||||||
shielded: $0.shielded,
|
shielded: $0.shielded,
|
||||||
status: $0.status,
|
status: $0.status,
|
||||||
subtitle: $0.subtitle,
|
|
||||||
timestamp: $0.date,
|
timestamp: $0.date,
|
||||||
uuid: $0.uuid
|
uuid: $0.uuid
|
||||||
)
|
)
|
||||||
|
@ -77,7 +76,6 @@ class HomeSnapshotTests: XCTestCase {
|
||||||
fee: Zatoshi(amount: 1_000_000),
|
fee: Zatoshi(amount: 1_000_000),
|
||||||
id: "ff3927e1f83df9b1b0dc75540ddc59ee435eecebae914d2e6dfe8576fbedc9a8",
|
id: "ff3927e1f83df9b1b0dc75540ddc59ee435eecebae914d2e6dfe8576fbedc9a8",
|
||||||
status: .paid(success: true),
|
status: .paid(success: true),
|
||||||
subtitle: "",
|
|
||||||
timestamp: 1234567,
|
timestamp: 1234567,
|
||||||
zecAmount: Zatoshi(amount: 25_000_000)
|
zecAmount: Zatoshi(amount: 25_000_000)
|
||||||
)
|
)
|
||||||
|
@ -103,9 +101,10 @@ class HomeSnapshotTests: XCTestCase {
|
||||||
|
|
||||||
// wallet event detail
|
// wallet event detail
|
||||||
let testEnvironment = WalletEventsFlowEnvironment(
|
let testEnvironment = WalletEventsFlowEnvironment(
|
||||||
|
pasteboard: .test,
|
||||||
scheduler: DispatchQueue.test.eraseToAnyScheduler(),
|
scheduler: DispatchQueue.test.eraseToAnyScheduler(),
|
||||||
SDKSynchronizer: TestWrappedSDKSynchronizer(),
|
SDKSynchronizer: TestWrappedSDKSynchronizer(),
|
||||||
pasteboard: .test
|
zcashSDKEnvironment: .testnet
|
||||||
)
|
)
|
||||||
|
|
||||||
ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent))))
|
ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent))))
|
||||||
|
|
|
@ -10,7 +10,7 @@ import XCTest
|
||||||
import ComposableArchitecture
|
import ComposableArchitecture
|
||||||
|
|
||||||
class WalletEventsSnapshotTests: XCTestCase {
|
class WalletEventsSnapshotTests: XCTestCase {
|
||||||
func testWalletEventDetailSnapshot() throws {
|
func testWalletEventDetailSnapshot_sent() throws {
|
||||||
let transaction = TransactionState(
|
let transaction = TransactionState(
|
||||||
memo:
|
memo:
|
||||||
"""
|
"""
|
||||||
|
@ -23,7 +23,6 @@ class WalletEventsSnapshotTests: XCTestCase {
|
||||||
fee: Zatoshi(amount: 1_000_000),
|
fee: Zatoshi(amount: 1_000_000),
|
||||||
id: "ff3927e1f83df9b1b0dc75540ddc59ee435eecebae914d2e6dfe8576fbedc9a8",
|
id: "ff3927e1f83df9b1b0dc75540ddc59ee435eecebae914d2e6dfe8576fbedc9a8",
|
||||||
status: .paid(success: true),
|
status: .paid(success: true),
|
||||||
subtitle: "",
|
|
||||||
timestamp: 1234567,
|
timestamp: 1234567,
|
||||||
zecAmount: Zatoshi(amount: 25_000_000)
|
zecAmount: Zatoshi(amount: 25_000_000)
|
||||||
)
|
)
|
||||||
|
@ -49,9 +48,187 @@ class WalletEventsSnapshotTests: XCTestCase {
|
||||||
|
|
||||||
// wallet event detail
|
// wallet event detail
|
||||||
let testEnvironment = WalletEventsFlowEnvironment(
|
let testEnvironment = WalletEventsFlowEnvironment(
|
||||||
|
pasteboard: .test,
|
||||||
scheduler: DispatchQueue.test.eraseToAnyScheduler(),
|
scheduler: DispatchQueue.test.eraseToAnyScheduler(),
|
||||||
SDKSynchronizer: TestWrappedSDKSynchronizer(),
|
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))))
|
ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent))))
|
||||||
|
|
|
@ -13,9 +13,10 @@ class WalletEventsTests: XCTestCase {
|
||||||
static let testScheduler = DispatchQueue.test
|
static let testScheduler = DispatchQueue.test
|
||||||
|
|
||||||
let testEnvironment = WalletEventsFlowEnvironment(
|
let testEnvironment = WalletEventsFlowEnvironment(
|
||||||
|
pasteboard: .test,
|
||||||
scheduler: testScheduler.eraseToAnyScheduler(),
|
scheduler: testScheduler.eraseToAnyScheduler(),
|
||||||
SDKSynchronizer: TestWrappedSDKSynchronizer(),
|
SDKSynchronizer: TestWrappedSDKSynchronizer(),
|
||||||
pasteboard: .test
|
zcashSDKEnvironment: .testnet
|
||||||
)
|
)
|
||||||
|
|
||||||
func testSynchronizerSubscription() throws {
|
func testSynchronizerSubscription() throws {
|
||||||
|
@ -48,12 +49,11 @@ class WalletEventsTests: XCTestCase {
|
||||||
date: 1651039606,
|
date: 1651039606,
|
||||||
amount: Zatoshi(amount: 6),
|
amount: Zatoshi(amount: 6),
|
||||||
status: .paid(success: false),
|
status: .paid(success: false),
|
||||||
subtitle: "pending",
|
|
||||||
uuid: "ff66"
|
uuid: "ff66"
|
||||||
),
|
),
|
||||||
TransactionStateMockHelper(date: 1651039303, amount: Zatoshi(amount: 7), subtitle: "pending", uuid: "gg77"),
|
TransactionStateMockHelper(date: 1651039303, amount: Zatoshi(amount: 7), uuid: "gg77"),
|
||||||
TransactionStateMockHelper(date: 1651039707, amount: Zatoshi(amount: 8), status: .paid(success: true), subtitle: "pending", uuid: "hh88"),
|
TransactionStateMockHelper(date: 1651039707, amount: Zatoshi(amount: 8), status: .paid(success: true), uuid: "hh88"),
|
||||||
TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(amount: 9), subtitle: "pending", uuid: "ii99")
|
TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(amount: 9), uuid: "ii99")
|
||||||
]
|
]
|
||||||
|
|
||||||
let walletEvents: [WalletEvent] = mocked.map {
|
let walletEvents: [WalletEvent] = mocked.map {
|
||||||
|
@ -61,14 +61,13 @@ class WalletEventsTests: XCTestCase {
|
||||||
amount: $0.amount,
|
amount: $0.amount,
|
||||||
fee: Zatoshi(amount: 10),
|
fee: Zatoshi(amount: 10),
|
||||||
shielded: $0.shielded,
|
shielded: $0.shielded,
|
||||||
status: $0.status,
|
status: $0.amount.amount > 5 ? .pending : $0.status,
|
||||||
subtitle: $0.subtitle,
|
|
||||||
timestamp: $0.date,
|
timestamp: $0.date,
|
||||||
uuid: $0.uuid
|
uuid: $0.uuid
|
||||||
)
|
)
|
||||||
return WalletEvent(
|
return WalletEvent(
|
||||||
id: transaction.id,
|
id: transaction.id,
|
||||||
state: transaction.subtitle == "pending" ? .pending(transaction) : .send(transaction),
|
state: transaction.status == .pending ? .pending(transaction) : .send(transaction),
|
||||||
timestamp: transaction.timestamp
|
timestamp: transaction.timestamp
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -106,9 +105,10 @@ class WalletEventsTests: XCTestCase {
|
||||||
let pasteboard = WrappedPasteboard.test
|
let pasteboard = WrappedPasteboard.test
|
||||||
|
|
||||||
let testEnvironment = WalletEventsFlowEnvironment(
|
let testEnvironment = WalletEventsFlowEnvironment(
|
||||||
|
pasteboard: pasteboard,
|
||||||
scheduler: DispatchQueue.test.eraseToAnyScheduler(),
|
scheduler: DispatchQueue.test.eraseToAnyScheduler(),
|
||||||
SDKSynchronizer: TestWrappedSDKSynchronizer(),
|
SDKSynchronizer: TestWrappedSDKSynchronizer(),
|
||||||
pasteboard: pasteboard
|
zcashSDKEnvironment: .testnet
|
||||||
)
|
)
|
||||||
|
|
||||||
let store = TestStore(
|
let store = TestStore(
|
||||||
|
|
Loading…
Reference in New Issue