[#1164] Restoring UI state in TopAppBar
- Closes #1164 - This incorporates the new wallet restoring label into the custom TopAppBar UI component, so it’s accessible from all screens - This also fixes the adjust brightness feature that previously stayed turned on when the user left to a surrounding tab screen (Send or Balances) - Changelog update Move DisableScreenTimeout into the parent HomeView Persist restoring state Fix infinite loading trx history UI state Add New wallet syncing state This also adds the wallet restoring state into the transaction history state calculation
This commit is contained in:
parent
84c7618037
commit
8c027003cc
|
@ -19,6 +19,8 @@ directly impact users rather than highlighting other key architectural updates.*
|
|||
- Transitions between screens are now animated with a simple slide animation
|
||||
- Proposal API from the Zcash SDK has been integrated together with handling error states for multi-transaction
|
||||
submission
|
||||
- New Restoring Your Wallet label has been added to all post-onboarding screens to notify users about the current
|
||||
state of the wallet-restoring process.
|
||||
|
||||
### Changed
|
||||
- The Transaction History UI has been incorporated into the Account screen and completely reworked according to the
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
@file:Suppress("TooManyFunctions")
|
||||
|
||||
package co.electriccoin.zcash.ui.design.component
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
|
@ -7,6 +9,7 @@ import androidx.compose.foundation.layout.Column
|
|||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
|
@ -34,7 +37,10 @@ import androidx.compose.ui.draw.clip
|
|||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
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.R
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.design.theme.internal.SecondaryTypography
|
||||
|
@ -49,6 +55,34 @@ private fun TopAppBarTextComposablePreview() {
|
|||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun TopAppBarTextRestoringComposablePreview() {
|
||||
ZcashTheme(forceDarkMode = false) {
|
||||
GradientSurface {
|
||||
SmallTopAppBar(
|
||||
titleText = "Screen A",
|
||||
backText = "Back",
|
||||
restoringLabel = "[RESTORING YOUR WALLET…]"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun TopAppBarTextRestoringLongComposablePreview() {
|
||||
ZcashTheme(forceDarkMode = false) {
|
||||
GradientSurface {
|
||||
SmallTopAppBar(
|
||||
titleText = "Screen A",
|
||||
backText = "Back",
|
||||
restoringLabel = "[RESTORING YOUR WALLET LONG TEXT…]"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun TopAppBarLogoComposablePreview() {
|
||||
|
@ -59,6 +93,20 @@ private fun TopAppBarLogoComposablePreview() {
|
|||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun TopAppBarLogoRestoringComposablePreview() {
|
||||
ZcashTheme(forceDarkMode = false) {
|
||||
GradientSurface {
|
||||
SmallTopAppBar(
|
||||
showTitleLogo = true,
|
||||
backText = "Back",
|
||||
restoringLabel = "[RESTORING YOUR WALLET…]"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun TopAppBarRegularMenuComposablePreview() {
|
||||
|
@ -213,10 +261,11 @@ private fun TopBarOneVisibleActionMenuExample(
|
|||
}
|
||||
|
||||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
@Suppress("LongParameterList", "LongMethod")
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
fun SmallTopAppBar(
|
||||
modifier: Modifier = Modifier,
|
||||
restoringLabel: String? = null,
|
||||
titleText: String? = null,
|
||||
showTitleLogo: Boolean = false,
|
||||
backText: String? = null,
|
||||
|
@ -227,17 +276,40 @@ fun SmallTopAppBar(
|
|||
) {
|
||||
CenterAlignedTopAppBar(
|
||||
title = {
|
||||
if (titleText != null) {
|
||||
Text(
|
||||
text = titleText.uppercase(),
|
||||
style = SecondaryTypography.headlineSmall
|
||||
)
|
||||
} else if (showTitleLogo) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.zashi_text_logo),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.height(ZcashTheme.dimens.topAppBarZcashLogoHeight)
|
||||
)
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
var restoringSpacerHeight: Dp = 0.dp
|
||||
|
||||
if (titleText != null) {
|
||||
Text(
|
||||
text = titleText.uppercase(),
|
||||
style = SecondaryTypography.headlineSmall
|
||||
)
|
||||
restoringSpacerHeight = ZcashTheme.dimens.spacingTiny
|
||||
} else if (showTitleLogo) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.zashi_text_logo),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.height(ZcashTheme.dimens.topAppBarZcashLogoHeight)
|
||||
)
|
||||
restoringSpacerHeight = ZcashTheme.dimens.spacingSmall
|
||||
}
|
||||
|
||||
if (restoringLabel != null) {
|
||||
Spacer(modifier = Modifier.height(restoringSpacerHeight))
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
Text(
|
||||
text = restoringLabel.uppercase(),
|
||||
style = ZcashTheme.extendedTypography.restoringTopAppBarStyle,
|
||||
color = ZcashTheme.colors.restoringTopAppBarColor,
|
||||
modifier = Modifier.fillMaxWidth(0.75f),
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
navigationIcon = {
|
||||
|
|
|
@ -18,6 +18,7 @@ data class ExtendedColors(
|
|||
val circularProgressBarScreen: Color,
|
||||
val linearProgressBarTrack: Color,
|
||||
val linearProgressBarBackground: Color,
|
||||
val restoringTopAppBarColor: Color,
|
||||
val chipIndex: Color,
|
||||
val textCommon: Color,
|
||||
val textMedium: Color,
|
||||
|
|
|
@ -54,6 +54,7 @@ internal object Dark {
|
|||
val circularProgressBarScreen = Color(0xFFFFFFFF)
|
||||
val linearProgressBarTrack = Color(0xFFD9D9D9)
|
||||
val linearProgressBarBackground = Light.complementaryColor
|
||||
val restoringTopAppBarColor = Color(0xFF8A8888)
|
||||
|
||||
val callout = Color(0xFFFFFFFF)
|
||||
val onCallout = Color(0xFFFFFFFF)
|
||||
|
@ -112,6 +113,7 @@ internal object Light {
|
|||
val circularProgressBarScreen = Color(0xFF000000)
|
||||
val linearProgressBarTrack = Color(0xFFD9D9D9)
|
||||
val linearProgressBarBackground = complementaryColor
|
||||
val restoringTopAppBarColor = Color(0xFF8A8888)
|
||||
|
||||
val callout = Color(0xFFFFFFFF)
|
||||
val onCallout = Color(0xFFFFFFFF)
|
||||
|
@ -165,6 +167,7 @@ internal val DarkExtendedColorPalette =
|
|||
circularProgressBarScreen = Dark.circularProgressBarScreen,
|
||||
linearProgressBarTrack = Dark.linearProgressBarTrack,
|
||||
linearProgressBarBackground = Dark.linearProgressBarBackground,
|
||||
restoringTopAppBarColor = Dark.restoringTopAppBarColor,
|
||||
chipIndex = Dark.textChipIndex,
|
||||
textCommon = Dark.textCommon,
|
||||
textMedium = Dark.textMedium,
|
||||
|
@ -207,6 +210,7 @@ internal val LightExtendedColorPalette =
|
|||
circularProgressBarSmall = Light.circularProgressBarSmall,
|
||||
linearProgressBarTrack = Light.linearProgressBarTrack,
|
||||
linearProgressBarBackground = Light.linearProgressBarBackground,
|
||||
restoringTopAppBarColor = Light.restoringTopAppBarColor,
|
||||
chipIndex = Light.textChipIndex,
|
||||
textCommon = Light.textCommon,
|
||||
textMedium = Dark.textMedium,
|
||||
|
@ -251,6 +255,7 @@ internal val LocalExtendedColors =
|
|||
circularProgressBarSmall = Color.Unspecified,
|
||||
linearProgressBarTrack = Color.Unspecified,
|
||||
linearProgressBarBackground = Color.Unspecified,
|
||||
restoringTopAppBarColor = Color.Unspecified,
|
||||
chipIndex = Color.Unspecified,
|
||||
textCommon = Color.Unspecified,
|
||||
textMedium = Color.Unspecified,
|
||||
|
|
|
@ -191,6 +191,7 @@ data class ExtendedTypography(
|
|||
val radioButton: TextStyle,
|
||||
// Grouping transaction item text styles to a wrapper class
|
||||
val transactionItemStyles: TransactionItemTextStyles,
|
||||
val restoringTopAppBarStyle: TextStyle,
|
||||
)
|
||||
|
||||
@Suppress("CompositionLocalAllowlist")
|
||||
|
@ -361,5 +362,10 @@ val LocalExtendedTypography =
|
|||
fontWeight = FontWeight.SemiBold
|
||||
),
|
||||
),
|
||||
restoringTopAppBarStyle =
|
||||
SecondaryTypography.labelMedium.copy(
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.SemiBold
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ import co.electriccoin.zcash.test.UiTestPrerequisites
|
|||
import co.electriccoin.zcash.ui.common.compose.BrightenScreen
|
||||
import co.electriccoin.zcash.ui.common.compose.LocalScreenBrightness
|
||||
import co.electriccoin.zcash.ui.common.compose.ScreenBrightness
|
||||
import co.electriccoin.zcash.ui.common.compose.ScreenBrightnessState
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.test.runTest
|
||||
|
@ -20,7 +20,6 @@ import org.junit.Rule
|
|||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class ScreenBrightnessTest : UiTestPrerequisites() {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
@ -31,19 +30,19 @@ class ScreenBrightnessTest : UiTestPrerequisites() {
|
|||
runTest {
|
||||
val testSetup = TestSetup(composeTestRule)
|
||||
|
||||
assertEquals(1, testSetup.getSecureBrightnessCount())
|
||||
assertEquals(ScreenBrightnessState.FULL, testSetup.getSecureBrightnessCount())
|
||||
|
||||
testSetup.mutableScreenBrightnessFlag.update { false }
|
||||
composeTestRule.awaitIdle()
|
||||
assertEquals(0, testSetup.getSecureBrightnessCount())
|
||||
assertEquals(ScreenBrightnessState.NORMAL, testSetup.getSecureBrightnessCount())
|
||||
}
|
||||
|
||||
private class TestSetup(composeTestRule: ComposeContentTestRule) {
|
||||
val mutableScreenBrightnessFlag = MutableStateFlow(true)
|
||||
|
||||
private val screenBrightness = ScreenBrightness()
|
||||
private val screenBrightness = ScreenBrightness
|
||||
|
||||
fun getSecureBrightnessCount() = screenBrightness.referenceCount.value
|
||||
fun getSecureBrightnessCount() = screenBrightness.referenceSwitch.value
|
||||
|
||||
init {
|
||||
runTest {
|
||||
|
|
|
@ -3,6 +3,7 @@ package co.electriccoin.zcash.ui.screen.about.view
|
|||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.screen.support.model.ConfigInfo
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
@ -24,10 +25,11 @@ class AboutViewTestSetup(
|
|||
ZcashTheme {
|
||||
About(
|
||||
onBack = { onBackCount.incrementAndGet() },
|
||||
versionInfo = versionInfo,
|
||||
configInfo = configInfo,
|
||||
onPrivacyPolicy = {},
|
||||
snackbarHostState = SnackbarHostState()
|
||||
snackbarHostState = SnackbarHostState(),
|
||||
versionInfo = versionInfo,
|
||||
walletRestoringState = WalletRestoringState.NONE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package co.electriccoin.zcash.ui.screen.account
|
|||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.screen.account.history.fixture.TransactionHistoryUiStateFixture
|
||||
|
@ -58,8 +59,6 @@ class AccountTestSetup(
|
|||
@Suppress("TestFunctionName")
|
||||
fun DefaultContent() {
|
||||
Account(
|
||||
walletSnapshot = walletSnapshot,
|
||||
isKeepScreenOnWhileSyncing = false,
|
||||
goSettings = {
|
||||
onSettingsCount.incrementAndGet()
|
||||
},
|
||||
|
@ -68,6 +67,8 @@ class AccountTestSetup(
|
|||
onTransactionItemAction = {
|
||||
onItemClickCount.incrementAndGet()
|
||||
},
|
||||
walletSnapshot = walletSnapshot,
|
||||
walletRestoringState = WalletRestoringState.NONE,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package co.electriccoin.zcash.ui.screen.account.history
|
||||
|
||||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.screen.account.model.TransactionUiState
|
||||
import co.electriccoin.zcash.ui.screen.account.view.HistoryContainer
|
||||
|
@ -30,7 +31,8 @@ class HistoryTestSetup(
|
|||
transactionState = initialHistoryUiState,
|
||||
onTransactionItemAction = {
|
||||
onItemIdClickCount.incrementAndGet()
|
||||
}
|
||||
},
|
||||
walletRestoringState = WalletRestoringState.NONE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,16 +7,16 @@ import kotlinx.collections.immutable.ImmutableList
|
|||
|
||||
internal object TransactionHistoryUiStateFixture {
|
||||
val TRANSACTIONS = TransactionsFixture.new()
|
||||
val STATE = TransactionUiState.Prepared(TRANSACTIONS)
|
||||
val STATE = TransactionUiState.Done(TRANSACTIONS)
|
||||
|
||||
fun new(
|
||||
transactions: ImmutableList<TransactionUi> = TRANSACTIONS,
|
||||
state: TransactionUiState = STATE
|
||||
) = when (state) {
|
||||
is TransactionUiState.Loading -> state
|
||||
is TransactionUiState.Syncing -> state
|
||||
is TransactionUiState.Prepared -> {
|
||||
state.copy(transactions)
|
||||
}
|
||||
is TransactionUiState.Syncing -> state.copy(transactions)
|
||||
is TransactionUiState.Done -> state.copy(transactions)
|
||||
TransactionUiState.DoneEmpty -> state
|
||||
TransactionUiState.SyncingEmpty -> state
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ class HistoryViewTest {
|
|||
fun check_syncing_state() {
|
||||
newTestSetup(
|
||||
TransactionHistoryUiStateFixture.new(
|
||||
state = TransactionUiState.Prepared(persistentListOf()),
|
||||
state = TransactionUiState.Syncing(persistentListOf()),
|
||||
transactions = TransactionHistoryUiStateFixture.TRANSACTIONS
|
||||
)
|
||||
)
|
||||
|
@ -62,7 +62,7 @@ class HistoryViewTest {
|
|||
fun check_done_state_no_transactions() {
|
||||
newTestSetup(
|
||||
TransactionHistoryUiStateFixture.new(
|
||||
state = TransactionUiState.Prepared(persistentListOf()),
|
||||
state = TransactionUiState.Syncing(persistentListOf()),
|
||||
transactions = TransactionHistoryUiStateFixture.TRANSACTIONS
|
||||
)
|
||||
)
|
||||
|
@ -85,7 +85,7 @@ class HistoryViewTest {
|
|||
fun check_done_state_with_transactions() {
|
||||
newTestSetup(
|
||||
TransactionHistoryUiStateFixture.new(
|
||||
state = TransactionUiState.Prepared(persistentListOf()),
|
||||
state = TransactionUiState.Syncing(persistentListOf()),
|
||||
transactions = TransactionHistoryUiStateFixture.TRANSACTIONS
|
||||
)
|
||||
)
|
||||
|
|
|
@ -2,6 +2,7 @@ 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.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.screen.balances.model.ShieldState
|
||||
|
@ -33,13 +34,13 @@ class BalancesTestSetup(
|
|||
onSettingsCount.incrementAndGet()
|
||||
},
|
||||
isFiatConversionEnabled = isShowFiatConversion,
|
||||
isKeepScreenOnWhileSyncing = false,
|
||||
isUpdateAvailable = false,
|
||||
isShowingErrorDialog = false,
|
||||
setShowErrorDialog = {},
|
||||
onShielding = {},
|
||||
shieldState = ShieldState.Available,
|
||||
walletSnapshot = walletSnapshot,
|
||||
isShowingErrorDialog = false,
|
||||
setShowErrorDialog = {}
|
||||
walletRestoringState = WalletRestoringState.NONE
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package co.electriccoin.zcash.ui.screen.exportdata.view
|
|||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
@ -33,7 +34,7 @@ class ExportPrivateDataViewTestSetup(private val composeTestRule: ComposeContent
|
|||
@Suppress("TestFunctionName")
|
||||
fun DefaultContent() {
|
||||
ExportPrivateData(
|
||||
SnackbarHostState(),
|
||||
snackbarHostState = SnackbarHostState(),
|
||||
onBack = {
|
||||
onBackCount.incrementAndGet()
|
||||
},
|
||||
|
@ -42,7 +43,8 @@ class ExportPrivateDataViewTestSetup(private val composeTestRule: ComposeContent
|
|||
},
|
||||
onConfirm = {
|
||||
onConfirmCount.incrementAndGet()
|
||||
}
|
||||
},
|
||||
walletRestoringState = WalletRestoringState.NONE
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import androidx.test.filters.MediumTest
|
|||
import cash.z.ecc.android.sdk.fixture.WalletAddressesFixture
|
||||
import cash.z.ecc.android.sdk.model.WalletAddresses
|
||||
import co.electriccoin.zcash.test.UiTestPrerequisites
|
||||
import co.electriccoin.zcash.ui.common.compose.ScreenBrightnessState
|
||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||
import co.electriccoin.zcash.ui.fixture.VersionInfoFixture
|
||||
import kotlinx.coroutines.test.runTest
|
||||
|
@ -27,7 +28,7 @@ class ReceiveViewScreenBrightnessTest : UiTestPrerequisites() {
|
|||
VersionInfoFixture.new(isDebuggable = true)
|
||||
)
|
||||
|
||||
assertEquals(0, testSetup.getScreenBrightnessCount())
|
||||
assertEquals(ScreenBrightnessState.NORMAL, testSetup.getScreenBrightness())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -41,13 +42,11 @@ class ReceiveViewScreenBrightnessTest : UiTestPrerequisites() {
|
|||
VersionInfoFixture.new(isDebuggable = true)
|
||||
)
|
||||
|
||||
assertEquals(false, testSetup.getOnAdjustBrightness())
|
||||
assertEquals(0, testSetup.getScreenBrightnessCount())
|
||||
assertEquals(ScreenBrightnessState.NORMAL, testSetup.getOnAdjustBrightness())
|
||||
|
||||
composeTestRule.clickAdjustBrightness()
|
||||
|
||||
assertEquals(true, testSetup.getOnAdjustBrightness())
|
||||
assertEquals(1, testSetup.getScreenBrightnessCount())
|
||||
assertEquals(ScreenBrightnessState.FULL, testSetup.getOnAdjustBrightness())
|
||||
}
|
||||
|
||||
private fun newTestSetup(
|
||||
|
|
|
@ -40,12 +40,10 @@ class ReceiveViewScreenTimeoutTest : UiTestPrerequisites() {
|
|||
VersionInfoFixture.new(isDebuggable = true)
|
||||
)
|
||||
|
||||
assertEquals(false, testSetup.getOnAdjustBrightness())
|
||||
assertEquals(0, testSetup.getScreenTimeoutCount())
|
||||
|
||||
composeTestRule.clickAdjustBrightness()
|
||||
|
||||
assertEquals(true, testSetup.getOnAdjustBrightness())
|
||||
assertEquals(1, testSetup.getScreenTimeoutCount())
|
||||
}
|
||||
|
||||
|
|
|
@ -10,12 +10,13 @@ import co.electriccoin.zcash.ui.R
|
|||
import co.electriccoin.zcash.ui.common.compose.LocalScreenBrightness
|
||||
import co.electriccoin.zcash.ui.common.compose.LocalScreenTimeout
|
||||
import co.electriccoin.zcash.ui.common.compose.ScreenBrightness
|
||||
import co.electriccoin.zcash.ui.common.compose.ScreenBrightnessState
|
||||
import co.electriccoin.zcash.ui.common.compose.ScreenTimeout
|
||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.fixture.VersionInfoFixture
|
||||
import co.electriccoin.zcash.ui.test.getStringResource
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
class ReceiveViewTestSetup(
|
||||
|
@ -25,17 +26,17 @@ class ReceiveViewTestSetup(
|
|||
) {
|
||||
private val onSettingsCount = AtomicInteger(0)
|
||||
private val onAddressDetailsCount = AtomicInteger(0)
|
||||
private val screenBrightness = ScreenBrightness()
|
||||
private val screenBrightness = ScreenBrightness
|
||||
private val screenTimeout = ScreenTimeout()
|
||||
private val onAdjustBrightness = AtomicBoolean(false)
|
||||
private var onAdjustBrightness: ScreenBrightnessState = ScreenBrightnessState.NORMAL
|
||||
|
||||
fun getScreenBrightnessCount() = screenBrightness.referenceCount.value
|
||||
fun getScreenBrightness() = screenBrightness.referenceSwitch.value
|
||||
|
||||
fun getScreenTimeoutCount() = screenTimeout.referenceCount.value
|
||||
|
||||
fun getOnAdjustBrightness(): Boolean {
|
||||
fun getOnAdjustBrightness(): ScreenBrightnessState {
|
||||
composeTestRule.waitForIdle()
|
||||
return onAdjustBrightness.get()
|
||||
return onAdjustBrightness
|
||||
}
|
||||
|
||||
fun getOnSettingsCount(): Int {
|
||||
|
@ -63,11 +64,14 @@ class ReceiveViewTestSetup(
|
|||
onSettingsCount.getAndIncrement()
|
||||
},
|
||||
onAdjustBrightness = {
|
||||
onAdjustBrightness.getAndSet(it)
|
||||
onAdjustBrightness = onAdjustBrightness.getChange()
|
||||
screenTimeout.disableScreenTimeout()
|
||||
},
|
||||
onAddrCopyToClipboard = {},
|
||||
onQrImageShare = {},
|
||||
versionInfo = versionInfo
|
||||
screenBrightnessState = ScreenBrightnessState.NORMAL,
|
||||
versionInfo = versionInfo,
|
||||
walletRestoringState = WalletRestoringState.NONE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||
import cash.z.ecc.sdk.fixture.PersistableWalletFixture
|
||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
|
@ -39,10 +40,11 @@ class SeedRecoveryTestSetup(
|
|||
SeedRecovery(
|
||||
PersistableWalletFixture.new(),
|
||||
onBack = { onBackCount.incrementAndGet() },
|
||||
onSeedCopy = { /* Not tested - debug mode feature only */ },
|
||||
onBirthdayCopy = { onBirthdayCopyCount.incrementAndGet() },
|
||||
onDone = { onCompleteCallbackCount.incrementAndGet() },
|
||||
onSeedCopy = { /* Not tested - debug mode feature only */ },
|
||||
versionInfo = versionInfo,
|
||||
walletRestoringState = WalletRestoringState.NONE,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import cash.z.ecc.sdk.fixture.PersistableWalletFixture
|
|||
import co.electriccoin.zcash.test.UiTestPrerequisites
|
||||
import co.electriccoin.zcash.ui.common.compose.LocalScreenSecurity
|
||||
import co.electriccoin.zcash.ui.common.compose.ScreenSecurity
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.fixture.VersionInfoFixture
|
||||
import kotlinx.coroutines.test.runTest
|
||||
|
@ -45,10 +46,11 @@ class SeedRecoveryViewsSecuredScreenTest : UiTestPrerequisites() {
|
|||
SeedRecovery(
|
||||
PersistableWalletFixture.new(),
|
||||
onBack = {},
|
||||
onSeedCopy = {},
|
||||
onBirthdayCopy = {},
|
||||
onDone = {},
|
||||
versionInfo = VersionInfoFixture.new()
|
||||
onSeedCopy = {},
|
||||
versionInfo = VersionInfoFixture.new(),
|
||||
walletRestoringState = WalletRestoringState.NONE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import cash.z.ecc.android.sdk.model.MonetarySeparators
|
|||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
import cash.z.ecc.android.sdk.model.ZecSend
|
||||
import cash.z.ecc.android.sdk.type.AddressType
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.fixture.WalletSnapshotFixture
|
||||
import co.electriccoin.zcash.ui.screen.send.ext.Saver
|
||||
|
@ -137,6 +138,7 @@ class SendViewTestSetup(
|
|||
setAmountState = {},
|
||||
memoState = MemoState.new(""),
|
||||
setMemoState = {},
|
||||
walletRestoringState = WalletRestoringState.NONE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import cash.z.ecc.android.sdk.model.MonetarySeparators
|
|||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||
import cash.z.ecc.sdk.fixture.ZecSendFixture
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.fixture.MockSynchronizer
|
||||
import co.electriccoin.zcash.ui.fixture.WalletSnapshotFixture
|
||||
import co.electriccoin.zcash.ui.screen.send.WrapSend
|
||||
|
@ -78,7 +79,8 @@ class SendViewIntegrationTest {
|
|||
hasCameraFeature = true,
|
||||
goSettings = {},
|
||||
monetarySeparators = monetarySeparators,
|
||||
goSendConfirmation = {}
|
||||
goSendConfirmation = {},
|
||||
walletRestoringState = WalletRestoringState.NONE,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package co.electriccoin.zcash.ui.screen.settings
|
||||
|
||||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.screen.settings.model.TroubleshootingParameters
|
||||
import co.electriccoin.zcash.ui.screen.settings.view.Settings
|
||||
|
@ -87,7 +88,8 @@ class SettingsViewTestSetup(
|
|||
},
|
||||
onAnalyticsSettingsChanged = {
|
||||
onAnalyticsChangedCount.incrementAndGet()
|
||||
}
|
||||
},
|
||||
walletRestoringState = WalletRestoringState.NONE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package co.electriccoin.zcash.ui.screen.support.view
|
|||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
@ -36,7 +37,8 @@ class SupportViewTestSetup(private val composeTestRule: ComposeContentTestRule)
|
|||
@Suppress("TestFunctionName")
|
||||
fun DefaultContent() {
|
||||
Support(
|
||||
snackbarHostState = SnackbarHostState(),
|
||||
isShowingDialog = false,
|
||||
setShowDialog = {},
|
||||
onBack = {
|
||||
onBackCount.incrementAndGet()
|
||||
},
|
||||
|
@ -44,8 +46,8 @@ class SupportViewTestSetup(private val composeTestRule: ComposeContentTestRule)
|
|||
onSendCount.incrementAndGet()
|
||||
onSendMessage.set(it)
|
||||
},
|
||||
isShowingDialog = false,
|
||||
setShowDialog = {}
|
||||
snackbarHostState = SnackbarHostState(),
|
||||
walletRestoringState = WalletRestoringState.NONE
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import cash.z.ecc.sdk.type.fromResources
|
|||
import co.electriccoin.zcash.spackle.FirebaseTestLabUtil
|
||||
import co.electriccoin.zcash.ui.common.compose.BindCompLocalProvider
|
||||
import co.electriccoin.zcash.ui.common.model.OnboardingState
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.HomeViewModel
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.SecretState
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||
|
@ -53,7 +54,7 @@ import kotlin.time.Duration.Companion.milliseconds
|
|||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
val homeViewModel by viewModels<HomeViewModel>()
|
||||
private val homeViewModel by viewModels<HomeViewModel>()
|
||||
|
||||
val walletViewModel by viewModels<WalletViewModel>()
|
||||
|
||||
|
@ -173,6 +174,7 @@ class MainActivity : ComponentActivity() {
|
|||
)
|
||||
} else {
|
||||
walletViewModel.persistNewWallet()
|
||||
walletViewModel.persistWalletRestoringState(WalletRestoringState.INITIATING)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -74,9 +74,6 @@ internal fun MainActivity.Navigation() {
|
|||
WrapHome(
|
||||
goBack = { finish() },
|
||||
goScan = { navController.navigateJustOnce(SCAN) },
|
||||
onPageChange = {
|
||||
homeViewModel.screenIndex.value = it
|
||||
},
|
||||
goSendConfirmation = { zecSend ->
|
||||
navController.currentBackStackEntry?.savedStateHandle?.let { handle ->
|
||||
fillInHandleForConfirmation(handle, zecSend, SendConfirmationStage.Confirmation)
|
||||
|
@ -140,7 +137,7 @@ internal fun MainActivity.Navigation() {
|
|||
},
|
||||
goChooseServer = {
|
||||
navController.navigateJustOnce(CHOOSE_SERVER)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
composable(CHOOSE_SERVER) {
|
||||
|
@ -157,7 +154,7 @@ internal fun MainActivity.Navigation() {
|
|||
},
|
||||
onDone = {
|
||||
navController.popBackStackJustOnce(SEED_RECOVERY)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
composable(REQUEST) {
|
||||
|
|
|
@ -15,7 +15,7 @@ fun ComponentActivity.BindCompLocalProvider(content: @Composable () -> Unit) {
|
|||
val screenSecurity = ScreenSecurity()
|
||||
observeScreenSecurityFlag(screenSecurity)
|
||||
|
||||
val screenBrightness = ScreenBrightness()
|
||||
val screenBrightness = ScreenBrightness
|
||||
observeScreenBrightnessFlag(screenBrightness)
|
||||
|
||||
val screenTimeout = ScreenTimeout()
|
||||
|
@ -46,19 +46,21 @@ private fun ComponentActivity.observeScreenSecurityFlag(screenSecurity: ScreenSe
|
|||
}
|
||||
|
||||
private fun ComponentActivity.observeScreenBrightnessFlag(screenBrightness: ScreenBrightness) {
|
||||
screenBrightness.referenceCount.map { it > 0 }.collectWith(lifecycleScope) { maxBrightness ->
|
||||
if (maxBrightness) {
|
||||
window.attributes =
|
||||
window.attributes.apply {
|
||||
this.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL
|
||||
}
|
||||
} else {
|
||||
window.attributes =
|
||||
window.attributes.apply {
|
||||
this.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
|
||||
}
|
||||
screenBrightness.referenceSwitch
|
||||
.map { it == ScreenBrightnessState.FULL }
|
||||
.collectWith(lifecycleScope) { maxBrightness ->
|
||||
if (maxBrightness) {
|
||||
window.attributes =
|
||||
window.attributes.apply {
|
||||
this.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL
|
||||
}
|
||||
} else {
|
||||
window.attributes =
|
||||
window.attributes.apply {
|
||||
this.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ComponentActivity.observeScreenTimeoutFlag(screenTimeout: ScreenTimeout) {
|
||||
|
|
|
@ -6,28 +6,32 @@ import androidx.compose.runtime.compositionLocalOf
|
|||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.flow.updateAndGet
|
||||
|
||||
class ScreenBrightness {
|
||||
private val mutableReferenceCount: MutableStateFlow<Int> = MutableStateFlow(0)
|
||||
|
||||
val referenceCount = mutableReferenceCount.asStateFlow()
|
||||
|
||||
fun fullBrightness() {
|
||||
mutableReferenceCount.update { it + 1 }
|
||||
}
|
||||
|
||||
fun restoreBrightness() {
|
||||
val after = mutableReferenceCount.updateAndGet { it - 1 }
|
||||
|
||||
if (after < 0) {
|
||||
error("Released brightness reference count too many times")
|
||||
sealed class ScreenBrightnessState {
|
||||
fun getChange(): ScreenBrightnessState {
|
||||
return when (this) {
|
||||
NORMAL -> FULL
|
||||
FULL -> NORMAL
|
||||
}
|
||||
}
|
||||
|
||||
data object FULL : ScreenBrightnessState()
|
||||
|
||||
data object NORMAL : ScreenBrightnessState()
|
||||
}
|
||||
|
||||
object ScreenBrightness {
|
||||
private val mutableSwitch: MutableStateFlow<ScreenBrightnessState> = MutableStateFlow(ScreenBrightnessState.NORMAL)
|
||||
|
||||
val referenceSwitch = mutableSwitch.asStateFlow()
|
||||
|
||||
fun fullBrightness() = mutableSwitch.update { ScreenBrightnessState.FULL }
|
||||
|
||||
fun restoreBrightness() = mutableSwitch.update { ScreenBrightnessState.NORMAL }
|
||||
}
|
||||
|
||||
@Suppress("CompositionLocalAllowlist")
|
||||
val LocalScreenBrightness = compositionLocalOf { ScreenBrightness() }
|
||||
val LocalScreenBrightness = compositionLocalOf { ScreenBrightness }
|
||||
|
||||
@Composable
|
||||
fun BrightenScreen() {
|
||||
|
@ -37,3 +41,9 @@ fun BrightenScreen() {
|
|||
onDispose { screenBrightness.restoreBrightness() }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RestoreScreenBrightness() {
|
||||
val screenBrightness = LocalScreenBrightness.current
|
||||
screenBrightness.restoreBrightness()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package co.electriccoin.zcash.ui.common.model
|
||||
|
||||
/**
|
||||
* Common wallet restoring state enum. This describes whether the current block synchronization run is in the
|
||||
* restoring state or a subsequent synchronization state.
|
||||
*
|
||||
* WARN: Do NOT reorder or change the values; doing so would update their ordinal numbers, which could break the
|
||||
* wallet UI.
|
||||
*/
|
||||
enum class WalletRestoringState {
|
||||
NONE,
|
||||
INITIATING, // New wallet syncing
|
||||
RESTORING, // Existing wallet syncing
|
||||
SYNCING; // Follow-up syncing
|
||||
|
||||
fun isRunningRestoring() = this == NONE || this == RESTORING
|
||||
|
||||
fun toNumber() = ordinal
|
||||
|
||||
companion object {
|
||||
fun fromNumber(ordinal: Int) = entries[ordinal]
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@ import co.electriccoin.zcash.spackle.Twig
|
|||
import co.electriccoin.zcash.ui.common.ANDROID_STATE_FLOW_TIMEOUT
|
||||
import co.electriccoin.zcash.ui.common.extension.throttle
|
||||
import co.electriccoin.zcash.ui.common.model.OnboardingState
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||
import co.electriccoin.zcash.ui.preference.EncryptedPreferenceKeys
|
||||
import co.electriccoin.zcash.ui.preference.EncryptedPreferenceSingleton
|
||||
|
@ -98,6 +99,23 @@ class WalletViewModel(application: Application) : AndroidViewModel(application)
|
|||
null
|
||||
)
|
||||
|
||||
/**
|
||||
* A flow of the wallet block synchronization state.
|
||||
*/
|
||||
val walletRestoringState: StateFlow<WalletRestoringState> =
|
||||
flow {
|
||||
val preferenceProvider = StandardPreferenceSingleton.getInstance(application)
|
||||
emitAll(
|
||||
StandardPreferenceKeys.WALLET_RESTORING_STATE.observe(preferenceProvider).map { persistedNumber ->
|
||||
WalletRestoringState.fromNumber(persistedNumber)
|
||||
}
|
||||
)
|
||||
}.stateIn(
|
||||
viewModelScope,
|
||||
SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT),
|
||||
WalletRestoringState.NONE
|
||||
)
|
||||
|
||||
/**
|
||||
* A flow of the wallet onboarding state.
|
||||
*/
|
||||
|
@ -288,12 +306,28 @@ class WalletViewModel(application: Application) : AndroidViewModel(application)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously notes that the wallet has completed the initial wallet restoring block synchronization run.
|
||||
*
|
||||
* Note that in the current SDK implementation, we don't have any information about the block synchronization
|
||||
* state from the SDK, and thus, we need to note the wallet restoring state here on the client side.
|
||||
*/
|
||||
fun persistWalletRestoringState(walletRestoringState: WalletRestoringState) {
|
||||
val application = getApplication<Application>()
|
||||
|
||||
viewModelScope.launch {
|
||||
val preferenceProvider = StandardPreferenceSingleton.getInstance(application)
|
||||
StandardPreferenceKeys.WALLET_RESTORING_STATE.putValue(preferenceProvider, walletRestoringState.toNumber())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method only has an effect if the synchronizer currently is loaded.
|
||||
*/
|
||||
fun rescanBlockchain() {
|
||||
viewModelScope.launch {
|
||||
walletCoordinator.rescanBlockchain()
|
||||
persistWalletRestoringState(WalletRestoringState.RESTORING)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -435,4 +469,6 @@ private fun Synchronizer.toWalletSnapshot() =
|
|||
)
|
||||
}
|
||||
|
||||
private fun Synchronizer.Status.isSyncing() = this == Synchronizer.Status.SYNCING
|
||||
fun Synchronizer.Status.isSyncing() = this == Synchronizer.Status.SYNCING
|
||||
|
||||
fun Synchronizer.Status.isSynced() = this == Synchronizer.Status.SYNCED
|
||||
|
|
|
@ -4,6 +4,7 @@ import co.electriccoin.zcash.preference.model.entry.BooleanPreferenceDefault
|
|||
import co.electriccoin.zcash.preference.model.entry.IntegerPreferenceDefault
|
||||
import co.electriccoin.zcash.preference.model.entry.PreferenceKey
|
||||
import co.electriccoin.zcash.ui.common.model.OnboardingState
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
|
||||
object StandardPreferenceKeys {
|
||||
/**
|
||||
|
@ -15,6 +16,16 @@ object StandardPreferenceKeys {
|
|||
OnboardingState.NONE.toNumber()
|
||||
)
|
||||
|
||||
/**
|
||||
* State defining whether the current block synchronization run is in the restoring state or a subsequent
|
||||
* synchronization state.
|
||||
*/
|
||||
val WALLET_RESTORING_STATE =
|
||||
IntegerPreferenceDefault(
|
||||
PreferenceKey("wallet_restoring_state"),
|
||||
WalletRestoringState.RESTORING.toNumber()
|
||||
)
|
||||
|
||||
// Default to true until https://github.com/Electric-Coin-Company/zashi-android/issues/304
|
||||
val IS_ANALYTICS_ENABLED = BooleanPreferenceDefault(PreferenceKey("is_analytics_enabled"), true)
|
||||
|
||||
|
|
|
@ -4,15 +4,19 @@ package co.electriccoin.zcash.ui.screen.about
|
|||
|
||||
import android.content.Context
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import co.electriccoin.zcash.configuration.AndroidConfigurationFactory
|
||||
import co.electriccoin.zcash.ui.MainActivity
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.screen.about.util.WebBrowserUtil
|
||||
import co.electriccoin.zcash.ui.screen.about.view.About
|
||||
import co.electriccoin.zcash.ui.screen.support.model.ConfigInfo
|
||||
|
@ -21,13 +25,22 @@ import kotlinx.coroutines.launch
|
|||
|
||||
@Composable
|
||||
internal fun MainActivity.WrapAbout(goBack: () -> Unit) {
|
||||
WrapAbout(this, goBack)
|
||||
val walletViewModel by viewModels<WalletViewModel>()
|
||||
|
||||
val walletRestoringState = walletViewModel.walletRestoringState.collectAsStateWithLifecycle().value
|
||||
|
||||
WrapAbout(
|
||||
activity = this,
|
||||
goBack = goBack,
|
||||
walletRestoringState = walletRestoringState
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun WrapAbout(
|
||||
activity: ComponentActivity,
|
||||
goBack: () -> Unit
|
||||
goBack: () -> Unit,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
val configInfo = ConfigInfo.new(AndroidConfigurationFactory.getInstance(activity.applicationContext))
|
||||
val versionInfo = VersionInfo.new(activity.applicationContext)
|
||||
|
@ -38,6 +51,7 @@ internal fun WrapAbout(
|
|||
}
|
||||
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
About(
|
||||
|
@ -52,6 +66,7 @@ internal fun WrapAbout(
|
|||
)
|
||||
},
|
||||
snackbarHostState = snackbarHostState,
|
||||
walletRestoringState = walletRestoringState,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ import androidx.compose.ui.text.withStyle
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||
import co.electriccoin.zcash.ui.design.component.SmallTopAppBar
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
|
@ -55,29 +56,33 @@ private fun AboutPreview() {
|
|||
GradientSurface {
|
||||
About(
|
||||
onBack = {},
|
||||
versionInfo = VersionInfoFixture.new(),
|
||||
configInfo = ConfigInfoFixture.new(),
|
||||
snackbarHostState = SnackbarHostState(),
|
||||
onPrivacyPolicy = {},
|
||||
snackbarHostState = SnackbarHostState(),
|
||||
versionInfo = VersionInfoFixture.new(),
|
||||
walletRestoringState = WalletRestoringState.NONE,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
fun About(
|
||||
onBack: () -> Unit,
|
||||
configInfo: ConfigInfo,
|
||||
onPrivacyPolicy: () -> Unit,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
versionInfo: VersionInfo,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
AboutTopAppBar(
|
||||
onBack = onBack,
|
||||
versionInfo = versionInfo,
|
||||
configInfo = configInfo
|
||||
configInfo = configInfo,
|
||||
showRestoring = walletRestoringState == WalletRestoringState.RESTORING,
|
||||
)
|
||||
},
|
||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||
|
@ -105,9 +110,16 @@ fun About(
|
|||
private fun AboutTopAppBar(
|
||||
onBack: () -> Unit,
|
||||
versionInfo: VersionInfo,
|
||||
configInfo: ConfigInfo
|
||||
configInfo: ConfigInfo,
|
||||
showRestoring: Boolean
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
restoringLabel =
|
||||
if (showRestoring) {
|
||||
stringResource(id = R.string.restoring_wallet_label)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
titleText = stringResource(id = R.string.about_title).uppercase(),
|
||||
backText = stringResource(id = R.string.about_back).uppercase(),
|
||||
backContentDescriptionText = stringResource(R.string.about_back_content_description),
|
||||
|
@ -116,7 +128,7 @@ private fun AboutTopAppBar(
|
|||
if (versionInfo.isDebuggable && !versionInfo.isRunningUnderTestService) {
|
||||
DebugMenu(versionInfo, configInfo)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import cash.z.ecc.android.sdk.Synchronizer
|
|||
import cash.z.ecc.android.sdk.internal.Twig
|
||||
import co.electriccoin.zcash.spackle.ClipboardManagerUtil
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
|
||||
|
@ -19,7 +20,6 @@ import co.electriccoin.zcash.ui.screen.account.model.TransactionUiState
|
|||
import co.electriccoin.zcash.ui.screen.account.view.Account
|
||||
import co.electriccoin.zcash.ui.screen.account.view.TrxItemAction
|
||||
import co.electriccoin.zcash.ui.screen.account.viewmodel.TransactionHistoryViewModel
|
||||
import co.electriccoin.zcash.ui.screen.settings.viewmodel.SettingsViewModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.annotations.VisibleForTesting
|
||||
|
@ -36,12 +36,8 @@ internal fun WrapAccount(
|
|||
|
||||
val transactionHistoryViewModel by activity.viewModels<TransactionHistoryViewModel>()
|
||||
|
||||
val settingsViewModel by activity.viewModels<SettingsViewModel>()
|
||||
|
||||
val walletSnapshot = walletViewModel.walletSnapshot.collectAsStateWithLifecycle().value
|
||||
|
||||
val isKeepScreenOnWhileSyncing = settingsViewModel.isKeepScreenOnWhileSyncing.collectAsStateWithLifecycle().value
|
||||
|
||||
val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value
|
||||
|
||||
val transactionsUiState = transactionHistoryViewModel.transactionUiState.collectAsStateWithLifecycle().value
|
||||
|
@ -50,16 +46,18 @@ internal fun WrapAccount(
|
|||
transactionHistoryViewModel.processTransactionState(value)
|
||||
}
|
||||
|
||||
val walletRestoringState = walletViewModel.walletRestoringState.collectAsStateWithLifecycle().value
|
||||
|
||||
WrapAccount(
|
||||
context = activity.applicationContext,
|
||||
goBalances = goBalances,
|
||||
goSettings = goSettings,
|
||||
isKeepScreenOnWhileSyncing = isKeepScreenOnWhileSyncing,
|
||||
scope = scope,
|
||||
synchronizer = synchronizer,
|
||||
transactionHistoryViewModel = transactionHistoryViewModel,
|
||||
transactionsUiState = transactionsUiState,
|
||||
walletSnapshot = walletSnapshot,
|
||||
walletRestoringState = walletRestoringState
|
||||
)
|
||||
|
||||
// For benchmarking purposes
|
||||
|
@ -78,7 +76,7 @@ internal fun WrapAccount(
|
|||
synchronizer: Synchronizer?,
|
||||
transactionHistoryViewModel: TransactionHistoryViewModel,
|
||||
walletSnapshot: WalletSnapshot?,
|
||||
isKeepScreenOnWhileSyncing: Boolean?,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
if (null == synchronizer || null == walletSnapshot) {
|
||||
// TODO [#1146]: Consider moving CircularScreenProgressIndicator from Android layer to View layer
|
||||
|
@ -88,7 +86,6 @@ internal fun WrapAccount(
|
|||
} else {
|
||||
Account(
|
||||
walletSnapshot = walletSnapshot,
|
||||
isKeepScreenOnWhileSyncing = isKeepScreenOnWhileSyncing,
|
||||
transactionsUiState = transactionsUiState,
|
||||
onTransactionItemAction = { action ->
|
||||
when (action) {
|
||||
|
@ -130,6 +127,7 @@ internal fun WrapAccount(
|
|||
},
|
||||
goBalances = goBalances,
|
||||
goSettings = goSettings,
|
||||
walletRestoringState = walletRestoringState
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,13 @@ import kotlinx.collections.immutable.ImmutableList
|
|||
sealed interface TransactionUiState {
|
||||
data object Loading : TransactionUiState
|
||||
|
||||
data object Syncing : TransactionUiState
|
||||
data object SyncingEmpty : TransactionUiState
|
||||
|
||||
data class Prepared(val transactions: ImmutableList<TransactionUi>) : TransactionUiState
|
||||
data object DoneEmpty : TransactionUiState
|
||||
|
||||
sealed class Prepared(open val transactions: ImmutableList<TransactionUi>) : TransactionUiState
|
||||
|
||||
data class Syncing(override val transactions: ImmutableList<TransactionUi>) : Prepared(transactions)
|
||||
|
||||
data class Done(override val transactions: ImmutableList<TransactionUi>) : Prepared(transactions)
|
||||
}
|
||||
|
|
|
@ -6,9 +6,7 @@ import kotlinx.collections.immutable.ImmutableList
|
|||
sealed interface TransactionHistorySyncState {
|
||||
data object Loading : TransactionHistorySyncState
|
||||
|
||||
sealed class Prepared(open val transactions: ImmutableList<TransactionOverviewExt>) : TransactionHistorySyncState
|
||||
data class Syncing(val transactions: ImmutableList<TransactionOverviewExt>) : TransactionHistorySyncState
|
||||
|
||||
data class Syncing(override val transactions: ImmutableList<TransactionOverviewExt>) : Prepared(transactions)
|
||||
|
||||
data class Done(override val transactions: ImmutableList<TransactionOverviewExt>) : Prepared(transactions)
|
||||
data class Done(val transactions: ImmutableList<TransactionOverviewExt>) : TransactionHistorySyncState
|
||||
}
|
||||
|
|
|
@ -15,10 +15,9 @@ import androidx.compose.ui.platform.testTag
|
|||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import cash.z.ecc.android.sdk.Synchronizer
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.compose.BalanceWidget
|
||||
import co.electriccoin.zcash.ui.common.compose.DisableScreenTimeout
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||
import co.electriccoin.zcash.ui.common.test.CommonTag
|
||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||
|
@ -36,11 +35,11 @@ private fun HistoryLoadingComposablePreview() {
|
|||
GradientSurface {
|
||||
Account(
|
||||
walletSnapshot = WalletSnapshotFixture.new(),
|
||||
isKeepScreenOnWhileSyncing = false,
|
||||
goBalances = {},
|
||||
goSettings = {},
|
||||
transactionsUiState = TransactionUiState.Loading,
|
||||
onTransactionItemAction = {}
|
||||
onTransactionItemAction = {},
|
||||
walletRestoringState = WalletRestoringState.SYNCING
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -54,11 +53,11 @@ private fun HistoryListComposablePreview() {
|
|||
@Suppress("MagicNumber")
|
||||
Account(
|
||||
walletSnapshot = WalletSnapshotFixture.new(),
|
||||
isKeepScreenOnWhileSyncing = false,
|
||||
goBalances = {},
|
||||
goSettings = {},
|
||||
transactionsUiState = TransactionUiState.Prepared(transactions = TransactionsFixture.new()),
|
||||
transactionsUiState = TransactionUiState.Done(transactions = TransactionsFixture.new()),
|
||||
onTransactionItemAction = {},
|
||||
walletRestoringState = WalletRestoringState.NONE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -69,19 +68,22 @@ private fun HistoryListComposablePreview() {
|
|||
internal fun Account(
|
||||
goBalances: () -> Unit,
|
||||
goSettings: () -> Unit,
|
||||
isKeepScreenOnWhileSyncing: Boolean?,
|
||||
onTransactionItemAction: (TrxItemAction) -> Unit,
|
||||
transactionsUiState: TransactionUiState,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
walletSnapshot: WalletSnapshot,
|
||||
) {
|
||||
Scaffold(topBar = {
|
||||
AccountTopAppBar(onSettings = goSettings)
|
||||
AccountTopAppBar(
|
||||
showRestoring = walletRestoringState == WalletRestoringState.RESTORING,
|
||||
onSettings = goSettings
|
||||
)
|
||||
}) { paddingValues ->
|
||||
AccountMainContent(
|
||||
walletSnapshot = walletSnapshot,
|
||||
isKeepScreenOnWhileSyncing = isKeepScreenOnWhileSyncing,
|
||||
goBalances = goBalances,
|
||||
transactionState = transactionsUiState,
|
||||
walletRestoringState = walletRestoringState,
|
||||
onTransactionItemAction = onTransactionItemAction,
|
||||
modifier =
|
||||
Modifier.padding(
|
||||
|
@ -94,8 +96,17 @@ internal fun Account(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun AccountTopAppBar(onSettings: () -> Unit) {
|
||||
private fun AccountTopAppBar(
|
||||
onSettings: () -> Unit,
|
||||
showRestoring: Boolean
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
restoringLabel =
|
||||
if (showRestoring) {
|
||||
stringResource(id = R.string.restoring_wallet_label)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
showTitleLogo = true,
|
||||
hamburgerMenuActions = {
|
||||
IconButton(
|
||||
|
@ -115,11 +126,11 @@ private fun AccountTopAppBar(onSettings: () -> Unit) {
|
|||
@Suppress("LongParameterList")
|
||||
private fun AccountMainContent(
|
||||
walletSnapshot: WalletSnapshot,
|
||||
isKeepScreenOnWhileSyncing: Boolean?,
|
||||
goBalances: () -> Unit,
|
||||
onTransactionItemAction: (TrxItemAction) -> Unit,
|
||||
transactionState: TransactionUiState,
|
||||
modifier: Modifier = Modifier
|
||||
walletRestoringState: WalletRestoringState,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
|
@ -139,12 +150,9 @@ private fun AccountMainContent(
|
|||
|
||||
HistoryContainer(
|
||||
transactionState = transactionState,
|
||||
walletRestoringState = walletRestoringState,
|
||||
onTransactionItemAction = onTransactionItemAction,
|
||||
)
|
||||
|
||||
if (isKeepScreenOnWhileSyncing == true && walletSnapshot.status == Synchronizer.Status.SYNCING) {
|
||||
DisableScreenTimeout()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ import cash.z.ecc.android.sdk.model.TransactionState
|
|||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
import cash.z.ecc.android.sdk.model.toZecString
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.design.component.CircularMidProgressIndicator
|
||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||
import co.electriccoin.zcash.ui.design.component.StyledBalance
|
||||
|
@ -70,7 +71,8 @@ private fun ComposablePreview() {
|
|||
GradientSurface {
|
||||
HistoryContainer(
|
||||
transactionState = TransactionUiState.Loading,
|
||||
onTransactionItemAction = {}
|
||||
onTransactionItemAction = {},
|
||||
walletRestoringState = WalletRestoringState.SYNCING
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -82,8 +84,9 @@ private fun ComposableHistoryListPreview() {
|
|||
ZcashTheme(forceDarkMode = false) {
|
||||
GradientSurface {
|
||||
HistoryContainer(
|
||||
transactionState = TransactionUiState.Prepared(transactions = TransactionsFixture.new()),
|
||||
onTransactionItemAction = {}
|
||||
transactionState = TransactionUiState.Done(transactions = TransactionsFixture.new()),
|
||||
onTransactionItemAction = {},
|
||||
walletRestoringState = WalletRestoringState.NONE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +105,8 @@ private val dateFormat: DateFormat by lazy {
|
|||
internal fun HistoryContainer(
|
||||
transactionState: TransactionUiState,
|
||||
onTransactionItemAction: (TrxItemAction) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
walletRestoringState: WalletRestoringState,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(
|
||||
modifier =
|
||||
|
@ -114,42 +118,61 @@ internal fun HistoryContainer(
|
|||
)
|
||||
) {
|
||||
when (transactionState) {
|
||||
TransactionUiState.Loading, TransactionUiState.Syncing -> {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingUpLarge))
|
||||
CircularMidProgressIndicator(
|
||||
modifier = Modifier.testTag(HistoryTag.PROGRESS),
|
||||
)
|
||||
TransactionUiState.Loading -> {
|
||||
LoadingTransactionHistory()
|
||||
}
|
||||
TransactionUiState.SyncingEmpty -> {
|
||||
if (walletRestoringState == WalletRestoringState.INITIATING) {
|
||||
// In case we are syncing a new wallet, it's empty
|
||||
EmptyTransactionHistory()
|
||||
} else {
|
||||
// Intentionally leaving the UI empty otherwise
|
||||
}
|
||||
}
|
||||
is TransactionUiState.Prepared -> {
|
||||
if (transactionState.transactions.isEmpty()) {
|
||||
Column {
|
||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingUpLarge))
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textAlign = TextAlign.Center,
|
||||
text = stringResource(id = R.string.account_history_empty),
|
||||
style = ZcashTheme.extendedTypography.transactionItemStyles.titleRegular,
|
||||
color = ZcashTheme.colors.textCommon,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
HistoryList(
|
||||
transactions = transactionState.transactions,
|
||||
onAction = onTransactionItemAction,
|
||||
)
|
||||
}
|
||||
HistoryList(
|
||||
transactions = transactionState.transactions,
|
||||
onAction = onTransactionItemAction,
|
||||
)
|
||||
}
|
||||
is TransactionUiState.DoneEmpty -> {
|
||||
EmptyTransactionHistory()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LoadingTransactionHistory() {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingUpLarge))
|
||||
|
||||
CircularMidProgressIndicator(
|
||||
modifier = Modifier.testTag(HistoryTag.PROGRESS),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EmptyTransactionHistory() {
|
||||
Column {
|
||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingUpLarge))
|
||||
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textAlign = TextAlign.Center,
|
||||
text = stringResource(id = R.string.account_history_empty),
|
||||
style = ZcashTheme.extendedTypography.transactionItemStyles.titleRegular,
|
||||
color = ZcashTheme.colors.textCommon,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun HistoryList(
|
||||
transactions: ImmutableList<TransactionUi>,
|
||||
|
|
|
@ -8,6 +8,7 @@ import cash.z.ecc.android.sdk.internal.Twig
|
|||
import cash.z.ecc.android.sdk.model.FirstClassByteArray
|
||||
import cash.z.ecc.android.sdk.model.TransactionOverview
|
||||
import co.electriccoin.zcash.ui.common.ANDROID_STATE_FLOW_TIMEOUT
|
||||
import co.electriccoin.zcash.ui.screen.account.ext.TransactionOverviewExt
|
||||
import co.electriccoin.zcash.ui.screen.account.model.TransactionUi
|
||||
import co.electriccoin.zcash.ui.screen.account.model.TransactionUiState
|
||||
import co.electriccoin.zcash.ui.screen.account.model.TrxItemState
|
||||
|
@ -19,19 +20,23 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.WhileSubscribed
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.toList
|
||||
|
||||
class TransactionHistoryViewModel(application: Application) : AndroidViewModel(application) {
|
||||
private val state: MutableStateFlow<State> = MutableStateFlow(State.LOADING)
|
||||
|
||||
private val transactions: MutableStateFlow<ImmutableList<TransactionUi>> = MutableStateFlow(persistentListOf())
|
||||
|
||||
val transactionUiState: StateFlow<TransactionUiState> =
|
||||
transactions.map {
|
||||
if (it.isEmpty()) {
|
||||
TransactionUiState.Syncing
|
||||
} else {
|
||||
TransactionUiState.Prepared(it)
|
||||
state.combine(transactions) { state: State, transactions: ImmutableList<TransactionUi> ->
|
||||
when (state) {
|
||||
State.LOADING -> TransactionUiState.Loading
|
||||
State.SYNCING -> TransactionUiState.Syncing(transactions)
|
||||
State.SYNCING_EMPTY -> TransactionUiState.SyncingEmpty
|
||||
State.DONE -> TransactionUiState.Done(transactions)
|
||||
State.DONE_EMPTY -> TransactionUiState.DoneEmpty
|
||||
}
|
||||
}.stateIn(
|
||||
viewModelScope,
|
||||
|
@ -40,26 +45,49 @@ class TransactionHistoryViewModel(application: Application) : AndroidViewModel(a
|
|||
)
|
||||
|
||||
fun processTransactionState(dataState: TransactionHistorySyncState) {
|
||||
transactions.value =
|
||||
when (dataState) {
|
||||
TransactionHistorySyncState.Loading -> persistentListOf()
|
||||
is TransactionHistorySyncState.Prepared -> {
|
||||
dataState.transactions.map { data ->
|
||||
val existingTransaction =
|
||||
transactions.value.find {
|
||||
data.overview.rawId == it.overview.rawId
|
||||
}
|
||||
TransactionUi.new(
|
||||
data = data,
|
||||
expandableState = existingTransaction?.expandableState ?: TrxItemState.COLLAPSED,
|
||||
messages = existingTransaction?.messages,
|
||||
)
|
||||
}.toPersistentList()
|
||||
when (dataState) {
|
||||
TransactionHistorySyncState.Loading -> {
|
||||
state.value = State.LOADING
|
||||
transactions.value = persistentListOf()
|
||||
}
|
||||
is TransactionHistorySyncState.Syncing -> {
|
||||
if (dataState.transactions.isEmpty()) {
|
||||
state.value = State.SYNCING_EMPTY
|
||||
} else {
|
||||
state.value = State.SYNCING
|
||||
transactions.value =
|
||||
dataState.transactions
|
||||
.map { data -> getOrUpdateTransactionItem(data) }
|
||||
.toPersistentList()
|
||||
}
|
||||
}
|
||||
is TransactionHistorySyncState.Done -> {
|
||||
if (dataState.transactions.isEmpty()) {
|
||||
state.value = State.DONE_EMPTY
|
||||
} else {
|
||||
state.value = State.DONE
|
||||
transactions.value =
|
||||
dataState.transactions
|
||||
.map { data -> getOrUpdateTransactionItem(data) }
|
||||
.toPersistentList()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTransaction(newTransaction: TransactionUi) {
|
||||
private fun getOrUpdateTransactionItem(data: TransactionOverviewExt): TransactionUi {
|
||||
val existingTransaction =
|
||||
transactions.value.find {
|
||||
data.overview.rawId == it.overview.rawId
|
||||
}
|
||||
return TransactionUi.new(
|
||||
data = data,
|
||||
expandableState = existingTransaction?.expandableState ?: TrxItemState.COLLAPSED,
|
||||
messages = existingTransaction?.messages,
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateTransactionInList(newTransaction: TransactionUi) {
|
||||
transactions.value =
|
||||
transactions.value.map { item ->
|
||||
if (item.overview.rawId == newTransaction.overview.rawId) {
|
||||
|
@ -87,7 +115,7 @@ class TransactionHistoryViewModel(application: Application) : AndroidViewModel(a
|
|||
val messages = loadMessageForTransaction(synchronizer, updated.overview)
|
||||
updatedWithMessages = updated.copy(messages = messages)
|
||||
}
|
||||
updateTransaction(updatedWithMessages)
|
||||
updateTransactionInList(updatedWithMessages)
|
||||
} else {
|
||||
Twig.warn { "Transaction not found" }
|
||||
}
|
||||
|
@ -101,3 +129,11 @@ class TransactionHistoryViewModel(application: Application) : AndroidViewModel(a
|
|||
Twig.info { "Transaction messages count: ${it.size}" }
|
||||
}
|
||||
}
|
||||
|
||||
private enum class State {
|
||||
LOADING,
|
||||
SYNCING,
|
||||
SYNCING_EMPTY,
|
||||
DONE,
|
||||
DONE_EMPTY,
|
||||
}
|
||||
|
|
|
@ -3,31 +3,41 @@
|
|||
package co.electriccoin.zcash.ui.screen.advancedsettings
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import co.electriccoin.zcash.ui.MainActivity
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.screen.advancedsettings.view.AdvancedSettings
|
||||
|
||||
@Composable
|
||||
internal fun WrapAdvancedSettings(
|
||||
internal fun MainActivity.WrapAdvancedSettings(
|
||||
goBack: () -> Unit,
|
||||
goExportPrivateData: () -> Unit,
|
||||
goSeedRecovery: () -> Unit,
|
||||
goChooseServer: () -> Unit,
|
||||
) {
|
||||
WrapSettings(
|
||||
val walletViewModel by viewModels<WalletViewModel>()
|
||||
|
||||
val walletRestoringState = walletViewModel.walletRestoringState.collectAsStateWithLifecycle().value
|
||||
|
||||
WrapAdvancedSettings(
|
||||
goBack = goBack,
|
||||
goExportPrivateData = goExportPrivateData,
|
||||
goChooseServer = goChooseServer,
|
||||
goSeedRecovery = goSeedRecovery,
|
||||
walletRestoringState = walletRestoringState
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
private fun WrapSettings(
|
||||
private fun WrapAdvancedSettings(
|
||||
goBack: () -> Unit,
|
||||
goExportPrivateData: () -> Unit,
|
||||
goChooseServer: () -> Unit,
|
||||
goSeedRecovery: () -> Unit,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
BackHandler {
|
||||
goBack()
|
||||
|
@ -37,6 +47,7 @@ private fun WrapSettings(
|
|||
onBack = goBack,
|
||||
onSeedRecovery = goSeedRecovery,
|
||||
onExportPrivateData = goExportPrivateData,
|
||||
onChooseServer = goChooseServer
|
||||
onChooseServer = goChooseServer,
|
||||
walletRestoringState = walletRestoringState,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import androidx.compose.ui.platform.testTag
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||
import co.electriccoin.zcash.ui.design.component.PrimaryButton
|
||||
import co.electriccoin.zcash.ui.design.component.SmallTopAppBar
|
||||
|
@ -34,8 +35,9 @@ private fun PreviewAdvancedSettings() {
|
|||
AdvancedSettings(
|
||||
onBack = {},
|
||||
onExportPrivateData = {},
|
||||
onSeedRecovery = {},
|
||||
onChooseServer = {},
|
||||
onSeedRecovery = {},
|
||||
walletRestoringState = WalletRestoringState.NONE,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -47,10 +49,12 @@ fun AdvancedSettings(
|
|||
onExportPrivateData: () -> Unit,
|
||||
onChooseServer: () -> Unit,
|
||||
onSeedRecovery: () -> Unit,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
Scaffold(topBar = {
|
||||
AdvancedSettingsTopAppBar(
|
||||
onBack = onBack,
|
||||
showRestoring = walletRestoringState == WalletRestoringState.RESTORING,
|
||||
)
|
||||
}) { paddingValues ->
|
||||
AdvancedSettingsMainContent(
|
||||
|
@ -73,13 +77,22 @@ fun AdvancedSettings(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun AdvancedSettingsTopAppBar(onBack: () -> Unit) {
|
||||
private fun AdvancedSettingsTopAppBar(
|
||||
onBack: () -> Unit,
|
||||
showRestoring: Boolean
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
restoringLabel =
|
||||
if (showRestoring) {
|
||||
stringResource(id = R.string.restoring_wallet_label)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
modifier = Modifier.testTag(AdvancedSettingsTag.ADVANCED_SETTINGS_TOP_APP_BAR),
|
||||
showTitleLogo = true,
|
||||
backText = stringResource(id = R.string.advanced_settings_back).uppercase(),
|
||||
backContentDescriptionText = stringResource(R.string.advanced_settings_back_content_description),
|
||||
onBack = onBack,
|
||||
showTitleLogo = true,
|
||||
modifier = Modifier.testTag(AdvancedSettingsTag.ADVANCED_SETTINGS_TOP_APP_BAR)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import cash.z.ecc.android.sdk.Synchronizer
|
|||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
import co.electriccoin.zcash.spackle.Twig
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.CheckUpdateViewModel
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||
|
@ -24,7 +25,6 @@ import co.electriccoin.zcash.ui.screen.balances.model.ShieldState
|
|||
import co.electriccoin.zcash.ui.screen.balances.view.Balances
|
||||
import co.electriccoin.zcash.ui.screen.sendconfirmation.model.SubmitResult
|
||||
import co.electriccoin.zcash.ui.screen.sendconfirmation.viewmodel.CreateTransactionsViewModel
|
||||
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
|
||||
import kotlinx.coroutines.delay
|
||||
|
@ -47,6 +47,8 @@ internal fun WrapBalances(
|
|||
|
||||
val spendingKey = walletViewModel.spendingKey.collectAsStateWithLifecycle().value
|
||||
|
||||
val walletRestoringState = walletViewModel.walletRestoringState.collectAsStateWithLifecycle().value
|
||||
|
||||
val checkUpdateViewModel by activity.viewModels<CheckUpdateViewModel> {
|
||||
CheckUpdateViewModel.CheckUpdateViewModelFactory(
|
||||
activity.application,
|
||||
|
@ -54,17 +56,15 @@ internal fun WrapBalances(
|
|||
)
|
||||
}
|
||||
|
||||
val settingsViewModel by activity.viewModels<SettingsViewModel>()
|
||||
|
||||
WrapBalances(
|
||||
checkUpdateViewModel = checkUpdateViewModel,
|
||||
createTransactionsViewModel = createTransactionsViewModel,
|
||||
goSettings = goSettings,
|
||||
goMultiTrxSubmissionFailure = goMultiTrxSubmissionFailure,
|
||||
spendingKey = spendingKey,
|
||||
settingsViewModel = settingsViewModel,
|
||||
synchronizer = synchronizer,
|
||||
walletSnapshot = walletSnapshot
|
||||
walletSnapshot = walletSnapshot,
|
||||
walletRestoringState = walletRestoringState,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -78,10 +78,10 @@ internal fun WrapBalances(
|
|||
createTransactionsViewModel: CreateTransactionsViewModel,
|
||||
goSettings: () -> Unit,
|
||||
goMultiTrxSubmissionFailure: () -> Unit,
|
||||
settingsViewModel: SettingsViewModel,
|
||||
spendingKey: UnifiedSpendingKey?,
|
||||
synchronizer: Synchronizer?,
|
||||
walletSnapshot: WalletSnapshot?,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
|
@ -91,8 +91,6 @@ internal fun WrapBalances(
|
|||
it?.appUpdateInfo != null && it.state == UpdateState.Prepared
|
||||
}
|
||||
|
||||
val isKeepScreenOnWhileSyncing = settingsViewModel.isKeepScreenOnWhileSyncing.collectAsStateWithLifecycle().value
|
||||
|
||||
val isFiatConversionEnabled = ConfigurationEntries.IS_FIAT_CONVERSION_ENABLED.getValue(RemoteConfig.current)
|
||||
|
||||
val (shieldState, setShieldState) =
|
||||
|
@ -128,7 +126,6 @@ internal fun WrapBalances(
|
|||
Balances(
|
||||
onSettings = goSettings,
|
||||
isFiatConversionEnabled = isFiatConversionEnabled,
|
||||
isKeepScreenOnWhileSyncing = isKeepScreenOnWhileSyncing,
|
||||
isUpdateAvailable = isUpdateAvailable,
|
||||
isShowingErrorDialog = isShowingErrorDialog,
|
||||
setShowErrorDialog = setShowErrorDialog,
|
||||
|
@ -187,6 +184,7 @@ internal fun WrapBalances(
|
|||
},
|
||||
shieldState = shieldState,
|
||||
walletSnapshot = walletSnapshot,
|
||||
walletRestoringState = walletRestoringState,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,14 +47,13 @@ import androidx.compose.ui.text.font.FontWeight
|
|||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
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.Zatoshi
|
||||
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.common.compose.BalanceWidget
|
||||
import co.electriccoin.zcash.ui.common.compose.DisableScreenTimeout
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||
import co.electriccoin.zcash.ui.common.model.changePendingBalance
|
||||
import co.electriccoin.zcash.ui.common.model.spendableBalance
|
||||
|
@ -86,13 +85,13 @@ private fun ComposableBalancesPreview() {
|
|||
Balances(
|
||||
onSettings = {},
|
||||
isFiatConversionEnabled = false,
|
||||
isKeepScreenOnWhileSyncing = false,
|
||||
isUpdateAvailable = false,
|
||||
isShowingErrorDialog = false,
|
||||
setShowErrorDialog = {},
|
||||
onShielding = {},
|
||||
shieldState = ShieldState.Available,
|
||||
walletSnapshot = WalletSnapshotFixture.new(),
|
||||
isShowingErrorDialog = false,
|
||||
setShowErrorDialog = {},
|
||||
walletRestoringState = WalletRestoringState.NONE,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -106,13 +105,13 @@ private fun ComposableBalancesShieldFailurePreview() {
|
|||
Balances(
|
||||
onSettings = {},
|
||||
isFiatConversionEnabled = false,
|
||||
isKeepScreenOnWhileSyncing = false,
|
||||
isUpdateAvailable = false,
|
||||
isShowingErrorDialog = true,
|
||||
setShowErrorDialog = {},
|
||||
onShielding = {},
|
||||
shieldState = ShieldState.Available,
|
||||
walletSnapshot = WalletSnapshotFixture.new(),
|
||||
isShowingErrorDialog = true,
|
||||
setShowErrorDialog = {},
|
||||
walletRestoringState = WalletRestoringState.NONE,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -123,23 +122,25 @@ private fun ComposableBalancesShieldFailurePreview() {
|
|||
fun Balances(
|
||||
onSettings: () -> Unit,
|
||||
isFiatConversionEnabled: Boolean,
|
||||
isKeepScreenOnWhileSyncing: Boolean?,
|
||||
isUpdateAvailable: Boolean,
|
||||
isShowingErrorDialog: Boolean,
|
||||
setShowErrorDialog: (Boolean) -> Unit,
|
||||
onShielding: () -> Unit,
|
||||
shieldState: ShieldState,
|
||||
walletSnapshot: WalletSnapshot?,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
Scaffold(topBar = {
|
||||
BalancesTopAppBar(onSettings = onSettings)
|
||||
BalancesTopAppBar(
|
||||
showRestoring = walletRestoringState == WalletRestoringState.RESTORING,
|
||||
onSettings = onSettings
|
||||
)
|
||||
}) { paddingValues ->
|
||||
if (null == walletSnapshot) {
|
||||
CircularScreenProgressIndicator()
|
||||
} else {
|
||||
BalancesMainContent(
|
||||
isFiatConversionEnabled = isFiatConversionEnabled,
|
||||
isKeepScreenOnWhileSyncing = isKeepScreenOnWhileSyncing,
|
||||
isUpdateAvailable = isUpdateAvailable,
|
||||
onShielding = onShielding,
|
||||
walletSnapshot = walletSnapshot,
|
||||
|
@ -197,10 +198,19 @@ fun ShieldingErrorDialog(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun BalancesTopAppBar(onSettings: () -> Unit) {
|
||||
private fun BalancesTopAppBar(
|
||||
onSettings: () -> Unit,
|
||||
showRestoring: Boolean
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
showTitleLogo = false,
|
||||
restoringLabel =
|
||||
if (showRestoring) {
|
||||
stringResource(id = R.string.restoring_wallet_label)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
titleText = stringResource(id = R.string.balances_title),
|
||||
showTitleLogo = false,
|
||||
hamburgerMenuActions = {
|
||||
IconButton(
|
||||
onClick = onSettings,
|
||||
|
@ -211,7 +221,7 @@ private fun BalancesTopAppBar(onSettings: () -> Unit) {
|
|||
contentDescription = stringResource(id = R.string.settings_menu_content_description)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -219,7 +229,6 @@ private fun BalancesTopAppBar(onSettings: () -> Unit) {
|
|||
@Composable
|
||||
private fun BalancesMainContent(
|
||||
isFiatConversionEnabled: Boolean,
|
||||
isKeepScreenOnWhileSyncing: Boolean?,
|
||||
isUpdateAvailable: Boolean,
|
||||
onShielding: () -> Unit,
|
||||
walletSnapshot: WalletSnapshot,
|
||||
|
@ -272,10 +281,6 @@ private fun BalancesMainContent(
|
|||
walletSnapshot = walletSnapshot,
|
||||
isUpdateAvailable = isUpdateAvailable,
|
||||
)
|
||||
|
||||
if (isKeepScreenOnWhileSyncing == true && walletSnapshot.status == Synchronizer.Status.SYNCING) {
|
||||
DisableScreenTimeout()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package co.electriccoin.zcash.ui.screen.chooseserver
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
@ -18,17 +19,23 @@ import cash.z.ecc.android.sdk.model.ZcashNetwork
|
|||
import cash.z.ecc.android.sdk.type.ServerValidation
|
||||
import cash.z.ecc.sdk.type.fromResources
|
||||
import co.electriccoin.zcash.ui.MainActivity
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.SecretState
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
|
||||
import co.electriccoin.zcash.ui.screen.chooseserver.view.ChooseServer
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
internal fun MainActivity.WrapChooseServer(goBack: () -> Unit) {
|
||||
val walletViewModel by viewModels<WalletViewModel>()
|
||||
|
||||
val secretState = walletViewModel.secretState.collectAsStateWithLifecycle().value
|
||||
|
||||
val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value
|
||||
|
||||
val walletRestoringState = walletViewModel.walletRestoringState.collectAsStateWithLifecycle().value
|
||||
|
||||
WrapChooseServer(
|
||||
activity = this,
|
||||
goBack = goBack,
|
||||
|
@ -39,7 +46,8 @@ internal fun MainActivity.WrapChooseServer(goBack: () -> Unit) {
|
|||
},
|
||||
onWalletPersist = {
|
||||
walletViewModel.persistExistingWallet(it)
|
||||
}
|
||||
},
|
||||
walletRestoringState = walletRestoringState
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -52,6 +60,7 @@ private fun WrapChooseServer(
|
|||
onWalletPersist: (PersistableWallet) -> Unit,
|
||||
secretState: SecretState,
|
||||
synchronizer: Synchronizer?,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
if (synchronizer == null || secretState !is SecretState.Ready) {
|
||||
// TODO [#1146]: Consider moving CircularScreenProgressIndicator from Android layer to View layer
|
||||
|
@ -118,7 +127,8 @@ private fun WrapChooseServer(
|
|||
isShowingErrorDialog = isShowingErrorDialog,
|
||||
setShowErrorDialog = setShowErrorDialog,
|
||||
isShowingSuccessDialog = isShowingSuccessDialog,
|
||||
setShowSuccessDialog = setShowSuccessDialog
|
||||
setShowSuccessDialog = setShowSuccessDialog,
|
||||
walletRestoringState = walletRestoringState
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import cash.z.ecc.sdk.extension.isValid
|
|||
import cash.z.ecc.sdk.fixture.PersistableWalletFixture
|
||||
import co.electriccoin.lightwallet.client.model.LightWalletEndpoint
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.design.component.AppAlertDialog
|
||||
import co.electriccoin.zcash.ui.design.component.FormTextField
|
||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||
|
@ -62,6 +63,7 @@ private fun PreviewChooseServer() {
|
|||
setShowErrorDialog = {},
|
||||
isShowingSuccessDialog = false,
|
||||
setShowSuccessDialog = {},
|
||||
walletRestoringState = WalletRestoringState.NONE,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -79,10 +81,14 @@ fun ChooseServer(
|
|||
setShowErrorDialog: (Boolean) -> Unit,
|
||||
isShowingSuccessDialog: Boolean,
|
||||
setShowSuccessDialog: (Boolean) -> Unit,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
ChooseServerTopAppBar(onBack = onBack)
|
||||
ChooseServerTopAppBar(
|
||||
onBack = onBack,
|
||||
showRestoring = walletRestoringState == WalletRestoringState.RESTORING,
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
ChooseServerMainContent(
|
||||
|
@ -120,13 +126,22 @@ fun ChooseServer(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun ChooseServerTopAppBar(onBack: () -> Unit) {
|
||||
private fun ChooseServerTopAppBar(
|
||||
onBack: () -> Unit,
|
||||
showRestoring: Boolean
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
restoringLabel =
|
||||
if (showRestoring) {
|
||||
stringResource(id = R.string.restoring_wallet_label)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
modifier = Modifier.testTag(ChooseServerTag.CHOOSE_SERVER_TOP_APP_BAR),
|
||||
showTitleLogo = true,
|
||||
backText = stringResource(id = R.string.choose_server_back).uppercase(),
|
||||
backContentDescriptionText = stringResource(R.string.choose_server_back_content_description),
|
||||
onBack = onBack,
|
||||
showTitleLogo = true,
|
||||
modifier = Modifier.testTag(ChooseServerTag.CHOOSE_SERVER_TOP_APP_BAR)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import cash.z.ecc.sdk.type.fromResources
|
|||
import co.electriccoin.zcash.ui.MainActivity
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
|
||||
import co.electriccoin.zcash.ui.screen.exportdata.view.ExportPrivateData
|
||||
|
@ -29,10 +30,18 @@ internal fun MainActivity.WrapExportPrivateData(
|
|||
goBack: () -> Unit,
|
||||
onConfirm: () -> Unit
|
||||
) {
|
||||
val walletViewModel by viewModels<WalletViewModel>()
|
||||
|
||||
val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value
|
||||
|
||||
val walletRestoringState = walletViewModel.walletRestoringState.collectAsStateWithLifecycle().value
|
||||
|
||||
WrapExportPrivateData(
|
||||
this,
|
||||
onBack = goBack,
|
||||
onShare = onConfirm
|
||||
onShare = onConfirm,
|
||||
synchronizer = synchronizer,
|
||||
walletRestoringState = walletRestoringState,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -40,11 +49,10 @@ internal fun MainActivity.WrapExportPrivateData(
|
|||
internal fun WrapExportPrivateData(
|
||||
activity: ComponentActivity,
|
||||
onBack: () -> Unit,
|
||||
onShare: () -> Unit
|
||||
onShare: () -> Unit,
|
||||
synchronizer: Synchronizer?,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
val walletViewModel by activity.viewModels<WalletViewModel>()
|
||||
val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value
|
||||
|
||||
if (synchronizer == null) {
|
||||
// TODO [#1146]: Consider moving CircularScreenProgressIndicator from Android layer to View layer
|
||||
// TODO [#1146]: Improve this by allowing screen composition and updating it after the data is available
|
||||
|
@ -72,7 +80,8 @@ internal fun WrapExportPrivateData(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
walletRestoringState = walletRestoringState
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.sp
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
|
||||
import co.electriccoin.zcash.ui.design.component.Body
|
||||
import co.electriccoin.zcash.ui.design.component.CheckBox
|
||||
|
@ -42,6 +43,7 @@ private fun ExportPrivateDataPreview() {
|
|||
onBack = {},
|
||||
onAgree = {},
|
||||
onConfirm = {},
|
||||
walletRestoringState = WalletRestoringState.NONE,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -56,9 +58,15 @@ fun ExportPrivateData(
|
|||
onBack: () -> Unit,
|
||||
onAgree: (Boolean) -> Unit,
|
||||
onConfirm: () -> Unit,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = { ExportPrivateDataTopAppBar(onBack = onBack) },
|
||||
topBar = {
|
||||
ExportPrivateDataTopAppBar(
|
||||
onBack = onBack,
|
||||
showRestoring = walletRestoringState == WalletRestoringState.RESTORING,
|
||||
)
|
||||
},
|
||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||
) { paddingValues ->
|
||||
ExportPrivateDataContent(
|
||||
|
@ -79,8 +87,17 @@ fun ExportPrivateData(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun ExportPrivateDataTopAppBar(onBack: () -> Unit) {
|
||||
private fun ExportPrivateDataTopAppBar(
|
||||
onBack: () -> Unit,
|
||||
showRestoring: Boolean
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
restoringLabel =
|
||||
if (showRestoring) {
|
||||
stringResource(id = R.string.restoring_wallet_label)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
backText = stringResource(R.string.export_data_back).uppercase(),
|
||||
backContentDescriptionText = stringResource(R.string.export_data_back_content_description),
|
||||
onBack = onBack,
|
||||
|
|
|
@ -8,10 +8,16 @@ import androidx.activity.viewModels
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import cash.z.ecc.android.sdk.model.ZecSend
|
||||
import co.electriccoin.zcash.ui.MainActivity
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.compose.RestoreScreenBrightness
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.HomeViewModel
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.isSynced
|
||||
import co.electriccoin.zcash.ui.screen.account.WrapAccount
|
||||
import co.electriccoin.zcash.ui.screen.balances.WrapBalances
|
||||
import co.electriccoin.zcash.ui.screen.home.model.TabItem
|
||||
|
@ -19,6 +25,7 @@ import co.electriccoin.zcash.ui.screen.home.view.Home
|
|||
import co.electriccoin.zcash.ui.screen.receive.WrapReceive
|
||||
import co.electriccoin.zcash.ui.screen.send.WrapSend
|
||||
import co.electriccoin.zcash.ui.screen.send.model.SendArguments
|
||||
import co.electriccoin.zcash.ui.screen.settings.viewmodel.SettingsViewModel
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
@ -26,7 +33,6 @@ import kotlinx.coroutines.flow.MutableSharedFlow
|
|||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
internal fun MainActivity.WrapHome(
|
||||
onPageChange: (HomeScreenIndex) -> Unit,
|
||||
goBack: () -> Unit,
|
||||
goSettings: () -> Unit,
|
||||
goMultiTrxSubmissionFailure: () -> Unit,
|
||||
|
@ -34,15 +40,39 @@ internal fun MainActivity.WrapHome(
|
|||
goSendConfirmation: (ZecSend) -> Unit,
|
||||
sendArguments: SendArguments
|
||||
) {
|
||||
val homeViewModel by viewModels<HomeViewModel>()
|
||||
|
||||
val walletViewModel by viewModels<WalletViewModel>()
|
||||
|
||||
val settingsViewModel by viewModels<SettingsViewModel>()
|
||||
|
||||
val homeScreenIndex = homeViewModel.screenIndex.collectAsStateWithLifecycle().value
|
||||
|
||||
val isKeepScreenOnWhileSyncing = settingsViewModel.isKeepScreenOnWhileSyncing.collectAsStateWithLifecycle().value
|
||||
|
||||
val walletSnapshot = walletViewModel.walletSnapshot.collectAsStateWithLifecycle().value
|
||||
|
||||
val walletRestoringState = walletViewModel.walletRestoringState.collectAsStateWithLifecycle().value
|
||||
|
||||
// Once the wallet is fully synced and still in restoring state, persist the new state
|
||||
if (walletSnapshot?.status?.isSynced() == true && walletRestoringState.isRunningRestoring()) {
|
||||
walletViewModel.persistWalletRestoringState(WalletRestoringState.SYNCING)
|
||||
}
|
||||
|
||||
WrapHome(
|
||||
this,
|
||||
onPageChange = onPageChange,
|
||||
goBack = goBack,
|
||||
goScan = goScan,
|
||||
goSendConfirmation = goSendConfirmation,
|
||||
goSettings = goSettings,
|
||||
goMultiTrxSubmissionFailure = goMultiTrxSubmissionFailure,
|
||||
sendArguments = sendArguments
|
||||
homeScreenIndex = homeScreenIndex,
|
||||
isKeepScreenOnWhileSyncing = isKeepScreenOnWhileSyncing,
|
||||
onPageChange = {
|
||||
homeViewModel.screenIndex.value = it
|
||||
},
|
||||
sendArguments = sendArguments,
|
||||
walletSnapshot = walletSnapshot
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -55,11 +85,12 @@ internal fun WrapHome(
|
|||
goMultiTrxSubmissionFailure: () -> Unit,
|
||||
goScan: () -> Unit,
|
||||
goSendConfirmation: (ZecSend) -> Unit,
|
||||
homeScreenIndex: HomeScreenIndex,
|
||||
isKeepScreenOnWhileSyncing: Boolean?,
|
||||
onPageChange: (HomeScreenIndex) -> Unit,
|
||||
sendArguments: SendArguments
|
||||
sendArguments: SendArguments,
|
||||
walletSnapshot: WalletSnapshot?,
|
||||
) {
|
||||
val homeViewModel by activity.viewModels<HomeViewModel>()
|
||||
|
||||
// Flow for propagating the new page index to the pager in the view layer
|
||||
val forceHomePageIndexFlow: MutableSharedFlow<ForcePage?> =
|
||||
MutableSharedFlow(
|
||||
|
@ -70,7 +101,7 @@ internal fun WrapHome(
|
|||
val forceIndex = forceHomePageIndexFlow.collectAsState(initial = null).value
|
||||
|
||||
val homeGoBack: () -> Unit = {
|
||||
when (homeViewModel.screenIndex.value) {
|
||||
when (homeScreenIndex) {
|
||||
HomeScreenIndex.ACCOUNT -> goBack()
|
||||
HomeScreenIndex.SEND,
|
||||
HomeScreenIndex.RECEIVE,
|
||||
|
@ -82,6 +113,11 @@ internal fun WrapHome(
|
|||
homeGoBack()
|
||||
}
|
||||
|
||||
// Reset the screen brightness for all pages except Receive which maintain the screen brightness by itself
|
||||
if (homeScreenIndex != HomeScreenIndex.RECEIVE) {
|
||||
RestoreScreenBrightness()
|
||||
}
|
||||
|
||||
val tabs =
|
||||
persistentListOf(
|
||||
TabItem(
|
||||
|
@ -92,7 +128,7 @@ internal fun WrapHome(
|
|||
WrapAccount(
|
||||
activity = activity,
|
||||
goBalances = { forceHomePageIndexFlow.tryEmit(ForcePage(HomeScreenIndex.BALANCES)) },
|
||||
goSettings = goSettings,
|
||||
goSettings = goSettings
|
||||
)
|
||||
}
|
||||
),
|
||||
|
@ -119,7 +155,7 @@ internal fun WrapHome(
|
|||
screenContent = {
|
||||
WrapReceive(
|
||||
activity = activity,
|
||||
onSettings = goSettings,
|
||||
onSettings = goSettings
|
||||
)
|
||||
}
|
||||
),
|
||||
|
@ -140,7 +176,9 @@ internal fun WrapHome(
|
|||
Home(
|
||||
subScreens = tabs,
|
||||
forcePage = forceIndex,
|
||||
onPageChange = onPageChange
|
||||
isKeepScreenOnWhileSyncing = isKeepScreenOnWhileSyncing,
|
||||
onPageChange = onPageChange,
|
||||
walletSnapshot = walletSnapshot
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -24,10 +24,14 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import androidx.constraintlayout.compose.Dimension
|
||||
import cash.z.ecc.android.sdk.Synchronizer
|
||||
import co.electriccoin.zcash.spackle.Twig
|
||||
import co.electriccoin.zcash.ui.common.compose.DisableScreenTimeout
|
||||
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||
import co.electriccoin.zcash.ui.design.component.NavigationTabText
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.fixture.WalletSnapshotFixture
|
||||
import co.electriccoin.zcash.ui.screen.home.ForcePage
|
||||
import co.electriccoin.zcash.ui.screen.home.HomeScreenIndex
|
||||
import co.electriccoin.zcash.ui.screen.home.model.TabItem
|
||||
|
@ -42,9 +46,11 @@ private fun ComposablePreview() {
|
|||
ZcashTheme(forceDarkMode = false) {
|
||||
GradientSurface {
|
||||
Home(
|
||||
subScreens = persistentListOf(),
|
||||
isKeepScreenOnWhileSyncing = false,
|
||||
forcePage = null,
|
||||
onPageChange = {}
|
||||
onPageChange = {},
|
||||
subScreens = persistentListOf(),
|
||||
walletSnapshot = WalletSnapshotFixture.new(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -54,9 +60,11 @@ private fun ComposablePreview() {
|
|||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
fun Home(
|
||||
subScreens: ImmutableList<TabItem>,
|
||||
isKeepScreenOnWhileSyncing: Boolean?,
|
||||
forcePage: ForcePage?,
|
||||
onPageChange: (HomeScreenIndex) -> Unit,
|
||||
subScreens: ImmutableList<TabItem>,
|
||||
walletSnapshot: WalletSnapshot?,
|
||||
) {
|
||||
val pagerState =
|
||||
rememberPagerState(
|
||||
|
@ -169,4 +177,10 @@ fun Home(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isKeepScreenOnWhileSyncing == true &&
|
||||
walletSnapshot?.status == Synchronizer.Status.SYNCING
|
||||
) {
|
||||
DisableScreenTimeout()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ private fun NewWalletRecoveryTopAppBar(
|
|||
if (versionInfo.isDebuggable && !versionInfo.isRunningUnderTestService) {
|
||||
DebugMenu(onCopyToClipboard = onSeedCopy)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import co.electriccoin.zcash.spackle.FirebaseTestLabUtil
|
|||
import co.electriccoin.zcash.ui.MainActivity
|
||||
import co.electriccoin.zcash.ui.common.model.OnboardingState
|
||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.screen.onboarding.view.ShortOnboarding
|
||||
import co.electriccoin.zcash.ui.screen.onboarding.viewmodel.OnboardingViewModel
|
||||
|
@ -117,4 +118,5 @@ internal fun persistExistingWalletWithSeedPhrase(
|
|||
walletInitMode = WalletInitMode.RestoreWallet
|
||||
)
|
||||
walletViewModel.persistExistingWallet(restoredWallet)
|
||||
walletViewModel.persistWalletRestoringState(WalletRestoringState.RESTORING)
|
||||
}
|
||||
|
|
|
@ -164,7 +164,7 @@ private fun OnboardingMainContent(
|
|||
if (isDebugMenuEnabled) {
|
||||
DebugMenu(onFixtureWallet)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
Column(
|
||||
modifier = modifier,
|
||||
|
|
|
@ -16,9 +16,11 @@ import co.electriccoin.zcash.spackle.ClipboardManagerUtil
|
|||
import co.electriccoin.zcash.spackle.Twig
|
||||
import co.electriccoin.zcash.spackle.getInternalCacheDirSuspend
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.compose.ScreenBrightnessState
|
||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.screen.receive.view.Receive
|
||||
import co.electriccoin.zcash.ui.screen.settings.viewmodel.ScreenBrightnessViewModel
|
||||
import co.electriccoin.zcash.ui.util.FileShareUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
|
@ -33,8 +35,15 @@ internal fun WrapReceive(
|
|||
activity: ComponentActivity,
|
||||
onSettings: () -> Unit,
|
||||
) {
|
||||
val viewModel by activity.viewModels<WalletViewModel>()
|
||||
val walletAddresses = viewModel.addresses.collectAsStateWithLifecycle().value
|
||||
val walletViewModel by activity.viewModels<WalletViewModel>()
|
||||
|
||||
val brightnessViewModel by activity.viewModels<ScreenBrightnessViewModel>()
|
||||
|
||||
val screenBrightnessState = brightnessViewModel.screenBrightnessState.collectAsStateWithLifecycle().value
|
||||
|
||||
val walletAddresses = walletViewModel.addresses.collectAsStateWithLifecycle().value
|
||||
|
||||
val walletRestoringState = walletViewModel.walletRestoringState.collectAsStateWithLifecycle().value
|
||||
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val scope = rememberCoroutineScope()
|
||||
|
@ -42,9 +51,13 @@ internal fun WrapReceive(
|
|||
val versionInfo = VersionInfo.new(activity.applicationContext)
|
||||
|
||||
Receive(
|
||||
walletAddress = walletAddresses,
|
||||
snackbarHostState = snackbarHostState,
|
||||
onAdjustBrightness = { /* Just for testing purposes */ },
|
||||
screenBrightnessState = screenBrightnessState,
|
||||
onAdjustBrightness = {
|
||||
when (it) {
|
||||
ScreenBrightnessState.NORMAL -> brightnessViewModel.restoreBrightness()
|
||||
ScreenBrightnessState.FULL -> brightnessViewModel.fullBrightness()
|
||||
}
|
||||
},
|
||||
onAddrCopyToClipboard = { address ->
|
||||
ClipboardManagerUtil.copyToClipboard(
|
||||
activity.applicationContext,
|
||||
|
@ -72,7 +85,10 @@ internal fun WrapReceive(
|
|||
}
|
||||
},
|
||||
onSettings = onSettings,
|
||||
versionInfo = versionInfo
|
||||
snackbarHostState = snackbarHostState,
|
||||
versionInfo = versionInfo,
|
||||
walletAddress = walletAddresses,
|
||||
walletRestoringState = walletRestoringState,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -13,9 +13,6 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.BrightnessHigh
|
||||
import androidx.compose.material.icons.filled.BrightnessLow
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
|
@ -23,9 +20,7 @@ import androidx.compose.material3.SnackbarHost
|
|||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
|
@ -44,7 +39,9 @@ import cash.z.ecc.android.sdk.model.WalletAddresses
|
|||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.compose.BrightenScreen
|
||||
import co.electriccoin.zcash.ui.common.compose.DisableScreenTimeout
|
||||
import co.electriccoin.zcash.ui.common.compose.ScreenBrightnessState
|
||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.test.CommonTag
|
||||
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
|
||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||
|
@ -64,13 +61,15 @@ private fun ComposablePreview() {
|
|||
ZcashTheme(forceDarkMode = false) {
|
||||
GradientSurface {
|
||||
Receive(
|
||||
screenBrightnessState = ScreenBrightnessState.NORMAL,
|
||||
walletAddress = runBlocking { WalletAddressesFixture.new() },
|
||||
snackbarHostState = SnackbarHostState(),
|
||||
onSettings = {},
|
||||
onAdjustBrightness = {},
|
||||
onAddrCopyToClipboard = {},
|
||||
onQrImageShare = {},
|
||||
versionInfo = VersionInfoFixture.new()
|
||||
versionInfo = VersionInfoFixture.new(),
|
||||
walletRestoringState = WalletRestoringState.NONE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -79,25 +78,24 @@ private fun ComposablePreview() {
|
|||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
fun Receive(
|
||||
screenBrightnessState: ScreenBrightnessState,
|
||||
walletAddress: WalletAddresses?,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
onSettings: () -> Unit,
|
||||
onAdjustBrightness: (Boolean) -> Unit,
|
||||
onAdjustBrightness: (ScreenBrightnessState) -> Unit,
|
||||
onAddrCopyToClipboard: (String) -> Unit,
|
||||
onQrImageShare: (ImageBitmap) -> Unit,
|
||||
versionInfo: VersionInfo,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
val (brightness, setBrightness) = rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
ReceiveTopAppBar(
|
||||
adjustBrightness = brightness,
|
||||
onSettings = onSettings,
|
||||
onBrightness = {
|
||||
onAdjustBrightness(!brightness)
|
||||
setBrightness(!brightness)
|
||||
onAdjustBrightness(screenBrightnessState.getChange())
|
||||
},
|
||||
showRestoring = walletRestoringState == WalletRestoringState.RESTORING,
|
||||
versionInfo = versionInfo,
|
||||
)
|
||||
},
|
||||
|
@ -110,7 +108,7 @@ fun Receive(
|
|||
walletAddress = walletAddress,
|
||||
onAddressCopyToClipboard = onAddrCopyToClipboard,
|
||||
onQrImageShare = onQrImageShare,
|
||||
adjustBrightness = brightness,
|
||||
screenBrightnessState = screenBrightnessState,
|
||||
versionInfo = versionInfo,
|
||||
modifier =
|
||||
Modifier.padding(
|
||||
|
@ -126,30 +124,19 @@ fun Receive(
|
|||
|
||||
@Composable
|
||||
private fun ReceiveTopAppBar(
|
||||
adjustBrightness: Boolean,
|
||||
onSettings: () -> Unit,
|
||||
onBrightness: () -> Unit,
|
||||
versionInfo: VersionInfo
|
||||
versionInfo: VersionInfo,
|
||||
showRestoring: Boolean
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
restoringLabel =
|
||||
if (showRestoring) {
|
||||
stringResource(id = R.string.restoring_wallet_label)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
titleText = stringResource(id = R.string.receive_title),
|
||||
regularActions = {
|
||||
if (versionInfo.isDebuggable) {
|
||||
IconButton(
|
||||
onClick = onBrightness
|
||||
) {
|
||||
Icon(
|
||||
imageVector =
|
||||
if (adjustBrightness) {
|
||||
Icons.Default.BrightnessLow
|
||||
} else {
|
||||
Icons.Default.BrightnessHigh
|
||||
},
|
||||
contentDescription = stringResource(R.string.receive_brightness_content_description)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
hamburgerMenuActions = {
|
||||
IconButton(
|
||||
onClick = onSettings,
|
||||
|
@ -160,7 +147,19 @@ private fun ReceiveTopAppBar(
|
|||
contentDescription = stringResource(id = R.string.settings_menu_content_description)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
regularActions = {
|
||||
if (versionInfo.isDebuggable) {
|
||||
IconButton(
|
||||
onClick = onBrightness
|
||||
) {
|
||||
Image(
|
||||
imageVector = ImageVector.vectorResource(id = R.drawable.ic_adjust_brightness),
|
||||
contentDescription = stringResource(R.string.receive_brightness_content_description)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -170,7 +169,7 @@ private fun ReceiveContents(
|
|||
walletAddress: WalletAddresses,
|
||||
onAddressCopyToClipboard: (String) -> Unit,
|
||||
onQrImageShare: (ImageBitmap) -> Unit,
|
||||
adjustBrightness: Boolean,
|
||||
screenBrightnessState: ScreenBrightnessState,
|
||||
versionInfo: VersionInfo,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
|
@ -182,7 +181,7 @@ private fun ReceiveContents(
|
|||
.then(modifier),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
if (adjustBrightness) {
|
||||
if (screenBrightnessState == ScreenBrightnessState.FULL) {
|
||||
BrightenScreen()
|
||||
DisableScreenTimeout()
|
||||
}
|
||||
|
|
|
@ -294,6 +294,7 @@ private fun RestoreSeedTopAppBar(
|
|||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
modifier = modifier,
|
||||
backText = stringResource(id = R.string.restore_back).uppercase(),
|
||||
backContentDescriptionText = stringResource(R.string.restore_back_content_description),
|
||||
onBack = onBack,
|
||||
|
@ -302,7 +303,6 @@ private fun RestoreSeedTopAppBar(
|
|||
onSeedClear = onClear
|
||||
)
|
||||
},
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -312,10 +312,10 @@ private fun RestoreSeedBirthdayTopAppBar(
|
|||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
modifier = modifier,
|
||||
backText = stringResource(id = R.string.restore_back).uppercase(),
|
||||
backContentDescriptionText = stringResource(R.string.restore_back_content_description),
|
||||
onBack = onBack,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -4,10 +4,12 @@ import androidx.activity.ComponentActivity
|
|||
import androidx.activity.viewModels
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import cash.z.ecc.android.sdk.Synchronizer
|
||||
import co.electriccoin.zcash.spackle.ClipboardManagerUtil
|
||||
import co.electriccoin.zcash.ui.MainActivity
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.SecretState
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
|
||||
|
@ -16,31 +18,44 @@ import co.electriccoin.zcash.ui.screen.seedrecovery.view.SeedRecovery
|
|||
@Composable
|
||||
internal fun MainActivity.WrapSeedRecovery(
|
||||
goBack: () -> Unit,
|
||||
onDone: () -> Unit
|
||||
onDone: () -> Unit,
|
||||
) {
|
||||
WrapSeedRecovery(this, goBack, onDone)
|
||||
val walletViewModel by viewModels<WalletViewModel>()
|
||||
|
||||
val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value
|
||||
|
||||
val secretState = walletViewModel.secretState.collectAsStateWithLifecycle().value
|
||||
|
||||
val walletRestoringState = walletViewModel.walletRestoringState.collectAsStateWithLifecycle().value
|
||||
|
||||
WrapSeedRecovery(
|
||||
activity = this,
|
||||
goBack = goBack,
|
||||
onDone = onDone,
|
||||
secretState = secretState,
|
||||
synchronizer = synchronizer,
|
||||
walletRestoringState = walletRestoringState
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
private fun WrapSeedRecovery(
|
||||
activity: ComponentActivity,
|
||||
goBack: () -> Unit,
|
||||
onDone: () -> Unit
|
||||
onDone: () -> Unit,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
synchronizer: Synchronizer?,
|
||||
secretState: SecretState,
|
||||
) {
|
||||
val versionInfo = VersionInfo.new(activity.applicationContext)
|
||||
|
||||
val walletViewModel by activity.viewModels<WalletViewModel>()
|
||||
|
||||
val persistableWallet =
|
||||
run {
|
||||
val secretState = walletViewModel.secretState.collectAsStateWithLifecycle().value
|
||||
if (secretState is SecretState.Ready) {
|
||||
secretState.persistableWallet
|
||||
} else {
|
||||
null
|
||||
}
|
||||
if (secretState is SecretState.Ready) {
|
||||
secretState.persistableWallet
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value
|
||||
|
||||
if (null == synchronizer || null == persistableWallet) {
|
||||
// TODO [#1146]: Consider moving CircularScreenProgressIndicator from Android layer to View layer
|
||||
|
@ -67,6 +82,7 @@ private fun WrapSeedRecovery(
|
|||
},
|
||||
onDone = onDone,
|
||||
versionInfo = versionInfo,
|
||||
walletRestoringState = walletRestoringState
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ import co.electriccoin.zcash.ui.R
|
|||
import co.electriccoin.zcash.ui.common.compose.SecureScreen
|
||||
import co.electriccoin.zcash.ui.common.compose.shouldSecureScreen
|
||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.test.CommonTag.WALLET_BIRTHDAY
|
||||
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
|
||||
import co.electriccoin.zcash.ui.design.component.BodySmall
|
||||
|
@ -66,6 +67,7 @@ private fun ComposablePreview() {
|
|||
onDone = {},
|
||||
onSeedCopy = {},
|
||||
versionInfo = VersionInfoFixture.new(),
|
||||
walletRestoringState = WalletRestoringState.NONE,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -86,6 +88,7 @@ fun SeedRecovery(
|
|||
onDone: () -> Unit,
|
||||
onSeedCopy: () -> Unit,
|
||||
versionInfo: VersionInfo,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
|
@ -93,6 +96,7 @@ fun SeedRecovery(
|
|||
onBack = onBack,
|
||||
onSeedCopy = onSeedCopy,
|
||||
versionInfo = versionInfo,
|
||||
showRestoring = walletRestoringState == WalletRestoringState.RESTORING,
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
|
@ -118,9 +122,16 @@ private fun SeedRecoveryTopAppBar(
|
|||
onBack: () -> Unit,
|
||||
onSeedCopy: () -> Unit,
|
||||
versionInfo: VersionInfo,
|
||||
showRestoring: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
restoringLabel =
|
||||
if (showRestoring) {
|
||||
stringResource(id = R.string.restoring_wallet_label)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
modifier = modifier,
|
||||
backText = stringResource(id = R.string.seed_recovery_back).uppercase(),
|
||||
backContentDescriptionText = stringResource(R.string.seed_recovery_back_content_description),
|
||||
|
@ -131,7 +142,7 @@ private fun SeedRecoveryTopAppBar(
|
|||
onCopyToClipboard = onSeedCopy
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import cash.z.ecc.android.sdk.model.ZecSend
|
|||
import cash.z.ecc.android.sdk.model.proposeSend
|
||||
import cash.z.ecc.android.sdk.model.toZecString
|
||||
import co.electriccoin.zcash.spackle.Twig
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.HomeViewModel
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||
|
@ -48,10 +49,10 @@ internal fun WrapSend(
|
|||
goSendConfirmation: (ZecSend) -> Unit,
|
||||
goSettings: () -> Unit,
|
||||
) {
|
||||
val hasCameraFeature = activity.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)
|
||||
|
||||
val walletViewModel by activity.viewModels<WalletViewModel>()
|
||||
|
||||
val hasCameraFeature = activity.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)
|
||||
|
||||
val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value
|
||||
|
||||
val walletSnapshot = walletViewModel.walletSnapshot.collectAsStateWithLifecycle().value
|
||||
|
@ -71,6 +72,8 @@ internal fun WrapSend(
|
|||
// TODO [#1171]: https://github.com/Electric-Coin-Company/zashi-android/issues/1171
|
||||
val monetarySeparators = MonetarySeparators.current(Locale.US)
|
||||
|
||||
val walletRestoringState = walletViewModel.walletRestoringState.collectAsStateWithLifecycle().value
|
||||
|
||||
WrapSend(
|
||||
sendArguments,
|
||||
synchronizer,
|
||||
|
@ -83,7 +86,8 @@ internal fun WrapSend(
|
|||
goSettings,
|
||||
goSendConfirmation,
|
||||
hasCameraFeature,
|
||||
monetarySeparators
|
||||
monetarySeparators,
|
||||
walletRestoringState
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -102,7 +106,8 @@ internal fun WrapSend(
|
|||
goSettings: () -> Unit,
|
||||
goSendConfirmation: (ZecSend) -> Unit,
|
||||
hasCameraFeature: Boolean,
|
||||
monetarySeparators: MonetarySeparators
|
||||
monetarySeparators: MonetarySeparators,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
|
@ -213,7 +218,8 @@ internal fun WrapSend(
|
|||
setAmountState = setAmountState,
|
||||
onQrScannerOpen = goToQrScanner,
|
||||
goBalances = goBalances,
|
||||
hasCameraFeature = hasCameraFeature
|
||||
hasCameraFeature = hasCameraFeature,
|
||||
walletRestoringState = walletRestoringState
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ import cash.z.ecc.sdk.type.ZcashCurrency
|
|||
import co.electriccoin.zcash.spackle.Twig
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.compose.BalanceWidget
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
|
||||
import co.electriccoin.zcash.ui.common.model.canSpend
|
||||
import co.electriccoin.zcash.ui.common.model.spendableBalance
|
||||
|
@ -94,7 +95,8 @@ private fun PreviewSendForm() {
|
|||
setAmountState = {},
|
||||
amountState = AmountState.Valid(ZatoshiFixture.ZATOSHI_LONG.toString(), ZatoshiFixture.new()),
|
||||
setMemoState = {},
|
||||
memoState = MemoState.new("Test message")
|
||||
memoState = MemoState.new("Test message"),
|
||||
walletRestoringState = WalletRestoringState.NONE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +108,6 @@ private fun PreviewSendForm() {
|
|||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
fun Send(
|
||||
walletSnapshot: WalletSnapshot,
|
||||
sendStage: SendStage,
|
||||
onCreateZecSend: (ZecSend) -> Unit,
|
||||
focusManager: FocusManager,
|
||||
|
@ -121,9 +122,14 @@ fun Send(
|
|||
amountState: AmountState,
|
||||
setMemoState: (MemoState) -> Unit,
|
||||
memoState: MemoState,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
walletSnapshot: WalletSnapshot,
|
||||
) {
|
||||
Scaffold(topBar = {
|
||||
SendTopAppBar(onSettings = onSettings)
|
||||
SendTopAppBar(
|
||||
showRestoring = walletRestoringState == WalletRestoringState.RESTORING,
|
||||
onSettings = onSettings
|
||||
)
|
||||
}) { paddingValues ->
|
||||
SendMainContent(
|
||||
walletSnapshot = walletSnapshot,
|
||||
|
@ -153,8 +159,17 @@ fun Send(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun SendTopAppBar(onSettings: () -> Unit) {
|
||||
private fun SendTopAppBar(
|
||||
onSettings: () -> Unit,
|
||||
showRestoring: Boolean
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
restoringLabel =
|
||||
if (showRestoring) {
|
||||
stringResource(id = R.string.restoring_wallet_label)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
titleText = stringResource(id = R.string.send_stage_send_title),
|
||||
hamburgerMenuActions = {
|
||||
IconButton(
|
||||
|
@ -166,7 +181,7 @@ private fun SendTopAppBar(onSettings: () -> Unit) {
|
|||
contentDescription = stringResource(id = R.string.settings_menu_content_description)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import cash.z.ecc.android.sdk.model.ZecSend
|
|||
import co.electriccoin.zcash.spackle.Twig
|
||||
import co.electriccoin.zcash.ui.MainActivity
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
|
||||
import co.electriccoin.zcash.ui.screen.send.ext.Saver
|
||||
|
@ -52,13 +53,15 @@ internal fun MainActivity.WrapSendConfirmation(
|
|||
|
||||
val createTransactionsViewModel by viewModels<CreateTransactionsViewModel>()
|
||||
|
||||
val viewModel by viewModels<SupportViewModel>()
|
||||
val supportViewModel by viewModels<SupportViewModel>()
|
||||
|
||||
val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value
|
||||
|
||||
val spendingKey = walletViewModel.spendingKey.collectAsStateWithLifecycle().value
|
||||
|
||||
val supportMessage = viewModel.supportInfo.collectAsStateWithLifecycle().value
|
||||
val supportMessage = supportViewModel.supportInfo.collectAsStateWithLifecycle().value
|
||||
|
||||
val walletRestoringState = walletViewModel.walletRestoringState.collectAsStateWithLifecycle().value
|
||||
|
||||
WrapSendConfirmation(
|
||||
activity = this,
|
||||
|
@ -69,6 +72,7 @@ internal fun MainActivity.WrapSendConfirmation(
|
|||
spendingKey = spendingKey,
|
||||
supportMessage = supportMessage,
|
||||
synchronizer = synchronizer,
|
||||
walletRestoringState = walletRestoringState,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -84,6 +88,7 @@ internal fun WrapSendConfirmation(
|
|||
spendingKey: UnifiedSpendingKey?,
|
||||
supportMessage: SupportInfo?,
|
||||
synchronizer: Synchronizer?,
|
||||
walletRestoringState: WalletRestoringState
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
|
@ -193,7 +198,8 @@ internal fun WrapSendConfirmation(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
walletRestoringState = walletRestoringState
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ import cash.z.ecc.sdk.fixture.MemoFixture
|
|||
import cash.z.ecc.sdk.fixture.ZatoshiFixture
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.compose.BalanceWidgetBigLineOnly
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
|
||||
import co.electriccoin.zcash.ui.design.component.AppAlertDialog
|
||||
import co.electriccoin.zcash.ui.design.component.Body
|
||||
|
@ -124,9 +125,16 @@ fun SendConfirmation(
|
|||
stage: SendConfirmationStage,
|
||||
submissionResults: ImmutableList<TransactionSubmitResult>,
|
||||
zecSend: ZecSend?,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = { SendConfirmationTopAppBar(onBack, stage) },
|
||||
topBar = {
|
||||
SendConfirmationTopAppBar(
|
||||
onBack = onBack,
|
||||
stage = stage,
|
||||
showRestoring = walletRestoringState == WalletRestoringState.RESTORING,
|
||||
)
|
||||
},
|
||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||
) { paddingValues ->
|
||||
SendConfirmationMainContent(
|
||||
|
@ -152,26 +160,49 @@ fun SendConfirmation(
|
|||
@Composable
|
||||
private fun SendConfirmationTopAppBar(
|
||||
onBack: () -> Unit,
|
||||
stage: SendConfirmationStage
|
||||
stage: SendConfirmationStage,
|
||||
showRestoring: Boolean
|
||||
) {
|
||||
when (stage) {
|
||||
SendConfirmationStage.Confirmation,
|
||||
SendConfirmationStage.Sending,
|
||||
is SendConfirmationStage.Failure -> {
|
||||
SmallTopAppBar(titleText = stringResource(id = R.string.send_stage_confirmation_title))
|
||||
SmallTopAppBar(
|
||||
restoringLabel =
|
||||
if (showRestoring) {
|
||||
stringResource(id = R.string.restoring_wallet_label)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
titleText = stringResource(id = R.string.send_stage_confirmation_title),
|
||||
)
|
||||
}
|
||||
SendConfirmationStage.MultipleTrxFailure -> {
|
||||
SmallTopAppBar(titleText = stringResource(id = R.string.send_confirmation_multiple_error_title))
|
||||
SmallTopAppBar(
|
||||
restoringLabel =
|
||||
if (showRestoring) {
|
||||
stringResource(id = R.string.restoring_wallet_label)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
titleText = stringResource(id = R.string.send_confirmation_multiple_error_title),
|
||||
)
|
||||
}
|
||||
SendConfirmationStage.MultipleTrxFailureReported -> {
|
||||
SmallTopAppBar(
|
||||
restoringLabel =
|
||||
if (showRestoring) {
|
||||
stringResource(id = R.string.restoring_wallet_label)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
titleText = stringResource(id = R.string.send_confirmation_multiple_error_title),
|
||||
backText = stringResource(id = R.string.send_confirmation_multiple_error_back),
|
||||
backContentDescriptionText =
|
||||
stringResource(
|
||||
id = R.string.send_confirmation_multiple_error_back_content_description
|
||||
),
|
||||
onBack = onBack
|
||||
onBack = onBack,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import co.electriccoin.zcash.ui.MainActivity
|
||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.configuration.ConfigurationEntries
|
||||
import co.electriccoin.zcash.ui.configuration.RemoteConfig
|
||||
|
@ -24,40 +25,47 @@ internal fun MainActivity.WrapSettings(
|
|||
goBack: () -> Unit,
|
||||
goFeedback: () -> Unit,
|
||||
) {
|
||||
val walletViewModel by viewModels<WalletViewModel>()
|
||||
|
||||
val settingsViewModel by viewModels<SettingsViewModel>()
|
||||
|
||||
val walletRestoringState = walletViewModel.walletRestoringState.collectAsStateWithLifecycle().value
|
||||
|
||||
WrapSettings(
|
||||
activity = this,
|
||||
goAbout = goAbout,
|
||||
goAdvancedSettings = goAdvancedSettings,
|
||||
goBack = goBack,
|
||||
goFeedback = goFeedback,
|
||||
settingsViewModel = settingsViewModel,
|
||||
walletViewModel = walletViewModel,
|
||||
walletRestoringState = walletRestoringState
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
private fun WrapSettings(
|
||||
activity: ComponentActivity,
|
||||
goAbout: () -> Unit,
|
||||
goAdvancedSettings: () -> Unit,
|
||||
goBack: () -> Unit,
|
||||
goFeedback: () -> Unit,
|
||||
settingsViewModel: SettingsViewModel,
|
||||
walletViewModel: WalletViewModel,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
val walletViewModel by activity.viewModels<WalletViewModel>()
|
||||
val settingsViewModel by activity.viewModels<SettingsViewModel>()
|
||||
|
||||
val versionInfo = VersionInfo.new(activity.applicationContext)
|
||||
|
||||
val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value
|
||||
val isBackgroundSyncEnabled = settingsViewModel.isBackgroundSync.collectAsStateWithLifecycle().value
|
||||
val isKeepScreenOnWhileSyncing = settingsViewModel.isKeepScreenOnWhileSyncing.collectAsStateWithLifecycle().value
|
||||
val isAnalyticsEnabled = settingsViewModel.isAnalyticsEnabled.collectAsStateWithLifecycle().value
|
||||
|
||||
val versionInfo = VersionInfo.new(activity.applicationContext)
|
||||
|
||||
BackHandler {
|
||||
goBack()
|
||||
}
|
||||
|
||||
@Suppress("ComplexCondition")
|
||||
if (null == synchronizer ||
|
||||
null == isAnalyticsEnabled ||
|
||||
if (null == isAnalyticsEnabled ||
|
||||
null == isBackgroundSyncEnabled ||
|
||||
null == isKeepScreenOnWhileSyncing
|
||||
) {
|
||||
|
@ -90,7 +98,8 @@ private fun WrapSettings(
|
|||
},
|
||||
onAnalyticsSettingsChanged = {
|
||||
settingsViewModel.setAnalyticsEnabled(it)
|
||||
}
|
||||
},
|
||||
walletRestoringState = walletRestoringState
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import androidx.compose.ui.platform.testTag
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
|
||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||
import co.electriccoin.zcash.ui.design.component.PrimaryButton
|
||||
|
@ -60,6 +61,7 @@ private fun PreviewSettings() {
|
|||
isAnalyticsEnabled = false,
|
||||
isRescanEnabled = false
|
||||
),
|
||||
walletRestoringState = WalletRestoringState.NONE,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -77,6 +79,7 @@ fun Settings(
|
|||
onKeepScreenOnDuringSyncSettingsChanged: (Boolean) -> Unit,
|
||||
onAnalyticsSettingsChanged: (Boolean) -> Unit,
|
||||
troubleshootingParameters: TroubleshootingParameters,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
Scaffold(topBar = {
|
||||
SettingsTopAppBar(
|
||||
|
@ -86,6 +89,7 @@ fun Settings(
|
|||
onAnalyticsSettingsChanged = onAnalyticsSettingsChanged,
|
||||
onRescanWallet = onRescanWallet,
|
||||
onBack = onBack,
|
||||
showRestoring = walletRestoringState == WalletRestoringState.RESTORING,
|
||||
)
|
||||
}) { paddingValues ->
|
||||
SettingsMainContent(
|
||||
|
@ -116,12 +120,20 @@ private fun SettingsTopAppBar(
|
|||
onAnalyticsSettingsChanged: (Boolean) -> Unit,
|
||||
onRescanWallet: () -> Unit,
|
||||
onBack: () -> Unit,
|
||||
showRestoring: Boolean
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
restoringLabel =
|
||||
if (showRestoring) {
|
||||
stringResource(id = R.string.restoring_wallet_label)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
modifier = Modifier.testTag(SettingsTag.SETTINGS_TOP_APP_BAR),
|
||||
showTitleLogo = true,
|
||||
backText = stringResource(id = R.string.settings_back).uppercase(),
|
||||
backContentDescriptionText = stringResource(R.string.settings_back_content_description),
|
||||
onBack = onBack,
|
||||
showTitleLogo = true,
|
||||
regularActions = {
|
||||
if (troubleshootingParameters.isEnabled) {
|
||||
TroubleshootingMenu(
|
||||
|
@ -133,7 +145,6 @@ private fun SettingsTopAppBar(
|
|||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.testTag(SettingsTag.SETTINGS_TOP_APP_BAR)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package co.electriccoin.zcash.ui.screen.settings.viewmodel
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import co.electriccoin.zcash.ui.common.compose.ScreenBrightness
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class ScreenBrightnessViewModel(application: Application) : AndroidViewModel(application) {
|
||||
private val screenBrightness: MutableStateFlow<ScreenBrightness> = MutableStateFlow(ScreenBrightness)
|
||||
|
||||
val screenBrightnessState = screenBrightness.value.referenceSwitch
|
||||
|
||||
fun fullBrightness() {
|
||||
screenBrightness.value.fullBrightness()
|
||||
}
|
||||
|
||||
fun restoreBrightness() {
|
||||
screenBrightness.value.restoreBrightness()
|
||||
}
|
||||
}
|
|
@ -14,6 +14,8 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
|||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import co.electriccoin.zcash.ui.MainActivity
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.screen.support.model.SupportInfo
|
||||
import co.electriccoin.zcash.ui.screen.support.model.SupportInfoType
|
||||
import co.electriccoin.zcash.ui.screen.support.view.Support
|
||||
|
@ -23,17 +25,31 @@ import kotlinx.coroutines.launch
|
|||
|
||||
@Composable
|
||||
internal fun MainActivity.WrapSupport(goBack: () -> Unit) {
|
||||
WrapSupport(this, goBack)
|
||||
val supportViewModel by viewModels<SupportViewModel>()
|
||||
|
||||
val walletViewModel by viewModels<WalletViewModel>()
|
||||
|
||||
val supportInfo = supportViewModel.supportInfo.collectAsStateWithLifecycle().value
|
||||
|
||||
val walletRestoringState = walletViewModel.walletRestoringState.collectAsStateWithLifecycle().value
|
||||
|
||||
WrapSupport(
|
||||
activity = this,
|
||||
goBack = goBack,
|
||||
supportInfo = supportInfo,
|
||||
walletRestoringState = walletRestoringState
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun WrapSupport(
|
||||
activity: ComponentActivity,
|
||||
goBack: () -> Unit
|
||||
goBack: () -> Unit,
|
||||
supportInfo: SupportInfo?,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
val viewModel by activity.viewModels<SupportViewModel>()
|
||||
val supportMessage = viewModel.supportInfo.collectAsStateWithLifecycle().value
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val (isShowingDialog, setShowDialog) = rememberSaveable { mutableStateOf(false) }
|
||||
|
@ -44,7 +60,7 @@ internal fun WrapSupport(
|
|||
setShowDialog = setShowDialog,
|
||||
onBack = goBack,
|
||||
onSend = { userMessage ->
|
||||
val fullMessage = formatMessage(userMessage, supportMessage)
|
||||
val fullMessage = formatMessage(userMessage, supportInfo)
|
||||
|
||||
val mailIntent =
|
||||
EmailUtil.newMailActivityIntent(
|
||||
|
@ -67,7 +83,8 @@ internal fun WrapSupport(
|
|||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
walletRestoringState = walletRestoringState
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package co.electriccoin.zcash.ui.screen.support.view
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
|
@ -9,30 +10,33 @@ import androidx.compose.foundation.layout.height
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
|
||||
import co.electriccoin.zcash.ui.design.component.AppAlertDialog
|
||||
import co.electriccoin.zcash.ui.design.component.Body
|
||||
import co.electriccoin.zcash.ui.design.component.FormTextField
|
||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||
import co.electriccoin.zcash.ui.design.component.PrimaryButton
|
||||
import co.electriccoin.zcash.ui.design.component.SmallTopAppBar
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
|
||||
@Preview("Support")
|
||||
|
@ -41,11 +45,12 @@ private fun PreviewSupport() {
|
|||
ZcashTheme(forceDarkMode = false) {
|
||||
GradientSurface {
|
||||
Support(
|
||||
snackbarHostState = SnackbarHostState(),
|
||||
isShowingDialog = false,
|
||||
setShowDialog = {},
|
||||
onBack = {},
|
||||
onSend = {},
|
||||
isShowingDialog = false,
|
||||
setShowDialog = {}
|
||||
snackbarHostState = SnackbarHostState(),
|
||||
walletRestoringState = WalletRestoringState.NONE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -65,18 +70,23 @@ private fun PreviewSupportPopup() {
|
|||
}
|
||||
|
||||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
fun Support(
|
||||
isShowingDialog: Boolean,
|
||||
setShowDialog: (Boolean) -> Unit,
|
||||
onBack: () -> Unit,
|
||||
onSend: (String) -> Unit,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
walletRestoringState: WalletRestoringState,
|
||||
) {
|
||||
val (message, setMessage) = rememberSaveable { mutableStateOf("") }
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
SupportTopAppBar(onBack = onBack)
|
||||
SupportTopAppBar(
|
||||
onBack = onBack,
|
||||
showRestoring = walletRestoringState == WalletRestoringState.RESTORING,
|
||||
)
|
||||
},
|
||||
snackbarHost = { SnackbarHost(snackbarHostState) }
|
||||
) { paddingValues ->
|
||||
|
@ -103,20 +113,21 @@ fun Support(
|
|||
}
|
||||
|
||||
@Composable
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
private fun SupportTopAppBar(onBack: () -> Unit) {
|
||||
TopAppBar(
|
||||
title = { Text(text = stringResource(id = R.string.support_header)) },
|
||||
navigationIcon = {
|
||||
IconButton(
|
||||
onClick = onBack
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.ArrowBack,
|
||||
contentDescription = stringResource(R.string.support_back_content_description)
|
||||
)
|
||||
}
|
||||
}
|
||||
private fun SupportTopAppBar(
|
||||
onBack: () -> Unit,
|
||||
showRestoring: Boolean
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
restoringLabel =
|
||||
if (showRestoring) {
|
||||
stringResource(id = R.string.restoring_wallet_label)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
titleText = stringResource(id = R.string.support_header),
|
||||
backText = stringResource(id = R.string.support_back).uppercase(),
|
||||
backContentDescriptionText = stringResource(R.string.support_back_content_description),
|
||||
onBack = onBack,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -128,6 +139,8 @@ private fun SupportMainContent(
|
|||
setShowDialog: (Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxHeight()
|
||||
|
@ -137,7 +150,19 @@ private fun SupportMainContent(
|
|||
.then(modifier),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Body(stringResource(id = R.string.support_information))
|
||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
|
||||
|
||||
Image(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.zashi_logo_sign),
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingBig))
|
||||
|
||||
Body(
|
||||
text = stringResource(id = R.string.support_information),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
|
||||
|
||||
|
@ -146,14 +171,13 @@ private fun SupportMainContent(
|
|||
onValueChange = setMessage,
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth(),
|
||||
.fillMaxWidth()
|
||||
.focusRequester(focusRequester),
|
||||
placeholder = { Text(text = stringResource(id = R.string.support_hint)) },
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
|
||||
|
||||
Body(stringResource(id = R.string.support_disclaimer))
|
||||
|
||||
Spacer(
|
||||
modifier =
|
||||
Modifier
|
||||
|
@ -166,11 +190,19 @@ private fun SupportMainContent(
|
|||
PrimaryButton(
|
||||
onClick = { setShowDialog(true) },
|
||||
text = stringResource(id = R.string.support_send),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = ZcashTheme.dimens.screenHorizontalSpacingRegular)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingHuge))
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
// Causes the TextFiled to focus on the first screen visit
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
@ -131,7 +131,7 @@ private fun UpdateTopAppBar(updateInfo: UpdateInfo) {
|
|||
R.string.update_header
|
||||
}
|
||||
}
|
||||
)
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -7,4 +7,5 @@
|
|||
<string name="balance_widget_available">Available Balance:</string>
|
||||
<!-- This is replaced by a resource overlay via app/build.gradle.kts -->
|
||||
<string name="support_email_address" />
|
||||
<string name="restoring_wallet_label">[Restoring Your Wallet…]</string>
|
||||
</resources>
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M0,0h20v20h-20z"/>
|
||||
<path
|
||||
android:pathData="M10,3.585C9.73,3.585 9.51,3.365 9.51,3.095V0.49C9.51,0.219 9.73,0 10,0C10.27,0 10.49,0.219 10.49,0.49V3.095C10.49,3.365 10.27,3.585 10,3.585Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M10,20C9.73,20 9.51,19.78 9.51,19.51V16.905C9.51,16.634 9.73,16.415 10,16.415C10.27,16.415 10.49,16.634 10.49,16.905V19.51C10.49,19.78 10.27,20 10,20Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M10,13.811C12.105,13.811 13.811,12.105 13.811,10C13.811,7.895 12.105,6.189 10,6.189C7.895,6.189 6.189,7.895 6.189,10C6.189,12.105 7.895,13.811 10,13.811Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M10,14.301C7.629,14.301 5.699,12.371 5.699,10C5.699,7.629 7.629,5.699 10,5.699C12.371,5.699 14.301,7.629 14.301,10C14.301,12.371 12.371,14.301 10,14.301ZM10,6.679C8.168,6.679 6.679,8.168 6.679,10C6.679,11.831 8.168,13.321 10,13.321C11.831,13.321 13.321,11.831 13.321,10C13.321,8.168 11.831,6.679 10,6.679Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M10,13.404C11.88,13.404 13.403,11.88 13.403,10C13.403,8.121 11.88,6.597 10,6.597V13.404Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M3.095,10.49H0.49C0.219,10.49 0,10.27 0,10C0,9.73 0.219,9.51 0.49,9.51H3.095C3.365,9.51 3.585,9.73 3.585,10C3.585,10.27 3.365,10.49 3.095,10.49Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M19.51,10.49H16.905C16.634,10.49 16.415,10.27 16.415,10C16.415,9.73 16.634,9.51 16.905,9.51H19.51C19.78,9.51 20,9.73 20,10C20,10.27 19.78,10.49 19.51,10.49Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M5.117,5.607C4.992,5.607 4.867,5.559 4.771,5.464L2.928,3.622C2.737,3.431 2.737,3.12 2.928,2.929C3.119,2.738 3.43,2.738 3.621,2.929L5.463,4.772C5.654,4.963 5.654,5.273 5.463,5.464C5.367,5.56 5.242,5.607 5.116,5.607H5.117Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M16.725,17.215C16.6,17.215 16.474,17.167 16.378,17.072L14.536,15.229C14.345,15.038 14.345,14.728 14.536,14.537C14.727,14.346 15.037,14.346 15.228,14.537L17.071,16.379C17.262,16.57 17.262,16.881 17.071,17.072C16.975,17.168 16.849,17.215 16.724,17.215H16.725Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M3.275,17.215C3.15,17.215 3.024,17.167 2.928,17.072C2.737,16.881 2.737,16.57 2.928,16.379L4.771,14.537C4.962,14.346 5.272,14.346 5.463,14.537C5.654,14.728 5.654,15.038 5.463,15.229L3.621,17.072C3.525,17.168 3.4,17.215 3.274,17.215H3.275Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M14.882,5.607C14.757,5.607 14.632,5.559 14.536,5.464C14.345,5.273 14.345,4.963 14.536,4.772L16.378,2.929C16.569,2.738 16.88,2.738 17.071,2.929C17.262,3.12 17.262,3.431 17.071,3.622L15.228,5.464C15.132,5.56 15.007,5.607 14.882,5.607H14.882Z"
|
||||
android:fillColor="#000000"/>
|
||||
</group>
|
||||
</vector>
|
|
@ -1,5 +1,6 @@
|
|||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="support_header">Contact support</string>
|
||||
<string name="support_header">Support</string>
|
||||
<string name="support_back">Back</string>
|
||||
<string name="support_back_content_description">Back</string>
|
||||
|
||||
<string name="support_hint">How can we help?</string>
|
||||
|
@ -10,6 +11,5 @@
|
|||
<string name="support_confirmation_explanation"><xliff:g id="app_name" example="Zcash">%1$s</xliff:g> is about to
|
||||
open your e-mail app with a pre-filled message.\n\nBe sure to hit send within your e-mail app.</string>
|
||||
<string name="support_information">Please let us know about any problems you have had, or features you want to see in the future.</string>
|
||||
<string name="support_disclaimer">Information provided is handled in accordance with our Privacy Policy.</string>
|
||||
<string name="support_unable_to_open_email">Unable to launch email app.</string>
|
||||
</resources>
|
||||
|
|
|
@ -507,7 +507,7 @@ private fun supportScreenshots(
|
|||
tag: String,
|
||||
composeTestRule: ComposeTestRule
|
||||
) {
|
||||
composeTestRule.onNode(hasText(resContext.getString(R.string.support_header))).also {
|
||||
composeTestRule.onNode(hasText(resContext.getString(R.string.support_header).uppercase())).also {
|
||||
it.assertExists()
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue