[#1145] Receive screen
- Closes #1145 - Closes #1057 - Closes #1088 - Closes #1154 - Closes #1155 - Closes #1185
This commit is contained in:
parent
a276cb41e0
commit
6519df7539
|
@ -29,7 +29,7 @@
|
||||||
tools:targetApi="29" />
|
tools:targetApi="29" />
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="co.electriccoin.zcash.ui.screen.exportdata.util.ShareFileProvider"
|
android:name="co.electriccoin.zcash.global.ShareFileProvider"
|
||||||
android:authorities="co.electriccoin.zcash.provider"
|
android:authorities="co.electriccoin.zcash.provider"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:grantUriPermissions="true">
|
android:grantUriPermissions="true">
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="co.electriccoin.zcash.ui.screen.exportdata.util.ShareFileProvider"
|
android:name="co.electriccoin.zcash.global.ShareFileProvider"
|
||||||
android:authorities="co.electriccoin.zcash.debug.provider"
|
android:authorities="co.electriccoin.zcash.debug.provider"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:grantUriPermissions="true"
|
android:grantUriPermissions="true"
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="co.electriccoin.zcash.ui.screen.exportdata.util.ShareFileProvider"
|
android:name="co.electriccoin.zcash.global.ShareFileProvider"
|
||||||
android:authorities="co.electriccoin.zcash.provider.testnet"
|
android:authorities="co.electriccoin.zcash.provider.testnet"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:grantUriPermissions="true"
|
android:grantUriPermissions="true"
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="co.electriccoin.zcash.ui.screen.exportdata.util.ShareFileProvider"
|
android:name="co.electriccoin.zcash.global.ShareFileProvider"
|
||||||
android:authorities="co.electriccoin.zcash.debug.provider.testnet"
|
android:authorities="co.electriccoin.zcash.debug.provider.testnet"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:grantUriPermissions="true"
|
android:grantUriPermissions="true"
|
||||||
|
|
|
@ -188,7 +188,7 @@ ZCASH_BIP39_VERSION=1.0.7
|
||||||
ZXING_VERSION=3.5.2
|
ZXING_VERSION=3.5.2
|
||||||
|
|
||||||
# WARNING: Ensure a non-snapshot version is used before releasing to production.
|
# WARNING: Ensure a non-snapshot version is used before releasing to production.
|
||||||
ZCASH_SDK_VERSION=2.0.4-SNAPSHOT
|
ZCASH_SDK_VERSION=2.0.4
|
||||||
|
|
||||||
# Toolchain is the Java version used to build the application, which is separate from the
|
# Toolchain is the Java version used to build the application, which is separate from the
|
||||||
# Java version used to run the application.
|
# Java version used to run the application.
|
||||||
|
|
|
@ -3,10 +3,20 @@
|
||||||
package co.electriccoin.zcash.spackle
|
package co.electriccoin.zcash.spackle
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import co.electriccoin.zcash.spackle.io.mkdirsSuspend
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
// TODO [#1182]: Cover ContextExt with tests
|
||||||
|
// TODO [#1182]: https://github.com/Electric-Coin-Company/zashi-android/issues/1182
|
||||||
|
|
||||||
suspend fun Context.getExternalFilesDirSuspend(type: String?) =
|
suspend fun Context.getExternalFilesDirSuspend(type: String?) =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
getExternalFilesDir(type)
|
getExternalFilesDir(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun Context.getInternalCacheDirSuspend(subDirectory: String?): File =
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
(subDirectory?.let { File(cacheDir, subDirectory) } ?: cacheDir).apply { mkdirsSuspend() }
|
||||||
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ suspend fun File.renameToSuspend(destination: File) =
|
||||||
renameTo(destination)
|
renameTo(destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun File.listFilesSuspend() =
|
suspend fun File.listFilesSuspend(): Array<out File>? =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
listFiles()
|
listFiles()
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,25 +5,47 @@ package co.electriccoin.zcash.ui.design.component
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.basicMarquee
|
import androidx.compose.foundation.basicMarquee
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
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.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.wrapContentSize
|
import androidx.compose.foundation.layout.wrapContentSize
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.AccountBox
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextDecoration
|
import androidx.compose.ui.text.style.TextDecoration
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import co.electriccoin.zcash.ui.design.R
|
import co.electriccoin.zcash.ui.design.R
|
||||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun TextComposablePreview() {
|
||||||
|
ZcashTheme(forceDarkMode = false) {
|
||||||
|
GradientSurface {
|
||||||
|
Column {
|
||||||
|
Reference(text = "Test reference text", onClick = {})
|
||||||
|
Reference(text = "User account", imageVector = Icons.Outlined.AccountBox, onClick = {})
|
||||||
|
// Preview the rest of the composable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Header(
|
fun Header(
|
||||||
text: String,
|
text: String,
|
||||||
|
@ -36,7 +58,23 @@ fun Header(
|
||||||
color = color,
|
color = color,
|
||||||
textAlign = textAlign,
|
textAlign = textAlign,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
style = MaterialTheme.typography.headlineLarge,
|
style = ZcashTheme.typography.secondary.headlineLarge,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SubHeader(
|
||||||
|
text: String,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
textAlign: TextAlign = TextAlign.Start,
|
||||||
|
color: Color = ZcashTheme.colors.onBackgroundHeader,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
color = color,
|
||||||
|
textAlign = textAlign,
|
||||||
|
modifier = modifier,
|
||||||
|
style = ZcashTheme.typography.secondary.headlineSmall,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,33 +209,46 @@ fun ListHeader(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
@Composable
|
@Composable
|
||||||
fun Reference(
|
fun Reference(
|
||||||
text: String,
|
text: String,
|
||||||
|
onClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
textAlign: TextAlign = TextAlign.Start,
|
textAlign: TextAlign = TextAlign.Center,
|
||||||
onClick: () -> Unit
|
imageVector: ImageVector? = null,
|
||||||
|
imageContentDescription: String? = null
|
||||||
) {
|
) {
|
||||||
Box(
|
Row(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.wrapContentSize()
|
.wrapContentSize()
|
||||||
.clip(RoundedCornerShape(ZcashTheme.dimens.topAppBarActionRippleCorner))
|
.clip(RoundedCornerShape(ZcashTheme.dimens.topAppBarActionRippleCorner))
|
||||||
.clickable { onClick() }
|
.clickable { onClick() }
|
||||||
.then(modifier)
|
.padding(all = ZcashTheme.dimens.spacingDefault)
|
||||||
|
.then(modifier),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
|
imageVector?.let {
|
||||||
|
Icon(
|
||||||
|
imageVector = imageVector,
|
||||||
|
contentDescription = imageContentDescription
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.padding(ZcashTheme.dimens.spacingTiny))
|
||||||
Text(
|
Text(
|
||||||
text = text,
|
text = text,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
style =
|
style =
|
||||||
MaterialTheme.typography.bodyLarge
|
ZcashTheme.typography.primary.bodyLarge
|
||||||
.merge(
|
.merge(
|
||||||
TextStyle(
|
TextStyle(
|
||||||
color = ZcashTheme.colors.reference,
|
color = ZcashTheme.colors.reference,
|
||||||
textAlign = textAlign,
|
textAlign = textAlign,
|
||||||
textDecoration = TextDecoration.Underline
|
textDecoration = TextDecoration.Underline,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
)
|
||||||
)
|
)
|
||||||
),
|
|
||||||
modifier = Modifier.padding(all = ZcashTheme.dimens.spacingDefault)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,7 +271,10 @@ fun HeaderWithZecIcon(
|
||||||
style = ZcashTheme.extendedTypography.zecBalance,
|
style = ZcashTheme.extendedTypography.zecBalance,
|
||||||
color = MaterialTheme.colorScheme.onBackground,
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
modifier = Modifier.basicMarquee().then(modifier)
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.basicMarquee()
|
||||||
|
.then(modifier)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,13 +19,10 @@ data class ExtendedColors(
|
||||||
val progressBackground: Color,
|
val progressBackground: Color,
|
||||||
val chipIndex: Color,
|
val chipIndex: Color,
|
||||||
val textFieldHint: Color,
|
val textFieldHint: Color,
|
||||||
|
val textDescription: Color,
|
||||||
val layoutStroke: Color,
|
val layoutStroke: Color,
|
||||||
val overlay: Color,
|
val overlay: Color,
|
||||||
val highlight: Color,
|
val highlight: Color,
|
||||||
val addressHighlightBorder: Color,
|
|
||||||
val addressHighlightUnified: Color,
|
|
||||||
val addressHighlightSapling: Color,
|
|
||||||
val addressHighlightTransparent: Color,
|
|
||||||
val dangerous: Color,
|
val dangerous: Color,
|
||||||
val onDangerous: Color,
|
val onDangerous: Color,
|
||||||
val reference: Color,
|
val reference: Color,
|
||||||
|
|
|
@ -27,6 +27,8 @@ internal object Dark {
|
||||||
val textCaption = Color(0xFFFFFFFF)
|
val textCaption = Color(0xFFFFFFFF)
|
||||||
val textChipIndex = Color(0xFFFFB900)
|
val textChipIndex = Color(0xFFFFB900)
|
||||||
val textFieldHint = Color(0xFFB7B7B7)
|
val textFieldHint = Color(0xFFB7B7B7)
|
||||||
|
val textDescription = Color(0xFF777777)
|
||||||
|
|
||||||
val layoutStroke = Color(0xFFFFFFFF)
|
val layoutStroke = Color(0xFFFFFFFF)
|
||||||
|
|
||||||
val primaryButton = Color(0xFFFFFFFF)
|
val primaryButton = Color(0xFFFFFFFF)
|
||||||
|
@ -90,10 +92,10 @@ internal object Light {
|
||||||
val textCaption = Color(0xFF000000)
|
val textCaption = Color(0xFF000000)
|
||||||
val textChipIndex = Color(0xFFEE8592)
|
val textChipIndex = Color(0xFFEE8592)
|
||||||
val textFieldHint = Color(0xFFB7B7B7)
|
val textFieldHint = Color(0xFFB7B7B7)
|
||||||
|
val textDescription = Color(0xFF777777)
|
||||||
|
|
||||||
val layoutStroke = Color(0xFF000000)
|
val layoutStroke = Color(0xFF000000)
|
||||||
|
|
||||||
// TODO [#159]: The button colors are wrong for light
|
|
||||||
// TODO [#159]: https://github.com/Electric-Coin-Company/zashi-android/issues/159
|
|
||||||
val primaryButton = Color(0xFF000000)
|
val primaryButton = Color(0xFF000000)
|
||||||
val primaryButtonPressed = Color(0xFF000000)
|
val primaryButtonPressed = Color(0xFF000000)
|
||||||
val primaryButtonDisabled = Color(0xFF000000)
|
val primaryButtonDisabled = Color(0xFF000000)
|
||||||
|
@ -118,13 +120,6 @@ internal object Light {
|
||||||
val overlay = Color(0x22000000)
|
val overlay = Color(0x22000000)
|
||||||
val highlight = Color(0xFFFFD800)
|
val highlight = Color(0xFFFFD800)
|
||||||
|
|
||||||
// TODO [#159]: The colors are wrong for light theme
|
|
||||||
// TODO [#159]: https://github.com/Electric-Coin-Company/zashi-android/issues/159
|
|
||||||
val addressHighlightBorder = Color(0xFF525252)
|
|
||||||
val addressHighlightUnified = Color(0xFFFFD800)
|
|
||||||
val addressHighlightSapling = Color(0xFF1BBFF6)
|
|
||||||
val addressHighlightTransparent = Color(0xFF97999A)
|
|
||||||
|
|
||||||
val dangerous = Color(0xFFEC0008)
|
val dangerous = Color(0xFFEC0008)
|
||||||
val onDangerous = Color(0xFFFFFFFF)
|
val onDangerous = Color(0xFFFFFFFF)
|
||||||
|
|
||||||
|
@ -179,13 +174,10 @@ internal val DarkExtendedColorPalette =
|
||||||
progressBackground = Dark.progressBackground,
|
progressBackground = Dark.progressBackground,
|
||||||
chipIndex = Dark.textChipIndex,
|
chipIndex = Dark.textChipIndex,
|
||||||
textFieldHint = Dark.textFieldHint,
|
textFieldHint = Dark.textFieldHint,
|
||||||
|
textDescription = Dark.textDescription,
|
||||||
layoutStroke = Dark.layoutStroke,
|
layoutStroke = Dark.layoutStroke,
|
||||||
overlay = Dark.overlay,
|
overlay = Dark.overlay,
|
||||||
highlight = Dark.highlight,
|
highlight = Dark.highlight,
|
||||||
addressHighlightBorder = Dark.addressHighlightBorder,
|
|
||||||
addressHighlightUnified = Dark.addressHighlightUnified,
|
|
||||||
addressHighlightSapling = Dark.addressHighlightSapling,
|
|
||||||
addressHighlightTransparent = Dark.addressHighlightTransparent,
|
|
||||||
dangerous = Dark.dangerous,
|
dangerous = Dark.dangerous,
|
||||||
onDangerous = Dark.onDangerous,
|
onDangerous = Dark.onDangerous,
|
||||||
disabledButtonTextColor = Dark.disabledButtonTextColor,
|
disabledButtonTextColor = Dark.disabledButtonTextColor,
|
||||||
|
@ -213,13 +205,10 @@ internal val LightExtendedColorPalette =
|
||||||
progressBackground = Light.progressBackground,
|
progressBackground = Light.progressBackground,
|
||||||
chipIndex = Light.textChipIndex,
|
chipIndex = Light.textChipIndex,
|
||||||
textFieldHint = Light.textFieldHint,
|
textFieldHint = Light.textFieldHint,
|
||||||
|
textDescription = Light.textDescription,
|
||||||
layoutStroke = Light.layoutStroke,
|
layoutStroke = Light.layoutStroke,
|
||||||
overlay = Light.overlay,
|
overlay = Light.overlay,
|
||||||
highlight = Light.highlight,
|
highlight = Light.highlight,
|
||||||
addressHighlightBorder = Light.addressHighlightBorder,
|
|
||||||
addressHighlightUnified = Light.addressHighlightUnified,
|
|
||||||
addressHighlightSapling = Light.addressHighlightSapling,
|
|
||||||
addressHighlightTransparent = Light.addressHighlightTransparent,
|
|
||||||
dangerous = Light.dangerous,
|
dangerous = Light.dangerous,
|
||||||
onDangerous = Light.onDangerous,
|
onDangerous = Light.onDangerous,
|
||||||
disabledButtonTextColor = Light.disabledButtonTextColor,
|
disabledButtonTextColor = Light.disabledButtonTextColor,
|
||||||
|
@ -249,13 +238,10 @@ internal val LocalExtendedColors =
|
||||||
progressBackground = Color.Unspecified,
|
progressBackground = Color.Unspecified,
|
||||||
chipIndex = Color.Unspecified,
|
chipIndex = Color.Unspecified,
|
||||||
textFieldHint = Color.Unspecified,
|
textFieldHint = Color.Unspecified,
|
||||||
|
textDescription = Color.Unspecified,
|
||||||
layoutStroke = Color.Unspecified,
|
layoutStroke = Color.Unspecified,
|
||||||
overlay = Color.Unspecified,
|
overlay = Color.Unspecified,
|
||||||
highlight = Color.Unspecified,
|
highlight = Color.Unspecified,
|
||||||
addressHighlightBorder = Color.Unspecified,
|
|
||||||
addressHighlightUnified = Color.Unspecified,
|
|
||||||
addressHighlightSapling = Color.Unspecified,
|
|
||||||
addressHighlightTransparent = Color.Unspecified,
|
|
||||||
dangerous = Color.Unspecified,
|
dangerous = Color.Unspecified,
|
||||||
onDangerous = Color.Unspecified,
|
onDangerous = Color.Unspecified,
|
||||||
disabledButtonTextColor = Color.Unspecified,
|
disabledButtonTextColor = Color.Unspecified,
|
||||||
|
|
|
@ -107,7 +107,7 @@ internal val SecondaryTypography =
|
||||||
headlineSmall =
|
headlineSmall =
|
||||||
TextStyle(
|
TextStyle(
|
||||||
fontFamily = ArchivoFontFamily,
|
fontFamily = ArchivoFontFamily,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.SemiBold,
|
||||||
fontSize = 20.sp,
|
fontSize = 20.sp,
|
||||||
textAlign = TextAlign.Center
|
textAlign = TextAlign.Center
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,185 +0,0 @@
|
||||||
package co.electriccoin.zcash.ui.screen.address.view
|
|
||||||
|
|
||||||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
|
||||||
import androidx.compose.ui.test.junit4.createComposeRule
|
|
||||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
|
||||||
import androidx.compose.ui.test.onNodeWithTag
|
|
||||||
import androidx.compose.ui.test.onNodeWithText
|
|
||||||
import androidx.compose.ui.test.performClick
|
|
||||||
import androidx.test.filters.MediumTest
|
|
||||||
import cash.z.ecc.android.sdk.fixture.WalletAddressesFixture
|
|
||||||
import cash.z.ecc.android.sdk.model.WalletAddresses
|
|
||||||
import co.electriccoin.zcash.test.UiTestPrerequisites
|
|
||||||
import co.electriccoin.zcash.ui.R
|
|
||||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
|
||||||
import co.electriccoin.zcash.ui.screen.address.WalletAddressesTag
|
|
||||||
import co.electriccoin.zcash.ui.test.getStringResource
|
|
||||||
import kotlinx.coroutines.test.runTest
|
|
||||||
import org.junit.Assert.assertEquals
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
|
||||||
|
|
||||||
class WalletAddressViewTest : UiTestPrerequisites() {
|
|
||||||
@get:Rule
|
|
||||||
val composeTestRule = createComposeRule()
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@MediumTest
|
|
||||||
fun initial_screen_setup() =
|
|
||||||
runTest {
|
|
||||||
val walletAddresses = WalletAddressesFixture.new()
|
|
||||||
newTestSetup(walletAddresses)
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithText(getStringResource(R.string.wallet_address_unified)).also {
|
|
||||||
it.assertExists()
|
|
||||||
}
|
|
||||||
composeTestRule.onNodeWithText(getStringResource(R.string.wallet_address_sapling)).also {
|
|
||||||
it.assertExists()
|
|
||||||
}
|
|
||||||
composeTestRule.onNodeWithText(getStringResource(R.string.wallet_address_transparent)).also {
|
|
||||||
it.assertExists()
|
|
||||||
}
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithText(walletAddresses.unified.address).also {
|
|
||||||
it.assertExists()
|
|
||||||
}
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithText(walletAddresses.sapling.address).also {
|
|
||||||
it.assertDoesNotExist()
|
|
||||||
}
|
|
||||||
composeTestRule.onNodeWithText(walletAddresses.transparent.address).also {
|
|
||||||
it.assertDoesNotExist()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@MediumTest
|
|
||||||
fun unified_collapses() =
|
|
||||||
runTest {
|
|
||||||
val walletAddresses = WalletAddressesFixture.new()
|
|
||||||
newTestSetup(walletAddresses)
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithText(walletAddresses.unified.address).also {
|
|
||||||
it.assertExists()
|
|
||||||
}
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithText(getStringResource(R.string.wallet_address_unified)).also {
|
|
||||||
it.assertExists()
|
|
||||||
it.performClick()
|
|
||||||
}
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithText(walletAddresses.unified.address).also {
|
|
||||||
it.assertDoesNotExist()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@MediumTest
|
|
||||||
fun sapling_expands() =
|
|
||||||
runTest {
|
|
||||||
val walletAddresses = WalletAddressesFixture.new()
|
|
||||||
newTestSetup(walletAddresses)
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithText(walletAddresses.sapling.address).also {
|
|
||||||
it.assertDoesNotExist()
|
|
||||||
}
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithText(getStringResource(R.string.wallet_address_sapling)).also {
|
|
||||||
it.assertExists()
|
|
||||||
it.performClick()
|
|
||||||
}
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithText(walletAddresses.sapling.address).also {
|
|
||||||
it.assertExists()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@MediumTest
|
|
||||||
fun transparent_expands() =
|
|
||||||
runTest {
|
|
||||||
val walletAddresses = WalletAddressesFixture.new()
|
|
||||||
newTestSetup(walletAddresses)
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithText(walletAddresses.transparent.address).also {
|
|
||||||
it.assertDoesNotExist()
|
|
||||||
}
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithText(getStringResource(R.string.wallet_address_transparent)).also {
|
|
||||||
it.assertExists()
|
|
||||||
it.performClick()
|
|
||||||
}
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithText(walletAddresses.transparent.address).also {
|
|
||||||
it.assertExists()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@MediumTest
|
|
||||||
fun back_clicked() =
|
|
||||||
runTest {
|
|
||||||
val testSetup = newTestSetup(WalletAddressesFixture.new())
|
|
||||||
|
|
||||||
assertEquals(0, testSetup.getOnBackCount())
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithContentDescription(
|
|
||||||
getStringResource(R.string.wallet_address_back_content_description)
|
|
||||||
).also {
|
|
||||||
it.performClick()
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals(1, testSetup.getOnBackCount())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@MediumTest
|
|
||||||
fun copy_to_clipboard_clicked() =
|
|
||||||
runTest {
|
|
||||||
val testSetup = newTestSetup(WalletAddressesFixture.new())
|
|
||||||
|
|
||||||
assertEquals(0, testSetup.getOnCopyToClipboardCount())
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithTag(
|
|
||||||
WalletAddressesTag.WALLET_ADDRESS
|
|
||||||
).also {
|
|
||||||
it.performClick()
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals(1, testSetup.getOnCopyToClipboardCount())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun newTestSetup(initialState: WalletAddresses) = TestSetup(composeTestRule, initialState)
|
|
||||||
|
|
||||||
private class TestSetup(private val composeTestRule: ComposeContentTestRule, initialState: WalletAddresses) {
|
|
||||||
private val onBackCount = AtomicInteger(0)
|
|
||||||
private val onCopyToClipboardCount = AtomicInteger(0)
|
|
||||||
|
|
||||||
fun getOnBackCount(): Int {
|
|
||||||
composeTestRule.waitForIdle()
|
|
||||||
return onBackCount.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getOnCopyToClipboardCount(): Int {
|
|
||||||
composeTestRule.waitForIdle()
|
|
||||||
return onCopyToClipboardCount.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
composeTestRule.setContent {
|
|
||||||
ZcashTheme {
|
|
||||||
WalletAddresses(
|
|
||||||
walletAddresses = initialState,
|
|
||||||
onCopyToClipboard = {
|
|
||||||
onCopyToClipboardCount.incrementAndGet()
|
|
||||||
},
|
|
||||||
onBack = {
|
|
||||||
onBackCount.incrementAndGet()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,6 +4,7 @@ import android.content.Intent
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import co.electriccoin.zcash.ui.fixture.VersionInfoFixture
|
import co.electriccoin.zcash.ui.fixture.VersionInfoFixture
|
||||||
import co.electriccoin.zcash.ui.test.getAppContext
|
import co.electriccoin.zcash.ui.test.getAppContext
|
||||||
|
import co.electriccoin.zcash.ui.util.FileShareUtil
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.io.path.pathString
|
import kotlin.io.path.pathString
|
||||||
|
@ -26,6 +27,7 @@ class FileShareUtilTest {
|
||||||
FileShareUtil.newShareContentIntent(
|
FileShareUtil.newShareContentIntent(
|
||||||
context = getAppContext(),
|
context = getAppContext(),
|
||||||
dataFilePath = tempFilePath.pathString,
|
dataFilePath = tempFilePath.pathString,
|
||||||
|
fileType = FileShareUtil.ZASHI_INTERNAL_DATA_MIME_TYPE,
|
||||||
versionInfo = VersionInfoFixture.new()
|
versionInfo = VersionInfoFixture.new()
|
||||||
)
|
)
|
||||||
assertEquals(intent.action, Intent.ACTION_VIEW)
|
assertEquals(intent.action, Intent.ACTION_VIEW)
|
||||||
|
|
|
@ -2,9 +2,11 @@ package co.electriccoin.zcash.ui.screen.receive.view
|
||||||
|
|
||||||
import androidx.compose.ui.test.junit4.createComposeRule
|
import androidx.compose.ui.test.junit4.createComposeRule
|
||||||
import androidx.test.filters.MediumTest
|
import androidx.test.filters.MediumTest
|
||||||
import cash.z.ecc.android.sdk.fixture.WalletAddressFixture
|
import cash.z.ecc.android.sdk.fixture.WalletAddressesFixture
|
||||||
import cash.z.ecc.android.sdk.model.WalletAddress
|
import cash.z.ecc.android.sdk.model.WalletAddresses
|
||||||
import co.electriccoin.zcash.test.UiTestPrerequisites
|
import co.electriccoin.zcash.test.UiTestPrerequisites
|
||||||
|
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||||
|
import co.electriccoin.zcash.ui.fixture.VersionInfoFixture
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
@ -18,7 +20,12 @@ class ReceiveViewScreenBrightnessTest : UiTestPrerequisites() {
|
||||||
@MediumTest
|
@MediumTest
|
||||||
fun testBrightnessDefaultState() =
|
fun testBrightnessDefaultState() =
|
||||||
runTest {
|
runTest {
|
||||||
val testSetup = newTestSetup(WalletAddressFixture.unified())
|
// Using isDebuggable flag to have brightness toggle in the UI
|
||||||
|
val testSetup =
|
||||||
|
newTestSetup(
|
||||||
|
WalletAddressesFixture.new(),
|
||||||
|
VersionInfoFixture.new(isDebuggable = true)
|
||||||
|
)
|
||||||
|
|
||||||
assertEquals(0, testSetup.getScreenBrightnessCount())
|
assertEquals(0, testSetup.getScreenBrightnessCount())
|
||||||
}
|
}
|
||||||
|
@ -27,7 +34,12 @@ class ReceiveViewScreenBrightnessTest : UiTestPrerequisites() {
|
||||||
@MediumTest
|
@MediumTest
|
||||||
fun testBrightnessOnState() =
|
fun testBrightnessOnState() =
|
||||||
runTest {
|
runTest {
|
||||||
val testSetup = newTestSetup(WalletAddressFixture.unified())
|
// Using isDebuggable flag to have brightness toggle in the UI
|
||||||
|
val testSetup =
|
||||||
|
newTestSetup(
|
||||||
|
WalletAddressesFixture.new(),
|
||||||
|
VersionInfoFixture.new(isDebuggable = true)
|
||||||
|
)
|
||||||
|
|
||||||
assertEquals(false, testSetup.getOnAdjustBrightness())
|
assertEquals(false, testSetup.getOnAdjustBrightness())
|
||||||
assertEquals(0, testSetup.getScreenBrightnessCount())
|
assertEquals(0, testSetup.getScreenBrightnessCount())
|
||||||
|
@ -38,5 +50,8 @@ class ReceiveViewScreenBrightnessTest : UiTestPrerequisites() {
|
||||||
assertEquals(1, testSetup.getScreenBrightnessCount())
|
assertEquals(1, testSetup.getScreenBrightnessCount())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun newTestSetup(walletAddress: WalletAddress) = ReceiveViewTestSetup(composeTestRule, walletAddress)
|
private fun newTestSetup(
|
||||||
|
walletAddresses: WalletAddresses,
|
||||||
|
versionInfo: VersionInfo
|
||||||
|
) = ReceiveViewTestSetup(composeTestRule, walletAddresses, versionInfo)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,11 @@ package co.electriccoin.zcash.ui.screen.receive.view
|
||||||
|
|
||||||
import androidx.compose.ui.test.junit4.createComposeRule
|
import androidx.compose.ui.test.junit4.createComposeRule
|
||||||
import androidx.test.filters.MediumTest
|
import androidx.test.filters.MediumTest
|
||||||
import cash.z.ecc.android.sdk.fixture.WalletAddressFixture
|
import cash.z.ecc.android.sdk.fixture.WalletAddressesFixture
|
||||||
import cash.z.ecc.android.sdk.model.WalletAddress
|
import cash.z.ecc.android.sdk.model.WalletAddresses
|
||||||
import co.electriccoin.zcash.test.UiTestPrerequisites
|
import co.electriccoin.zcash.test.UiTestPrerequisites
|
||||||
|
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||||
|
import co.electriccoin.zcash.ui.fixture.VersionInfoFixture
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
@ -18,7 +20,11 @@ class ReceiveViewScreenTimeoutTest : UiTestPrerequisites() {
|
||||||
@MediumTest
|
@MediumTest
|
||||||
fun testTimeoutDefaultState() =
|
fun testTimeoutDefaultState() =
|
||||||
runTest {
|
runTest {
|
||||||
val testSetup = newTestSetup(WalletAddressFixture.unified())
|
val testSetup =
|
||||||
|
newTestSetup(
|
||||||
|
WalletAddressesFixture.new(),
|
||||||
|
VersionInfoFixture.new()
|
||||||
|
)
|
||||||
|
|
||||||
assertEquals(0, testSetup.getScreenTimeoutCount())
|
assertEquals(0, testSetup.getScreenTimeoutCount())
|
||||||
}
|
}
|
||||||
|
@ -27,7 +33,12 @@ class ReceiveViewScreenTimeoutTest : UiTestPrerequisites() {
|
||||||
@MediumTest
|
@MediumTest
|
||||||
fun testTimeoutOnState() =
|
fun testTimeoutOnState() =
|
||||||
runTest {
|
runTest {
|
||||||
val testSetup = newTestSetup(WalletAddressFixture.unified())
|
// Using isDebuggable flag to have brightness toggle in the UI
|
||||||
|
val testSetup =
|
||||||
|
newTestSetup(
|
||||||
|
WalletAddressesFixture.new(),
|
||||||
|
VersionInfoFixture.new(isDebuggable = true)
|
||||||
|
)
|
||||||
|
|
||||||
assertEquals(false, testSetup.getOnAdjustBrightness())
|
assertEquals(false, testSetup.getOnAdjustBrightness())
|
||||||
assertEquals(0, testSetup.getScreenTimeoutCount())
|
assertEquals(0, testSetup.getScreenTimeoutCount())
|
||||||
|
@ -38,5 +49,8 @@ class ReceiveViewScreenTimeoutTest : UiTestPrerequisites() {
|
||||||
assertEquals(1, testSetup.getScreenTimeoutCount())
|
assertEquals(1, testSetup.getScreenTimeoutCount())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun newTestSetup(walletAddress: WalletAddress) = ReceiveViewTestSetup(composeTestRule, walletAddress)
|
private fun newTestSetup(
|
||||||
|
walletAddresses: WalletAddresses,
|
||||||
|
versionInfo: VersionInfo
|
||||||
|
) = ReceiveViewTestSetup(composeTestRule, walletAddresses, versionInfo)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@ import androidx.compose.ui.test.onNodeWithContentDescription
|
||||||
import androidx.compose.ui.test.onNodeWithText
|
import androidx.compose.ui.test.onNodeWithText
|
||||||
import androidx.compose.ui.test.performClick
|
import androidx.compose.ui.test.performClick
|
||||||
import androidx.test.filters.MediumTest
|
import androidx.test.filters.MediumTest
|
||||||
import cash.z.ecc.android.sdk.fixture.WalletAddressFixture
|
import cash.z.ecc.android.sdk.fixture.WalletAddressesFixture
|
||||||
import cash.z.ecc.android.sdk.model.WalletAddress
|
import cash.z.ecc.android.sdk.model.WalletAddresses
|
||||||
import co.electriccoin.zcash.ui.R
|
import co.electriccoin.zcash.ui.R
|
||||||
import co.electriccoin.zcash.ui.test.getStringResource
|
import co.electriccoin.zcash.ui.test.getStringResource
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
|
@ -14,6 +14,9 @@ import org.junit.Assert.assertEquals
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
|
// TODO [#1184]: Improve ReceiveScreen UI tests
|
||||||
|
// TODO [#1184]: https://github.com/Electric-Coin-Company/zashi-android/issues/1184
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: It is difficult to test the QR code from automated tests. There is a manual test case
|
* Note: It is difficult to test the QR code from automated tests. There is a manual test case
|
||||||
* for that currently. A future enhancement could take a screenshot and try to analyze the
|
* for that currently. A future enhancement could take a screenshot and try to analyze the
|
||||||
|
@ -27,11 +30,11 @@ class ReceiveViewTest {
|
||||||
@MediumTest
|
@MediumTest
|
||||||
fun setup() =
|
fun setup() =
|
||||||
runTest {
|
runTest {
|
||||||
val walletAddress = WalletAddressFixture.unified()
|
val walletAddresses = WalletAddressesFixture.new()
|
||||||
newTestSetup(walletAddress)
|
newTestSetup(walletAddresses)
|
||||||
|
|
||||||
// Enable substring for ellipsizing
|
// Enable substring for ellipsizing
|
||||||
composeTestRule.onNodeWithText(walletAddress.address, substring = true).also {
|
composeTestRule.onNodeWithText(walletAddresses.unified.address, substring = true).also {
|
||||||
it.assertExists()
|
it.assertExists()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +43,7 @@ class ReceiveViewTest {
|
||||||
@MediumTest
|
@MediumTest
|
||||||
fun click_settings_test() =
|
fun click_settings_test() =
|
||||||
runTest {
|
runTest {
|
||||||
val testSetup = newTestSetup(WalletAddressFixture.unified())
|
val testSetup = newTestSetup(WalletAddressesFixture.new())
|
||||||
|
|
||||||
assertEquals(0, testSetup.getOnSettingsCount())
|
assertEquals(0, testSetup.getOnSettingsCount())
|
||||||
|
|
||||||
|
@ -53,23 +56,5 @@ class ReceiveViewTest {
|
||||||
assertEquals(1, testSetup.getOnSettingsCount())
|
assertEquals(1, testSetup.getOnSettingsCount())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private fun newTestSetup(walletAddresses: WalletAddresses) = ReceiveViewTestSetup(composeTestRule, walletAddresses)
|
||||||
@MediumTest
|
|
||||||
fun address_details() =
|
|
||||||
runTest {
|
|
||||||
val testSetup = newTestSetup(WalletAddressFixture.unified())
|
|
||||||
|
|
||||||
assertEquals(0, testSetup.getOnAddressDetailsCount())
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithText(
|
|
||||||
text = getStringResource(R.string.receive_see_address_details),
|
|
||||||
ignoreCase = true
|
|
||||||
).also {
|
|
||||||
it.performClick()
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals(1, testSetup.getOnAddressDetailsCount())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun newTestSetup(walletAddress: WalletAddress) = ReceiveViewTestSetup(composeTestRule, walletAddress)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,27 @@
|
||||||
package co.electriccoin.zcash.ui.screen.receive.view
|
package co.electriccoin.zcash.ui.screen.receive.view
|
||||||
|
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||||
import androidx.compose.ui.test.performClick
|
import androidx.compose.ui.test.performClick
|
||||||
import cash.z.ecc.android.sdk.model.WalletAddress
|
import cash.z.ecc.android.sdk.model.WalletAddresses
|
||||||
import co.electriccoin.zcash.ui.R
|
import co.electriccoin.zcash.ui.R
|
||||||
import co.electriccoin.zcash.ui.common.LocalScreenBrightness
|
import co.electriccoin.zcash.ui.common.LocalScreenBrightness
|
||||||
import co.electriccoin.zcash.ui.common.LocalScreenTimeout
|
import co.electriccoin.zcash.ui.common.LocalScreenTimeout
|
||||||
import co.electriccoin.zcash.ui.common.ScreenBrightness
|
import co.electriccoin.zcash.ui.common.ScreenBrightness
|
||||||
import co.electriccoin.zcash.ui.common.ScreenTimeout
|
import co.electriccoin.zcash.ui.common.ScreenTimeout
|
||||||
|
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
|
import co.electriccoin.zcash.ui.fixture.VersionInfoFixture
|
||||||
import co.electriccoin.zcash.ui.test.getStringResource
|
import co.electriccoin.zcash.ui.test.getStringResource
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
class ReceiveViewTestSetup(
|
class ReceiveViewTestSetup(
|
||||||
private val composeTestRule: ComposeContentTestRule,
|
private val composeTestRule: ComposeContentTestRule,
|
||||||
walletAddress: WalletAddress
|
walletAddresses: WalletAddresses,
|
||||||
|
versionInfo: VersionInfo = VersionInfoFixture.new()
|
||||||
) {
|
) {
|
||||||
private val onSettingsCount = AtomicInteger(0)
|
private val onSettingsCount = AtomicInteger(0)
|
||||||
private val onAddressDetailsCount = AtomicInteger(0)
|
private val onAddressDetailsCount = AtomicInteger(0)
|
||||||
|
@ -53,16 +57,17 @@ class ReceiveViewTestSetup(
|
||||||
ZcashTheme {
|
ZcashTheme {
|
||||||
ZcashTheme {
|
ZcashTheme {
|
||||||
Receive(
|
Receive(
|
||||||
walletAddress,
|
walletAddress = walletAddresses,
|
||||||
|
snackbarHostState = SnackbarHostState(),
|
||||||
onSettings = {
|
onSettings = {
|
||||||
onSettingsCount.getAndIncrement()
|
onSettingsCount.getAndIncrement()
|
||||||
},
|
},
|
||||||
onAddressDetails = {
|
|
||||||
onAddressDetailsCount.getAndIncrement()
|
|
||||||
},
|
|
||||||
onAdjustBrightness = {
|
onAdjustBrightness = {
|
||||||
onAdjustBrightness.getAndSet(it)
|
onAdjustBrightness.getAndSet(it)
|
||||||
},
|
},
|
||||||
|
onAddrCopyToClipboard = {},
|
||||||
|
onQrImageShare = {},
|
||||||
|
versionInfo = versionInfo
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package co.electriccoin.zcash.ui.screen.exportdata.util
|
package co.electriccoin.zcash.global
|
||||||
|
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import co.electriccoin.zcash.ui.R
|
import co.electriccoin.zcash.ui.R
|
|
@ -20,11 +20,9 @@ import co.electriccoin.zcash.ui.NavigationTargets.SCAN
|
||||||
import co.electriccoin.zcash.ui.NavigationTargets.SEED_RECOVERY
|
import co.electriccoin.zcash.ui.NavigationTargets.SEED_RECOVERY
|
||||||
import co.electriccoin.zcash.ui.NavigationTargets.SETTINGS
|
import co.electriccoin.zcash.ui.NavigationTargets.SETTINGS
|
||||||
import co.electriccoin.zcash.ui.NavigationTargets.SUPPORT
|
import co.electriccoin.zcash.ui.NavigationTargets.SUPPORT
|
||||||
import co.electriccoin.zcash.ui.NavigationTargets.WALLET_ADDRESS_DETAILS
|
|
||||||
import co.electriccoin.zcash.ui.configuration.ConfigurationEntries
|
import co.electriccoin.zcash.ui.configuration.ConfigurationEntries
|
||||||
import co.electriccoin.zcash.ui.configuration.RemoteConfig
|
import co.electriccoin.zcash.ui.configuration.RemoteConfig
|
||||||
import co.electriccoin.zcash.ui.screen.about.WrapAbout
|
import co.electriccoin.zcash.ui.screen.about.WrapAbout
|
||||||
import co.electriccoin.zcash.ui.screen.address.WrapWalletAddresses
|
|
||||||
import co.electriccoin.zcash.ui.screen.exportdata.WrapExportPrivateData
|
import co.electriccoin.zcash.ui.screen.exportdata.WrapExportPrivateData
|
||||||
import co.electriccoin.zcash.ui.screen.history.WrapHistory
|
import co.electriccoin.zcash.ui.screen.history.WrapHistory
|
||||||
import co.electriccoin.zcash.ui.screen.home.WrapHome
|
import co.electriccoin.zcash.ui.screen.home.WrapHome
|
||||||
|
@ -51,7 +49,6 @@ internal fun MainActivity.Navigation() {
|
||||||
onPageChange = {
|
onPageChange = {
|
||||||
homeViewModel.screenIndex.value = it
|
homeViewModel.screenIndex.value = it
|
||||||
},
|
},
|
||||||
goAddressDetails = { navController.navigateJustOnce(WALLET_ADDRESS_DETAILS) },
|
|
||||||
goBack = { finish() },
|
goBack = { finish() },
|
||||||
goHistory = { navController.navigateJustOnce(HISTORY) },
|
goHistory = { navController.navigateJustOnce(HISTORY) },
|
||||||
goSettings = { navController.navigateJustOnce(SETTINGS) },
|
goSettings = { navController.navigateJustOnce(SETTINGS) },
|
||||||
|
@ -72,13 +69,6 @@ internal fun MainActivity.Navigation() {
|
||||||
WrapCheckForUpdate()
|
WrapCheckForUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
composable(WALLET_ADDRESS_DETAILS) {
|
|
||||||
WrapWalletAddresses(
|
|
||||||
goBack = {
|
|
||||||
navController.popBackStackJustOnce(WALLET_ADDRESS_DETAILS)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
composable(SETTINGS) {
|
composable(SETTINGS) {
|
||||||
WrapSettings(
|
WrapSettings(
|
||||||
goAbout = {
|
goAbout = {
|
||||||
|
@ -201,5 +191,4 @@ object NavigationTargets {
|
||||||
const val SEND = "send"
|
const val SEND = "send"
|
||||||
const val SETTINGS = "settings"
|
const val SETTINGS = "settings"
|
||||||
const val SUPPORT = "support"
|
const val SUPPORT = "support"
|
||||||
const val WALLET_ADDRESS_DETAILS = "wallet_address_details"
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
@file:Suppress("ktlint:standard:filename")
|
|
||||||
|
|
||||||
package co.electriccoin.zcash.ui.screen.address
|
|
||||||
|
|
||||||
import androidx.activity.ComponentActivity
|
|
||||||
import androidx.activity.viewModels
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|
||||||
import co.electriccoin.zcash.spackle.ClipboardManagerUtil
|
|
||||||
import co.electriccoin.zcash.ui.MainActivity
|
|
||||||
import co.electriccoin.zcash.ui.R
|
|
||||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
|
||||||
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
|
|
||||||
import co.electriccoin.zcash.ui.screen.address.view.WalletAddresses
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
internal fun MainActivity.WrapWalletAddresses(goBack: () -> Unit) {
|
|
||||||
WrapWalletAddresses(this, goBack)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun WrapWalletAddresses(
|
|
||||||
activity: ComponentActivity,
|
|
||||||
goBack: () -> Unit
|
|
||||||
) {
|
|
||||||
val walletViewModel by activity.viewModels<WalletViewModel>()
|
|
||||||
|
|
||||||
val walletAddresses = walletViewModel.addresses.collectAsStateWithLifecycle().value
|
|
||||||
|
|
||||||
if (null == walletAddresses) {
|
|
||||||
// TODO [#1146]: Consider moving CircularScreenProgressIndicator from Android layer to View layer
|
|
||||||
// TODO [#1146]: Improve this by allowing screen composition and updating it after the data is available
|
|
||||||
// TODO [#1146]: https://github.com/Electric-Coin-Company/zashi-android/issues/1146
|
|
||||||
CircularScreenProgressIndicator()
|
|
||||||
} else {
|
|
||||||
WalletAddresses(
|
|
||||||
walletAddresses,
|
|
||||||
goBack,
|
|
||||||
onCopyToClipboard = { address ->
|
|
||||||
ClipboardManagerUtil.copyToClipboard(
|
|
||||||
activity.applicationContext,
|
|
||||||
activity.getString(R.string.wallet_address_clipboard_tag),
|
|
||||||
address
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package co.electriccoin.zcash.ui.screen.address
|
|
||||||
|
|
||||||
/**
|
|
||||||
* These are only used for automated testing.
|
|
||||||
*/
|
|
||||||
object WalletAddressesTag {
|
|
||||||
const val WALLET_ADDRESS = "wallet_address_tag"
|
|
||||||
}
|
|
|
@ -1,295 +0,0 @@
|
||||||
@file:Suppress("TooManyFunctions")
|
|
||||||
|
|
||||||
package co.electriccoin.zcash.ui.screen.address.view
|
|
||||||
|
|
||||||
import androidx.compose.foundation.Image
|
|
||||||
import androidx.compose.foundation.border
|
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.IntrinsicSize
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.defaultMinSize
|
|
||||||
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.padding
|
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.foundation.rememberScrollState
|
|
||||||
import androidx.compose.foundation.verticalScroll
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
|
||||||
import androidx.compose.material.icons.filled.ArrowDropDownCircle
|
|
||||||
import androidx.compose.material3.Divider
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TopAppBar
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.rotate
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.graphics.painter.ColorPainter
|
|
||||||
import androidx.compose.ui.platform.testTag
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import cash.z.ecc.android.sdk.fixture.WalletAddressesFixture
|
|
||||||
import cash.z.ecc.android.sdk.model.WalletAddresses
|
|
||||||
import co.electriccoin.zcash.ui.R
|
|
||||||
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
|
|
||||||
import co.electriccoin.zcash.ui.design.component.Body
|
|
||||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
|
||||||
import co.electriccoin.zcash.ui.design.component.ListHeader
|
|
||||||
import co.electriccoin.zcash.ui.design.component.ListItem
|
|
||||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
|
||||||
import co.electriccoin.zcash.ui.screen.address.WalletAddressesTag
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
|
|
||||||
@Preview("WalletAddresses")
|
|
||||||
@Composable
|
|
||||||
private fun ComposablePreview() {
|
|
||||||
ZcashTheme(forceDarkMode = false) {
|
|
||||||
GradientSurface {
|
|
||||||
WalletAddresses(
|
|
||||||
runBlocking { WalletAddressesFixture.new() },
|
|
||||||
onBack = {},
|
|
||||||
onCopyToClipboard = {}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun WalletAddresses(
|
|
||||||
walletAddresses: WalletAddresses,
|
|
||||||
onBack: () -> Unit,
|
|
||||||
onCopyToClipboard: (String) -> Unit
|
|
||||||
) {
|
|
||||||
Column {
|
|
||||||
WalletDetailTopAppBar(onBack)
|
|
||||||
WalletDetailAddresses(
|
|
||||||
walletAddresses = walletAddresses,
|
|
||||||
onCopyToClipboard = onCopyToClipboard,
|
|
||||||
modifier =
|
|
||||||
Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
private fun WalletDetailTopAppBar(onBack: () -> Unit) {
|
|
||||||
TopAppBar(
|
|
||||||
title = {
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.wallet_address_title)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
navigationIcon = {
|
|
||||||
IconButton(
|
|
||||||
onClick = onBack
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Filled.ArrowBack,
|
|
||||||
contentDescription = stringResource(R.string.wallet_address_back_content_description)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val BIG_INDICATOR_WIDTH = 24.dp
|
|
||||||
private val SMALL_INDICATOR_WIDTH = 16.dp
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun WalletDetailAddresses(
|
|
||||||
walletAddresses: WalletAddresses,
|
|
||||||
onCopyToClipboard: (String) -> Unit,
|
|
||||||
modifier: Modifier = Modifier
|
|
||||||
) {
|
|
||||||
Column(modifier) {
|
|
||||||
Row(
|
|
||||||
Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(IntrinsicSize.Min)
|
|
||||||
) {
|
|
||||||
Image(
|
|
||||||
painter = ColorPainter(ZcashTheme.colors.highlight),
|
|
||||||
contentDescription = "",
|
|
||||||
modifier =
|
|
||||||
Modifier
|
|
||||||
.fillMaxHeight()
|
|
||||||
.width(BIG_INDICATOR_WIDTH)
|
|
||||||
)
|
|
||||||
|
|
||||||
Column(Modifier.fillMaxWidth()) {
|
|
||||||
ExpandableRow(
|
|
||||||
title = stringResource(R.string.wallet_address_unified),
|
|
||||||
content = walletAddresses.unified.address,
|
|
||||||
isInitiallyExpanded = true,
|
|
||||||
onCopyToClipboard = onCopyToClipboard
|
|
||||||
)
|
|
||||||
|
|
||||||
Box(Modifier.height(IntrinsicSize.Min)) {
|
|
||||||
Divider(modifier = Modifier.fillMaxHeight())
|
|
||||||
ListHeader(
|
|
||||||
text = stringResource(R.string.wallet_address_header_includes),
|
|
||||||
modifier = Modifier.padding(all = ZcashTheme.dimens.spacingSmall)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
SaplingAddress(
|
|
||||||
saplingAddress = walletAddresses.sapling.address,
|
|
||||||
onCopyToClipboard = onCopyToClipboard,
|
|
||||||
modifier =
|
|
||||||
Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(IntrinsicSize.Min)
|
|
||||||
)
|
|
||||||
|
|
||||||
TransparentAddress(
|
|
||||||
transparentAddress = walletAddresses.transparent.address,
|
|
||||||
onCopyToClipboard = onCopyToClipboard,
|
|
||||||
modifier =
|
|
||||||
Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(IntrinsicSize.Min)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: The addresses code below has opportunities to be made more DRY.
|
|
||||||
// Refactoring that is being held off until issue #160 is fixed, since knowledge
|
|
||||||
// of row position will be needed.
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun SaplingAddress(
|
|
||||||
saplingAddress: String,
|
|
||||||
onCopyToClipboard: (String) -> Unit,
|
|
||||||
modifier: Modifier = Modifier
|
|
||||||
) {
|
|
||||||
Row(modifier) {
|
|
||||||
SmallIndicator(ZcashTheme.colors.addressHighlightSapling)
|
|
||||||
|
|
||||||
ExpandableRow(
|
|
||||||
title = stringResource(R.string.wallet_address_sapling),
|
|
||||||
content = saplingAddress,
|
|
||||||
isInitiallyExpanded = false,
|
|
||||||
onCopyToClipboard = onCopyToClipboard
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun TransparentAddress(
|
|
||||||
transparentAddress: String,
|
|
||||||
onCopyToClipboard: (String) -> Unit,
|
|
||||||
modifier: Modifier = Modifier
|
|
||||||
) {
|
|
||||||
Row(modifier) {
|
|
||||||
SmallIndicator(ZcashTheme.colors.addressHighlightTransparent)
|
|
||||||
ExpandableRow(
|
|
||||||
title = stringResource(R.string.wallet_address_transparent),
|
|
||||||
content = transparentAddress,
|
|
||||||
isInitiallyExpanded = false,
|
|
||||||
onCopyToClipboard = onCopyToClipboard
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun ExpandableRow(
|
|
||||||
title: String,
|
|
||||||
content: String,
|
|
||||||
isInitiallyExpanded: Boolean,
|
|
||||||
onCopyToClipboard: (String) -> Unit
|
|
||||||
) {
|
|
||||||
var expandedState by rememberSaveable { mutableStateOf(isInitiallyExpanded) }
|
|
||||||
|
|
||||||
Column {
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
modifier =
|
|
||||||
Modifier
|
|
||||||
.defaultMinSize(minHeight = 48.dp)
|
|
||||||
.clickable { expandedState = !expandedState }
|
|
||||||
.padding(
|
|
||||||
horizontal = ZcashTheme.dimens.spacingDefault,
|
|
||||||
vertical = ZcashTheme.dimens.spacingTiny
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
ListItem(text = title)
|
|
||||||
Spacer(
|
|
||||||
modifier =
|
|
||||||
Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.weight(MINIMAL_WEIGHT)
|
|
||||||
)
|
|
||||||
ExpandableArrow(expandedState)
|
|
||||||
}
|
|
||||||
if (expandedState) {
|
|
||||||
Body(
|
|
||||||
content,
|
|
||||||
modifier =
|
|
||||||
Modifier
|
|
||||||
.clickable { onCopyToClipboard(content) }
|
|
||||||
.padding(
|
|
||||||
horizontal = ZcashTheme.dimens.spacingDefault,
|
|
||||||
vertical = ZcashTheme.dimens.spacingTiny
|
|
||||||
)
|
|
||||||
.testTag(WalletAddressesTag.WALLET_ADDRESS)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun SmallIndicator(color: Color) {
|
|
||||||
// TODO [#160]: Border is not the right implementation here, as it causes double thickness for the middle item
|
|
||||||
// TODO [#160]: https://github.com/Electric-Coin-Company/zashi-android/issues/160
|
|
||||||
Image(
|
|
||||||
modifier =
|
|
||||||
Modifier
|
|
||||||
.fillMaxHeight()
|
|
||||||
.width(SMALL_INDICATOR_WIDTH)
|
|
||||||
.border(1.dp, ZcashTheme.colors.addressHighlightBorder),
|
|
||||||
painter = ColorPainter(color),
|
|
||||||
contentDescription = ""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private const val NINETY_DEGREES = 90f
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun ExpandableArrow(isExpanded: Boolean) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Filled.ArrowDropDownCircle,
|
|
||||||
contentDescription =
|
|
||||||
if (isExpanded) {
|
|
||||||
stringResource(id = R.string.wallet_address_hide)
|
|
||||||
} else {
|
|
||||||
stringResource(id = R.string.wallet_address_show)
|
|
||||||
},
|
|
||||||
modifier =
|
|
||||||
if (isExpanded) {
|
|
||||||
Modifier
|
|
||||||
} else {
|
|
||||||
Modifier.rotate(NINETY_DEGREES)
|
|
||||||
},
|
|
||||||
tint = MaterialTheme.colorScheme.onBackground
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -17,8 +17,8 @@ import co.electriccoin.zcash.ui.R
|
||||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||||
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
|
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
|
||||||
import co.electriccoin.zcash.ui.screen.exportdata.util.FileShareUtil
|
|
||||||
import co.electriccoin.zcash.ui.screen.exportdata.view.ExportPrivateData
|
import co.electriccoin.zcash.ui.screen.exportdata.view.ExportPrivateData
|
||||||
|
import co.electriccoin.zcash.ui.util.FileShareUtil
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
|
@ -93,6 +93,7 @@ fun shareData(
|
||||||
context = context,
|
context = context,
|
||||||
network = ZcashNetwork.fromResources(context)
|
network = ZcashNetwork.fromResources(context)
|
||||||
),
|
),
|
||||||
|
fileType = FileShareUtil.ZASHI_INTERNAL_DATA_MIME_TYPE,
|
||||||
versionInfo = VersionInfo.new(context.applicationContext)
|
versionInfo = VersionInfo.new(context.applicationContext)
|
||||||
)
|
)
|
||||||
runCatching {
|
runCatching {
|
||||||
|
|
|
@ -26,7 +26,6 @@ import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
@Composable
|
@Composable
|
||||||
internal fun MainActivity.WrapHome(
|
internal fun MainActivity.WrapHome(
|
||||||
onPageChange: (HomeScreenIndex) -> Unit,
|
onPageChange: (HomeScreenIndex) -> Unit,
|
||||||
goAddressDetails: () -> Unit,
|
|
||||||
goBack: () -> Unit,
|
goBack: () -> Unit,
|
||||||
goHistory: () -> Unit,
|
goHistory: () -> Unit,
|
||||||
goSettings: () -> Unit,
|
goSettings: () -> Unit,
|
||||||
|
@ -36,7 +35,6 @@ internal fun MainActivity.WrapHome(
|
||||||
WrapHome(
|
WrapHome(
|
||||||
this,
|
this,
|
||||||
onPageChange = onPageChange,
|
onPageChange = onPageChange,
|
||||||
goAddressDetails = goAddressDetails,
|
|
||||||
goBack = goBack,
|
goBack = goBack,
|
||||||
goHistory = goHistory,
|
goHistory = goHistory,
|
||||||
goScan = goScan,
|
goScan = goScan,
|
||||||
|
@ -49,7 +47,6 @@ internal fun MainActivity.WrapHome(
|
||||||
@Composable
|
@Composable
|
||||||
internal fun WrapHome(
|
internal fun WrapHome(
|
||||||
activity: ComponentActivity,
|
activity: ComponentActivity,
|
||||||
goAddressDetails: () -> Unit,
|
|
||||||
goBack: () -> Unit,
|
goBack: () -> Unit,
|
||||||
goHistory: () -> Unit,
|
goHistory: () -> Unit,
|
||||||
goSettings: () -> Unit,
|
goSettings: () -> Unit,
|
||||||
|
@ -117,7 +114,6 @@ internal fun WrapHome(
|
||||||
WrapReceive(
|
WrapReceive(
|
||||||
activity = activity,
|
activity = activity,
|
||||||
onSettings = goSettings,
|
onSettings = goSettings,
|
||||||
onAddressDetails = goAddressDetails,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|
|
@ -2,48 +2,134 @@
|
||||||
|
|
||||||
package co.electriccoin.zcash.ui.screen.receive
|
package co.electriccoin.zcash.ui.screen.receive
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Bitmap
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.graphics.asAndroidBitmap
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import cash.z.ecc.android.sdk.model.WalletAddresses
|
import co.electriccoin.zcash.spackle.ClipboardManagerUtil
|
||||||
|
import co.electriccoin.zcash.spackle.Twig
|
||||||
|
import co.electriccoin.zcash.spackle.getInternalCacheDirSuspend
|
||||||
|
import co.electriccoin.zcash.ui.R
|
||||||
|
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||||
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
|
|
||||||
import co.electriccoin.zcash.ui.screen.receive.view.Receive
|
import co.electriccoin.zcash.ui.screen.receive.view.Receive
|
||||||
|
import co.electriccoin.zcash.ui.util.FileShareUtil
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun WrapReceive(
|
internal fun WrapReceive(
|
||||||
activity: ComponentActivity,
|
activity: ComponentActivity,
|
||||||
onSettings: () -> Unit,
|
onSettings: () -> Unit,
|
||||||
onAddressDetails: () -> Unit,
|
|
||||||
) {
|
) {
|
||||||
val viewModel by activity.viewModels<WalletViewModel>()
|
val viewModel by activity.viewModels<WalletViewModel>()
|
||||||
val walletAddresses = viewModel.addresses.collectAsStateWithLifecycle().value
|
val walletAddresses = viewModel.addresses.collectAsStateWithLifecycle().value
|
||||||
|
|
||||||
WrapReceive(
|
val snackbarHostState = remember { SnackbarHostState() }
|
||||||
walletAddresses,
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
val versionInfo = VersionInfo.new(activity.applicationContext)
|
||||||
|
|
||||||
|
Receive(
|
||||||
|
walletAddress = walletAddresses,
|
||||||
|
snackbarHostState = snackbarHostState,
|
||||||
|
onAdjustBrightness = { /* Just for testing purposes */ },
|
||||||
|
onAddrCopyToClipboard = { address ->
|
||||||
|
ClipboardManagerUtil.copyToClipboard(
|
||||||
|
activity.applicationContext,
|
||||||
|
activity.getString(R.string.receive_clipboard_tag),
|
||||||
|
address
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onQrImageShare = { imageBitmap ->
|
||||||
|
scope.launch {
|
||||||
|
shareData(
|
||||||
|
context = activity.applicationContext,
|
||||||
|
snackbarHostState = snackbarHostState,
|
||||||
|
qrImageBitmap = imageBitmap.asAndroidBitmap(),
|
||||||
|
versionInfo = versionInfo
|
||||||
|
).collect { shareResult ->
|
||||||
|
Twig.info {
|
||||||
|
if (shareResult) {
|
||||||
|
"Sharing the address QR code was successful"
|
||||||
|
} else {
|
||||||
|
"Sharing the address QR code failed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No other action for now
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
onSettings = onSettings,
|
onSettings = onSettings,
|
||||||
onAddressDetails = onAddressDetails,
|
versionInfo = versionInfo
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
private const val CACHE_SUBDIR = "zcash_address_qr_images" // NON-NLS
|
||||||
internal fun WrapReceive(
|
private const val TEMP_FILE_NAME_PREFIX = "zcash_address_qr_" // NON-NLS
|
||||||
walletAddresses: WalletAddresses?,
|
private const val TEMP_FILE_NAME_SUFFIX = ".png" // NON-NLS
|
||||||
onSettings: () -> Unit,
|
|
||||||
onAddressDetails: () -> Unit,
|
fun shareData(
|
||||||
) {
|
context: Context,
|
||||||
if (null == walletAddresses) {
|
snackbarHostState: SnackbarHostState,
|
||||||
// TODO [#1146]: Consider moving CircularScreenProgressIndicator from Android layer to View layer
|
qrImageBitmap: Bitmap,
|
||||||
// TODO [#1146]: Improve this by allowing screen composition and updating it after the data is available
|
versionInfo: VersionInfo
|
||||||
// TODO [#1146]: https://github.com/Electric-Coin-Company/zashi-android/issues/1146
|
): Flow<Boolean> =
|
||||||
CircularScreenProgressIndicator()
|
callbackFlow {
|
||||||
} else {
|
// Initialize cache directory
|
||||||
Receive(
|
val cacheDir = context.getInternalCacheDirSuspend(CACHE_SUBDIR)
|
||||||
walletAddresses.unified,
|
|
||||||
onSettings = onSettings,
|
// Save the bitmap to a temporary file in the cache directory
|
||||||
onAddressDetails = onAddressDetails,
|
val bitmapFile =
|
||||||
onAdjustBrightness = { /* Just for testing */ }
|
withContext(Dispatchers.IO) {
|
||||||
|
File.createTempFile(
|
||||||
|
TEMP_FILE_NAME_PREFIX,
|
||||||
|
TEMP_FILE_NAME_SUFFIX,
|
||||||
|
cacheDir,
|
||||||
|
).also {
|
||||||
|
it.storeBitmap(qrImageBitmap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example of the expected temporary file path:
|
||||||
|
// /data/user/0/co.electriccoin.zcash.debug/cache/zcash_address_qr_images/
|
||||||
|
// zcash_address_qr_6455164324646067652.png
|
||||||
|
|
||||||
|
val shareIntent =
|
||||||
|
FileShareUtil.newShareContentIntent(
|
||||||
|
context = context,
|
||||||
|
dataFilePath = bitmapFile.absolutePath,
|
||||||
|
versionInfo = versionInfo,
|
||||||
|
fileType = FileShareUtil.ZASHI_QR_CODE_MIME_TYPE
|
||||||
)
|
)
|
||||||
|
runCatching {
|
||||||
|
context.startActivity(shareIntent)
|
||||||
|
trySend(true)
|
||||||
|
}.onFailure {
|
||||||
|
snackbarHostState.showSnackbar(message = context.getString(R.string.receive_data_unable_to_share))
|
||||||
|
trySend(false)
|
||||||
|
}
|
||||||
|
awaitClose {
|
||||||
|
// No resources to release
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun File.storeBitmap(bitmap: Bitmap) =
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
outputStream().use { fOut ->
|
||||||
|
@Suppress("MagicNumber")
|
||||||
|
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut)
|
||||||
|
fOut.flush()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,7 @@ object JvmQrCodeGenerator : QrCodeGenerator {
|
||||||
data: String,
|
data: String,
|
||||||
sizePixels: Int
|
sizePixels: Int
|
||||||
): BooleanArray {
|
): BooleanArray {
|
||||||
val bitMatrix =
|
val bitMatrix = QRCodeWriter().encode(data, BarcodeFormat.QR_CODE, sizePixels, sizePixels)
|
||||||
QRCodeWriter().let {
|
|
||||||
it.encode(data, BarcodeFormat.QR_CODE, sizePixels, sizePixels)
|
|
||||||
}
|
|
||||||
|
|
||||||
return BooleanArray(sizePixels * sizePixels).apply {
|
return BooleanArray(sizePixels * sizePixels).apply {
|
||||||
var booleanArrayPosition = 0
|
var booleanArrayPosition = 0
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
package co.electriccoin.zcash.ui.screen.receive.view
|
package co.electriccoin.zcash.ui.screen.receive.view
|
||||||
|
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.wrapContentSize
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
@ -13,34 +18,41 @@ import androidx.compose.material.icons.filled.BrightnessHigh
|
||||||
import androidx.compose.material.icons.filled.BrightnessLow
|
import androidx.compose.material.icons.filled.BrightnessLow
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.SnackbarHost
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.res.vectorResource
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.Dp
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import cash.z.ecc.android.sdk.fixture.WalletAddressFixture
|
import cash.z.ecc.android.sdk.fixture.WalletAddressesFixture
|
||||||
import cash.z.ecc.android.sdk.model.WalletAddress
|
import cash.z.ecc.android.sdk.model.WalletAddress
|
||||||
|
import cash.z.ecc.android.sdk.model.WalletAddresses
|
||||||
import co.electriccoin.zcash.ui.R
|
import co.electriccoin.zcash.ui.R
|
||||||
import co.electriccoin.zcash.ui.common.BrightenScreen
|
import co.electriccoin.zcash.ui.common.BrightenScreen
|
||||||
import co.electriccoin.zcash.ui.common.DisableScreenTimeout
|
import co.electriccoin.zcash.ui.common.DisableScreenTimeout
|
||||||
|
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||||
import co.electriccoin.zcash.ui.common.test.CommonTag
|
import co.electriccoin.zcash.ui.common.test.CommonTag
|
||||||
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
|
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
|
||||||
import co.electriccoin.zcash.ui.design.component.Body
|
|
||||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||||
import co.electriccoin.zcash.ui.design.component.PrimaryButton
|
import co.electriccoin.zcash.ui.design.component.Reference
|
||||||
import co.electriccoin.zcash.ui.design.component.SmallTopAppBar
|
import co.electriccoin.zcash.ui.design.component.SmallTopAppBar
|
||||||
|
import co.electriccoin.zcash.ui.design.component.SubHeader
|
||||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
|
import co.electriccoin.zcash.ui.fixture.VersionInfoFixture
|
||||||
import co.electriccoin.zcash.ui.screen.receive.util.AndroidQrCodeImageGenerator
|
import co.electriccoin.zcash.ui.screen.receive.util.AndroidQrCodeImageGenerator
|
||||||
import co.electriccoin.zcash.ui.screen.receive.util.JvmQrCodeGenerator
|
import co.electriccoin.zcash.ui.screen.receive.util.JvmQrCodeGenerator
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
@ -52,58 +64,77 @@ private fun ComposablePreview() {
|
||||||
ZcashTheme(forceDarkMode = false) {
|
ZcashTheme(forceDarkMode = false) {
|
||||||
GradientSurface {
|
GradientSurface {
|
||||||
Receive(
|
Receive(
|
||||||
walletAddress = runBlocking { WalletAddressFixture.unified() },
|
walletAddress = runBlocking { WalletAddressesFixture.new() },
|
||||||
|
snackbarHostState = SnackbarHostState(),
|
||||||
onSettings = {},
|
onSettings = {},
|
||||||
onAddressDetails = {},
|
|
||||||
onAdjustBrightness = {},
|
onAdjustBrightness = {},
|
||||||
|
onAddrCopyToClipboard = {},
|
||||||
|
onQrImageShare = {},
|
||||||
|
versionInfo = VersionInfoFixture.new()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
@Composable
|
@Composable
|
||||||
fun Receive(
|
fun Receive(
|
||||||
walletAddress: WalletAddress,
|
walletAddress: WalletAddresses?,
|
||||||
|
snackbarHostState: SnackbarHostState,
|
||||||
onSettings: () -> Unit,
|
onSettings: () -> Unit,
|
||||||
onAddressDetails: () -> Unit,
|
|
||||||
onAdjustBrightness: (Boolean) -> Unit,
|
onAdjustBrightness: (Boolean) -> Unit,
|
||||||
|
onAddrCopyToClipboard: (String) -> Unit,
|
||||||
|
onQrImageShare: (ImageBitmap) -> Unit,
|
||||||
|
versionInfo: VersionInfo,
|
||||||
) {
|
) {
|
||||||
val (brightness, setBrightness) = rememberSaveable { mutableStateOf(false) }
|
val (brightness, setBrightness) = rememberSaveable { mutableStateOf(false) }
|
||||||
|
|
||||||
Scaffold(topBar = {
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
ReceiveTopAppBar(
|
ReceiveTopAppBar(
|
||||||
adjustBrightness = brightness,
|
adjustBrightness = brightness,
|
||||||
onSettings = onSettings,
|
onSettings = onSettings,
|
||||||
onBrightness = {
|
onBrightness = {
|
||||||
onAdjustBrightness(!brightness)
|
onAdjustBrightness(!brightness)
|
||||||
setBrightness(!brightness)
|
setBrightness(!brightness)
|
||||||
}
|
},
|
||||||
|
versionInfo = versionInfo,
|
||||||
)
|
)
|
||||||
}) { paddingValues ->
|
},
|
||||||
|
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||||
|
) { paddingValues ->
|
||||||
|
if (null == walletAddress) {
|
||||||
|
CircularScreenProgressIndicator()
|
||||||
|
} else {
|
||||||
ReceiveContents(
|
ReceiveContents(
|
||||||
walletAddress = walletAddress,
|
walletAddress = walletAddress,
|
||||||
onAddressDetails = onAddressDetails,
|
onAddressCopyToClipboard = onAddrCopyToClipboard,
|
||||||
|
onQrImageShare = onQrImageShare,
|
||||||
adjustBrightness = brightness,
|
adjustBrightness = brightness,
|
||||||
|
versionInfo = versionInfo,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.padding(
|
Modifier.padding(
|
||||||
top = paddingValues.calculateTopPadding() + ZcashTheme.dimens.spacingDefault,
|
top = paddingValues.calculateTopPadding() + ZcashTheme.dimens.spacingDefault,
|
||||||
bottom = paddingValues.calculateBottomPadding() + ZcashTheme.dimens.spacingHuge,
|
bottom = paddingValues.calculateBottomPadding() + ZcashTheme.dimens.spacingDefault,
|
||||||
start = ZcashTheme.dimens.screenHorizontalSpacingRegular,
|
start = ZcashTheme.dimens.screenHorizontalSpacingRegular,
|
||||||
end = ZcashTheme.dimens.screenHorizontalSpacingRegular
|
end = ZcashTheme.dimens.screenHorizontalSpacingRegular
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ReceiveTopAppBar(
|
private fun ReceiveTopAppBar(
|
||||||
adjustBrightness: Boolean,
|
adjustBrightness: Boolean,
|
||||||
onSettings: () -> Unit,
|
onSettings: () -> Unit,
|
||||||
onBrightness: () -> Unit
|
onBrightness: () -> Unit,
|
||||||
|
versionInfo: VersionInfo
|
||||||
) {
|
) {
|
||||||
SmallTopAppBar(
|
SmallTopAppBar(
|
||||||
titleText = stringResource(id = R.string.receive_title),
|
titleText = stringResource(id = R.string.receive_title),
|
||||||
regularActions = {
|
regularActions = {
|
||||||
|
if (versionInfo.isDebuggable) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = onBrightness
|
onClick = onBrightness
|
||||||
) {
|
) {
|
||||||
|
@ -117,6 +148,7 @@ private fun ReceiveTopAppBar(
|
||||||
contentDescription = stringResource(R.string.receive_brightness_content_description)
|
contentDescription = stringResource(R.string.receive_brightness_content_description)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
hamburgerMenuActions = {
|
hamburgerMenuActions = {
|
||||||
IconButton(
|
IconButton(
|
||||||
|
@ -132,13 +164,14 @@ private fun ReceiveTopAppBar(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val DEFAULT_QR_CODE_SIZE = 320.dp
|
@Suppress("LongParameterList")
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ReceiveContents(
|
private fun ReceiveContents(
|
||||||
walletAddress: WalletAddress,
|
walletAddress: WalletAddresses,
|
||||||
onAddressDetails: () -> Unit,
|
onAddressCopyToClipboard: (String) -> Unit,
|
||||||
|
onQrImageShare: (ImageBitmap) -> Unit,
|
||||||
adjustBrightness: Boolean,
|
adjustBrightness: Boolean,
|
||||||
|
versionInfo: VersionInfo,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
|
@ -149,76 +182,160 @@ private fun ReceiveContents(
|
||||||
.then(modifier),
|
.then(modifier),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
QrCode(
|
|
||||||
data = walletAddress.address,
|
|
||||||
size = DEFAULT_QR_CODE_SIZE,
|
|
||||||
adjustBrightness = adjustBrightness,
|
|
||||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
|
|
||||||
|
|
||||||
Body(
|
|
||||||
text = stringResource(id = R.string.wallet_address_unified),
|
|
||||||
Modifier.align(Alignment.CenterHorizontally)
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
|
|
||||||
|
|
||||||
// TODO [#163]: Ellipsize center of the string
|
|
||||||
// TODO [#163]: https://github.com/Electric-Coin-Company/zashi-android/issues/163
|
|
||||||
Text(
|
|
||||||
text = walletAddress.address,
|
|
||||||
style = MaterialTheme.typography.bodyLarge,
|
|
||||||
color = MaterialTheme.colorScheme.onBackground,
|
|
||||||
modifier = Modifier.align(Alignment.CenterHorizontally),
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
maxLines = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(
|
|
||||||
modifier =
|
|
||||||
Modifier
|
|
||||||
.fillMaxHeight()
|
|
||||||
.weight(MINIMAL_WEIGHT)
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
|
|
||||||
|
|
||||||
PrimaryButton(
|
|
||||||
onClick = onAddressDetails,
|
|
||||||
text = stringResource(id = R.string.receive_see_address_details)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun QrCode(
|
|
||||||
data: String,
|
|
||||||
size: Dp,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
adjustBrightness: Boolean = false,
|
|
||||||
) {
|
|
||||||
Column(modifier = modifier) {
|
|
||||||
if (adjustBrightness) {
|
if (adjustBrightness) {
|
||||||
BrightenScreen()
|
BrightenScreen()
|
||||||
DisableScreenTimeout()
|
DisableScreenTimeout()
|
||||||
}
|
}
|
||||||
|
|
||||||
val sizePixels = with(LocalDensity.current) { size.toPx() }.roundToInt()
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
|
||||||
|
|
||||||
|
Address(
|
||||||
|
walletAddress = walletAddress.unified,
|
||||||
|
onAddressCopyToClipboard = onAddressCopyToClipboard,
|
||||||
|
onQrImageShare = onQrImageShare,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (versionInfo.isTestnet) {
|
||||||
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingHuge))
|
||||||
|
|
||||||
|
Address(
|
||||||
|
walletAddress = walletAddress.sapling,
|
||||||
|
onAddressCopyToClipboard = onAddressCopyToClipboard,
|
||||||
|
onQrImageShare = onQrImageShare,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingHuge))
|
||||||
|
|
||||||
|
Address(
|
||||||
|
walletAddress = walletAddress.transparent,
|
||||||
|
onAddressCopyToClipboard = onAddressCopyToClipboard,
|
||||||
|
onQrImageShare = onQrImageShare,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val DEFAULT_QR_CODE_SIZE = 320.dp
|
||||||
|
|
||||||
|
@Suppress("LongMethod")
|
||||||
|
@Composable
|
||||||
|
private fun Address(
|
||||||
|
walletAddress: WalletAddress,
|
||||||
|
onAddressCopyToClipboard: (String) -> Unit,
|
||||||
|
onQrImageShare: (ImageBitmap) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Column(modifier = modifier) {
|
||||||
|
SubHeader(
|
||||||
|
text =
|
||||||
|
stringResource(
|
||||||
|
id =
|
||||||
|
when (walletAddress) {
|
||||||
|
is WalletAddress.Unified -> R.string.receive_wallet_address_unified
|
||||||
|
is WalletAddress.Sapling -> R.string.receive_wallet_address_sapling
|
||||||
|
is WalletAddress.Transparent -> R.string.receive_wallet_address_transparent
|
||||||
|
}
|
||||||
|
),
|
||||||
|
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingTiny))
|
||||||
|
|
||||||
|
val sizePixels = with(LocalDensity.current) { DEFAULT_QR_CODE_SIZE.toPx() }.roundToInt()
|
||||||
|
val qrCodeImage =
|
||||||
|
remember {
|
||||||
|
qrCodeForAddress(
|
||||||
|
address = walletAddress.address,
|
||||||
|
size = sizePixels
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
QrCode(
|
||||||
|
qrCodeImage = qrCodeImage,
|
||||||
|
onQrImageBitmapShare = onQrImageShare,
|
||||||
|
contentDescription =
|
||||||
|
stringResource(
|
||||||
|
id =
|
||||||
|
when (walletAddress) {
|
||||||
|
is WalletAddress.Unified -> R.string.receive_unified_content_description
|
||||||
|
is WalletAddress.Sapling -> R.string.receive_sapling_content_description
|
||||||
|
is WalletAddress.Transparent -> R.string.receive_transparent_content_description
|
||||||
|
}
|
||||||
|
),
|
||||||
|
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingTiny))
|
||||||
|
|
||||||
|
// TODO [#163]: Ellipsize center of the string
|
||||||
|
// TODO [#163]: https://github.com/Electric-Coin-Company/zashi-android/issues/163
|
||||||
|
Text(
|
||||||
|
text = walletAddress.address,
|
||||||
|
style = ZcashTheme.typography.primary.bodyLarge,
|
||||||
|
color = ZcashTheme.colors.textDescription,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.align(Alignment.CenterHorizontally)
|
||||||
|
.clickable { onAddressCopyToClipboard(walletAddress.address) }
|
||||||
|
.padding(horizontal = ZcashTheme.dimens.spacingLarge)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
Reference(
|
||||||
|
text = stringResource(id = R.string.receive_copy),
|
||||||
|
onClick = { onAddressCopyToClipboard(walletAddress.address) },
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
imageVector = ImageVector.vectorResource(R.drawable.copy),
|
||||||
|
imageContentDescription = null,
|
||||||
|
modifier = Modifier.wrapContentSize(),
|
||||||
|
)
|
||||||
|
Reference(
|
||||||
|
text = stringResource(id = R.string.receive_share),
|
||||||
|
onClick = { onQrImageShare(qrCodeImage) },
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
imageVector = ImageVector.vectorResource(R.drawable.share),
|
||||||
|
imageContentDescription = null,
|
||||||
|
modifier = Modifier.wrapContentSize(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun qrCodeForAddress(
|
||||||
|
address: String,
|
||||||
|
size: Int,
|
||||||
|
): ImageBitmap {
|
||||||
// In the future, use actual/expect to switch QR code generator implementations for multiplatform
|
// In the future, use actual/expect to switch QR code generator implementations for multiplatform
|
||||||
|
|
||||||
// Note that our implementation has an extra array copy to BooleanArray, which is a cross-platform
|
// Note that our implementation has an extra array copy to BooleanArray, which is a cross-platform
|
||||||
// representation. This should have minimal performance impact since the QR code is relatively
|
// representation. This should have minimal performance impact since the QR code is relatively
|
||||||
// small and we only generate QR codes infrequently.
|
// small and we only generate QR codes infrequently.
|
||||||
|
|
||||||
val qrCodePixelArray = JvmQrCodeGenerator.generate(data, sizePixels)
|
val qrCodePixelArray = JvmQrCodeGenerator.generate(address, size)
|
||||||
val qrCodeImage = AndroidQrCodeImageGenerator.generate(qrCodePixelArray, sizePixels)
|
|
||||||
|
|
||||||
|
return AndroidQrCodeImageGenerator.generate(qrCodePixelArray, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun QrCode(
|
||||||
|
contentDescription: String,
|
||||||
|
qrCodeImage: ImageBitmap,
|
||||||
|
onQrImageBitmapShare: (ImageBitmap) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
Image(
|
Image(
|
||||||
bitmap = qrCodeImage,
|
bitmap = qrCodeImage,
|
||||||
contentDescription = stringResource(R.string.receive_qr_code_content_description)
|
contentDescription = contentDescription,
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.clickable { onQrImageBitmapShare(qrCodeImage) }
|
||||||
|
.then(modifier)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -37,12 +37,13 @@ private const val MAX_EXCEPTIONS_TO_REPORT = 5
|
||||||
|
|
||||||
suspend fun CrashInfo.Companion.all(context: Context): List<CrashInfo> {
|
suspend fun CrashInfo.Companion.all(context: Context): List<CrashInfo> {
|
||||||
val exceptionDirectory = ExceptionPath.getExceptionDirectory(context) ?: return emptyList()
|
val exceptionDirectory = ExceptionPath.getExceptionDirectory(context) ?: return emptyList()
|
||||||
val filesList: List<File> = exceptionDirectory.listFilesSuspend().toList()
|
val filesList: List<File>? = exceptionDirectory.listFilesSuspend()?.toList()
|
||||||
return filesList
|
return filesList?.run {
|
||||||
.mapNotNull {
|
mapNotNull {
|
||||||
ReportedException.new(it)
|
ReportedException.new(it)
|
||||||
}.sortedBy { it.time }
|
}.sortedBy { it.time }
|
||||||
.reversed()
|
.reversed()
|
||||||
.take(MAX_EXCEPTIONS_TO_REPORT)
|
.take(MAX_EXCEPTIONS_TO_REPORT)
|
||||||
.map { CrashInfo(it.exceptionClassName, it.isUncaught, it.time) }
|
.map { CrashInfo(it.exceptionClassName, it.isUncaught, it.time) }
|
||||||
|
} ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package co.electriccoin.zcash.ui.screen.exportdata.util
|
package co.electriccoin.zcash.ui.util
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
@ -13,6 +13,7 @@ object FileShareUtil {
|
||||||
const val SHARE_CONTENT_PERMISSION_FLAGS = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
const val SHARE_CONTENT_PERMISSION_FLAGS = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
|
|
||||||
const val ZASHI_INTERNAL_DATA_MIME_TYPE = "application/octet-stream" // NON-NLS
|
const val ZASHI_INTERNAL_DATA_MIME_TYPE = "application/octet-stream" // NON-NLS
|
||||||
|
const val ZASHI_QR_CODE_MIME_TYPE = "image/png" // NON-NLS
|
||||||
|
|
||||||
const val ZASHI_INTERNAL_DATA_AUTHORITY = "co.electriccoin.zcash.provider" // NON-NLS
|
const val ZASHI_INTERNAL_DATA_AUTHORITY = "co.electriccoin.zcash.provider" // NON-NLS
|
||||||
const val ZASHI_INTERNAL_DATA_AUTHORITY_DEBUG = "co.electriccoin.zcash.debug.provider" // NON-NLS
|
const val ZASHI_INTERNAL_DATA_AUTHORITY_DEBUG = "co.electriccoin.zcash.debug.provider" // NON-NLS
|
||||||
|
@ -30,7 +31,8 @@ object FileShareUtil {
|
||||||
internal fun newShareContentIntent(
|
internal fun newShareContentIntent(
|
||||||
context: Context,
|
context: Context,
|
||||||
dataFilePath: String,
|
dataFilePath: String,
|
||||||
versionInfo: VersionInfo
|
fileType: String,
|
||||||
|
versionInfo: VersionInfo,
|
||||||
): Intent {
|
): Intent {
|
||||||
val fileUri =
|
val fileUri =
|
||||||
FileProvider.getUriForFile(
|
FileProvider.getUriForFile(
|
||||||
|
@ -43,7 +45,7 @@ object FileShareUtil {
|
||||||
Intent().apply {
|
Intent().apply {
|
||||||
action = Intent.ACTION_SEND
|
action = Intent.ACTION_SEND
|
||||||
putExtra(Intent.EXTRA_STREAM, fileUri)
|
putExtra(Intent.EXTRA_STREAM, fileUri)
|
||||||
type = ZASHI_INTERNAL_DATA_MIME_TYPE
|
type = fileType
|
||||||
}
|
}
|
||||||
|
|
||||||
val shareDataIntent =
|
val shareDataIntent =
|
|
@ -1,21 +1,24 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<paths>
|
<paths>
|
||||||
|
<!-- TODO [#1183]: Rework the way we grant access to file provider -->
|
||||||
|
<!-- TODO [#1183]: https://github.com/Electric-Coin-Company/zashi-android/issues/1183 -->
|
||||||
|
|
||||||
<!-- Android Studio complains about root-path. Search for an alternative way of approaching no_backup folder -->
|
<!-- Android Studio complains about root-path. Search for an alternative way of approaching no_backup folder -->
|
||||||
<!-- Another way is to split paths into packages depending on current build type -->
|
|
||||||
<root-path
|
<root-path
|
||||||
name="root_mainnet_release"
|
name="root_mainnet_release"
|
||||||
path="/data/data/co.electriccoin.zcash/no_backup/co.electricoin.zcash/."
|
path="/data/data/co.electriccoin.zcash/."
|
||||||
/>
|
/>
|
||||||
<root-path
|
<root-path
|
||||||
name="root_mainnet_debug"
|
name="root_mainnet_debug"
|
||||||
path="/data/data/co.electriccoin.zcash.debug/no_backup/co.electricoin.zcash/."
|
path="/data/data/co.electriccoin.zcash.debug/."
|
||||||
/>
|
/>
|
||||||
<root-path
|
<root-path
|
||||||
name="root_testnet_release"
|
name="root_testnet_release"
|
||||||
path="/data/data/co.electriccoin.zcash.testnet/no_backup/co.electricoin.zcash/."
|
path="/data/data/co.electriccoin.zcash.testnet/."
|
||||||
/>
|
/>
|
||||||
<root-path
|
<root-path
|
||||||
name="root_testnet_debug"
|
name="root_testnet_debug"
|
||||||
path="/data/data/co.electriccoin.zcash.testnet.debug/no_backup/co.electricoin.zcash/."
|
path="/data/data/co.electriccoin.zcash.testnet.debug/."
|
||||||
/>
|
/>
|
||||||
</paths>
|
</paths>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="16dp"
|
||||||
|
android:height="16dp"
|
||||||
|
android:viewportWidth="16"
|
||||||
|
android:viewportHeight="16">
|
||||||
|
<group>
|
||||||
|
<clip-path
|
||||||
|
android:pathData="M0,0h16v16h-16z"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M0,16V2.823H13.206V16H0ZM11.832,14.605V4.218H1.374V14.622H11.832V14.605Z"
|
||||||
|
android:fillColor="#000000"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M15.313,11.816C14.939,11.816 14.627,11.504 14.627,11.126V1.395H4.839C4.465,1.395 4.152,1.083 4.152,0.706C4.152,0.328 4.465,0.017 4.839,0.017H16V11.143C16,11.52 15.688,11.832 15.313,11.832V11.816Z"
|
||||||
|
android:fillColor="#000000"/>
|
||||||
|
</group>
|
||||||
|
</vector>
|
|
@ -0,0 +1,40 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="16dp"
|
||||||
|
android:height="14dp"
|
||||||
|
android:viewportWidth="16"
|
||||||
|
android:viewportHeight="14">
|
||||||
|
<group>
|
||||||
|
<clip-path
|
||||||
|
android:pathData="M0,0.155h16v13.58h-16z"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M16,12.005H0V13.735H16V12.005Z"
|
||||||
|
android:fillColor="#231F20"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M15.5,12.505H0.5V13.235H15.5V12.505Z"
|
||||||
|
android:fillColor="#231F20"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M1.7,8.465H0V13.735H1.7V8.465Z"
|
||||||
|
android:fillColor="#231F20"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M1.2,8.965H0.5V13.235H1.2V8.965Z"
|
||||||
|
android:fillColor="#231F20"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M16,8.465H14.3V13.735H16V8.465Z"
|
||||||
|
android:fillColor="#231F20"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M15.5,8.965H14.8V13.235H15.5V8.965Z"
|
||||||
|
android:fillColor="#231F20"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M8.85,1.175H7.15V8.335H8.85V1.175Z"
|
||||||
|
android:fillColor="#231F20"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M8.35,1.675H7.65V7.835H8.35V1.675Z"
|
||||||
|
android:fillColor="#231F20"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M8.5,1.395L8,0.875L7.5,1.395L5.42,3.555L5.92,4.075L7.99,1.915L10.07,4.075L10.57,3.555L8.5,1.395Z"
|
||||||
|
android:fillColor="#231F20"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M8,2.625L5.93,4.785L4.73,3.555L8,0.155L11.26,3.555L10.08,4.785L8,2.625Z"
|
||||||
|
android:fillColor="#231F20"/>
|
||||||
|
</group>
|
||||||
|
</vector>
|
|
@ -2,8 +2,14 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="receive_title">Receive</string>
|
<string name="receive_title">Receive</string>
|
||||||
<string name="receive_brightness_content_description">Adjust brightness</string>
|
<string name="receive_brightness_content_description">Adjust brightness</string>
|
||||||
<string name="receive_qr_code_content_description">QR code for address</string>
|
<string name="receive_unified_content_description">Unified Address QR code</string>
|
||||||
<string name="receive_caption">Your Address</string>
|
<string name="receive_sapling_content_description">Sapling Address QR code</string>
|
||||||
<string name="receive_see_address_details">See Address Details</string>
|
<string name="receive_transparent_content_description">Transparent Address QR code</string>
|
||||||
|
<string name="receive_wallet_address_unified">Unified Address</string>
|
||||||
|
<string name="receive_wallet_address_sapling">Sapling Address</string>
|
||||||
|
<string name="receive_wallet_address_transparent">Transparent Address</string>
|
||||||
|
<string name="receive_copy">Copy</string>
|
||||||
|
<string name="receive_share">Share</string>
|
||||||
|
<string name="receive_clipboard_tag">Zcash Wallet Address</string>
|
||||||
|
<string name="receive_data_unable_to_share">Unable to find an application to share the QR code with.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<string name="wallet_address_title">My wallet addresses</string>
|
|
||||||
<string name="wallet_address_back_content_description">Back</string>
|
|
||||||
|
|
||||||
<string name="wallet_address_unified">Your Unified Address:</string>
|
|
||||||
<string name="wallet_address_header_includes">which includes</string>
|
|
||||||
<string name="wallet_address_sapling">Shielded Sapling (NU1)</string>
|
|
||||||
<string name="wallet_address_transparent">Transparent</string>
|
|
||||||
<string name="wallet_address_show">Show address</string>
|
|
||||||
<string name="wallet_address_hide">Hide address</string>
|
|
||||||
|
|
||||||
<string name="wallet_address_clipboard_tag">Zcash Wallet Address</string>
|
|
||||||
</resources>
|
|
|
@ -3,9 +3,9 @@
|
||||||
<string name="not_enough_space_title">Not enough space!</string>
|
<string name="not_enough_space_title">Not enough space!</string>
|
||||||
<string name="not_enough_space_logo_content_description"></string>
|
<string name="not_enough_space_logo_content_description"></string>
|
||||||
<string name="not_enough_space_description">You need approximately <xliff:g example="1" id="required_gigabytes">
|
<string name="not_enough_space_description">You need approximately <xliff:g example="1" id="required_gigabytes">
|
||||||
%1$d</xliff:g> gig of space while synchronizing the Zcash blockchain, but only 300 megs once done. Syncing
|
%1$d</xliff:g> Gbyte of space while synchronizing the Zcash blockchain, but only 300 Mbyte once done. Syncing
|
||||||
will stay paused until more space is available.</string>
|
will stay paused until more space is available.</string>
|
||||||
<string name="space_required_to_continue"><xliff:g example="300" id="required_megabytes">~%1$d</xliff:g> megs
|
<string name="space_required_to_continue"><xliff:g example="300" id="required_megabytes">~%1$d</xliff:g> Mbyte
|
||||||
required to continue </string>
|
required to continue </string>
|
||||||
<string name="unknown">Unknown</string>
|
<string name="unknown">Unknown</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -290,9 +290,6 @@ class ScreenshotTest : UiTestPrerequisites() {
|
||||||
composeTestRule.navigateInHomeTab(HomeTag.TAB_BALANCES)
|
composeTestRule.navigateInHomeTab(HomeTag.TAB_BALANCES)
|
||||||
balancesScreenshots(resContext, tag, composeTestRule)
|
balancesScreenshots(resContext, tag, composeTestRule)
|
||||||
|
|
||||||
navigateTo(NavigationTargets.WALLET_ADDRESS_DETAILS)
|
|
||||||
addressDetailsScreenshots(resContext, tag, composeTestRule)
|
|
||||||
|
|
||||||
navigateTo(NavigationTargets.HISTORY)
|
navigateTo(NavigationTargets.HISTORY)
|
||||||
transactionHistoryScreenshots(resContext, tag, composeTestRule)
|
transactionHistoryScreenshots(resContext, tag, composeTestRule)
|
||||||
|
|
||||||
|
@ -419,18 +416,6 @@ private fun settingsScreenshots(
|
||||||
ScreenshotTest.takeScreenshot(tag, "Settings 1")
|
ScreenshotTest.takeScreenshot(tag, "Settings 1")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addressDetailsScreenshots(
|
|
||||||
resContext: Context,
|
|
||||||
tag: String,
|
|
||||||
composeTestRule: ComposeTestRule
|
|
||||||
) {
|
|
||||||
composeTestRule.onNode(hasText(resContext.getString(R.string.wallet_address_title))).also {
|
|
||||||
it.assertExists()
|
|
||||||
}
|
|
||||||
|
|
||||||
ScreenshotTest.takeScreenshot(tag, "Addresses 1")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun transactionHistoryScreenshots(
|
private fun transactionHistoryScreenshots(
|
||||||
resContext: Context,
|
resContext: Context,
|
||||||
tag: String,
|
tag: String,
|
||||||
|
@ -468,7 +453,7 @@ private fun receiveZecScreenshots(
|
||||||
|
|
||||||
composeTestRule.onNode(
|
composeTestRule.onNode(
|
||||||
hasContentDescription(
|
hasContentDescription(
|
||||||
value = resContext.getString(R.string.receive_qr_code_content_description),
|
value = resContext.getString(R.string.receive_unified_content_description),
|
||||||
ignoreCase = true
|
ignoreCase = true
|
||||||
)
|
)
|
||||||
).also {
|
).also {
|
||||||
|
|
Loading…
Reference in New Issue