[#1165] Syncing progressbar
* [#1165] Syncing progressbar - UI + logic + tests - Closes #1165 * Changelog update
This commit is contained in:
parent
1058802b19
commit
cc333ea902
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -9,10 +9,18 @@ directly impact users rather than highlighting other key architectural updates.*
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Update the Zcash SDK dependency to version 2.0.6, which adds more details on current balances
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- The Balances screen now provides details on current balances like Change pending and Pending transactions
|
||||||
|
- The screen also adds a new Block synchronization progress bar and status, which were initially part of the Account
|
||||||
|
screen and redesigned
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fixed character replacement in Zcash addresses on the Receive screen caused by ligatures in the app's primary font
|
- Fixed character replacement in Zcash addresses on the Receive screen caused by ligatures in the app's primary font
|
||||||
using the secondary font. This will be revisited once a proper font is added.
|
using the secondary font. This will be revisited once a proper font is added.
|
||||||
- Improved spacing of titles of bottom navigation tabs so they work better on smaller screens
|
- Improved spacing of titles of bottom navigation tabs, so they work better on smaller screens
|
||||||
|
|
||||||
## [0.2.0 (541)] - 2024-01-30
|
## [0.2.0 (541)] - 2024-01-30
|
||||||
- Update the Zcash SDK dependency to version 2.0.5, which improves the performance of block synchronization
|
- Update the Zcash SDK dependency to version 2.0.5, which improves the performance of block synchronization
|
||||||
|
|
|
@ -3,11 +3,15 @@ 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.Column
|
||||||
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.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.LinearProgressIndicator
|
||||||
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.StrokeCap
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
|
@ -35,7 +39,7 @@ fun CircularScreenProgressIndicator(modifier: Modifier = Modifier) {
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
CircularProgressIndicator(
|
CircularProgressIndicator(
|
||||||
color = ZcashTheme.colors.progressBarScreen,
|
color = ZcashTheme.colors.circularProgressBarScreen,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.size(ZcashTheme.dimens.circularScreenProgressWidth)
|
.size(ZcashTheme.dimens.circularScreenProgressWidth)
|
||||||
|
@ -46,7 +50,7 @@ fun CircularScreenProgressIndicator(modifier: Modifier = Modifier) {
|
||||||
@Composable
|
@Composable
|
||||||
fun CircularSmallProgressIndicator(modifier: Modifier = Modifier) {
|
fun CircularSmallProgressIndicator(modifier: Modifier = Modifier) {
|
||||||
CircularProgressIndicator(
|
CircularProgressIndicator(
|
||||||
color = ZcashTheme.colors.progressBarSmall,
|
color = ZcashTheme.colors.circularProgressBarSmall,
|
||||||
strokeWidth = 2.dp,
|
strokeWidth = 2.dp,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
|
@ -54,3 +58,32 @@ fun CircularSmallProgressIndicator(modifier: Modifier = Modifier) {
|
||||||
.then(modifier)
|
.then(modifier)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun LinearProgressIndicatorComposablePreview() {
|
||||||
|
ZcashTheme(forceDarkMode = false) {
|
||||||
|
GradientSurface {
|
||||||
|
@Suppress("MagicNumber")
|
||||||
|
LinearProgressIndicator(0.75f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LinearProgressIndicator(
|
||||||
|
progress: Float,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
LinearProgressIndicator(
|
||||||
|
progress = progress,
|
||||||
|
color = ZcashTheme.colors.linearProgressBarBackground,
|
||||||
|
trackColor = ZcashTheme.colors.linearProgressBarTrack,
|
||||||
|
strokeCap = StrokeCap.Butt,
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(ZcashTheme.dimens.linearProgressHeight)
|
||||||
|
.then(modifier)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -125,6 +125,7 @@ fun BodySmall(
|
||||||
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(
|
||||||
|
@ -135,6 +136,7 @@ fun BodySmall(
|
||||||
textAlign = textAlign,
|
textAlign = textAlign,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
fontWeight = textFontWeight
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ data class Dimens(
|
||||||
// Progress
|
// Progress
|
||||||
val circularScreenProgressWidth: Dp,
|
val circularScreenProgressWidth: Dp,
|
||||||
val circularSmallProgressWidth: Dp,
|
val circularSmallProgressWidth: Dp,
|
||||||
|
val linearProgressHeight: Dp,
|
||||||
// TopAppBar:
|
// TopAppBar:
|
||||||
val topAppBarZcashLogoHeight: Dp,
|
val topAppBarZcashLogoHeight: Dp,
|
||||||
val topAppBarActionRippleCorner: Dp,
|
val topAppBarActionRippleCorner: Dp,
|
||||||
|
@ -67,6 +68,7 @@ private val defaultDimens =
|
||||||
chipStroke = 0.5.dp,
|
chipStroke = 0.5.dp,
|
||||||
circularScreenProgressWidth = 48.dp,
|
circularScreenProgressWidth = 48.dp,
|
||||||
circularSmallProgressWidth = 14.dp,
|
circularSmallProgressWidth = 14.dp,
|
||||||
|
linearProgressHeight = 14.dp,
|
||||||
topAppBarZcashLogoHeight = 24.dp,
|
topAppBarZcashLogoHeight = 24.dp,
|
||||||
topAppBarActionRippleCorner = 28.dp,
|
topAppBarActionRippleCorner = 28.dp,
|
||||||
textFieldDefaultHeight = 64.dp,
|
textFieldDefaultHeight = 64.dp,
|
||||||
|
|
|
@ -14,8 +14,10 @@ data class ExtendedColors(
|
||||||
val onTertiary: Color,
|
val onTertiary: Color,
|
||||||
val callout: Color,
|
val callout: Color,
|
||||||
val onCallout: Color,
|
val onCallout: Color,
|
||||||
val progressBarSmall: Color,
|
val circularProgressBarSmall: Color,
|
||||||
val progressBarScreen: Color,
|
val circularProgressBarScreen: Color,
|
||||||
|
val linearProgressBarTrack: Color,
|
||||||
|
val linearProgressBarBackground: Color,
|
||||||
val chipIndex: Color,
|
val chipIndex: Color,
|
||||||
val textCommon: Color,
|
val textCommon: Color,
|
||||||
val textFieldHint: Color,
|
val textFieldHint: Color,
|
||||||
|
@ -37,6 +39,7 @@ data class ExtendedColors(
|
||||||
val dividerColor: Color,
|
val dividerColor: Color,
|
||||||
val darkDividerColor: Color,
|
val darkDividerColor: Color,
|
||||||
val tabTextColor: Color,
|
val tabTextColor: Color,
|
||||||
|
val panelBackgroundColor: Color,
|
||||||
) {
|
) {
|
||||||
@Composable
|
@Composable
|
||||||
fun surfaceGradient() =
|
fun surfaceGradient() =
|
||||||
|
|
|
@ -30,7 +30,15 @@ internal object Dark {
|
||||||
val textDescription = Color(0xFF777777)
|
val textDescription = Color(0xFF777777)
|
||||||
val textProgress = Color(0xFF8B8A8A)
|
val textProgress = Color(0xFF8B8A8A)
|
||||||
|
|
||||||
|
val aboutTextColor = Color.Unspecified
|
||||||
|
val screenTitleColor = Color(0xFF040404)
|
||||||
|
val welcomeAnimationColor = Color(0xFF231F20)
|
||||||
|
val complementaryColor = Color(0xFFF4B728)
|
||||||
|
val dividerColor = Color(0xFFDDDDDD)
|
||||||
|
val darkDividerColor = Color(0xFF000000)
|
||||||
|
val tabTextColor = Color(0xFF040404)
|
||||||
val layoutStroke = Color(0xFFFFFFFF)
|
val layoutStroke = Color(0xFFFFFFFF)
|
||||||
|
val panelBackgroundColor = Color(0xFFEAEAEA)
|
||||||
|
|
||||||
val primaryButton = Color(0xFFFFFFFF)
|
val primaryButton = Color(0xFFFFFFFF)
|
||||||
val primaryButtonPressed = Color(0xFFFFFFFF)
|
val primaryButtonPressed = Color(0xFFFFFFFF)
|
||||||
|
@ -46,8 +54,10 @@ internal object Dark {
|
||||||
val navigationButton = Color(0xFFFFFFFF)
|
val navigationButton = Color(0xFFFFFFFF)
|
||||||
val navigationButtonPressed = Color(0xFFFFFFFF)
|
val navigationButtonPressed = Color(0xFFFFFFFF)
|
||||||
|
|
||||||
val progressBarSmall = Color(0xFF8B8A8A)
|
val circularProgressBarSmall = Color(0xFF8B8A8A)
|
||||||
val progressBarScreen = Color(0xFFFFFFFF)
|
val circularProgressBarScreen = Color(0xFFFFFFFF)
|
||||||
|
val linearProgressBarTrack = Color(0xFFD9D9D9)
|
||||||
|
val linearProgressBarBackground = Light.complementaryColor
|
||||||
|
|
||||||
val callout = Color(0xFFFFFFFF)
|
val callout = Color(0xFFFFFFFF)
|
||||||
val onCallout = Color(0xFFFFFFFF)
|
val onCallout = Color(0xFFFFFFFF)
|
||||||
|
@ -64,15 +74,6 @@ internal object Dark {
|
||||||
val disabledButtonTextColor = Color(0xFFDDDDDD)
|
val disabledButtonTextColor = Color(0xFFDDDDDD)
|
||||||
|
|
||||||
val buttonShadowColor = Color(0xFFFFFFFF)
|
val buttonShadowColor = Color(0xFFFFFFFF)
|
||||||
|
|
||||||
// Proper values will be added later, see #998
|
|
||||||
val aboutTextColor = Color.Unspecified
|
|
||||||
val screenTitleColor = Color(0xFF040404)
|
|
||||||
val welcomeAnimationColor = Color(0xFF231F20)
|
|
||||||
val complementaryColor = Color(0xFFF4B728)
|
|
||||||
val dividerColor = Color(0xFFDDDDDD)
|
|
||||||
val darkDividerColor = Color(0xFF000000)
|
|
||||||
val tabTextColor = Color(0xFF040404)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal object Light {
|
internal object Light {
|
||||||
|
@ -91,7 +92,15 @@ internal object Light {
|
||||||
val textDescription = Color(0xFF777777)
|
val textDescription = Color(0xFF777777)
|
||||||
val textProgress = Color(0xFF8B8A8A)
|
val textProgress = Color(0xFF8B8A8A)
|
||||||
|
|
||||||
|
val screenTitleColor = Color(0xFF040404)
|
||||||
|
val aboutTextColor = Color(0xFF4E4E4E)
|
||||||
|
val welcomeAnimationColor = Color(0xFF231F20)
|
||||||
|
val complementaryColor = Color(0xFFF4B728)
|
||||||
|
val dividerColor = Color(0xFFDDDDDD)
|
||||||
|
val darkDividerColor = Color(0xFF000000)
|
||||||
|
val tabTextColor = Color(0xFF040404)
|
||||||
val layoutStroke = Color(0xFF000000)
|
val layoutStroke = Color(0xFF000000)
|
||||||
|
val panelBackgroundColor = Color(0xFFEAEAEA)
|
||||||
|
|
||||||
val primaryButton = Color(0xFF000000)
|
val primaryButton = Color(0xFF000000)
|
||||||
val primaryButtonPressed = Color(0xFF000000)
|
val primaryButtonPressed = Color(0xFF000000)
|
||||||
|
@ -107,8 +116,10 @@ internal object Light {
|
||||||
val navigationButton = Color(0xFFFFFFFF)
|
val navigationButton = Color(0xFFFFFFFF)
|
||||||
val navigationButtonPressed = Color(0xFFFFFFFF)
|
val navigationButtonPressed = Color(0xFFFFFFFF)
|
||||||
|
|
||||||
val progressBarSmall = Color(0xFF8B8A8A)
|
val circularProgressBarSmall = Color(0xFF8B8A8A)
|
||||||
val progressBarScreen = Color(0xFF000000)
|
val circularProgressBarScreen = Color(0xFF000000)
|
||||||
|
val linearProgressBarTrack = Color(0xFFD9D9D9)
|
||||||
|
val linearProgressBarBackground = complementaryColor
|
||||||
|
|
||||||
val callout = Color(0xFFFFFFFF)
|
val callout = Color(0xFFFFFFFF)
|
||||||
val onCallout = Color(0xFFFFFFFF)
|
val onCallout = Color(0xFFFFFFFF)
|
||||||
|
@ -124,14 +135,6 @@ internal object Light {
|
||||||
val disabledButtonColor = Color(0xFFB7B7B7)
|
val disabledButtonColor = Color(0xFFB7B7B7)
|
||||||
val disabledButtonTextColor = Color(0xFFDDDDDD)
|
val disabledButtonTextColor = Color(0xFFDDDDDD)
|
||||||
val buttonShadowColor = Color(0xFF000000)
|
val buttonShadowColor = Color(0xFF000000)
|
||||||
|
|
||||||
val screenTitleColor = Color(0xFF040404)
|
|
||||||
val aboutTextColor = Color(0xFF4E4E4E)
|
|
||||||
val welcomeAnimationColor = Color(0xFF231F20)
|
|
||||||
val complementaryColor = Color(0xFFF4B728)
|
|
||||||
val dividerColor = Color(0xFFDDDDDD)
|
|
||||||
val darkDividerColor = Color(0xFF000000)
|
|
||||||
val tabTextColor = Color(0xFF040404)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val DarkColorPalette =
|
internal val DarkColorPalette =
|
||||||
|
@ -166,8 +169,10 @@ internal val DarkExtendedColorPalette =
|
||||||
onTertiary = Dark.textTertiaryButton,
|
onTertiary = Dark.textTertiaryButton,
|
||||||
callout = Dark.callout,
|
callout = Dark.callout,
|
||||||
onCallout = Dark.onCallout,
|
onCallout = Dark.onCallout,
|
||||||
progressBarSmall = Dark.progressBarSmall,
|
circularProgressBarSmall = Dark.circularProgressBarSmall,
|
||||||
progressBarScreen = Dark.progressBarScreen,
|
circularProgressBarScreen = Dark.circularProgressBarScreen,
|
||||||
|
linearProgressBarTrack = Dark.linearProgressBarTrack,
|
||||||
|
linearProgressBarBackground = Dark.linearProgressBarBackground,
|
||||||
chipIndex = Dark.textChipIndex,
|
chipIndex = Dark.textChipIndex,
|
||||||
textCommon = Dark.textCommon,
|
textCommon = Dark.textCommon,
|
||||||
textFieldHint = Dark.textFieldHint,
|
textFieldHint = Dark.textFieldHint,
|
||||||
|
@ -189,6 +194,7 @@ internal val DarkExtendedColorPalette =
|
||||||
dividerColor = Dark.dividerColor,
|
dividerColor = Dark.dividerColor,
|
||||||
darkDividerColor = Dark.darkDividerColor,
|
darkDividerColor = Dark.darkDividerColor,
|
||||||
tabTextColor = Dark.tabTextColor,
|
tabTextColor = Dark.tabTextColor,
|
||||||
|
panelBackgroundColor = Dark.panelBackgroundColor,
|
||||||
)
|
)
|
||||||
|
|
||||||
internal val LightExtendedColorPalette =
|
internal val LightExtendedColorPalette =
|
||||||
|
@ -199,8 +205,10 @@ internal val LightExtendedColorPalette =
|
||||||
onTertiary = Light.textTertiaryButton,
|
onTertiary = Light.textTertiaryButton,
|
||||||
callout = Light.callout,
|
callout = Light.callout,
|
||||||
onCallout = Light.onCallout,
|
onCallout = Light.onCallout,
|
||||||
progressBarScreen = Light.progressBarScreen,
|
circularProgressBarScreen = Light.circularProgressBarScreen,
|
||||||
progressBarSmall = Light.progressBarSmall,
|
circularProgressBarSmall = Light.circularProgressBarSmall,
|
||||||
|
linearProgressBarTrack = Light.linearProgressBarTrack,
|
||||||
|
linearProgressBarBackground = Light.linearProgressBarBackground,
|
||||||
chipIndex = Light.textChipIndex,
|
chipIndex = Light.textChipIndex,
|
||||||
textCommon = Light.textCommon,
|
textCommon = Light.textCommon,
|
||||||
textFieldHint = Light.textFieldHint,
|
textFieldHint = Light.textFieldHint,
|
||||||
|
@ -222,6 +230,7 @@ internal val LightExtendedColorPalette =
|
||||||
dividerColor = Light.dividerColor,
|
dividerColor = Light.dividerColor,
|
||||||
darkDividerColor = Light.darkDividerColor,
|
darkDividerColor = Light.darkDividerColor,
|
||||||
tabTextColor = Light.tabTextColor,
|
tabTextColor = Light.tabTextColor,
|
||||||
|
panelBackgroundColor = Light.panelBackgroundColor,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Suppress("CompositionLocalAllowlist")
|
@Suppress("CompositionLocalAllowlist")
|
||||||
|
@ -234,8 +243,10 @@ internal val LocalExtendedColors =
|
||||||
onTertiary = Color.Unspecified,
|
onTertiary = Color.Unspecified,
|
||||||
callout = Color.Unspecified,
|
callout = Color.Unspecified,
|
||||||
onCallout = Color.Unspecified,
|
onCallout = Color.Unspecified,
|
||||||
progressBarScreen = Color.Unspecified,
|
circularProgressBarScreen = Color.Unspecified,
|
||||||
progressBarSmall = Color.Unspecified,
|
circularProgressBarSmall = Color.Unspecified,
|
||||||
|
linearProgressBarTrack = Color.Unspecified,
|
||||||
|
linearProgressBarBackground = Color.Unspecified,
|
||||||
chipIndex = Color.Unspecified,
|
chipIndex = Color.Unspecified,
|
||||||
textCommon = Color.Unspecified,
|
textCommon = Color.Unspecified,
|
||||||
textFieldHint = Color.Unspecified,
|
textFieldHint = Color.Unspecified,
|
||||||
|
@ -256,6 +267,7 @@ internal val LocalExtendedColors =
|
||||||
complementaryColor = Color.Unspecified,
|
complementaryColor = Color.Unspecified,
|
||||||
dividerColor = Color.Unspecified,
|
dividerColor = Color.Unspecified,
|
||||||
darkDividerColor = Color.Unspecified,
|
darkDividerColor = Color.Unspecified,
|
||||||
tabTextColor = Color.Unspecified
|
tabTextColor = Color.Unspecified,
|
||||||
|
panelBackgroundColor = Color.Unspecified,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import java.util.concurrent.atomic.AtomicInteger
|
||||||
class AccountTestSetup(
|
class AccountTestSetup(
|
||||||
private val composeTestRule: ComposeContentTestRule,
|
private val composeTestRule: ComposeContentTestRule,
|
||||||
private val walletSnapshot: WalletSnapshot,
|
private val walletSnapshot: WalletSnapshot,
|
||||||
private val isShowFiatConversion: Boolean
|
|
||||||
) {
|
) {
|
||||||
private val onSettingsCount = AtomicInteger(0)
|
private val onSettingsCount = AtomicInteger(0)
|
||||||
private val onReceiveCount = AtomicInteger(0)
|
private val onReceiveCount = AtomicInteger(0)
|
||||||
|
@ -46,10 +45,8 @@ class AccountTestSetup(
|
||||||
@Suppress("TestFunctionName")
|
@Suppress("TestFunctionName")
|
||||||
fun DefaultContent() {
|
fun DefaultContent() {
|
||||||
Account(
|
Account(
|
||||||
walletSnapshot,
|
walletSnapshot = walletSnapshot,
|
||||||
isUpdateAvailable = false,
|
isKeepScreenOnWhileSyncing = false,
|
||||||
isKeepScreenOnDuringSync = false,
|
|
||||||
isFiatConversionEnabled = isShowFiatConversion,
|
|
||||||
goSettings = {
|
goSettings = {
|
||||||
onSettingsCount.incrementAndGet()
|
onSettingsCount.incrementAndGet()
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,15 +7,12 @@ import androidx.compose.ui.test.junit4.createComposeRule
|
||||||
import androidx.compose.ui.test.onNodeWithTag
|
import androidx.compose.ui.test.onNodeWithTag
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.test.filters.MediumTest
|
import androidx.test.filters.MediumTest
|
||||||
import cash.z.ecc.android.sdk.Synchronizer
|
|
||||||
import cash.z.ecc.android.sdk.model.PercentDecimal
|
|
||||||
import co.electriccoin.zcash.test.UiTestPrerequisites
|
import co.electriccoin.zcash.test.UiTestPrerequisites
|
||||||
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||||
import co.electriccoin.zcash.ui.fixture.WalletSnapshotFixture
|
import co.electriccoin.zcash.ui.fixture.WalletSnapshotFixture
|
||||||
import co.electriccoin.zcash.ui.screen.account.AccountTag
|
import co.electriccoin.zcash.ui.screen.account.AccountTag
|
||||||
import co.electriccoin.zcash.ui.screen.account.AccountTestSetup
|
import co.electriccoin.zcash.ui.screen.account.AccountTestSetup
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Assert.assertNotEquals
|
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
|
@ -27,7 +24,6 @@ class AccountViewIntegrationTest : UiTestPrerequisites() {
|
||||||
AccountTestSetup(
|
AccountTestSetup(
|
||||||
composeTestRule,
|
composeTestRule,
|
||||||
walletSnapshot,
|
walletSnapshot,
|
||||||
isShowFiatConversion = false
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is just basic sanity check that we still have UI set up as expected after the state restore
|
// This is just basic sanity check that we still have UI set up as expected after the state restore
|
||||||
|
@ -37,8 +33,9 @@ class AccountViewIntegrationTest : UiTestPrerequisites() {
|
||||||
val restorationTester = StateRestorationTester(composeTestRule)
|
val restorationTester = StateRestorationTester(composeTestRule)
|
||||||
val walletSnapshot =
|
val walletSnapshot =
|
||||||
WalletSnapshotFixture.new(
|
WalletSnapshotFixture.new(
|
||||||
status = Synchronizer.Status.SYNCING,
|
saplingBalance = WalletSnapshotFixture.SAPLING_BALANCE,
|
||||||
progress = PercentDecimal(0.5f)
|
orchardBalance = WalletSnapshotFixture.ORCHARD_BALANCE,
|
||||||
|
transparentBalance = WalletSnapshotFixture.TRANSPARENT_BALANCE
|
||||||
)
|
)
|
||||||
val testSetup = newTestSetup(walletSnapshot)
|
val testSetup = newTestSetup(walletSnapshot)
|
||||||
|
|
||||||
|
@ -46,21 +43,17 @@ class AccountViewIntegrationTest : UiTestPrerequisites() {
|
||||||
testSetup.DefaultContent()
|
testSetup.DefaultContent()
|
||||||
}
|
}
|
||||||
|
|
||||||
assertNotEquals(WalletSnapshotFixture.STATUS, testSetup.getWalletSnapshot().status)
|
assertEquals(WalletSnapshotFixture.SAPLING_BALANCE, testSetup.getWalletSnapshot().saplingBalance)
|
||||||
assertEquals(Synchronizer.Status.SYNCING, testSetup.getWalletSnapshot().status)
|
assertEquals(WalletSnapshotFixture.ORCHARD_BALANCE, testSetup.getWalletSnapshot().orchardBalance)
|
||||||
|
assertEquals(WalletSnapshotFixture.TRANSPARENT_BALANCE, testSetup.getWalletSnapshot().transparentBalance)
|
||||||
assertNotEquals(WalletSnapshotFixture.PROGRESS, testSetup.getWalletSnapshot().progress)
|
|
||||||
assertEquals(0.5f, testSetup.getWalletSnapshot().progress.decimal)
|
|
||||||
|
|
||||||
restorationTester.emulateSavedInstanceStateRestore()
|
restorationTester.emulateSavedInstanceStateRestore()
|
||||||
|
|
||||||
assertNotEquals(WalletSnapshotFixture.STATUS, testSetup.getWalletSnapshot().status)
|
assertEquals(WalletSnapshotFixture.SAPLING_BALANCE, testSetup.getWalletSnapshot().saplingBalance)
|
||||||
assertEquals(Synchronizer.Status.SYNCING, testSetup.getWalletSnapshot().status)
|
assertEquals(WalletSnapshotFixture.ORCHARD_BALANCE, testSetup.getWalletSnapshot().orchardBalance)
|
||||||
|
assertEquals(WalletSnapshotFixture.TRANSPARENT_BALANCE, testSetup.getWalletSnapshot().transparentBalance)
|
||||||
|
|
||||||
assertNotEquals(WalletSnapshotFixture.PROGRESS, testSetup.getWalletSnapshot().progress)
|
composeTestRule.onNodeWithTag(AccountTag.BALANCE_VIEWS).also {
|
||||||
assertEquals(0.5f, testSetup.getWalletSnapshot().progress.decimal)
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithTag(AccountTag.SINGLE_LINE_TEXT).also {
|
|
||||||
it.assertIsDisplayed()
|
it.assertIsDisplayed()
|
||||||
it.assertWidthIsAtLeast(1.dp)
|
it.assertWidthIsAtLeast(1.dp)
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,11 +38,7 @@ class AccountViewTest : UiTestPrerequisites() {
|
||||||
it.assertIsDisplayed()
|
it.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
|
|
||||||
composeTestRule.onNodeWithTag(AccountTag.STATUS_VIEWS).also {
|
composeTestRule.onNodeWithTag(AccountTag.BALANCE_VIEWS).also {
|
||||||
it.assertIsDisplayed()
|
|
||||||
}
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithTag(AccountTag.FIAT_CONVERSION).also {
|
|
||||||
it.assertIsDisplayed()
|
it.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,16 +47,6 @@ class AccountViewTest : UiTestPrerequisites() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@MediumTest
|
|
||||||
fun hide_fiat_conversion() {
|
|
||||||
newTestSetup(isShowFiatConversion = false)
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithTag(AccountTag.FIAT_CONVERSION).also {
|
|
||||||
it.assertDoesNotExist()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@MediumTest
|
@MediumTest
|
||||||
fun click_history_button() {
|
fun click_history_button() {
|
||||||
|
@ -78,23 +64,20 @@ class AccountViewTest : UiTestPrerequisites() {
|
||||||
fun hamburger_settings_test() {
|
fun hamburger_settings_test() {
|
||||||
val testSetup = newTestSetup()
|
val testSetup = newTestSetup()
|
||||||
|
|
||||||
Assert.assertEquals(0, testSetup.getOnReceiveCount())
|
Assert.assertEquals(0, testSetup.getOnSettingsCount())
|
||||||
|
|
||||||
composeTestRule.clickSettingsTopAppBarMenu()
|
composeTestRule.clickSettingsTopAppBarMenu()
|
||||||
|
|
||||||
Assert.assertEquals(1, testSetup.getOnSettingsCount())
|
Assert.assertEquals(1, testSetup.getOnSettingsCount())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun newTestSetup(
|
private fun newTestSetup(walletSnapshot: WalletSnapshot = WalletSnapshotFixture.new()) =
|
||||||
isShowFiatConversion: Boolean = true,
|
AccountTestSetup(
|
||||||
walletSnapshot: WalletSnapshot = WalletSnapshotFixture.new()
|
composeTestRule,
|
||||||
) = AccountTestSetup(
|
walletSnapshot = walletSnapshot,
|
||||||
composeTestRule,
|
).apply {
|
||||||
walletSnapshot = walletSnapshot,
|
setDefaultContent()
|
||||||
isShowFiatConversion = isShowFiatConversion
|
}
|
||||||
).apply {
|
|
||||||
setDefaultContent()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ComposeContentTestRule.clickHistory() {
|
private fun ComposeContentTestRule.clickHistory() {
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package co.electriccoin.zcash.ui.screen.balances
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||||
|
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||||
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
|
import co.electriccoin.zcash.ui.screen.balances.view.Balances
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
|
class BalancesTestSetup(
|
||||||
|
private val composeTestRule: ComposeContentTestRule,
|
||||||
|
private val walletSnapshot: WalletSnapshot,
|
||||||
|
private val isShowFiatConversion: Boolean
|
||||||
|
) {
|
||||||
|
private val onSettingsCount = AtomicInteger(0)
|
||||||
|
|
||||||
|
fun getOnSettingsCount(): Int {
|
||||||
|
composeTestRule.waitForIdle()
|
||||||
|
return onSettingsCount.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getWalletSnapshot(): WalletSnapshot {
|
||||||
|
composeTestRule.waitForIdle()
|
||||||
|
return walletSnapshot
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@Suppress("TestFunctionName")
|
||||||
|
fun DefaultContent() {
|
||||||
|
Balances(
|
||||||
|
isFiatConversionEnabled = isShowFiatConversion,
|
||||||
|
isKeepScreenOnWhileSyncing = false,
|
||||||
|
isUpdateAvailable = false,
|
||||||
|
onSettings = {
|
||||||
|
onSettingsCount.incrementAndGet()
|
||||||
|
},
|
||||||
|
walletSnapshot = walletSnapshot,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setDefaultContent() {
|
||||||
|
composeTestRule.setContent {
|
||||||
|
ZcashTheme {
|
||||||
|
DefaultContent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
package co.electriccoin.zcash.ui.screen.balances.integration
|
||||||
|
|
||||||
|
import androidx.compose.ui.test.assertIsDisplayed
|
||||||
|
import androidx.compose.ui.test.assertWidthIsAtLeast
|
||||||
|
import androidx.compose.ui.test.junit4.StateRestorationTester
|
||||||
|
import androidx.compose.ui.test.junit4.createComposeRule
|
||||||
|
import androidx.compose.ui.test.onNodeWithTag
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.test.filters.MediumTest
|
||||||
|
import cash.z.ecc.android.sdk.Synchronizer
|
||||||
|
import cash.z.ecc.android.sdk.model.PercentDecimal
|
||||||
|
import co.electriccoin.zcash.test.UiTestPrerequisites
|
||||||
|
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||||
|
import co.electriccoin.zcash.ui.fixture.WalletSnapshotFixture
|
||||||
|
import co.electriccoin.zcash.ui.screen.balances.BalancesTag
|
||||||
|
import co.electriccoin.zcash.ui.screen.balances.BalancesTestSetup
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertNotEquals
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class BalancesViewIntegrationTest : UiTestPrerequisites() {
|
||||||
|
@get:Rule
|
||||||
|
val composeTestRule = createComposeRule()
|
||||||
|
|
||||||
|
private fun newTestSetup(walletSnapshot: WalletSnapshot) =
|
||||||
|
BalancesTestSetup(
|
||||||
|
composeTestRule,
|
||||||
|
walletSnapshot,
|
||||||
|
isShowFiatConversion = true
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is just basic sanity check that we still have UI set up as expected after the state restore
|
||||||
|
@Test
|
||||||
|
@MediumTest
|
||||||
|
fun wallet_snapshot_restoration() {
|
||||||
|
val restorationTester = StateRestorationTester(composeTestRule)
|
||||||
|
val walletSnapshot =
|
||||||
|
WalletSnapshotFixture.new(
|
||||||
|
status = Synchronizer.Status.SYNCING,
|
||||||
|
progress = PercentDecimal(0.5f)
|
||||||
|
)
|
||||||
|
val testSetup = newTestSetup(walletSnapshot)
|
||||||
|
|
||||||
|
restorationTester.setContent {
|
||||||
|
testSetup.DefaultContent()
|
||||||
|
}
|
||||||
|
|
||||||
|
assertNotEquals(WalletSnapshotFixture.STATUS, testSetup.getWalletSnapshot().status)
|
||||||
|
assertEquals(Synchronizer.Status.SYNCING, testSetup.getWalletSnapshot().status)
|
||||||
|
|
||||||
|
assertNotEquals(WalletSnapshotFixture.PROGRESS, testSetup.getWalletSnapshot().progress)
|
||||||
|
assertEquals(0.5f, testSetup.getWalletSnapshot().progress.decimal)
|
||||||
|
|
||||||
|
restorationTester.emulateSavedInstanceStateRestore()
|
||||||
|
|
||||||
|
assertNotEquals(WalletSnapshotFixture.STATUS, testSetup.getWalletSnapshot().status)
|
||||||
|
assertEquals(Synchronizer.Status.SYNCING, testSetup.getWalletSnapshot().status)
|
||||||
|
|
||||||
|
assertNotEquals(WalletSnapshotFixture.PROGRESS, testSetup.getWalletSnapshot().progress)
|
||||||
|
assertEquals(0.5f, testSetup.getWalletSnapshot().progress.decimal)
|
||||||
|
|
||||||
|
composeTestRule.onNodeWithTag(BalancesTag.STATUS).also {
|
||||||
|
it.assertIsDisplayed()
|
||||||
|
it.assertWidthIsAtLeast(1.dp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package co.electriccoin.zcash.ui.screen.account.model
|
package co.electriccoin.zcash.ui.screen.balances.model
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import cash.z.ecc.android.sdk.Synchronizer
|
import cash.z.ecc.android.sdk.Synchronizer
|
||||||
|
@ -37,7 +37,7 @@ class WalletDisplayValuesTest {
|
||||||
assertNotNull(values)
|
assertNotNull(values)
|
||||||
assertEquals(1f, values.progress.decimal)
|
assertEquals(1f, values.progress.decimal)
|
||||||
assertEquals(walletSnapshot.totalBalance().toZecString(), values.zecAmountText)
|
assertEquals(walletSnapshot.totalBalance().toZecString(), values.zecAmountText)
|
||||||
assertTrue(values.statusText.startsWith(getStringResource(R.string.account_status_syncing_catchup)))
|
assertTrue(values.statusText.startsWith(getStringResource(R.string.balances_status_syncing)))
|
||||||
// TODO [#578]: Provide Zatoshi -> USD fiat currency formatting
|
// TODO [#578]: Provide Zatoshi -> USD fiat currency formatting
|
||||||
// TODO [#578]: https://github.com/Electric-Coin-Company/zcash-android-wallet-sdk/issues/578
|
// TODO [#578]: https://github.com/Electric-Coin-Company/zcash-android-wallet-sdk/issues/578
|
||||||
assertEquals(FiatCurrencyConversionRateState.Unavailable, values.fiatCurrencyAmountState)
|
assertEquals(FiatCurrencyConversionRateState.Unavailable, values.fiatCurrencyAmountState)
|
|
@ -0,0 +1,69 @@
|
||||||
|
package co.electriccoin.zcash.ui.screen.balances.view
|
||||||
|
|
||||||
|
import androidx.compose.ui.test.assertIsDisplayed
|
||||||
|
import androidx.compose.ui.test.junit4.createComposeRule
|
||||||
|
import androidx.compose.ui.test.onNodeWithTag
|
||||||
|
import androidx.test.filters.MediumTest
|
||||||
|
import co.electriccoin.zcash.test.UiTestPrerequisites
|
||||||
|
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||||
|
import co.electriccoin.zcash.ui.design.component.CommonTag
|
||||||
|
import co.electriccoin.zcash.ui.fixture.WalletSnapshotFixture
|
||||||
|
import co.electriccoin.zcash.ui.screen.balances.BalancesTag
|
||||||
|
import co.electriccoin.zcash.ui.screen.balances.BalancesTestSetup
|
||||||
|
import co.electriccoin.zcash.ui.screen.send.clickSettingsTopAppBarMenu
|
||||||
|
import org.junit.Assert
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import kotlin.test.DefaultAsserter.assertEquals
|
||||||
|
|
||||||
|
// TODO [#1227]: Cover Balances UI and logic with tests
|
||||||
|
// TODO [#1227]: https://github.com/Electric-Coin-Company/zashi-android/issues/1227
|
||||||
|
|
||||||
|
class BalancesViewTest : UiTestPrerequisites() {
|
||||||
|
@get:Rule
|
||||||
|
val composeTestRule = createComposeRule()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@MediumTest
|
||||||
|
fun check_all_elementary_ui_elements_displayed() {
|
||||||
|
newTestSetup()
|
||||||
|
|
||||||
|
composeTestRule.onNodeWithTag(CommonTag.TOP_APP_BAR)
|
||||||
|
.also {
|
||||||
|
it.assertIsDisplayed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@MediumTest
|
||||||
|
fun hide_fiat_conversion() {
|
||||||
|
newTestSetup(isShowFiatConversion = false)
|
||||||
|
|
||||||
|
composeTestRule.onNodeWithTag(BalancesTag.FIAT_CONVERSION).also {
|
||||||
|
it.assertDoesNotExist()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@MediumTest
|
||||||
|
fun hamburger_settings_test() {
|
||||||
|
val testSetup = newTestSetup()
|
||||||
|
|
||||||
|
assertEquals("Failed in comparison", 0, testSetup.getOnSettingsCount())
|
||||||
|
|
||||||
|
composeTestRule.clickSettingsTopAppBarMenu()
|
||||||
|
|
||||||
|
Assert.assertEquals(1, testSetup.getOnSettingsCount())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun newTestSetup(
|
||||||
|
isShowFiatConversion: Boolean = true,
|
||||||
|
walletSnapshot: WalletSnapshot = WalletSnapshotFixture.new()
|
||||||
|
) = BalancesTestSetup(
|
||||||
|
composeTestRule,
|
||||||
|
walletSnapshot = walletSnapshot,
|
||||||
|
isShowFiatConversion = isShowFiatConversion
|
||||||
|
).apply {
|
||||||
|
setDefaultContent()
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,5 @@ package co.electriccoin.zcash.ui.screen.account
|
||||||
* These are only used for automated testing.
|
* These are only used for automated testing.
|
||||||
*/
|
*/
|
||||||
object AccountTag {
|
object AccountTag {
|
||||||
const val STATUS_VIEWS = "status_views"
|
const val BALANCE_VIEWS = "balance_views"
|
||||||
const val SINGLE_LINE_TEXT = "single_line_text"
|
|
||||||
const val FIAT_CONVERSION = "fiat_conversion"
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,15 +6,10 @@ import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import co.electriccoin.zcash.ui.common.viewmodel.CheckUpdateViewModel
|
|
||||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||||
import co.electriccoin.zcash.ui.configuration.ConfigurationEntries
|
|
||||||
import co.electriccoin.zcash.ui.configuration.RemoteConfig
|
|
||||||
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
|
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
|
||||||
import co.electriccoin.zcash.ui.screen.account.view.Account
|
import co.electriccoin.zcash.ui.screen.account.view.Account
|
||||||
import co.electriccoin.zcash.ui.screen.settings.viewmodel.SettingsViewModel
|
import co.electriccoin.zcash.ui.screen.settings.viewmodel.SettingsViewModel
|
||||||
import co.electriccoin.zcash.ui.screen.update.AppUpdateCheckerImp
|
|
||||||
import co.electriccoin.zcash.ui.screen.update.model.UpdateState
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun WrapAccount(
|
internal fun WrapAccount(
|
||||||
|
@ -23,25 +18,12 @@ internal fun WrapAccount(
|
||||||
goBalances: () -> Unit,
|
goBalances: () -> Unit,
|
||||||
goSettings: () -> Unit,
|
goSettings: () -> Unit,
|
||||||
) {
|
) {
|
||||||
// Show information about the app update, if available
|
|
||||||
val checkUpdateViewModel by activity.viewModels<CheckUpdateViewModel> {
|
|
||||||
CheckUpdateViewModel.CheckUpdateViewModelFactory(
|
|
||||||
activity.application,
|
|
||||||
AppUpdateCheckerImp.new()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
val updateAvailable =
|
|
||||||
checkUpdateViewModel.updateInfo.collectAsStateWithLifecycle().value.let {
|
|
||||||
it?.appUpdateInfo != null && it.state == UpdateState.Prepared
|
|
||||||
}
|
|
||||||
|
|
||||||
val walletViewModel by activity.viewModels<WalletViewModel>()
|
val walletViewModel by activity.viewModels<WalletViewModel>()
|
||||||
val walletSnapshot = walletViewModel.walletSnapshot.collectAsStateWithLifecycle().value
|
val walletSnapshot = walletViewModel.walletSnapshot.collectAsStateWithLifecycle().value
|
||||||
|
|
||||||
val settingsViewModel by activity.viewModels<SettingsViewModel>()
|
val settingsViewModel by activity.viewModels<SettingsViewModel>()
|
||||||
|
|
||||||
val isKeepScreenOnWhileSyncing = settingsViewModel.isKeepScreenOnWhileSyncing.collectAsStateWithLifecycle().value
|
val isKeepScreenOnWhileSyncing = settingsViewModel.isKeepScreenOnWhileSyncing.collectAsStateWithLifecycle().value
|
||||||
val isFiatConversionEnabled = ConfigurationEntries.IS_FIAT_CONVERSION_ENABLED.getValue(RemoteConfig.current)
|
|
||||||
|
|
||||||
if (null == walletSnapshot) {
|
if (null == walletSnapshot) {
|
||||||
// TODO [#1146]: Consider moving CircularScreenProgressIndicator from Android layer to View layer
|
// TODO [#1146]: Consider moving CircularScreenProgressIndicator from Android layer to View layer
|
||||||
|
@ -51,9 +33,7 @@ internal fun WrapAccount(
|
||||||
} else {
|
} else {
|
||||||
Account(
|
Account(
|
||||||
walletSnapshot = walletSnapshot,
|
walletSnapshot = walletSnapshot,
|
||||||
isUpdateAvailable = updateAvailable,
|
isKeepScreenOnWhileSyncing = isKeepScreenOnWhileSyncing,
|
||||||
isKeepScreenOnDuringSync = isKeepScreenOnWhileSyncing,
|
|
||||||
isFiatConversionEnabled = isFiatConversionEnabled,
|
|
||||||
goBalances = goBalances,
|
goBalances = goBalances,
|
||||||
goHistory = goHistory,
|
goHistory = goHistory,
|
||||||
goSettings = goSettings,
|
goSettings = goSettings,
|
||||||
|
|
|
@ -14,28 +14,23 @@ 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.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.tooling.preview.Preview
|
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 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.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
|
||||||
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
|
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
|
||||||
import co.electriccoin.zcash.ui.design.component.Body
|
|
||||||
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.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
|
||||||
import co.electriccoin.zcash.ui.fixture.WalletSnapshotFixture
|
import co.electriccoin.zcash.ui.fixture.WalletSnapshotFixture
|
||||||
import co.electriccoin.zcash.ui.screen.account.AccountTag
|
import co.electriccoin.zcash.ui.screen.account.AccountTag
|
||||||
import co.electriccoin.zcash.ui.screen.account.model.WalletDisplayValues
|
|
||||||
|
|
||||||
@Preview("Account")
|
@Preview("Account")
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -44,9 +39,7 @@ private fun ComposablePreview() {
|
||||||
GradientSurface {
|
GradientSurface {
|
||||||
Account(
|
Account(
|
||||||
walletSnapshot = WalletSnapshotFixture.new(),
|
walletSnapshot = WalletSnapshotFixture.new(),
|
||||||
isUpdateAvailable = false,
|
isKeepScreenOnWhileSyncing = false,
|
||||||
isKeepScreenOnDuringSync = false,
|
|
||||||
isFiatConversionEnabled = false,
|
|
||||||
goHistory = {},
|
goHistory = {},
|
||||||
goBalances = {},
|
goBalances = {},
|
||||||
goSettings = {},
|
goSettings = {},
|
||||||
|
@ -55,13 +48,10 @@ private fun ComposablePreview() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Account(
|
fun Account(
|
||||||
walletSnapshot: WalletSnapshot,
|
walletSnapshot: WalletSnapshot,
|
||||||
isUpdateAvailable: Boolean,
|
isKeepScreenOnWhileSyncing: Boolean?,
|
||||||
isKeepScreenOnDuringSync: Boolean?,
|
|
||||||
isFiatConversionEnabled: Boolean,
|
|
||||||
goBalances: () -> Unit,
|
goBalances: () -> Unit,
|
||||||
goHistory: () -> Unit,
|
goHistory: () -> Unit,
|
||||||
goSettings: () -> Unit,
|
goSettings: () -> Unit,
|
||||||
|
@ -71,9 +61,7 @@ fun Account(
|
||||||
}) { paddingValues ->
|
}) { paddingValues ->
|
||||||
AccountMainContent(
|
AccountMainContent(
|
||||||
walletSnapshot = walletSnapshot,
|
walletSnapshot = walletSnapshot,
|
||||||
isUpdateAvailable = isUpdateAvailable,
|
isKeepScreenOnWhileSyncing = isKeepScreenOnWhileSyncing,
|
||||||
isKeepScreenOnDuringSync = isKeepScreenOnDuringSync,
|
|
||||||
isFiatConversionEnabled = isFiatConversionEnabled,
|
|
||||||
goHistory = goHistory,
|
goHistory = goHistory,
|
||||||
goBalances = goBalances,
|
goBalances = goBalances,
|
||||||
modifier =
|
modifier =
|
||||||
|
@ -105,13 +93,10 @@ private fun AccountTopAppBar(onSettings: () -> Unit) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun AccountMainContent(
|
private fun AccountMainContent(
|
||||||
walletSnapshot: WalletSnapshot,
|
walletSnapshot: WalletSnapshot,
|
||||||
isUpdateAvailable: Boolean,
|
isKeepScreenOnWhileSyncing: Boolean?,
|
||||||
isKeepScreenOnDuringSync: Boolean?,
|
|
||||||
isFiatConversionEnabled: Boolean,
|
|
||||||
goBalances: () -> Unit,
|
goBalances: () -> Unit,
|
||||||
goHistory: () -> Unit,
|
goHistory: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
|
@ -125,7 +110,7 @@ private fun AccountMainContent(
|
||||||
) {
|
) {
|
||||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
|
||||||
|
|
||||||
Status(walletSnapshot, isUpdateAvailable, isFiatConversionEnabled, goBalances)
|
BalancesStatus(walletSnapshot, goBalances)
|
||||||
|
|
||||||
Spacer(
|
Spacer(
|
||||||
modifier =
|
modifier =
|
||||||
|
@ -138,72 +123,29 @@ private fun AccountMainContent(
|
||||||
|
|
||||||
PrimaryButton(onClick = goHistory, text = stringResource(R.string.account_button_history))
|
PrimaryButton(onClick = goHistory, text = stringResource(R.string.account_button_history))
|
||||||
|
|
||||||
if (isKeepScreenOnDuringSync == true && walletSnapshot.status == Synchronizer.Status.SYNCING) {
|
if (isKeepScreenOnWhileSyncing == true && walletSnapshot.status == Synchronizer.Status.SYNCING) {
|
||||||
DisableScreenTimeout()
|
DisableScreenTimeout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@Suppress("LongMethod", "MagicNumber")
|
@Suppress("LongMethod")
|
||||||
private fun Status(
|
private fun BalancesStatus(
|
||||||
walletSnapshot: WalletSnapshot,
|
walletSnapshot: WalletSnapshot,
|
||||||
updateAvailable: Boolean,
|
|
||||||
isFiatConversionEnabled: Boolean,
|
|
||||||
goBalances: () -> Unit
|
goBalances: () -> Unit
|
||||||
) {
|
) {
|
||||||
val walletDisplayValues =
|
|
||||||
WalletDisplayValues.getNextValues(
|
|
||||||
LocalContext.current,
|
|
||||||
walletSnapshot,
|
|
||||||
updateAvailable
|
|
||||||
)
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.testTag(AccountTag.STATUS_VIEWS),
|
.testTag(AccountTag.BALANCE_VIEWS),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
if (walletDisplayValues.zecAmountText.isNotEmpty()) {
|
BalanceWidget(
|
||||||
BalanceWidget(
|
walletSnapshot = walletSnapshot,
|
||||||
walletSnapshot = walletSnapshot,
|
isReferenceToBalances = true,
|
||||||
isReferenceToBalances = true,
|
onReferenceClick = goBalances
|
||||||
onReferenceClick = goBalances
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isFiatConversionEnabled) {
|
|
||||||
Column(Modifier.testTag(AccountTag.FIAT_CONVERSION)) {
|
|
||||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
|
|
||||||
|
|
||||||
when (walletDisplayValues.fiatCurrencyAmountState) {
|
|
||||||
is FiatCurrencyConversionRateState.Current -> {
|
|
||||||
BodyWithFiatCurrencySymbol(
|
|
||||||
amount = walletDisplayValues.fiatCurrencyAmountText
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is FiatCurrencyConversionRateState.Stale -> {
|
|
||||||
// Note: we should show information about staleness too
|
|
||||||
BodyWithFiatCurrencySymbol(
|
|
||||||
amount = walletDisplayValues.fiatCurrencyAmountText
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is FiatCurrencyConversionRateState.Unavailable -> {
|
|
||||||
Body(text = walletDisplayValues.fiatCurrencyAmountText)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
|
|
||||||
|
|
||||||
if (walletDisplayValues.statusText.isNotEmpty()) {
|
|
||||||
Body(
|
|
||||||
text = walletDisplayValues.statusText,
|
|
||||||
modifier = Modifier.testTag(AccountTag.SINGLE_LINE_TEXT)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,19 +6,45 @@ import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import co.electriccoin.zcash.ui.common.viewmodel.CheckUpdateViewModel
|
||||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||||
|
import co.electriccoin.zcash.ui.configuration.ConfigurationEntries
|
||||||
|
import co.electriccoin.zcash.ui.configuration.RemoteConfig
|
||||||
import co.electriccoin.zcash.ui.screen.balances.view.Balances
|
import co.electriccoin.zcash.ui.screen.balances.view.Balances
|
||||||
|
import co.electriccoin.zcash.ui.screen.settings.viewmodel.SettingsViewModel
|
||||||
|
import co.electriccoin.zcash.ui.screen.update.AppUpdateCheckerImp
|
||||||
|
import co.electriccoin.zcash.ui.screen.update.model.UpdateState
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun WrapBalances(
|
internal fun WrapBalances(
|
||||||
activity: ComponentActivity,
|
activity: ComponentActivity,
|
||||||
goSettings: () -> Unit,
|
goSettings: () -> Unit,
|
||||||
) {
|
) {
|
||||||
|
// Show information about the app update, if available
|
||||||
|
val checkUpdateViewModel by activity.viewModels<CheckUpdateViewModel> {
|
||||||
|
CheckUpdateViewModel.CheckUpdateViewModelFactory(
|
||||||
|
activity.application,
|
||||||
|
AppUpdateCheckerImp.new()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val isUpdateAvailable =
|
||||||
|
checkUpdateViewModel.updateInfo.collectAsStateWithLifecycle().value.let {
|
||||||
|
it?.appUpdateInfo != null && it.state == UpdateState.Prepared
|
||||||
|
}
|
||||||
|
|
||||||
|
val settingsViewModel by activity.viewModels<SettingsViewModel>()
|
||||||
|
|
||||||
|
val isKeepScreenOnWhileSyncing = settingsViewModel.isKeepScreenOnWhileSyncing.collectAsStateWithLifecycle().value
|
||||||
|
val isFiatConversionEnabled = ConfigurationEntries.IS_FIAT_CONVERSION_ENABLED.getValue(RemoteConfig.current)
|
||||||
|
|
||||||
val walletViewModel by activity.viewModels<WalletViewModel>()
|
val walletViewModel by activity.viewModels<WalletViewModel>()
|
||||||
val walletSnapshot = walletViewModel.walletSnapshot.collectAsStateWithLifecycle().value
|
val walletSnapshot = walletViewModel.walletSnapshot.collectAsStateWithLifecycle().value
|
||||||
|
|
||||||
Balances(
|
Balances(
|
||||||
walletSnapshot = walletSnapshot,
|
isFiatConversionEnabled = isFiatConversionEnabled,
|
||||||
|
isKeepScreenOnWhileSyncing = isKeepScreenOnWhileSyncing,
|
||||||
|
isUpdateAvailable = isUpdateAvailable,
|
||||||
onSettings = goSettings,
|
onSettings = goSettings,
|
||||||
|
walletSnapshot = walletSnapshot,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package co.electriccoin.zcash.ui.screen.balances
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These are only used for automated testing.
|
||||||
|
*/
|
||||||
|
object BalancesTag {
|
||||||
|
const val STATUS = "status"
|
||||||
|
const val FIAT_CONVERSION = "fiat_conversion"
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package co.electriccoin.zcash.ui.screen.account.model
|
package co.electriccoin.zcash.ui.screen.balances.model
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.compose.ui.text.intl.Locale
|
import androidx.compose.ui.text.intl.Locale
|
||||||
|
@ -8,7 +8,6 @@ import cash.z.ecc.android.sdk.model.MonetarySeparators
|
||||||
import cash.z.ecc.android.sdk.model.PercentDecimal
|
import cash.z.ecc.android.sdk.model.PercentDecimal
|
||||||
import cash.z.ecc.android.sdk.model.toFiatCurrencyState
|
import cash.z.ecc.android.sdk.model.toFiatCurrencyState
|
||||||
import cash.z.ecc.android.sdk.model.toZecString
|
import cash.z.ecc.android.sdk.model.toZecString
|
||||||
import cash.z.ecc.sdk.extension.toPercentageWithDecimal
|
|
||||||
import co.electriccoin.zcash.ui.R
|
import co.electriccoin.zcash.ui.R
|
||||||
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
|
||||||
|
@ -48,47 +47,43 @@ data class WalletDisplayValues(
|
||||||
when (walletSnapshot.status) {
|
when (walletSnapshot.status) {
|
||||||
Synchronizer.Status.SYNCING -> {
|
Synchronizer.Status.SYNCING -> {
|
||||||
progress = walletSnapshot.progress
|
progress = walletSnapshot.progress
|
||||||
// we add "so far" to the amount
|
// We add "so far" to the amount
|
||||||
if (fiatCurrencyAmountState != FiatCurrencyConversionRateState.Unavailable) {
|
if (fiatCurrencyAmountState != FiatCurrencyConversionRateState.Unavailable) {
|
||||||
fiatCurrencyAmountText =
|
fiatCurrencyAmountText =
|
||||||
context.getString(
|
context.getString(
|
||||||
R.string.account_status_syncing_amount_suffix,
|
R.string.balances_status_syncing_amount_suffix,
|
||||||
fiatCurrencyAmountText
|
fiatCurrencyAmountText
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
statusText =
|
statusText = context.getString(R.string.balances_status_syncing)
|
||||||
context.getString(
|
|
||||||
R.string.account_status_syncing_format,
|
|
||||||
walletSnapshot.progress.toPercentageWithDecimal()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
Synchronizer.Status.SYNCED -> {
|
Synchronizer.Status.SYNCED -> {
|
||||||
statusText =
|
statusText =
|
||||||
if (updateAvailable) {
|
if (updateAvailable) {
|
||||||
context.getString(R.string.account_status_update)
|
context.getString(R.string.balances_status_update)
|
||||||
} else {
|
} else {
|
||||||
context.getString(R.string.account_status_up_to_date)
|
context.getString(R.string.balances_status_synced)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Synchronizer.Status.DISCONNECTED -> {
|
Synchronizer.Status.DISCONNECTED -> {
|
||||||
statusText =
|
statusText =
|
||||||
context.getString(
|
context.getString(
|
||||||
R.string.account_status_error,
|
R.string.balances_status_error,
|
||||||
context.getString(R.string.account_status_error_connection)
|
context.getString(R.string.balances_status_error_connection)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Synchronizer.Status.STOPPED -> {
|
Synchronizer.Status.STOPPED -> {
|
||||||
statusText = context.getString(R.string.account_status_stopped)
|
statusText = context.getString(R.string.balances_status_stopped)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// more detailed error message
|
// More detailed error message
|
||||||
walletSnapshot.synchronizerError?.let {
|
walletSnapshot.synchronizerError?.let {
|
||||||
statusText =
|
statusText =
|
||||||
context.getString(
|
context.getString(
|
||||||
R.string.account_status_error,
|
R.string.balances_status_error,
|
||||||
walletSnapshot.synchronizerError.getCauseMessage()
|
walletSnapshot.synchronizerError.getCauseMessage()
|
||||||
?: context.getString(R.string.account_status_error_unknown)
|
?: context.getString(R.string.balances_status_error_unknown)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package co.electriccoin.zcash.ui.screen.balances.view
|
package co.electriccoin.zcash.ui.screen.balances.view
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
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.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.fillMaxWidth
|
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
|
||||||
|
@ -26,12 +26,17 @@ 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.res.vectorResource
|
||||||
|
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.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import cash.z.ecc.android.sdk.Synchronizer
|
||||||
|
import cash.z.ecc.android.sdk.model.FiatCurrencyConversionRateState
|
||||||
import cash.z.ecc.android.sdk.model.toZecString
|
import cash.z.ecc.android.sdk.model.toZecString
|
||||||
|
import cash.z.ecc.sdk.extension.toPercentageWithDecimal
|
||||||
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.DisableScreenTimeout
|
||||||
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.changePendingBalance
|
||||||
import co.electriccoin.zcash.ui.common.model.spendableBalance
|
import co.electriccoin.zcash.ui.common.model.spendableBalance
|
||||||
|
@ -39,14 +44,17 @@ 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.BodySmall
|
||||||
|
import co.electriccoin.zcash.ui.design.component.BodyWithFiatCurrencySymbol
|
||||||
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.CircularSmallProgressIndicator
|
||||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||||
|
import co.electriccoin.zcash.ui.design.component.LinearProgressIndicator
|
||||||
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.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.balances.BalancesTag
|
||||||
|
import co.electriccoin.zcash.ui.screen.balances.model.WalletDisplayValues
|
||||||
|
|
||||||
@Preview("Balances")
|
@Preview("Balances")
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -54,20 +62,23 @@ private fun ComposablePreview() {
|
||||||
ZcashTheme(forceDarkMode = false) {
|
ZcashTheme(forceDarkMode = false) {
|
||||||
GradientSurface {
|
GradientSurface {
|
||||||
Balances(
|
Balances(
|
||||||
walletSnapshot = WalletSnapshotFixture.new(),
|
|
||||||
onSettings = {},
|
onSettings = {},
|
||||||
|
isFiatConversionEnabled = false,
|
||||||
|
isKeepScreenOnWhileSyncing = false,
|
||||||
|
isUpdateAvailable = false,
|
||||||
|
walletSnapshot = WalletSnapshotFixture.new(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO [#1127]: Implement Balances screen
|
|
||||||
// TODO [#1127]: https://github.com/Electric-Coin-Company/zashi-android/issues/1127
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Balances(
|
fun Balances(
|
||||||
|
onSettings: () -> Unit,
|
||||||
|
isFiatConversionEnabled: Boolean,
|
||||||
|
isKeepScreenOnWhileSyncing: Boolean?,
|
||||||
|
isUpdateAvailable: Boolean,
|
||||||
walletSnapshot: WalletSnapshot?,
|
walletSnapshot: WalletSnapshot?,
|
||||||
onSettings: () -> Unit
|
|
||||||
) {
|
) {
|
||||||
Scaffold(topBar = {
|
Scaffold(topBar = {
|
||||||
BalancesTopAppBar(onSettings = onSettings)
|
BalancesTopAppBar(onSettings = onSettings)
|
||||||
|
@ -76,6 +87,9 @@ fun Balances(
|
||||||
CircularScreenProgressIndicator()
|
CircularScreenProgressIndicator()
|
||||||
} else {
|
} else {
|
||||||
BalancesMainContent(
|
BalancesMainContent(
|
||||||
|
isFiatConversionEnabled = isFiatConversionEnabled,
|
||||||
|
isKeepScreenOnWhileSyncing = isKeepScreenOnWhileSyncing,
|
||||||
|
isUpdateAvailable = isUpdateAvailable,
|
||||||
walletSnapshot = walletSnapshot,
|
walletSnapshot = walletSnapshot,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.padding(
|
Modifier.padding(
|
||||||
|
@ -110,15 +124,12 @@ private fun BalancesTopAppBar(onSettings: () -> Unit) {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun BalancesMainContent(
|
private fun BalancesMainContent(
|
||||||
|
isFiatConversionEnabled: Boolean,
|
||||||
|
isKeepScreenOnWhileSyncing: Boolean?,
|
||||||
|
isUpdateAvailable: Boolean,
|
||||||
walletSnapshot: WalletSnapshot,
|
walletSnapshot: WalletSnapshot,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val walletDisplayValues =
|
|
||||||
WalletDisplayValues.getNextValues(
|
|
||||||
LocalContext.current,
|
|
||||||
walletSnapshot
|
|
||||||
)
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
|
@ -129,13 +140,11 @@ private fun BalancesMainContent(
|
||||||
) {
|
) {
|
||||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
|
||||||
|
|
||||||
if (walletDisplayValues.zecAmountText.isNotEmpty()) {
|
BalanceWidget(
|
||||||
BalanceWidget(
|
walletSnapshot = walletSnapshot,
|
||||||
walletSnapshot = walletSnapshot,
|
isReferenceToBalances = false,
|
||||||
isReferenceToBalances = false,
|
onReferenceClick = {}
|
||||||
onReferenceClick = {}
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingHuge))
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingHuge))
|
||||||
|
|
||||||
|
@ -146,27 +155,48 @@ private fun BalancesMainContent(
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
|
||||||
|
|
||||||
BalancesOverview(walletSnapshot)
|
BalancesOverview(
|
||||||
|
walletSnapshot = walletSnapshot,
|
||||||
|
isFiatConversionEnabled = isFiatConversionEnabled,
|
||||||
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(166.dp)
|
||||||
|
.background(color = ZcashTheme.colors.panelBackgroundColor),
|
||||||
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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.weight(1f, true))
|
||||||
|
|
||||||
|
SyncStatus(
|
||||||
|
walletSnapshot = walletSnapshot,
|
||||||
|
isUpdateAvailable = isUpdateAvailable,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (isKeepScreenOnWhileSyncing == true && walletSnapshot.status == Synchronizer.Status.SYNCING) {
|
||||||
|
DisableScreenTimeout()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BalancesOverview(walletSnapshot: WalletSnapshot) {
|
fun BalancesOverview(
|
||||||
|
walletSnapshot: WalletSnapshot,
|
||||||
|
isFiatConversionEnabled: Boolean,
|
||||||
|
) {
|
||||||
Column {
|
Column {
|
||||||
SpendableBalanceRow(walletSnapshot)
|
SpendableBalanceRow(walletSnapshot)
|
||||||
|
|
||||||
|
@ -178,6 +208,36 @@ fun BalancesOverview(walletSnapshot: WalletSnapshot) {
|
||||||
|
|
||||||
// aka value pending
|
// aka value pending
|
||||||
PendingTransactionsRow(walletSnapshot)
|
PendingTransactionsRow(walletSnapshot)
|
||||||
|
|
||||||
|
if (isFiatConversionEnabled) {
|
||||||
|
val walletDisplayValues =
|
||||||
|
WalletDisplayValues.getNextValues(
|
||||||
|
LocalContext.current,
|
||||||
|
walletSnapshot,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(Modifier.testTag(BalancesTag.FIAT_CONVERSION)) {
|
||||||
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
|
||||||
|
|
||||||
|
when (walletDisplayValues.fiatCurrencyAmountState) {
|
||||||
|
is FiatCurrencyConversionRateState.Current -> {
|
||||||
|
BodyWithFiatCurrencySymbol(
|
||||||
|
amount = walletDisplayValues.fiatCurrencyAmountText
|
||||||
|
)
|
||||||
|
}
|
||||||
|
is FiatCurrencyConversionRateState.Stale -> {
|
||||||
|
// Note: we should show information about staleness too
|
||||||
|
BodyWithFiatCurrencySymbol(
|
||||||
|
amount = walletDisplayValues.fiatCurrencyAmountText
|
||||||
|
)
|
||||||
|
}
|
||||||
|
is FiatCurrencyConversionRateState.Unavailable -> {
|
||||||
|
Body(text = walletDisplayValues.fiatCurrencyAmountText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,3 +349,48 @@ fun PendingTransactionsRow(walletSnapshot: WalletSnapshot) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SyncStatus(
|
||||||
|
isUpdateAvailable: Boolean,
|
||||||
|
walletSnapshot: WalletSnapshot,
|
||||||
|
) {
|
||||||
|
val walletDisplayValues =
|
||||||
|
WalletDisplayValues.getNextValues(
|
||||||
|
LocalContext.current,
|
||||||
|
walletSnapshot,
|
||||||
|
isUpdateAvailable
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
if (walletDisplayValues.statusText.isNotEmpty()) {
|
||||||
|
BodySmall(
|
||||||
|
text = walletDisplayValues.statusText,
|
||||||
|
modifier = Modifier.testTag(BalancesTag.STATUS)
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
|
||||||
|
}
|
||||||
|
|
||||||
|
BodySmall(
|
||||||
|
text =
|
||||||
|
stringResource(
|
||||||
|
id = R.string.balances_status_syncing_percentage,
|
||||||
|
walletSnapshot.progress.toPercentageWithDecimal()
|
||||||
|
),
|
||||||
|
textFontWeight = FontWeight.Black
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
|
||||||
|
|
||||||
|
LinearProgressIndicator(
|
||||||
|
progress = walletSnapshot.progress.decimal,
|
||||||
|
modifier =
|
||||||
|
Modifier.padding(
|
||||||
|
horizontal = ZcashTheme.dimens.spacingXlarge
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -68,7 +68,6 @@ import co.electriccoin.zcash.ui.design.component.SmallTopAppBar
|
||||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme.dimens
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme.dimens
|
||||||
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.send.SendTag
|
import co.electriccoin.zcash.ui.screen.send.SendTag
|
||||||
import co.electriccoin.zcash.ui.screen.send.ext.ABBREVIATION_INDEX
|
import co.electriccoin.zcash.ui.screen.send.ext.ABBREVIATION_INDEX
|
||||||
import co.electriccoin.zcash.ui.screen.send.ext.abbreviated
|
import co.electriccoin.zcash.ui.screen.send.ext.abbreviated
|
||||||
|
@ -361,21 +360,13 @@ private fun SendForm(
|
||||||
.then(modifier),
|
.then(modifier),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
val walletDisplayValues =
|
|
||||||
WalletDisplayValues.getNextValues(
|
|
||||||
context = LocalContext.current,
|
|
||||||
walletSnapshot = walletSnapshot
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(dimens.spacingDefault))
|
Spacer(modifier = Modifier.height(dimens.spacingDefault))
|
||||||
|
|
||||||
if (walletDisplayValues.zecAmountText.isNotEmpty()) {
|
BalanceWidget(
|
||||||
BalanceWidget(
|
walletSnapshot = walletSnapshot,
|
||||||
walletSnapshot = walletSnapshot,
|
isReferenceToBalances = true,
|
||||||
isReferenceToBalances = true,
|
onReferenceClick = goBalances
|
||||||
onReferenceClick = goBalances
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(dimens.spacingXlarge))
|
Spacer(modifier = Modifier.height(dimens.spacingXlarge))
|
||||||
|
|
||||||
|
|
|
@ -1,21 +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="account_button_history">Transaction History</string>
|
<string name="account_button_history">Transaction History</string>
|
||||||
|
|
||||||
<string name="account_status_syncing_format" formatted="true">Syncing - <xliff:g id="synced_percent" example="50.25">
|
|
||||||
%1$s</xliff:g>%%</string> <!-- double %% for escaping -->
|
|
||||||
<string name="account_status_syncing_catchup">Syncing</string>
|
|
||||||
<string name="account_status_syncing_amount_suffix" formatted="true"><xliff:g id="amount_prefix" example="123$">%1$s</xliff:g> so far</string>
|
|
||||||
<string name="account_status_syncing_additional_information">We will show you funds as we discover them.</string>
|
|
||||||
<string name="account_status_up_to_date">Up-to-date</string>
|
|
||||||
<string name="account_status_sending_format" formatted="true">Sending <xliff:g id="sending_amount" example=".023">%1$s</xliff:g></string>
|
|
||||||
<string name="account_status_receiving_format" formatted="true">Receiving <xliff:g id="receiving_amount" example=".023">%1$s</xliff:g> ZEC</string>
|
|
||||||
<string name="account_status_shielding_format" formatted="true">Shielding <xliff:g id="shielding_amount" example=".023">%1$s</xliff:g> ZEC</string>
|
|
||||||
<string name="account_status_update">Please Update</string>
|
|
||||||
<string name="account_status_error" formatted="true">Error: <xliff:g id="error_type" example="Lost connection">%1$s</xliff:g></string>
|
|
||||||
<string name="account_status_error_connection">Disconnected</string>
|
|
||||||
<string name="account_status_error_unknown">Unknown cause</string>
|
|
||||||
<string name="account_status_stopped">Synchronizer stopped</string>
|
|
||||||
<string name="account_status_updating_blockheight">Updating blockheight</string>
|
|
||||||
<string name="account_status_fiat_currency_price_out_of_date" formatted="true"><xliff:g id="fiat_currency" example="USD">%1$s</xliff:g> price out-of-date</string>
|
|
||||||
<string name="account_status_spendable" formatted="true">Fully spendable in <xliff:g id="spendable_time" example="2 minutes">%1$s</xliff:g></string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -3,6 +3,22 @@
|
||||||
<string name="balances_shielded_spendable">Shielded zec (spendable)</string>
|
<string name="balances_shielded_spendable">Shielded zec (spendable)</string>
|
||||||
<string name="balances_change_pending">Change pending</string>
|
<string name="balances_change_pending">Change pending</string>
|
||||||
<string name="balances_pending_transactions">Pending transactions</string>
|
<string name="balances_pending_transactions">Pending transactions</string>
|
||||||
<string name="balances_coming_soon">Coming soon:\n\nTransparent
|
<string name="balances_coming_soon">Transparent funds shielding\n(coming soon)</string>
|
||||||
funds shielding,\nBlock synchronization indicator</string>
|
|
||||||
|
<string name="balances_status_syncing" formatted="true">Syncing…</string>
|
||||||
|
<string name="balances_status_syncing_amount_suffix" formatted="true"><xliff:g id="amount_prefix" example="123$">%1$s</xliff:g> so far</string>
|
||||||
|
<string name="balances_status_syncing_percentage" formatted="true"><xliff:g id="synced_percent" example="50.25">
|
||||||
|
%1$s</xliff:g>%%</string> <!-- double %% for escaping -->
|
||||||
|
<string name="balances_status_synced">Synced</string>
|
||||||
|
<string name="balances_status_sending_format" formatted="true">Sending <xliff:g id="sending_amount" example=".023">%1$s</xliff:g></string>
|
||||||
|
<string name="balances_status_receiving_format" formatted="true">Receiving <xliff:g id="receiving_amount" example=".023">%1$s</xliff:g> ZEC</string>
|
||||||
|
<string name="balances_status_shielding_format" formatted="true">Shielding <xliff:g id="shielding_amount" example=".023">%1$s</xliff:g> ZEC</string>
|
||||||
|
<string name="balances_status_update">Please Update via Play Store</string>
|
||||||
|
<string name="balances_status_error" formatted="true">Error: <xliff:g id="error_type" example="Lost connection">%1$s</xliff:g></string>
|
||||||
|
<string name="balances_status_error_connection">Disconnected</string>
|
||||||
|
<string name="balances_status_error_unknown">Unknown cause</string>
|
||||||
|
<string name="balances_status_stopped">Synchronizer stopped</string>
|
||||||
|
<string name="balances_status_updating_blockheight">Updating blockheight</string>
|
||||||
|
<string name="balances_status_fiat_currency_price_out_of_date" formatted="true"><xliff:g id="fiat_currency" example="USD">%1$s</xliff:g> price out-of-date</string>
|
||||||
|
<string name="balances_status_spendable" formatted="true">Fully spendable in <xliff:g id="spendable_time" example="2 minutes">%1$s</xliff:g></string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -384,7 +384,7 @@ private fun accountScreenshots(
|
||||||
composeTestRule.activity.walletViewModel.walletSnapshot.value != null
|
composeTestRule.activity.walletViewModel.walletSnapshot.value != null
|
||||||
}
|
}
|
||||||
|
|
||||||
composeTestRule.onNodeWithTag(AccountTag.STATUS_VIEWS).also {
|
composeTestRule.onNodeWithTag(AccountTag.BALANCE_VIEWS).also {
|
||||||
it.assertExists()
|
it.assertExists()
|
||||||
ScreenshotTest.takeScreenshot(tag, "Account 1")
|
ScreenshotTest.takeScreenshot(tag, "Account 1")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue