Balance actions bugfixes
This commit is contained in:
parent
64af1a3d50
commit
2fe90bcc43
|
@ -25,29 +25,46 @@ sealed interface WalletAccount : Comparable<WalletAccount> {
|
|||
val hdAccountIndex: Zip32AccountIndex
|
||||
get() = sdkAccount.hdAccountIndex!!
|
||||
|
||||
/**
|
||||
* Total transparent + total shielded balance.
|
||||
*/
|
||||
val totalBalance: Zatoshi
|
||||
|
||||
/**
|
||||
* Total shielded balance including non-spendable.
|
||||
*/
|
||||
val totalShieldedBalance: Zatoshi
|
||||
val spendableBalance: Zatoshi
|
||||
val changePendingBalance: Zatoshi
|
||||
val valuePendingBalance: Zatoshi
|
||||
|
||||
val pendingBalance: Zatoshi
|
||||
get() = changePendingBalance + valuePendingBalance
|
||||
/**
|
||||
* Total spendable transparent balance.
|
||||
*/
|
||||
val totalTransparentBalance: Zatoshi
|
||||
|
||||
val hasChangePending: Boolean
|
||||
val hasValuePending: Boolean
|
||||
val isPending: Boolean
|
||||
get() = pendingBalance > Zatoshi(0)
|
||||
/**
|
||||
* Spendable & available shielded balance. Might be smaller than total shielded balance.
|
||||
*/
|
||||
val spendableShieldedBalance: Zatoshi
|
||||
|
||||
fun canSpend(amount: Zatoshi): Boolean = spendableBalance >= amount
|
||||
/**
|
||||
* Pending shielded Balance.
|
||||
*/
|
||||
val pendingShieldedBalance: Zatoshi
|
||||
|
||||
fun isProcessingZeroAvailableBalance(): Boolean {
|
||||
if (totalShieldedBalance == Zatoshi(0) && transparent.balance > Zatoshi(0)) {
|
||||
return false
|
||||
val isShieldedPending: Boolean
|
||||
get() = pendingShieldedBalance > Zatoshi(0)
|
||||
|
||||
val isShieldingAvailable: Boolean
|
||||
get() = totalTransparentBalance > Zatoshi(100000L)
|
||||
|
||||
val isProcessingZeroSpendableBalance: Boolean
|
||||
get() {
|
||||
if (totalShieldedBalance == Zatoshi(0) && totalTransparentBalance > Zatoshi(0)) {
|
||||
return false
|
||||
}
|
||||
return totalBalance > Zatoshi(0) && totalShieldedBalance == Zatoshi(0)
|
||||
}
|
||||
|
||||
return totalBalance != totalShieldedBalance && totalShieldedBalance == Zatoshi(0)
|
||||
}
|
||||
fun canSpend(amount: Zatoshi): Boolean = spendableShieldedBalance >= amount
|
||||
}
|
||||
|
||||
data class ZashiAccount(
|
||||
|
@ -59,22 +76,28 @@ data class ZashiAccount(
|
|||
) : WalletAccount {
|
||||
override val name: StringResource
|
||||
get() = stringRes(co.electriccoin.zcash.ui.R.string.zashi_wallet_name)
|
||||
|
||||
override val icon: Int
|
||||
get() = R.drawable.ic_item_zashi
|
||||
|
||||
override val totalBalance: Zatoshi
|
||||
get() = unified.balance.total + sapling.balance.total + transparent.balance
|
||||
|
||||
override val totalShieldedBalance: Zatoshi
|
||||
get() = unified.balance.total + sapling.balance.total
|
||||
override val spendableBalance: Zatoshi
|
||||
|
||||
override val totalTransparentBalance: Zatoshi
|
||||
get() = transparent.balance
|
||||
|
||||
override val spendableShieldedBalance: Zatoshi
|
||||
get() = unified.balance.available + sapling.balance.available
|
||||
override val changePendingBalance: Zatoshi
|
||||
get() = unified.balance.changePending + sapling.balance.changePending
|
||||
override val valuePendingBalance: Zatoshi
|
||||
get() = unified.balance.valuePending + sapling.balance.valuePending
|
||||
override val hasChangePending: Boolean
|
||||
get() = changePendingBalance.value > 0L
|
||||
override val hasValuePending: Boolean
|
||||
get() = valuePendingBalance.value > 0L
|
||||
|
||||
override val pendingShieldedBalance: Zatoshi
|
||||
get() {
|
||||
val changePendingShieldedBalance = unified.balance.changePending + sapling.balance.changePending
|
||||
val valuePendingShieldedBalance = unified.balance.valuePending + sapling.balance.valuePending
|
||||
return changePendingShieldedBalance + valuePendingShieldedBalance
|
||||
}
|
||||
|
||||
override fun compareTo(other: WalletAccount) =
|
||||
when (other) {
|
||||
|
@ -91,23 +114,26 @@ data class KeystoneAccount(
|
|||
) : WalletAccount {
|
||||
override val icon: Int
|
||||
get() = R.drawable.ic_item_keystone
|
||||
|
||||
override val name: StringResource
|
||||
get() = stringRes(co.electriccoin.zcash.ui.R.string.keystone_wallet_name)
|
||||
|
||||
override val sapling: SaplingInfo? = null
|
||||
|
||||
override val totalBalance: Zatoshi
|
||||
get() = unified.balance.total + transparent.balance
|
||||
|
||||
override val totalShieldedBalance: Zatoshi
|
||||
get() = unified.balance.total
|
||||
override val spendableBalance: Zatoshi
|
||||
|
||||
override val totalTransparentBalance: Zatoshi
|
||||
get() = transparent.balance
|
||||
|
||||
override val spendableShieldedBalance: Zatoshi
|
||||
get() = unified.balance.available
|
||||
override val changePendingBalance: Zatoshi
|
||||
get() = unified.balance.changePending
|
||||
override val valuePendingBalance: Zatoshi
|
||||
get() = unified.balance.valuePending
|
||||
override val hasChangePending: Boolean
|
||||
get() = changePendingBalance.value > 0L
|
||||
override val hasValuePending: Boolean
|
||||
get() = valuePendingBalance.value > 0L
|
||||
|
||||
override val pendingShieldedBalance: Zatoshi
|
||||
get() = unified.balance.changePending + unified.balance.valuePending
|
||||
|
||||
override fun compareTo(other: WalletAccount) =
|
||||
when (other) {
|
||||
|
@ -124,10 +150,7 @@ data class UnifiedInfo(
|
|||
data class TransparentInfo(
|
||||
val address: WalletAddress.Transparent,
|
||||
val balance: Zatoshi
|
||||
) {
|
||||
val isShieldingAvailable: Boolean
|
||||
get() = balance > Zatoshi(100000L)
|
||||
}
|
||||
)
|
||||
|
||||
data class SaplingInfo(
|
||||
val address: WalletAddress.Sapling,
|
||||
|
|
|
@ -42,7 +42,7 @@ class FlexaRepositoryImpl(
|
|||
Twig.info { "Flexa initialized" }
|
||||
|
||||
observeZashiAccountUseCase()
|
||||
.map { it?.totalShieldedBalance to it?.spendableBalance }
|
||||
.map { it?.totalShieldedBalance to it?.spendableShieldedBalance }
|
||||
.collect { (total, available) ->
|
||||
val totalZec = total.convertZatoshiToZec().toDouble()
|
||||
val availableZec = available.convertZatoshiToZec().toDouble()
|
||||
|
|
|
@ -29,7 +29,7 @@ class ShieldFundsRepositoryImpl(
|
|||
account == null ->
|
||||
flowOf(ShieldFundsData.Unavailable)
|
||||
|
||||
account.transparent.isShieldingAvailable ->
|
||||
account.isShieldingAvailable ->
|
||||
shieldFundsDataSource.observe(account.sdkAccount.accountUuid).map {
|
||||
when (it) {
|
||||
is ShieldFundsAvailability.Available -> ShieldFundsData.Available(
|
||||
|
|
|
@ -40,17 +40,15 @@ class BalanceWidgetViewModel(
|
|||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
private fun createState(account: WalletAccount?, exchangeRateUsd: ExchangeRateState): BalanceWidgetState {
|
||||
return BalanceWidgetState(
|
||||
private fun createState(account: WalletAccount?, exchangeRateUsd: ExchangeRateState) =
|
||||
BalanceWidgetState(
|
||||
totalBalance = account?.totalBalance ?: Zatoshi(0),
|
||||
exchangeRate = if (args.isExchangeRateButtonEnabled) exchangeRateUsd else null,
|
||||
button = when {
|
||||
!args.isBalanceButtonEnabled -> null
|
||||
account == null -> null
|
||||
account.totalBalance == account.spendableBalance -> null
|
||||
account.isProcessingZeroAvailableBalance() && !account.isPending ->
|
||||
account.totalBalance == account.spendableShieldedBalance -> null
|
||||
account.totalBalance > account.spendableShieldedBalance && account.isShieldedPending ->
|
||||
BalanceButtonState(
|
||||
icon = R.drawable.ic_balances_expand,
|
||||
text = stringRes(R.string.widget_balances_button_spendable),
|
||||
|
@ -58,10 +56,10 @@ class BalanceWidgetViewModel(
|
|||
onClick = ::onBalanceButtonClick
|
||||
)
|
||||
|
||||
account.totalBalance > account.spendableBalance -> BalanceButtonState(
|
||||
account.totalBalance > account.spendableShieldedBalance -> BalanceButtonState(
|
||||
icon = R.drawable.ic_balances_expand,
|
||||
text = stringRes(R.string.widget_balances_button_spendable),
|
||||
amount = account.spendableBalance,
|
||||
amount = account.spendableShieldedBalance,
|
||||
onClick = ::onBalanceButtonClick
|
||||
)
|
||||
|
||||
|
@ -69,7 +67,6 @@ class BalanceWidgetViewModel(
|
|||
},
|
||||
showDust = args.showDust
|
||||
)
|
||||
}
|
||||
|
||||
private fun onBalanceButtonClick() = navigationRouter.forward(BalanceAction)
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
import co.electriccoin.zcash.ui.R
|
||||
|
@ -62,10 +63,12 @@ fun BottomSheetContent(state: BalanceActionState, modifier: Modifier = Modifier)
|
|||
.padding(horizontal = 24.dp)
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = state.title.getValue(),
|
||||
color = ZashiColors.Text.textPrimary,
|
||||
style = ZashiTypography.textXl,
|
||||
fontWeight = FontWeight.SemiBold
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Spacer(12.dp)
|
||||
Text(
|
||||
|
@ -80,8 +83,8 @@ fun BottomSheetContent(state: BalanceActionState, modifier: Modifier = Modifier)
|
|||
}
|
||||
BalanceActionRow(state)
|
||||
}
|
||||
Spacer(32.dp)
|
||||
state.shieldButton?.let {
|
||||
Spacer(32.dp)
|
||||
BalanceShieldButton(it)
|
||||
}
|
||||
Spacer(32.dp)
|
||||
|
|
|
@ -37,7 +37,7 @@ class BalanceActionViewModel(
|
|||
if (account == null) return null
|
||||
|
||||
return BalanceActionState(
|
||||
title = stringRes("Spendable Balance"),
|
||||
title = stringRes(R.string.balance_action_title),
|
||||
message = createMessage(account),
|
||||
positive = createPositiveButton(account),
|
||||
onBack = ::onBack,
|
||||
|
@ -48,50 +48,58 @@ class BalanceActionViewModel(
|
|||
|
||||
private fun createMessage(account: WalletAccount): StringResource {
|
||||
val pending = when {
|
||||
account.totalBalance == account.spendableBalance && !account.isPending ->
|
||||
stringRes("All your funds are shielded and spendable.")
|
||||
account.totalShieldedBalance == account.spendableShieldedBalance ->
|
||||
stringRes(R.string.balance_action_all_shielded)
|
||||
|
||||
account.totalShieldedBalance > account.spendableShieldedBalance ->
|
||||
stringRes(R.string.balance_action_pending)
|
||||
|
||||
account.isPending || account.isProcessingZeroAvailableBalance() ->
|
||||
stringRes("Pending transactions are getting mined and confirmed.")
|
||||
else -> null
|
||||
}
|
||||
|
||||
val shielding =
|
||||
stringRes("Shield your transparent ZEC to make it spendable and private. Shielding transparent funds will create a shielding in-wallet transaction, consolidating your transparent and shielded funds. (Typical fee: .001 ZEC)")
|
||||
.takeIf { account.transparent.isShieldingAvailable }
|
||||
val shielding = stringRes(R.string.balance_action_shield_message).takeIf { account.isShieldingAvailable }
|
||||
|
||||
return if (pending != null && shielding != null) {
|
||||
pending + stringRes("\n\n") + shielding
|
||||
} else {
|
||||
listOfNotNull(pending, shielding).reduceOrNull { acc, stringResource -> acc + stringResource } ?: stringRes(
|
||||
""
|
||||
)
|
||||
pending ?: shielding ?: stringRes("")
|
||||
}
|
||||
}
|
||||
|
||||
private fun createPositiveButton(account: WalletAccount) = ButtonState(
|
||||
text = if (account.transparent.isShieldingAvailable) stringRes("Dismiss") else stringRes("Ok"),
|
||||
text = if (account.isShieldingAvailable) {
|
||||
stringRes(R.string.general_dismiss)
|
||||
} else {
|
||||
stringRes(R.string.general_ok)
|
||||
},
|
||||
onClick = ::onBack
|
||||
)
|
||||
|
||||
private fun createInfoRows(account: WalletAccount) = listOfNotNull(
|
||||
BalanceActionRowState(
|
||||
title = stringRes("Shielded ZEC (Spendable)"),
|
||||
title = stringRes(R.string.balance_action_info_shielded),
|
||||
icon = imageRes(R.drawable.ic_balance_shield),
|
||||
value = stringRes(R.string.general_zec, stringRes(account.spendableBalance))
|
||||
value = stringRes(R.string.general_zec, stringRes(account.spendableShieldedBalance))
|
||||
),
|
||||
if (!account.isProcessingZeroAvailableBalance()) {
|
||||
BalanceActionRowState(
|
||||
title = stringRes("Pending"),
|
||||
icon = loadingImageRes(),
|
||||
value = stringRes(R.string.general_zec, stringRes(account.totalBalance))
|
||||
)
|
||||
} else {
|
||||
BalanceActionRowState(
|
||||
title = stringRes("Pending"),
|
||||
icon = loadingImageRes(),
|
||||
value = stringRes(R.string.general_zec, stringRes(account.pendingBalance))
|
||||
).takeIf { account.isPending }
|
||||
when {
|
||||
account.totalShieldedBalance > account.spendableShieldedBalance && account.isShieldedPending ->
|
||||
BalanceActionRowState(
|
||||
title = stringRes(R.string.balance_action_info_pending),
|
||||
icon = loadingImageRes(),
|
||||
value = stringRes(R.string.general_zec, stringRes(account.pendingShieldedBalance))
|
||||
)
|
||||
|
||||
account.totalShieldedBalance > account.spendableShieldedBalance ->
|
||||
BalanceActionRowState(
|
||||
title = stringRes(R.string.balance_action_info_pending),
|
||||
icon = loadingImageRes(),
|
||||
value = stringRes(
|
||||
R.string.general_zec,
|
||||
stringRes(account.totalShieldedBalance - account.spendableShieldedBalance)
|
||||
)
|
||||
)
|
||||
|
||||
else -> null
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -99,7 +107,7 @@ class BalanceActionViewModel(
|
|||
return BalanceShieldButtonState(
|
||||
amount = account.transparent.balance,
|
||||
onShieldClick = ::onShieldClick
|
||||
).takeIf { account.transparent.isShieldingAvailable }
|
||||
).takeIf { account.isShieldingAvailable }
|
||||
}
|
||||
|
||||
private fun onBack() = navigationRouter.back()
|
||||
|
|
|
@ -5,8 +5,6 @@ package co.electriccoin.zcash.ui.screen.restore.seed
|
|||
*/
|
||||
object RestoreSeedTag {
|
||||
const val SEED_WORD_TEXT_FIELD = "seed_text_field"
|
||||
const val BIRTHDAY_TEXT_FIELD = "birthday_text_field"
|
||||
const val CHIP_LAYOUT = "chip_group"
|
||||
const val AUTOCOMPLETE_LAYOUT = "autocomplete_layout"
|
||||
const val AUTOCOMPLETE_ITEM = "autocomplete_item"
|
||||
}
|
||||
|
|
|
@ -331,7 +331,7 @@ private fun SendForm(
|
|||
recipientAddressState.type is AddressType.Valid &&
|
||||
recipientAddressState.type !is AddressType.Transparent &&
|
||||
recipientAddressState.type !is AddressType.Tex
|
||||
)
|
||||
)
|
||||
|
||||
SendFormAmountTextField(
|
||||
amountState = amountState,
|
||||
|
@ -430,10 +430,13 @@ fun SendButton(
|
|||
|
||||
AddressType.Tex ->
|
||||
WalletAddress.Tex.new(recipientAddressState.address)
|
||||
|
||||
AddressType.Transparent ->
|
||||
WalletAddress.Transparent.new(recipientAddressState.address)
|
||||
|
||||
AddressType.Unified ->
|
||||
WalletAddress.Unified.new(recipientAddressState.address)
|
||||
|
||||
null -> WalletAddress.Unified.new(recipientAddressState.address)
|
||||
}
|
||||
)
|
||||
|
@ -604,7 +607,7 @@ fun SendFormAmountTextField(
|
|||
}
|
||||
|
||||
is AmountState.Valid -> {
|
||||
if (selectedAccount.spendableBalance < amountState.zatoshi) {
|
||||
if (selectedAccount.spendableShieldedBalance < amountState.zatoshi) {
|
||||
stringResource(id = R.string.send_amount_insufficient_balance)
|
||||
} else {
|
||||
null
|
||||
|
@ -630,7 +633,9 @@ fun SendFormAmountTextField(
|
|||
|
||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
|
||||
|
||||
Row {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
ZashiTextField(
|
||||
singleLine = true,
|
||||
maxLines = 1,
|
||||
|
@ -648,7 +653,9 @@ fun SendFormAmountTextField(
|
|||
)
|
||||
},
|
||||
modifier = Modifier.weight(1f),
|
||||
innerModifier = Modifier.testTag(SendTag.SEND_AMOUNT_FIELD),
|
||||
innerModifier = ZashiTextFieldDefaults
|
||||
.innerModifier
|
||||
.testTag(SendTag.SEND_AMOUNT_FIELD),
|
||||
error = amountError,
|
||||
placeholder = {
|
||||
Text(
|
||||
|
|
|
@ -34,4 +34,6 @@
|
|||
<string name="general_remind_me_in_two_days">two days</string>
|
||||
<string name="general_remind_me_in_two_weeks">two weeks</string>
|
||||
<string name="general_remind_me_in_two_months">two months</string>
|
||||
<string name="general_zec">%S ZEC</string>
|
||||
<string name="general_dismiss">Dismiss</string>
|
||||
</resources>
|
||||
|
|
|
@ -35,6 +35,6 @@
|
|||
<string name="general_remind_me_in_two_days">two days</string>
|
||||
<string name="general_remind_me_in_two_weeks">two weeks</string>
|
||||
<string name="general_remind_me_in_two_months">two months</string>
|
||||
|
||||
<string name="general_zec">%S ZEC</string>
|
||||
<string name="general_dismiss">Dismiss</string>
|
||||
</resources>
|
||||
|
|
|
@ -70,4 +70,10 @@
|
|||
<string name="home_message_crash_reporting_title">Help improve Zashi</string>
|
||||
<string name="home_message_crash_reporting_subtitle">Allow sharing crash reports</string>
|
||||
<string name="home_message_crash_reporting_button">Review</string>
|
||||
<string name="balance_action_title">Spendable Balance</string>
|
||||
<string name="balance_action_all_shielded">All your funds are shielded and spendable.</string>
|
||||
<string name="balance_action_pending">Pending transactions are getting mined and confirmed.</string>
|
||||
<string name="balance_action_shield_message">Shield your transparent ZEC to make it spendable and private. Shielding transparent funds will create a shielding in-wallet transaction, consolidating your transparent and shielded funds. (Typical fee: .001 ZEC)</string>
|
||||
<string name="balance_action_info_shielded">Shielded ZEC (Spendable)</string>
|
||||
<string name="balance_action_info_pending">Pending</string>
|
||||
</resources>
|
|
@ -70,4 +70,10 @@
|
|||
<string name="home_message_crash_reporting_title">Help improve Zashi</string>
|
||||
<string name="home_message_crash_reporting_subtitle">Allow sharing crash reports</string>
|
||||
<string name="home_message_crash_reporting_button">Review</string>
|
||||
<string name="balance_action_title">Spendable Balance</string>
|
||||
<string name="balance_action_all_shielded">All your funds are shielded and spendable.</string>
|
||||
<string name="balance_action_pending">Pending transactions are getting mined and confirmed.</string>
|
||||
<string name="balance_action_shield_message">Shield your transparent ZEC to make it spendable and private. Shielding transparent funds will create a shielding in-wallet transaction, consolidating your transparent and shielded funds. (Typical fee: .001 ZEC)</string>
|
||||
<string name="balance_action_info_shielded">Shielded ZEC (Spendable)</string>
|
||||
<string name="balance_action_info_pending">Pending</string>
|
||||
</resources>
|
Loading…
Reference in New Issue