[#1156] Common current balance state UI component
* [#1156] Common current balance state UI component - Closes #1156 - Created a reusable current balances widget UI component for the Account and Balances screen - Incorporated into the Account screen - Improved ZcashCurrency API with localized currency identificators * Changelog update * File follow-up on testing
This commit is contained in:
parent
47bf1f9492
commit
155b171b46
|
@ -9,6 +9,10 @@ directly impact users rather than highlighting other key architectural updates.*
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- The current balance UI on top of the Account screen has been reworked. It now displays the currently available
|
||||||
|
balance as well.
|
||||||
|
|
||||||
## [0.2.0 (530)] - 2024-01-16
|
## [0.2.0 (530)] - 2024-01-16
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
@ -2,6 +2,7 @@ package cash.z.ecc.sdk.type
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
|
import cash.z.ecc.sdk.ext.R
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides Zcash currency types with a distinction mechanism. There is the ZEC currency type, which applies
|
* This class provides Zcash currency types with a distinction mechanism. There is the ZEC currency type, which applies
|
||||||
|
@ -12,24 +13,29 @@ import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
*/
|
*/
|
||||||
sealed class ZcashCurrency(
|
sealed class ZcashCurrency(
|
||||||
val id: Int = 0,
|
val id: Int = 0,
|
||||||
val name: String = "TAZ",
|
val name: String,
|
||||||
val network: ZcashNetwork = ZcashNetwork.Testnet
|
val network: ZcashNetwork = ZcashNetwork.Testnet
|
||||||
) {
|
) {
|
||||||
object TAZ : ZcashCurrency(id = 0, name = "TAZ", network = ZcashNetwork.Testnet)
|
object TAZ : ZcashCurrency(id = 0, name = "TAZ", network = ZcashNetwork.Testnet) {
|
||||||
|
override fun localizedName(context: Context) = context.getString(R.string.zcash_token_taz)
|
||||||
|
}
|
||||||
|
|
||||||
object ZEC : ZcashCurrency(id = 1, name = "ZEC", network = ZcashNetwork.Mainnet)
|
object ZEC : ZcashCurrency(id = 1, name = "ZEC", network = ZcashNetwork.Mainnet) {
|
||||||
|
override fun localizedName(context: Context) = context.getString(R.string.zcash_token_zec)
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun localizedName(context: Context): String
|
||||||
|
|
||||||
override fun toString(): String = "ZcashCurrency: id=$id, name=$name, network:$network"
|
override fun toString(): String = "ZcashCurrency: id=$id, name=$name, network:$network"
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromResources(context: Context) =
|
fun fromResources(context: Context) =
|
||||||
when (ZcashNetwork.fromResources(context)) {
|
when (ZcashNetwork.fromResources(context)) {
|
||||||
ZcashNetwork.Mainnet ->
|
ZcashNetwork.Mainnet -> ZEC
|
||||||
ZEC
|
ZcashNetwork.Testnet -> TAZ
|
||||||
ZcashNetwork.Testnet ->
|
else -> error("Not supported ZcashNetwork type while getting ZcashCurrency type.")
|
||||||
TAZ
|
|
||||||
else ->
|
|
||||||
error("Not supported ZcashNetwork type while getting ZcashCurrency type.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getLocalizedName(context: Context): String = fromResources(context).localizedName(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="zcash_token_zec">ZEC</string>
|
||||||
|
<string name="zcash_token_taz">TAZ</string>
|
||||||
|
</resources>
|
|
@ -22,30 +22,67 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.buildAnnotatedString
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextDecoration
|
import androidx.compose.ui.text.style.TextDecoration
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.text.withStyle
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import co.electriccoin.zcash.ui.design.R
|
|
||||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
private fun TextComposablePreview() {
|
private fun ReferenceComposablePreview() {
|
||||||
ZcashTheme(forceDarkMode = false) {
|
ZcashTheme(forceDarkMode = false) {
|
||||||
GradientSurface {
|
GradientSurface {
|
||||||
Column {
|
Column {
|
||||||
Reference(text = "Test reference text", onClick = {})
|
Reference(
|
||||||
Reference(text = "User account", imageVector = Icons.Outlined.AccountBox, onClick = {})
|
text = "Test reference text",
|
||||||
// Preview the rest of the composable
|
onClick = {},
|
||||||
|
modifier = Modifier.padding(all = ZcashTheme.dimens.spacingDefault)
|
||||||
|
)
|
||||||
|
Reference(
|
||||||
|
text = "Reference with icon",
|
||||||
|
imageVector = Icons.Outlined.AccountBox,
|
||||||
|
onClick = {},
|
||||||
|
modifier = Modifier.padding(all = ZcashTheme.dimens.spacingDefault)
|
||||||
|
)
|
||||||
|
Reference(
|
||||||
|
text = "Normal font weight reference",
|
||||||
|
onClick = {},
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
modifier = Modifier.padding(all = ZcashTheme.dimens.spacingDefault)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun StyledBalanceComposablePreview() {
|
||||||
|
ZcashTheme(forceDarkMode = false) {
|
||||||
|
GradientSurface {
|
||||||
|
Column {
|
||||||
|
StyledBalance(
|
||||||
|
mainPart = "1,234.567",
|
||||||
|
secondPart = "89012",
|
||||||
|
textStyles =
|
||||||
|
Pair(
|
||||||
|
ZcashTheme.extendedTypography.zecBalanceStyles.first,
|
||||||
|
ZcashTheme.extendedTypography.zecBalanceStyles.second
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add previews for the rest of the composables
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Header(
|
fun Header(
|
||||||
text: String,
|
text: String,
|
||||||
|
@ -107,6 +144,7 @@ fun Body(
|
||||||
maxLines: Int = Int.MAX_VALUE,
|
maxLines: Int = Int.MAX_VALUE,
|
||||||
overflow: TextOverflow = TextOverflow.Clip,
|
overflow: TextOverflow = TextOverflow.Clip,
|
||||||
textAlign: TextAlign = TextAlign.Start,
|
textAlign: TextAlign = TextAlign.Start,
|
||||||
|
textFontWeight: FontWeight = FontWeight.Normal,
|
||||||
color: Color = MaterialTheme.colorScheme.onBackground,
|
color: Color = MaterialTheme.colorScheme.onBackground,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
|
@ -116,7 +154,8 @@ fun Body(
|
||||||
overflow = overflow,
|
overflow = overflow,
|
||||||
textAlign = textAlign,
|
textAlign = textAlign,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
style = MaterialTheme.typography.bodyLarge,
|
style = ZcashTheme.typography.primary.bodyLarge,
|
||||||
|
fontWeight = textFontWeight
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,6 +254,7 @@ fun Reference(
|
||||||
text: String,
|
text: String,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
fontWeight: FontWeight = FontWeight.SemiBold,
|
||||||
textAlign: TextAlign = TextAlign.Center,
|
textAlign: TextAlign = TextAlign.Center,
|
||||||
imageVector: ImageVector? = null,
|
imageVector: ImageVector? = null,
|
||||||
imageContentDescription: String? = null
|
imageContentDescription: String? = null
|
||||||
|
@ -225,7 +265,6 @@ fun Reference(
|
||||||
.wrapContentSize()
|
.wrapContentSize()
|
||||||
.clip(RoundedCornerShape(ZcashTheme.dimens.topAppBarActionRippleCorner))
|
.clip(RoundedCornerShape(ZcashTheme.dimens.topAppBarActionRippleCorner))
|
||||||
.clickable { onClick() }
|
.clickable { onClick() }
|
||||||
.padding(all = ZcashTheme.dimens.spacingDefault)
|
|
||||||
.then(modifier),
|
.then(modifier),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
|
@ -246,7 +285,7 @@ fun Reference(
|
||||||
color = ZcashTheme.colors.reference,
|
color = ZcashTheme.colors.reference,
|
||||||
textAlign = textAlign,
|
textAlign = textAlign,
|
||||||
textDecoration = TextDecoration.Underline,
|
textDecoration = TextDecoration.Underline,
|
||||||
fontWeight = FontWeight.SemiBold
|
fontWeight = fontWeight
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -254,21 +293,37 @@ fun Reference(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pass amount of ZECs you want to display and the component appends ZEC symbol to it. We're using
|
* Pass amount of Zcash tokens you want to display and the component style it according to the design requirements.
|
||||||
* a custom font here, which is Roboto modified to replace the dollar symbol with the ZEC symbol internally.
|
|
||||||
*
|
*
|
||||||
* @param amount of ZECs to be displayed
|
* @param mainPart of Zcash tokens to be displayed in a bigger font style
|
||||||
|
* @param secondPart of Zcash tokens to be displayed in a smaller font style
|
||||||
* @param modifier to modify the Text UI element as needed
|
* @param modifier to modify the Text UI element as needed
|
||||||
*/
|
*/
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun HeaderWithZecIcon(
|
fun StyledBalance(
|
||||||
amount: String,
|
mainPart: String,
|
||||||
|
secondPart: String,
|
||||||
|
textStyles: Pair<TextStyle, TextStyle>,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
|
val content =
|
||||||
|
buildAnnotatedString {
|
||||||
|
withStyle(
|
||||||
|
style = textStyles.first.toSpanStyle()
|
||||||
|
) {
|
||||||
|
append(mainPart)
|
||||||
|
}
|
||||||
|
withStyle(
|
||||||
|
style = textStyles.second.toSpanStyle()
|
||||||
|
) {
|
||||||
|
append(secondPart)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.amount_with_zec_currency_symbol, amount),
|
text = content,
|
||||||
style = ZcashTheme.extendedTypography.zecBalance,
|
// fixme color
|
||||||
color = MaterialTheme.colorScheme.onBackground,
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
modifier =
|
modifier =
|
||||||
|
|
|
@ -208,7 +208,7 @@ private fun TopBarOneVisibleActionMenuExample(
|
||||||
text = "Action 1",
|
text = "Action 1",
|
||||||
onClick = actionCallback,
|
onClick = actionCallback,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
modifier = modifier
|
modifier = modifier.padding(all = ZcashTheme.dimens.spacingDefault)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@ package co.electriccoin.zcash.ui.design.theme.internal
|
||||||
import androidx.compose.material3.Typography
|
import androidx.compose.material3.Typography
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.compose.runtime.staticCompositionLocalOf
|
import androidx.compose.runtime.staticCompositionLocalOf
|
||||||
|
import androidx.compose.ui.text.PlatformTextStyle
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.Font
|
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.googlefonts.Font
|
import androidx.compose.ui.text.googlefonts.Font
|
||||||
|
@ -48,11 +48,6 @@ private val ArchivoFontFamily =
|
||||||
Font(googleFont = ArchivoFont, fontProvider = provider, weight = FontWeight.Bold)
|
Font(googleFont = ArchivoFont, fontProvider = provider, weight = FontWeight.Bold)
|
||||||
)
|
)
|
||||||
|
|
||||||
private val Zboto =
|
|
||||||
FontFamily(
|
|
||||||
Font(R.font.zboto, FontWeight.Normal)
|
|
||||||
)
|
|
||||||
|
|
||||||
// If you change this definition of our Typography, don't forget to check if you use only
|
// If you change this definition of our Typography, don't forget to check if you use only
|
||||||
// the defined font weights above, otherwise the closest one will be used.
|
// the defined font weights above, otherwise the closest one will be used.
|
||||||
internal val PrimaryTypography =
|
internal val PrimaryTypography =
|
||||||
|
@ -143,10 +138,19 @@ data class Typography(
|
||||||
val secondary: Typography
|
val secondary: Typography
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class BalanceTextStyles(
|
||||||
|
val first: TextStyle,
|
||||||
|
val second: TextStyle,
|
||||||
|
val third: TextStyle,
|
||||||
|
val fourth: TextStyle,
|
||||||
|
)
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class ExtendedTypography(
|
data class ExtendedTypography(
|
||||||
val listItem: TextStyle,
|
val listItem: TextStyle,
|
||||||
val zecBalance: TextStyle,
|
// Grouping balances text styles to a wrapper class
|
||||||
|
val zecBalanceStyles: BalanceTextStyles,
|
||||||
val aboutText: TextStyle,
|
val aboutText: TextStyle,
|
||||||
val buttonText: TextStyle,
|
val buttonText: TextStyle,
|
||||||
val checkboxText: TextStyle,
|
val checkboxText: TextStyle,
|
||||||
|
@ -174,11 +178,31 @@ val LocalExtendedTypography =
|
||||||
PrimaryTypography.bodyLarge.copy(
|
PrimaryTypography.bodyLarge.copy(
|
||||||
fontSize = 24.sp
|
fontSize = 24.sp
|
||||||
),
|
),
|
||||||
zecBalance =
|
// Note: the order here matters, be careful when reordering
|
||||||
TextStyle(
|
zecBalanceStyles =
|
||||||
fontFamily = Zboto,
|
BalanceTextStyles(
|
||||||
fontWeight = FontWeight.Normal,
|
first =
|
||||||
fontSize = 30.sp
|
SecondaryTypography.headlineLarge.copy(
|
||||||
|
fontSize = 42.sp,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
// Remove font padding to achieve desired design
|
||||||
|
platformStyle = PlatformTextStyle(includeFontPadding = false),
|
||||||
|
),
|
||||||
|
second =
|
||||||
|
SecondaryTypography.headlineSmall.copy(
|
||||||
|
fontSize = 11.sp,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
),
|
||||||
|
third =
|
||||||
|
PrimaryTypography.bodySmall.copy(
|
||||||
|
fontSize = 14.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
),
|
||||||
|
fourth =
|
||||||
|
PrimaryTypography.bodySmall.copy(
|
||||||
|
fontSize = 8.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
),
|
),
|
||||||
aboutText =
|
aboutText =
|
||||||
PrimaryTypography.bodyLarge.copy(
|
PrimaryTypography.bodyLarge.copy(
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="25dp"
|
||||||
|
android:height="25dp"
|
||||||
|
android:viewportWidth="25"
|
||||||
|
android:viewportHeight="25">
|
||||||
|
<group>
|
||||||
|
<clip-path
|
||||||
|
android:pathData="M0,0h25v25h-25z"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M12.5,25C19.404,25 25,19.404 25,12.5C25,5.596 19.404,0 12.5,0C5.596,0 0,5.596 0,12.5C0,19.404 5.596,25 12.5,25Z"
|
||||||
|
android:fillColor="#F4B728"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M17.304,8.306V6.26H13.632V4.003H11.375V6.26H7.703V8.977H13.401L7.703,16.706V18.753H11.375V20.997H13.632V18.753H17.304V16.036H11.606L17.304,8.306Z"
|
||||||
|
android:fillColor="#ffffff"/>
|
||||||
|
</group>
|
||||||
|
</vector>
|
Binary file not shown.
|
@ -1,4 +1,3 @@
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="amount_with_zec_currency_symbol" formatted="true">$<xliff:g id="zec_amount" example="123">%1$s</xliff:g></string>
|
|
||||||
<string name="amount_with_fiat_currency_symbol" formatted="true"><xliff:g id="fiat_currency_symbol" example="$">%1$s</xliff:g><xliff:g id="amount" example="123">%2$s</xliff:g></string>
|
<string name="amount_with_fiat_currency_symbol" formatted="true"><xliff:g id="fiat_currency_symbol" example="$">%1$s</xliff:g><xliff:g id="amount" example="123">%2$s</xliff:g></string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -53,6 +53,7 @@ class AccountTestSetup(
|
||||||
goSettings = {
|
goSettings = {
|
||||||
onSettingsCount.incrementAndGet()
|
onSettingsCount.incrementAndGet()
|
||||||
},
|
},
|
||||||
|
goBalances = {},
|
||||||
goHistory = {
|
goHistory = {
|
||||||
onHistoryCount.incrementAndGet()
|
onHistoryCount.incrementAndGet()
|
||||||
},
|
},
|
||||||
|
|
|
@ -21,6 +21,9 @@ import org.junit.Assert
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
|
// TODO [#1194]: Cover Current balances UI widget with tests
|
||||||
|
// TODO [#1194]: https://github.com/Electric-Coin-Company/zashi-android/issues/1194
|
||||||
|
|
||||||
class AccountViewTest : UiTestPrerequisites() {
|
class AccountViewTest : UiTestPrerequisites() {
|
||||||
@get:Rule
|
@get:Rule
|
||||||
val composeTestRule = createComposeRule()
|
val composeTestRule = createComposeRule()
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
package co.electriccoin.zcash.ui.common
|
||||||
|
|
||||||
|
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.layout.width
|
||||||
|
import androidx.compose.foundation.layout.wrapContentSize
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.tooling.preview.Devices
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import cash.z.ecc.android.sdk.model.MonetarySeparators
|
||||||
|
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||||
|
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||||
|
import cash.z.ecc.android.sdk.model.toZecString
|
||||||
|
import cash.z.ecc.sdk.type.ZcashCurrency
|
||||||
|
import co.electriccoin.zcash.spackle.Twig
|
||||||
|
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||||
|
import co.electriccoin.zcash.ui.common.model.spendableBalance
|
||||||
|
import co.electriccoin.zcash.ui.common.model.totalBalance
|
||||||
|
import co.electriccoin.zcash.ui.design.R
|
||||||
|
import co.electriccoin.zcash.ui.design.component.Body
|
||||||
|
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||||
|
import co.electriccoin.zcash.ui.design.component.Reference
|
||||||
|
import co.electriccoin.zcash.ui.design.component.StyledBalance
|
||||||
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
|
import co.electriccoin.zcash.ui.fixture.WalletSnapshotFixture
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
@Preview(device = Devices.PIXEL_2)
|
||||||
|
@Composable
|
||||||
|
private fun BalanceWidgetPreview() {
|
||||||
|
ZcashTheme(forceDarkMode = false) {
|
||||||
|
GradientSurface(
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
@Suppress("MagicNumber")
|
||||||
|
BalanceWidget(
|
||||||
|
walletSnapshot =
|
||||||
|
WalletSnapshotFixture.new(
|
||||||
|
saplingBalance =
|
||||||
|
WalletBalance(
|
||||||
|
Zatoshi(1234567891234567),
|
||||||
|
Zatoshi(123456789)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
isReferenceToBalances = true,
|
||||||
|
onReferenceClick = {},
|
||||||
|
modifier = Modifier
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun splitBalance(balance: String): Pair<String, String> {
|
||||||
|
Twig.debug { "Balance before split: $balance" }
|
||||||
|
|
||||||
|
@Suppress("MAGIC_CONSTANT", "MagicNumber")
|
||||||
|
val cutPosition = balance.indexOf(MonetarySeparators.current(Locale.US).decimal) + 4
|
||||||
|
val firstPart =
|
||||||
|
balance.substring(
|
||||||
|
startIndex = 0,
|
||||||
|
endIndex = cutPosition
|
||||||
|
)
|
||||||
|
val secondPart =
|
||||||
|
balance.substring(
|
||||||
|
startIndex = cutPosition
|
||||||
|
)
|
||||||
|
|
||||||
|
Twig.debug { "Balance after split: $firstPart|$secondPart" }
|
||||||
|
|
||||||
|
return Pair(firstPart, secondPart)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@Suppress("LongMethod")
|
||||||
|
fun BalanceWidget(
|
||||||
|
walletSnapshot: WalletSnapshot,
|
||||||
|
isReferenceToBalances: Boolean,
|
||||||
|
onReferenceClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.wrapContentSize()
|
||||||
|
.then(modifier),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
val totalBalanceSplit = splitBalance(walletSnapshot.totalBalance().toZecString())
|
||||||
|
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
StyledBalance(
|
||||||
|
mainPart = totalBalanceSplit.first,
|
||||||
|
secondPart = totalBalanceSplit.second,
|
||||||
|
textStyles =
|
||||||
|
Pair(
|
||||||
|
ZcashTheme.extendedTypography.zecBalanceStyles.first,
|
||||||
|
ZcashTheme.extendedTypography.zecBalanceStyles.second
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(ZcashTheme.dimens.spacingSmall))
|
||||||
|
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.ic_zcash_zec_icon),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
if (isReferenceToBalances) {
|
||||||
|
Reference(
|
||||||
|
text = stringResource(id = co.electriccoin.zcash.ui.R.string.balance_widget_available),
|
||||||
|
onClick = onReferenceClick,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
modifier = Modifier.padding(all = ZcashTheme.dimens.spacingTiny)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Body(
|
||||||
|
text = stringResource(id = co.electriccoin.zcash.ui.R.string.balance_widget_available),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(ZcashTheme.dimens.spacingTiny))
|
||||||
|
|
||||||
|
val availableBalanceSplit = splitBalance(walletSnapshot.spendableBalance().toZecString())
|
||||||
|
|
||||||
|
StyledBalance(
|
||||||
|
mainPart = availableBalanceSplit.first,
|
||||||
|
secondPart = availableBalanceSplit.second,
|
||||||
|
textStyles =
|
||||||
|
Pair(
|
||||||
|
ZcashTheme.extendedTypography.zecBalanceStyles.third,
|
||||||
|
ZcashTheme.extendedTypography.zecBalanceStyles.fourth
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(ZcashTheme.dimens.spacingTiny))
|
||||||
|
|
||||||
|
Body(
|
||||||
|
text = ZcashCurrency.getLocalizedName(LocalContext.current),
|
||||||
|
textFontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,8 +19,9 @@ import co.electriccoin.zcash.ui.screen.update.model.UpdateState
|
||||||
@Composable
|
@Composable
|
||||||
internal fun WrapAccount(
|
internal fun WrapAccount(
|
||||||
activity: ComponentActivity,
|
activity: ComponentActivity,
|
||||||
goSettings: () -> Unit,
|
|
||||||
goHistory: () -> Unit,
|
goHistory: () -> Unit,
|
||||||
|
goBalances: () -> Unit,
|
||||||
|
goSettings: () -> Unit,
|
||||||
) {
|
) {
|
||||||
// Show information about the app update, if available
|
// Show information about the app update, if available
|
||||||
val checkUpdateViewModel by activity.viewModels<CheckUpdateViewModel> {
|
val checkUpdateViewModel by activity.viewModels<CheckUpdateViewModel> {
|
||||||
|
@ -53,8 +54,9 @@ internal fun WrapAccount(
|
||||||
isUpdateAvailable = updateAvailable,
|
isUpdateAvailable = updateAvailable,
|
||||||
isKeepScreenOnDuringSync = isKeepScreenOnWhileSyncing,
|
isKeepScreenOnDuringSync = isKeepScreenOnWhileSyncing,
|
||||||
isFiatConversionEnabled = isFiatConversionEnabled,
|
isFiatConversionEnabled = isFiatConversionEnabled,
|
||||||
|
goBalances = goBalances,
|
||||||
|
goHistory = goHistory,
|
||||||
goSettings = goSettings,
|
goSettings = goSettings,
|
||||||
goHistory = goHistory
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// For benchmarking purposes
|
// For benchmarking purposes
|
||||||
|
|
|
@ -22,6 +22,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||||
import cash.z.ecc.android.sdk.Synchronizer
|
import cash.z.ecc.android.sdk.Synchronizer
|
||||||
import cash.z.ecc.android.sdk.model.FiatCurrencyConversionRateState
|
import cash.z.ecc.android.sdk.model.FiatCurrencyConversionRateState
|
||||||
import co.electriccoin.zcash.ui.R
|
import co.electriccoin.zcash.ui.R
|
||||||
|
import co.electriccoin.zcash.ui.common.BalanceWidget
|
||||||
import co.electriccoin.zcash.ui.common.DisableScreenTimeout
|
import co.electriccoin.zcash.ui.common.DisableScreenTimeout
|
||||||
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||||
import co.electriccoin.zcash.ui.common.test.CommonTag
|
import co.electriccoin.zcash.ui.common.test.CommonTag
|
||||||
|
@ -29,7 +30,6 @@ import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
|
||||||
import co.electriccoin.zcash.ui.design.component.Body
|
import co.electriccoin.zcash.ui.design.component.Body
|
||||||
import co.electriccoin.zcash.ui.design.component.BodyWithFiatCurrencySymbol
|
import co.electriccoin.zcash.ui.design.component.BodyWithFiatCurrencySymbol
|
||||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||||
import co.electriccoin.zcash.ui.design.component.HeaderWithZecIcon
|
|
||||||
import co.electriccoin.zcash.ui.design.component.PrimaryButton
|
import co.electriccoin.zcash.ui.design.component.PrimaryButton
|
||||||
import co.electriccoin.zcash.ui.design.component.SmallTopAppBar
|
import co.electriccoin.zcash.ui.design.component.SmallTopAppBar
|
||||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
|
@ -47,8 +47,9 @@ private fun ComposablePreview() {
|
||||||
isUpdateAvailable = false,
|
isUpdateAvailable = false,
|
||||||
isKeepScreenOnDuringSync = false,
|
isKeepScreenOnDuringSync = false,
|
||||||
isFiatConversionEnabled = false,
|
isFiatConversionEnabled = false,
|
||||||
|
goHistory = {},
|
||||||
|
goBalances = {},
|
||||||
goSettings = {},
|
goSettings = {},
|
||||||
goHistory = {}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,8 +62,9 @@ fun Account(
|
||||||
isUpdateAvailable: Boolean,
|
isUpdateAvailable: Boolean,
|
||||||
isKeepScreenOnDuringSync: Boolean?,
|
isKeepScreenOnDuringSync: Boolean?,
|
||||||
isFiatConversionEnabled: Boolean,
|
isFiatConversionEnabled: Boolean,
|
||||||
|
goBalances: () -> Unit,
|
||||||
|
goHistory: () -> Unit,
|
||||||
goSettings: () -> Unit,
|
goSettings: () -> Unit,
|
||||||
goHistory: () -> Unit
|
|
||||||
) {
|
) {
|
||||||
Scaffold(topBar = {
|
Scaffold(topBar = {
|
||||||
AccountTopAppBar(onSettings = goSettings)
|
AccountTopAppBar(onSettings = goSettings)
|
||||||
|
@ -73,6 +75,7 @@ fun Account(
|
||||||
isKeepScreenOnDuringSync = isKeepScreenOnDuringSync,
|
isKeepScreenOnDuringSync = isKeepScreenOnDuringSync,
|
||||||
isFiatConversionEnabled = isFiatConversionEnabled,
|
isFiatConversionEnabled = isFiatConversionEnabled,
|
||||||
goHistory = goHistory,
|
goHistory = goHistory,
|
||||||
|
goBalances = goBalances,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.padding(
|
Modifier.padding(
|
||||||
top = paddingValues.calculateTopPadding() + ZcashTheme.dimens.spacingDefault,
|
top = paddingValues.calculateTopPadding() + ZcashTheme.dimens.spacingDefault,
|
||||||
|
@ -109,6 +112,7 @@ private fun AccountMainContent(
|
||||||
isUpdateAvailable: Boolean,
|
isUpdateAvailable: Boolean,
|
||||||
isKeepScreenOnDuringSync: Boolean?,
|
isKeepScreenOnDuringSync: Boolean?,
|
||||||
isFiatConversionEnabled: Boolean,
|
isFiatConversionEnabled: Boolean,
|
||||||
|
goBalances: () -> Unit,
|
||||||
goHistory: () -> Unit,
|
goHistory: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
|
@ -121,7 +125,7 @@ private fun AccountMainContent(
|
||||||
) {
|
) {
|
||||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
|
||||||
|
|
||||||
Status(walletSnapshot, isUpdateAvailable, isFiatConversionEnabled)
|
Status(walletSnapshot, isUpdateAvailable, isFiatConversionEnabled, goBalances)
|
||||||
|
|
||||||
Spacer(
|
Spacer(
|
||||||
modifier =
|
modifier =
|
||||||
|
@ -145,7 +149,8 @@ private fun AccountMainContent(
|
||||||
private fun Status(
|
private fun Status(
|
||||||
walletSnapshot: WalletSnapshot,
|
walletSnapshot: WalletSnapshot,
|
||||||
updateAvailable: Boolean,
|
updateAvailable: Boolean,
|
||||||
isFiatConversionEnabled: Boolean
|
isFiatConversionEnabled: Boolean,
|
||||||
|
goBalances: () -> Unit
|
||||||
) {
|
) {
|
||||||
val walletDisplayValues =
|
val walletDisplayValues =
|
||||||
WalletDisplayValues.getNextValues(
|
WalletDisplayValues.getNextValues(
|
||||||
|
@ -161,10 +166,14 @@ private fun Status(
|
||||||
.testTag(AccountTag.STATUS_VIEWS),
|
.testTag(AccountTag.STATUS_VIEWS),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
|
||||||
|
|
||||||
if (walletDisplayValues.zecAmountText.isNotEmpty()) {
|
if (walletDisplayValues.zecAmountText.isNotEmpty()) {
|
||||||
HeaderWithZecIcon(amount = walletDisplayValues.zecAmountText)
|
BalanceWidget(
|
||||||
|
walletSnapshot = walletSnapshot,
|
||||||
|
isReferenceToBalances = true,
|
||||||
|
onReferenceClick = goBalances
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFiatConversionEnabled) {
|
if (isFiatConversionEnabled) {
|
||||||
|
|
|
@ -227,7 +227,7 @@ private fun HistoryList(
|
||||||
onItemClick: (TransactionOverview) -> Unit,
|
onItemClick: (TransactionOverview) -> Unit,
|
||||||
onTransactionIdClick: (String) -> Unit
|
onTransactionIdClick: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
val currency = ZcashCurrency.fromResources(LocalContext.current)
|
val currency = ZcashCurrency.getLocalizedName(LocalContext.current)
|
||||||
LazyColumn(modifier = Modifier.testTag(HistoryTag.TRANSACTION_LIST)) {
|
LazyColumn(modifier = Modifier.testTag(HistoryTag.TRANSACTION_LIST)) {
|
||||||
itemsIndexed(transactions) { index, item ->
|
itemsIndexed(transactions) { index, item ->
|
||||||
HistoryItem(
|
HistoryItem(
|
||||||
|
@ -250,7 +250,7 @@ private fun HistoryList(
|
||||||
@Suppress("LongMethod")
|
@Suppress("LongMethod")
|
||||||
fun HistoryItem(
|
fun HistoryItem(
|
||||||
transaction: TransactionOverview,
|
transaction: TransactionOverview,
|
||||||
currency: ZcashCurrency,
|
currency: String,
|
||||||
onItemClick: (TransactionOverview) -> Unit,
|
onItemClick: (TransactionOverview) -> Unit,
|
||||||
onIdClick: (String) -> Unit,
|
onIdClick: (String) -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
|
@ -340,7 +340,7 @@ fun HistoryItem(
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(ZcashTheme.dimens.spacingTiny))
|
Spacer(modifier = Modifier.width(ZcashTheme.dimens.spacingTiny))
|
||||||
|
|
||||||
Body(text = currency.name)
|
Body(text = currency)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ internal fun WrapHome(
|
||||||
HomeScreenIndex.ACCOUNT -> goBack()
|
HomeScreenIndex.ACCOUNT -> goBack()
|
||||||
HomeScreenIndex.SEND,
|
HomeScreenIndex.SEND,
|
||||||
HomeScreenIndex.RECEIVE,
|
HomeScreenIndex.RECEIVE,
|
||||||
HomeScreenIndex.BALANCES -> forceHomePageIndexFlow.tryEmit(ForcePage())
|
HomeScreenIndex.BALANCES -> forceHomePageIndexFlow.tryEmit(ForcePage(HomeScreenIndex.ACCOUNT))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +87,7 @@ internal fun WrapHome(
|
||||||
screenContent = {
|
screenContent = {
|
||||||
WrapAccount(
|
WrapAccount(
|
||||||
activity = activity,
|
activity = activity,
|
||||||
|
goBalances = { forceHomePageIndexFlow.tryEmit(ForcePage(HomeScreenIndex.BALANCES)) },
|
||||||
goHistory = goHistory,
|
goHistory = goHistory,
|
||||||
goSettings = goSettings,
|
goSettings = goSettings,
|
||||||
)
|
)
|
||||||
|
@ -141,7 +142,7 @@ internal fun WrapHome(
|
||||||
* Wrapper class used to pass forced pages index into the view layer
|
* Wrapper class used to pass forced pages index into the view layer
|
||||||
*/
|
*/
|
||||||
class ForcePage(
|
class ForcePage(
|
||||||
val currentPage: HomeScreenIndex = HomeScreenIndex.ACCOUNT,
|
val currentPage: HomeScreenIndex,
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -117,7 +117,7 @@ private fun NewWalletRecoveryCopyToBufferMenuItem(
|
||||||
text = stringResource(id = R.string.new_wallet_recovery_copy),
|
text = stringResource(id = R.string.new_wallet_recovery_copy),
|
||||||
onClick = onCopyToClipboard,
|
onClick = onCopyToClipboard,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
modifier = modifier
|
modifier = modifier.padding(all = ZcashTheme.dimens.spacingDefault)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -294,7 +294,10 @@ private fun Address(
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
imageVector = ImageVector.vectorResource(R.drawable.copy),
|
imageVector = ImageVector.vectorResource(R.drawable.copy),
|
||||||
imageContentDescription = null,
|
imageContentDescription = null,
|
||||||
modifier = Modifier.wrapContentSize(),
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.wrapContentSize()
|
||||||
|
.padding(all = ZcashTheme.dimens.spacingDefault),
|
||||||
)
|
)
|
||||||
Reference(
|
Reference(
|
||||||
text = stringResource(id = R.string.receive_share),
|
text = stringResource(id = R.string.receive_share),
|
||||||
|
@ -302,7 +305,10 @@ private fun Address(
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
imageVector = ImageVector.vectorResource(R.drawable.share),
|
imageVector = ImageVector.vectorResource(R.drawable.share),
|
||||||
imageContentDescription = null,
|
imageContentDescription = null,
|
||||||
modifier = Modifier.wrapContentSize(),
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.wrapContentSize()
|
||||||
|
.padding(all = ZcashTheme.dimens.spacingDefault),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -283,7 +283,7 @@ private fun ClearSeedMenuItem(
|
||||||
text = stringResource(id = R.string.restore_button_clear),
|
text = stringResource(id = R.string.restore_button_clear),
|
||||||
onClick = onSeedClear,
|
onClick = onSeedClear,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
modifier = modifier
|
modifier = modifier.padding(all = ZcashTheme.dimens.spacingDefault)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ private fun SeedRecoveryCopyToBufferMenuItem(
|
||||||
text = stringResource(id = R.string.seed_recovery_copy),
|
text = stringResource(id = R.string.seed_recovery_copy),
|
||||||
onClick = onCopyToClipboard,
|
onClick = onCopyToClipboard,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
modifier = modifier
|
modifier = modifier.padding(all = ZcashTheme.dimens.spacingDefault)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -202,13 +202,14 @@ private fun UpdateContentNormal(
|
||||||
|
|
||||||
Reference(
|
Reference(
|
||||||
text = stringResource(id = R.string.update_link_text),
|
text = stringResource(id = R.string.update_link_text),
|
||||||
|
onClick = {
|
||||||
|
onReference()
|
||||||
|
},
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.wrapContentHeight()
|
.wrapContentHeight()
|
||||||
.align(Alignment.CenterHorizontally),
|
.align(Alignment.CenterHorizontally)
|
||||||
onClick = {
|
.padding(all = ZcashTheme.dimens.spacingDefault),
|
||||||
onReference()
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,4 +4,5 @@
|
||||||
<string name="zcash_logo_content_description">Zcash logo</string>
|
<string name="zcash_logo_content_description">Zcash logo</string>
|
||||||
<string name="not_implemented_yet">Not implemented yet.</string>
|
<string name="not_implemented_yet">Not implemented yet.</string>
|
||||||
<string name="settings_menu_content_description">Open Settings</string>
|
<string name="settings_menu_content_description">Open Settings</string>
|
||||||
|
<string name="balance_widget_available">Available Balance:</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue