forked from hush/SilentDragonAndroid
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
5.6 KiB
147 lines
5.6 KiB
package cash.z.ecc.android.ui.home
|
|
|
|
import androidx.lifecycle.ViewModel
|
|
import cash.z.ecc.android.di.DependenciesHolder
|
|
import cash.z.ecc.android.lockbox.LockBox
|
|
import cash.z.ecc.android.sdk.Synchronizer
|
|
import cash.z.ecc.android.sdk.block.CompactBlockProcessor
|
|
import cash.z.ecc.android.sdk.db.entity.PendingTransaction
|
|
import cash.z.ecc.android.sdk.db.entity.isMined
|
|
import cash.z.ecc.android.sdk.db.entity.isSubmitSuccess
|
|
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
|
import cash.z.ecc.android.sdk.ext.convertZatoshiToZecString
|
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
|
import cash.z.ecc.android.sdk.model.WalletBalance
|
|
import cash.z.ecc.android.sdk.model.Zatoshi
|
|
import kotlinx.coroutines.flow.Flow
|
|
import kotlinx.coroutines.flow.combineTransform
|
|
|
|
class BalanceDetailViewModel : ViewModel() {
|
|
|
|
private val synchronizer: Synchronizer = DependenciesHolder.synchronizer
|
|
|
|
private val lockBox: LockBox = DependenciesHolder.lockBox
|
|
|
|
var showAvailable: Boolean = true
|
|
set(value) {
|
|
field = value
|
|
latestBalance?.showAvailable = value
|
|
}
|
|
|
|
var latestBalance: BalanceModel? = null
|
|
|
|
val balances: Flow<BalanceModel>
|
|
get() = combineTransform(
|
|
synchronizer.saplingBalances,
|
|
synchronizer.transparentBalances
|
|
) { saplingBalance, transparentBalance ->
|
|
BalanceModel(saplingBalance, transparentBalance, showAvailable).let {
|
|
latestBalance = it
|
|
emit(it)
|
|
}
|
|
}
|
|
|
|
val statuses: Flow<StatusModel>
|
|
get() = combineTransform(
|
|
balances,
|
|
synchronizer.pendingTransactions,
|
|
synchronizer.processorInfo
|
|
) { balances, pending, info ->
|
|
emit(StatusModel(balances, pending, info))
|
|
}
|
|
|
|
data class BalanceModel(
|
|
val shieldedBalance: WalletBalance?,
|
|
val transparentBalance: WalletBalance?,
|
|
var showAvailable: Boolean = false
|
|
) {
|
|
/** Whether to make calculations based on total or available zatoshi */
|
|
|
|
val canAutoShield: Boolean =
|
|
(transparentBalance?.available?.value ?: 0L) > ZcashSdk.MINERS_FEE.value
|
|
|
|
val balanceShielded: String
|
|
get() {
|
|
return if (showAvailable) shieldedBalance?.available.toDisplay()
|
|
else shieldedBalance?.total.toDisplay()
|
|
}
|
|
|
|
val balanceTransparent: String
|
|
get() {
|
|
return if (showAvailable) transparentBalance?.available.toDisplay()
|
|
else transparentBalance?.total.toDisplay()
|
|
}
|
|
|
|
val balanceTotal: String
|
|
get() {
|
|
return if (showAvailable) ((shieldedBalance?.available
|
|
?: Zatoshi(0)) + (transparentBalance?.available ?: Zatoshi(0))).toDisplay()
|
|
else ((shieldedBalance?.total ?: Zatoshi(0)) + (transparentBalance?.total
|
|
?: Zatoshi(0))).toDisplay()
|
|
}
|
|
|
|
val paddedShielded get() = pad(balanceShielded)
|
|
val paddedTransparent get() = pad(balanceTransparent)
|
|
val paddedTotal get() = pad(balanceTotal)
|
|
val maxLength
|
|
get() = maxOf(
|
|
balanceShielded.length,
|
|
balanceTransparent.length,
|
|
balanceTotal.length
|
|
)
|
|
val hasPending =
|
|
(null != shieldedBalance && shieldedBalance.available != shieldedBalance.total) ||
|
|
(null != transparentBalance && transparentBalance.available != transparentBalance.total)
|
|
|
|
private fun Zatoshi?.toDisplay(): String {
|
|
return this?.convertZatoshiToZecString(8, 8) ?: "0"
|
|
}
|
|
|
|
private fun pad(balance: String): String {
|
|
var diffLength = maxLength - balance.length
|
|
return buildString {
|
|
repeat(diffLength) {
|
|
append(' ')
|
|
}
|
|
append(balance)
|
|
}
|
|
}
|
|
|
|
fun hasData(): Boolean {
|
|
return shieldedBalance != null || transparentBalance != null
|
|
}
|
|
}
|
|
|
|
data class StatusModel(
|
|
val balances: BalanceModel,
|
|
val pending: List<PendingTransaction>,
|
|
val info: CompactBlockProcessor.ProcessorInfo,
|
|
) {
|
|
val pendingUnconfirmed =
|
|
pending.filter { it.isSubmitSuccess() && it.isMined() && !it.isConfirmed(info.lastScannedHeight) }
|
|
val pendingUnmined = pending.filter { it.isSubmitSuccess() && !it.isMined() }
|
|
val pendingShieldedBalance = balances.shieldedBalance?.pending
|
|
val pendingTransparentBalance = balances.transparentBalance?.pending
|
|
val hasUnconfirmed = pendingUnconfirmed.isNotEmpty()
|
|
val hasUnmined = pendingUnmined.isNotEmpty()
|
|
val hasPendingShieldedBalance = (pendingShieldedBalance?.value ?: 0L) > 0L
|
|
val hasPendingTransparentBalance = (pendingTransparentBalance?.value ?: 0L) > 0L
|
|
val missingBlocks = ((info.networkBlockHeight?.value ?: 0) - (info.lastScannedHeight?.value
|
|
?: 0)).coerceAtLeast(0)
|
|
|
|
private fun PendingTransaction.isConfirmed(networkBlockHeight: BlockHeight?): Boolean {
|
|
return networkBlockHeight?.let {
|
|
isMined() && (it.value - minedHeight + 1) > 10 // fix: plus 1 because the mined block counts as the FIRST confirmation
|
|
} ?: false
|
|
}
|
|
|
|
fun remainingConfirmations(confirmationsRequired: Int = 10) =
|
|
pendingUnconfirmed
|
|
.map {
|
|
confirmationsRequired - ((info.lastScannedHeight?.value
|
|
?: -1) - it.minedHeight + 1)
|
|
} // fix: plus 1 because the mined block counts as the FIRST confirmation
|
|
.filter { it > 0 }
|
|
.sortedDescending()
|
|
}
|
|
}
|
|
|