diff --git a/CHANGELOG.md b/CHANGELOG.md
index 680f7899..1b93b3da 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,8 @@ and this application adheres to [Semantic Versioning](https://semver.org/spec/v2
- The device authentication feature on the Zashi app launch has been added
- Zashi app now supports Spanish language
- The Flexa SDK has been adopted to enable payments using the embedded Flexa UI
+- New Sending, Success, Failure, and GrpcFailure subscreens of the Send Confirmation screen have been added
+- New Copy Transaction IDs feature has been added to the MultipleTransactionFailure screen
### Changelog
- Shielded transactions are properly indicated in transaction history
diff --git a/docs/whatsNew/WHATS_NEW_EN.md b/docs/whatsNew/WHATS_NEW_EN.md
index 45a86001..06627942 100644
--- a/docs/whatsNew/WHATS_NEW_EN.md
+++ b/docs/whatsNew/WHATS_NEW_EN.md
@@ -13,6 +13,8 @@ directly impact users rather than highlighting other key architectural updates.*
- The device authentication feature on the Zashi app launch has been added
- Zashi app now supports Spanish language
- The Flexa SDK has been adopted to enable payments using the embedded Flexa UI
+- New Sending, Success, Failure, and GrpcFailure subscreens of the Send Confirmation screen have been added
+- New Copy Transaction IDs feature has been added to the MultipleTransactionFailure screen
### Changelog
- Shielded transactions are properly indicated in transaction history
diff --git a/docs/whatsNew/WHATS_NEW_ES.md b/docs/whatsNew/WHATS_NEW_ES.md
index 26861f04..044370ae 100644
--- a/docs/whatsNew/WHATS_NEW_ES.md
+++ b/docs/whatsNew/WHATS_NEW_ES.md
@@ -13,6 +13,8 @@ directly impact users rather than highlighting other key architectural updates.*
- The device authentication feature on the Zashi app launch has been added
- Zashi app now supports Spanish language
- The Flexa SDK has been adopted to enable payments using the embedded Flexa UI
+- New Sending, Success, Failure, and GrpcFailure subscreens of the Send Confirmation screen have been added
+- New Copy Transaction IDs feature has been added to the MultipleTransactionFailure screen
### Changelog
- Shielded transactions are properly indicated in transaction history
diff --git a/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/Scaffold.kt b/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/Scaffold.kt
index 00da70f4..8525b858 100644
--- a/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/Scaffold.kt
+++ b/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/Scaffold.kt
@@ -1,10 +1,12 @@
package co.electriccoin.zcash.ui.design.component
+import androidx.compose.foundation.background
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
@@ -35,3 +37,25 @@ fun BlankBgScaffold(
modifier = modifier,
)
}
+
+@Composable
+fun GradientBgScaffold(
+ startColor: Color,
+ endColor: Color,
+ modifier: Modifier = Modifier,
+ topBar: @Composable () -> Unit = {},
+ bottomBar: @Composable () -> Unit = {},
+ snackbarHost: @Composable () -> Unit = {},
+ content: @Composable (PaddingValues) -> Unit
+) {
+ Scaffold(
+ containerColor = Color.Transparent,
+ topBar = topBar,
+ snackbarHost = snackbarHost,
+ bottomBar = bottomBar,
+ content = content,
+ modifier =
+ modifier
+ .background(zashiVerticalGradient(startColor, endColor)),
+ )
+}
diff --git a/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/ZashiBottomBar.kt b/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/ZashiBottomBar.kt
index a2c3bfed..ce739718 100644
--- a/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/ZashiBottomBar.kt
+++ b/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/ZashiBottomBar.kt
@@ -24,10 +24,10 @@ fun ZashiBottomBar(
content: @Composable () -> Unit,
) {
Surface(
- modifier = modifier,
shape = RoundedCornerShape(topStart = 32.dp, topEnd = 32.dp),
shadowElevation = 4.dp,
- color = ZashiColors.Surfaces.bgPrimary
+ color = ZashiColors.Surfaces.bgPrimary,
+ modifier = modifier,
) {
Column {
Spacer(modifier = Modifier.height(16.dp))
diff --git a/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/ZashiButton.kt b/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/ZashiButton.kt
index 32b6d562..e50c8284 100644
--- a/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/ZashiButton.kt
+++ b/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/ZashiButton.kt
@@ -3,11 +3,13 @@ package co.electriccoin.zcash.ui.design.component
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
@@ -100,6 +102,7 @@ fun ZashiButton(
onClick = onClick,
modifier = modifier,
shape = RoundedCornerShape(12.dp),
+ contentPadding = PaddingValues(horizontal = 10.dp),
enabled = enabled,
colors = colors.toButtonColors(),
border = colors.borderColor.takeIf { it != Color.Unspecified }?.let { BorderStroke(1.dp, it) },
@@ -269,3 +272,17 @@ private fun DestroyPreview() =
)
}
}
+
+@PreviewScreens
+@Composable
+private fun SmallWidthPreview() =
+ ZcashTheme {
+ BlankSurface {
+ ZashiButton(
+ modifier = Modifier.wrapContentWidth(),
+ text = "Small Width Button",
+ colors = ZashiButtonDefaults.destructive1Colors(),
+ onClick = {},
+ )
+ }
+ }
diff --git a/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/ZashiTopAppBar.kt b/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/ZashiTopAppBar.kt
index ced27319..0ac2db50 100644
--- a/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/ZashiTopAppBar.kt
+++ b/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/ZashiTopAppBar.kt
@@ -12,9 +12,9 @@ import co.electriccoin.zcash.ui.design.theme.internal.TopAppBarColors
@Composable
@Suppress("LongParameterList")
fun ZashiSmallTopAppBar(
- title: String?,
- subtitle: String?,
modifier: Modifier = Modifier,
+ title: String? = null,
+ subtitle: String? = null,
showTitleLogo: Boolean = false,
colors: TopAppBarColors = ZcashTheme.colors.topAppBarColors,
navigationAction: @Composable () -> Unit = {},
diff --git a/ui-design-lib/src/main/res/ui/common/drawable-night/ic_close.xml b/ui-design-lib/src/main/res/ui/common/drawable-night/ic_close.xml
new file mode 100644
index 00000000..82c25397
--- /dev/null
+++ b/ui-design-lib/src/main/res/ui/common/drawable-night/ic_close.xml
@@ -0,0 +1,13 @@
+
+
+
diff --git a/ui-design-lib/src/main/res/ui/common/drawable/ic_close.xml b/ui-design-lib/src/main/res/ui/common/drawable/ic_close.xml
new file mode 100644
index 00000000..ff2c4aa4
--- /dev/null
+++ b/ui-design-lib/src/main/res/ui/common/drawable/ic_close.xml
@@ -0,0 +1,13 @@
+
+
+
diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/Navigation.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/Navigation.kt
index 8ea79ef0..4a759821 100644
--- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/Navigation.kt
+++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/Navigation.kt
@@ -371,7 +371,7 @@ private fun MainActivity.NavigationHome(
goScan = { navController.navigateJustOnce(ScanNavigationArgs(ScanNavigationArgs.DEFAULT)) },
goSendConfirmation = { zecSend ->
navController.currentBackStackEntry?.savedStateHandle?.let { handle ->
- fillInHandleForConfirmation(handle, zecSend, SendConfirmationStage.Confirmation)
+ fillInHandleForConfirmation(handle, zecSend, SendConfirmationStage.Prepared)
}
navController.navigateJustOnce(SEND_CONFIRMATION)
},
diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/common/viewmodel/AuthenticationViewModel.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/common/viewmodel/AuthenticationViewModel.kt
index ebac6466..dd7e3cd6 100644
--- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/common/viewmodel/AuthenticationViewModel.kt
+++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/common/viewmodel/AuthenticationViewModel.kt
@@ -247,7 +247,7 @@ class AuthenticationViewModel(
// returning to biometric authentication, such as a button. The operation was canceled
// because [BiometricPrompt.ERROR_LOCKOUT] occurred too many times.
BiometricPrompt.ERROR_USER_CANCELED -> {
- authenticationResult.value = AuthenticationResult.Failed
+ authenticationResult.value = AuthenticationResult.Canceled
// The following values are just for testing purposes, so we can easier reproduce other
// non-success results obtained from [BiometricPrompt]
// = AuthenticationResult.Failed
diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/view/HomeView.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/view/HomeView.kt
index 6b4fc9f7..3a6dad0a 100644
--- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/view/HomeView.kt
+++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/home/view/HomeView.kt
@@ -87,7 +87,6 @@ fun Home(
@Composable
@Suppress("LongMethod")
-@OptIn(ExperimentalFoundationApi::class)
private fun HomeContent(
pagerState: PagerState,
subScreens: ImmutableList
diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/sendconfirmation/AndroidSendConfirmation.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/sendconfirmation/AndroidSendConfirmation.kt
index b884d3a2..e79f72db 100644
--- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/sendconfirmation/AndroidSendConfirmation.kt
+++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/sendconfirmation/AndroidSendConfirmation.kt
@@ -22,6 +22,7 @@ import cash.z.ecc.android.sdk.model.Proposal
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
import cash.z.ecc.android.sdk.model.ZecSend
import co.electriccoin.zcash.di.koinActivityViewModel
+import co.electriccoin.zcash.spackle.ClipboardManagerUtil
import co.electriccoin.zcash.spackle.Twig
import co.electriccoin.zcash.ui.MainActivity
import co.electriccoin.zcash.ui.R
@@ -124,25 +125,23 @@ internal fun WrapSendConfirmation(
val (stage, setStage) =
rememberSaveable(stateSaver = SendConfirmationStage.Saver) {
- mutableStateOf(arguments.initialStage ?: SendConfirmationStage.Confirmation)
+ mutableStateOf(arguments.initialStage ?: SendConfirmationStage.Prepared)
}
val submissionResults = createTransactionsViewModel.submissions.collectAsState().value.toImmutableList()
val onBackAction = {
when (stage) {
- SendConfirmationStage.Confirmation -> goBack(false)
- SendConfirmationStage.Sending -> { // no action - wait until the sending is done
- }
-
- is SendConfirmationStage.Failure -> setStage(SendConfirmationStage.Confirmation)
- is SendConfirmationStage.FailureGrpc -> {
- setStage(SendConfirmationStage.Confirmation)
+ SendConfirmationStage.Prepared -> goBack(false)
+ SendConfirmationStage.Sending -> { /* No action - wait until the sending is done */ }
+ SendConfirmationStage.Success -> {
goHome()
}
- is SendConfirmationStage.MultipleTrxFailure -> { // no action - wait until report the result
+ is SendConfirmationStage.Failure -> setStage(SendConfirmationStage.Prepared)
+ is SendConfirmationStage.FailureGrpc -> {
+ goHome()
}
-
+ is SendConfirmationStage.MultipleTrxFailure -> { /* No action - wait until the sending is done */ }
is SendConfirmationStage.MultipleTrxFailureReported -> goBack(true)
}
}
@@ -171,12 +170,12 @@ internal fun WrapSendConfirmation(
submissionResults = submissionResults,
snackbarHostState = snackbarHostState,
onBack = onBackAction,
- onContactSupport = { stageToGo, body ->
+ onContactSupport = { stageToGo ->
val fullMessage =
when (stageToGo) {
is SendConfirmationStage.Failure -> {
EmailUtil.formatMessage(
- body = body,
+ body = stageToGo.stackTrace,
supportInfo = supportMessage?.toSupportString(SupportInfoType.entries.toSet())
)
}
@@ -209,11 +208,22 @@ internal fun WrapSendConfirmation(
setStage(stageToGo)
scope.launch {
snackbarHostState.showSnackbar(
- message = activity.getString(R.string.send_confirmation_multiple_report_unable_open_email)
+ message =
+ activity.getString(
+ R.string.send_confirmation_multiple_trx_failure_report_unable_open_email
+ )
)
}
}
},
+ onMultipleTrxFailureIdsCopy = { idsString ->
+ Twig.info { "Multiple Trx IDs copied: $idsString" }
+ ClipboardManagerUtil.copyToClipboard(
+ activity.applicationContext,
+ activity.getString(R.string.send_confirmation_multiple_trx_failure_copy_tag),
+ idsString
+ )
+ },
onConfirmation = {
// Check and trigger authentication if required, or just submit transactions otherwise
lifecycleScope.launch {
@@ -225,7 +235,6 @@ internal fun WrapSendConfirmation(
} else {
runSendFundsAction(
createTransactionsViewModel = createTransactionsViewModel,
- goHome = goHome,
// The not-null assertion operator is necessary here even if we check its
// nullability before due to property is declared in different module. See more
// details on the Kotlin forum
@@ -238,6 +247,12 @@ internal fun WrapSendConfirmation(
}
}
},
+ onViewTransactions = {
+ val trxIds = submissionResults.map { it.txIdString() }
+ Twig.debug { "Transactions IDs passing to a new Transaction Details: $trxIds" }
+ // Once we implement transaction details screen we can start passing the trx ids to its destination
+ goHome()
+ },
topAppBarSubTitleState = topAppBarSubTitleState,
exchangeRate = exchangeRateState,
contactName = foundContact.value?.name
@@ -253,7 +268,6 @@ internal fun WrapSendConfirmation(
lifecycleScope.launch {
runSendFundsAction(
createTransactionsViewModel = createTransactionsViewModel,
- goHome = goHome,
// The not-null assertion operator is necessary here even if we check its
// nullability before due to property is declared in different module. See more
// details on the Kotlin forum
@@ -280,7 +294,6 @@ internal fun WrapSendConfirmation(
@Suppress("LongParameterList")
suspend fun runSendFundsAction(
createTransactionsViewModel: CreateTransactionsViewModel,
- goHome: () -> Unit,
proposal: Proposal,
setStage: (SendConfirmationStage) -> Unit,
spendingKey: UnifiedSpendingKey,
@@ -299,7 +312,6 @@ suspend fun runSendFundsAction(
Twig.debug { "Transactions submitted with result: $submitResult" }
processSubmissionResult(
- goHome = goHome,
setStage = setStage,
submitResult = submitResult
)
@@ -332,13 +344,11 @@ private suspend fun submitTransactions(
private fun processSubmissionResult(
submitResult: SubmitResult,
- setStage: (SendConfirmationStage) -> Unit,
- goHome: () -> Unit
+ setStage: (SendConfirmationStage) -> Unit
) {
when (submitResult) {
SubmitResult.Success -> {
- setStage(SendConfirmationStage.Confirmation)
- goHome()
+ setStage(SendConfirmationStage.Success)
}
is SubmitResult.SimpleTrxFailure.SimpleTrxFailureSubmit -> {
setStage(SendConfirmationStage.Failure(submitResult.toErrorMessage(), submitResult.toErrorStacktrace()))
diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/sendconfirmation/model/SendConfirmationStage.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/sendconfirmation/model/SendConfirmationStage.kt
index 89d15aa3..192d74c6 100644
--- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/sendconfirmation/model/SendConfirmationStage.kt
+++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/sendconfirmation/model/SendConfirmationStage.kt
@@ -3,10 +3,12 @@ package co.electriccoin.zcash.ui.screen.sendconfirmation.model
import androidx.compose.runtime.saveable.mapSaver
sealed class SendConfirmationStage {
- data object Confirmation : SendConfirmationStage()
+ data object Prepared : SendConfirmationStage()
data object Sending : SendConfirmationStage()
+ data object Success : SendConfirmationStage()
+
data class Failure(
val error: String,
val stackTrace: String,
@@ -20,18 +22,20 @@ sealed class SendConfirmationStage {
fun toStringName(): String {
return when (this) {
- Confirmation -> TYPE_CONFIRMATION
+ Prepared -> TYPE_PREPARED
is Failure -> TYPE_FAILURE
is FailureGrpc -> TYPE_FAILURE_GRPC
MultipleTrxFailure -> TYPE_MULTIPLE_TRX_FAILURE
MultipleTrxFailureReported -> TYPE_MULTIPLE_TRX_FAILURE_REPORTED
Sending -> TYPE_SENDING
+ Success -> TYPE_SUCCESS
}
}
companion object {
- private const val TYPE_CONFIRMATION = "confirmation" // $NON-NLS
+ private const val TYPE_PREPARED = "prepared" // $NON-NLS
private const val TYPE_SENDING = "sending" // $NON-NLS
+ private const val TYPE_SUCCESS = "success" // $NON-NLS
private const val TYPE_FAILURE = "failure" // $NON-NLS
private const val TYPE_FAILURE_GRPC = "type_failure_grpc" // $NON-NLS
private const val TYPE_MULTIPLE_TRX_FAILURE = "multiple_trx_failure" // $NON-NLS
@@ -52,8 +56,9 @@ sealed class SendConfirmationStage {
} else {
val sendStageString = (it[KEY_TYPE] as String)
when (sendStageString) {
- TYPE_CONFIRMATION -> Confirmation
+ TYPE_PREPARED -> Prepared
TYPE_SENDING -> Sending
+ TYPE_SUCCESS -> Success
TYPE_FAILURE ->
Failure(
error = (it[KEY_ERROR] as String),
@@ -72,8 +77,9 @@ sealed class SendConfirmationStage {
private fun SendConfirmationStage.toSaverMap(): HashMap {
val saverMap = HashMap()
when (this) {
- Confirmation -> saverMap[KEY_TYPE] = TYPE_CONFIRMATION
+ Prepared -> saverMap[KEY_TYPE] = TYPE_PREPARED
Sending -> saverMap[KEY_TYPE] = TYPE_SENDING
+ Success -> saverMap[KEY_TYPE] = TYPE_SUCCESS
is Failure -> {
saverMap[KEY_TYPE] = TYPE_FAILURE
saverMap[KEY_ERROR] = this.error
@@ -89,14 +95,15 @@ sealed class SendConfirmationStage {
fun fromStringName(stringName: String?): SendConfirmationStage {
return when (stringName) {
- TYPE_CONFIRMATION -> Confirmation
+ TYPE_PREPARED -> Prepared
TYPE_SENDING -> Sending
+ TYPE_SUCCESS -> Success
// Add the String error and stackTrace parameter storing and retrieving
TYPE_FAILURE -> Failure("", "")
TYPE_FAILURE_GRPC -> FailureGrpc
TYPE_MULTIPLE_TRX_FAILURE -> MultipleTrxFailure
TYPE_MULTIPLE_TRX_FAILURE_REPORTED -> MultipleTrxFailureReported
- else -> Confirmation
+ else -> Prepared
}
}
}
diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/sendconfirmation/view/SendConfirmationView.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/sendconfirmation/view/SendConfirmationView.kt
index 46e0d836..2244bef0 100644
--- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/sendconfirmation/view/SendConfirmationView.kt
+++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/sendconfirmation/view/SendConfirmationView.kt
@@ -3,22 +3,26 @@
package co.electriccoin.zcash.ui.screen.sendconfirmation.view
import androidx.compose.foundation.Image
-import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.background
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -28,11 +32,12 @@ import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
-import androidx.compose.ui.text.font.FontStyle
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.text.style.TextOverflow
import androidx.compose.ui.unit.dp
+import androidx.constraintlayout.compose.ConstraintLayout
+import androidx.constraintlayout.compose.Dimension
import cash.z.ecc.android.sdk.fixture.WalletAddressFixture
import cash.z.ecc.android.sdk.model.FirstClassByteArray
import cash.z.ecc.android.sdk.model.TransactionSubmitResult
@@ -47,213 +52,40 @@ import co.electriccoin.zcash.ui.common.extension.asZecAmountTriple
import co.electriccoin.zcash.ui.common.extension.totalAmount
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
import co.electriccoin.zcash.ui.common.wallet.ExchangeRateState
-import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
-import co.electriccoin.zcash.ui.design.component.AppAlertDialog
-import co.electriccoin.zcash.ui.design.component.BlankBgScaffold
-import co.electriccoin.zcash.ui.design.component.BlankSurface
-import co.electriccoin.zcash.ui.design.component.Body
import co.electriccoin.zcash.ui.design.component.ButtonState
-import co.electriccoin.zcash.ui.design.component.Small
-import co.electriccoin.zcash.ui.design.component.SmallTopAppBar
+import co.electriccoin.zcash.ui.design.component.GradientBgScaffold
import co.electriccoin.zcash.ui.design.component.StyledBalance
import co.electriccoin.zcash.ui.design.component.StyledBalanceDefaults
import co.electriccoin.zcash.ui.design.component.TextFieldState
import co.electriccoin.zcash.ui.design.component.TopAppBarBackNavigation
+import co.electriccoin.zcash.ui.design.component.ZashiBottomBar
import co.electriccoin.zcash.ui.design.component.ZashiButton
import co.electriccoin.zcash.ui.design.component.ZashiButtonDefaults
import co.electriccoin.zcash.ui.design.component.ZashiSmallTopAppBar
import co.electriccoin.zcash.ui.design.component.ZashiTextField
import co.electriccoin.zcash.ui.design.component.ZashiTextFieldDefaults
import co.electriccoin.zcash.ui.design.component.ZecAmountTriple
+import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.design.theme.colors.ZashiColors
+import co.electriccoin.zcash.ui.design.theme.dimensions.ZashiDimensions
import co.electriccoin.zcash.ui.design.theme.typography.ZashiTypography
import co.electriccoin.zcash.ui.design.util.scaffoldPadding
import co.electriccoin.zcash.ui.design.util.stringRes
import co.electriccoin.zcash.ui.fixture.ObserveFiatCurrencyResultFixture
import co.electriccoin.zcash.ui.screen.exchangerate.widget.StyledExchangeLabel
+import co.electriccoin.zcash.ui.screen.send.ext.abbreviated
import co.electriccoin.zcash.ui.screen.sendconfirmation.SendConfirmationTag
import co.electriccoin.zcash.ui.screen.sendconfirmation.model.SendConfirmationStage
+import com.airbnb.lottie.compose.LottieAnimation
+import com.airbnb.lottie.compose.LottieCompositionSpec
+import com.airbnb.lottie.compose.LottieConstants
+import com.airbnb.lottie.compose.animateLottieCompositionAsState
+import com.airbnb.lottie.compose.rememberLottieComposition
import kotlinx.collections.immutable.ImmutableList
-import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.runBlocking
-@Preview
-@Composable
-private fun SendConfirmationPreview() {
- ZcashTheme(forceDarkMode = false) {
- SendConfirmation(
- snackbarHostState = SnackbarHostState(),
- zecSend =
- ZecSend(
- destination = runBlocking { WalletAddressFixture.sapling() },
- amount = ZatoshiFixture.new(),
- memo = MemoFixture.new(),
- proposal = null,
- ),
- onConfirmation = {},
- onBack = {},
- stage = SendConfirmationStage.Confirmation,
- topAppBarSubTitleState = TopAppBarSubTitleState.None,
- onContactSupport = { _, _ -> },
- submissionResults = emptyList().toImmutableList(),
- exchangeRate = ObserveFiatCurrencyResultFixture.new(),
- contactName = "Romek"
- )
- }
-}
-
-@Preview
-@Composable
-private fun SendConfirmationDarkPreview() {
- ZcashTheme(forceDarkMode = true) {
- SendConfirmation(
- snackbarHostState = SnackbarHostState(),
- zecSend =
- ZecSend(
- destination = runBlocking { WalletAddressFixture.sapling() },
- amount = ZatoshiFixture.new(),
- memo = MemoFixture.new(),
- proposal = null,
- ),
- onConfirmation = {},
- onBack = {},
- stage = SendConfirmationStage.Confirmation,
- topAppBarSubTitleState = TopAppBarSubTitleState.None,
- onContactSupport = { _, _ -> },
- submissionResults = emptyList().toImmutableList(),
- exchangeRate = ObserveFiatCurrencyResultFixture.new(),
- contactName = "Romek"
- )
- }
-}
-
-@Preview
-@Composable
-private fun SendMultipleErrorPreview() {
- ZcashTheme(forceDarkMode = false) {
- SendConfirmation(
- snackbarHostState = SnackbarHostState(),
- zecSend =
- ZecSend(
- destination = runBlocking { WalletAddressFixture.sapling() },
- amount = ZatoshiFixture.new(),
- memo = MemoFixture.new(),
- proposal = null,
- ),
- onConfirmation = {},
- onBack = {},
- stage = SendConfirmationStage.MultipleTrxFailure,
- topAppBarSubTitleState = TopAppBarSubTitleState.None,
- onContactSupport = { _, _ -> },
- submissionResults = emptyList().toImmutableList(),
- exchangeRate = ObserveFiatCurrencyResultFixture.new(),
- contactName = "Romek"
- )
- }
-}
-
-@Preview
-@Composable
-private fun SendMultipleErrorDarkPreview() {
- ZcashTheme(forceDarkMode = true) {
- SendConfirmation(
- snackbarHostState = SnackbarHostState(),
- zecSend =
- ZecSend(
- destination = runBlocking { WalletAddressFixture.sapling() },
- amount = ZatoshiFixture.new(),
- memo = MemoFixture.new(),
- proposal = null,
- ),
- onConfirmation = {},
- onBack = {},
- stage = SendConfirmationStage.MultipleTrxFailure,
- topAppBarSubTitleState = TopAppBarSubTitleState.None,
- onContactSupport = { _, _ -> },
- submissionResults = emptyList().toImmutableList(),
- exchangeRate = ObserveFiatCurrencyResultFixture.new(),
- contactName = "Romek"
- )
- }
-}
-
-@Composable
-@Preview("SendConfirmation")
-private fun PreviewSendConfirmation() {
- ZcashTheme(forceDarkMode = false) {
- SendConfirmationContent(
- zecSend =
- ZecSend(
- destination = runBlocking { WalletAddressFixture.sapling() },
- amount = ZatoshiFixture.new(),
- memo = MemoFixture.new(),
- proposal = null,
- ),
- onConfirmation = {},
- onBack = {},
- isSending = false,
- exchangeRate = ObserveFiatCurrencyResultFixture.new(),
- contactName = "Romek"
- )
- }
-}
-
-@Preview
-@Composable
-private fun SendMultipleTransactionFailurePreview() {
- ZcashTheme(forceDarkMode = false) {
- @Suppress("MagicNumber")
- MultipleSubmissionFailure(
- onContactSupport = {},
- // Rework this into a test fixture
- submissionResults =
- persistentListOf(
- TransactionSubmitResult.Failure(
- FirstClassByteArray("test_transaction_id_1".toByteArray()),
- true,
- 123,
- "test transaction id failure"
- ),
- TransactionSubmitResult.NotAttempted(
- FirstClassByteArray("test_transaction_id_2".toByteArray())
- ),
- TransactionSubmitResult.NotAttempted(
- FirstClassByteArray("test_transaction_id_3".toByteArray())
- )
- )
- )
- }
-}
-
-@Preview
-@Composable
-private fun SendMultipleTransactionFailureDarkPreview() {
- ZcashTheme(forceDarkMode = true) {
- @Suppress("MagicNumber")
- MultipleSubmissionFailure(
- onContactSupport = {},
- // Rework this into a test fixture
- submissionResults =
- persistentListOf(
- TransactionSubmitResult.Failure(
- FirstClassByteArray("test_transaction_id_1".toByteArray()),
- true,
- 123,
- "test transaction id failure"
- ),
- TransactionSubmitResult.NotAttempted(
- FirstClassByteArray("test_transaction_id_2".toByteArray())
- ),
- TransactionSubmitResult.NotAttempted(
- FirstClassByteArray("test_transaction_id_3".toByteArray())
- )
- )
- )
- }
-}
-
// TODO [#1260]: Cover Send screens UI with tests
// TODO [#1260]: https://github.com/Electric-Coin-Company/zashi-android/issues/1260
@@ -262,16 +94,34 @@ private fun SendMultipleTransactionFailureDarkPreview() {
fun SendConfirmation(
onBack: () -> Unit,
onConfirmation: () -> Unit,
- onContactSupport: (SendConfirmationStage, String?) -> Unit,
+ onContactSupport: (SendConfirmationStage) -> Unit,
+ onMultipleTrxFailureIdsCopy: (String) -> Unit,
+ onViewTransactions: () -> Unit,
snackbarHostState: SnackbarHostState,
stage: SendConfirmationStage,
submissionResults: ImmutableList,
topAppBarSubTitleState: TopAppBarSubTitleState,
zecSend: ZecSend,
contactName: String?,
- exchangeRate: ExchangeRateState
+ exchangeRate: ExchangeRateState,
) {
- BlankBgScaffold(
+ val gradientColors =
+ Pair(
+ when (stage) {
+ SendConfirmationStage.Prepared,
+ SendConfirmationStage.Sending -> ZashiColors.Surfaces.bgPrimary
+ SendConfirmationStage.Success -> ZashiColors.Utility.SuccessGreen.utilitySuccess100
+ is SendConfirmationStage.Failure,
+ is SendConfirmationStage.FailureGrpc,
+ SendConfirmationStage.MultipleTrxFailure,
+ SendConfirmationStage.MultipleTrxFailureReported -> ZashiColors.Utility.ErrorRed.utilityError100
+ },
+ ZashiColors.Surfaces.bgPrimary
+ )
+
+ GradientBgScaffold(
+ startColor = gradientColors.first,
+ endColor = gradientColors.second,
topBar = {
SendConfirmationTopAppBar(
onBack = onBack,
@@ -280,19 +130,32 @@ fun SendConfirmation(
)
},
snackbarHost = { SnackbarHost(snackbarHostState) },
+ bottomBar = {
+ SendConfirmationBottomBarContent(
+ onClose = onBack,
+ onConfirmation = onConfirmation,
+ onReport = onContactSupport,
+ onCopyTrxIds = {
+ onMultipleTrxFailureIdsCopy(
+ submissionResults.joinToString(separator = ", ") { it.txIdString() }
+ )
+ },
+ stage = stage,
+ )
+ }
) { paddingValues ->
SendConfirmationMainContent(
- onBack = onBack,
- onContactSupport = onContactSupport,
- onConfirmation = onConfirmation,
+ contactName = contactName,
+ exchangeRate = exchangeRate,
+ onViewTransactions = onViewTransactions,
stage = stage,
submissionResults = submissionResults,
zecSend = zecSend,
modifier =
Modifier
+ .fillMaxSize()
+ .verticalScroll(rememberScrollState())
.scaffoldPadding(paddingValues),
- exchangeRate = exchangeRate,
- contactName = contactName
)
}
}
@@ -310,35 +173,49 @@ private fun SendConfirmationTopAppBar(
TopAppBarSubTitleState.None -> null
}
when (stage) {
- SendConfirmationStage.Confirmation,
- SendConfirmationStage.Sending,
- is SendConfirmationStage.Failure,
- is SendConfirmationStage.FailureGrpc,
- -> {
+ SendConfirmationStage.Prepared, -> {
ZashiSmallTopAppBar(
title = stringResource(id = R.string.send_stage_confirmation_title),
subtitle = subTitle,
)
}
-
- SendConfirmationStage.MultipleTrxFailure -> {
- SmallTopAppBar(
- subTitle = subTitle,
- titleText = stringResource(id = R.string.send_confirmation_multiple_error_title),
+ SendConfirmationStage.Sending -> {
+ ZashiSmallTopAppBar(subtitle = subTitle)
+ }
+ SendConfirmationStage.Success -> {
+ ZashiSmallTopAppBar(
+ subtitle = subTitle,
+ colors =
+ ZcashTheme.colors.topAppBarColors.copyColors(
+ containerColor = Color.Transparent
+ ),
)
}
-
SendConfirmationStage.MultipleTrxFailureReported -> {
- SmallTopAppBar(
- subTitle = subTitle,
- titleText = stringResource(id = R.string.send_confirmation_multiple_error_title),
+ ZashiSmallTopAppBar(
+ subtitle = subTitle,
navigationAction = {
TopAppBarBackNavigation(
- backText = stringResource(id = R.string.back_navigation).uppercase(),
- backContentDescriptionText = stringResource(R.string.back_navigation_content_description),
- onBack = onBack
+ backContentDescriptionText = stringResource(R.string.close_navigation_content_description),
+ onBack = onBack,
+ painter = painterResource(co.electriccoin.zcash.ui.design.R.drawable.ic_close)
)
},
+ colors =
+ ZcashTheme.colors.topAppBarColors.copyColors(
+ containerColor = Color.Transparent
+ ),
+ )
+ }
+ SendConfirmationStage.MultipleTrxFailure,
+ is SendConfirmationStage.Failure,
+ is SendConfirmationStage.FailureGrpc -> {
+ ZashiSmallTopAppBar(
+ subtitle = subTitle,
+ colors =
+ ZcashTheme.colors.topAppBarColors.copyColors(
+ containerColor = Color.Transparent
+ ),
)
}
}
@@ -348,72 +225,451 @@ private fun SendConfirmationTopAppBar(
@Suppress("LongParameterList")
private fun SendConfirmationMainContent(
contactName: String?,
+ exchangeRate: ExchangeRateState,
+ onViewTransactions: () -> Unit,
stage: SendConfirmationStage,
submissionResults: ImmutableList,
zecSend: ZecSend,
- onBack: () -> Unit,
- onContactSupport: (SendConfirmationStage, String?) -> Unit,
- onConfirmation: () -> Unit,
- exchangeRate: ExchangeRateState,
modifier: Modifier = Modifier,
) {
- when (stage) {
- SendConfirmationStage.Confirmation,
- SendConfirmationStage.Sending,
- is SendConfirmationStage.Failure,
- is SendConfirmationStage.FailureGrpc -> {
- SendConfirmationContent(
- contactName = contactName,
- zecSend = zecSend,
- onBack = onBack,
- onConfirmation = onConfirmation,
- isSending = stage == SendConfirmationStage.Sending,
- modifier = modifier,
- exchangeRate = exchangeRate
- )
- if (stage is SendConfirmationStage.FailureGrpc) {
- SendFailureGrpc(onDone = onBack)
- } else if (stage is SendConfirmationStage.Failure) {
- SendFailure(
- onDone = onBack,
- onReport = { status ->
- // Using [SendConfirmationStage.Confirmation] to dismiss the error dialog
- onContactSupport(SendConfirmationStage.Confirmation, status.stackTrace)
- },
- stage = stage,
+ Box(modifier = modifier) {
+ when (stage) {
+ SendConfirmationStage.Prepared -> {
+ SendConfirmationContent(
+ contactName = contactName,
+ zecSend = zecSend,
+ exchangeRate = exchangeRate
)
}
+ SendConfirmationStage.Sending -> {
+ SendingContent(destination = zecSend.destination)
+ }
+ SendConfirmationStage.Success -> {
+ SuccessContent(
+ destination = zecSend.destination,
+ onViewTransactions = onViewTransactions
+ )
+ }
+ is SendConfirmationStage.Failure -> {
+ SendFailure(onViewTransactions = onViewTransactions)
+ }
+ is SendConfirmationStage.FailureGrpc -> {
+ SendGrpcFailure()
+ }
+ is SendConfirmationStage.MultipleTrxFailure,
+ SendConfirmationStage.MultipleTrxFailureReported -> {
+ MultipleSubmissionFailure(submissionResults = submissionResults)
+ }
}
+ }
+}
- is SendConfirmationStage.MultipleTrxFailure, SendConfirmationStage.MultipleTrxFailureReported -> {
- MultipleSubmissionFailure(
- onContactSupport = {
- onContactSupport(SendConfirmationStage.MultipleTrxFailureReported, null)
- },
- submissionResults = submissionResults,
- modifier = modifier
+private const val TOP_BLANK_SPACE_RATIO = 0.2f
+
+@Composable
+private fun SendingContent(
+ destination: WalletAddress,
+ modifier: Modifier = Modifier
+) {
+ ConstraintLayout(modifier = modifier.fillMaxSize()) {
+ val (content, spaceTop) = createRefs()
+
+ Spacer(
+ modifier =
+ Modifier.constrainAs(spaceTop) {
+ height = Dimension.percent(TOP_BLANK_SPACE_RATIO)
+ width = Dimension.fillToConstraints
+ top.linkTo(parent.top)
+ bottom.linkTo(content.top)
+ start.linkTo(parent.start)
+ end.linkTo(parent.end)
+ }
+ )
+
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier =
+ Modifier
+ .constrainAs(content) {
+ top.linkTo(spaceTop.bottom)
+ start.linkTo(parent.start)
+ end.linkTo(parent.end)
+ width = Dimension.fillToConstraints
+ height = Dimension.wrapContent
+ }
+ ) {
+ // TODO [#1667]: Change lottie animation once we have it
+ // TODO [#1667]: https://github.com/Electric-Coin-Company/zashi-android/issues/1667
+ val lottieRes: Int =
+ if (isSystemInDarkTheme()) {
+ co.electriccoin.zcash.ui.design.R.raw.lottie_loading_white
+ } else {
+ co.electriccoin.zcash.ui.design.R.raw.lottie_loading
+ }
+
+ val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(lottieRes))
+ val progress by animateLottieCompositionAsState(
+ iterations = LottieConstants.IterateForever,
+ composition = composition
+ )
+
+ LottieAnimation(
+ modifier = Modifier.size(200.dp),
+ composition = composition,
+ progress = { progress },
+ maintainOriginalImageBounds = true
+ )
+
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacing2xl))
+
+ Text(
+ fontWeight = FontWeight.SemiBold,
+ style = ZashiTypography.header5,
+ text = stringResource(id = R.string.send_confirmation_sending_title),
+ )
+
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacingLg))
+
+ Text(
+ fontWeight = FontWeight.Normal,
+ style = ZashiTypography.textSm,
+ text = stringResource(id = R.string.send_confirmation_sending_subtitle, destination.abbreviated()),
+ modifier = Modifier.fillMaxWidth(),
+ textAlign = TextAlign.Center
+ )
+ }
+ }
+}
+
+private fun provideRandomResourceFrom(resources: List) = resources.random()
+
+@Composable
+private fun SuccessContent(
+ destination: WalletAddress,
+ onViewTransactions: () -> Unit,
+ modifier: Modifier = Modifier
+) {
+ ConstraintLayout(modifier = modifier.fillMaxSize()) {
+ val (content, spaceTop) = createRefs()
+
+ Spacer(
+ modifier =
+ Modifier.constrainAs(spaceTop) {
+ height = Dimension.percent(TOP_BLANK_SPACE_RATIO)
+ width = Dimension.fillToConstraints
+ top.linkTo(parent.top)
+ bottom.linkTo(content.top)
+ start.linkTo(parent.start)
+ end.linkTo(parent.end)
+ }
+ )
+
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier =
+ Modifier
+ .constrainAs(content) {
+ top.linkTo(spaceTop.bottom)
+ start.linkTo(parent.start)
+ end.linkTo(parent.end)
+ width = Dimension.fillToConstraints
+ height = Dimension.wrapContent
+ }
+ ) {
+ Image(
+ painter =
+ painterResource(
+ id =
+ provideRandomResourceFrom(
+ listOf(
+ R.drawable.ic_fist_punch,
+ R.drawable.ic_face_star
+ )
+ )
+ ),
+ contentDescription = null
+ )
+
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacing2xl))
+
+ Text(
+ fontWeight = FontWeight.SemiBold,
+ style = ZashiTypography.header5,
+ text = stringResource(id = R.string.send_confirmation_success_title),
+ )
+
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacingLg))
+
+ Text(
+ fontWeight = FontWeight.Normal,
+ style = ZashiTypography.textSm,
+ text = stringResource(id = R.string.send_confirmation_success_subtitle, destination.abbreviated()),
+ modifier = Modifier.fillMaxWidth(),
+ textAlign = TextAlign.Center
+ )
+
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacingXl))
+
+ ZashiButton(
+ state =
+ ButtonState(
+ text = stringRes(R.string.send_confirmation_success_view_trx),
+ onClick = onViewTransactions,
+ ),
+ modifier =
+ Modifier.wrapContentWidth(),
+ colors = ZashiButtonDefaults.tertiaryColors()
)
}
}
}
@Composable
-@Suppress("LongMethod", "LongParameterList")
+private fun SendFailure(
+ onViewTransactions: () -> Unit,
+ modifier: Modifier = Modifier
+) {
+ ConstraintLayout(modifier = modifier.fillMaxSize()) {
+ val (content, spaceTop) = createRefs()
+
+ Spacer(
+ modifier =
+ Modifier.constrainAs(spaceTop) {
+ height = Dimension.percent(TOP_BLANK_SPACE_RATIO)
+ width = Dimension.fillToConstraints
+ top.linkTo(parent.top)
+ bottom.linkTo(content.top)
+ start.linkTo(parent.start)
+ end.linkTo(parent.end)
+ }
+ )
+
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier =
+ Modifier
+ .constrainAs(content) {
+ top.linkTo(spaceTop.bottom)
+ start.linkTo(parent.start)
+ end.linkTo(parent.end)
+ width = Dimension.fillToConstraints
+ height = Dimension.wrapContent
+ }
+ ) {
+ Image(
+ painter =
+ painterResource(
+ id =
+ provideRandomResourceFrom(
+ listOf(
+ R.drawable.ic_skull,
+ R.drawable.ic_cloud_eyes,
+ R.drawable.ic_face_horns
+ )
+ )
+ ),
+ contentDescription = null
+ )
+
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacing2xl))
+
+ Text(
+ fontWeight = FontWeight.SemiBold,
+ style = ZashiTypography.header5,
+ text = stringResource(id = R.string.send_confirmation_failure_title),
+ )
+
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacingLg))
+
+ Text(
+ fontWeight = FontWeight.Normal,
+ style = ZashiTypography.textSm,
+ text = stringResource(id = R.string.send_confirmation_failure_subtitle),
+ modifier = Modifier.fillMaxWidth(),
+ textAlign = TextAlign.Center
+ )
+
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacingXl))
+
+ ZashiButton(
+ state =
+ ButtonState(
+ text = stringRes(R.string.send_confirmation_failure_view_trx),
+ onClick = onViewTransactions,
+ ),
+ modifier =
+ Modifier.wrapContentWidth(),
+ colors = ZashiButtonDefaults.tertiaryColors()
+ )
+ }
+ }
+}
+
+@Composable
+private fun SendGrpcFailure(modifier: Modifier = Modifier) {
+ ConstraintLayout(modifier = modifier.fillMaxSize()) {
+ val (content, spaceTop) = createRefs()
+
+ Spacer(
+ modifier =
+ Modifier.constrainAs(spaceTop) {
+ height = Dimension.percent(TOP_BLANK_SPACE_RATIO)
+ width = Dimension.fillToConstraints
+ top.linkTo(parent.top)
+ bottom.linkTo(content.top)
+ start.linkTo(parent.start)
+ end.linkTo(parent.end)
+ }
+ )
+
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier =
+ Modifier
+ .constrainAs(content) {
+ top.linkTo(spaceTop.bottom)
+ start.linkTo(parent.start)
+ end.linkTo(parent.end)
+ width = Dimension.fillToConstraints
+ height = Dimension.wrapContent
+ }
+ ) {
+ Image(
+ painter =
+ painterResource(
+ provideRandomResourceFrom(
+ listOf(
+ R.drawable.ic_frame,
+ R.drawable.ic_phone
+ )
+ )
+ ),
+ contentDescription = null
+ )
+
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacing2xl))
+
+ Text(
+ fontWeight = FontWeight.SemiBold,
+ style = ZashiTypography.header5,
+ text = stringResource(id = R.string.send_confirmation_failure_grpc_title),
+ )
+
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacingLg))
+
+ Text(
+ fontWeight = FontWeight.Normal,
+ style = ZashiTypography.textSm,
+ text = stringResource(id = R.string.send_confirmation_failure_grpc_subtitle),
+ modifier = Modifier.fillMaxWidth(),
+ textAlign = TextAlign.Center
+ )
+ }
+ }
+}
+
+@Composable
+fun MultipleSubmissionFailure(
+ submissionResults: ImmutableList,
+ modifier: Modifier = Modifier
+) {
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier = modifier,
+ ) {
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacingLg))
+
+ Image(
+ imageVector = ImageVector.vectorResource(R.drawable.ic_multi_trx_send_failed),
+ contentDescription = null,
+ )
+
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacingXl))
+
+ Text(
+ fontWeight = FontWeight.SemiBold,
+ style = ZashiTypography.header6,
+ text = stringResource(id = R.string.send_confirmation_multiple_trx_failure_title),
+ color = ZashiColors.Text.textPrimary
+ )
+
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacingLg))
+
+ Text(
+ style = ZashiTypography.textSm,
+ text = stringResource(id = R.string.send_confirmation_multiple_trx_failure_text_1),
+ modifier = Modifier.fillMaxWidth(),
+ textAlign = TextAlign.Center,
+ color = ZashiColors.Text.textPrimary
+ )
+
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacingLg))
+
+ Text(
+ style = ZashiTypography.textSm,
+ text = stringResource(id = R.string.send_confirmation_multiple_trx_failure_text_2),
+ modifier = Modifier.fillMaxWidth(),
+ textAlign = TextAlign.Center,
+ color = ZashiColors.Text.textPrimary
+ )
+
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacing4xl))
+
+ if (submissionResults.isNotEmpty()) {
+ TransactionSubmitResultWidget(submissionResults)
+ }
+ }
+}
+
+@Composable
+fun TransactionSubmitResultWidget(
+ submissionResults: ImmutableList,
+ modifier: Modifier = Modifier
+) {
+ Column(modifier = modifier) {
+ Text(
+ text = stringResource(id = R.string.send_confirmation_multiple_trx_failure_ids_title),
+ fontWeight = FontWeight.Medium,
+ style = ZashiTypography.textSm,
+ color = ZashiColors.Inputs.Default.label
+ )
+
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacingSm))
+
+ submissionResults.forEach { item ->
+ Text(
+ text = item.txIdString(),
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1,
+ style = ZashiTypography.textMd,
+ color = ZashiColors.Inputs.Default.text,
+ modifier =
+ Modifier
+ .background(
+ shape = RoundedCornerShape(ZashiDimensions.Radius.radiusIg),
+ color = ZashiColors.Inputs.Default.bg
+ )
+ .padding(
+ horizontal = ZashiDimensions.Spacing.spacingLg,
+ vertical = ZashiDimensions.Spacing.spacingMd
+ )
+ )
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacingMd))
+ }
+ }
+}
+
+@Composable
+@Suppress("LongMethod")
private fun SendConfirmationContent(
contactName: String?,
zecSend: ZecSend,
exchangeRate: ExchangeRateState,
- isSending: Boolean,
- onConfirmation: () -> Unit,
- onBack: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
horizontalAlignment = Alignment.Start,
- modifier =
- modifier
- .fillMaxSize()
- .verticalScroll(rememberScrollState()),
+ modifier = modifier.fillMaxSize(),
) {
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
@@ -571,27 +827,58 @@ private fun SendConfirmationContent(
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingUpLarge))
}
-
- Spacer(
- modifier =
- Modifier
- .fillMaxHeight()
- .weight(MINIMAL_WEIGHT)
- )
-
- SendConfirmationActionButtons(
- isSending = isSending,
- onBack = onBack,
- onConfirmation = onConfirmation
- )
}
}
@Composable
-fun SendConfirmationActionButtons(
+private fun SendConfirmationBottomBarContent(
+ onClose: () -> Unit,
+ onConfirmation: () -> Unit,
+ onReport: (SendConfirmationStage) -> Unit,
+ onCopyTrxIds: () -> Unit,
+ stage: SendConfirmationStage,
+ modifier: Modifier = Modifier,
+) {
+ ZashiBottomBar(modifier = modifier) {
+ when (stage) {
+ SendConfirmationStage.Prepared -> {
+ SendConfirmationBottomBar(
+ onConfirmation = onConfirmation,
+ onBack = onClose,
+ )
+ }
+ is SendConfirmationStage.Failure -> {
+ SendFailureBottomBar(
+ onClose = onClose,
+ onReport = { onReport(stage) },
+ )
+ }
+ SendConfirmationStage.FailureGrpc -> {
+ SendGrpcFailureBottomBar(
+ onClose = onClose,
+ )
+ }
+ SendConfirmationStage.MultipleTrxFailure,
+ SendConfirmationStage.MultipleTrxFailureReported -> {
+ SendMultipleTrxFailureBottomBar(
+ onCopyTrxIds = onCopyTrxIds,
+ onContactSupport = onReport,
+ )
+ }
+ SendConfirmationStage.Sending -> { /* No bottom bar in this stage */ }
+ SendConfirmationStage.Success -> {
+ SendSuccessBottomBar(
+ onClose = onClose,
+ )
+ }
+ }
+ }
+}
+
+@Composable
+fun SendConfirmationBottomBar(
onConfirmation: () -> Unit,
onBack: () -> Unit,
- isSending: Boolean,
modifier: Modifier = Modifier
) {
Column(
@@ -601,28 +888,27 @@ fun SendConfirmationActionButtons(
state =
ButtonState(
text = stringRes(R.string.send_confirmation_send_button),
- onClick = onConfirmation,
- isEnabled = !isSending,
- isLoading = isSending,
+ onClick = onConfirmation
),
modifier =
Modifier
.fillMaxWidth()
+ .padding(horizontal = ZashiDimensions.Spacing.spacing2xl)
.testTag(SendConfirmationTag.SEND_CONFIRMATION_SEND_BUTTON)
)
- Spacer(modifier = Modifier.height(12.dp))
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacingLg))
ZashiButton(
state =
ButtonState(
text = stringRes(R.string.send_confirmation_back_button),
onClick = onBack,
- isEnabled = !isSending,
),
modifier =
Modifier
.fillMaxWidth()
+ .padding(horizontal = ZashiDimensions.Spacing.spacing2xl)
.testTag(SendConfirmationTag.SEND_CONFIRMATION_BACK_BUTTON),
colors = ZashiButtonDefaults.tertiaryColors()
)
@@ -630,161 +916,302 @@ fun SendConfirmationActionButtons(
}
@Composable
-@Preview("SendConfirmationFailure")
-private fun PreviewSendConfirmationFailure() {
- ZcashTheme(forceDarkMode = false) {
- BlankSurface {
- SendFailure(
- onDone = {},
- onReport = {},
- stage = SendConfirmationStage.Failure("Failed - network error", "Failed stackTrace"),
- )
- }
- }
-}
-
-@Composable
-private fun SendFailure(
- onDone: () -> Unit,
- onReport: (SendConfirmationStage.Failure) -> Unit,
- stage: SendConfirmationStage.Failure,
-) {
- // TODO [#1276]: Once we ensure that the reason contains a localized message, we can leverage it for the UI prompt
- // TODO [#1276]: Consider adding support for a specific exception in AppAlertDialog
- // TODO [#1276]: https://github.com/Electric-Coin-Company/zashi-android/issues/1276
-
- AppAlertDialog(
- title = stringResource(id = R.string.send_confirmation_dialog_error_title),
- text = {
- Column(
- Modifier.verticalScroll(rememberScrollState())
- ) {
- Text(
- text = stringResource(id = R.string.send_confirmation_dialog_error_text),
- color = ZcashTheme.colors.textPrimary,
- )
-
- if (stage.error.isNotEmpty()) {
- Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
-
- Text(
- text = stage.error,
- fontStyle = FontStyle.Italic,
- color = ZcashTheme.colors.textPrimary,
- )
- }
- }
- },
- confirmButtonText = stringResource(id = R.string.send_confirmation_dialog_error_ok_btn),
- onConfirmButtonClick = onDone,
- dismissButtonText = stringResource(id = R.string.send_confirmation_dialog_error_report_btn),
- onDismissButtonClick = { onReport(stage) },
- )
-}
-
-@Composable
-private fun SendFailureGrpc(onDone: () -> Unit) {
- AppAlertDialog(
- title = stringResource(id = R.string.send_confirmation_dialog_error_grpc_title),
- text = {
- Column(
- Modifier.verticalScroll(rememberScrollState())
- ) {
- Text(
- text = stringResource(id = R.string.send_confirmation_dialog_error_grpc_text),
- color = ZcashTheme.colors.textPrimary,
- )
- }
- },
- confirmButtonText = stringResource(id = R.string.send_confirmation_dialog_error_grpc_btn),
- onConfirmButtonClick = onDone
- )
-}
-
-@Composable
-fun MultipleSubmissionFailure(
- onContactSupport: () -> Unit,
- submissionResults: ImmutableList,
+fun SendMultipleTrxFailureBottomBar(
+ onCopyTrxIds: () -> Unit,
+ onContactSupport: (SendConfirmationStage) -> Unit,
modifier: Modifier = Modifier
) {
Column(
- horizontalAlignment = Alignment.CenterHorizontally,
- modifier =
- modifier
- .fillMaxSize()
- .verticalScroll(rememberScrollState()),
- ) {
- Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
-
- Image(
- imageVector = ImageVector.vectorResource(R.drawable.ic_zashi_logo_sign_warn),
- colorFilter = ColorFilter.tint(color = ZcashTheme.colors.secondaryColor),
- contentDescription = null,
- )
-
- Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingBig))
-
- Body(
- text = stringResource(id = R.string.send_confirmation_multiple_error_text_1),
- textAlign = TextAlign.Center
- )
-
- Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
-
- Body(
- text = stringResource(id = R.string.send_confirmation_multiple_error_text_2),
- textAlign = TextAlign.Center
- )
-
- Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingBig))
-
- if (submissionResults.isNotEmpty()) {
- TransactionSubmitResultWidget(submissionResults)
- }
-
- Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
-
- Spacer(modifier = Modifier.weight(1f, true))
-
- ZashiButton(
- modifier = Modifier.fillMaxWidth(),
- onClick = onContactSupport,
- text = stringResource(id = R.string.send_confirmation_multiple_error_btn)
- )
-
- Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingHuge))
- }
-}
-
-@Composable
-fun TransactionSubmitResultWidget(
- submissionResults: ImmutableList,
- modifier: Modifier = Modifier
-) {
- Column(
- horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
) {
- Small(text = stringResource(id = R.string.send_confirmation_multiple_error_trx_title))
+ ZashiButton(
+ state =
+ ButtonState(
+ text = stringRes(R.string.send_confirmation_multiple_trx_failure_copy_button),
+ onClick = onCopyTrxIds
+ ),
+ modifier =
+ Modifier
+ .fillMaxWidth()
+ .padding(horizontal = ZashiDimensions.Spacing.spacing2xl),
+ colors = ZashiButtonDefaults.tertiaryColors()
+ )
- Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacingSm))
- submissionResults.forEachIndexed { index, item ->
- Row(
- modifier = Modifier.fillMaxWidth(),
- horizontalArrangement = Arrangement.Center
- ) {
- Small(
- text =
- stringResource(
- id = R.string.send_confirmation_multiple_error_trx_item,
- index + 1
- ),
- modifier = Modifier.wrapContentSize()
- )
- Spacer(modifier = Modifier.width(ZcashTheme.dimens.spacingTiny))
- Small(text = item.txIdString())
- }
- }
+ ZashiButton(
+ state =
+ ButtonState(
+ text = stringRes(R.string.send_confirmation_multiple_trx_failure_report_button),
+ onClick = { onContactSupport(SendConfirmationStage.MultipleTrxFailureReported) },
+ ),
+ modifier =
+ Modifier
+ .fillMaxWidth()
+ .padding(horizontal = ZashiDimensions.Spacing.spacing2xl),
+ )
+ }
+}
+
+@Composable
+fun SendSuccessBottomBar(
+ onClose: () -> Unit,
+ modifier: Modifier = Modifier
+) {
+ Column(
+ modifier = modifier
+ ) {
+ ZashiButton(
+ state =
+ ButtonState(
+ text = stringRes(R.string.send_confirmation_success_btn_close),
+ onClick = onClose
+ ),
+ modifier =
+ Modifier
+ .fillMaxWidth()
+ .padding(horizontal = ZashiDimensions.Spacing.spacing2xl)
+ )
+ }
+}
+
+@Composable
+fun SendFailureBottomBar(
+ onClose: () -> Unit,
+ onReport: () -> Unit,
+ modifier: Modifier = Modifier
+) {
+ Column(
+ modifier = modifier
+ ) {
+ ZashiButton(
+ state =
+ ButtonState(
+ text = stringRes(R.string.send_confirmation_failure_close_button),
+ onClick = onClose
+ ),
+ modifier =
+ Modifier
+ .fillMaxWidth()
+ .padding(horizontal = ZashiDimensions.Spacing.spacing2xl)
+ )
+
+ Spacer(modifier = Modifier.height(ZashiDimensions.Spacing.spacingLg))
+
+ ZashiButton(
+ state =
+ ButtonState(
+ text = stringRes(R.string.send_confirmation_failure_report_button),
+ onClick = onReport
+ ),
+ modifier =
+ Modifier
+ .fillMaxWidth()
+ .padding(horizontal = ZashiDimensions.Spacing.spacing2xl),
+ colors = ZashiButtonDefaults.tertiaryColors()
+ )
+ }
+}
+
+@Composable
+fun SendGrpcFailureBottomBar(
+ onClose: () -> Unit,
+ modifier: Modifier = Modifier
+) {
+ Column(
+ modifier = modifier
+ ) {
+ ZashiButton(
+ state =
+ ButtonState(
+ text = stringRes(R.string.send_confirmation_failure_grpc_close_button),
+ onClick = onClose
+ ),
+ modifier =
+ Modifier
+ .fillMaxWidth()
+ .padding(horizontal = ZashiDimensions.Spacing.spacing2xl)
+ )
+ }
+}
+
+@PreviewScreens
+@Composable
+private fun SendConfirmationPreview() {
+ ZcashTheme {
+ SendConfirmation(
+ snackbarHostState = SnackbarHostState(),
+ zecSend =
+ ZecSend(
+ destination = runBlocking { WalletAddressFixture.sapling() },
+ amount = ZatoshiFixture.new(),
+ memo = MemoFixture.new(),
+ proposal = null,
+ ),
+ onConfirmation = {},
+ onMultipleTrxFailureIdsCopy = {},
+ onViewTransactions = {},
+ onBack = {},
+ stage = SendConfirmationStage.Prepared,
+ topAppBarSubTitleState = TopAppBarSubTitleState.None,
+ onContactSupport = { _ -> },
+ submissionResults = emptyList().toImmutableList(),
+ exchangeRate = ObserveFiatCurrencyResultFixture.new(),
+ contactName = "Mom"
+ )
+ }
+}
+
+@PreviewScreens
+@Composable
+private fun SendingPreview() {
+ ZcashTheme {
+ SendConfirmation(
+ snackbarHostState = SnackbarHostState(),
+ zecSend =
+ ZecSend(
+ destination = runBlocking { WalletAddressFixture.sapling() },
+ amount = ZatoshiFixture.new(),
+ memo = MemoFixture.new(),
+ proposal = null,
+ ),
+ onBack = {},
+ onConfirmation = {},
+ onMultipleTrxFailureIdsCopy = {},
+ onViewTransactions = {},
+ stage = SendConfirmationStage.Sending,
+ topAppBarSubTitleState = TopAppBarSubTitleState.None,
+ onContactSupport = { _ -> },
+ submissionResults = emptyList().toImmutableList(),
+ exchangeRate = ObserveFiatCurrencyResultFixture.new(),
+ contactName = "Mom"
+ )
+ }
+}
+
+@PreviewScreens
+@Composable
+private fun SuccessPreview() {
+ ZcashTheme {
+ SendConfirmation(
+ snackbarHostState = SnackbarHostState(),
+ zecSend =
+ ZecSend(
+ destination = runBlocking { WalletAddressFixture.sapling() },
+ amount = ZatoshiFixture.new(),
+ memo = MemoFixture.new(),
+ proposal = null,
+ ),
+ onBack = {},
+ onConfirmation = {},
+ onMultipleTrxFailureIdsCopy = {},
+ onViewTransactions = {},
+ stage = SendConfirmationStage.Success,
+ topAppBarSubTitleState = TopAppBarSubTitleState.None,
+ onContactSupport = { _ -> },
+ submissionResults = emptyList().toImmutableList(),
+ exchangeRate = ObserveFiatCurrencyResultFixture.new(),
+ contactName = "Mom"
+ )
+ }
+}
+
+@PreviewScreens
+@Composable
+private fun PreviewSendConfirmationFailure() {
+ ZcashTheme {
+ SendConfirmation(
+ snackbarHostState = SnackbarHostState(),
+ zecSend =
+ ZecSend(
+ destination = runBlocking { WalletAddressFixture.sapling() },
+ amount = ZatoshiFixture.new(),
+ memo = MemoFixture.new(),
+ proposal = null,
+ ),
+ onBack = {},
+ onConfirmation = {},
+ onMultipleTrxFailureIdsCopy = {},
+ onViewTransactions = {},
+ stage =
+ SendConfirmationStage.Failure(
+ "The transaction has not been successfully created...",
+ "Failed stackTrace..."
+ ),
+ topAppBarSubTitleState = TopAppBarSubTitleState.None,
+ onContactSupport = { _ -> },
+ submissionResults = emptyList().toImmutableList(),
+ exchangeRate = ObserveFiatCurrencyResultFixture.new(),
+ contactName = "Mom"
+ )
+ }
+}
+
+@PreviewScreens
+@Composable
+private fun PreviewSendConfirmationGrpcFailure() {
+ ZcashTheme {
+ SendConfirmation(
+ snackbarHostState = SnackbarHostState(),
+ zecSend =
+ ZecSend(
+ destination = runBlocking { WalletAddressFixture.sapling() },
+ amount = ZatoshiFixture.new(),
+ memo = MemoFixture.new(),
+ proposal = null,
+ ),
+ onBack = {},
+ onConfirmation = {},
+ onMultipleTrxFailureIdsCopy = {},
+ onViewTransactions = {},
+ stage = SendConfirmationStage.FailureGrpc,
+ topAppBarSubTitleState = TopAppBarSubTitleState.None,
+ onContactSupport = { _ -> },
+ submissionResults = emptyList().toImmutableList(),
+ exchangeRate = ObserveFiatCurrencyResultFixture.new(),
+ contactName = "Mom"
+ )
+ }
+}
+
+@PreviewScreens
+@Composable
+private fun SendMultipleErrorPreview() {
+ ZcashTheme {
+ SendConfirmation(
+ snackbarHostState = SnackbarHostState(),
+ zecSend =
+ ZecSend(
+ destination = runBlocking { WalletAddressFixture.sapling() },
+ amount = ZatoshiFixture.new(),
+ memo = MemoFixture.new(),
+ proposal = null,
+ ),
+ onBack = {},
+ onConfirmation = {},
+ onMultipleTrxFailureIdsCopy = {},
+ onViewTransactions = {},
+ stage = SendConfirmationStage.MultipleTrxFailure,
+ topAppBarSubTitleState = TopAppBarSubTitleState.None,
+ onContactSupport = { _ -> },
+ submissionResults =
+ listOf(
+ TransactionSubmitResult.Success(FirstClassByteArray("test_transaction_id_1".toByteArray())),
+ TransactionSubmitResult.Failure(
+ FirstClassByteArray("test_transaction_id_2".toByteArray()),
+ true,
+ Int.MIN_VALUE,
+ "test transaction id failure"
+ ),
+ TransactionSubmitResult.NotAttempted(
+ FirstClassByteArray("test_transaction_id_3".toByteArray())
+ ),
+ TransactionSubmitResult.NotAttempted(
+ FirstClassByteArray("test_transaction_id_4".toByteArray())
+ )
+ ).toImmutableList(),
+ exchangeRate = ObserveFiatCurrencyResultFixture.new(),
+ contactName = "Romek"
+ )
}
}
diff --git a/ui-lib/src/main/res/ui/common/values-es/strings.xml b/ui-lib/src/main/res/ui/common/values-es/strings.xml
index 029dc521..0782bf1b 100644
--- a/ui-lib/src/main/res/ui/common/values-es/strings.xml
+++ b/ui-lib/src/main/res/ui/common/values-es/strings.xml
@@ -1,6 +1,7 @@
Atrás
Atrás
+ Close
No disponible
-
diff --git a/ui-lib/src/main/res/ui/common/values/strings.xml b/ui-lib/src/main/res/ui/common/values/strings.xml
index cea380ba..2d3b80e6 100644
--- a/ui-lib/src/main/res/ui/common/values/strings.xml
+++ b/ui-lib/src/main/res/ui/common/values/strings.xml
@@ -1,6 +1,7 @@
Back
Back
+ Close
Unavailable
-
diff --git a/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_cloud_eyes.xml b/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_cloud_eyes.xml
new file mode 100644
index 00000000..2b3fbf7c
--- /dev/null
+++ b/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_cloud_eyes.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_face_horns.xml b/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_face_horns.xml
new file mode 100644
index 00000000..33c84ce2
--- /dev/null
+++ b/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_face_horns.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_face_star.xml b/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_face_star.xml
new file mode 100644
index 00000000..5290f693
--- /dev/null
+++ b/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_face_star.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
diff --git a/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_fist_punch.xml b/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_fist_punch.xml
new file mode 100644
index 00000000..6ac8e55f
--- /dev/null
+++ b/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_fist_punch.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_frame.xml b/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_frame.xml
new file mode 100644
index 00000000..1ad79208
--- /dev/null
+++ b/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_frame.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_multi_trx_send_failed.xml b/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_multi_trx_send_failed.xml
new file mode 100644
index 00000000..39b620f6
--- /dev/null
+++ b/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_multi_trx_send_failed.xml
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_phone.xml b/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_phone.xml
new file mode 100644
index 00000000..6102899b
--- /dev/null
+++ b/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_phone.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_skull.xml b/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_skull.xml
new file mode 100644
index 00000000..f1cc3983
--- /dev/null
+++ b/ui-lib/src/main/res/ui/send_confirmation/drawable-night/ic_skull.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_cloud_eyes.xml b/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_cloud_eyes.xml
new file mode 100644
index 00000000..a75df317
--- /dev/null
+++ b/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_cloud_eyes.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_face_horns.xml b/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_face_horns.xml
new file mode 100644
index 00000000..40114529
--- /dev/null
+++ b/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_face_horns.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_face_star.xml b/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_face_star.xml
new file mode 100644
index 00000000..348e90f0
--- /dev/null
+++ b/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_face_star.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
diff --git a/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_fist_punch.xml b/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_fist_punch.xml
new file mode 100644
index 00000000..52474313
--- /dev/null
+++ b/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_fist_punch.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_frame.xml b/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_frame.xml
new file mode 100644
index 00000000..10403ac1
--- /dev/null
+++ b/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_frame.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_multi_trx_send_failed.xml b/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_multi_trx_send_failed.xml
new file mode 100644
index 00000000..e4a1c744
--- /dev/null
+++ b/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_multi_trx_send_failed.xml
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_phone.xml b/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_phone.xml
new file mode 100644
index 00000000..c0803add
--- /dev/null
+++ b/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_phone.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_skull.xml b/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_skull.xml
new file mode 100644
index 00000000..111575a3
--- /dev/null
+++ b/ui-lib/src/main/res/ui/send_confirmation/drawable/ic_skull.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-lib/src/main/res/ui/send_confirmation/values-es/strings.xml b/ui-lib/src/main/res/ui/send_confirmation/values-es/strings.xml
index efad2f3d..01436b2f 100644
--- a/ui-lib/src/main/res/ui/send_confirmation/values-es/strings.xml
+++ b/ui-lib/src/main/res/ui/send_confirmation/values-es/strings.xml
@@ -9,23 +9,39 @@
Enviar
Cancelar
- Transacción Fallida
- Ocurrió un error y el intento de enviar fondos falló. Inténtelo de nuevo, por favor.
- OK
- Reportar
-
- Error de Conexión
- Zashi encontró algunos problemas de conexión al enviar la transacción a la red. Volverá a intentarlo durante los próximos minutos.
- OK
-
- Error de Transacción
- Enviar a este destinatario requirió múltiples transacciones, pero solo algunas de ellas se completaron con éxito. Tus fondos están seguros, pero deben recuperarse con la ayuda del soporte del equipo de Zashi.
- Por favor, usa el botón de abajo para contactarnos y recuperar tus fondos. Tu mensaje para nosotros estará pre-rellenado con todos los datos necesarios para resolver este problema.
- IDs DE TRANSACCIÓN:
-
- %1$d. ID:
+ Sending…
+ Your tokens are being sent to\n
+ %1$s
- Contactar Soporte
+
+ Sent!
+ Your tokens were successfully sent to\n
+ %1$s
+
+ View Transaction
+ Close
+
+ Send Failed
+ There was an error attempting to send tokens.\n
+ Try it again, please.
+ View Transaction
+ Close
+ Report
+
+ Connection Error
+ Zashi encountered connection issues when submitting the
+ transaction. It will retry in the next few minutes.
+ Close
+
+ Send Failed
+ Send to this recipient required multiple
+ transactions but only some of them succeeded and the rest failed. Your funds are safe but need to be
+ recovered with assistance from our side.
+ Please use the button below to contact us. it
+ automatically prepares all the data we need in order to help you restore your funds.
+ Copy transaction IDs
+ Contact Support
+ Transaction IDs
Hola, equipo de Zashi.\n\nAl enviar una transacción a una dirección TEX, encontré un estado de error. Me pongo en contacto para recibir orientación sobre cómo recuperar mis fondos.\n\nGracias.
Estados de la transacción:
@@ -41,6 +57,7 @@
código: %3$d,
descripción: %4$s
- No se pudo iniciar la aplicación de correo.
+ Unable to launch email app.
+ Transaction IDs
diff --git a/ui-lib/src/main/res/ui/send_confirmation/values/strings.xml b/ui-lib/src/main/res/ui/send_confirmation/values/strings.xml
index ef716e45..94cbf1ec 100644
--- a/ui-lib/src/main/res/ui/send_confirmation/values/strings.xml
+++ b/ui-lib/src/main/res/ui/send_confirmation/values/strings.xml
@@ -9,28 +9,39 @@
Send
Cancel
- Transaction Failed
- An error occurred and the attempt to send funds failed. Try it again, please.
- OK
- Report
-
- Connection Error
- Zashi encountered some connection issues when submitting
- the transaction to the network. It will retry during the next few minutes.
- OK
-
- Transaction error
- Sending to this recipient required multiple transactions,
- but only some of them succeeded. Your funds are safe, but they need to be recovered with the help of Zashi
- team support.
- Please use the button below to contact us and recover your
- funds. Your message to us will be pre-populated with all the data we need to resolve this issue.
- TRANSACTION IDs:
-
- %1$d. ID:
+ Sending…
+ Your tokens are being sent to\n
+ %1$s
- Contact Support
+ Sent!
+ Your tokens were successfully sent to\n
+ %1$s
+
+ View Transaction
+ Close
+
+ Send Failed
+ There was an error attempting to send tokens.\n
+ Try it again, please.
+ View Transaction
+ Close
+ Report
+
+ Connection Error
+ Zashi encountered connection issues when submitting the
+ transaction. It will retry in the next few minutes.
+ Close
+
+ Send Failed
+ Send to this recipient required multiple
+ transactions but only some of them succeeded and the rest failed. Your funds are safe but need to be
+ recovered with assistance from our side.
+ Please use the button below to contact us. it
+ automatically prepares all the data we need in order to help you restore your funds.
+ Copy transaction IDs
+ Contact Support
+ Transaction IDs
Hi, Zashi Team.\n\nWhile sending a transaction to a TEX
address, I encountered an error state. I\'m reaching out to get guidance on how to recover my funds.\n\nThank
you.
@@ -47,6 +58,7 @@
code: %3$d,
description: %4$s
- Unable to launch email app.
+ Unable to launch email app.
+ Transaction IDs