[#937] Shielded transaction UI
- The TransactionState has been extended to handle shielding - The UI for the transaction row has been extended to handle right states for all types of transactions, newly for shielding, shielded and shielding failed [#937] Shielded transaction UI - Rebased and updated to the latest API [#937] Shielded transaction UI - WIP [#937] Shielded transaction UI - Shileding UI updated to show amount the same way as sent/received - Shielding UI updated to show ID [#937] Shielded transaction UI - Duplicated code is removed, happened probably due to some rebases [#937] Shielded transaction UI - Code cleanup
This commit is contained in:
parent
eabdd22634
commit
16d51ea716
|
@ -240,81 +240,6 @@ public struct TabsView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.overlayPreferenceValue(ExchangeRateFeaturePreferenceKey.self) { preferences in
|
||||
if viewStore.isRateEducationEnabled {
|
||||
GeometryReader { geometry in
|
||||
preferences.map {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
HStack(alignment: .top, spacing: 0) {
|
||||
Asset.Assets.coinsSwap.image
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.frame(width: 20, height: 20)
|
||||
.foregroundColor(Asset.Colors.CurrencyConversion.optionTint.color)
|
||||
.padding(10)
|
||||
.background {
|
||||
Circle()
|
||||
.fill(Asset.Colors.CurrencyConversion.optionBcg.color)
|
||||
}
|
||||
.padding(.trailing, 16)
|
||||
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text(L10n.CurrencyConversion.cardTitle)
|
||||
.font(.custom(FontFamily.Inter.regular.name, size: 14))
|
||||
.foregroundColor(Asset.Colors.CurrencyConversion.tertiary.color)
|
||||
|
||||
Text(L10n.CurrencyConversion.title)
|
||||
.font(.custom(FontFamily.Inter.semiBold.name, size: 16))
|
||||
.foregroundColor(Asset.Colors.CurrencyConversion.primary.color)
|
||||
.lineLimit(nil)
|
||||
}
|
||||
.padding(.trailing, 16)
|
||||
|
||||
Spacer()
|
||||
|
||||
Button {
|
||||
viewStore.send(.currencyConversionCloseTapped)
|
||||
} label: {
|
||||
Asset.Assets.buttonCloseX.image
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.frame(width: 20, height: 20)
|
||||
.foregroundColor(Asset.Colors.CurrencyConversion.Card.close.color)
|
||||
}
|
||||
.padding(20)
|
||||
.offset(x: 20, y: -20)
|
||||
}
|
||||
|
||||
Button {
|
||||
viewStore.send(.updateDestination(.currencyConversionSetup))
|
||||
} label: {
|
||||
Text(L10n.CurrencyConversion.cardButton)
|
||||
.font(.custom(FontFamily.Inter.semiBold.name, size: 16))
|
||||
.foregroundColor(Asset.Colors.CurrencyConversion.primary.color)
|
||||
.frame(height: 24)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.vertical, 12)
|
||||
.background {
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.fill(Asset.Colors.CurrencyConversion.btnPrimaryDisabled.color)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(24)
|
||||
.background {
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.fill(Asset.Colors.CurrencyConversion.Card.bcg.color)
|
||||
.background {
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.stroke(Asset.Colors.CurrencyConversion.Card.outline.color)
|
||||
}
|
||||
}
|
||||
.frame(width: geometry.size.width - 40)
|
||||
.offset(x: 20, y: geometry[$0].minY + geometry[$0].height)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,11 +41,17 @@ struct TransactionHeaderView: View {
|
|||
|
||||
titleText()
|
||||
|
||||
addressArea()
|
||||
if !transaction.isShieldingTransaction {
|
||||
addressArea()
|
||||
|
||||
Spacer(minLength: 60)
|
||||
|
||||
balanceView()
|
||||
Spacer(minLength: 60)
|
||||
|
||||
balanceView()
|
||||
} else {
|
||||
Spacer()
|
||||
|
||||
balanceView()
|
||||
}
|
||||
}
|
||||
.padding(.trailing, 30)
|
||||
|
||||
|
@ -125,7 +131,7 @@ struct TransactionHeaderView: View {
|
|||
fontName: FontFamily.Inter.regular.name,
|
||||
mostSignificantFontSize: 12,
|
||||
leastSignificantFontSize: 8,
|
||||
prefixSymbol: transaction.isSpending ? .minus : .plus,
|
||||
prefixSymbol: (transaction.isSpending || transaction.isShieldingTransaction) ? .minus : .plus,
|
||||
format: transaction.isExpanded ? .expanded : .abbreviated,
|
||||
strikethrough: transaction.status == .failed,
|
||||
couldBeHidden: true
|
||||
|
@ -145,6 +151,13 @@ extension TransactionHeaderView {
|
|||
.frame(width: 20, height: 16)
|
||||
.foregroundColor(Asset.Colors.primary.color)
|
||||
|
||||
case .shielded, .shielding:
|
||||
Asset.Assets.shieldedFunds.image
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.frame(width: 20, height: 19)
|
||||
.foregroundColor(Asset.Colors.primary.color)
|
||||
|
||||
case .received, .receiving:
|
||||
if transaction.isUnread {
|
||||
Asset.Assets.flyReceivedFilled.image
|
||||
|
@ -195,7 +208,13 @@ extension TransactionHeaderView {
|
|||
transaction: .mockedSending
|
||||
)
|
||||
.listRowSeparator(.hidden)
|
||||
|
||||
|
||||
TransactionHeaderView(
|
||||
store: .placeholder,
|
||||
transaction: .mockedShielded
|
||||
)
|
||||
.listRowSeparator(.hidden)
|
||||
|
||||
TransactionHeaderView(
|
||||
store: .placeholder,
|
||||
transaction: .mockedReceiving
|
||||
|
|
|
@ -52,7 +52,7 @@ public struct TransactionRowView: View {
|
|||
|
||||
if transaction.isExpanded {
|
||||
Group {
|
||||
if !transaction.isTransparentRecipient {
|
||||
if !transaction.isTransparentRecipient && !transaction.isShieldingTransaction {
|
||||
MessageView(
|
||||
store: store,
|
||||
messages: transaction.textMemos,
|
||||
|
@ -65,8 +65,8 @@ public struct TransactionRowView: View {
|
|||
store: store,
|
||||
transaction: transaction
|
||||
)
|
||||
|
||||
if transaction.isSpending {
|
||||
|
||||
if transaction.isSpending || transaction.isShieldingTransaction {
|
||||
TransactionFeeView(fee: transaction.fee ?? .zero)
|
||||
.padding(.vertical, 10)
|
||||
}
|
||||
|
@ -94,6 +94,22 @@ public struct TransactionRowView: View {
|
|||
.listRowSeparator(.hidden)
|
||||
.listRowInsets(EdgeInsets())
|
||||
|
||||
TransactionRowView(
|
||||
store: .placeholder,
|
||||
transaction: .mockedShielded,
|
||||
tokenName: "ZEC"
|
||||
)
|
||||
.listRowSeparator(.hidden)
|
||||
.listRowInsets(EdgeInsets())
|
||||
|
||||
TransactionRowView(
|
||||
store: .placeholder,
|
||||
transaction: .mockedShieldedExpanded,
|
||||
tokenName: "ZEC"
|
||||
)
|
||||
.listRowSeparator(.hidden)
|
||||
.listRowInsets(EdgeInsets())
|
||||
|
||||
TransactionRowView(
|
||||
store: .placeholder,
|
||||
transaction: .mockedReceived,
|
||||
|
|
|
@ -737,6 +737,8 @@ public enum L10n {
|
|||
public static let failedReceive = L10n.tr("Localizable", "transaction.failedReceive", fallback: "Receive failed")
|
||||
/// Send failed
|
||||
public static let failedSend = L10n.tr("Localizable", "transaction.failedSend", fallback: "Send failed")
|
||||
/// Shielded Funds Failed
|
||||
public static let failedShieldedFunds = L10n.tr("Localizable", "transaction.failedShieldedFunds", fallback: "Shielded Funds Failed")
|
||||
/// Received
|
||||
public static let received = L10n.tr("Localizable", "transaction.received", fallback: "Received")
|
||||
/// Receiving...
|
||||
|
@ -745,6 +747,10 @@ public enum L10n {
|
|||
public static let sending = L10n.tr("Localizable", "transaction.sending", fallback: "Sending...")
|
||||
/// Sent
|
||||
public static let sent = L10n.tr("Localizable", "transaction.sent", fallback: "Sent")
|
||||
/// Shielded Funds
|
||||
public static let shieldedFunds = L10n.tr("Localizable", "transaction.shieldedFunds", fallback: "Shielded Funds")
|
||||
/// Shielding Funds
|
||||
public static let shieldingFunds = L10n.tr("Localizable", "transaction.shieldingFunds", fallback: "Shielding Funds")
|
||||
}
|
||||
public enum TransactionList {
|
||||
/// Collapse transaction
|
||||
|
|
12
modules/Sources/Generated/Resources/Assets.xcassets/shieldedFunds.imageset/Contents.json
vendored
Normal file
12
modules/Sources/Generated/Resources/Assets.xcassets/shieldedFunds.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "shieldedFunds.png",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
modules/Sources/Generated/Resources/Assets.xcassets/shieldedFunds.imageset/shieldedFunds.png
vendored
Normal file
BIN
modules/Sources/Generated/Resources/Assets.xcassets/shieldedFunds.imageset/shieldedFunds.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
|
@ -229,6 +229,9 @@ Sharing this private data is irrevocable — once you have shared this private d
|
|||
"transaction.received" = "Received";
|
||||
"transaction.failedSend" = "Send failed";
|
||||
"transaction.failedReceive" = "Receive failed";
|
||||
"transaction.shieldingFunds" = "Shielding Funds";
|
||||
"transaction.shieldedFunds" = "Shielded Funds";
|
||||
"transaction.failedShieldedFunds" = "Shielded Funds Failed";
|
||||
|
||||
// MARK: - Local authentication
|
||||
"localAuthentication.reason" = "The Following content requires authentication.";
|
||||
|
|
|
@ -51,6 +51,7 @@ public enum Asset {
|
|||
public static let share = ImageAsset(name: "share")
|
||||
public static let shield = ImageAsset(name: "shield")
|
||||
public static let shieldTick = ImageAsset(name: "shieldTick")
|
||||
public static let shieldedFunds = ImageAsset(name: "shieldedFunds")
|
||||
public static let surroundedShield = ImageAsset(name: "surroundedShield")
|
||||
public static let tooltip = ImageAsset(name: "tooltip")
|
||||
public static let torchOff = ImageAsset(name: "torchOff")
|
||||
|
|
|
@ -18,6 +18,8 @@ public struct TransactionState: Equatable, Identifiable {
|
|||
case received
|
||||
case receiving
|
||||
case sending
|
||||
case shielding
|
||||
case shielded
|
||||
}
|
||||
|
||||
public var errorMessage: String?
|
||||
|
@ -28,6 +30,7 @@ public struct TransactionState: Equatable, Identifiable {
|
|||
public var shielded = true
|
||||
public var zAddress: String?
|
||||
public var isSentTransaction: Bool
|
||||
public var isShieldingTransaction: Bool
|
||||
public var isTransparentRecipient: Bool
|
||||
|
||||
public var fee: Zatoshi?
|
||||
|
@ -47,7 +50,7 @@ public struct TransactionState: Equatable, Identifiable {
|
|||
public var balanceColor: Color {
|
||||
status == .failed
|
||||
? Asset.Colors.error.color
|
||||
: isSpending
|
||||
: (isSpending || isShieldingTransaction)
|
||||
? Asset.Colors.error.color
|
||||
: Asset.Colors.primary.color
|
||||
}
|
||||
|
@ -98,6 +101,7 @@ public struct TransactionState: Equatable, Identifiable {
|
|||
public var title: String {
|
||||
switch status {
|
||||
case .failed:
|
||||
// TODO: failed shileded is not covered!
|
||||
return isSentTransaction
|
||||
? L10n.Transaction.failedSend
|
||||
: L10n.Transaction.failedReceive
|
||||
|
@ -109,6 +113,10 @@ public struct TransactionState: Equatable, Identifiable {
|
|||
return L10n.Transaction.receiving
|
||||
case .sending:
|
||||
return L10n.Transaction.sending
|
||||
case .shielding:
|
||||
return L10n.Transaction.shieldingFunds
|
||||
case .shielded:
|
||||
return L10n.Transaction.shieldedFunds
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,6 +140,10 @@ public struct TransactionState: Equatable, Identifiable {
|
|||
return true
|
||||
case .sending:
|
||||
return true
|
||||
case .shielded:
|
||||
return false
|
||||
case .shielding:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,6 +154,8 @@ public struct TransactionState: Equatable, Identifiable {
|
|||
return true
|
||||
case .received, .receiving:
|
||||
return false
|
||||
case .shielded, .shielding:
|
||||
return false
|
||||
case .failed:
|
||||
return isSentTransaction
|
||||
}
|
||||
|
@ -184,6 +198,7 @@ public struct TransactionState: Equatable, Identifiable {
|
|||
timestamp: TimeInterval? = nil,
|
||||
zecAmount: Zatoshi,
|
||||
isSentTransaction: Bool = false,
|
||||
isShieldingTransaction: Bool = false,
|
||||
isTransparentRecipient: Bool = false,
|
||||
isAddressExpanded: Bool = false,
|
||||
isExpanded: Bool = false,
|
||||
|
@ -203,6 +218,7 @@ public struct TransactionState: Equatable, Identifiable {
|
|||
self.timestamp = timestamp
|
||||
self.zecAmount = zecAmount
|
||||
self.isSentTransaction = isSentTransaction
|
||||
self.isShieldingTransaction = isShieldingTransaction
|
||||
self.isTransparentRecipient = isTransparentRecipient
|
||||
self.isAddressExpanded = isAddressExpanded
|
||||
self.isExpanded = isExpanded
|
||||
|
@ -238,8 +254,9 @@ extension TransactionState {
|
|||
fee = transaction.fee
|
||||
id = transaction.rawID.toHexStringTxId()
|
||||
timestamp = transaction.blockTime
|
||||
zecAmount = transaction.isSentTransaction ? Zatoshi(-transaction.value.amount) : transaction.value
|
||||
isSentTransaction = transaction.isSentTransaction
|
||||
isShieldingTransaction = transaction.isShielding
|
||||
zecAmount = isSentTransaction ? Zatoshi(-transaction.value.amount) : transaction.value
|
||||
isTransparentRecipient = false
|
||||
isAddressExpanded = false
|
||||
isExpanded = false
|
||||
|
@ -247,18 +264,24 @@ extension TransactionState {
|
|||
memoCount = transaction.memoCount
|
||||
self.memos = memos
|
||||
|
||||
if transaction.isShielding {
|
||||
print("aa")
|
||||
}
|
||||
|
||||
// TODO: [#1313] SDK improvements so a client doesn't need to determing if the transaction isPending
|
||||
// https://github.com/zcash/ZcashLightClientKit/issues/1313
|
||||
// The only reason why `latestBlockHeight` is provided here is to determine pending
|
||||
// state of the transaction. SDK knows the latestBlockHeight so ideally ZcashTransaction.Overview
|
||||
// already knows and provides isPending as a bool value.
|
||||
// Once SDK's #1313 is done, adopt the SDK and remove latestBlockHeight here.
|
||||
let isPending = transaction.isPending(currentHeight: latestBlockHeight)
|
||||
|
||||
// failed check
|
||||
if let expiryHeight = transaction.expiryHeight, expiryHeight <= latestBlockHeight && minedHeight == nil {
|
||||
status = .failed
|
||||
} else if isShieldingTransaction {
|
||||
status = isPending ? .shielding : .shielded
|
||||
} else {
|
||||
// TODO: [#1313] SDK improvements so a client doesn't need to determing if the transaction isPending
|
||||
// https://github.com/zcash/ZcashLightClientKit/issues/1313
|
||||
// The only reason why `latestBlockHeight` is provided here is to determine pending
|
||||
// state of the transaction. SDK knows the latestBlockHeight so ideally ZcashTransaction.Overview
|
||||
// already knows and provides isPending as a bool value.
|
||||
// Once SDK's #1313 is done, adopt the SDK and remove latestBlockHeight here.
|
||||
let isPending = transaction.isPending(currentHeight: latestBlockHeight)
|
||||
|
||||
switch (isSentTransaction, isPending) {
|
||||
case (true, true): status = .sending
|
||||
case (true, false): status = .paid
|
||||
|
@ -378,6 +401,34 @@ extension TransactionState {
|
|||
isExpanded: false,
|
||||
isIdExpanded: false
|
||||
)
|
||||
|
||||
public static let mockedShielded = TransactionState(
|
||||
minedHeight: BlockHeight(1),
|
||||
zAddress: "utest1vergg5jkp4xy8sqfasw6s5zkdpnxvfxlxh35uuc3me7dp596y2r05t6dv9htwe3pf8ksrfr8ksca2lskzjanqtl8uqp5vln3zyy246ejtx86vqftp73j7jg9099jxafyjhfm6u956j3",
|
||||
fee: Zatoshi(10_000),
|
||||
id: "t1vergg5jkp4wy8sqfasw6s5zkdpnxvfxlxh35uuc3me7dp596y2r05t6dv9htwe3pf8ksrfr8ksca2lskzja",
|
||||
status: .shielded,
|
||||
timestamp: 1699290621,
|
||||
zecAmount: Zatoshi(25_000_000),
|
||||
isShieldingTransaction: true,
|
||||
isAddressExpanded: false,
|
||||
isExpanded: false,
|
||||
isIdExpanded: false
|
||||
)
|
||||
|
||||
public static let mockedShieldedExpanded = TransactionState(
|
||||
minedHeight: BlockHeight(1),
|
||||
zAddress: "utest1vergg5jkp4xy8sqfasw6s5zkdpnxvfxlxh35uuc3me7dp596y2r05t6dv9htwe3pf8ksrfr8ksca2lskzjanqtl8uqp5vln3zyy246ejtx86vqftp73j7jg9099jxafyjhfm6u956j3",
|
||||
fee: Zatoshi(10_000),
|
||||
id: "t1vergg5jkp4wy8sqfasw6s5zkdpnxvfxlxh35uuc3me7dp596y2r05t6dv9htwe3pf8ksrfr8ksca2lskzja",
|
||||
status: .shielded,
|
||||
timestamp: 1699290621,
|
||||
zecAmount: Zatoshi(25_000_000),
|
||||
isShieldingTransaction: true,
|
||||
isAddressExpanded: false,
|
||||
isExpanded: true,
|
||||
isIdExpanded: false
|
||||
)
|
||||
}
|
||||
|
||||
public struct TransactionStateMockHelper {
|
||||
|
|
Loading…
Reference in New Issue