[#664] - transaction history, not fully implemented

This commit is contained in:
Alexej Hlinka 2023-01-03 14:27:42 +01:00
parent 2b899a7200
commit 97a7fa9892
8 changed files with 177 additions and 6 deletions

View File

@ -6,8 +6,6 @@
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
</value>
</option>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
</JetCodeStyleSettings>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />

View File

@ -8,6 +8,7 @@ import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import co.electriccoin.zcash.ui.NavigationTargets.ABOUT
import co.electriccoin.zcash.ui.NavigationTargets.HISTORY
import co.electriccoin.zcash.ui.NavigationTargets.HOME
import co.electriccoin.zcash.ui.NavigationTargets.PROFILE
import co.electriccoin.zcash.ui.NavigationTargets.REQUEST
@ -17,6 +18,7 @@ import co.electriccoin.zcash.ui.NavigationTargets.SEND
import co.electriccoin.zcash.ui.NavigationTargets.SETTINGS
import co.electriccoin.zcash.ui.NavigationTargets.SUPPORT
import co.electriccoin.zcash.ui.NavigationTargets.WALLET_ADDRESS_DETAILS
import co.electriccoin.zcash.ui.history.WrapHistory
import co.electriccoin.zcash.ui.screen.about.WrapAbout
import co.electriccoin.zcash.ui.screen.address.WrapWalletAddresses
import co.electriccoin.zcash.ui.screen.home.WrapHome
@ -44,7 +46,8 @@ internal fun MainActivity.Navigation() {
goScan = { navController.navigateJustOnce(SCAN) },
goProfile = { navController.navigateJustOnce(PROFILE) },
goSend = { navController.navigateJustOnce(SEND) },
goRequest = { navController.navigateJustOnce(REQUEST) }
goRequest = { navController.navigateJustOnce(REQUEST) },
goHistory = { navController.navigateJustOnce(HISTORY) }
)
WrapCheckForUpdate()
@ -108,6 +111,10 @@ internal fun MainActivity.Navigation() {
goBack = { navController.popBackStackJustOnce(SCAN) }
)
}
composable(HISTORY) {
WrapHistory(goBack = { navController.navigateUp() })
}
}
}
@ -152,6 +159,8 @@ object NavigationTargets {
const val REQUEST = "request"
const val HISTORY = "history"
const val SEND = "send"
const val SUPPORT = "support"

View File

@ -0,0 +1,35 @@
package co.electriccoin.zcash.ui.history
import androidx.activity.ComponentActivity
import androidx.activity.viewModels
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import co.electriccoin.zcash.ui.MainActivity
import co.electriccoin.zcash.ui.history.view.History
import co.electriccoin.zcash.ui.screen.home.viewmodel.WalletViewModel
@Composable
internal fun MainActivity.WrapHistory(
goBack: () -> Unit
) {
WrapHistory(
activity = this,
goBack = goBack
)
}
@Composable
internal fun WrapHistory(
activity: ComponentActivity,
goBack: () -> Unit
) {
val walletViewModel by activity.viewModels<WalletViewModel>()
val transactionHistory by walletViewModel.transactionHistory.collectAsState()
History(
transactions = transactionHistory,
goBack = goBack
)
}

View File

@ -0,0 +1,99 @@
package co.electriccoin.zcash.ui.history.view
import android.annotation.SuppressLint
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.sp
import cash.z.ecc.android.sdk.internal.twig
import cash.z.ecc.android.sdk.model.TransactionOverview
import cash.z.ecc.sdk.ext.ui.model.toZecString
import cash.z.ecc.sdk.ext.ui.toFiatString
import cash.z.ecc.sdk.model.CurrencyConversion
import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.design.component.Body
import co.electriccoin.zcash.ui.design.component.GradientSurface
import co.electriccoin.zcash.ui.design.component.Small
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
@Composable
fun ComposablePreview() {
ZcashTheme(darkTheme = true) {
GradientSurface {
History(transactions = listOf(), goBack = {})
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun History(
transactions: List<TransactionOverview>,
goBack: () -> Unit
) {
Scaffold(topBar = {
HistoryTopBar(onBack = goBack)
}) { paddingValues ->
LazyColumn(Modifier.padding(paddingValues)) {
items(transactions) {
TransactionHistoryItem(it)
}
}
}
}
@Composable
fun TransactionHistoryItem(transaction: TransactionOverview) {
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Image(
painter = painterResource(id = co.electriccoin.zcash.ui.design.R.drawable.ic_dollar_currency_symbol),
contentDescription = "")
Column {
Body(text = "sent tx")
Small(text = "description", textAlign = TextAlign.Start)
}
Spacer(modifier = Modifier.weight(0.2f))
Column(horizontalAlignment = Alignment.End) {
Text(text = transaction.netValue.toZecString(), fontSize = 18.sp)
Body(text = transaction.feePaid.toZecString())
}
}
}
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun HistoryTopBar(onBack: () -> Unit) {
TopAppBar(
title = { Text(text = stringResource(id = R.string.about_title)) },
navigationIcon = {
IconButton(
onClick = onBack
) {
Icon(
imageVector = Icons.Filled.ArrowBack,
contentDescription = stringResource(R.string.about_back_content_description)
)
}
}
)
}

View File

@ -24,14 +24,16 @@ internal fun MainActivity.WrapHome(
goScan: () -> Unit,
goProfile: () -> Unit,
goSend: () -> Unit,
goRequest: () -> Unit
goRequest: () -> Unit,
goHistory: () -> Unit,
) {
WrapHome(
this,
goScan = goScan,
goProfile = goProfile,
goSend = goSend,
goRequest = goRequest
goRequest = goRequest,
goHistory = goHistory
)
}
@ -42,7 +44,8 @@ internal fun WrapHome(
goScan: () -> Unit,
goProfile: () -> Unit,
goSend: () -> Unit,
goRequest: () -> Unit
goRequest: () -> Unit,
goHistory: () -> Unit,
) {
// we want to show information about app update, if available
val checkUpdateViewModel by activity.viewModels<CheckUpdateViewModel> {
@ -77,6 +80,7 @@ internal fun WrapHome(
transactionSnapshot,
goScan = goScan,
goRequest = goRequest,
goHistory = goHistory,
goSend = goSend,
goProfile = goProfile,
isDebugMenuEnabled = isDebugMenuEnabled,

View File

@ -72,6 +72,7 @@ fun ComposablePreview() {
goProfile = {},
goSend = {},
goRequest = {},
goHistory = {},
resetSdk = {},
wipeEntireWallet = {},
isDebugMenuEnabled = false,
@ -91,6 +92,7 @@ fun Home(
goProfile: () -> Unit,
goSend: () -> Unit,
goRequest: () -> Unit,
goHistory: () -> Unit,
resetSdk: () -> Unit,
wipeEntireWallet: () -> Unit,
isDebugMenuEnabled: Boolean,
@ -107,6 +109,7 @@ fun Home(
goProfile = goProfile,
goSend = goSend,
goRequest = goRequest,
goHistory = goHistory,
updateAvailable = updateAvailable
)
}
@ -184,6 +187,7 @@ private fun HomeMainContent(
goProfile: () -> Unit,
goSend: () -> Unit,
goRequest: () -> Unit,
goHistory: () -> Unit,
updateAvailable: Boolean
) {
Column(Modifier.verticalScroll(rememberScrollState())) {
@ -219,6 +223,8 @@ private fun HomeMainContent(
TertiaryButton(onClick = goRequest, text = stringResource(R.string.home_button_request))
TertiaryButton(onClick = goHistory, text = stringResource(R.string.home_button_history))
History(transactionHistory)
}
}
@ -295,12 +301,14 @@ private fun Status(
amount = walletDisplayValues.fiatCurrencyAmountText
)
}
is FiatCurrencyConversionRateState.Stale -> {
// Note: we should show information about staleness too
BodyWithFiatCurrencySymbol(
amount = walletDisplayValues.fiatCurrencyAmountText
)
}
is FiatCurrencyConversionRateState.Unavailable -> {
Body(text = walletDisplayValues.fiatCurrencyAmountText)
}

View File

@ -172,6 +172,20 @@ class WalletViewModel(application: Application) : AndroidViewModel(application)
null
)
@OptIn(ExperimentalCoroutinesApi::class)
val transactionHistory = synchronizer
.flatMapLatest {
if (null == it) {
flowOf(emptyList())
} else {
it.toTransactionHistory()
}
}.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT),
emptyList()
)
/**
* Creates a wallet asynchronously and then persists it. Clients observe
* [secretState] to see the side effects. This would be used for a user creating a new wallet.
@ -387,3 +401,6 @@ private fun Synchronizer.toTransactions() =
addAll(pending.map { CommonTransaction.Pending(it) })
}
}
private fun Synchronizer.toTransactionHistory() = clearedTransactions.distinctUntilChanged()

View File

@ -3,6 +3,7 @@
<string name="home_profile_content_description">Profile</string>
<string name="home_button_send">Send</string>
<string name="home_button_request">Request ZEC</string>
<string name="home_button_history">Transaction History</string>
<string name="home_status_syncing_format" formatted="true">Syncing - <xliff:g id="synced_percent" example="50">%1$d</xliff:g>%%</string> <!-- double %% for escaping -->
<string name="home_status_syncing_catchup">Syncing</string>