demo: add initial balance view

This commit is contained in:
Oscar Mira 2023-10-19 17:33:59 +02:00
parent 471f22777c
commit a84375d384
7 changed files with 142 additions and 10 deletions

View File

@ -12,7 +12,7 @@ import kotlinx.coroutines.flow.onStart
sealed interface Result<out T> {
data class Success<T>(val data: T) : Result<T>
data class Error(val exception: Throwable? = null) : Result<Nothing>
object Loading : Result<Nothing>
data object Loading : Result<Nothing>
}
/**

View File

@ -21,16 +21,16 @@ class HomeViewModel(
}
sealed interface HomeUiState {
object Loading : HomeUiState
data object Loading : HomeUiState
// data class Ready(
// val wallets: List<WalletDetails>
// ) : HomeUiState
object Empty : HomeUiState
data object Empty : HomeUiState
}
sealed interface WalletListUiState {
data class Success(val ids: List<Long>) : WalletListUiState
object Loading : WalletListUiState
data object Loading : WalletListUiState
}

View File

@ -98,5 +98,5 @@ sealed interface SettingsUiState {
val remoteNodes: List<RemoteNode>,
) : SettingsUiState
object Loading : SettingsUiState
data object Loading : SettingsUiState
}

View File

@ -0,0 +1,127 @@
package im.molly.monero.demo.ui
import androidx.compose.foundation.layout.Arrangement
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.Divider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import im.molly.monero.MoneroAmount
import im.molly.monero.Balance
import im.molly.monero.BlockchainTime
import im.molly.monero.MoneroCurrency
import im.molly.monero.TimeLocked
import im.molly.monero.demo.ui.theme.AppTheme
import im.molly.monero.xmr
import kotlinx.coroutines.delay
import java.math.BigDecimal
import java.time.Duration
import java.time.Instant
import kotlin.time.Duration.Companion.seconds
import kotlin.time.toKotlinDuration
@Composable
fun WalletBalanceView(
balance: Balance,
blockchainTime: BlockchainTime,
modifier: Modifier = Modifier,
) {
var now by remember { mutableStateOf(Instant.now()) }
LaunchedEffect(now) {
delay(1.seconds)
now = Instant.now()
}
Column(
modifier = modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text(
style = MaterialTheme.typography.headlineSmall,
text = "Balance at Block #${blockchainTime.height}",
)
BalanceRow("Confirmed", balance.confirmedAmount)
BalanceRow("Pending", balance.pendingAmount)
Divider()
BalanceRow("Total", balance.totalAmount)
BalanceRow("Unlocked", balance.unlockedAmountAt(blockchainTime.height, now))
balance.lockedAmountsAt(blockchainTime.height, now).forEach { (timeSpan, amount) ->
LockedBalanceRow("Locked", amount, timeSpan.blocks, timeSpan.timeRemaining)
}
}
}
@Composable
fun BalanceRow(
label: String,
amount: MoneroAmount,
format: MoneroCurrency.Format = MoneroCurrency.Format(),
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp),
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text(text = label)
Text(text = format.format(amount))
}
}
@Composable
fun LockedBalanceRow(
label: String,
amount: MoneroAmount,
blockCount: Int,
timeRemaining: Duration,
moneroFormat: MoneroCurrency.Format = MoneroCurrency.DefaultFormat,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp),
horizontalArrangement = Arrangement.SpaceBetween,
) {
val durationText =
"${timeRemaining.toKotlinDuration()} ($blockCount blocks)"
Column {
Text(text = label)
Text(text = durationText, fontSize = 12.sp)
}
Text(text = moneroFormat.format(amount))
}
}
@Preview
@Composable
fun WalletBalanceDetailsPreview() {
AppTheme {
WalletBalanceView(
balance = Balance(
pendingAmount = 5.xmr,
timeLockedAmounts = listOf(
TimeLocked(10.xmr, BlockchainTime.Genesis),
TimeLocked(BigDecimal("0.000000000001").xmr, BlockchainTime.Block(10)),
TimeLocked(30.xmr, BlockchainTime.Block(500)),
),
),
blockchainTime = BlockchainTime.Genesis,
)
}
}

View File

@ -113,11 +113,16 @@ private fun WalletScreenPopulated(
text = buildAnnotatedString {
append(MoneroCurrency.SYMBOL + " ")
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
append(MoneroCurrency.Formatter(precision = 5).format(ledger.balance.confirmedAmount))
append(MoneroCurrency.Format(precision = 5).format(ledger.balance.confirmedAmount))
}
}
)
Text(text = walletConfig.name, style = MaterialTheme.typography.headlineSmall)
WalletBalanceView(
balance = ledger.balance,
blockchainTime = ledger.checkedAt,
)
}
if (showRenameDialog) {

View File

@ -71,6 +71,6 @@ sealed interface WalletUiState {
val ledger: Ledger,
) : WalletUiState
object Error : WalletUiState
object Loading : WalletUiState
data object Error : WalletUiState
data object Loading : WalletUiState
}

View File

@ -8,9 +8,9 @@ object MoneroCurrency {
const val MAX_PRECISION = MoneroAmount.ATOMIC_UNIT_SCALE
val DefaultFormatter = Formatter()
val DefaultFormat = Format()
data class Formatter(
data class Format(
val precision: Int = MAX_PRECISION,
val locale: Locale = Locale.US,
) {