[#1143] Transaction ID row in Transaction item

* [#1143] Transaction ID row in Transaction item

- Added a new transaction ID row into the transaction item on the Transactions screen
- It displays a TODO value instead of the TXID until the #1316 in SDK done
- Closes #1143

Changelog update
This commit is contained in:
Honza Rychnovský 2024-01-02 14:25:24 +01:00 committed by GitHub
parent b544de316d
commit 2f33ccf818
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 124 additions and 45 deletions

View File

@ -11,6 +11,7 @@ directly impact users rather than highlighting other key architectural updates.*
### Added
- Transaction history items now display Memos within the Android Toast, triggered by clicking the item
- Transaction history items add displaying transaction IDs; the ID element is also clickable
## [0.2.0 (517)] - 2023-12-21

View File

@ -124,6 +124,27 @@ fun Small(
)
}
@Composable
@Suppress("LongParameterList")
fun Tiny(
text: String,
modifier: Modifier = Modifier,
maxLines: Int = Int.MAX_VALUE,
overflow: TextOverflow = TextOverflow.Clip,
textAlign: TextAlign = TextAlign.Start,
color: Color = MaterialTheme.colorScheme.onBackground,
) {
Text(
text = text,
color = color,
maxLines = maxLines,
overflow = overflow,
textAlign = textAlign,
modifier = modifier,
style = MaterialTheme.typography.labelSmall,
)
}
@Composable
fun ListItem(
text: String,

View File

@ -12,6 +12,7 @@ class HistoryTestSetup(
) {
private val onBackClickCount = AtomicInteger(0)
private val onItemClickCount = AtomicInteger(0)
private val onItemIdClickCount = AtomicInteger(0)
fun getOnBackClickCount(): Int {
composeTestRule.waitForIdle()
@ -23,6 +24,11 @@ class HistoryTestSetup(
return onItemClickCount.get()
}
fun getOnItemIdClickCount(): Int {
composeTestRule.waitForIdle()
return onItemIdClickCount.get()
}
init {
composeTestRule.setContent {
ZcashTheme {
@ -33,6 +39,9 @@ class HistoryTestSetup(
},
onItemClick = {
onItemClickCount.incrementAndGet()
},
onTransactionIdClick = {
onItemIdClickCount.incrementAndGet()
}
)
}

View File

@ -1,5 +1,6 @@
package co.electriccoin.zcash.ui.screen.history.view
import androidx.compose.ui.test.assertCountEquals
import androidx.compose.ui.test.assertHeightIsAtLeast
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onAllNodesWithTag
@ -127,7 +128,9 @@ class HistoryViewTest {
assertEquals(0, testSetup.getOnItemClickCount())
composeTestRule.onAllNodesWithTag(HistoryTag.TRANSACTION_ITEM).also {
composeTestRule.onAllNodesWithTag(HistoryTag.TRANSACTION_ITEM, useUnmergedTree = true).also {
it.assertCountEquals(TransactionHistorySyncStateFixture.TRANSACTIONS.size)
TransactionHistorySyncStateFixture.TRANSACTIONS.forEachIndexed { index, _ ->
it[index].performClick()
}
@ -136,6 +139,24 @@ class HistoryViewTest {
assertEquals(TransactionHistorySyncStateFixture.TRANSACTIONS.size, testSetup.getOnItemClickCount())
}
@Test
@MediumTest
fun transaction_id_click_test() {
val testSetup = newTestSetup(TransactionHistorySyncStateFixture.STATE)
assertEquals(0, testSetup.getOnItemIdClickCount())
composeTestRule.onAllNodesWithTag(HistoryTag.TRANSACTION_ID).also {
it.assertCountEquals(TransactionHistorySyncStateFixture.TRANSACTIONS.size)
TransactionHistorySyncStateFixture.TRANSACTIONS.forEachIndexed { index, _ ->
it[index].performClick()
}
}
assertEquals(TransactionHistorySyncStateFixture.TRANSACTIONS.size, testSetup.getOnItemIdClickCount())
}
private fun newTestSetup(
transactionHistorySyncState: TransactionHistorySyncState = TransactionHistorySyncStateFixture.new()
): HistoryTestSetup {

View File

@ -10,7 +10,6 @@ import co.electriccoin.zcash.spackle.ClipboardManagerUtil
import co.electriccoin.zcash.ui.MainActivity
import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
import co.electriccoin.zcash.ui.screen.history.view.History
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
@ -39,30 +38,31 @@ internal fun WrapHistory(
Twig.info { "Current transaction history state: $transactionHistoryState" }
if (synchronizer == null) {
// TODO [#1146]: Consider moving CircularScreenProgressIndicator from Android layer to View layer
// TODO [#1146]: Improve this by allowing screen composition and updating it after the data is available
// TODO [#1146]: https://github.com/Electric-Coin-Company/zashi-android/issues/1146
CircularScreenProgressIndicator()
} else {
History(
transactionState = transactionHistoryState,
onBack = goBack,
onItemClick = { tx ->
Twig.debug { "Querying transaction memos..." }
val memos = synchronizer.getMemos(tx)
queryScope.launch {
memos.toList().run {
val merged = joinToString().ifEmpty { "-" }
Twig.info { "Transaction memos: count: $size, contains: $merged" }
ClipboardManagerUtil.copyToClipboard(
activity.applicationContext,
activity.getString(R.string.history_item_clipboard_tag),
merged
)
}
History(
transactionState = transactionHistoryState,
onBack = goBack,
onItemClick = { tx ->
Twig.debug { "Transaction item clicked - querying memos..." }
val memos = synchronizer?.getMemos(tx)
queryScope.launch {
memos?.toList()?.let {
val merged = it.joinToString().ifEmpty { "-" }
Twig.info { "Transaction memos: count: ${it.size}, contains: $merged" }
ClipboardManagerUtil.copyToClipboard(
activity.applicationContext,
activity.getString(R.string.history_item_clipboard_tag),
merged
)
}
},
)
}
}
},
onTransactionIdClick = { txId ->
Twig.debug { "Transaction ID clicked: $txId" }
ClipboardManagerUtil.copyToClipboard(
activity.applicationContext,
activity.getString(R.string.history_id_clipboard_tag),
txId
)
}
)
}

View File

@ -6,5 +6,6 @@ package co.electriccoin.zcash.ui.screen.history
object HistoryTag {
const val TRANSACTION_LIST = "transaction_list"
const val TRANSACTION_ITEM = "transaction_item"
const val TRANSACTION_ID = "transaction_id"
const val PROGRESS = "progress_bar"
}

View File

@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
@ -49,7 +50,9 @@ import cash.z.ecc.android.sdk.model.toZecString
import cash.z.ecc.sdk.type.ZcashCurrency
import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.design.component.Body
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
import co.electriccoin.zcash.ui.design.component.GradientSurface
import co.electriccoin.zcash.ui.design.component.Tiny
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.screen.history.HistoryTag
import co.electriccoin.zcash.ui.screen.history.state.TransactionHistorySyncState
@ -67,7 +70,8 @@ private fun ComposablePreview() {
History(
transactionState = TransactionHistorySyncState.Loading,
onBack = {},
onItemClick = {}
onItemClick = {},
onTransactionIdClick = {}
)
}
}
@ -89,7 +93,8 @@ private fun ComposableHistoryListPreview() {
)
),
onBack = {},
onItemClick = {}
onItemClick = {},
onTransactionIdClick = {}
)
}
}
@ -107,7 +112,8 @@ val dateFormat: DateFormat by lazy {
fun History(
transactionState: TransactionHistorySyncState,
onBack: () -> Unit,
onItemClick: (TransactionOverview) -> Unit
onItemClick: (TransactionOverview) -> Unit,
onTransactionIdClick: (String) -> Unit
) {
Scaffold(topBar = {
HistoryTopBar(onBack = onBack)
@ -115,6 +121,7 @@ fun History(
HistoryMainContent(
transactionState = transactionState,
onItemClick = onItemClick,
onTransactionIdClick = onTransactionIdClick,
modifier =
Modifier
.fillMaxHeight()
@ -145,15 +152,17 @@ private fun HistoryTopBar(onBack: () -> Unit) {
}
@Composable
@Suppress("LongMethod")
private fun HistoryMainContent(
transactionState: TransactionHistorySyncState,
onItemClick: (TransactionOverview) -> Unit,
onTransactionIdClick: (String) -> Unit,
modifier: Modifier = Modifier
) {
Box(modifier = modifier.fillMaxSize()) {
when (transactionState) {
is TransactionHistorySyncState.Loading -> {
CircularProgressIndicator(
CircularScreenProgressIndicator(
modifier =
Modifier
.align(alignment = Center)
@ -177,7 +186,8 @@ private fun HistoryMainContent(
)
HistoryList(
transactions = transactionState.transactions,
onItemClick = onItemClick
onItemClick = onItemClick,
onTransactionIdClick = onTransactionIdClick
)
}
// Add progress indicator only in the state of empty transaction
@ -202,7 +212,8 @@ private fun HistoryMainContent(
} else {
HistoryList(
transactions = transactionState.transactions,
onItemClick = onItemClick
onItemClick = onItemClick,
onTransactionIdClick = onTransactionIdClick
)
}
}
@ -213,7 +224,8 @@ private fun HistoryMainContent(
@Composable
private fun HistoryList(
transactions: ImmutableList<TransactionOverview>,
onItemClick: (TransactionOverview) -> Unit
onItemClick: (TransactionOverview) -> Unit,
onTransactionIdClick: (String) -> Unit
) {
val currency = ZcashCurrency.fromResources(LocalContext.current)
LazyColumn(modifier = Modifier.testTag(HistoryTag.TRANSACTION_LIST)) {
@ -222,7 +234,7 @@ private fun HistoryList(
transaction = item,
currency = currency,
onItemClick = onItemClick,
modifier = Modifier.testTag(HistoryTag.TRANSACTION_ITEM)
onIdClick = onTransactionIdClick,
)
if (index < transactions.lastIndex) {
Divider(
@ -240,6 +252,7 @@ fun HistoryItem(
transaction: TransactionOverview,
currency: ZcashCurrency,
onItemClick: (TransactionOverview) -> Unit,
onIdClick: (String) -> Unit,
modifier: Modifier = Modifier
) {
val transactionTypeText: String
@ -269,15 +282,13 @@ fun HistoryItem(
Row(
modifier =
modifier.then(
Modifier
.fillMaxWidth()
.clickable { onItemClick(transaction) }
.padding(
horizontal = ZcashTheme.dimens.spacingDefault,
vertical = ZcashTheme.dimens.spacingDefault
)
),
Modifier
.fillMaxWidth()
.clickable { onItemClick(transaction) }
.padding(
horizontal = ZcashTheme.dimens.spacingDefault,
vertical = ZcashTheme.dimens.spacingDefault
).then(modifier),
verticalAlignment = Alignment.CenterVertically
) {
Image(
@ -296,7 +307,8 @@ fun HistoryItem(
) {
Body(
text = transactionTypeText,
color = Color.Black
color = Color.Black,
modifier = Modifier.testTag(HistoryTag.TRANSACTION_ITEM)
)
val dateString =
@ -332,6 +344,19 @@ fun HistoryItem(
}
}
}
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingTiny))
// TODO [#1316]: Provide readable TxId on TransactionOverview
// TODO [#1316]: https://github.com/Electric-Coin-Company/zcash-android-wallet-sdk/issues/1316
// TODO [#1316]: transaction.rawId.byteArray.toHexReversed()
val txId = "TODO [#1316]: SDK: Provide readable TxId"
Tiny(
text = txId,
modifier =
Modifier
.clickable { onIdClick(txId) }
.testTag(HistoryTag.TRANSACTION_ID)
)
}
}
}

View File

@ -4,6 +4,7 @@
<string name="history_syncing">Additional transactions may be found after syncing completes…</string>
<string name="history_empty">No transactions yet</string>
<string name="history_item_clipboard_tag">Transaction memo</string>
<string name="history_id_clipboard_tag">Transaction ID</string>
<string name="history_item_sent">Sent</string>
<string name="history_item_received">Received</string>