[#1219] Current balances UI
* [#1219] Current balances UI - This represents UI changes for balance, change, and transaction on the Balances screen - Reworked StyledBalance to be more reusable, too - Adopted the latest SDK changes related to change pending and pending transactions - Closes #1224 - Closes #1219 * Adopted latest SDK snapshot version
This commit is contained in:
parent
c5efcabf4c
commit
1058802b19
|
@ -188,7 +188,7 @@ ZCASH_BIP39_VERSION=1.0.7
|
||||||
ZXING_VERSION=3.5.2
|
ZXING_VERSION=3.5.2
|
||||||
|
|
||||||
# WARNING: Ensure a non-snapshot version is used before releasing to production.
|
# WARNING: Ensure a non-snapshot version is used before releasing to production.
|
||||||
ZCASH_SDK_VERSION=2.0.6
|
ZCASH_SDK_VERSION=2.0.6-SNAPSHOT
|
||||||
|
|
||||||
# Toolchain is the Java version used to build the application, which is separate from the
|
# Toolchain is the Java version used to build the application, which is separate from the
|
||||||
# Java version used to run the application.
|
# Java version used to run the application.
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
package co.electriccoin.zcash.ui.design.component
|
package co.electriccoin.zcash.ui.design.component
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
|
@ -15,7 +17,10 @@ import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
private fun CircularScreenProgressIndicatorComposablePreview() {
|
private fun CircularScreenProgressIndicatorComposablePreview() {
|
||||||
ZcashTheme(forceDarkMode = false) {
|
ZcashTheme(forceDarkMode = false) {
|
||||||
GradientSurface {
|
GradientSurface {
|
||||||
|
Column {
|
||||||
CircularScreenProgressIndicator()
|
CircularScreenProgressIndicator()
|
||||||
|
CircularSmallProgressIndicator()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +35,22 @@ fun CircularScreenProgressIndicator(modifier: Modifier = Modifier) {
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
CircularProgressIndicator(
|
CircularProgressIndicator(
|
||||||
modifier = Modifier.width(ZcashTheme.dimens.circularScreenProgressWidth)
|
color = ZcashTheme.colors.progressBarScreen,
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.size(ZcashTheme.dimens.circularScreenProgressWidth)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CircularSmallProgressIndicator(modifier: Modifier = Modifier) {
|
||||||
|
CircularProgressIndicator(
|
||||||
|
color = ZcashTheme.colors.progressBarSmall,
|
||||||
|
strokeWidth = 2.dp,
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.size(ZcashTheme.dimens.circularSmallProgressWidth)
|
||||||
|
.then(modifier)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -30,7 +30,10 @@ 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.text.withStyle
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import cash.z.ecc.android.sdk.model.MonetarySeparators
|
||||||
|
import co.electriccoin.zcash.spackle.Twig
|
||||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -67,12 +70,11 @@ private fun StyledBalanceComposablePreview() {
|
||||||
GradientSurface {
|
GradientSurface {
|
||||||
Column {
|
Column {
|
||||||
StyledBalance(
|
StyledBalance(
|
||||||
mainPart = "1,234.567",
|
balanceString = "1,234.56789012",
|
||||||
secondPart = "89012",
|
|
||||||
textStyles =
|
textStyles =
|
||||||
Pair(
|
Pair(
|
||||||
ZcashTheme.extendedTypography.balanceStyles.first,
|
ZcashTheme.extendedTypography.balanceWidgetStyles.first,
|
||||||
ZcashTheme.extendedTypography.balanceStyles.second
|
ZcashTheme.extendedTypography.balanceWidgetStyles.second
|
||||||
),
|
),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
)
|
)
|
||||||
|
@ -222,19 +224,6 @@ fun Tiny(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ListItem(
|
|
||||||
text: String,
|
|
||||||
modifier: Modifier = Modifier
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = text,
|
|
||||||
style = ZcashTheme.extendedTypography.listItem,
|
|
||||||
color = MaterialTheme.colorScheme.onBackground,
|
|
||||||
modifier = modifier
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ListHeader(
|
fun ListHeader(
|
||||||
text: String,
|
text: String,
|
||||||
|
@ -293,44 +282,78 @@ fun Reference(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pass amount of Zcash tokens you want to display and the component style it according to the design requirements.
|
* This accepts string with balance and displays it in the UI component styled according to the design
|
||||||
|
* requirements. The function displays the balance within two parts.
|
||||||
*
|
*
|
||||||
* @param mainPart of Zcash tokens to be displayed in a bigger font style
|
* @param balanceString String of Zcash formatted balance
|
||||||
* @param secondPart of Zcash tokens to be displayed in a smaller font style
|
* @param textStyles Styles for the first and second part of the balance
|
||||||
* @param modifier to modify the Text UI element as needed
|
* @param textColor Optional color to modify the default font color from [textStyles]
|
||||||
|
* @param modifier Modifier to modify the Text UI element as needed
|
||||||
*/
|
*/
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun StyledBalance(
|
fun StyledBalance(
|
||||||
mainPart: String,
|
balanceString: String,
|
||||||
secondPart: String,
|
|
||||||
textStyles: Pair<TextStyle, TextStyle>,
|
textStyles: Pair<TextStyle, TextStyle>,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier,
|
||||||
|
textColor: Color? = null
|
||||||
) {
|
) {
|
||||||
|
val balanceSplit = splitBalance(balanceString)
|
||||||
|
|
||||||
val content =
|
val content =
|
||||||
buildAnnotatedString {
|
buildAnnotatedString {
|
||||||
withStyle(
|
withStyle(
|
||||||
style = textStyles.first.toSpanStyle()
|
style = textStyles.first.toSpanStyle()
|
||||||
) {
|
) {
|
||||||
append(mainPart)
|
append(balanceSplit.first)
|
||||||
}
|
}
|
||||||
withStyle(
|
withStyle(
|
||||||
style = textStyles.second.toSpanStyle()
|
style = textStyles.second.toSpanStyle()
|
||||||
) {
|
) {
|
||||||
append(secondPart)
|
append(balanceSplit.second)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (textColor != null) {
|
||||||
Text(
|
Text(
|
||||||
text = content,
|
text = content,
|
||||||
// fixme color
|
color = textColor,
|
||||||
color = MaterialTheme.colorScheme.onBackground,
|
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.basicMarquee()
|
.basicMarquee()
|
||||||
.then(modifier)
|
.then(modifier)
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
Text(
|
||||||
|
text = content,
|
||||||
|
maxLines = 1,
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.basicMarquee()
|
||||||
|
.then(modifier)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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
|
@Composable
|
||||||
|
|
|
@ -30,6 +30,7 @@ data class Dimens(
|
||||||
val chipStroke: Dp,
|
val chipStroke: Dp,
|
||||||
// Progress
|
// Progress
|
||||||
val circularScreenProgressWidth: Dp,
|
val circularScreenProgressWidth: Dp,
|
||||||
|
val circularSmallProgressWidth: Dp,
|
||||||
// TopAppBar:
|
// TopAppBar:
|
||||||
val topAppBarZcashLogoHeight: Dp,
|
val topAppBarZcashLogoHeight: Dp,
|
||||||
val topAppBarActionRippleCorner: Dp,
|
val topAppBarActionRippleCorner: Dp,
|
||||||
|
@ -37,6 +38,7 @@ data class Dimens(
|
||||||
val textFieldDefaultHeight: Dp,
|
val textFieldDefaultHeight: Dp,
|
||||||
val textFieldPanelDefaultHeight: Dp,
|
val textFieldPanelDefaultHeight: Dp,
|
||||||
// Any Layout:
|
// Any Layout:
|
||||||
|
val divider: Dp,
|
||||||
val layoutStroke: Dp,
|
val layoutStroke: Dp,
|
||||||
// Screen custom spacings:
|
// Screen custom spacings:
|
||||||
val inScreenZcashLogoHeight: Dp,
|
val inScreenZcashLogoHeight: Dp,
|
||||||
|
@ -64,11 +66,13 @@ private val defaultDimens =
|
||||||
chipShadowElevation = 4.dp,
|
chipShadowElevation = 4.dp,
|
||||||
chipStroke = 0.5.dp,
|
chipStroke = 0.5.dp,
|
||||||
circularScreenProgressWidth = 48.dp,
|
circularScreenProgressWidth = 48.dp,
|
||||||
|
circularSmallProgressWidth = 14.dp,
|
||||||
topAppBarZcashLogoHeight = 24.dp,
|
topAppBarZcashLogoHeight = 24.dp,
|
||||||
topAppBarActionRippleCorner = 28.dp,
|
topAppBarActionRippleCorner = 28.dp,
|
||||||
textFieldDefaultHeight = 64.dp,
|
textFieldDefaultHeight = 64.dp,
|
||||||
textFieldPanelDefaultHeight = 215.dp,
|
textFieldPanelDefaultHeight = 215.dp,
|
||||||
layoutStroke = 1.dp,
|
layoutStroke = 1.dp,
|
||||||
|
divider = 1.dp,
|
||||||
inScreenZcashLogoHeight = 100.dp,
|
inScreenZcashLogoHeight = 100.dp,
|
||||||
inScreenZcashLogoWidth = 60.dp,
|
inScreenZcashLogoWidth = 60.dp,
|
||||||
inScreenZcashTextLogoHeight = 30.dp,
|
inScreenZcashTextLogoHeight = 30.dp,
|
||||||
|
|
|
@ -14,12 +14,13 @@ data class ExtendedColors(
|
||||||
val onTertiary: Color,
|
val onTertiary: Color,
|
||||||
val callout: Color,
|
val callout: Color,
|
||||||
val onCallout: Color,
|
val onCallout: Color,
|
||||||
val progressStart: Color,
|
val progressBarSmall: Color,
|
||||||
val progressEnd: Color,
|
val progressBarScreen: Color,
|
||||||
val progressBackground: Color,
|
|
||||||
val chipIndex: Color,
|
val chipIndex: Color,
|
||||||
|
val textCommon: Color,
|
||||||
val textFieldHint: Color,
|
val textFieldHint: Color,
|
||||||
val textDescription: Color,
|
val textDescription: Color,
|
||||||
|
val textPending: Color,
|
||||||
val layoutStroke: Color,
|
val layoutStroke: Color,
|
||||||
val overlay: Color,
|
val overlay: Color,
|
||||||
val highlight: Color,
|
val highlight: Color,
|
||||||
|
@ -34,6 +35,7 @@ data class ExtendedColors(
|
||||||
val welcomeAnimationColor: Color,
|
val welcomeAnimationColor: Color,
|
||||||
val complementaryColor: Color,
|
val complementaryColor: Color,
|
||||||
val dividerColor: Color,
|
val dividerColor: Color,
|
||||||
|
val darkDividerColor: Color,
|
||||||
val tabTextColor: Color,
|
val tabTextColor: Color,
|
||||||
) {
|
) {
|
||||||
@Composable
|
@Composable
|
||||||
|
|
|
@ -24,10 +24,11 @@ internal object Dark {
|
||||||
val textSecondaryButton = Color(0xFF000000)
|
val textSecondaryButton = Color(0xFF000000)
|
||||||
val textTertiaryButton = Color.White
|
val textTertiaryButton = Color.White
|
||||||
val textNavigationButton = Color.Black
|
val textNavigationButton = Color.Black
|
||||||
val textCaption = Color(0xFFFFFFFF)
|
val textCommon = Color(0xFFFFFFFF)
|
||||||
val textChipIndex = Color(0xFFFFB900)
|
val textChipIndex = Color(0xFFFFB900)
|
||||||
val textFieldHint = Color(0xFFB7B7B7)
|
val textFieldHint = Color(0xFFB7B7B7)
|
||||||
val textDescription = Color(0xFF777777)
|
val textDescription = Color(0xFF777777)
|
||||||
|
val textProgress = Color(0xFF8B8A8A)
|
||||||
|
|
||||||
val layoutStroke = Color(0xFFFFFFFF)
|
val layoutStroke = Color(0xFFFFFFFF)
|
||||||
|
|
||||||
|
@ -45,9 +46,8 @@ internal object Dark {
|
||||||
val navigationButton = Color(0xFFFFFFFF)
|
val navigationButton = Color(0xFFFFFFFF)
|
||||||
val navigationButtonPressed = Color(0xFFFFFFFF)
|
val navigationButtonPressed = Color(0xFFFFFFFF)
|
||||||
|
|
||||||
val progressStart = Color(0xFFF364CE)
|
val progressBarSmall = Color(0xFF8B8A8A)
|
||||||
val progressEnd = Color(0xFFF8964F)
|
val progressBarScreen = Color(0xFFFFFFFF)
|
||||||
val progressBackground = Color(0xFF929bb3)
|
|
||||||
|
|
||||||
val callout = Color(0xFFFFFFFF)
|
val callout = Color(0xFFFFFFFF)
|
||||||
val onCallout = Color(0xFFFFFFFF)
|
val onCallout = Color(0xFFFFFFFF)
|
||||||
|
@ -55,11 +55,6 @@ internal object Dark {
|
||||||
val overlay = Color(0x22000000)
|
val overlay = Color(0x22000000)
|
||||||
val highlight = Color(0xFFFFD800)
|
val highlight = Color(0xFFFFD800)
|
||||||
|
|
||||||
val addressHighlightBorder = Color(0xFF525252)
|
|
||||||
val addressHighlightUnified = Color(0xFFFFD800)
|
|
||||||
val addressHighlightSapling = Color(0xFF1BBFF6)
|
|
||||||
val addressHighlightTransparent = Color(0xFF97999A)
|
|
||||||
|
|
||||||
val dangerous = Color(0xFFEC0008)
|
val dangerous = Color(0xFFEC0008)
|
||||||
val onDangerous = Color(0xFFFFFFFF)
|
val onDangerous = Color(0xFFFFFFFF)
|
||||||
|
|
||||||
|
@ -76,6 +71,7 @@ internal object Dark {
|
||||||
val welcomeAnimationColor = Color(0xFF231F20)
|
val welcomeAnimationColor = Color(0xFF231F20)
|
||||||
val complementaryColor = Color(0xFFF4B728)
|
val complementaryColor = Color(0xFFF4B728)
|
||||||
val dividerColor = Color(0xFFDDDDDD)
|
val dividerColor = Color(0xFFDDDDDD)
|
||||||
|
val darkDividerColor = Color(0xFF000000)
|
||||||
val tabTextColor = Color(0xFF040404)
|
val tabTextColor = Color(0xFF040404)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,10 +85,11 @@ internal object Light {
|
||||||
val textPrimaryButton = Color(0xFFFFFFFF)
|
val textPrimaryButton = Color(0xFFFFFFFF)
|
||||||
val textSecondaryButton = Color(0xFF000000)
|
val textSecondaryButton = Color(0xFF000000)
|
||||||
val textTertiaryButton = Color(0xFF000000)
|
val textTertiaryButton = Color(0xFF000000)
|
||||||
val textCaption = Color(0xFF000000)
|
val textCommon = Color(0xFF000000)
|
||||||
val textChipIndex = Color(0xFFEE8592)
|
val textChipIndex = Color(0xFFEE8592)
|
||||||
val textFieldHint = Color(0xFFB7B7B7)
|
val textFieldHint = Color(0xFFB7B7B7)
|
||||||
val textDescription = Color(0xFF777777)
|
val textDescription = Color(0xFF777777)
|
||||||
|
val textProgress = Color(0xFF8B8A8A)
|
||||||
|
|
||||||
val layoutStroke = Color(0xFF000000)
|
val layoutStroke = Color(0xFF000000)
|
||||||
|
|
||||||
|
@ -110,9 +107,8 @@ internal object Light {
|
||||||
val navigationButton = Color(0xFFFFFFFF)
|
val navigationButton = Color(0xFFFFFFFF)
|
||||||
val navigationButtonPressed = Color(0xFFFFFFFF)
|
val navigationButtonPressed = Color(0xFFFFFFFF)
|
||||||
|
|
||||||
val progressStart = Color(0xFFF364CE)
|
val progressBarSmall = Color(0xFF8B8A8A)
|
||||||
val progressEnd = Color(0xFFF8964F)
|
val progressBarScreen = Color(0xFF000000)
|
||||||
val progressBackground = Color(0xFFFFFFFF)
|
|
||||||
|
|
||||||
val callout = Color(0xFFFFFFFF)
|
val callout = Color(0xFFFFFFFF)
|
||||||
val onCallout = Color(0xFFFFFFFF)
|
val onCallout = Color(0xFFFFFFFF)
|
||||||
|
@ -134,6 +130,7 @@ internal object Light {
|
||||||
val welcomeAnimationColor = Color(0xFF231F20)
|
val welcomeAnimationColor = Color(0xFF231F20)
|
||||||
val complementaryColor = Color(0xFFF4B728)
|
val complementaryColor = Color(0xFFF4B728)
|
||||||
val dividerColor = Color(0xFFDDDDDD)
|
val dividerColor = Color(0xFFDDDDDD)
|
||||||
|
val darkDividerColor = Color(0xFF000000)
|
||||||
val tabTextColor = Color(0xFF040404)
|
val tabTextColor = Color(0xFF040404)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,12 +166,13 @@ internal val DarkExtendedColorPalette =
|
||||||
onTertiary = Dark.textTertiaryButton,
|
onTertiary = Dark.textTertiaryButton,
|
||||||
callout = Dark.callout,
|
callout = Dark.callout,
|
||||||
onCallout = Dark.onCallout,
|
onCallout = Dark.onCallout,
|
||||||
progressStart = Dark.progressStart,
|
progressBarSmall = Dark.progressBarSmall,
|
||||||
progressEnd = Dark.progressEnd,
|
progressBarScreen = Dark.progressBarScreen,
|
||||||
progressBackground = Dark.progressBackground,
|
|
||||||
chipIndex = Dark.textChipIndex,
|
chipIndex = Dark.textChipIndex,
|
||||||
|
textCommon = Dark.textCommon,
|
||||||
textFieldHint = Dark.textFieldHint,
|
textFieldHint = Dark.textFieldHint,
|
||||||
textDescription = Dark.textDescription,
|
textDescription = Dark.textDescription,
|
||||||
|
textPending = Dark.textProgress,
|
||||||
layoutStroke = Dark.layoutStroke,
|
layoutStroke = Dark.layoutStroke,
|
||||||
overlay = Dark.overlay,
|
overlay = Dark.overlay,
|
||||||
highlight = Dark.highlight,
|
highlight = Dark.highlight,
|
||||||
|
@ -189,6 +187,7 @@ internal val DarkExtendedColorPalette =
|
||||||
welcomeAnimationColor = Dark.welcomeAnimationColor,
|
welcomeAnimationColor = Dark.welcomeAnimationColor,
|
||||||
complementaryColor = Dark.complementaryColor,
|
complementaryColor = Dark.complementaryColor,
|
||||||
dividerColor = Dark.dividerColor,
|
dividerColor = Dark.dividerColor,
|
||||||
|
darkDividerColor = Dark.darkDividerColor,
|
||||||
tabTextColor = Dark.tabTextColor,
|
tabTextColor = Dark.tabTextColor,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -200,12 +199,13 @@ internal val LightExtendedColorPalette =
|
||||||
onTertiary = Light.textTertiaryButton,
|
onTertiary = Light.textTertiaryButton,
|
||||||
callout = Light.callout,
|
callout = Light.callout,
|
||||||
onCallout = Light.onCallout,
|
onCallout = Light.onCallout,
|
||||||
progressStart = Light.progressStart,
|
progressBarScreen = Light.progressBarScreen,
|
||||||
progressEnd = Light.progressEnd,
|
progressBarSmall = Light.progressBarSmall,
|
||||||
progressBackground = Light.progressBackground,
|
|
||||||
chipIndex = Light.textChipIndex,
|
chipIndex = Light.textChipIndex,
|
||||||
|
textCommon = Light.textCommon,
|
||||||
textFieldHint = Light.textFieldHint,
|
textFieldHint = Light.textFieldHint,
|
||||||
textDescription = Light.textDescription,
|
textDescription = Light.textDescription,
|
||||||
|
textPending = Light.textProgress,
|
||||||
layoutStroke = Light.layoutStroke,
|
layoutStroke = Light.layoutStroke,
|
||||||
overlay = Light.overlay,
|
overlay = Light.overlay,
|
||||||
highlight = Light.highlight,
|
highlight = Light.highlight,
|
||||||
|
@ -220,7 +220,8 @@ internal val LightExtendedColorPalette =
|
||||||
welcomeAnimationColor = Light.welcomeAnimationColor,
|
welcomeAnimationColor = Light.welcomeAnimationColor,
|
||||||
complementaryColor = Light.complementaryColor,
|
complementaryColor = Light.complementaryColor,
|
||||||
dividerColor = Light.dividerColor,
|
dividerColor = Light.dividerColor,
|
||||||
tabTextColor = Dark.tabTextColor,
|
darkDividerColor = Light.darkDividerColor,
|
||||||
|
tabTextColor = Light.tabTextColor,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Suppress("CompositionLocalAllowlist")
|
@Suppress("CompositionLocalAllowlist")
|
||||||
|
@ -233,12 +234,13 @@ internal val LocalExtendedColors =
|
||||||
onTertiary = Color.Unspecified,
|
onTertiary = Color.Unspecified,
|
||||||
callout = Color.Unspecified,
|
callout = Color.Unspecified,
|
||||||
onCallout = Color.Unspecified,
|
onCallout = Color.Unspecified,
|
||||||
progressStart = Color.Unspecified,
|
progressBarScreen = Color.Unspecified,
|
||||||
progressEnd = Color.Unspecified,
|
progressBarSmall = Color.Unspecified,
|
||||||
progressBackground = Color.Unspecified,
|
|
||||||
chipIndex = Color.Unspecified,
|
chipIndex = Color.Unspecified,
|
||||||
|
textCommon = Color.Unspecified,
|
||||||
textFieldHint = Color.Unspecified,
|
textFieldHint = Color.Unspecified,
|
||||||
textDescription = Color.Unspecified,
|
textDescription = Color.Unspecified,
|
||||||
|
textPending = Color.Unspecified,
|
||||||
layoutStroke = Color.Unspecified,
|
layoutStroke = Color.Unspecified,
|
||||||
overlay = Color.Unspecified,
|
overlay = Color.Unspecified,
|
||||||
highlight = Color.Unspecified,
|
highlight = Color.Unspecified,
|
||||||
|
@ -253,6 +255,7 @@ internal val LocalExtendedColors =
|
||||||
welcomeAnimationColor = Color.Unspecified,
|
welcomeAnimationColor = Color.Unspecified,
|
||||||
complementaryColor = Color.Unspecified,
|
complementaryColor = Color.Unspecified,
|
||||||
dividerColor = Color.Unspecified,
|
dividerColor = Color.Unspecified,
|
||||||
|
darkDividerColor = Color.Unspecified,
|
||||||
tabTextColor = Color.Unspecified
|
tabTextColor = Color.Unspecified
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,8 +73,8 @@ internal val PrimaryTypography =
|
||||||
bodySmall =
|
bodySmall =
|
||||||
TextStyle(
|
TextStyle(
|
||||||
fontFamily = InterFontFamily,
|
fontFamily = InterFontFamily,
|
||||||
fontWeight = FontWeight.Medium,
|
fontWeight = FontWeight.Normal,
|
||||||
fontSize = 16.sp
|
fontSize = 14.sp
|
||||||
),
|
),
|
||||||
labelLarge =
|
labelLarge =
|
||||||
TextStyle(
|
TextStyle(
|
||||||
|
@ -139,18 +139,26 @@ data class Typography(
|
||||||
)
|
)
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class BalanceTextStyles(
|
data class BalanceWidgetTextStyles(
|
||||||
val first: TextStyle,
|
val first: TextStyle,
|
||||||
val second: TextStyle,
|
val second: TextStyle,
|
||||||
val third: TextStyle,
|
val third: TextStyle,
|
||||||
val fourth: TextStyle,
|
val fourth: TextStyle,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class BalanceSingleTextStyles(
|
||||||
|
val first: TextStyle,
|
||||||
|
val second: TextStyle,
|
||||||
|
)
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class ExtendedTypography(
|
data class ExtendedTypography(
|
||||||
val listItem: TextStyle,
|
val listItem: TextStyle,
|
||||||
// Grouping balances text styles to a wrapper class
|
// Grouping balances text styles to a wrapper class for BalanceWidget
|
||||||
val balanceStyles: BalanceTextStyles,
|
val balanceWidgetStyles: BalanceWidgetTextStyles,
|
||||||
|
// Grouping balances text styles to a wrapper class for single balance use case
|
||||||
|
val balanceSingleStyles: BalanceSingleTextStyles,
|
||||||
val addressStyle: TextStyle,
|
val addressStyle: TextStyle,
|
||||||
val aboutText: TextStyle,
|
val aboutText: TextStyle,
|
||||||
val buttonText: TextStyle,
|
val buttonText: TextStyle,
|
||||||
|
@ -180,8 +188,8 @@ val LocalExtendedTypography =
|
||||||
fontSize = 24.sp
|
fontSize = 24.sp
|
||||||
),
|
),
|
||||||
// Note: the order here matters, be careful when reordering
|
// Note: the order here matters, be careful when reordering
|
||||||
balanceStyles =
|
balanceWidgetStyles =
|
||||||
BalanceTextStyles(
|
BalanceWidgetTextStyles(
|
||||||
first =
|
first =
|
||||||
SecondaryTypography.headlineLarge.copy(
|
SecondaryTypography.headlineLarge.copy(
|
||||||
fontSize = 42.sp,
|
fontSize = 42.sp,
|
||||||
|
@ -205,6 +213,19 @@ val LocalExtendedTypography =
|
||||||
fontWeight = FontWeight.Bold
|
fontWeight = FontWeight.Bold
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
balanceSingleStyles =
|
||||||
|
BalanceSingleTextStyles(
|
||||||
|
first =
|
||||||
|
SecondaryTypography.bodySmall.copy(
|
||||||
|
fontSize = 14.sp,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
),
|
||||||
|
second =
|
||||||
|
SecondaryTypography.bodySmall.copy(
|
||||||
|
fontSize = 8.sp,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
)
|
||||||
|
),
|
||||||
addressStyle =
|
addressStyle =
|
||||||
SecondaryTypography.bodyLarge.copy(
|
SecondaryTypography.bodyLarge.copy(
|
||||||
// TODO [#1032]: Addresses can be shown with "×" symbols
|
// TODO [#1032]: Addresses can be shown with "×" symbols
|
||||||
|
|
|
@ -71,7 +71,7 @@ internal class MockSynchronizer : CloseableSynchronizer {
|
||||||
override val transactions: Flow<List<TransactionOverview>>
|
override val transactions: Flow<List<TransactionOverview>>
|
||||||
get() = TODO("Not yet implemented")
|
get() = TODO("Not yet implemented")
|
||||||
|
|
||||||
override val transparentBalances: StateFlow<WalletBalance?>
|
override val transparentBalance: StateFlow<Zatoshi?>
|
||||||
get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
get() = error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
|
@ -98,7 +98,7 @@ internal class MockSynchronizer : CloseableSynchronizer {
|
||||||
error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getTransparentBalance(tAddr: String): WalletBalance {
|
override suspend fun getTransparentBalance(tAddr: String): Zatoshi {
|
||||||
error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.ui.platform.LocalFocusManager
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
import cash.z.ecc.android.sdk.fixture.WalletBalanceFixture
|
||||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||||
import cash.z.ecc.android.sdk.model.ZecSend
|
import cash.z.ecc.android.sdk.model.ZecSend
|
||||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
|
@ -101,8 +101,7 @@ class SendViewTestSetup(
|
||||||
walletSnapshot =
|
walletSnapshot =
|
||||||
WalletSnapshotFixture.new(
|
WalletSnapshotFixture.new(
|
||||||
saplingBalance =
|
saplingBalance =
|
||||||
WalletBalance(
|
WalletBalanceFixture.new(
|
||||||
total = Zatoshi(Zatoshi.MAX_INCLUSIVE.div(100)),
|
|
||||||
available = Zatoshi(Zatoshi.MAX_INCLUSIVE.div(100))
|
available = Zatoshi(Zatoshi.MAX_INCLUSIVE.div(100))
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
|
@ -6,8 +6,8 @@ import androidx.compose.ui.test.junit4.StateRestorationTester
|
||||||
import androidx.compose.ui.test.junit4.createComposeRule
|
import androidx.compose.ui.test.junit4.createComposeRule
|
||||||
import androidx.compose.ui.test.onNodeWithText
|
import androidx.compose.ui.test.onNodeWithText
|
||||||
import androidx.test.filters.MediumTest
|
import androidx.test.filters.MediumTest
|
||||||
|
import cash.z.ecc.android.sdk.fixture.WalletBalanceFixture
|
||||||
import cash.z.ecc.android.sdk.fixture.WalletFixture
|
import cash.z.ecc.android.sdk.fixture.WalletFixture
|
||||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
|
||||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
import cash.z.ecc.sdk.fixture.ZecSendFixture
|
import cash.z.ecc.sdk.fixture.ZecSendFixture
|
||||||
|
@ -44,8 +44,7 @@ class SendViewIntegrationTest {
|
||||||
private val walletSnapshot =
|
private val walletSnapshot =
|
||||||
WalletSnapshotFixture.new(
|
WalletSnapshotFixture.new(
|
||||||
saplingBalance =
|
saplingBalance =
|
||||||
WalletBalance(
|
WalletBalanceFixture.new(
|
||||||
total = Zatoshi(Zatoshi.MAX_INCLUSIVE.div(100)),
|
|
||||||
available = Zatoshi(Zatoshi.MAX_INCLUSIVE.div(100))
|
available = Zatoshi(Zatoshi.MAX_INCLUSIVE.div(100))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -17,12 +17,10 @@ import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.tooling.preview.Devices
|
import androidx.compose.ui.tooling.preview.Devices
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
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.WalletBalance
|
||||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||||
import cash.z.ecc.android.sdk.model.toZecString
|
import cash.z.ecc.android.sdk.model.toZecString
|
||||||
import cash.z.ecc.sdk.type.ZcashCurrency
|
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.WalletSnapshot
|
||||||
import co.electriccoin.zcash.ui.common.model.spendableBalance
|
import co.electriccoin.zcash.ui.common.model.spendableBalance
|
||||||
import co.electriccoin.zcash.ui.common.model.totalBalance
|
import co.electriccoin.zcash.ui.common.model.totalBalance
|
||||||
|
@ -33,7 +31,6 @@ import co.electriccoin.zcash.ui.design.component.Reference
|
||||||
import co.electriccoin.zcash.ui.design.component.StyledBalance
|
import co.electriccoin.zcash.ui.design.component.StyledBalance
|
||||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
import co.electriccoin.zcash.ui.fixture.WalletSnapshotFixture
|
import co.electriccoin.zcash.ui.fixture.WalletSnapshotFixture
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
@Preview(device = Devices.PIXEL_2)
|
@Preview(device = Devices.PIXEL_2)
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -49,7 +46,8 @@ private fun BalanceWidgetPreview() {
|
||||||
saplingBalance =
|
saplingBalance =
|
||||||
WalletBalance(
|
WalletBalance(
|
||||||
Zatoshi(1234567891234567),
|
Zatoshi(1234567891234567),
|
||||||
Zatoshi(123456789)
|
Zatoshi(123456789),
|
||||||
|
Zatoshi(123)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
isReferenceToBalances = true,
|
isReferenceToBalances = true,
|
||||||
|
@ -60,26 +58,6 @@ private fun BalanceWidgetPreview() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
@Composable
|
||||||
@Suppress("LongMethod")
|
@Suppress("LongMethod")
|
||||||
fun BalanceWidget(
|
fun BalanceWidget(
|
||||||
|
@ -95,18 +73,15 @@ fun BalanceWidget(
|
||||||
.then(modifier),
|
.then(modifier),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
val totalBalanceSplit = splitBalance(walletSnapshot.totalBalance().toZecString())
|
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
StyledBalance(
|
StyledBalance(
|
||||||
mainPart = totalBalanceSplit.first,
|
balanceString = walletSnapshot.totalBalance().toZecString(),
|
||||||
secondPart = totalBalanceSplit.second,
|
|
||||||
textStyles =
|
textStyles =
|
||||||
Pair(
|
Pair(
|
||||||
ZcashTheme.extendedTypography.balanceStyles.first,
|
ZcashTheme.extendedTypography.balanceWidgetStyles.first,
|
||||||
ZcashTheme.extendedTypography.balanceStyles.second
|
ZcashTheme.extendedTypography.balanceWidgetStyles.second
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -136,15 +111,12 @@ fun BalanceWidget(
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(ZcashTheme.dimens.spacingTiny))
|
Spacer(modifier = Modifier.width(ZcashTheme.dimens.spacingTiny))
|
||||||
|
|
||||||
val availableBalanceSplit = splitBalance(walletSnapshot.spendableBalance().toZecString())
|
|
||||||
|
|
||||||
StyledBalance(
|
StyledBalance(
|
||||||
mainPart = availableBalanceSplit.first,
|
balanceString = walletSnapshot.spendableBalance().toZecString(),
|
||||||
secondPart = availableBalanceSplit.second,
|
|
||||||
textStyles =
|
textStyles =
|
||||||
Pair(
|
Pair(
|
||||||
ZcashTheme.extendedTypography.balanceStyles.third,
|
ZcashTheme.extendedTypography.balanceWidgetStyles.third,
|
||||||
ZcashTheme.extendedTypography.balanceStyles.fourth
|
ZcashTheme.extendedTypography.balanceWidgetStyles.fourth
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ data class WalletSnapshot(
|
||||||
val processorInfo: CompactBlockProcessor.ProcessorInfo,
|
val processorInfo: CompactBlockProcessor.ProcessorInfo,
|
||||||
val orchardBalance: WalletBalance,
|
val orchardBalance: WalletBalance,
|
||||||
val saplingBalance: WalletBalance,
|
val saplingBalance: WalletBalance,
|
||||||
val transparentBalance: WalletBalance,
|
val transparentBalance: Zatoshi,
|
||||||
val progress: PercentDecimal,
|
val progress: PercentDecimal,
|
||||||
val synchronizerError: SynchronizerError?
|
val synchronizerError: SynchronizerError?
|
||||||
) {
|
) {
|
||||||
|
@ -28,9 +28,15 @@ data class WalletSnapshot(
|
||||||
val isSendEnabled: Boolean get() = status == Synchronizer.Status.SYNCED && hasFunds
|
val isSendEnabled: Boolean get() = status == Synchronizer.Status.SYNCED && hasFunds
|
||||||
}
|
}
|
||||||
|
|
||||||
fun WalletSnapshot.totalBalance() = orchardBalance.total + saplingBalance.total + transparentBalance.total
|
fun WalletSnapshot.totalBalance() = orchardBalance.total + saplingBalance.total + transparentBalance
|
||||||
|
|
||||||
// Note that considering both to be spendable is subject to change.
|
// Note that considering both to be spendable is subject to change.
|
||||||
// The user experience could be confusing, and in the future we might prefer to ask users
|
// The user experience could be confusing, and in the future we might prefer to ask users
|
||||||
// to transfer their balance to the latest balance type to make it spendable.
|
// to transfer their balance to the latest balance type to make it spendable.
|
||||||
fun WalletSnapshot.spendableBalance() = orchardBalance.available + saplingBalance.available
|
fun WalletSnapshot.spendableBalance() = orchardBalance.available + saplingBalance.available
|
||||||
|
|
||||||
|
// Note that summing both values could be confusing, and we might prefer dividing them in the future
|
||||||
|
fun WalletSnapshot.changePendingBalance() = orchardBalance.changePending + saplingBalance.changePending
|
||||||
|
|
||||||
|
// Note that summing both values could be confusing, and we might prefer dividing them in the future
|
||||||
|
fun WalletSnapshot.valuePendingBalance() = orchardBalance.valuePending + saplingBalance.valuePending
|
||||||
|
|
|
@ -378,7 +378,7 @@ private fun Synchronizer.toWalletSnapshot() =
|
||||||
// 3
|
// 3
|
||||||
saplingBalances,
|
saplingBalances,
|
||||||
// 4
|
// 4
|
||||||
transparentBalances,
|
transparentBalance,
|
||||||
// 5
|
// 5
|
||||||
progress,
|
progress,
|
||||||
// 6
|
// 6
|
||||||
|
@ -386,16 +386,16 @@ private fun Synchronizer.toWalletSnapshot() =
|
||||||
) { flows ->
|
) { flows ->
|
||||||
val orchardBalance = flows[2] as WalletBalance?
|
val orchardBalance = flows[2] as WalletBalance?
|
||||||
val saplingBalance = flows[3] as WalletBalance?
|
val saplingBalance = flows[3] as WalletBalance?
|
||||||
val transparentBalance = flows[4] as WalletBalance?
|
val transparentBalance = flows[4] as Zatoshi?
|
||||||
|
|
||||||
val progressPercentDecimal = flows[5] as PercentDecimal
|
val progressPercentDecimal = flows[5] as PercentDecimal
|
||||||
|
|
||||||
WalletSnapshot(
|
WalletSnapshot(
|
||||||
flows[0] as Synchronizer.Status,
|
flows[0] as Synchronizer.Status,
|
||||||
flows[1] as CompactBlockProcessor.ProcessorInfo,
|
flows[1] as CompactBlockProcessor.ProcessorInfo,
|
||||||
orchardBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0)),
|
orchardBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0), Zatoshi(0)),
|
||||||
saplingBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0)),
|
saplingBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0), Zatoshi(0)),
|
||||||
transparentBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0)),
|
transparentBalance ?: Zatoshi(0),
|
||||||
progressPercentDecimal,
|
progressPercentDecimal,
|
||||||
flows[6] as SynchronizerError?
|
flows[6] as SynchronizerError?
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,9 +2,11 @@ package co.electriccoin.zcash.ui.fixture
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.Synchronizer
|
import cash.z.ecc.android.sdk.Synchronizer
|
||||||
import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor
|
import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor
|
||||||
|
import cash.z.ecc.android.sdk.fixture.WalletBalanceFixture
|
||||||
import cash.z.ecc.android.sdk.model.PercentDecimal
|
import cash.z.ecc.android.sdk.model.PercentDecimal
|
||||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||||
|
import cash.z.ecc.sdk.fixture.ZatoshiFixture
|
||||||
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||||
import co.electriccoin.zcash.ui.common.viewmodel.SynchronizerError
|
import co.electriccoin.zcash.ui.common.viewmodel.SynchronizerError
|
||||||
|
|
||||||
|
@ -12,9 +14,9 @@ import co.electriccoin.zcash.ui.common.viewmodel.SynchronizerError
|
||||||
object WalletSnapshotFixture {
|
object WalletSnapshotFixture {
|
||||||
val STATUS = Synchronizer.Status.SYNCED
|
val STATUS = Synchronizer.Status.SYNCED
|
||||||
val PROGRESS = PercentDecimal.ZERO_PERCENT
|
val PROGRESS = PercentDecimal.ZERO_PERCENT
|
||||||
val TRANSPARENT_BALANCE: WalletBalance = WalletBalance(Zatoshi(8), Zatoshi(1))
|
val TRANSPARENT_BALANCE: Zatoshi = ZatoshiFixture.new(8)
|
||||||
val ORCHARD_BALANCE: WalletBalance = WalletBalance(Zatoshi(5), Zatoshi(2))
|
val ORCHARD_BALANCE: WalletBalance = WalletBalanceFixture.newLong(8, 2, 1)
|
||||||
val SAPLING_BALANCE: WalletBalance = WalletBalance(Zatoshi(4), Zatoshi(4))
|
val SAPLING_BALANCE: WalletBalance = WalletBalanceFixture.newLong(5, 2, 1)
|
||||||
|
|
||||||
// Should fill in with non-empty values for better example values in tests and UI previews
|
// Should fill in with non-empty values for better example values in tests and UI previews
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
|
@ -28,7 +30,7 @@ object WalletSnapshotFixture {
|
||||||
),
|
),
|
||||||
orchardBalance: WalletBalance = ORCHARD_BALANCE,
|
orchardBalance: WalletBalance = ORCHARD_BALANCE,
|
||||||
saplingBalance: WalletBalance = SAPLING_BALANCE,
|
saplingBalance: WalletBalance = SAPLING_BALANCE,
|
||||||
transparentBalance: WalletBalance = TRANSPARENT_BALANCE,
|
transparentBalance: Zatoshi = TRANSPARENT_BALANCE,
|
||||||
progress: PercentDecimal = PROGRESS,
|
progress: PercentDecimal = PROGRESS,
|
||||||
synchronizerError: SynchronizerError? = null
|
synchronizerError: SynchronizerError? = null
|
||||||
) = WalletSnapshot(
|
) = WalletSnapshot(
|
||||||
|
|
|
@ -1,32 +1,49 @@
|
||||||
package co.electriccoin.zcash.ui.screen.balances.view
|
package co.electriccoin.zcash.ui.screen.balances.view
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.Divider
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.res.vectorResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import cash.z.ecc.android.sdk.model.toZecString
|
||||||
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.BalanceWidget
|
||||||
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||||
|
import co.electriccoin.zcash.ui.common.model.changePendingBalance
|
||||||
|
import co.electriccoin.zcash.ui.common.model.spendableBalance
|
||||||
|
import co.electriccoin.zcash.ui.common.model.valuePendingBalance
|
||||||
import co.electriccoin.zcash.ui.common.test.CommonTag
|
import co.electriccoin.zcash.ui.common.test.CommonTag
|
||||||
import co.electriccoin.zcash.ui.design.component.Body
|
import co.electriccoin.zcash.ui.design.component.Body
|
||||||
|
import co.electriccoin.zcash.ui.design.component.BodySmall
|
||||||
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
|
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
|
||||||
|
import co.electriccoin.zcash.ui.design.component.CircularSmallProgressIndicator
|
||||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||||
import co.electriccoin.zcash.ui.design.component.SmallTopAppBar
|
import co.electriccoin.zcash.ui.design.component.SmallTopAppBar
|
||||||
|
import co.electriccoin.zcash.ui.design.component.StyledBalance
|
||||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
import co.electriccoin.zcash.ui.fixture.WalletSnapshotFixture
|
import co.electriccoin.zcash.ui.fixture.WalletSnapshotFixture
|
||||||
import co.electriccoin.zcash.ui.screen.account.model.WalletDisplayValues
|
import co.electriccoin.zcash.ui.screen.account.model.WalletDisplayValues
|
||||||
|
@ -106,7 +123,7 @@ private fun BalancesMainContent(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
// .verticalScroll(rememberScrollState()) Uncomment this once the whole screen UI is implemented
|
.verticalScroll(rememberScrollState())
|
||||||
.then(modifier),
|
.then(modifier),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
|
@ -118,20 +135,157 @@ private fun BalancesMainContent(
|
||||||
isReferenceToBalances = false,
|
isReferenceToBalances = false,
|
||||||
onReferenceClick = {}
|
onReferenceClick = {}
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingHuge))
|
||||||
|
|
||||||
|
Divider(
|
||||||
|
color = ZcashTheme.colors.darkDividerColor,
|
||||||
|
thickness = ZcashTheme.dimens.divider
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
|
||||||
|
|
||||||
|
BalancesOverview(walletSnapshot)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
verticalArrangement = Arrangement.Center,
|
verticalArrangement = Arrangement.Center,
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingHuge))
|
||||||
|
|
||||||
Body(
|
Body(
|
||||||
text = stringResource(id = R.string.balances_coming_soon),
|
text = stringResource(id = R.string.balances_coming_soon),
|
||||||
textAlign = TextAlign.Center
|
textAlign = TextAlign.Center
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun BalancesOverview(walletSnapshot: WalletSnapshot) {
|
||||||
|
Column {
|
||||||
|
SpendableBalanceRow(walletSnapshot)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
|
||||||
|
|
||||||
|
ChangePendingRow(walletSnapshot)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
|
||||||
|
|
||||||
|
// aka value pending
|
||||||
|
PendingTransactionsRow(walletSnapshot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const val TEXT_PART_WIDTH_RATIO = 0.6f
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SpendableBalanceRow(walletSnapshot: WalletSnapshot) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
BodySmall(
|
||||||
|
text = stringResource(id = R.string.balances_shielded_spendable).uppercase(),
|
||||||
|
modifier = Modifier.fillMaxWidth(TEXT_PART_WIDTH_RATIO)
|
||||||
|
)
|
||||||
|
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
StyledBalance(
|
||||||
|
balanceString = walletSnapshot.spendableBalance().toZecString(),
|
||||||
|
textStyles =
|
||||||
|
Pair(
|
||||||
|
ZcashTheme.extendedTypography.balanceSingleStyles.first,
|
||||||
|
ZcashTheme.extendedTypography.balanceSingleStyles.second
|
||||||
|
),
|
||||||
|
textColor = ZcashTheme.colors.textCommon
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(12.dp))
|
||||||
|
|
||||||
|
Icon(
|
||||||
|
imageVector = ImageVector.vectorResource(R.drawable.balance_shield),
|
||||||
|
contentDescription = null,
|
||||||
|
// The same size as the following progress bars
|
||||||
|
modifier = Modifier.width(ZcashTheme.dimens.circularSmallProgressWidth)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ChangePendingRow(walletSnapshot: WalletSnapshot) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
BodySmall(
|
||||||
|
text = stringResource(id = R.string.balances_change_pending).uppercase(),
|
||||||
|
modifier = Modifier.fillMaxWidth(TEXT_PART_WIDTH_RATIO)
|
||||||
|
)
|
||||||
|
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
val changePendingHasValue = walletSnapshot.changePendingBalance().value > 0L
|
||||||
|
|
||||||
|
StyledBalance(
|
||||||
|
balanceString = walletSnapshot.changePendingBalance().toZecString(),
|
||||||
|
textStyles =
|
||||||
|
Pair(
|
||||||
|
ZcashTheme.extendedTypography.balanceSingleStyles.first,
|
||||||
|
ZcashTheme.extendedTypography.balanceSingleStyles.second
|
||||||
|
),
|
||||||
|
textColor = ZcashTheme.colors.textPending
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(12.dp))
|
||||||
|
|
||||||
|
Box(Modifier.width(ZcashTheme.dimens.circularSmallProgressWidth)) {
|
||||||
|
if (changePendingHasValue) {
|
||||||
|
CircularSmallProgressIndicator()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PendingTransactionsRow(walletSnapshot: WalletSnapshot) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
BodySmall(
|
||||||
|
text = stringResource(id = R.string.balances_pending_transactions).uppercase(),
|
||||||
|
modifier = Modifier.fillMaxWidth(TEXT_PART_WIDTH_RATIO)
|
||||||
|
)
|
||||||
|
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
val valuePendingHasValue = walletSnapshot.valuePendingBalance().value > 0L
|
||||||
|
|
||||||
|
StyledBalance(
|
||||||
|
balanceString = walletSnapshot.valuePendingBalance().toZecString(),
|
||||||
|
textStyles =
|
||||||
|
Pair(
|
||||||
|
ZcashTheme.extendedTypography.balanceSingleStyles.first,
|
||||||
|
ZcashTheme.extendedTypography.balanceSingleStyles.second
|
||||||
|
),
|
||||||
|
textColor = ZcashTheme.colors.textPending
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(12.dp))
|
||||||
|
|
||||||
|
Box(Modifier.width(ZcashTheme.dimens.circularSmallProgressWidth)) {
|
||||||
|
if (valuePendingHasValue) {
|
||||||
|
CircularSmallProgressIndicator()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="11dp"
|
||||||
|
android:height="14dp"
|
||||||
|
android:viewportWidth="11"
|
||||||
|
android:viewportHeight="14">
|
||||||
|
<group>
|
||||||
|
<clip-path
|
||||||
|
android:pathData="M0,0h11v14h-11z"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M10.727,1.675L5.61,0.032C5.537,0.004 5.463,0.004 5.39,0.032L0.272,1.675C0.04,1.748 0,1.804 0,2.067V8.092C0,8.875 0.297,9.677 0.881,10.476C1.328,11.086 1.946,11.698 2.717,12.295C4.014,13.3 5.291,13.916 5.344,13.941C5.448,13.993 5.552,13.993 5.657,13.941C5.71,13.916 6.986,13.3 8.284,12.295C9.055,11.698 9.673,11.085 10.12,10.476C10.704,9.677 11.001,8.875 11.001,8.092V2.067C10.988,1.794 10.915,1.756 10.729,1.675H10.727Z"
|
||||||
|
android:fillColor="#231F20"/>
|
||||||
|
</group>
|
||||||
|
</vector>
|
|
@ -1,5 +1,8 @@
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="balances_title">Balances</string>
|
<string name="balances_title">Balances</string>
|
||||||
<string name="balances_coming_soon">Coming soon:\n\nBalances overview,\nTransparent
|
<string name="balances_shielded_spendable">Shielded zec (spendable)</string>
|
||||||
|
<string name="balances_change_pending">Change pending</string>
|
||||||
|
<string name="balances_pending_transactions">Pending transactions</string>
|
||||||
|
<string name="balances_coming_soon">Coming soon:\n\nTransparent
|
||||||
funds shielding,\nBlock synchronization indicator</string>
|
funds shielding,\nBlock synchronization indicator</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue