[#1147] Show transaction memo

- Improves the screen UI so we’re able to call click, and query transaction memos
- These APIs will be useful once we approach screen refactoring according to the Figma design
- Adds UI test for the new feature
- Closes #1147

Changelog update
This commit is contained in:
Honza Rychnovský 2024-01-02 09:03:12 +01:00 committed by GitHub
parent d4fdb9aec2
commit b544de316d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 223 additions and 105 deletions

View File

@ -9,6 +9,9 @@ directly impact users rather than highlighting other key architectural updates.*
## [Unreleased] ## [Unreleased]
### Added
- Transaction history items now display Memos within the Android Toast, triggered by clicking the item
## [0.2.0 (517)] - 2023-12-21 ## [0.2.0 (517)] - 2023-12-21
### Changed ### Changed

View File

@ -104,15 +104,20 @@ fun TitleLarge(
} }
@Composable @Composable
@Suppress("LongParameterList")
fun Small( fun Small(
text: String, text: String,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
maxLines: Int = Int.MAX_VALUE,
overflow: TextOverflow = TextOverflow.Clip,
textAlign: TextAlign = TextAlign.Start, textAlign: TextAlign = TextAlign.Start,
color: Color = MaterialTheme.colorScheme.onBackground, color: Color = MaterialTheme.colorScheme.onBackground,
) { ) {
Text( Text(
text = text, text = text,
color = color, color = color,
maxLines = maxLines,
overflow = overflow,
textAlign = textAlign, textAlign = textAlign,
modifier = modifier, modifier = modifier,
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,

View File

@ -10,11 +10,17 @@ class HistoryTestSetup(
private val composeTestRule: ComposeContentTestRule, private val composeTestRule: ComposeContentTestRule,
initialHistorySyncState: TransactionHistorySyncState initialHistorySyncState: TransactionHistorySyncState
) { ) {
private val onBackCount = AtomicInteger(0) private val onBackClickCount = AtomicInteger(0)
private val onItemClickCount = AtomicInteger(0)
fun getOnBackCount(): Int { fun getOnBackClickCount(): Int {
composeTestRule.waitForIdle() composeTestRule.waitForIdle()
return onBackCount.get() return onBackClickCount.get()
}
fun getOnItemClickCount(): Int {
composeTestRule.waitForIdle()
return onItemClickCount.get()
} }
init { init {
@ -22,8 +28,11 @@ class HistoryTestSetup(
ZcashTheme { ZcashTheme {
History( History(
transactionState = initialHistorySyncState, transactionState = initialHistorySyncState,
goBack = { onBack = {
onBackCount.incrementAndGet() onBackClickCount.incrementAndGet()
},
onItemClick = {
onItemClickCount.incrementAndGet()
} }
) )
} }

View File

@ -2,6 +2,7 @@ package co.electriccoin.zcash.ui.screen.history.view
import androidx.compose.ui.test.assertHeightIsAtLeast import androidx.compose.ui.test.assertHeightIsAtLeast
import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onAllNodesWithTag
import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.onNodeWithText
@ -105,10 +106,10 @@ class HistoryViewTest {
@Test @Test
@MediumTest @MediumTest
fun back() { fun back_click_test() {
val testSetup = newTestSetup() val testSetup = newTestSetup()
assertEquals(0, testSetup.getOnBackCount()) assertEquals(0, testSetup.getOnBackClickCount())
composeTestRule.onNodeWithContentDescription( composeTestRule.onNodeWithContentDescription(
getStringResource(R.string.history_back_content_description) getStringResource(R.string.history_back_content_description)
@ -116,7 +117,23 @@ class HistoryViewTest {
it.performClick() it.performClick()
} }
assertEquals(1, testSetup.getOnBackCount()) assertEquals(1, testSetup.getOnBackClickCount())
}
@Test
@MediumTest
fun item_click_test() {
val testSetup = newTestSetup(TransactionHistorySyncStateFixture.STATE)
assertEquals(0, testSetup.getOnItemClickCount())
composeTestRule.onAllNodesWithTag(HistoryTag.TRANSACTION_ITEM).also {
TransactionHistorySyncStateFixture.TRANSACTIONS.forEachIndexed { index, _ ->
it[index].performClick()
}
}
assertEquals(TransactionHistorySyncStateFixture.TRANSACTIONS.size, testSetup.getOnItemClickCount())
} }
private fun newTestSetup( private fun newTestSetup(

View File

@ -43,7 +43,9 @@ internal fun WrapAccount(
val isFiatConversionEnabled = ConfigurationEntries.IS_FIAT_CONVERSION_ENABLED.getValue(RemoteConfig.current) val isFiatConversionEnabled = ConfigurationEntries.IS_FIAT_CONVERSION_ENABLED.getValue(RemoteConfig.current)
if (null == walletSnapshot) { if (null == walletSnapshot) {
// Improve this by allowing screen composition and updating it after the data is available // 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() CircularScreenProgressIndicator()
} else { } else {
Account( Account(

View File

@ -28,7 +28,9 @@ private fun WrapWalletAddresses(
val walletAddresses = walletViewModel.addresses.collectAsStateWithLifecycle().value val walletAddresses = walletViewModel.addresses.collectAsStateWithLifecycle().value
if (null == walletAddresses) { if (null == walletAddresses) {
// Improve this by allowing screen composition and updating it after the data is available // 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() CircularScreenProgressIndicator()
} else { } else {
WalletAddresses( WalletAddresses(

View File

@ -46,7 +46,9 @@ internal fun WrapExportPrivateData(
val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value
if (synchronizer == null) { if (synchronizer == null) {
// Improve this by allowing screen composition and updating it after the data is available // 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() CircularScreenProgressIndicator()
} else { } else {
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }

View File

@ -3,11 +3,17 @@ package co.electriccoin.zcash.ui.screen.history
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import cash.z.ecc.android.sdk.internal.Twig import cash.z.ecc.android.sdk.internal.Twig
import co.electriccoin.zcash.spackle.ClipboardManagerUtil
import co.electriccoin.zcash.ui.MainActivity 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.common.viewmodel.WalletViewModel
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
import co.electriccoin.zcash.ui.screen.history.view.History import co.electriccoin.zcash.ui.screen.history.view.History
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
@Composable @Composable
internal fun MainActivity.WrapHistory(goBack: () -> Unit) { internal fun MainActivity.WrapHistory(goBack: () -> Unit) {
@ -22,15 +28,41 @@ internal fun WrapHistory(
activity: ComponentActivity, activity: ComponentActivity,
goBack: () -> Unit goBack: () -> Unit
) { ) {
val queryScope = rememberCoroutineScope()
val walletViewModel by activity.viewModels<WalletViewModel>() val walletViewModel by activity.viewModels<WalletViewModel>()
val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value
val transactionHistoryState = val transactionHistoryState =
walletViewModel.transactionHistoryState.collectAsStateWithLifecycle().value walletViewModel.transactionHistoryState.collectAsStateWithLifecycle().value
Twig.info { "Current transaction history state: $transactionHistoryState" } 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( History(
transactionState = transactionHistoryState, transactionState = transactionHistoryState,
goBack = goBack 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
) )
} }
}
},
)
}
}

View File

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

View File

@ -1,19 +1,18 @@
package co.electriccoin.zcash.ui.screen.history.view package co.electriccoin.zcash.ui.screen.history.view
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Cancel import androidx.compose.material.icons.filled.Cancel
@ -22,6 +21,8 @@ import androidx.compose.material.icons.outlined.ArrowCircleUp
import androidx.compose.material.icons.twotone.ArrowCircleDown import androidx.compose.material.icons.twotone.ArrowCircleDown
import androidx.compose.material.icons.twotone.ArrowCircleUp import androidx.compose.material.icons.twotone.ArrowCircleUp
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Divider
import androidx.compose.material3.DividerDefaults
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
@ -65,7 +66,8 @@ private fun ComposablePreview() {
GradientSurface { GradientSurface {
History( History(
transactionState = TransactionHistorySyncState.Loading, transactionState = TransactionHistorySyncState.Loading,
goBack = {} onBack = {},
onItemClick = {}
) )
} }
} }
@ -86,7 +88,8 @@ private fun ComposableHistoryListPreview() {
TransactionOverviewFixture.new(netValue = Zatoshi(300000000)), TransactionOverviewFixture.new(netValue = Zatoshi(300000000)),
) )
), ),
goBack = {} onBack = {},
onItemClick = {}
) )
} }
} }
@ -103,13 +106,15 @@ val dateFormat: DateFormat by lazy {
@Composable @Composable
fun History( fun History(
transactionState: TransactionHistorySyncState, transactionState: TransactionHistorySyncState,
goBack: () -> Unit onBack: () -> Unit,
onItemClick: (TransactionOverview) -> Unit
) { ) {
Scaffold(topBar = { Scaffold(topBar = {
HistoryTopBar(onBack = goBack) HistoryTopBar(onBack = onBack)
}) { paddingValues -> }) { paddingValues ->
HistoryMainContent( HistoryMainContent(
transactionState = transactionState, transactionState = transactionState,
onItemClick = onItemClick,
modifier = modifier =
Modifier Modifier
.fillMaxHeight() .fillMaxHeight()
@ -142,6 +147,7 @@ private fun HistoryTopBar(onBack: () -> Unit) {
@Composable @Composable
private fun HistoryMainContent( private fun HistoryMainContent(
transactionState: TransactionHistorySyncState, transactionState: TransactionHistorySyncState,
onItemClick: (TransactionOverview) -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
Box(modifier = modifier.fillMaxSize()) { Box(modifier = modifier.fillMaxSize()) {
@ -169,7 +175,10 @@ private fun HistoryMainContent(
end = ZcashTheme.dimens.spacingDefault end = ZcashTheme.dimens.spacingDefault
) )
) )
HistoryList(transactions = transactionState.transactions) HistoryList(
transactions = transactionState.transactions,
onItemClick = onItemClick
)
} }
// Add progress indicator only in the state of empty transaction // Add progress indicator only in the state of empty transaction
if (transactionState.hasNoTransactions()) { if (transactionState.hasNoTransactions()) {
@ -191,7 +200,10 @@ private fun HistoryMainContent(
.align(alignment = Center) .align(alignment = Center)
) )
} else { } else {
HistoryList(transactions = transactionState.transactions) HistoryList(
transactions = transactionState.transactions,
onItemClick = onItemClick
)
} }
} }
} }
@ -199,17 +211,25 @@ private fun HistoryMainContent(
} }
@Composable @Composable
private fun HistoryList(transactions: ImmutableList<TransactionOverview>) { private fun HistoryList(
val currency = ZcashCurrency.fromResources(LocalContext.current) transactions: ImmutableList<TransactionOverview>,
LazyColumn( onItemClick: (TransactionOverview) -> Unit
contentPadding = PaddingValues(all = ZcashTheme.dimens.spacingDefault),
modifier = Modifier.testTag(HistoryTag.TRANSACTION_LIST)
) { ) {
items(transactions) { val currency = ZcashCurrency.fromResources(LocalContext.current)
LazyColumn(modifier = Modifier.testTag(HistoryTag.TRANSACTION_LIST)) {
itemsIndexed(transactions) { index, item ->
HistoryItem( HistoryItem(
transaction = it, transaction = item,
currency = currency currency = currency,
onItemClick = onItemClick,
modifier = Modifier.testTag(HistoryTag.TRANSACTION_ITEM)
) )
if (index < transactions.lastIndex) {
Divider(
color = ZcashTheme.colors.dividerColor,
thickness = DividerDefaults.Thickness
)
}
} }
} }
} }
@ -218,56 +238,67 @@ private fun HistoryList(transactions: ImmutableList<TransactionOverview>) {
@Suppress("LongMethod") @Suppress("LongMethod")
fun HistoryItem( fun HistoryItem(
transaction: TransactionOverview, transaction: TransactionOverview,
currency: ZcashCurrency currency: ZcashCurrency,
onItemClick: (TransactionOverview) -> Unit,
modifier: Modifier = Modifier
) { ) {
Row( val transactionTypeText: String
modifier = val transactionTypeIcon: ImageVector
Modifier
.fillMaxWidth()
.padding(vertical = ZcashTheme.dimens.spacingSmall),
verticalAlignment = Alignment.CenterVertically
) {
val transactionText: String
val transactionIcon: ImageVector
when (transaction.getExtendedState()) { when (transaction.getExtendedState()) {
TransactionExtendedState.SENT -> { TransactionExtendedState.SENT -> {
transactionText = stringResource(id = R.string.history_item_sent) transactionTypeText = stringResource(id = R.string.history_item_sent)
transactionIcon = Icons.TwoTone.ArrowCircleUp transactionTypeIcon = Icons.TwoTone.ArrowCircleUp
} }
TransactionExtendedState.SENDING -> { TransactionExtendedState.SENDING -> {
transactionText = stringResource(id = R.string.history_item_sending) transactionTypeText = stringResource(id = R.string.history_item_sending)
transactionIcon = Icons.Outlined.ArrowCircleUp transactionTypeIcon = Icons.Outlined.ArrowCircleUp
} }
TransactionExtendedState.RECEIVED -> { TransactionExtendedState.RECEIVED -> {
transactionText = stringResource(id = R.string.history_item_received) transactionTypeText = stringResource(id = R.string.history_item_received)
transactionIcon = Icons.TwoTone.ArrowCircleDown transactionTypeIcon = Icons.TwoTone.ArrowCircleDown
} }
TransactionExtendedState.RECEIVING -> { TransactionExtendedState.RECEIVING -> {
transactionText = stringResource(id = R.string.history_item_receiving) transactionTypeText = stringResource(id = R.string.history_item_receiving)
transactionIcon = Icons.Outlined.ArrowCircleDown transactionTypeIcon = Icons.Outlined.ArrowCircleDown
} }
TransactionExtendedState.EXPIRED -> { TransactionExtendedState.EXPIRED -> {
transactionText = stringResource(id = R.string.history_item_expired) transactionTypeText = stringResource(id = R.string.history_item_expired)
transactionIcon = Icons.Filled.Cancel transactionTypeIcon = Icons.Filled.Cancel
} }
} }
Row(
modifier =
modifier.then(
Modifier
.fillMaxWidth()
.clickable { onItemClick(transaction) }
.padding(
horizontal = ZcashTheme.dimens.spacingDefault,
vertical = ZcashTheme.dimens.spacingDefault
)
),
verticalAlignment = Alignment.CenterVertically
) {
Image( Image(
imageVector = transactionIcon, imageVector = transactionTypeIcon,
contentDescription = transactionText, contentDescription = transactionTypeText,
modifier = Modifier.padding(all = ZcashTheme.dimens.spacingTiny) modifier = Modifier.padding(all = ZcashTheme.dimens.spacingTiny)
) )
Spacer(modifier = Modifier.width(ZcashTheme.dimens.spacingTiny))
Column(modifier = Modifier.fillMaxWidth()) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Column( Column(
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) { ) {
Body( Body(
text = transactionText, text = transactionTypeText,
color = Color.Black color = Color.Black
) )
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingTiny))
val dateString = val dateString =
transaction.minedHeight?.let { transaction.minedHeight?.let {
transaction.blockTimeEpochSeconds?.let { blockTimeEpochSeconds -> transaction.blockTimeEpochSeconds?.let { blockTimeEpochSeconds ->
@ -302,6 +333,8 @@ fun HistoryItem(
} }
} }
} }
}
}
enum class TransactionExtendedState { enum class TransactionExtendedState {
SENT, SENT,

View File

@ -130,7 +130,6 @@ fun Home(
thickness = DividerDefaults.Thickness, thickness = DividerDefaults.Thickness,
color = ZcashTheme.colors.dividerColor color = ZcashTheme.colors.dividerColor
) )
TabRow( TabRow(
selectedTabIndex = pagerState.currentPage, selectedTabIndex = pagerState.currentPage,
// Don't use the predefined divider, as it's fixed position is below the tabs bar // Don't use the predefined divider, as it's fixed position is below the tabs bar

View File

@ -34,7 +34,9 @@ internal fun WrapReceive(
onAddressDetails: () -> Unit, onAddressDetails: () -> Unit,
) { ) {
if (null == walletAddresses) { if (null == walletAddresses) {
// Improve this by allowing screen composition and updating it after the data is available // 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() CircularScreenProgressIndicator()
} else { } else {
Receive( Receive(

View File

@ -30,7 +30,9 @@ private fun WrapRequest(
val walletAddresses = walletViewModel.addresses.collectAsStateWithLifecycle().value val walletAddresses = walletViewModel.addresses.collectAsStateWithLifecycle().value
if (null == walletAddresses) { if (null == walletAddresses) {
// Improve this by allowing screen composition and updating it after the data is available // 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() CircularScreenProgressIndicator()
} else { } else {
Request( Request(

View File

@ -41,7 +41,9 @@ fun WrapScan(
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
if (synchronizer == null) { if (synchronizer == null) {
// Improve this by allowing screen composition and updating it after the data is available // 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() CircularScreenProgressIndicator()
} else { } else {
Scan( Scan(

View File

@ -40,7 +40,9 @@ private fun WrapSeedRecovery(
val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value
if (null == synchronizer || null == persistableWallet) { if (null == synchronizer || null == persistableWallet) {
// Improve this by allowing screen composition and updating it after the data is available // 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() CircularScreenProgressIndicator()
} else { } else {
SeedRecovery( SeedRecovery(

View File

@ -100,7 +100,9 @@ internal fun WrapSend(
} }
if (null == synchronizer || null == spendableBalance || null == spendingKey) { if (null == synchronizer || null == spendableBalance || null == spendingKey) {
// Improve this by allowing screen composition and updating it after the data is available // 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() CircularScreenProgressIndicator()
} else { } else {
Send( Send(

View File

@ -72,7 +72,9 @@ private fun WrapSettings(
null == isBackgroundSyncEnabled || null == isBackgroundSyncEnabled ||
null == isKeepScreenOnWhileSyncing null == isKeepScreenOnWhileSyncing
) { ) {
// Improve this by allowing screen composition and updating it after the data is available // 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() CircularScreenProgressIndicator()
} else { } else {
Settings( Settings(

View File

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