diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a98d2e1b..b78af2468 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this application adheres to [Semantic Versioning](https://semver.org/spec/v2 ## [Unreleased] +### Changed +- The QR code image logic of the `QrCode`, `Request`, and `SignTransaction` screens has been refactored to work + with the newer `ZashiQr` component + ### Fixed - The Disconnected popup trigger when the app is backgrounded has been fixed diff --git a/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/ZashiQr.kt b/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/ZashiQr.kt index fcb3319b1..9bdb0356b 100644 --- a/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/ZashiQr.kt +++ b/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/ZashiQr.kt @@ -2,16 +2,21 @@ package co.electriccoin.zcash.ui.design.component import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Surface import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.res.vectorResource import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import co.electriccoin.zcash.ui.design.theme.colors.ZashiColors @@ -19,31 +24,44 @@ import co.electriccoin.zcash.ui.design.theme.dimensions.ZashiDimensions import co.electriccoin.zcash.ui.design.util.AndroidQrCodeImageGenerator import co.electriccoin.zcash.ui.design.util.JvmQrCodeGenerator import co.electriccoin.zcash.ui.design.util.QrCodeColors +import co.electriccoin.zcash.ui.design.util.StringResource +import co.electriccoin.zcash.ui.design.util.getValue import co.electriccoin.zcash.ui.design.util.orDark @Composable fun ZashiQr( - qrData: String, + state: QrState, modifier: Modifier = Modifier, qrSize: Dp = ZashiQrDefaults.width, - colors: QrCodeColors = QrCodeDefaults.colors() + colors: QrCodeColors = QrCodeDefaults.colors(), ) { val qrSizePx = with(LocalDensity.current) { qrSize.roundToPx() } - val bitmap = getQrCode(qrData, qrSizePx, colors) + val bitmap = getQrCode(state.qrData, qrSizePx, colors) Surface( modifier = modifier, shape = RoundedCornerShape(ZashiDimensions.Radius.radius4xl), border = BorderStroke(width = 1.dp, color = ZashiColors.Surfaces.strokePrimary), - color = ZashiColors.Surfaces.bgPrimary + color = ZashiColors.Surfaces.bgPrimary, ) { Box( modifier = Modifier.padding(all = 12.dp) ) { Image( bitmap = bitmap, - contentDescription = null, + contentDescription = state.contentDescription?.getValue(), + Modifier.clickable { state.onClick() } ) + if (state.centerImageResId != null) { + Image( + modifier = + Modifier + .size(64.dp) + .align(Alignment.Center), + imageVector = ImageVector.vectorResource(state.centerImageResId), + contentDescription = null, + ) + } } } } @@ -75,3 +93,10 @@ object QrCodeDefaults { foreground = foreground ) } + +data class QrState( + val qrData: String, + val contentDescription: StringResource? = null, + val onClick: () -> Unit = {}, + val centerImageResId: Int? = null, +) 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 1a386dd30..5a60b0160 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 @@ -541,20 +541,7 @@ fun NavHostController.popBackStackJustOnce(currentRouteToBePopped: String) { object NavigationArguments { const val SEND_SCAN_RECIPIENT_ADDRESS = "send_scan_recipient_address" const val SEND_SCAN_ZIP_321_URI = "send_scan_zip_321_uri" - - const val SEND_CONFIRM_RECIPIENT_ADDRESS = "send_confirm_recipient_address" - const val SEND_CONFIRM_AMOUNT = "send_confirm_amount" - const val SEND_CONFIRM_MEMO = "send_confirm_memo" - const val SEND_CONFIRM_PROPOSAL = "send_confirm_proposal" - const val SEND_CONFIRM_INITIAL_STAGE = "send_confirm_initial_stage" - const val MULTIPLE_SUBMISSION_CLEAR_FORM = "multiple_submission_clear_form" - - const val PAYMENT_REQUEST_ADDRESS = "payment_request_address" - const val PAYMENT_REQUEST_AMOUNT = "payment_request_amount" - const val PAYMENT_REQUEST_MEMO = "payment_request_memo" - const val PAYMENT_REQUEST_PROPOSAL = "payment_request_proposal" - const val PAYMENT_REQUEST_URI = "payment_request_uri" } object NavigationTargets { diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/exchangerate/widget/StyledExchangeBalance.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/exchangerate/widget/StyledExchangeBalance.kt index 9d0de0f0a..98777887a 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/exchangerate/widget/StyledExchangeBalance.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/exchangerate/widget/StyledExchangeBalance.kt @@ -5,7 +5,6 @@ package co.electriccoin.zcash.ui.screen.exchangerate.widget import androidx.compose.animation.animateContentSize import androidx.compose.animation.core.MutableTransitionState import androidx.compose.foundation.BorderStroke -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.basicMarquee import androidx.compose.foundation.layout.Column @@ -93,7 +92,6 @@ fun StyledExchangeBalance( } @Suppress("LongParameterList", "LongMethod") -@OptIn(ExperimentalFoundationApi::class) @Composable private fun ExchangeAvailableRateLabelInternal( style: TextStyle, diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/qrcode/model/QrCodeState.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/qrcode/model/QrCodeState.kt index 6591f7531..59941f2b9 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/qrcode/model/QrCodeState.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/qrcode/model/QrCodeState.kt @@ -2,8 +2,10 @@ package co.electriccoin.zcash.ui.screen.qrcode.model import androidx.compose.ui.graphics.ImageBitmap import cash.z.ecc.android.sdk.model.WalletAddress +import co.electriccoin.zcash.ui.design.component.QrState +import co.electriccoin.zcash.ui.design.util.StringResource -internal sealed class QrCodeState { +sealed class QrCodeState { data object Loading : QrCodeState() data class Prepared( @@ -11,8 +13,19 @@ internal sealed class QrCodeState { val walletAddress: WalletAddress, val onAddressCopy: (String) -> Unit, val onQrCodeShare: (ImageBitmap) -> Unit, + val onQrCodeClick: () -> Unit, val onBack: () -> Unit, - ) : QrCodeState() + ) : QrCodeState() { + fun toQrState( + contentDescription: StringResource? = null, + centerImageResId: Int? = null + ) = QrState( + qrData = walletAddress.address, + onClick = onQrCodeClick, + contentDescription = contentDescription, + centerImageResId = centerImageResId + ) + } } enum class QrCodeType { diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/qrcode/view/QrCodeView.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/qrcode/view/QrCodeView.kt index ae7290cc4..da654056f 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/qrcode/view/QrCodeView.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/qrcode/view/QrCodeView.kt @@ -3,15 +3,10 @@ package co.electriccoin.zcash.ui.screen.qrcode.view import androidx.compose.animation.animateContentSize -import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Spacer @@ -21,7 +16,6 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material3.IconButton import androidx.compose.material3.SnackbarHost @@ -33,7 +27,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment +import androidx.compose.ui.Alignment.Companion.CenterHorizontally import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.platform.LocalDensity @@ -55,15 +49,16 @@ import co.electriccoin.zcash.ui.design.component.ZashiBadgeColors 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.ZashiQr import co.electriccoin.zcash.ui.design.component.ZashiSmallTopAppBar 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.AndroidQrCodeImageGenerator import co.electriccoin.zcash.ui.design.util.JvmQrCodeGenerator import co.electriccoin.zcash.ui.design.util.QrCodeColors +import co.electriccoin.zcash.ui.design.util.stringRes import co.electriccoin.zcash.ui.screen.qrcode.model.QrCodeState import co.electriccoin.zcash.ui.screen.qrcode.model.QrCodeType import kotlinx.coroutines.runBlocking @@ -91,6 +86,7 @@ private fun ZashiPreview() = walletAddress = runBlocking { WalletAddressFixture.unified() }, onAddressCopy = {}, onQrCodeShare = {}, + onQrCodeClick = {}, onBack = {}, ), snackbarHostState = SnackbarHostState(), @@ -109,6 +105,7 @@ private fun KeystonePreview() = walletAddress = runBlocking { WalletAddressFixture.unified() }, onAddressCopy = {}, onQrCodeShare = {}, + onQrCodeClick = {}, onBack = {}, ), snackbarHostState = SnackbarHostState(), @@ -154,10 +151,7 @@ internal fun QrCodeView( } ) { paddingValues -> QrCodeContents( - qrCodeType = state.qrCodeType, - walletAddress = state.walletAddress, - onAddressCopy = state.onAddressCopy, - onQrCodeShare = state.onQrCodeShare, + state = state, modifier = Modifier.padding( top = paddingValues.calculateTopPadding(), @@ -239,10 +233,7 @@ private fun QrCodeBottomBar( @Composable private fun QrCodeContents( - qrCodeType: QrCodeType, - walletAddress: WalletAddress, - onAddressCopy: (String) -> Unit, - onQrCodeShare: (ImageBitmap) -> Unit, + state: QrCodeState.Prepared, modifier: Modifier = Modifier, ) { Column( @@ -254,16 +245,16 @@ private fun QrCodeContents( ) { Spacer(Modifier.height(ZcashTheme.dimens.spacingDefault)) - when (walletAddress) { + when (state.walletAddress) { // We use the same design for the Sapling address for the Testnet app variant is WalletAddress.Unified, is WalletAddress.Sapling -> { - UnifiedQrCodePanel(qrCodeType, walletAddress, onAddressCopy, onQrCodeShare) + UnifiedQrCodePanel(state) } is WalletAddress.Transparent -> { - TransparentQrCodePanel(qrCodeType, walletAddress, onAddressCopy, onQrCodeShare) + TransparentQrCodePanel(state) } else -> { - error("Unsupported address type: $walletAddress") + error("Unsupported address type: ${state.walletAddress}") } } } @@ -272,10 +263,7 @@ private fun QrCodeContents( @Composable @Suppress("LongMethod") fun UnifiedQrCodePanel( - qrCodeType: QrCodeType, - walletAddress: WalletAddress, - onAddressCopy: (String) -> Unit, - onQrCodeShare: (ImageBitmap) -> Unit, + state: QrCodeState.Prepared, modifier: Modifier = Modifier ) { var expandedAddress by rememberSaveable { mutableStateOf(false) } @@ -284,15 +272,13 @@ fun UnifiedQrCodePanel( modifier = modifier .padding(vertical = ZcashTheme.dimens.spacingDefault), - horizontalAlignment = Alignment.CenterHorizontally + horizontalAlignment = CenterHorizontally ) { QrCode( - walletAddress = walletAddress, - onQrImageShare = onQrCodeShare, + preparedState = state, modifier = Modifier .padding(horizontal = 24.dp), - qrCodeType = qrCodeType, ) Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingUpLarge)) @@ -312,18 +298,18 @@ fun UnifiedQrCodePanel( Text( text = - when (walletAddress) { + when (state.walletAddress) { is WalletAddress.Unified -> - when (qrCodeType) { + when (state.qrCodeType) { QrCodeType.ZASHI -> stringResource(R.string.qr_code_wallet_address_shielded) QrCodeType.KEYSTONE -> stringResource(R.string.qr_code_wallet_address_shielded_keystone) } is WalletAddress.Sapling -> - when (qrCodeType) { + when (state.qrCodeType) { QrCodeType.ZASHI -> stringResource(id = R.string.qr_code_wallet_address_sapling) QrCodeType.KEYSTONE -> stringResource(id = R.string.qr_code_wallet_address_sapling_keystone) } - else -> error("Unsupported address type: $walletAddress") + else -> error("Unsupported address type: ${state.walletAddress}") }, color = ZashiColors.Text.textPrimary, style = ZashiTypography.textXl, @@ -335,7 +321,7 @@ fun UnifiedQrCodePanel( @OptIn(ExperimentalFoundationApi::class) Text( - text = walletAddress.address, + text = state.walletAddress.address, color = ZashiColors.Text.textTertiary, style = ZashiTypography.textSm, textAlign = TextAlign.Center, @@ -353,7 +339,7 @@ fun UnifiedQrCodePanel( indication = null, interactionSource = remember { MutableInteractionSource() }, onClick = { expandedAddress = !expandedAddress }, - onLongClick = { onAddressCopy(walletAddress.address) } + onLongClick = { state.onAddressCopy(state.walletAddress.address) } ) ) } @@ -362,10 +348,7 @@ fun UnifiedQrCodePanel( @Composable @Suppress("LongMethod") fun TransparentQrCodePanel( - qrCodeType: QrCodeType, - walletAddress: WalletAddress, - onAddressCopy: (String) -> Unit, - onQrCodeShare: (ImageBitmap) -> Unit, + state: QrCodeState.Prepared, modifier: Modifier = Modifier ) { var expandedAddress by rememberSaveable { mutableStateOf(false) } @@ -374,15 +357,13 @@ fun TransparentQrCodePanel( modifier = modifier .padding(vertical = ZcashTheme.dimens.spacingDefault), - horizontalAlignment = Alignment.CenterHorizontally + horizontalAlignment = CenterHorizontally ) { QrCode( - walletAddress = walletAddress, - onQrImageShare = onQrCodeShare, + preparedState = state, modifier = Modifier .padding(horizontal = 24.dp), - qrCodeType = qrCodeType, ) Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingUpLarge)) @@ -412,7 +393,7 @@ fun TransparentQrCodePanel( @OptIn(ExperimentalFoundationApi::class) Text( - text = walletAddress.address, + text = state.walletAddress.address, color = ZashiColors.Text.textTertiary, style = ZashiTypography.textSm, textAlign = TextAlign.Center, @@ -430,7 +411,7 @@ fun TransparentQrCodePanel( indication = null, interactionSource = remember { MutableInteractionSource() }, onClick = { expandedAddress = !expandedAddress }, - onLongClick = { onAddressCopy(walletAddress.address) } + onLongClick = { state.onAddressCopy(state.walletAddress.address) } ) ) } @@ -438,51 +419,28 @@ fun TransparentQrCodePanel( @Composable private fun ColumnScope.QrCode( - qrCodeType: QrCodeType, - walletAddress: WalletAddress, - onQrImageShare: (ImageBitmap) -> Unit, + preparedState: QrCodeState.Prepared, modifier: Modifier = Modifier ) { - val sizePixels = with(LocalDensity.current) { DEFAULT_QR_CODE_SIZE.toPx() }.roundToInt() - val colors = QrCodeDefaults.colors() - val qrCodeImage = - remember { - qrCodeForAddress( - address = walletAddress.address, - size = sizePixels, - colors = colors - ) - } - - QrCode( - qrCodeImage = qrCodeImage, - onQrImageBitmapShare = onQrImageShare, - contentDescription = - stringResource( - when (walletAddress) { - is WalletAddress.Unified -> R.string.qr_code_unified_content_description - is WalletAddress.Sapling -> R.string.qr_code_sapling_content_description - is WalletAddress.Transparent -> R.string.qr_code_transparent_content_description - else -> error("Unsupported address type: $walletAddress") - } + ZashiQr( + state = + preparedState.toQrState( + contentDescription = + stringRes( + when (preparedState.walletAddress) { + is WalletAddress.Unified -> R.string.qr_code_unified_content_description + is WalletAddress.Sapling -> R.string.qr_code_sapling_content_description + is WalletAddress.Transparent -> R.string.qr_code_transparent_content_description + else -> error("Unsupported address type: ${preparedState.walletAddress}") + } + ), + centerImageResId = + when (preparedState.qrCodeType) { + QrCodeType.ZASHI -> R.drawable.logo_zec_fill_stroke + QrCodeType.KEYSTONE -> co.electriccoin.zcash.ui.design.R.drawable.ic_item_keystone_qr + } ), - modifier = - modifier - .align(Alignment.CenterHorizontally) - .border( - border = - BorderStroke( - width = 1.dp, - color = ZashiColors.Surfaces.strokePrimary - ), - shape = RoundedCornerShape(ZashiDimensions.Radius.radius4xl) - ) - .background( - color = ZashiColors.Surfaces.bgPrimary, - shape = RoundedCornerShape(ZashiDimensions.Radius.radius4xl) - ) - .padding(all = 12.dp), - qrCodeType = qrCodeType + modifier = modifier.align(CenterHorizontally), ) } @@ -502,45 +460,4 @@ private fun qrCodeForAddress( return AndroidQrCodeImageGenerator.generate(qrCodePixelArray, size, colors) } -@Composable -private fun QrCode( - qrCodeType: QrCodeType, - contentDescription: String, - qrCodeImage: ImageBitmap, - onQrImageBitmapShare: (ImageBitmap) -> Unit, - modifier: Modifier = Modifier, -) { - Box( - contentAlignment = Alignment.Center, - modifier = - Modifier - .clickable( - indication = null, - interactionSource = remember { MutableInteractionSource() }, - onClick = { onQrImageBitmapShare(qrCodeImage) }, - ) - .then(modifier) - ) { - Image( - bitmap = qrCodeImage, - contentDescription = contentDescription, - ) - - Image( - modifier = Modifier.size(64.dp), - painter = - when (qrCodeType) { - QrCodeType.ZASHI -> painterResource(id = R.drawable.logo_zec_fill_stroke) - QrCodeType.KEYSTONE -> - painterResource( - id = - co.electriccoin.zcash.ui.design.R.drawable - .ic_item_keystone_qr - ) - }, - contentDescription = contentDescription, - ) - } -} - private val DEFAULT_QR_CODE_SIZE = 320.dp diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/qrcode/viewmodel/QrCodeViewModel.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/qrcode/viewmodel/QrCodeViewModel.kt index e7e42ee9c..d168f7425 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/qrcode/viewmodel/QrCodeViewModel.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/qrcode/viewmodel/QrCodeViewModel.kt @@ -57,6 +57,10 @@ class QrCodeViewModel( walletAddress = walletAddress, onAddressCopy = { address -> onAddressCopyClick(address) }, onQrCodeShare = { onQrCodeShareClick(it, versionInfo) }, + onQrCodeClick = { + // TODO [#1731]: Allow QR codes colors switching + // TODO [#1731]: https://github.com/Electric-Coin-Company/zashi-android/issues/1731 + }, onBack = ::onBack, qrCodeType = when (account) { diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/request/model/RequestState.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/request/model/RequestState.kt index 00e68391a..797cfd6d3 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/request/model/RequestState.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/request/model/RequestState.kt @@ -5,7 +5,9 @@ import cash.z.ecc.android.sdk.model.MonetarySeparators import cash.z.ecc.android.sdk.model.WalletAddress import cash.z.ecc.sdk.type.ZcashCurrency import co.electriccoin.zcash.ui.common.wallet.ExchangeRateState +import co.electriccoin.zcash.ui.design.component.QrState import co.electriccoin.zcash.ui.design.util.QrCodeColors +import co.electriccoin.zcash.ui.design.util.StringResource internal sealed class RequestState { data object Loading : RequestState() @@ -37,10 +39,21 @@ internal sealed class RequestState { val icon: Int, val request: Request, val walletAddress: WalletAddress, + val onQrCodeClick: () -> Unit, val onQrCodeShare: (ImageBitmap) -> Unit, val onQrCodeGenerate: (pixels: Int, colors: QrCodeColors) -> Unit, override val onBack: () -> Unit, val onClose: () -> Unit, val zcashCurrency: ZcashCurrency, - ) : Prepared(onBack) + ) : Prepared(onBack) { + fun toQrState( + contentDescription: StringResource? = null, + centerImageResId: Int? = null, + ) = QrState( + qrData = walletAddress.address, + onClick = onQrCodeClick, + contentDescription = contentDescription, + centerImageResId = centerImageResId + ) + } } diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/request/view/RequestQrCodeView.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/request/view/RequestQrCodeView.kt index ae414bd2e..3a98dd497 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/request/view/RequestQrCodeView.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/request/view/RequestQrCodeView.kt @@ -1,28 +1,18 @@ package co.electriccoin.zcash.ui.screen.request.view -import androidx.compose.foundation.BorderStroke -import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment +import androidx.compose.ui.Alignment.Companion.CenterHorizontally import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.SpanStyle @@ -32,16 +22,14 @@ import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import cash.z.ecc.android.sdk.model.WalletAddress import co.electriccoin.zcash.ui.R -import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator -import co.electriccoin.zcash.ui.design.component.QrCodeDefaults import co.electriccoin.zcash.ui.design.component.ZashiBadge import co.electriccoin.zcash.ui.design.component.ZashiBadgeColors +import co.electriccoin.zcash.ui.design.component.ZashiQr 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.stringRes import co.electriccoin.zcash.ui.screen.request.model.RequestState -import kotlin.math.roundToInt @Composable internal fun RequestQrCodeView( @@ -96,7 +84,7 @@ internal fun RequestQrCodeView( Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingBig)) QrCode( - state = state, + requestState = state, modifier = Modifier.padding(horizontal = 24.dp), ) @@ -106,71 +94,19 @@ internal fun RequestQrCodeView( @Composable private fun ColumnScope.QrCode( - state: RequestState.QrCode, + requestState: RequestState.QrCode, modifier: Modifier = Modifier ) { - val sizePixels = with(LocalDensity.current) { DEFAULT_QR_CODE_SIZE.toPx() }.roundToInt() - - if (state.request.qrCodeState.bitmap == null) { - val colors = QrCodeDefaults.colors() - state.onQrCodeGenerate(sizePixels, colors) - } - - QrCode( - state = state, - contentDescription = stringResource(id = R.string.request_qr_code_content_description), - modifier = - modifier - .align(Alignment.CenterHorizontally) - .border( - border = - BorderStroke( - width = 1.dp, - color = ZashiColors.Surfaces.strokePrimary - ), - shape = RoundedCornerShape(ZashiDimensions.Radius.radius4xl) - ) - .background( - color = ZashiColors.Surfaces.bgPrimary, - shape = RoundedCornerShape(ZashiDimensions.Radius.radius4xl) - ) - .padding(all = 12.dp) + ZashiQr( + state = + requestState.toQrState( + contentDescription = stringRes(R.string.request_qr_code_content_description), + centerImageResId = requestState.icon + ), + modifier = modifier.align(CenterHorizontally), ) } -@Composable -private fun QrCode( - state: RequestState.QrCode, - contentDescription: String, - modifier: Modifier = Modifier, -) { - Box( - contentAlignment = Alignment.Center, - modifier = - Modifier - .clickable( - indication = null, - interactionSource = remember { MutableInteractionSource() }, - onClick = { state.request.qrCodeState.bitmap?.let { state.onQrCodeShare(it) } }, - ) - .then(modifier) - ) { - if (state.request.qrCodeState.bitmap == null) { - CircularScreenProgressIndicator() - } else { - Image( - bitmap = state.request.qrCodeState.bitmap, - contentDescription = contentDescription, - ) - Image( - modifier = Modifier.size(64.dp), - painter = painterResource(id = state.icon), - contentDescription = contentDescription, - ) - } - } -} - @Composable private fun RequestQrCodeZecAmountView( state: RequestState.QrCode, @@ -196,5 +132,3 @@ private fun RequestQrCodeZecAmountView( modifier = modifier ) } - -private val DEFAULT_QR_CODE_SIZE = 320.dp diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/request/viewmodel/RequestViewModel.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/request/viewmodel/RequestViewModel.kt index f8a8997ea..82c688f7c 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/request/viewmodel/RequestViewModel.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/request/viewmodel/RequestViewModel.kt @@ -144,6 +144,10 @@ class RequestViewModel( colors = colors, ) }, + onQrCodeClick = { + // TODO [#1731]: Allow QR codes colors switching + // TODO [#1731]: https://github.com/Electric-Coin-Company/zashi-android/issues/1731 + }, onQrCodeShare = { onRequestQrCodeShare(it, shareImageBitmap) }, onBack = ::onBack, onClose = ::onClose, diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/signkeystonetransaction/state/SignKeystoneTransactionState.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/signkeystonetransaction/state/SignKeystoneTransactionState.kt index c8e1eab7b..10f5c14d7 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/signkeystonetransaction/state/SignKeystoneTransactionState.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/signkeystonetransaction/state/SignKeystoneTransactionState.kt @@ -2,17 +2,32 @@ package co.electriccoin.zcash.ui.screen.signkeystonetransaction.state import androidx.annotation.DrawableRes import co.electriccoin.zcash.ui.design.component.ButtonState +import co.electriccoin.zcash.ui.design.component.QrState import co.electriccoin.zcash.ui.design.util.StringResource data class SignKeystoneTransactionState( val onBack: () -> Unit, + val onQrCodeClick: () -> Unit, val accountInfo: ZashiAccountInfoListItemState, val qrData: String?, val generateNextQrCode: () -> Unit, val shareButton: ButtonState?, val positiveButton: ButtonState, val negativeButton: ButtonState, -) +) { + fun toQrState( + contentDescription: StringResource? = null, + centerImageResId: Int? = null, + ): QrState { + requireNotNull(qrData) { "The QR code data needs to be set at this point" } + return QrState( + qrData = qrData, + onClick = onQrCodeClick, + contentDescription = contentDescription, + centerImageResId = centerImageResId + ) + } +} data class ZashiAccountInfoListItemState( @DrawableRes val icon: Int, diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/signkeystonetransaction/view/SignKeystoneTransactionView.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/signkeystonetransaction/view/SignKeystoneTransactionView.kt index 79c3b0d73..5585748a7 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/signkeystonetransaction/view/SignKeystoneTransactionView.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/signkeystonetransaction/view/SignKeystoneTransactionView.kt @@ -124,14 +124,17 @@ private fun ZashiAccountInfoListItem( } @Composable -private fun ColumnScope.QrContent(state: SignKeystoneTransactionState) { - state.qrData?.let { - ZashiQr(qrData = it, modifier = Modifier.align(CenterHorizontally)) +private fun ColumnScope.QrContent(ksState: SignKeystoneTransactionState) { + ksState.qrData?.let { + ZashiQr( + state = ksState.toQrState(), + modifier = Modifier.align(CenterHorizontally) + ) } - LaunchedEffect(state.qrData) { - if (state.qrData != null) { + LaunchedEffect(ksState.qrData) { + if (ksState.qrData != null) { delay(100.milliseconds) - state.generateNextQrCode() + ksState.generateNextQrCode() } } } @@ -182,6 +185,7 @@ private fun Preview() = positiveButton = ButtonState(stringRes("Get Signature")), negativeButton = ButtonState(stringRes("Reject")), onBack = {}, + onQrCodeClick = {}, ) ) } @@ -205,6 +209,7 @@ private fun DebugPreview() = positiveButton = ButtonState(stringRes("Get Signature")), negativeButton = ButtonState(stringRes("Reject")), onBack = {}, + onQrCodeClick = {}, ) ) } diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/signkeystonetransaction/viewmodel/SignKeystoneTransactionViewModel.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/signkeystonetransaction/viewmodel/SignKeystoneTransactionViewModel.kt index dcfaaeb87..e312bd7ef 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/signkeystonetransaction/viewmodel/SignKeystoneTransactionViewModel.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/signkeystonetransaction/viewmodel/SignKeystoneTransactionViewModel.kt @@ -75,7 +75,11 @@ class SignKeystoneTransactionViewModel( text = stringRes("Share PCZT"), onClick = ::onSharePCZTClick ).takeIf { BuildConfig.DEBUG }, - onBack = ::onBack + onBack = ::onBack, + onQrCodeClick = { + // TODO [#1731]: Allow QR codes colors switching + // TODO [#1731]: https://github.com/Electric-Coin-Company/zashi-android/issues/1731 + }, ) }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT), null)