diff --git a/CHANGELOG.md b/CHANGELOG.md index c542b8c6..680f7899 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/docs/whatsNew/WHATS_NEW_EN.md b/docs/whatsNew/WHATS_NEW_EN.md index b857e449..45a86001 100644 --- a/docs/whatsNew/WHATS_NEW_EN.md +++ b/docs/whatsNew/WHATS_NEW_EN.md @@ -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 diff --git a/docs/whatsNew/WHATS_NEW_ES.md b/docs/whatsNew/WHATS_NEW_ES.md index 813f1bdb..26861f04 100644 --- a/docs/whatsNew/WHATS_NEW_ES.md +++ b/docs/whatsNew/WHATS_NEW_ES.md @@ -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 \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 9aff154d..f2827ade 100644 --- a/gradle.properties +++ b/gradle.properties @@ -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. diff --git a/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/fixture/MockSynchronizer.kt b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/fixture/MockSynchronizer.kt index c25bb006..80668c01 100644 --- a/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/fixture/MockSynchronizer.kt +++ b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/fixture/MockSynchronizer.kt @@ -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 { + error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.") + } + companion object { fun new() = MockSynchronizer() } diff --git a/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/account/history/fixture/TransactionHistorySyncStateFixture.kt b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/account/history/fixture/TransactionHistorySyncStateFixture.kt index 616b1896..fc71fc99 100644 --- a/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/account/history/fixture/TransactionHistorySyncStateFixture.kt +++ b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/account/history/fixture/TransactionHistorySyncStateFixture.kt @@ -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) diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/common/viewmodel/WalletViewModel.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/common/viewmodel/WalletViewModel.kt index 11ed48ed..dd959c57 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/common/viewmodel/WalletViewModel.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/common/viewmodel/WalletViewModel.kt @@ -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, ) } } diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/ext/TransactionOverviewExt.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/ext/TransactionOverviewExt.kt index d9947f53..7823e318 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/ext/TransactionOverviewExt.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/ext/TransactionOverviewExt.kt @@ -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 ) /** diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/fixture/TransactionUiFixture.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/fixture/TransactionUiFixture.kt index 6308ceee..01d7535c 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/fixture/TransactionUiFixture.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/fixture/TransactionUiFixture.kt @@ -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 = 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 = MESSAGES, - addressBookContact: AddressBookContact? = ADDRESS_BOOK_CONTACT + addressBookContact: AddressBookContact? = ADDRESS_BOOK_CONTACT, + outputs: List = OUTPUTS ) = TransactionUi( overview = overview, recipient = recipient, recipientAddressType = recipientAddressType, expandableState = expandableState, messages = messages, - addressBookContact = addressBookContact + addressBookContact = addressBookContact, + outputs = outputs ) } diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/model/TransactionUi.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/model/TransactionUi.kt index 7d8e5f79..c458e2ea 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/model/TransactionUi.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/model/TransactionUi.kt @@ -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?, - val addressBookContact: AddressBookContact? + val addressBookContact: AddressBookContact?, + val outputs: List, ) { companion object { fun new( data: TransactionOverviewExt, expandableState: TrxItemState, messages: List?, - 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 ) } } diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/view/HistoryView.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/view/HistoryView.kt index 9c966511..02167e2e 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/view/HistoryView.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/view/HistoryView.kt @@ -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.") } } diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/viewmodel/TransactionHistoryViewModel.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/viewmodel/TransactionHistoryViewModel.kt index db408680..731a5822 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/viewmodel/TransactionHistoryViewModel.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/account/viewmodel/TransactionHistoryViewModel.kt @@ -131,7 +131,7 @@ class TransactionHistoryViewModel( data = data, expandableState = existingTransaction?.expandableState ?: TrxItemState.COLLAPSED, messages = existingTransaction?.messages, - addressBookContact = addressBookContact + addressBookContact = addressBookContact, ) } diff --git a/ui-lib/src/main/res/ui/account/drawable/ic_trx_shielded_funds.xml b/ui-lib/src/main/res/ui/account/drawable/ic_trx_shielded_funds.xml new file mode 100644 index 00000000..e414d393 --- /dev/null +++ b/ui-lib/src/main/res/ui/account/drawable/ic_trx_shielded_funds.xml @@ -0,0 +1,16 @@ + + + + + + + diff --git a/ui-lib/src/main/res/ui/account/values-es/strings.xml b/ui-lib/src/main/res/ui/account/values-es/strings.xml index a411f765..1d9d9766 100644 --- a/ui-lib/src/main/res/ui/account/values-es/strings.xml +++ b/ui-lib/src/main/res/ui/account/values-es/strings.xml @@ -3,6 +3,9 @@ Sin historial de transacciones Enviado + Fondos Protegidos + Protegiendo fondos… + Fondos Protegidos Fallidos… Recibido Enviando… Recibiendo… diff --git a/ui-lib/src/main/res/ui/account/values/strings.xml b/ui-lib/src/main/res/ui/account/values/strings.xml index 254a83ea..7a8628ac 100644 --- a/ui-lib/src/main/res/ui/account/values/strings.xml +++ b/ui-lib/src/main/res/ui/account/values/strings.xml @@ -3,6 +3,9 @@ No transaction history Sent + Shielded Funds + Shielding Funds… + Shielding Failed… Received Sending… Receiving…