[#1416] Shielded transaction UI
* [#1416] Shielded transaction UI * Shielded transaction design update * [#1416] Design updates Closes #1416 * [#1416] Code cleanup Closes #1416 * [#1416] Documentation update Closes #1416 * [#1416] Code cleanup Closes #1416 * [#1416] Shielding icon fix #Closes #1416 * [#1416] Resources update #Closes #1416 * Add Spanish whatsnew * [#1416] SDK snapshot Closes #1416 * Fix failing tests * Fix changelogs entry --------- Co-authored-by: Honza <rychnovsky.honza@gmail.com>
This commit is contained in:
parent
c6350641e3
commit
60fa9268e6
|
@ -11,7 +11,9 @@ and this application adheres to [Semantic Versioning](https://semver.org/spec/v2
|
|||
- Zashi app now supports Spanish language
|
||||
- The Flexa SDK has been adopted to enable payments using the embedded Flexa UI
|
||||
|
||||
### Changed
|
||||
### Changelog
|
||||
- Shielded transactions are properly indicated in transaction history
|
||||
- The in-app update logic has been fixed and is now correctly requested with every app launch
|
||||
- The Not enough space and In-app udpate screens have been redesigned
|
||||
|
||||
### Fixed
|
||||
|
|
|
@ -14,7 +14,9 @@ directly impact users rather than highlighting other key architectural updates.*
|
|||
- Zashi app now supports Spanish language
|
||||
- The Flexa SDK has been adopted to enable payments using the embedded Flexa UI
|
||||
|
||||
### Changed
|
||||
### Changelog
|
||||
- Shielded transactions are properly indicated in transaction history
|
||||
- The in-app update logic has been fixed and is now correctly requested with every app launch
|
||||
- The Not enough space and In-app udpate screens have been redesigned
|
||||
|
||||
### Fixed
|
||||
|
|
|
@ -14,11 +14,13 @@ directly impact users rather than highlighting other key architectural updates.*
|
|||
- Zashi app now supports Spanish language
|
||||
- The Flexa SDK has been adopted to enable payments using the embedded Flexa UI
|
||||
|
||||
### Changelog
|
||||
- Shielded transactions are properly indicated in transaction history
|
||||
- The in-app update logic has been fixed and is now correctly requested with every app launch
|
||||
- The Not enough space and In-app udpate screens have been redesigned
|
||||
|
||||
### Fixed
|
||||
- Address book toast now correctly shows on send screen when adding both new and known addresses to text field
|
||||
- The application now correctly navigates to the homepage after deleting the current wallet and creating a new or
|
||||
recovering an older one
|
||||
- The in-app update logic has been fixed and is now correctly requested with every app launch
|
||||
|
||||
### Changed
|
||||
- The Not enough space and In-app udpate screens have been redesigned
|
||||
- The in-app update logic has been fixed and is now correctly requested with every app launch
|
|
@ -219,7 +219,7 @@ ZCASH_BIP39_VERSION=1.0.8
|
|||
FLEXA_VERSION=1.0.5
|
||||
|
||||
# WARNING: Ensure a non-snapshot version is used before releasing to production
|
||||
ZCASH_SDK_VERSION=2.2.5
|
||||
ZCASH_SDK_VERSION=2.2.5-SNAPSHOT
|
||||
|
||||
# Toolchain is the Java version used to build the application, which is separate from the
|
||||
# Java version used to run the application.
|
||||
|
|
|
@ -10,6 +10,7 @@ import cash.z.ecc.android.sdk.model.FastestServersResult
|
|||
import cash.z.ecc.android.sdk.model.ObserveFiatCurrencyResult
|
||||
import cash.z.ecc.android.sdk.model.PercentDecimal
|
||||
import cash.z.ecc.android.sdk.model.Proposal
|
||||
import cash.z.ecc.android.sdk.model.TransactionOutput
|
||||
import cash.z.ecc.android.sdk.model.TransactionOverview
|
||||
import cash.z.ecc.android.sdk.model.TransactionRecipient
|
||||
import cash.z.ecc.android.sdk.model.TransactionSubmitResult
|
||||
|
@ -234,6 +235,10 @@ internal class MockSynchronizer : CloseableSynchronizer {
|
|||
error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
||||
}
|
||||
|
||||
override suspend fun getTransactionOutputs(transactionOverview: TransactionOverview): List<TransactionOutput> {
|
||||
error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun new() = MockSynchronizer()
|
||||
}
|
||||
|
|
|
@ -15,17 +15,20 @@ internal object TransactionHistorySyncStateFixture {
|
|||
TransactionOverviewExt(
|
||||
TransactionOverviewFixture.new(),
|
||||
TransactionRecipient.Account(Account.DEFAULT),
|
||||
AddressType.Shielded
|
||||
AddressType.Shielded,
|
||||
emptyList()
|
||||
),
|
||||
TransactionOverviewExt(
|
||||
TransactionOverviewFixture.new(),
|
||||
TransactionRecipient.Account(Account(1)),
|
||||
AddressType.Transparent
|
||||
AddressType.Transparent,
|
||||
emptyList()
|
||||
),
|
||||
TransactionOverviewExt(
|
||||
TransactionOverviewFixture.new(),
|
||||
null,
|
||||
AddressType.Unified
|
||||
AddressType.Unified,
|
||||
emptyList()
|
||||
),
|
||||
)
|
||||
val STATE = TransactionHistorySyncState.Syncing(TRANSACTIONS)
|
||||
|
|
|
@ -108,6 +108,8 @@ class WalletViewModel(
|
|||
it.getSortHeight(networkHeight)
|
||||
}
|
||||
.map {
|
||||
val outputs = synchronizer.getTransactionOutputs(it)
|
||||
|
||||
if (it.isSentTransaction) {
|
||||
val recipient = synchronizer.getRecipients(it).firstOrNull()
|
||||
TransactionOverviewExt(
|
||||
|
@ -118,14 +120,16 @@ class WalletViewModel(
|
|||
synchronizer.validateAddress(recipient.addressValue)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
},
|
||||
transactionOutputs = outputs,
|
||||
)
|
||||
} else {
|
||||
// Note that recipients can only be queried for sent transactions
|
||||
TransactionOverviewExt(
|
||||
overview = it,
|
||||
recipient = null,
|
||||
recipientAddressType = null
|
||||
recipientAddressType = null,
|
||||
transactionOutputs = outputs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package co.electriccoin.zcash.ui.screen.account.ext
|
||||
|
||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||
import cash.z.ecc.android.sdk.model.TransactionOutput
|
||||
import cash.z.ecc.android.sdk.model.TransactionOverview
|
||||
import cash.z.ecc.android.sdk.model.TransactionRecipient
|
||||
import cash.z.ecc.android.sdk.type.AddressType
|
||||
|
@ -8,7 +9,8 @@ import cash.z.ecc.android.sdk.type.AddressType
|
|||
data class TransactionOverviewExt(
|
||||
val overview: TransactionOverview,
|
||||
val recipient: TransactionRecipient?,
|
||||
val recipientAddressType: AddressType?
|
||||
val recipientAddressType: AddressType?,
|
||||
val transactionOutputs: List<TransactionOutput>
|
||||
)
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,6 +2,7 @@ package co.electriccoin.zcash.ui.screen.account.fixture
|
|||
|
||||
import cash.z.ecc.android.sdk.fixture.TransactionOverviewFixture
|
||||
import cash.z.ecc.android.sdk.fixture.WalletFixture
|
||||
import cash.z.ecc.android.sdk.model.TransactionOutput
|
||||
import cash.z.ecc.android.sdk.model.TransactionOverview
|
||||
import cash.z.ecc.android.sdk.model.TransactionRecipient
|
||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||
|
@ -26,6 +27,8 @@ object TransactionUiFixture {
|
|||
|
||||
val ADDRESS_BOOK_CONTACT: AddressBookContact? = null
|
||||
|
||||
val OUTPUTS: List<TransactionOutput> = emptyList()
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal fun new(
|
||||
overview: TransactionOverview = OVERVIEW,
|
||||
|
@ -33,13 +36,15 @@ object TransactionUiFixture {
|
|||
recipientAddressType: AddressType = RECIPIENT_ADDRESS_TYPE,
|
||||
expandableState: TrxItemState = EXPANDABLE_STATE,
|
||||
messages: List<String> = MESSAGES,
|
||||
addressBookContact: AddressBookContact? = ADDRESS_BOOK_CONTACT
|
||||
addressBookContact: AddressBookContact? = ADDRESS_BOOK_CONTACT,
|
||||
outputs: List<TransactionOutput> = OUTPUTS
|
||||
) = TransactionUi(
|
||||
overview = overview,
|
||||
recipient = recipient,
|
||||
recipientAddressType = recipientAddressType,
|
||||
expandableState = expandableState,
|
||||
messages = messages,
|
||||
addressBookContact = addressBookContact
|
||||
addressBookContact = addressBookContact,
|
||||
outputs = outputs
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package co.electriccoin.zcash.ui.screen.account.model
|
||||
|
||||
import cash.z.ecc.android.sdk.model.TransactionOutput
|
||||
import cash.z.ecc.android.sdk.model.TransactionOverview
|
||||
import cash.z.ecc.android.sdk.model.TransactionRecipient
|
||||
import cash.z.ecc.android.sdk.type.AddressType
|
||||
|
@ -12,21 +13,23 @@ data class TransactionUi(
|
|||
val recipientAddressType: AddressType?,
|
||||
val expandableState: TrxItemState,
|
||||
val messages: List<String>?,
|
||||
val addressBookContact: AddressBookContact?
|
||||
val addressBookContact: AddressBookContact?,
|
||||
val outputs: List<TransactionOutput>,
|
||||
) {
|
||||
companion object {
|
||||
fun new(
|
||||
data: TransactionOverviewExt,
|
||||
expandableState: TrxItemState,
|
||||
messages: List<String>?,
|
||||
addressBookContact: AddressBookContact?
|
||||
addressBookContact: AddressBookContact?,
|
||||
) = TransactionUi(
|
||||
overview = data.overview,
|
||||
recipient = data.recipient,
|
||||
recipientAddressType = data.recipientAddressType,
|
||||
expandableState = expandableState,
|
||||
messages = messages,
|
||||
addressBookContact = addressBookContact
|
||||
addressBookContact = addressBookContact,
|
||||
outputs = data.transactionOutputs
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ import androidx.compose.ui.unit.dp
|
|||
import cash.z.ecc.android.sdk.fixture.TransactionOverviewFixture
|
||||
import cash.z.ecc.android.sdk.model.FirstClassByteArray
|
||||
import cash.z.ecc.android.sdk.model.TransactionOverview
|
||||
import cash.z.ecc.android.sdk.model.TransactionPool
|
||||
import cash.z.ecc.android.sdk.model.TransactionRecipient
|
||||
import cash.z.ecc.android.sdk.model.TransactionState
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
|
@ -316,7 +317,7 @@ private fun ComposableHistoryListItemsPreview() {
|
|||
const val ADDRESS_IN_TITLE_WIDTH_RATIO = 0.5f
|
||||
|
||||
@Composable
|
||||
@Suppress("LongMethod")
|
||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||
private fun HistoryItem(
|
||||
transaction: TransactionUi,
|
||||
isHideBalances: Boolean,
|
||||
|
@ -375,6 +376,30 @@ private fun HistoryItem(
|
|||
textDecoration = TextDecoration.LineThrough
|
||||
)
|
||||
}
|
||||
|
||||
TransactionExtendedState.SHIELDED -> {
|
||||
typeText = stringResource(id = R.string.account_history_item_shielded_funds)
|
||||
typeIcon = ImageVector.vectorResource(R.drawable.ic_trx_shielded_funds)
|
||||
textColor = ZashiColors.Text.textPrimary
|
||||
textStyle = ZashiTypography.textSm
|
||||
}
|
||||
|
||||
TransactionExtendedState.SHIELDING -> {
|
||||
typeText = stringResource(id = R.string.account_history_item_shielding_funds)
|
||||
typeIcon = ImageVector.vectorResource(R.drawable.ic_trx_shielded_funds)
|
||||
textColor = ZashiColors.Text.textPrimary
|
||||
textStyle = ZashiTypography.textSm
|
||||
}
|
||||
|
||||
TransactionExtendedState.SHIELDING_FAILED -> {
|
||||
typeText = stringResource(id = R.string.account_history_item_shielding_failed)
|
||||
typeIcon = ImageVector.vectorResource(R.drawable.ic_trx_shielded_funds)
|
||||
textColor = ZashiColors.Text.textError
|
||||
textStyle =
|
||||
ZashiTypography.textSm.copy(
|
||||
textDecoration = TextDecoration.LineThrough
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
|
@ -581,7 +606,10 @@ private fun HistoryItemCollapsedAddressPart(
|
|||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if (
|
||||
transaction.outputs.none { it.pool == TransactionPool.TRANSPARENT } &&
|
||||
!transaction.overview.isShielding
|
||||
) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_trx_shielded),
|
||||
contentDescription = stringResource(id = R.string.account_history_item_shielded)
|
||||
|
@ -689,7 +717,7 @@ private fun HistoryItemExpandedPart(
|
|||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Column(modifier = modifier) {
|
||||
if (transaction.messages.containsValidMemo()) {
|
||||
if (transaction.overview.isShielding.not() && transaction.messages.containsValidMemo()) {
|
||||
Text(
|
||||
text =
|
||||
pluralStringResource(
|
||||
|
@ -974,41 +1002,41 @@ internal enum class TransactionExtendedState {
|
|||
SEND_FAILED,
|
||||
RECEIVED,
|
||||
RECEIVING,
|
||||
RECEIVE_FAILED;
|
||||
RECEIVE_FAILED,
|
||||
SHIELDED,
|
||||
SHIELDING,
|
||||
SHIELDING_FAILED;
|
||||
|
||||
fun isFailed(): Boolean = this == SEND_FAILED || this == RECEIVE_FAILED
|
||||
fun isShielding() = this in listOf(SHIELDED, RECEIVE_FAILED, SHIELDING_FAILED)
|
||||
|
||||
fun isSendType(): Boolean = this == SENDING || this == SENT || this == SEND_FAILED
|
||||
fun isFailed(): Boolean = this in listOf(SEND_FAILED, RECEIVE_FAILED, SHIELDING_FAILED)
|
||||
|
||||
fun isSendType(): Boolean = this in listOf(SENDING, SENT, SEND_FAILED, SHIELDED, SHIELDING_FAILED, SHIELDING)
|
||||
}
|
||||
|
||||
private fun TransactionOverview.getExtendedState(): TransactionExtendedState {
|
||||
return when (transactionState) {
|
||||
TransactionState.Expired -> {
|
||||
if (isSentTransaction) {
|
||||
TransactionExtendedState.SEND_FAILED
|
||||
} else {
|
||||
TransactionExtendedState.RECEIVE_FAILED
|
||||
TransactionState.Expired ->
|
||||
when {
|
||||
isShielding -> TransactionExtendedState.SHIELDING_FAILED
|
||||
isSentTransaction -> TransactionExtendedState.SEND_FAILED
|
||||
else -> TransactionExtendedState.RECEIVE_FAILED
|
||||
}
|
||||
}
|
||||
|
||||
TransactionState.Confirmed -> {
|
||||
if (isSentTransaction) {
|
||||
TransactionExtendedState.SENT
|
||||
} else {
|
||||
TransactionExtendedState.RECEIVED
|
||||
TransactionState.Confirmed ->
|
||||
when {
|
||||
isShielding -> TransactionExtendedState.SHIELDED
|
||||
isSentTransaction -> TransactionExtendedState.SENT
|
||||
else -> TransactionExtendedState.RECEIVED
|
||||
}
|
||||
}
|
||||
|
||||
TransactionState.Pending -> {
|
||||
if (isSentTransaction) {
|
||||
TransactionExtendedState.SENDING
|
||||
} else {
|
||||
TransactionExtendedState.RECEIVING
|
||||
TransactionState.Pending ->
|
||||
when {
|
||||
isShielding -> TransactionExtendedState.SHIELDING
|
||||
isSentTransaction -> TransactionExtendedState.SENDING
|
||||
else -> TransactionExtendedState.RECEIVING
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
error("Unexpected transaction state found while calculating its extended state.")
|
||||
}
|
||||
else -> error("Unexpected transaction state found while calculating its extended state.")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -131,7 +131,7 @@ class TransactionHistoryViewModel(
|
|||
data = data,
|
||||
expandableState = existingTransaction?.expandableState ?: TrxItemState.COLLAPSED,
|
||||
messages = existingTransaction?.messages,
|
||||
addressBookContact = addressBookContact
|
||||
addressBookContact = addressBookContact,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="19dp"
|
||||
android:height="18dp"
|
||||
android:viewportWidth="19"
|
||||
android:viewportHeight="18">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M5.979,0l12.774,8.126l-5.979,9.399l-12.774,-8.126z"/>
|
||||
<path
|
||||
android:pathData="M16.174,6.853C16.209,6.649 16.121,6.451 15.944,6.339L10.325,2.764C10.215,2.694 10.087,2.672 9.949,2.703C9.811,2.734 9.704,2.808 9.634,2.918C9.565,3.027 9.537,3.164 9.573,3.293C9.601,3.418 9.678,3.538 9.788,3.608L14.04,6.313L4.548,6.367L2.102,6.375C1.84,6.433 1.659,6.698 1.721,6.974C1.782,7.25 2.049,7.408 2.32,7.355L15.792,7.249C15.985,7.206 16.145,7.047 16.174,6.853Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M17.028,10.56C17,10.436 16.923,10.315 16.813,10.245C16.703,10.176 16.567,10.148 16.437,10.184L2.962,10.276C2.769,10.319 2.609,10.478 2.58,10.673C2.545,10.876 2.633,11.074 2.801,11.181L8.421,14.756C8.53,14.826 8.667,14.853 8.797,14.817C8.921,14.79 9.041,14.712 9.111,14.602C9.181,14.493 9.208,14.356 9.172,14.227C9.145,14.102 9.067,13.982 8.957,13.912L4.815,11.277L16.652,11.151C16.914,11.092 17.094,10.828 17.033,10.552L17.028,10.56Z"
|
||||
android:fillColor="#000000"/>
|
||||
</group>
|
||||
</vector>
|
|
@ -3,6 +3,9 @@
|
|||
<string name="account_history_empty">Sin historial de transacciones</string>
|
||||
|
||||
<string name="account_history_item_sent">Enviado</string>
|
||||
<string name="account_history_item_shielded_funds">Fondos Protegidos</string>
|
||||
<string name="account_history_item_shielding_funds">Protegiendo fondos…</string>
|
||||
<string name="account_history_item_shielding_failed">Fondos Protegidos Fallidos…</string>
|
||||
<string name="account_history_item_received">Recibido</string>
|
||||
<string name="account_history_item_sending">Enviando…</string>
|
||||
<string name="account_history_item_receiving">Recibiendo…</string>
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
<string name="account_history_empty">No transaction history</string>
|
||||
|
||||
<string name="account_history_item_sent">Sent</string>
|
||||
<string name="account_history_item_shielded_funds">Shielded Funds</string>
|
||||
<string name="account_history_item_shielding_funds">Shielding Funds…</string>
|
||||
<string name="account_history_item_shielding_failed">Shielding Failed…</string>
|
||||
<string name="account_history_item_received">Received</string>
|
||||
<string name="account_history_item_sending">Sending…</string>
|
||||
<string name="account_history_item_receiving">Receiving…</string>
|
||||
|
|
Loading…
Reference in New Issue