Skip to content

Commit

Permalink
[#1657] Redesign SendConfirmation subscreens
Browse files Browse the repository at this point in the history
* [#1657] Improve sub-screens previews

* Initial design structure changes

* Bottom bar by screen stage

* Bottom bar paddings

* TopAppBar for all screens

* Content part - success (partly)

* Fix SendConfirmationContent composable scrolling

* Improve SendConfirmationSending UI

* SendConfirmationSending subscreen final UI

* SendingConfirmationSuccess subscreen UI

* SendConfirmationFailure UI

* Failed/Success view transaction logic

* SendConfirmationGrpcFailire UI

* MultipleTrxFailure UI partly done

* MultipleTrxFailure screen UI

* Gradient Scaffold for subscreens

* Fix static code analysis warnings

* Changelogs update

* Screen images update

* WhatNewEs changelog update

* Update Spanish translation keys
  • Loading branch information
HonzaR authored Nov 13, 2024
1 parent 60fa926 commit 882605d
Show file tree
Hide file tree
Showing 35 changed files with 1,896 additions and 475 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions docs/whatsNew/WHATS_NEW_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions docs/whatsNew/WHATS_NEW_ES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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)),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) },
Expand Down Expand Up @@ -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 = {},
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {},
Expand Down
13 changes: 13 additions & 0 deletions ui-design-lib/src/main/res/ui/common/drawable-night/ic_close.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M18,6L6,18M6,6L18,18"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#E8E8E8"
android:strokeLineCap="round"/>
</vector>
13 changes: 13 additions & 0 deletions ui-design-lib/src/main/res/ui/common/drawable/ic_close.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M18,6L6,18M6,6L18,18"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#231F20"
android:strokeLineCap="round"/>
</vector>
Original file line number Diff line number Diff line change
Expand Up @@ -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)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ fun Home(

@Composable
@Suppress("LongMethod")
@OptIn(ExperimentalFoundationApi::class)
private fun HomeContent(
pagerState: PagerState,
subScreens: ImmutableList<TabItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
SendConfirmationStage.Prepared -> goBack(false)
SendConfirmationStage.Sending -> { /* No action - wait until the sending is done */ }
SendConfirmationStage.Success -> {
goHome()
}

is SendConfirmationStage.Failure -> setStage(SendConfirmationStage.Confirmation)
is SendConfirmationStage.Failure -> setStage(SendConfirmationStage.Prepared)
is SendConfirmationStage.FailureGrpc -> {
setStage(SendConfirmationStage.Confirmation)
goHome()
}
is SendConfirmationStage.MultipleTrxFailure -> { // no action - wait until report the result
}

is SendConfirmationStage.MultipleTrxFailure -> { /* No action - wait until the sending is done */ }
is SendConfirmationStage.MultipleTrxFailureReported -> goBack(true)
}
}
Expand Down Expand Up @@ -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())
)
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -280,7 +294,6 @@ internal fun WrapSendConfirmation(
@Suppress("LongParameterList")
suspend fun runSendFundsAction(
createTransactionsViewModel: CreateTransactionsViewModel,
goHome: () -> Unit,
proposal: Proposal,
setStage: (SendConfirmationStage) -> Unit,
spendingKey: UnifiedSpendingKey,
Expand All @@ -299,7 +312,6 @@ suspend fun runSendFundsAction(
Twig.debug { "Transactions submitted with result: $submitResult" }

processSubmissionResult(
goHome = goHome,
setStage = setStage,
submitResult = submitResult
)
Expand Down Expand Up @@ -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()))
Expand Down
Loading

0 comments on commit 882605d

Please sign in to comment.