Skip to content

Commit

Permalink
[#1612] QR Code screen
Browse files Browse the repository at this point in the history
* Refactor Receive screen architecture

- Added QrCodeScreen architecture and basic UI

* QrCode Detail screen UI + logic

* Improve share intent

+ Attach snackbar to the failed sharing attempt
+ Fix tests

* Changelogs update

* Ktlint warnings fix
  • Loading branch information
HonzaR authored Oct 8, 2024
1 parent 1fedce1 commit c6257d8
Show file tree
Hide file tree
Showing 46 changed files with 1,292 additions and 151 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ and this application adheres to [Semantic Versioning](https://semver.org/spec/v2
- Confirmation screen redesigned
- History item redesigned

### Added
- New QR Code detail screen has been added

## [1.2 (739)] - 2024-09-27

### Changed
Expand Down
3 changes: 3 additions & 0 deletions docs/whatsNew/WHATS_NEW_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ directly impact users rather than highlighting other key architectural updates.*
- Confirmation screen redesigned
- History item redesigned

### Added
- New QR Code detail screen has been added

## [1.2 (739)] - 2024-09-27

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import androidx.compose.ui.graphics.PaintingStyle
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.text.TextStyle
Expand Down Expand Up @@ -467,6 +468,7 @@ private enum class ButtonMode { Pressed, Idle }

data class ButtonState(
val text: StringResource,
val leadingIconVector: Painter? = null,
val isEnabled: Boolean = true,
val isLoading: Boolean = false,
val onClick: () -> Unit = {},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
package co.electriccoin.zcash.ui.design.component

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
Expand All @@ -23,10 +30,12 @@ import co.electriccoin.zcash.ui.design.util.stringRes
fun ZashiBadge(
text: String,
modifier: Modifier = Modifier,
leadingIconVector: Painter? = null,
colors: ZashiBadgeColors = ZashiBadgeDefaults.successBadgeColors()
) {
ZashiBadge(
text = stringRes(text),
leadingIconVector = leadingIconVector,
modifier = modifier,
colors = colors
)
Expand All @@ -36,6 +45,7 @@ fun ZashiBadge(
fun ZashiBadge(
text: StringResource,
modifier: Modifier = Modifier,
leadingIconVector: Painter? = null,
colors: ZashiBadgeColors = ZashiBadgeDefaults.successBadgeColors()
) {
Surface(
Expand All @@ -44,9 +54,20 @@ fun ZashiBadge(
color = colors.container,
border = BorderStroke(1.dp, colors.border),
) {
Box(
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(horizontal = 10.dp, vertical = 4.dp)
) {
if (leadingIconVector != null) {
Image(
painter = leadingIconVector,
contentDescription = null,
modifier = Modifier.size(14.dp)
)

Spacer(modifier = Modifier.width(4.dp))
}

Text(
text = text.getValue(),
style = ZcashTheme.extendedTypography.transactionItemStyles.contentMedium,
Expand Down Expand Up @@ -82,5 +103,8 @@ object ZashiBadgeDefaults {
@Composable
private fun BadgePreview() =
ZcashTheme {
ZashiBadge(text = stringRes("Badge"))
ZashiBadge(
text = stringRes("Badge"),
leadingIconVector = painterResource(id = android.R.drawable.ic_input_add),
)
}
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.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.isSystemInDarkTheme
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.shape.RoundedCornerShape
import androidx.compose.material3.Button
Expand All @@ -14,6 +16,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import co.electriccoin.zcash.ui.design.R
Expand All @@ -32,6 +36,7 @@ fun ZashiButton(
) {
ZashiButton(
text = state.text.getValue(),
leadingIcon = state.leadingIconVector,
onClick = state.onClick,
modifier = modifier,
enabled = state.isEnabled,
Expand All @@ -47,13 +52,25 @@ fun ZashiButton(
text: String,
onClick: () -> Unit,
modifier: Modifier = Modifier,
leadingIcon: Painter? = null,
enabled: Boolean = true,
isLoading: Boolean = false,
colors: ZashiButtonColors = ZashiButtonDefaults.primaryColors(),
content: @Composable RowScope.(ZashiButtonScope) -> Unit = ZashiButtonDefaults.content
) {
val scope =
object : ZashiButtonScope {
@Composable
override fun LeadingIcon() {
if (leadingIcon != null) {
Image(
painter = leadingIcon,
contentDescription = null,
modifier = Modifier.size(20.dp)
)
}
}

@Composable
override fun Text() {
Text(
Expand Down Expand Up @@ -92,6 +109,9 @@ fun ZashiButton(
}

interface ZashiButtonScope {
@Composable
fun LeadingIcon()

@Composable
fun Text()

Expand All @@ -102,6 +122,8 @@ interface ZashiButtonScope {
object ZashiButtonDefaults {
val content: @Composable RowScope.(ZashiButtonScope) -> Unit
get() = { scope ->
scope.LeadingIcon()
Spacer(modifier = Modifier.width(6.dp))
scope.Text()
Spacer(modifier = Modifier.width(6.dp))
scope.Loading()
Expand All @@ -121,6 +143,20 @@ object ZashiButtonDefaults {
borderColor = Color.Unspecified
)

@Composable
fun secondaryColors(
containerColor: Color = ZashiColors.Btns.Secondary.btnSecondaryBg,
contentColor: Color = ZashiColors.Btns.Secondary.btnSecondaryFg,
disabledContainerColor: Color = ZashiColors.Btns.Secondary.btnSecondaryBgDisabled,
disabledContentColor: Color = ZashiColors.Btns.Secondary.btnSecondaryFg,
) = ZashiButtonColors(
containerColor = containerColor,
contentColor = contentColor,
disabledContainerColor = disabledContainerColor,
disabledContentColor = disabledContentColor,
borderColor = Color.Unspecified
)

@Composable
fun tertiaryColors(
containerColor: Color = ZashiColors.Btns.Tertiary.btnTertiaryBg,
Expand Down Expand Up @@ -169,7 +205,6 @@ private fun ZashiButtonColors.toButtonColors() =
disabledContentColor = disabledContentColor,
)

@Suppress("UnusedPrivateMember")
@PreviewScreens
@Composable
private fun PrimaryPreview() =
Expand All @@ -183,7 +218,20 @@ private fun PrimaryPreview() =
}
}

@Suppress("UnusedPrivateMember")
@PreviewScreens
@Composable
private fun PrimaryWithIconPreview() =
ZcashTheme {
BlankSurface {
ZashiButton(
modifier = Modifier.fillMaxWidth(),
text = "Primary",
leadingIcon = painterResource(id = android.R.drawable.ic_secure),
onClick = {},
)
}
}

@PreviewScreens
@Composable
private fun TertiaryPreview() =
Expand All @@ -198,7 +246,6 @@ private fun TertiaryPreview() =
}
}

@Suppress("UnusedPrivateMember")
@PreviewScreens
@Composable
private fun DestroyPreview() =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import androidx.compose.foundation.layout.RowScope
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.design.theme.internal.SecondaryTypography
import co.electriccoin.zcash.ui.design.theme.internal.TopAppBarColors

@Composable
@Suppress("LongParameterList")
fun ZashiSmallTopAppBar(
title: String,
title: String?,
subtitle: String?,
modifier: Modifier = Modifier,
showTitleLogo: Boolean = false,
Expand All @@ -32,3 +33,13 @@ fun ZashiSmallTopAppBar(
titleStyle = SecondaryTypography.headlineSmall.copy(fontWeight = FontWeight.SemiBold)
)
}

@PreviewScreens
@Composable
private fun ZashiSmallTopAppBarPreview() =
ZcashTheme {
ZashiSmallTopAppBar(
title = "Test Title",
subtitle = "Subtitle",
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="40dp"
android:height="40dp"
android:viewportWidth="40"
android:viewportHeight="40">
<path
android:pathData="M0,12C0,5.373 5.373,0 12,0H28C34.627,0 40,5.373 40,12V28C40,34.627 34.627,40 28,40H12C5.373,40 0,34.627 0,28V12Z"
android:fillColor="#343031"/>
<path
android:pathData="M26,14L14,26M14,14L26,26"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#D2D1D2"
android:strokeLineCap="round"/>
</vector>
16 changes: 16 additions & 0 deletions ui-design-lib/src/main/res/ui/common/drawable/ic_close_full.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="40dp"
android:height="40dp"
android:viewportWidth="40"
android:viewportHeight="40">
<path
android:pathData="M0,12C0,5.373 5.373,0 12,0H28C34.627,0 40,5.373 40,12V28C40,34.627 34.627,40 28,40H12C5.373,40 0,34.627 0,28V12Z"
android:fillColor="#EBEBE6"/>
<path
android:pathData="M26,14L14,26M14,14L26,26"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#4D4941"
android:strokeLineCap="round"/>
</vector>
1 change: 1 addition & 0 deletions ui-lib/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ android {
"src/main/res/ui/choose_server",
"src/main/res/ui/new_wallet_recovery",
"src/main/res/ui/onboarding",
"src/main/res/ui/qr_code",
"src/main/res/ui/receive",
"src/main/res/ui/restore",
"src/main/res/ui/restore_success",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,13 @@ internal class MockSynchronizer : CloseableSynchronizer {
error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} yet.")
}

override suspend fun proposeFulfillingPaymentUri(
account: Account,
uri: String
): Proposal {
error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} yet.")
}

override suspend fun quickRewind() {
error("Intentionally not implemented in ${MockSynchronizer::class.simpleName} implementation.")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class FileShareUtilTest {
context = getAppContext(),
dataFilePath = tempFilePath.pathString,
fileType = FileShareUtil.ZASHI_INTERNAL_DATA_MIME_TYPE,
shareText = null,
sharePickerText = "Test Picker Title",
versionInfo = VersionInfoFixture.new()
)
assertEquals(intent.action, Intent.ACTION_VIEW)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
import co.electriccoin.zcash.ui.common.model.VersionInfo
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.fixture.VersionInfoFixture
import co.electriccoin.zcash.ui.screen.receive.model.ReceiveState
import kotlinx.coroutines.runBlocking
import java.util.concurrent.atomic.AtomicInteger

class ReceiveViewTestSetup(
Expand All @@ -31,17 +33,20 @@ class ReceiveViewTestSetup(
composeTestRule.setContent {
ZcashTheme {
ZcashTheme {
Receive(
walletAddresses = walletAddresses,
ReceiveView(
state =
ReceiveState.Prepared(
walletAddresses = runBlocking { walletAddresses },
isTestnet = versionInfo.isTestnet,
onAddressCopy = {},
onQrCode = {},
onSettings = {
onSettingsCount.getAndIncrement()
},
onRequest = {},
),
snackbarHostState = SnackbarHostState(),
onSettings = {
onSettingsCount.getAndIncrement()
},
onAddrCopyToClipboard = {},
onQrCode = {},
onRequest = {},
topAppBarSubTitleState = TopAppBarSubTitleState.None,
versionInfo = versionInfo,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package co.electriccoin.zcash.di

import co.electriccoin.zcash.ui.common.usecase.CopyToClipboardUseCase
import co.electriccoin.zcash.ui.common.usecase.DeleteContactUseCase
import co.electriccoin.zcash.ui.common.usecase.GetAddressesUseCase
import co.electriccoin.zcash.ui.common.usecase.GetContactUseCase
import co.electriccoin.zcash.ui.common.usecase.GetPersistableWalletUseCase
import co.electriccoin.zcash.ui.common.usecase.GetSelectedEndpointUseCase
Expand Down Expand Up @@ -43,4 +45,6 @@ val useCaseModule =
singleOf(::UpdateContactUseCase)
singleOf(::DeleteContactUseCase)
singleOf(::GetContactUseCase)
singleOf(::GetAddressesUseCase)
singleOf(::CopyToClipboardUseCase)
}
Loading

0 comments on commit c6257d8

Please sign in to comment.