mirror of
https://github.com/mollyim/monero-wallet-sdk.git
synced 2024-12-24 23:19:23 -05:00
demo: minor UI improvements
This commit is contained in:
parent
21e8c77e26
commit
894788f3b2
@ -1,6 +1,7 @@
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
@ -9,6 +10,7 @@ import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
@ -17,6 +19,10 @@ import im.molly.monero.MoneroCurrency
|
||||
import im.molly.monero.Transaction
|
||||
import im.molly.monero.demo.ui.preview.PreviewParameterData
|
||||
import im.molly.monero.demo.ui.theme.AppTheme
|
||||
import im.molly.monero.demo.ui.theme.Blue40
|
||||
import im.molly.monero.demo.ui.theme.Red40
|
||||
import java.time.ZoneId
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@ -25,29 +31,47 @@ fun TransactionCardExpanded(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
|
||||
|
||||
Card(
|
||||
onClick = onClick,
|
||||
modifier = modifier.padding(top = 8.dp, start = 8.dp, end = 8.dp)
|
||||
modifier = modifier.padding(top = 8.dp, start = 8.dp, end = 8.dp),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(12.dp),
|
||||
modifier = Modifier.padding(14.dp)
|
||||
) {
|
||||
TransactionDetail("State", transaction.state.toString())
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
TransactionDetail("Sent", transaction.sent.toString())
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
TransactionDetail("Received", transaction.received.toString())
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
TransactionDetail("Payments", transaction.payments.toString())
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
TransactionDetail("Time lock", transaction.timeLock.toString())
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
TransactionDetail("Change", MoneroCurrency.format(transaction.change))
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
TransactionDetail("Fee", MoneroCurrency.format(transaction.fee))
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
TransactionDetail("Transaction ID", transaction.txId)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
) {
|
||||
val timestamp = transaction.timestamp?.let {
|
||||
val localDateTime = it.atZone(ZoneId.systemDefault()).toLocalDateTime()
|
||||
localDateTime.format(formatter)
|
||||
}
|
||||
Text(
|
||||
text = timestamp ?: "",
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
)
|
||||
Text(
|
||||
text = MoneroCurrency.format(transaction.amount, precision = 5),
|
||||
color = if (transaction.amount < 0) Red40 else Blue40,
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
}
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
) {
|
||||
Text(
|
||||
text = "#${transaction.blockHeight}",
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
)
|
||||
Text(
|
||||
text = "fee ${MoneroCurrency.format(transaction.fee, precision = 8)}",
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -82,6 +106,7 @@ private fun TransactionCardExpandedPreview(
|
||||
}
|
||||
}
|
||||
|
||||
private class TransactionCardPreviewParameterProvider : PreviewParameterProvider<List<Transaction>> {
|
||||
private class TransactionCardPreviewParameterProvider :
|
||||
PreviewParameterProvider<List<Transaction>> {
|
||||
override val values = sequenceOf(PreviewParameterData.transactions)
|
||||
}
|
||||
|
@ -80,6 +80,8 @@ private fun TransactionScreen(
|
||||
val tx = uiState.transaction
|
||||
TransactionDetail("State", tx.state.toString())
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
TransactionDetail("Amount", MoneroCurrency.format(tx.amount))
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
TransactionDetail("Sent", tx.sent.toString())
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
TransactionDetail("Received", tx.received.toString())
|
||||
|
@ -2,6 +2,7 @@ package im.molly.monero.demo.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
@ -33,17 +34,16 @@ fun WalletCard(
|
||||
val uiState: WalletUiState by viewModel.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
Card(
|
||||
onClick = onClick, modifier = modifier.padding(8.dp)
|
||||
onClick = onClick,
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 8.dp, start = 8.dp, end = 8.dp),
|
||||
) {
|
||||
Column {
|
||||
Column(
|
||||
modifier = Modifier.padding(14.dp),
|
||||
) {
|
||||
when (uiState) {
|
||||
is WalletUiState.Loaded -> {
|
||||
WalletCardExpanded(
|
||||
(uiState as WalletUiState.Loaded).config,
|
||||
(uiState as WalletUiState.Loaded).balance,
|
||||
)
|
||||
}
|
||||
|
||||
is WalletUiState.Loaded -> WalletCardExpanded(uiState as WalletUiState.Loaded)
|
||||
WalletUiState.Error -> WalletCardError()
|
||||
WalletUiState.Loading -> WalletCardLoading()
|
||||
}
|
||||
@ -53,14 +53,13 @@ fun WalletCard(
|
||||
|
||||
@Composable
|
||||
fun WalletCardExpanded(
|
||||
config: WalletConfig,
|
||||
balance: Balance,
|
||||
uiState: WalletUiState.Loaded,
|
||||
) {
|
||||
Row {
|
||||
Text(text = "Name: ${config.name}")
|
||||
Text(text = "Wallet ID #${uiState.config.id} (${uiState.config.name}) ${uiState.config.publicAddress}")
|
||||
}
|
||||
Row {
|
||||
Text(text = "Ledger: $balance")
|
||||
Text(text = uiState.blockchainTime.toString())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,7 @@ private fun WalletScreenLoaded(
|
||||
.padding(padding),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(style = MaterialTheme.typography.headlineLarge, text = buildAnnotatedString {
|
||||
Text(style = MaterialTheme.typography.headlineMedium, text = buildAnnotatedString {
|
||||
append(MoneroCurrency.SYMBOL + " ")
|
||||
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
|
||||
append(
|
||||
|
@ -62,7 +62,9 @@ private fun walletUiState(
|
||||
val balance = ledger.balance
|
||||
val blockchainTime = ledger.checkedAt
|
||||
val transactions =
|
||||
ledger.transactions.map { WalletTransaction(config.id, it.value) }
|
||||
ledger.transactions
|
||||
.map { WalletTransaction(config.id, it.value) }
|
||||
.sortedByDescending { it.transaction.timestamp }
|
||||
WalletUiState.Loaded(config, blockchainTime, balance, transactions)
|
||||
}
|
||||
|
||||
|
@ -8,4 +8,6 @@ val Pink80 = Color(0xFFEFB8C8)
|
||||
|
||||
val Purple40 = Color(0xFF6650a4)
|
||||
val PurpleGrey40 = Color(0xFF625b71)
|
||||
val Pink40 = Color(0xFF7D5260)
|
||||
val Pink40 = Color(0xFF7D5260)
|
||||
val Red40 = Color(0xFFBA1B1B)
|
||||
val Blue40 = Color(0xFF1546F6)
|
||||
|
@ -23,4 +23,16 @@ class Enote(
|
||||
override fun hashCode() = System.identityHashCode(this)
|
||||
|
||||
override fun equals(other: Any?) = this === other
|
||||
|
||||
override fun toString(): String {
|
||||
return "Enote(" +
|
||||
"amount=${amount.xmr}" +
|
||||
", age=$age" +
|
||||
", spent=$spent" +
|
||||
", owner=$owner" +
|
||||
", key=$key" +
|
||||
", keyImage=$keyImage" +
|
||||
", sourceTxId=$sourceTxId" +
|
||||
")"
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package im.molly.monero
|
||||
|
||||
import java.text.NumberFormat
|
||||
import java.util.Locale
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
object MoneroCurrency {
|
||||
const val SYMBOL = "XMR"
|
||||
@ -33,7 +34,11 @@ object MoneroCurrency {
|
||||
|
||||
val ExactFormat = object : Format(MoneroAmount.ATOMIC_UNIT_SCALE) {
|
||||
override fun format(amount: MoneroAmount) = buildString {
|
||||
val num = amount.atomicUnits.toString()
|
||||
if (amount.atomicUnits < 0) {
|
||||
append('-')
|
||||
}
|
||||
|
||||
val num = amount.atomicUnits.absoluteValue.toString()
|
||||
|
||||
if (precision < num.length) {
|
||||
val point = num.length - precision
|
||||
@ -50,8 +55,11 @@ object MoneroCurrency {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun format(amount: MoneroAmount, outputFormat: Format = ExactFormat): String {
|
||||
return outputFormat.format(amount)
|
||||
}
|
||||
|
||||
fun format(amount: MoneroAmount, precision: Int): String {
|
||||
return Format(precision = precision).format(amount)
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ class MoneroWallet internal constructor(
|
||||
|
||||
private fun sendLedger(ledger: Ledger) {
|
||||
trySend(ledger).onFailure {
|
||||
logger.e("Too many ledger updates, channel capacity exceeded")
|
||||
logger.e("Too many ledger updates, channel capacity exceeded", it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,4 +5,6 @@ value class PublicKey(private val publicKey: String) {
|
||||
init {
|
||||
require(publicKey.length == 64) { "Public key length must be 64 bytes" }
|
||||
}
|
||||
|
||||
override fun toString(): String = publicKey
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package im.molly.monero
|
||||
|
||||
import java.time.Instant
|
||||
|
||||
data class Transaction(
|
||||
val hash: HashDigest,
|
||||
// TODO: val version: ProtocolInfo,
|
||||
@ -11,11 +13,16 @@ data class Transaction(
|
||||
val fee: MoneroAmount,
|
||||
val change: MoneroAmount,
|
||||
) {
|
||||
val amount: MoneroAmount = received.sumOf { it.amount } - sent.sumOf { it.amount }
|
||||
|
||||
val txId: String
|
||||
get() = hash.toString()
|
||||
|
||||
val blockHeight: Int?
|
||||
get() = (state as? TxState.OnChain)?.blockHeader?.height
|
||||
|
||||
val timestamp: Instant?
|
||||
get() = (state as? TxState.OnChain)?.let { Instant.ofEpochSecond(it.blockHeader.epochSecond) }
|
||||
}
|
||||
|
||||
sealed interface TxState {
|
||||
|
Loading…
Reference in New Issue
Block a user