* [#1011] Rework buttons design system

* [#1011] Dark mode in Onboarding screen

* [#1011] Welcome animation dark mode

* [#1011] SecurityWarning screen dark mode

+ Proper coloring of the labeled checkbox across the app

* [#1011] NewWalletRecovery dark mode

+ Chip and ChipGrid coloring
+ Navigation button and Dialog coloring
+ NewWalletRecovery screen button copy update

* [#1011] RestoreView dark mode

+ Chip components coloring

* [#1011] RestoreView.Birthday dark mode

+ Fix Primary/Secondary colors

* [#1011] Settings screen dark mode

- Fix TopAppBar colors in dark mode

* [#1011] Support screen dark mode

* Fix static code analysis warnings

* [#1011] About screen dark mode

* [#1011] ChooseServer screen dark mode

+ LabeledRadioButton coloring
- Closes #1410

* [#1011] AppAlertDialog dark mode

* [#1011] Not Enough Free Space screen dark mode

- Screen redesigned to align with latest design specifications
- Added Go To System Settings and Go To App Settings buttons to the screen
- Closes #1337
- Few unused resources removed

* [#1011] App Update screen dark mode

* [#1011] Balances screen dark mode

+ dividers’ color review

* [#1011] Receive screen dark mode

* [#1011] Send.Form screen dark mode

* [#1011] Send.Confirmation screen dark mode

* [#1011] Send.MultipleTrxError screen dark mode

* [#1011] Scan screen dark mode

* [#1011] TransactionHistory screen dark mode

* Changelog update

* Address review comments
This commit is contained in:
Honza Rychnovský 2024-06-19 14:09:28 +02:00 committed by GitHub
parent 20348014be
commit 987595eaa2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
69 changed files with 1705 additions and 609 deletions

View File

@ -12,6 +12,10 @@ directly impact users rather than highlighting other key architectural updates.*
### Added
- New bubble message style for the Send and Transaction history item text components
- Display all messages within the transaction history record when it is expanded
- The Dark mode is now officially supported by the entire app UI
### Changed
- The Not Enough Free Space screen UI has been slightly refactored to align with the latest design guidelines
## [1.1.1 (660)] - 2024-06-05

View File

@ -32,7 +32,7 @@ private const val COMPONENT_MIN_WIDTH = ARROW_WIDTH * 3
@Composable
private fun BubbleWithTextPreview() {
ZcashTheme {
BubbleMessage(backgroundColor = ZcashTheme.colors.dividerColor) {
BubbleMessage(backgroundColor = ZcashTheme.colors.primaryDividerColor) {
Text(
text = "TextTextTextText",
fontSize = 16.sp,

View File

@ -2,6 +2,7 @@ package co.electriccoin.zcash.ui.design.component
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.waitForUpOrCancellation
@ -11,13 +12,13 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults.buttonColors
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@ -42,6 +43,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.design.theme.internal.ButtonColors
@Preview
@Composable
@ -49,11 +51,59 @@ private fun ButtonComposablePreview() {
ZcashTheme(forceDarkMode = false) {
BlankSurface {
Column(Modifier.padding(ZcashTheme.dimens.spacingDefault)) {
PrimaryButton(onClick = { }, text = "Primary")
PrimaryButton(onClick = { }, text = "Primary...", showProgressBar = true)
PrimaryButton(onClick = { }, text = "Primary Small", minHeight = ZcashTheme.dimens.buttonHeightSmall)
SecondaryButton(onClick = { }, text = "Secondary")
NavigationButton(onClick = { }, text = "Navigation")
Column(
modifier =
Modifier
.background(color = Color.Gray)
.padding(all = 24.dp)
) {
PrimaryButton(onClick = { }, text = "Primary Basic")
PrimaryButton(onClick = { }, text = "Primary Disabled", enabled = false)
SecondaryButton(onClick = { }, text = "Secondary Basic")
SecondaryButton(onClick = { }, text = "Secondary Disabled", enabled = false)
}
Spacer(modifier = Modifier.height(24.dp))
PrimaryButton(onClick = { }, text = "Primary loading", showProgressBar = true)
Spacer(modifier = Modifier.height(24.dp))
@Suppress("MagicNumber")
Row {
PrimaryButton(onClick = { }, text = "Button 1", modifier = Modifier.weight(0.5f))
Spacer(modifier = Modifier.width(24.dp))
PrimaryButton(onClick = { }, text = "Button 2", modifier = Modifier.weight(0.5f))
}
}
}
}
}
@Preview
@Composable
private fun ButtonComposableDarkPreview() {
ZcashTheme(forceDarkMode = true) {
BlankSurface {
Column(Modifier.padding(ZcashTheme.dimens.spacingDefault)) {
Column(
modifier =
Modifier
.background(color = Color.Gray)
.padding(all = 24.dp)
) {
PrimaryButton(onClick = { }, text = "Primary Basic")
PrimaryButton(onClick = { }, text = "Primary Disabled", enabled = false)
SecondaryButton(onClick = { }, text = "Secondary Basic")
SecondaryButton(onClick = { }, text = "Secondary Disabled", enabled = false)
}
Spacer(modifier = Modifier.height(24.dp))
PrimaryButton(onClick = { }, text = "Primary loading", showProgressBar = true)
Spacer(modifier = Modifier.height(24.dp))
@Suppress("MagicNumber")
Row {
PrimaryButton(onClick = { }, text = "Button 1", modifier = Modifier.weight(0.5f))
@ -75,8 +125,7 @@ fun PrimaryButton(
minHeight: Dp = ZcashTheme.dimens.buttonHeight,
enabled: Boolean = true,
showProgressBar: Boolean = false,
buttonColor: Color = MaterialTheme.colorScheme.primary,
textColor: Color = MaterialTheme.colorScheme.onPrimary,
buttonColors: ButtonColors = ZcashTheme.colors.primaryButtonColors,
textStyle: TextStyle = ZcashTheme.extendedTypography.buttonText,
outerPaddingValues: PaddingValues =
PaddingValues(
@ -94,37 +143,66 @@ fun PrimaryButton(
Modifier
.padding(outerPaddingValues)
.shadow(
contentColor = textColor,
strokeColor = buttonColor,
contentColor =
if (enabled) {
buttonColors.shadowColor
} else {
buttonColors.disabledShadowColor
},
strokeColor =
if (enabled) {
buttonColors.shadowStrokeColor
} else {
buttonColors.shadowDisabledStrokeColor
},
strokeWidth = 1.dp,
offsetX = ZcashTheme.dimens.buttonShadowOffsetX,
offsetY = ZcashTheme.dimens.buttonShadowOffsetY,
spread = ZcashTheme.dimens.buttonShadowSpread,
)
.translationClick(
// + 6dp to exactly cover the bottom shadow
translationX = ZcashTheme.dimens.buttonShadowOffsetX + 6.dp,
translationY = ZcashTheme.dimens.buttonShadowOffsetX + 6.dp
.then(
if (enabled) {
Modifier.translationClick(
// + 6dp to exactly cover the bottom shadow
translationX = ZcashTheme.dimens.buttonShadowOffsetX + 6.dp,
translationY = ZcashTheme.dimens.buttonShadowOffsetX + 6.dp
)
} else {
Modifier
}
)
.defaultMinSize(minWidth, minHeight)
.border(1.dp, Color.Black)
.border(
width = 1.dp,
color =
if (enabled) {
buttonColors.strokeColor
} else {
buttonColors.disabledStrokeColor
}
)
),
colors =
buttonColors(
containerColor = buttonColor,
disabledContainerColor = ZcashTheme.colors.disabledButtonColor,
disabledContentColor = ZcashTheme.colors.disabledButtonTextColor
containerColor = buttonColors.containerColor,
disabledContainerColor = buttonColors.disabledContainerColor,
disabledContentColor = buttonColors.disabledContainerColor,
),
onClick = onClick,
) {
ConstraintLayout {
ConstraintLayout(modifier = Modifier.fillMaxWidth()) {
val (title, spacer, progress) = createRefs()
Text(
style = textStyle,
textAlign = TextAlign.Center,
text = text.uppercase(),
color = textColor,
color =
if (enabled) {
buttonColors.textColor
} else {
buttonColors.disabledTextColor
},
modifier =
Modifier.constrainAs(title) {
top.linkTo(parent.top)
@ -165,7 +243,7 @@ fun PrimaryButton(
}
@Composable
@Suppress("LongParameterList")
@Suppress("LongParameterList", "LongMethod")
fun SecondaryButton(
onClick: () -> Unit,
text: String,
@ -173,8 +251,7 @@ fun SecondaryButton(
minWidth: Dp = ZcashTheme.dimens.buttonWidth,
minHeight: Dp = ZcashTheme.dimens.buttonHeight,
enabled: Boolean = true,
buttonColor: Color = MaterialTheme.colorScheme.secondary,
textColor: Color = MaterialTheme.colorScheme.onSecondary,
buttonColors: ButtonColors = ZcashTheme.colors.secondaryButtonColors,
outerPaddingValues: PaddingValues =
PaddingValues(
horizontal = ZcashTheme.dimens.spacingNone,
@ -191,27 +268,51 @@ fun SecondaryButton(
Modifier
.padding(outerPaddingValues)
.shadow(
contentColor = textColor,
strokeColor = buttonColor,
contentColor =
if (enabled) {
buttonColors.shadowColor
} else {
buttonColors.disabledShadowColor
},
strokeColor =
if (enabled) {
buttonColors.shadowStrokeColor
} else {
buttonColors.shadowDisabledStrokeColor
},
strokeWidth = 1.dp,
offsetX = ZcashTheme.dimens.buttonShadowOffsetX,
offsetY = ZcashTheme.dimens.buttonShadowOffsetY,
spread = ZcashTheme.dimens.buttonShadowSpread,
)
.translationClick(
// + 6dp to exactly cover the bottom shadow
translationX = ZcashTheme.dimens.buttonShadowOffsetX + 6.dp,
translationY = ZcashTheme.dimens.buttonShadowOffsetX + 6.dp
.then(
if (enabled) {
Modifier.translationClick(
// + 6dp to exactly cover the bottom shadow
translationX = ZcashTheme.dimens.buttonShadowOffsetX + 6.dp,
translationY = ZcashTheme.dimens.buttonShadowOffsetX + 6.dp
)
} else {
Modifier
}
)
.defaultMinSize(minWidth, minHeight)
.fillMaxWidth()
.border(1.dp, Color.Black)
.border(
width = 1.dp,
color =
if (enabled) {
buttonColors.strokeColor
} else {
buttonColors.disabledStrokeColor
}
)
),
colors =
buttonColors(
containerColor = buttonColor,
disabledContainerColor = ZcashTheme.colors.disabledButtonColor,
disabledContentColor = ZcashTheme.colors.disabledButtonTextColor
containerColor = buttonColors.containerColor,
disabledContainerColor = buttonColors.disabledContainerColor,
disabledContentColor = buttonColors.disabledContainerColor
),
onClick = onClick,
) {
@ -219,37 +320,12 @@ fun SecondaryButton(
style = ZcashTheme.extendedTypography.buttonText,
textAlign = TextAlign.Center,
text = text.uppercase(),
color = textColor
)
}
}
@Composable
fun NavigationButton(
onClick: () -> Unit,
text: String,
modifier: Modifier = Modifier,
outerPaddingValues: PaddingValues =
PaddingValues(
horizontal = ZcashTheme.dimens.spacingNone,
vertical = ZcashTheme.dimens.spacingSmall
),
) {
Button(
shape = RectangleShape,
onClick = onClick,
modifier =
modifier.then(
Modifier
.padding(outerPaddingValues)
),
colors = buttonColors(containerColor = MaterialTheme.colorScheme.secondary)
) {
Text(
style = MaterialTheme.typography.labelLarge,
textAlign = TextAlign.Center,
text = text,
color = MaterialTheme.colorScheme.onSecondary
color =
if (enabled) {
buttonColors.textColor
} else {
buttonColors.disabledTextColor
}
)
}
}

View File

@ -1,15 +1,19 @@
package co.electriccoin.zcash.ui.design.component
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Checkbox
import androidx.compose.material3.CheckboxDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.tooling.preview.Preview
@ -17,60 +21,102 @@ import co.electriccoin.zcash.ui.design.theme.ZcashTheme
@Preview
@Composable
private fun ComposablePreview() {
val checkBoxState = remember { mutableStateOf(false) }
private fun LabeledCheckboxPreview() {
ZcashTheme(forceDarkMode = false) {
CheckBox(
onCheckedChange = { checkBoxState.value = it },
text = "test",
checked = checkBoxState.value,
checkBoxTestTag = null
)
BlankSurface {
Row {
LabeledCheckBox(
onCheckedChange = {},
text = "Checkbox",
checked = false
)
LabeledCheckBox(
onCheckedChange = {},
text = "Checkbox",
checked = true
)
}
}
}
}
@Preview
@Composable
private fun LabeledCheckboxDarkPreview() {
ZcashTheme(forceDarkMode = true) {
BlankSurface {
Row {
LabeledCheckBox(
onCheckedChange = {},
text = "Checkbox",
checked = false
)
LabeledCheckBox(
onCheckedChange = {},
text = "Checkbox",
checked = true
)
}
}
}
}
@Composable
fun CheckBox(
fun LabeledCheckBox(
onCheckedChange: (Boolean) -> Unit,
text: String,
modifier: Modifier = Modifier,
checked: Boolean = false,
checkBoxTestTag: String? = null
) {
val (checkedState, setCheckedState) = rememberSaveable { mutableStateOf(checked) }
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = modifier
) {
val checkBoxModifier =
Modifier
.padding(
top = ZcashTheme.dimens.spacingTiny,
bottom = ZcashTheme.dimens.spacingTiny,
end = ZcashTheme.dimens.spacingTiny
)
.then(
if (checkBoxTestTag != null) {
Modifier.testTag(checkBoxTestTag)
} else {
Modifier
modifier =
modifier.then(
Modifier
.wrapContentSize()
.clip(RoundedCornerShape(ZcashTheme.dimens.regularRippleEffectCorner))
.clickable {
setCheckedState(!checkedState)
onCheckedChange(!checkedState)
}
)
val (checkedState, setCheckedState) = rememberSaveable { mutableStateOf(checked) }
// Setting just the end padding, the start one is taken from the checkbox
.padding(end = ZcashTheme.dimens.spacingMid)
)
) {
Checkbox(
checked = checkedState,
colors =
CheckboxDefaults.colors(
checkedColor = ZcashTheme.colors.secondaryColor,
uncheckedColor = ZcashTheme.colors.secondaryColor,
checkmarkColor = ZcashTheme.colors.primaryColor,
),
onCheckedChange = {
setCheckedState(it)
onCheckedChange(it)
},
enabled = true,
modifier = checkBoxModifier
modifier =
Modifier
.padding(
top = ZcashTheme.dimens.spacingTiny,
bottom = ZcashTheme.dimens.spacingTiny,
end = ZcashTheme.dimens.spacingTiny
)
.then(
if (checkBoxTestTag != null) {
Modifier.testTag(checkBoxTestTag)
} else {
Modifier
}
)
)
ClickableText(
onClick = {
setCheckedState(!checkedState)
onCheckedChange(!checkedState)
},
Text(
text = AnnotatedString(text),
color = ZcashTheme.colors.textPrimary,
style = ZcashTheme.extendedTypography.checkboxText
)
}

View File

@ -2,16 +2,19 @@ package co.electriccoin.zcash.ui.design.component
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import co.electriccoin.zcash.spackle.model.Index
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
@ -19,7 +22,9 @@ import co.electriccoin.zcash.ui.design.theme.ZcashTheme
@Composable
private fun ComposableChipPreview() {
ZcashTheme(forceDarkMode = false) {
Chip("route")
Box(modifier = Modifier.padding(all = 12.dp)) {
Chip("route")
}
}
}
@ -27,7 +32,9 @@ private fun ComposableChipPreview() {
@Composable
private fun ComposableChipIndexedPreview() {
ZcashTheme(forceDarkMode = false) {
ChipIndexed(Index(0), "edict")
Box(modifier = Modifier.padding(all = 12.dp)) {
ChipIndexed(Index(0), "edict")
}
}
}
@ -35,7 +42,12 @@ private fun ComposableChipIndexedPreview() {
@Composable
private fun ComposableLongChipPreview() {
ZcashTheme(forceDarkMode = false) {
ChipIndexed(Index(1), "a_very_long_seed_word_that_does_not_fit_into_the_chip_and_thus_needs_to_be_truncated")
Box(modifier = Modifier.padding(all = 12.dp)) {
ChipIndexed(
Index(1),
"a_very_long_seed_word_that_does_not_fit_into_the_chip_and_thus_needs_to_be_truncated"
)
}
}
}
@ -43,7 +55,19 @@ private fun ComposableLongChipPreview() {
@Composable
private fun ComposableChipOnSurfacePreview() {
ZcashTheme(forceDarkMode = false) {
ChipOnSurface("ribbon")
Box(modifier = Modifier.padding(all = 12.dp)) {
ChipOnSurface({}, "ribbon")
}
}
}
@Preview
@Composable
private fun ComposableChipOnSurfaceDarkPreview() {
ZcashTheme(forceDarkMode = true) {
Box(modifier = Modifier.padding(all = 12.dp)) {
ChipOnSurface({}, "ribbon")
}
}
}
@ -55,7 +79,7 @@ fun Chip(
Text(
text = text,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSecondary,
color = ZcashTheme.colors.textPrimary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = modifier.then(Modifier.testTag(CommonTag.CHIP))
@ -71,7 +95,7 @@ fun ChipIndexed(
Text(
text = "${index.value + 1}. $text",
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSecondary,
color = ZcashTheme.colors.textPrimary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = modifier.then(Modifier.testTag(CommonTag.CHIP))
@ -80,11 +104,12 @@ fun ChipIndexed(
@Composable
fun ChipOnSurface(
onClick: () -> Unit,
text: String,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
) {
Surface(
shape = RectangleShape,
shape = RoundedCornerShape(size = ZcashTheme.dimens.regularRippleEffectCorner),
modifier =
modifier
.padding(horizontal = ZcashTheme.dimens.spacingTiny)
@ -92,20 +117,22 @@ fun ChipOnSurface(
border =
BorderStroke(
width = ZcashTheme.dimens.chipStroke,
color = ZcashTheme.colors.layoutStroke
)
),
color = MaterialTheme.colorScheme.secondary,
color = ZcashTheme.colors.layoutStrokeSecondary
),
shape = RoundedCornerShape(size = ZcashTheme.dimens.regularRippleEffectCorner),
)
.clickable { onClick() },
color = ZcashTheme.colors.primaryColor,
shadowElevation = ZcashTheme.dimens.chipShadowElevation,
) {
Text(
text = text,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSecondary,
color = ZcashTheme.colors.textPrimary,
modifier =
Modifier
.padding(
vertical = ZcashTheme.dimens.spacingSmall,
vertical = ZcashTheme.dimens.spacingMid,
horizontal = ZcashTheme.dimens.spacingDefault
)
.testTag(CommonTag.CHIP)

View File

@ -26,12 +26,27 @@ const val CHIP_GRID_COLUMN_SIZE = 12
@Preview
@Composable
private fun ComposablePreview() {
private fun ChipGridPreview() {
ZcashTheme(forceDarkMode = false) {
ChipGrid(
SeedPhrase.new(WalletFixture.Alice.seedPhrase).split.toPersistentList(),
onGridClick = {}
)
BlankSurface {
ChipGrid(
SeedPhrase.new(WalletFixture.Alice.seedPhrase).split.toPersistentList(),
onGridClick = {}
)
}
}
}
@Preview
@Composable
private fun ChipGridDarkPreview() {
ZcashTheme(forceDarkMode = true) {
BlankSurface {
ChipGrid(
SeedPhrase.new(WalletFixture.Alice.seedPhrase).split.toPersistentList(),
onGridClick = {}
)
}
}
}

View File

@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
@ -27,6 +28,19 @@ private fun TopScreenLogoRegularComposablePreview() {
}
}
@Preview
@Composable
private fun TopScreenLogoRegularDarkComposablePreview() {
ZcashTheme(forceDarkMode = true) {
BlankSurface {
TopScreenLogoTitle(
title = "Test screen title",
logoContentDescription = "Test logo content description"
)
}
}
}
@Preview
@Composable
private fun TopScreenLogoLongComposablePreview() {
@ -49,6 +63,7 @@ fun TopScreenLogoTitle(
Column(modifier = modifier) {
Image(
painter = painterResource(id = R.drawable.zashi_logo_without_text),
colorFilter = ColorFilter.tint(color = ZcashTheme.colors.secondaryColor),
contentDescription = logoContentDescription,
modifier = Modifier.fillMaxWidth()
)
@ -57,6 +72,7 @@ fun TopScreenLogoTitle(
Text(
text = title,
color = ZcashTheme.colors.textPrimary,
style = ZcashTheme.typography.secondary.headlineMedium,
maxLines = 2,
overflow = TextOverflow.Ellipsis,

View File

@ -1,14 +1,19 @@
package co.electriccoin.zcash.ui.design.component
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults.buttonColors
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
@ -30,6 +35,20 @@ private fun LightAlertDialogComposablePreview() {
}
}
@Preview
@Composable
private fun NoButtonAlertDialogComposablePreview() {
ZcashTheme(forceDarkMode = false) {
AppAlertDialog(
title = "Light popup",
text =
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Temporibus autem quibusdam et aut " +
"officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et " +
"molestiae non recusandae. Duis condimentum augue id magna semper rutrum.",
)
}
}
@Preview
@Composable
private fun DarkAlertDialogComposablePreview() {
@ -40,6 +59,8 @@ private fun DarkAlertDialogComposablePreview() {
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Temporibus autem quibusdam et aut " +
"officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et " +
"molestiae non recusandae. Duis condimentum augue id magna semper rutrum.",
confirmButtonText = "OK",
dismissButtonText = "Cancel"
)
}
}
@ -86,6 +107,8 @@ fun AppAlertDialog(
text = text,
icon = icon?.let { { Icon(imageVector = icon, null) } },
properties = properties,
titleContentColor = ZcashTheme.colors.textPrimary,
textContentColor = ZcashTheme.colors.textPrimary,
modifier = modifier,
)
}
@ -117,3 +140,50 @@ fun AppAlertDialog(
onDismissButtonClick = onDismissButtonClick
)
}
@Preview
@Composable
private fun NavigationButtonPreview() {
ZcashTheme(forceDarkMode = false) {
NavigationButton(
onClick = {},
text = "Test button",
)
}
}
@Preview
@Composable
private fun NavigationButtonDarkPreview() {
ZcashTheme(forceDarkMode = true) {
NavigationButton(
onClick = {},
text = "Dark button",
)
}
}
@Composable
private fun NavigationButton(
onClick: () -> Unit,
text: String,
modifier: Modifier = Modifier,
outerPaddingValues: PaddingValues =
PaddingValues(
horizontal = ZcashTheme.dimens.spacingNone,
vertical = ZcashTheme.dimens.spacingSmall
),
) {
Button(
onClick = onClick,
modifier = modifier.padding(outerPaddingValues),
colors = buttonColors(containerColor = ZcashTheme.colors.primaryColor)
) {
Text(
style = MaterialTheme.typography.labelLarge,
textAlign = TextAlign.Center,
text = text,
color = ZcashTheme.colors.textPrimary
)
}
}

View File

@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.PagerState
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.Text
@ -64,10 +63,7 @@ fun PagerTabs(
onTabSelected: (index: Int) -> Unit = {},
) {
TabRow(
modifier =
modifier
.padding(horizontal = ZcashTheme.dimens.screenHorizontalSpacingBig)
.border(ZcashTheme.dimens.spacingTiny, ZcashTheme.colors.layoutStroke),
modifier = modifier.border(ZcashTheme.dimens.spacingTiny, ZcashTheme.colors.layoutStroke),
selectedTabIndex = pagerState.currentPage,
divider = {},
indicator = {},
@ -118,7 +114,7 @@ private fun PagerTab(
.fillMaxWidth()
.padding(horizontal = ZcashTheme.dimens.spacingXtiny),
text = title,
color = if (selected) ZcashTheme.colors.textCommon else MaterialTheme.colorScheme.onPrimary,
color = if (selected) ZcashTheme.colors.textPrimary else ZcashTheme.colors.textSecondary,
style = ZcashTheme.extendedTypography.restoringTopAppBarStyle,
textAlign = TextAlign.Center,
maxLines = 2,

View File

@ -19,14 +19,43 @@ import co.electriccoin.zcash.ui.design.theme.ZcashTheme
@Preview
@Composable
private fun ComposablePreview() {
private fun RadioButtonPreview() {
ZcashTheme(forceDarkMode = false) {
RadioButton(
text = "test",
selected = true,
onClick = {},
modifier = Modifier
)
BlankBgColumn {
RadioButton(
text = "test",
selected = false,
onClick = {},
modifier = Modifier
)
RadioButton(
text = "test",
selected = true,
onClick = {},
modifier = Modifier
)
}
}
}
@Preview
@Composable
private fun RadioButtonDarkPreview() {
ZcashTheme(forceDarkMode = true) {
BlankBgColumn {
RadioButton(
text = "Dark test",
selected = false,
onClick = {},
modifier = Modifier
)
RadioButton(
text = "Dark test",
selected = true,
onClick = {},
modifier = Modifier
)
}
}
}
@ -59,14 +88,14 @@ fun RadioButton(
onClick = onClick,
colors =
RadioButtonDefaults.colors(
selectedColor = ZcashTheme.colors.radioButtonColor,
unselectedColor = ZcashTheme.colors.radioButtonColor,
selectedColor = ZcashTheme.colors.secondaryColor,
unselectedColor = ZcashTheme.colors.secondaryColor,
)
)
Text(
text = text,
style = ZcashTheme.extendedTypography.radioButton,
color = ZcashTheme.colors.radioButtonTextColor,
color = ZcashTheme.colors.textPrimary,
modifier =
Modifier.padding(
top = 16.dp,

View File

@ -23,6 +23,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString
@ -93,14 +94,14 @@ fun Header(
text: String,
modifier: Modifier = Modifier,
textAlign: TextAlign = TextAlign.Start,
color: Color = ZcashTheme.colors.onBackgroundHeader,
color: Color = ZcashTheme.colors.textPrimary,
) {
Text(
text = text,
color = color,
textAlign = textAlign,
modifier = modifier,
style = ZcashTheme.typography.secondary.headlineLarge,
style = ZcashTheme.typography.primary.headlineLarge,
)
}
@ -109,7 +110,7 @@ fun SubHeader(
text: String,
modifier: Modifier = Modifier,
textAlign: TextAlign = TextAlign.Start,
color: Color = ZcashTheme.colors.onBackgroundHeader,
color: Color = ZcashTheme.colors.textPrimary,
) {
Text(
text = text,
@ -129,7 +130,7 @@ fun BodySmall(
overflow: TextOverflow = TextOverflow.Clip,
textAlign: TextAlign = TextAlign.Start,
textFontWeight: FontWeight = FontWeight.Normal,
color: Color = MaterialTheme.colorScheme.onBackground,
color: Color = ZcashTheme.colors.textPrimary,
) {
Text(
text = text,
@ -152,7 +153,7 @@ fun Body(
overflow: TextOverflow = TextOverflow.Clip,
textAlign: TextAlign = TextAlign.Start,
textFontWeight: FontWeight = FontWeight.Normal,
color: Color = MaterialTheme.colorScheme.onBackground,
color: Color = ZcashTheme.colors.textPrimary,
) {
Text(
text = text,
@ -174,7 +175,7 @@ fun TitleLarge(
maxLines: Int = Int.MAX_VALUE,
overflow: TextOverflow = TextOverflow.Clip,
textAlign: TextAlign = TextAlign.Start,
color: Color = MaterialTheme.colorScheme.onBackground,
color: Color = ZcashTheme.colors.textPrimary,
) {
Text(
text = text,
@ -196,7 +197,7 @@ fun Small(
maxLines: Int = Int.MAX_VALUE,
overflow: TextOverflow = TextOverflow.Clip,
textAlign: TextAlign = TextAlign.Start,
color: Color = MaterialTheme.colorScheme.onBackground,
color: Color = ZcashTheme.colors.textPrimary,
) {
Text(
text = text,
@ -218,7 +219,7 @@ fun Tiny(
maxLines: Int = Int.MAX_VALUE,
overflow: TextOverflow = TextOverflow.Clip,
textAlign: TextAlign = TextAlign.Start,
color: Color = MaterialTheme.colorScheme.onBackground,
color: Color = ZcashTheme.colors.textPrimary,
) {
Text(
text = text,
@ -234,15 +235,16 @@ fun Tiny(
@Composable
@Suppress("LongParameterList")
fun TextWithIcon(
text: String,
iconVector: ImageVector,
text: String,
modifier: Modifier = Modifier,
iconContentDescription: String? = null,
iconTintColor: Color? = null,
maxLines: Int = Int.MAX_VALUE,
overflow: TextOverflow = TextOverflow.Clip,
textAlign: TextAlign = TextAlign.Start,
style: TextStyle = LocalTextStyle.current,
color: Color = MaterialTheme.colorScheme.onBackground,
color: Color = ZcashTheme.colors.textPrimary,
) {
Row(
modifier =
@ -251,10 +253,18 @@ fun TextWithIcon(
.then(modifier),
verticalAlignment = Alignment.CenterVertically
) {
Image(
imageVector = iconVector,
contentDescription = iconContentDescription
)
if (iconTintColor != null) {
Image(
imageVector = iconVector,
colorFilter = ColorFilter.tint(color = iconTintColor),
contentDescription = iconContentDescription,
)
} else {
Image(
imageVector = iconVector,
contentDescription = iconContentDescription
)
}
Spacer(modifier = Modifier.padding(3.dp))
@ -402,7 +412,7 @@ fun BodyWithFiatCurrencySymbol(
Text(
text = amount,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onBackground,
color = ZcashTheme.colors.textPrimary,
modifier = modifier
)
}
@ -443,7 +453,7 @@ fun NavigationTabText(
},
maxLines = 1,
overflow = TextOverflow.Visible,
color = ZcashTheme.colors.textCommon,
color = ZcashTheme.colors.textPrimary,
modifier =
Modifier
.clip(RoundedCornerShape(ZcashTheme.dimens.regularRippleEffectCorner))

View File

@ -50,9 +50,10 @@ fun FormTextField(
keyboardOptions: KeyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
colors: TextFieldColors =
TextFieldDefaults.colors(
focusedContainerColor = ZcashTheme.colors.backgroundColor,
unfocusedContainerColor = ZcashTheme.colors.backgroundColor,
disabledContainerColor = ZcashTheme.colors.textDisabled,
cursorColor = ZcashTheme.colors.textPrimary,
focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent,
disabledContainerColor = Color.Transparent,
errorContainerColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,

View File

@ -56,6 +56,16 @@ private fun TopAppBarTextComposablePreview() {
}
}
@Preview
@Composable
private fun TopAppBarTextDarkComposablePreview() {
ZcashTheme(forceDarkMode = true) {
BlankSurface {
SmallTopAppBar(titleText = "Screen A", backText = "Back")
}
}
}
@Preview
@Composable
private fun TopAppBarTextRestoringComposablePreview() {
@ -108,6 +118,20 @@ private fun TopAppBarLogoRestoringComposablePreview() {
}
}
@Preview
@Composable
private fun TopAppBarLogoRestoringDarkComposablePreview() {
ZcashTheme(forceDarkMode = true) {
BlankSurface {
SmallTopAppBar(
showTitleLogo = true,
backText = "Back",
subTitle = "[RESTORING YOUR WALLET…]"
)
}
}
}
@Preview
@Composable
private fun TopAppBarRegularMenuComposablePreview() {

View File

@ -24,6 +24,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.painter.ColorPainter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
@ -68,6 +69,7 @@ fun WelcomeAnimationAutostart(
private const val LOGO_RELATIVE_LOCATION = 0.2f
@Composable
@Suppress("LongMethod")
fun WelcomeAnimation(
animationState: Boolean,
modifier: Modifier = Modifier,
@ -111,6 +113,7 @@ fun WelcomeAnimation(
Image(
painter = painterResource(id = R.drawable.chart_line),
contentScale = ContentScale.FillBounds,
colorFilter = ColorFilter.tint(color = ZcashTheme.colors.welcomeAnimationColor),
contentDescription = null,
)
}

View File

@ -84,7 +84,7 @@ private val defaultDimens =
buttonHeightSmall = 38.dp,
gridCellSize = 14.dp,
gridLineWidth = 1.dp,
chipShadowElevation = 4.dp,
chipShadowElevation = 2.dp,
chipStroke = 0.5.dp,
circularScreenProgressWidth = 48.dp,
circularMidProgressWidth = 22.dp,

View File

@ -2,19 +2,22 @@ package co.electriccoin.zcash.ui.design.theme
import androidx.compose.runtime.Immutable
import androidx.compose.ui.graphics.Color
import co.electriccoin.zcash.ui.design.theme.internal.ButtonColors
import co.electriccoin.zcash.ui.design.theme.internal.TopAppBarColors
@Immutable
data class ExtendedColors(
val primaryColor: Color,
val secondaryColor: Color,
val backgroundColor: Color,
val gridColor: Color,
val onBackgroundHeader: Color,
val circularProgressBarSmall: Color,
val circularProgressBarSmallDark: Color,
val circularProgressBarScreen: Color,
val linearProgressBarTrack: Color,
val linearProgressBarBackground: Color,
val textCommon: Color,
val textPrimary: Color,
val textSecondary: Color,
val textDescription: Color,
val textDisabled: Color,
val textFieldHint: Color,
@ -22,22 +25,27 @@ data class ExtendedColors(
val textFieldFrame: Color,
val textDescriptionDark: Color,
val layoutStroke: Color,
val layoutStrokeSecondary: Color,
val overlay: Color,
val overlayProgressBar: Color,
val reference: Color,
val disabledButtonColor: Color,
val disabledButtonTextColor: Color,
val primaryButtonColors: ButtonColors,
val secondaryButtonColors: ButtonColors,
val tertiaryButtonColors: ButtonColors,
val welcomeAnimationColor: Color,
val complementaryColor: Color,
val dividerColor: Color,
val darkDividerColor: Color,
val primaryDividerColor: Color,
val secondaryDividerColor: Color,
val tertiaryDividerColor: Color,
val panelBackgroundColor: Color,
val panelBackgroundColorActive: Color,
val cameraDisabledBackgroundColor: Color,
val cameraDisabledFrameColor: Color,
val radioButtonColor: Color,
val radioButtonTextColor: Color,
val historyBackgroundColor: Color,
val historyMessageBubbleColor: Color,
val historyMessageBubbleStrokeColor: Color,
val historyRedColor: Color,
val historySyncingColor: Color,
val topAppBarColors: TopAppBarColors,
val transparentTopAppBarColors: TopAppBarColors
val transparentTopAppBarColors: TopAppBarColors,
)

View File

@ -0,0 +1,123 @@
@file:Suppress("MagicNumber")
package co.electriccoin.zcash.ui.design.theme.internal
import androidx.compose.runtime.Immutable
import androidx.compose.ui.graphics.Color
@Immutable
interface ButtonColors {
val containerColor: Color
val disabledContainerColor: Color
val shadowColor: Color
val disabledShadowColor: Color
val textColor: Color
val disabledTextColor: Color
val strokeColor: Color
val disabledStrokeColor: Color
val shadowStrokeColor: Color
val shadowDisabledStrokeColor: Color
}
@Immutable
internal data class DefaultButtonColors(
override val containerColor: Color = Color.Unspecified,
override val disabledContainerColor: Color = Color.Unspecified,
override val shadowColor: Color = Color.Unspecified,
override val disabledShadowColor: Color = Color.Unspecified,
override val textColor: Color = Color.Unspecified,
override val disabledTextColor: Color = Color.Unspecified,
override val strokeColor: Color = Color.Unspecified,
override val disabledStrokeColor: Color = Color.Unspecified,
override val shadowStrokeColor: Color = Color.Unspecified,
override val shadowDisabledStrokeColor: Color = Color.Unspecified,
) : ButtonColors
// LIGHT THEME BUTTONS:
@Immutable
internal data class LightPrimaryButtonColors(
override val containerColor: Color = Color(0xFF000000),
override val disabledContainerColor: Color = Color(0xFFB7B7B7),
override val shadowColor: Color = Color(0xFFFFFFFF),
override val disabledShadowColor: Color = Color(0xFFFFFFFF),
override val textColor: Color = Color(0xFFFFFFFF),
override val disabledTextColor: Color = Color(0xFFDDDDDD),
override val strokeColor: Color = Color(0xFF000000),
override val disabledStrokeColor: Color = Color(0xFF000000),
override val shadowStrokeColor: Color = Color(0xFF000000),
override val shadowDisabledStrokeColor: Color = Color(0xFF000000),
) : ButtonColors
@Immutable
internal data class LightSecondaryButtonColors(
override val containerColor: Color = Color(0xFFFFFFFF),
override val disabledContainerColor: Color = Color(0xFFFFFFFF),
override val shadowColor: Color = Color(0xFF000000),
override val disabledShadowColor: Color = Color(0xFFFFFFFF),
override val textColor: Color = Color(0xFF000000),
override val disabledTextColor: Color = Color(0xFFDDDDDD),
override val strokeColor: Color = Color(0xFF000000),
override val disabledStrokeColor: Color = Color(0xFF000000),
override val shadowStrokeColor: Color = Color(0xFFE6E7E8),
override val shadowDisabledStrokeColor: Color = Color(0xFF000000),
) : ButtonColors
// Currently the same as Light-Primary version
@Immutable
internal data class LightTertiaryButtonColors(
override val containerColor: Color = Color(0xFF000000),
override val disabledContainerColor: Color = Color(0xFFB7B7B7),
override val shadowColor: Color = Color(0xFFFFFFFF),
override val disabledShadowColor: Color = Color(0xFFFFFFFF),
override val textColor: Color = Color(0xFFFFFFFF),
override val disabledTextColor: Color = Color(0xFFDDDDDD),
override val strokeColor: Color = Color(0xFF000000),
override val disabledStrokeColor: Color = Color(0xFF000000),
override val shadowStrokeColor: Color = Color(0xFF000000),
override val shadowDisabledStrokeColor: Color = Color(0xFF000000),
) : ButtonColors
// DARK THEME BUTTONS:
@Immutable
internal data class DarkPrimaryButtonColors(
override val containerColor: Color = Color(0xFF181716),
override val disabledContainerColor: Color = Color(0xFF4D4D4D),
override val shadowColor: Color = Color(0xFF181716),
override val disabledShadowColor: Color = Color(0xFF181716),
override val textColor: Color = Color(0xFFFFFFFF),
override val disabledTextColor: Color = Color(0xFFFFFFFF),
override val strokeColor: Color = Color(0xFFFFFFFF),
override val disabledStrokeColor: Color = Color(0xFFFFFFFF),
override val shadowStrokeColor: Color = Color(0xFFFFFFFF),
override val shadowDisabledStrokeColor: Color = Color(0xFFFFFFFF),
) : ButtonColors
@Immutable
internal data class DarkSecondaryButtonColors(
override val containerColor: Color = Color(0xFF181716),
override val disabledContainerColor: Color = Color(0xFFFFFFFF),
override val shadowColor: Color = Color(0xFF4D4D4D),
override val disabledShadowColor: Color = Color(0xFFFFFFFF),
override val textColor: Color = Color(0xFFFFFFFF),
override val disabledTextColor: Color = Color(0xFFB7B7B7),
override val strokeColor: Color = Color(0xFFFFFFFF),
override val disabledStrokeColor: Color = Color(0xFF000000),
override val shadowStrokeColor: Color = Color(0xFFFFFFFF),
override val shadowDisabledStrokeColor: Color = Color(0xFF000000),
) : ButtonColors
@Immutable
internal data class DarkTertiaryButtonColors(
override val containerColor: Color = Color(0xFFFFFFFF),
override val disabledContainerColor: Color = Color(0xFFFFFFFF),
override val shadowColor: Color = Color(0xFF000000),
override val disabledShadowColor: Color = Color(0xFFFFFFFF),
override val textColor: Color = Color(0xFF000000),
override val disabledTextColor: Color = Color(0xFFDDDDDD),
override val strokeColor: Color = Color(0xFF000000),
override val disabledStrokeColor: Color = Color(0xFF000000),
override val shadowStrokeColor: Color = Color(0xFFE6E7E8),
override val shadowDisabledStrokeColor: Color = Color(0xFF000000),
) : ButtonColors

View File

@ -8,108 +8,111 @@ import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.Color
import co.electriccoin.zcash.ui.design.theme.ExtendedColors
// TODO [#998]: Check and enhance screen dark mode
// TODO [#998]: https://github.com/Electric-Coin-Company/zashi-android/issues/998
internal object Dark {
val backgroundColor = Color(0xFF231F20)
val primaryColor = Color(0xFF231F20)
val secondaryColor = Color(0xFFFFFFFF)
val backgroundColor = primaryColor
val gridColor = Color(0xFF272727)
val textHeaderOnBackground = Color(0xFFFFFFFF)
val textBodyOnBackground = Color(0xFFFFFFFF)
val textPrimaryButton = Color(0xFF000000)
val textSecondaryButton = Color(0xFF000000)
val textCommon = Color(0xFFFFFFFF)
val textDisabled = Color(0xFFB7B7B7)
val textFieldFrame = Color(0xFF231F20)
val textFieldWarning = Color(0xFFF40202)
val textPrimary = secondaryColor
val textSecondary = primaryColor
val textDisabled = Color(0xFF4D4D4D)
val textFieldFrame = Color(0xFFFFFFFF)
val textFieldWarning = Color(0xFFFE5858)
val textFieldHint = Color(0xFFB7B7B7)
val textDescription = Color(0xFF777777)
val textDescriptionDark = Color(0xFF4D4D4D)
val textDescription = Color(0xFFC1C1C1)
val textDescriptionDark = Color(0xFFFFFFFF)
val reference = Color(0xFFFFFFFF)
val welcomeAnimationColor = Color(0xFF231F20)
val welcomeAnimationColor = Color(0xFF181716)
val complementaryColor = Color(0xFFF4B728)
val dividerColor = Color(0xFFDDDDDD)
val darkDividerColor = Color(0xFF000000)
val primaryDividerColor = Color(0xFF4D4D4D)
val secondaryDividerColor = Color(0xFFFFFFFF)
val tertiaryDividerColor = Color(0xFF4D4D4D)
val panelBackgroundColor = Color(0xFF262324)
val panelBackgroundColorActive = Color(0xFF000000)
val layoutStroke = Color(0xFFFFFFFF)
val panelBackgroundColor = Color(0xFFF6F6F6)
val cameraDisabledBackgroundColor = Color(0xFF5E5C5C)
val cameraDisabledFrameColor = Color(0xFFFFFFFF)
val layoutStrokeSecondary = Color(0xFFDDDDDD)
val cameraDisabledBackgroundColor = Color(0xFF000000)
val cameraDisabledFrameColor = Color(0xFF5E5C5C)
val primaryButton = Color(0xFFFFFFFF)
val secondaryButton = Color(0xFFFFFFFF)
val primaryButtonColors = DarkPrimaryButtonColors()
val secondaryButtonColors = DarkSecondaryButtonColors()
val tertiaryButtonColors = DarkTertiaryButtonColors()
val radioButtonColor = Color(0xFF070707)
val radioButtonTextColor = Color(0xFF4E4E4E)
val circularProgressBarSmall = Color(0xFF8B8A8A)
val circularProgressBarSmallDark = textBodyOnBackground
val circularProgressBarSmall = Color(0xFFFFFFFF)
val circularProgressBarSmallDark = Color(0xFFFFFFFF)
val circularProgressBarScreen = Color(0xFFFFFFFF)
val linearProgressBarTrack = Color(0xFFD9D9D9)
val linearProgressBarTrack = Color(0xFFDDDDDD)
val linearProgressBarBackground = complementaryColor
val overlay = Color(0x22000000)
val overlayProgressBar = Color(0xFFFFFFFF)
val reference = Color(0xFFFFFFFF)
val disabledButtonColor = Color(0xFFB7B7B7)
val disabledButtonTextColor = Color(0xFFDDDDDD)
val historyBackgroundColor = Color(0xFFF6F6F6)
val historyBackgroundColor = Color(0xFF262324)
val historyRedColor = textFieldWarning
val historySyncingColor = panelBackgroundColor
val historySyncingColor = Color(0xFF181716)
val historyMessageBubbleColor = Color(0xFF000000)
val historyMessageBubbleStrokeColor = Color(0xFF000000)
val topAppBarColors = DarkTopAppBarColors()
val transparentTopAppBarColors = TransparentTopAppBarColors()
}
internal object Light {
val backgroundColor = Color(0xFFFFFFFF)
val primaryColor = Color(0xFFFFFFFF)
val secondaryColor = Color(0xFF000000)
val backgroundColor = primaryColor
val gridColor = Color(0xFFFBFBFB)
val textHeaderOnBackground = Color(0xFF000000)
val textBodyOnBackground = Color(0xFF000000)
val textPrimaryButton = Color(0xFFFFFFFF)
val textSecondaryButton = Color(0xFF000000)
val textCommon = Color(0xFF000000)
val textPrimary = secondaryColor
val textSecondary = primaryColor
val textDisabled = Color(0xFFB7B7B7)
val textFieldFrame = Color(0xFF231F20)
val textFieldFrame = Color(0xFF000000)
val textFieldWarning = Color(0xFFF40202)
val textFieldHint = Color(0xFFB7B7B7)
val textDescription = Color(0xFF777777)
val textDescriptionDark = Color(0xFF4D4D4D)
val reference = Color(0xFF000000)
val welcomeAnimationColor = Color(0xFF231F20)
val complementaryColor = Color(0xFFF4B728)
val dividerColor = Color(0xFFDDDDDD)
val darkDividerColor = Color(0xFF000000)
val layoutStroke = Color(0xFF000000)
val primaryDividerColor = Color(0xFFDDDDDD)
val secondaryDividerColor = Color(0xFF000000)
val tertiaryDividerColor = Color(0xFF000000)
val panelBackgroundColor = Color(0xFFEBEBEB)
val panelBackgroundColorActive = Color(0xFFFFFFFF)
val layoutStroke = Color(0xFF000000)
val layoutStrokeSecondary = Color(0xFFDDDDDD)
val cameraDisabledBackgroundColor = Color(0xFF5E5C5C)
val cameraDisabledFrameColor = Color(0xFFFFFFFF)
val primaryButton = Color(0xFF000000)
val secondaryButton = Color(0xFFFFFFFF)
val radioButtonColor = Color(0xFF070707)
val radioButtonTextColor = Color(0xFF4E4E4E)
val primaryButtonColors = LightPrimaryButtonColors()
val secondaryButtonColors = LightSecondaryButtonColors()
val tertiaryButtonColors = LightTertiaryButtonColors()
val circularProgressBarSmall = Color(0xFF8B8A8A)
val circularProgressBarSmallDark = textPrimary
val circularProgressBarScreen = Color(0xFF000000)
val circularProgressBarSmallDark = textBodyOnBackground
val linearProgressBarTrack = Color(0xFFD9D9D9)
val linearProgressBarTrack = Color(0xFFDDDDDD)
val linearProgressBarBackground = complementaryColor
val overlay = Color(0x22000000)
val reference = Color(0xFF000000)
val disabledButtonColor = Color(0xFFB7B7B7)
val disabledButtonTextColor = Color(0xFFDDDDDD)
val overlayProgressBar = Color(0xFFFFFFFF)
val historyBackgroundColor = Color(0xFFF6F6F6)
val historyRedColor = textFieldWarning
val historySyncingColor = panelBackgroundColor
val historySyncingColor = Color(0xFFEBEBEB)
val historyMessageBubbleColor = Color(0xFFDDDDDD)
val historyMessageBubbleStrokeColor = Color(0xFF000000)
val topAppBarColors = LightTopAppBarColors()
val transparentTopAppBarColors = TransparentTopAppBarColors()
@ -117,39 +120,43 @@ internal object Light {
internal val DarkColorPalette =
darkColorScheme(
primary = Dark.primaryButton,
secondary = Dark.secondaryButton,
onPrimary = Dark.textPrimaryButton,
onSecondary = Dark.textSecondaryButton,
// Our colors intentionally use a different naming than the ones from MaterialTheme
primary = Dark.textPrimary,
secondary = Dark.secondaryColor,
onPrimary = Dark.textPrimary,
onSecondary = Dark.textSecondary,
surface = Dark.backgroundColor,
onSurface = Dark.textBodyOnBackground,
onSurface = Dark.textPrimary,
background = Dark.backgroundColor,
onBackground = Dark.textBodyOnBackground,
onBackground = Dark.textPrimary,
)
internal val LightColorPalette =
lightColorScheme(
primary = Light.primaryButton,
secondary = Light.secondaryButton,
onPrimary = Light.textPrimaryButton,
onSecondary = Light.textSecondaryButton,
// Our colors intentionally use a different naming than the ones from MaterialTheme
primary = Light.textPrimary,
secondary = Light.secondaryColor,
onPrimary = Light.textPrimary,
onSecondary = Light.textSecondary,
surface = Light.backgroundColor,
onSurface = Light.textBodyOnBackground,
onSurface = Light.textPrimary,
background = Light.backgroundColor,
onBackground = Light.textBodyOnBackground,
onBackground = Light.textPrimary,
)
internal val DarkExtendedColorPalette =
ExtendedColors(
primaryColor = Dark.primaryColor,
secondaryColor = Dark.secondaryColor,
backgroundColor = Dark.backgroundColor,
gridColor = Dark.gridColor,
onBackgroundHeader = Dark.textHeaderOnBackground,
circularProgressBarSmall = Dark.circularProgressBarSmall,
circularProgressBarSmallDark = Dark.circularProgressBarSmallDark,
circularProgressBarScreen = Dark.circularProgressBarScreen,
linearProgressBarTrack = Dark.linearProgressBarTrack,
linearProgressBarBackground = Dark.linearProgressBarBackground,
textCommon = Dark.textCommon,
textPrimary = Dark.textPrimary,
textSecondary = Dark.textSecondary,
textDisabled = Dark.textDisabled,
textFieldFrame = Dark.textFieldFrame,
textFieldWarning = Dark.textFieldWarning,
@ -157,37 +164,44 @@ internal val DarkExtendedColorPalette =
textDescription = Dark.textDescription,
textDescriptionDark = Dark.textDescriptionDark,
layoutStroke = Dark.layoutStroke,
layoutStrokeSecondary = Dark.layoutStrokeSecondary,
overlay = Dark.overlay,
disabledButtonTextColor = Dark.disabledButtonTextColor,
disabledButtonColor = Dark.disabledButtonColor,
overlayProgressBar = Dark.overlayProgressBar,
reference = Dark.reference,
welcomeAnimationColor = Dark.welcomeAnimationColor,
complementaryColor = Dark.complementaryColor,
dividerColor = Dark.dividerColor,
darkDividerColor = Dark.darkDividerColor,
primaryDividerColor = Dark.primaryDividerColor,
secondaryDividerColor = Dark.secondaryDividerColor,
tertiaryDividerColor = Dark.tertiaryDividerColor,
panelBackgroundColor = Dark.panelBackgroundColor,
panelBackgroundColorActive = Dark.panelBackgroundColorActive,
cameraDisabledBackgroundColor = Dark.cameraDisabledBackgroundColor,
cameraDisabledFrameColor = Dark.cameraDisabledFrameColor,
radioButtonColor = Dark.radioButtonColor,
radioButtonTextColor = Dark.radioButtonTextColor,
historyBackgroundColor = Dark.historyBackgroundColor,
historyRedColor = Dark.historyRedColor,
historySyncingColor = Dark.historySyncingColor,
historyMessageBubbleColor = Dark.historyMessageBubbleColor,
historyMessageBubbleStrokeColor = Dark.historyMessageBubbleStrokeColor,
topAppBarColors = Dark.topAppBarColors,
transparentTopAppBarColors = Dark.transparentTopAppBarColors
transparentTopAppBarColors = Dark.transparentTopAppBarColors,
primaryButtonColors = Dark.primaryButtonColors,
secondaryButtonColors = Dark.secondaryButtonColors,
tertiaryButtonColors = Dark.tertiaryButtonColors,
)
internal val LightExtendedColorPalette =
ExtendedColors(
primaryColor = Light.primaryColor,
secondaryColor = Light.secondaryColor,
backgroundColor = Light.backgroundColor,
gridColor = Light.gridColor,
onBackgroundHeader = Light.textHeaderOnBackground,
circularProgressBarScreen = Light.circularProgressBarScreen,
circularProgressBarSmall = Light.circularProgressBarSmall,
circularProgressBarSmallDark = Light.circularProgressBarSmallDark,
linearProgressBarTrack = Light.linearProgressBarTrack,
linearProgressBarBackground = Light.linearProgressBarBackground,
textCommon = Light.textCommon,
textPrimary = Light.textPrimary,
textSecondary = Light.textSecondary,
textDisabled = Light.textDisabled,
textFieldFrame = Light.textFieldFrame,
textFieldWarning = Light.textFieldWarning,
@ -195,39 +209,46 @@ internal val LightExtendedColorPalette =
textDescription = Light.textDescription,
textDescriptionDark = Light.textDescriptionDark,
layoutStroke = Light.layoutStroke,
layoutStrokeSecondary = Light.layoutStrokeSecondary,
overlay = Light.overlay,
disabledButtonTextColor = Light.disabledButtonTextColor,
disabledButtonColor = Light.disabledButtonColor,
overlayProgressBar = Light.overlayProgressBar,
reference = Light.reference,
welcomeAnimationColor = Light.welcomeAnimationColor,
complementaryColor = Light.complementaryColor,
dividerColor = Light.dividerColor,
darkDividerColor = Light.darkDividerColor,
primaryDividerColor = Light.primaryDividerColor,
secondaryDividerColor = Light.secondaryDividerColor,
tertiaryDividerColor = Light.tertiaryDividerColor,
panelBackgroundColor = Light.panelBackgroundColor,
panelBackgroundColorActive = Light.panelBackgroundColorActive,
cameraDisabledBackgroundColor = Light.cameraDisabledBackgroundColor,
cameraDisabledFrameColor = Light.cameraDisabledFrameColor,
radioButtonColor = Light.radioButtonColor,
radioButtonTextColor = Light.radioButtonTextColor,
historyBackgroundColor = Light.historyBackgroundColor,
historyRedColor = Light.historyRedColor,
historySyncingColor = Light.historySyncingColor,
historyMessageBubbleColor = Light.historyMessageBubbleColor,
historyMessageBubbleStrokeColor = Light.historyMessageBubbleStrokeColor,
topAppBarColors = Light.topAppBarColors,
transparentTopAppBarColors = Light.transparentTopAppBarColors
transparentTopAppBarColors = Light.transparentTopAppBarColors,
primaryButtonColors = Light.primaryButtonColors,
secondaryButtonColors = Light.secondaryButtonColors,
tertiaryButtonColors = Light.tertiaryButtonColors,
)
@Suppress("CompositionLocalAllowlist")
internal val LocalExtendedColors =
staticCompositionLocalOf {
ExtendedColors(
primaryColor = Color.Unspecified,
secondaryColor = Color.Unspecified,
backgroundColor = Color.Unspecified,
gridColor = Color.Unspecified,
onBackgroundHeader = Color.Unspecified,
circularProgressBarScreen = Color.Unspecified,
circularProgressBarSmall = Color.Unspecified,
circularProgressBarSmallDark = Color.Unspecified,
linearProgressBarTrack = Color.Unspecified,
linearProgressBarBackground = Color.Unspecified,
textCommon = Color.Unspecified,
textPrimary = Color.Unspecified,
textSecondary = Color.Unspecified,
textDisabled = Color.Unspecified,
textFieldHint = Color.Unspecified,
textFieldWarning = Color.Unspecified,
@ -235,23 +256,28 @@ internal val LocalExtendedColors =
textDescription = Color.Unspecified,
textDescriptionDark = Color.Unspecified,
layoutStroke = Color.Unspecified,
layoutStrokeSecondary = Color.Unspecified,
overlay = Color.Unspecified,
disabledButtonTextColor = Color.Unspecified,
disabledButtonColor = Color.Unspecified,
overlayProgressBar = Color.Unspecified,
reference = Color.Unspecified,
welcomeAnimationColor = Color.Unspecified,
complementaryColor = Color.Unspecified,
dividerColor = Color.Unspecified,
darkDividerColor = Color.Unspecified,
primaryDividerColor = Color.Unspecified,
secondaryDividerColor = Color.Unspecified,
tertiaryDividerColor = Color.Unspecified,
panelBackgroundColor = Color.Unspecified,
panelBackgroundColorActive = Color.Unspecified,
cameraDisabledBackgroundColor = Color.Unspecified,
cameraDisabledFrameColor = Color.Unspecified,
radioButtonColor = Color.Unspecified,
radioButtonTextColor = Color.Unspecified,
historyBackgroundColor = Color.Unspecified,
historyRedColor = Color.Unspecified,
historySyncingColor = Color.Unspecified,
historyMessageBubbleColor = Color.Unspecified,
historyMessageBubbleStrokeColor = Color.Unspecified,
topAppBarColors = DefaultTopAppBarColors(),
transparentTopAppBarColors = DefaultTopAppBarColors(),
primaryButtonColors = DefaultButtonColors(),
secondaryButtonColors = DefaultButtonColors(),
tertiaryButtonColors = DefaultButtonColors(),
)
}

View File

@ -81,10 +81,10 @@ internal data class LightTopAppBarColors(
@Immutable
internal data class DarkTopAppBarColors(
override val containerColor: Color = Color(0xFF000000),
override val containerColor: Color = Color(0xFF231F20),
override val navigationColor: Color = Color(0xFFFFFFFF),
override val titleColor: Color = Color(0xFFFFFFFF),
override val subTitleColor: Color = Color(0xFF8A8888),
override val subTitleColor: Color = Color(0xFFFFFFFF),
override val actionColor: Color = Color(0xFFFFFFFF),
) : TopAppBarColors {
override fun copyColors(

View File

@ -57,8 +57,8 @@ internal val PrimaryTypography =
headlineLarge =
TextStyle(
fontFamily = InterFontFamily,
fontWeight = FontWeight.SemiBold,
fontSize = 30.sp
fontWeight = FontWeight.Bold,
fontSize = 22.sp
),
titleSmall =
TextStyle(
@ -194,7 +194,6 @@ data class ExtendedTypography(
val transactionItemStyles: TransactionItemTextStyles,
val restoringTopAppBarStyle: TextStyle,
val deleteWalletWarnStyle: TextStyle,
val updateTitleStyle: TextStyle,
)
@Suppress("CompositionLocalAllowlist")
@ -379,9 +378,5 @@ val LocalExtendedTypography =
PrimaryTypography.bodyLarge.copy(
fontWeight = FontWeight.Bold
),
updateTitleStyle =
PrimaryTypography.titleLarge.copy(
fontWeight = FontWeight.Bold
)
)
}

View File

@ -4,6 +4,7 @@ import android.content.Intent
import android.provider.Settings
import androidx.test.filters.SmallTest
import co.electriccoin.zcash.ui.test.getAppContext
import co.electriccoin.zcash.ui.util.SettingsUtil
import org.junit.Test
import kotlin.test.assertContains
import kotlin.test.assertEquals

View File

@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.Lifecycle
@ -50,7 +49,6 @@ import co.electriccoin.zcash.ui.screen.onboarding.WrapOnboarding
import co.electriccoin.zcash.ui.screen.onboarding.persistExistingWalletWithSeedPhrase
import co.electriccoin.zcash.ui.screen.securitywarning.WrapSecurityWarning
import co.electriccoin.zcash.ui.screen.support.WrapSupport
import co.electriccoin.zcash.ui.screen.warning.WrapNotEnoughSpace
import co.electriccoin.zcash.ui.screen.warning.viewmodel.StorageCheckViewModel
import co.electriccoin.zcash.work.WorkIds
import kotlinx.coroutines.delay
@ -68,7 +66,6 @@ class MainActivity : AppCompatActivity() {
val walletViewModel by viewModels<WalletViewModel>()
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
val storageCheckViewModel by viewModels<StorageCheckViewModel>()
internal val authenticationViewModel by viewModels<AuthenticationViewModel> {
@ -138,13 +135,7 @@ class MainActivity : AppCompatActivity() {
.fillMaxHeight()
) {
BindCompLocalProvider {
val isEnoughSpace by storageCheckViewModel.isEnoughSpace.collectAsStateWithLifecycle()
if (isEnoughSpace == false) {
WrapNotEnoughSpace()
} else {
MainContent()
}
MainContent()
AuthenticationForAppAccess()
}
}

View File

@ -1,6 +1,7 @@
package co.electriccoin.zcash.ui
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.lifecycle.LifecycleCoroutineScope
@ -29,6 +30,7 @@ import co.electriccoin.zcash.ui.NavigationTargets.CHOOSE_SERVER
import co.electriccoin.zcash.ui.NavigationTargets.DELETE_WALLET
import co.electriccoin.zcash.ui.NavigationTargets.EXPORT_PRIVATE_DATA
import co.electriccoin.zcash.ui.NavigationTargets.HOME
import co.electriccoin.zcash.ui.NavigationTargets.NOT_ENOUGH_SPACE
import co.electriccoin.zcash.ui.NavigationTargets.SCAN
import co.electriccoin.zcash.ui.NavigationTargets.SEED_RECOVERY
import co.electriccoin.zcash.ui.NavigationTargets.SEND_CONFIRMATION
@ -60,6 +62,7 @@ import co.electriccoin.zcash.ui.screen.sendconfirmation.model.SendConfirmationSt
import co.electriccoin.zcash.ui.screen.settings.WrapSettings
import co.electriccoin.zcash.ui.screen.support.WrapSupport
import co.electriccoin.zcash.ui.screen.update.WrapCheckForUpdate
import co.electriccoin.zcash.ui.screen.warning.WrapNotEnoughSpace
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.launch
@ -247,6 +250,12 @@ internal fun MainActivity.Navigation() {
)
}
}
composable(NOT_ENOUGH_SPACE) {
WrapNotEnoughSpace(
goPrevious = { navController.popBackStackJustOnce(NOT_ENOUGH_SPACE) },
goSettings = { navController.navigateJustOnce(SETTINGS) }
)
}
}
}
@ -291,11 +300,15 @@ private fun MainActivity.NavigationHome(
},
)
val isEnoughSpace by storageCheckViewModel.isEnoughSpace.collectAsStateWithLifecycle()
val sdkStatus = walletViewModel.walletSnapshot.collectAsStateWithLifecycle().value?.status
if (Synchronizer.Status.DISCONNECTED == sdkStatus) {
if (isEnoughSpace == false) {
Twig.info { "Not enough free space" }
navController.navigateJustOnce(NOT_ENOUGH_SPACE)
} else if (Synchronizer.Status.DISCONNECTED == sdkStatus) {
Twig.info { "Disconnected state received from Synchronizer" }
WrapDisconnected(
goChooseServer = {
navController.navigateJustOnce(CHOOSE_SERVER)
@ -305,6 +318,7 @@ private fun MainActivity.NavigationHome(
}
)
} else if (ConfigurationEntries.IS_APP_UPDATE_CHECK_ENABLED.getValue(RemoteConfig.current)) {
Twig.info { "App update available" }
WrapCheckForUpdate()
}
}
@ -421,6 +435,7 @@ object NavigationTargets {
const val EXPORT_PRIVATE_DATA = "export_private_data"
const val HOME = "home"
const val CHOOSE_SERVER = "choose_server"
const val NOT_ENOUGH_SPACE = "not_enough_space"
const val SCAN = "scan"
const val SEED_RECOVERY = "seed_recovery"
const val SEND_CONFIRMATION = "send_confirmation"

View File

@ -113,7 +113,10 @@ fun StatusDialog(
Column(
Modifier.verticalScroll(rememberScrollState())
) {
Text(text = statusAction.details)
Text(
text = statusAction.details,
color = ZcashTheme.colors.textPrimary,
)
}
},
confirmButtonText = stringResource(id = R.string.balances_status_dialog_button),

View File

@ -28,6 +28,7 @@ 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.graphics.ColorFilter
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@ -183,14 +184,17 @@ fun AboutMainContent(
) {
Image(
painter = painterResource(id = co.electriccoin.zcash.ui.design.R.drawable.zashi_logo_without_text),
colorFilter = ColorFilter.tint(color = ZcashTheme.colors.secondaryColor),
contentDescription = null,
Modifier
.height(ZcashTheme.dimens.inScreenZcashLogoHeight)
.width(ZcashTheme.dimens.inScreenZcashLogoWidth)
modifier =
Modifier
.height(ZcashTheme.dimens.inScreenZcashLogoHeight)
.width(ZcashTheme.dimens.inScreenZcashLogoWidth)
)
Spacer(modifier = Modifier.width(ZcashTheme.dimens.spacingDefault))
Image(
painter = painterResource(id = co.electriccoin.zcash.ui.design.R.drawable.zashi_text_logo),
colorFilter = ColorFilter.tint(color = ZcashTheme.colors.secondaryColor),
contentDescription = null,
modifier = Modifier.height(ZcashTheme.dimens.inScreenZcashTextLogoHeight)
)

View File

@ -188,7 +188,7 @@ private fun AccountMainContent(
.padding(horizontal = ZcashTheme.dimens.screenHorizontalSpacingRegular)
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingUpLarge))
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
HistoryContainer(
onStatusClick = onStatusClick,

View File

@ -3,6 +3,7 @@
package co.electriccoin.zcash.ui.screen.account.view
import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@ -27,6 +28,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.pluralStringResource
@ -197,7 +199,7 @@ private fun EmptyTransactionHistory() {
textAlign = TextAlign.Center,
text = stringResource(id = R.string.account_history_empty),
style = ZcashTheme.extendedTypography.transactionItemStyles.titleRegular,
color = ZcashTheme.colors.textCommon,
color = ZcashTheme.colors.textPrimary,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
@ -220,7 +222,7 @@ private fun HistoryList(
)
HorizontalDivider(
color = ZcashTheme.colors.dividerColor,
color = ZcashTheme.colors.primaryDividerColor,
thickness = DividerDefaults.Thickness,
modifier = Modifier.padding(horizontal = ZcashTheme.dimens.spacingDefault)
)
@ -359,7 +361,9 @@ private fun HistoryItem(
) {
Image(
imageVector = typeIcon,
contentDescription = typeText
colorFilter = ColorFilter.tint(color = ZcashTheme.colors.secondaryColor),
contentDescription = typeText,
modifier = Modifier.padding(top = ZcashTheme.dimens.spacingTiny)
)
Spacer(modifier = Modifier.width(ZcashTheme.dimens.spacingDefault))
@ -449,7 +453,7 @@ private fun HistoryItemCollapsedMainPart(
if (transaction.overview.isSentTransaction) {
ZcashTheme.colors.historyRedColor
} else {
ZcashTheme.colors.textCommon
ZcashTheme.colors.textPrimary
}
}
@ -546,7 +550,7 @@ private fun HistoryItemExpandedAddressPart(
Text(
text = recipient.addressValue,
style = ZcashTheme.extendedTypography.transactionItemStyles.content,
color = ZcashTheme.colors.textCommon,
color = ZcashTheme.colors.textPrimary,
modifier =
Modifier
.fillMaxWidth(EXPANDED_ADDRESS_WIDTH_RATIO)
@ -559,6 +563,7 @@ private fun HistoryItemExpandedAddressPart(
style = ZcashTheme.extendedTypography.transactionItemStyles.content,
color = ZcashTheme.colors.textDescription,
iconVector = ImageVector.vectorResource(R.drawable.ic_trx_copy),
iconTintColor = ZcashTheme.colors.secondaryColor,
modifier =
Modifier
.clip(RoundedCornerShape(ZcashTheme.dimens.regularRippleEffectCorner))
@ -608,7 +613,7 @@ private fun HistoryItemExpandedPart(
count = transaction.messages!!.size
),
style = ZcashTheme.extendedTypography.transactionItemStyles.contentMedium,
color = ZcashTheme.colors.textCommon
color = ZcashTheme.colors.textPrimary
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
@ -632,7 +637,7 @@ private fun HistoryItemExpandedPart(
Text(
text = stringResource(id = R.string.account_history_item_no_message),
style = ZcashTheme.extendedTypography.transactionItemStyles.contentItalic,
color = ZcashTheme.colors.textCommon,
color = ZcashTheme.colors.textPrimary,
modifier = Modifier.fillMaxWidth(EXPANDED_TRANSACTION_WIDTH_RATIO)
)
@ -708,7 +713,7 @@ private fun HistoryItemTransactionIdPart(
Text(
text = txIdString,
style = ZcashTheme.extendedTypography.transactionItemStyles.content,
color = ZcashTheme.colors.textCommon,
color = ZcashTheme.colors.textPrimary,
modifier =
Modifier
.fillMaxWidth(EXPANDED_TRANSACTION_WIDTH_RATIO)
@ -722,6 +727,7 @@ private fun HistoryItemTransactionIdPart(
style = ZcashTheme.extendedTypography.transactionItemStyles.content,
color = ZcashTheme.colors.textDescription,
iconVector = ImageVector.vectorResource(R.drawable.ic_trx_copy),
iconTintColor = ZcashTheme.colors.secondaryColor,
modifier =
Modifier
.clip(RoundedCornerShape(ZcashTheme.dimens.regularRippleEffectCorner))
@ -825,20 +831,27 @@ private fun HistoryItemMessagePart(
textColor = ZcashTheme.colors.historyRedColor
} else {
textStyle = ZcashTheme.extendedTypography.transactionItemStyles.content
textColor = ZcashTheme.colors.textCommon
textColor = ZcashTheme.colors.textPrimary
}
Column(modifier = modifier.then(Modifier.fillMaxWidth())) {
val (messageBackground, arrowAlignment) =
if (state.isSendType()) {
Color.Transparent to BubbleArrowAlignment.BottomLeft
} else {
ZcashTheme.colors.dividerColor to BubbleArrowAlignment.BottomRight
}
val bubbleBackgroundColor: Color
val bubbleStroke: BorderStroke
val arrowAlignment: BubbleArrowAlignment
if (state.isSendType()) {
bubbleBackgroundColor = Color.Transparent
bubbleStroke = BorderStroke(1.dp, ZcashTheme.colors.textFieldFrame)
arrowAlignment = BubbleArrowAlignment.BottomLeft
} else {
bubbleBackgroundColor = ZcashTheme.colors.historyMessageBubbleColor
bubbleStroke = BorderStroke(1.dp, ZcashTheme.colors.historyMessageBubbleStrokeColor)
arrowAlignment = BubbleArrowAlignment.BottomRight
}
BubbleMessage(
modifier = Modifier.fillMaxWidth(),
backgroundColor = messageBackground,
backgroundColor = bubbleBackgroundColor,
borderStroke = bubbleStroke,
arrowAlignment = arrowAlignment
) {
Text(
@ -856,6 +869,7 @@ private fun HistoryItemMessagePart(
style = ZcashTheme.extendedTypography.transactionItemStyles.content,
color = ZcashTheme.colors.textDescription,
iconVector = ImageVector.vectorResource(R.drawable.ic_trx_copy),
iconTintColor = ZcashTheme.colors.secondaryColor,
modifier =
Modifier
.clip(RoundedCornerShape(ZcashTheme.dimens.regularRippleEffectCorner))

View File

@ -30,9 +30,9 @@ private fun PreviewAppAccessAuthentication() {
}
}
@Preview("Error Authentication")
@Preview
@Composable
private fun PreviewErrorAuthentication() {
private fun ErrorAuthenticationPreview() {
ZcashTheme(forceDarkMode = false) {
BlankSurface {
AuthenticationErrorDialog(
@ -45,6 +45,21 @@ private fun PreviewErrorAuthentication() {
}
}
@Preview
@Composable
private fun ErrorAuthenticationDarkPreview() {
ZcashTheme(forceDarkMode = true) {
BlankSurface {
AuthenticationErrorDialog(
onDismiss = {},
onRetry = {},
onSupport = {},
reason = AuthenticationResult.Error(errorCode = -1, errorMessage = "Test Error Message")
)
}
}
}
@Composable
fun AppAccessAuthentication(
welcomeAnimVisibility: Boolean,
@ -69,7 +84,10 @@ fun AuthenticationErrorDialog(
Column(
Modifier.verticalScroll(rememberScrollState())
) {
Text(text = stringResource(id = R.string.authentication_error_text))
Text(
text = stringResource(id = R.string.authentication_error_text),
color = ZcashTheme.colors.textPrimary,
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
@ -80,7 +98,8 @@ fun AuthenticationErrorDialog(
reason.errorCode,
reason.errorMessage,
),
fontStyle = FontStyle.Italic
fontStyle = FontStyle.Italic,
color = ZcashTheme.colors.textPrimary,
)
}
},
@ -102,7 +121,10 @@ fun AuthenticationFailedDialog(
title = stringResource(id = R.string.authentication_failed_title),
text = {
Column(Modifier.verticalScroll(rememberScrollState())) {
Text(text = stringResource(id = R.string.authentication_failed_text))
Text(
text = stringResource(id = R.string.authentication_failed_text),
color = ZcashTheme.colors.textPrimary,
)
}
},
confirmButtonText = stringResource(id = R.string.authentication_failed_button_retry),

View File

@ -36,7 +36,6 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
@ -88,7 +87,7 @@ import co.electriccoin.zcash.ui.screen.balances.model.ShieldState
import co.electriccoin.zcash.ui.screen.balances.model.StatusAction
import co.electriccoin.zcash.ui.screen.balances.model.WalletDisplayValues
@Preview("Balances")
@Preview
@Composable
private fun ComposableBalancesPreview() {
ZcashTheme(forceDarkMode = false) {
@ -112,10 +111,10 @@ private fun ComposableBalancesPreview() {
}
}
@Preview("BalancesShieldFailure")
@Preview
@Composable
private fun ComposableBalancesShieldFailurePreview() {
ZcashTheme(forceDarkMode = false) {
private fun ComposableBalancesShieldDarkPreview() {
ZcashTheme(forceDarkMode = true) {
Balances(
balanceState = BalanceStateFixture.new(),
isFiatConversionEnabled = false,
@ -234,14 +233,18 @@ fun ShieldingErrorDialog(
Column(
Modifier.verticalScroll(rememberScrollState())
) {
Text(text = stringResource(id = R.string.balances_shielding_dialog_error_text))
Text(
text = stringResource(id = R.string.balances_shielding_dialog_error_text),
color = ZcashTheme.colors.textPrimary,
)
if (reason.isNotEmpty()) {
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
Text(
text = reason,
fontStyle = FontStyle.Italic
fontStyle = FontStyle.Italic,
color = ZcashTheme.colors.textPrimary,
)
}
}
@ -308,10 +311,10 @@ private fun BalancesMainContent(
onReferenceClick = {}
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingUpLarge))
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
HorizontalDivider(
color = ZcashTheme.colors.darkDividerColor,
color = ZcashTheme.colors.tertiaryDividerColor,
thickness = ZcashTheme.dimens.divider
)
@ -490,7 +493,7 @@ fun TransparentBalanceHelpPanel(onHideHelpPanel: () -> Unit) {
modifier =
Modifier
.padding(all = ZcashTheme.dimens.spacingDefault)
.background(color = Color.White)
.background(color = ZcashTheme.colors.panelBackgroundColorActive)
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
@ -592,7 +595,7 @@ fun SpendableBalanceRow(walletSnapshot: WalletSnapshot) {
ZcashTheme.extendedTypography.balanceSingleStyles.first,
ZcashTheme.extendedTypography.balanceSingleStyles.second
),
textColor = ZcashTheme.colors.textCommon
textColor = ZcashTheme.colors.textPrimary
)
Spacer(modifier = Modifier.width(12.dp))

View File

@ -107,7 +107,7 @@ fun ChooseServer(
options[CUSTOM_SERVER_OPTION_INDEX].run {
if (options[CUSTOM_SERVER_OPTION_INDEX].isValid()) {
stringResource(
R.string.choose_server_textfield_value,
R.string.choose_server_full_server_name,
options[CUSTOM_SERVER_OPTION_INDEX].host,
options[CUSTOM_SERVER_OPTION_INDEX].port
)
@ -194,7 +194,7 @@ fun ChooseServerBottomBar(
) {
HorizontalDivider(
thickness = DividerDefaults.Thickness,
color = ZcashTheme.colors.dividerColor
color = ZcashTheme.colors.primaryDividerColor
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
@ -239,6 +239,8 @@ private fun ChooseServerTopAppBar(
)
}
// When changing the following constants, be aware that they should not be the same
const val DEFAULT_SERVER_OPTION_INDEX = 0
const val CUSTOM_SERVER_OPTION_INDEX = 1
@Composable
@ -269,7 +271,7 @@ private fun ChooseServerMainContent(
@OptIn(ExperimentalFoundationApi::class)
@Composable
@Suppress("LongParameterList")
@Suppress("LongParameterList", "LongMethod")
fun ServerList(
options: ImmutableList<LightWalletEndpoint>,
customServerValue: String,
@ -282,59 +284,84 @@ fun ServerList(
options.forEachIndexed { index, endpoint ->
val isSelected = index == selectedOption
if (index == CUSTOM_SERVER_OPTION_INDEX) {
Column(
modifier = Modifier.animateContentSize()
) {
when (index) {
DEFAULT_SERVER_OPTION_INDEX -> {
LabeledRadioButton(
endpoint = endpoint,
changeClick = { setSelectedOption(index) },
name = stringResource(id = R.string.choose_server_custom),
name =
stringResource(
id = R.string.choose_server_default_label,
stringResource(
id = R.string.choose_server_full_server_name,
endpoint.host,
endpoint.port
)
),
selected = isSelected,
modifier = Modifier.fillMaxWidth()
)
if (isSelected) {
val focusManager = LocalFocusManager.current
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
FormTextField(
value = customServerValue,
onValueChange = {
setCustomServerValue(it)
},
placeholder = {
Text(text = stringResource(R.string.choose_server_textfield_hint))
},
keyboardActions =
KeyboardActions(
onDone = {
focusManager.clearFocus(true)
}
),
keyboardOptions =
KeyboardOptions(
keyboardType = KeyboardType.Uri,
imeAction = ImeAction.Done
),
modifier =
Modifier
.fillMaxWidth()
.padding(horizontal = ZcashTheme.dimens.spacingSmall)
}
CUSTOM_SERVER_OPTION_INDEX -> {
Column(
modifier = Modifier.animateContentSize()
) {
LabeledRadioButton(
endpoint = endpoint,
changeClick = { setSelectedOption(index) },
name = stringResource(id = R.string.choose_server_custom),
selected = isSelected,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
if (isSelected) {
val focusManager = LocalFocusManager.current
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
FormTextField(
value = customServerValue,
onValueChange = {
setCustomServerValue(it)
},
placeholder = {
Text(text = stringResource(R.string.choose_server_textfield_hint))
},
keyboardActions =
KeyboardActions(
onDone = {
focusManager.clearFocus(true)
}
),
keyboardOptions =
KeyboardOptions(
keyboardType = KeyboardType.Uri,
imeAction = ImeAction.Done
),
modifier =
Modifier
.fillMaxWidth()
.padding(horizontal = ZcashTheme.dimens.spacingSmall)
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
}
}
}
} else {
LabeledRadioButton(
endpoint = endpoint,
changeClick = { setSelectedOption(index) },
name = stringResource(id = R.string.choose_server_textfield_value, endpoint.host, endpoint.port),
selected = isSelected,
modifier = Modifier.fillMaxWidth()
)
else -> {
LabeledRadioButton(
endpoint = endpoint,
changeClick = { setSelectedOption(index) },
name =
stringResource(
id = R.string.choose_server_full_server_name,
endpoint.host,
endpoint.port
),
selected = isSelected,
modifier = Modifier.fillMaxWidth()
)
}
}
}
}
@ -357,7 +384,7 @@ fun LabeledRadioButton(
text = name,
selected = selected,
onClick = { changeClick(endpoint) },
modifier = modifier
modifier = modifier,
)
}

View File

@ -10,7 +10,6 @@ import co.electriccoin.zcash.ui.design.component.BlankSurface
import co.electriccoin.zcash.ui.design.component.Body
import co.electriccoin.zcash.ui.design.component.ChipIndexed
import co.electriccoin.zcash.ui.design.component.Header
import co.electriccoin.zcash.ui.design.component.NavigationButton
import co.electriccoin.zcash.ui.design.component.PrimaryButton
import co.electriccoin.zcash.ui.design.component.SecondaryButton
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
@ -31,8 +30,6 @@ fun DesignGuide() {
Column {
Header(text = "H1")
Body(text = "body")
NavigationButton(onClick = { }, text = "Back")
NavigationButton(onClick = { }, text = "Next")
PrimaryButton(onClick = { }, text = "Primary button", outerPaddingValues = PaddingValues(24.dp))
SecondaryButton(onClick = { }, text = "Secondary button", outerPaddingValues = PaddingValues(24.dp))
ChipIndexed(Index(1), "edict")

View File

@ -1,6 +1,7 @@
package co.electriccoin.zcash.ui.screen.deletewallet.view
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
@ -23,9 +24,9 @@ import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
import co.electriccoin.zcash.ui.design.component.Body
import co.electriccoin.zcash.ui.design.component.CheckBox
import co.electriccoin.zcash.ui.design.component.GridBgScaffold
import co.electriccoin.zcash.ui.design.component.GridBgSmallTopAppBar
import co.electriccoin.zcash.ui.design.component.LabeledCheckBox
import co.electriccoin.zcash.ui.design.component.PrimaryButton
import co.electriccoin.zcash.ui.design.component.TopScreenLogoTitle
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
@ -129,17 +130,15 @@ private fun DeleteWalletContent(
Spacer(Modifier.height(ZcashTheme.dimens.spacingDefault))
val checkedState = rememberSaveable { mutableStateOf(false) }
CheckBox(
modifier =
Modifier
.align(Alignment.Start)
.fillMaxWidth(),
checked = checkedState.value,
onCheckedChange = {
checkedState.value = it
},
text = stringResource(R.string.delete_wallet_acknowledge),
)
Row(Modifier.fillMaxWidth()) {
LabeledCheckBox(
checked = checkedState.value,
onCheckedChange = {
checkedState.value = it
},
text = stringResource(R.string.delete_wallet_acknowledge),
)
}
Spacer(
modifier =

View File

@ -48,7 +48,10 @@ fun ServerDisconnectedDialog(
Column(
Modifier.verticalScroll(rememberScrollState())
) {
Text(text = stringResource(id = R.string.server_disconnected_dialog_message))
Text(
text = stringResource(id = R.string.server_disconnected_dialog_message),
color = ZcashTheme.colors.textPrimary,
)
}
},
confirmButtonText = stringResource(id = R.string.server_disconnected_dialog_switch_btn),

View File

@ -1,6 +1,7 @@
package co.electriccoin.zcash.ui.screen.exportdata.view
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
@ -25,9 +26,9 @@ import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
import co.electriccoin.zcash.ui.design.component.Body
import co.electriccoin.zcash.ui.design.component.CheckBox
import co.electriccoin.zcash.ui.design.component.GridBgScaffold
import co.electriccoin.zcash.ui.design.component.GridBgSmallTopAppBar
import co.electriccoin.zcash.ui.design.component.LabeledCheckBox
import co.electriccoin.zcash.ui.design.component.PrimaryButton
import co.electriccoin.zcash.ui.design.component.TopScreenLogoTitle
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
@ -46,9 +47,6 @@ private fun ExportPrivateDataPreview() {
}
}
// TODO [#998]: Check and enhance screen dark mode
// TODO [#998]: https://github.com/Electric-Coin-Company/zashi-android/issues/998
@Composable
fun ExportPrivateData(
snackbarHostState: SnackbarHostState,
@ -134,19 +132,17 @@ private fun ExportPrivateDataContent(
Spacer(Modifier.height(ZcashTheme.dimens.spacingDefault))
val checkedState = rememberSaveable { mutableStateOf(false) }
CheckBox(
modifier =
Modifier
.align(Alignment.Start)
.fillMaxWidth(),
checked = checkedState.value,
onCheckedChange = {
checkedState.value = it
onAgree(it)
},
text = stringResource(R.string.export_data_agree),
checkBoxTestTag = ExportPrivateDataScreenTag.AGREE_CHECKBOX_TAG
)
Row(Modifier.fillMaxWidth()) {
LabeledCheckBox(
checked = checkedState.value,
onCheckedChange = {
checkedState.value = it
onAgree(it)
},
text = stringResource(R.string.export_data_agree),
checkBoxTestTag = ExportPrivateDataScreenTag.AGREE_CHECKBOX_TAG
)
}
Spacer(
modifier =

View File

@ -173,7 +173,7 @@ fun HomeContent(
) {
HorizontalDivider(
thickness = DividerDefaults.Thickness,
color = ZcashTheme.colors.dividerColor
color = ZcashTheme.colors.primaryDividerColor
)
TabRow(
selectedTabIndex = pagerState.currentPage,

View File

@ -52,9 +52,9 @@ import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.fixture.VersionInfoFixture
import kotlinx.collections.immutable.toPersistentList
@Preview(name = "NewWalletRecovery")
@Preview
@Composable
private fun ComposablePreview() {
private fun NewWalletRecoveryPreview() {
ZcashTheme(forceDarkMode = false) {
NewWalletRecovery(
PersistableWalletFixture.new(),
@ -66,8 +66,19 @@ private fun ComposablePreview() {
}
}
// TODO [#998]: Check and enhance screen dark mode
// TODO [#998]: https://github.com/Electric-Coin-Company/zashi-android/issues/998
@Preview
@Composable
private fun NewWalletRecoveryDarkPreview() {
ZcashTheme(forceDarkMode = true) {
NewWalletRecovery(
PersistableWalletFixture.new(),
onSeedCopy = {},
onBirthdayCopy = {},
onComplete = {},
versionInfo = VersionInfoFixture.new(),
)
}
}
/**
* @param onComplete Callback when the user has confirmed viewing the seed phrase.

View File

@ -17,6 +17,7 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
@ -43,8 +44,18 @@ private fun OnboardingComposablePreview() {
}
}
// TODO [#998]: Check and enhance screen dark mode
// TODO [#998]: https://github.com/Electric-Coin-Company/zashi-android/issues/998
@Preview("Onboarding")
@Composable
private fun OnboardingComposableDarkPreview() {
ZcashTheme(forceDarkMode = true) {
Onboarding(
isDebugMenuEnabled = true,
onImportWallet = {},
onCreateWallet = {},
onFixtureWallet = {}
)
}
}
// TODO [#1001]: Screens in landscape mode
// TODO [#1001]: https://github.com/Electric-Coin-Company/zashi-android/issues/1001
@ -108,16 +119,18 @@ private fun OnboardingMainContent(
}
Image(
painterResource(id = co.electriccoin.zcash.ui.design.R.drawable.zashi_logo_without_text),
stringResource(R.string.zcash_logo_content_description),
painter = painterResource(id = co.electriccoin.zcash.ui.design.R.drawable.zashi_logo_without_text),
colorFilter = ColorFilter.tint(color = ZcashTheme.colors.secondaryColor),
contentDescription = stringResource(R.string.zcash_logo_content_description),
modifier = imageModifier
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
Image(
painterResource(id = co.electriccoin.zcash.ui.design.R.drawable.zashi_text_logo),
""
painter = painterResource(id = co.electriccoin.zcash.ui.design.R.drawable.zashi_text_logo),
colorFilter = ColorFilter.tint(color = ZcashTheme.colors.secondaryColor),
contentDescription = null,
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingUpLarge))

View File

@ -17,6 +17,8 @@ object AndroidQrCodeImageGenerator : QrCodeImageGenerator {
}
}
// TODO [#1473]: Dark mode QR codes for Receive screen
// TODO [#1473]: https://github.com/Electric-Coin-Company/zashi-android/issues/1473
private fun BooleanArray.toBlackAndWhiteColorArray() =
IntArray(size) {
if (this[it]) {

View File

@ -1,14 +1,24 @@
package co.electriccoin.zcash.ui.screen.receive.util
import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.qrcode.QRCodeWriter
const val QR_CODE_IMAGE_MARGIN_IN_PIXELS = 2
object JvmQrCodeGenerator : QrCodeGenerator {
override fun generate(
data: String,
sizePixels: Int
): BooleanArray {
val bitMatrix = QRCodeWriter().encode(data, BarcodeFormat.QR_CODE, sizePixels, sizePixels)
val bitMatrix =
QRCodeWriter().encode(
data,
BarcodeFormat.QR_CODE,
sizePixels,
sizePixels,
mapOf(EncodeHintType.MARGIN to QR_CODE_IMAGE_MARGIN_IN_PIXELS)
)
return BooleanArray(sizePixels * sizePixels).apply {
var booleanArrayPosition = 0

View File

@ -16,6 +16,7 @@ import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@ -28,6 +29,8 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalDensity
@ -61,6 +64,40 @@ import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.runBlocking
import kotlin.math.roundToInt
@Preview
@Composable
private fun ReceivePreview() =
ZcashTheme(forceDarkMode = false) {
Receive(
screenBrightnessState = ScreenBrightnessState.NORMAL,
walletAddress = runBlocking { WalletAddressesFixture.new() },
snackbarHostState = SnackbarHostState(),
onSettings = {},
onAdjustBrightness = {},
onAddrCopyToClipboard = {},
onQrImageShare = {},
versionInfo = VersionInfoFixture.new(),
topAppBarSubTitleState = TopAppBarSubTitleState.None,
)
}
@Preview
@Composable
private fun ReceiveDarkPreview() =
ZcashTheme(forceDarkMode = true) {
Receive(
screenBrightnessState = ScreenBrightnessState.NORMAL,
walletAddress = runBlocking { WalletAddressesFixture.new() },
snackbarHostState = SnackbarHostState(),
onSettings = {},
onAdjustBrightness = {},
onAddrCopyToClipboard = {},
onQrImageShare = {},
versionInfo = VersionInfoFixture.new(),
topAppBarSubTitleState = TopAppBarSubTitleState.None,
)
}
@Suppress("LongParameterList")
@Composable
fun Receive(
@ -139,7 +176,8 @@ private fun ReceiveTopAppBar(
) {
Image(
imageVector = ImageVector.vectorResource(id = R.drawable.ic_adjust_brightness),
contentDescription = stringResource(R.string.receive_brightness_content_description)
colorFilter = ColorFilter.tint(color = ZcashTheme.colors.secondaryColor),
contentDescription = stringResource(R.string.receive_brightness_content_description),
)
}
}
@ -180,7 +218,10 @@ private fun ReceiveContents(
Spacer(Modifier.height(ZcashTheme.dimens.spacingDefault))
PagerTabs(
modifier = Modifier.fillMaxWidth(),
modifier =
Modifier
.padding(horizontal = ZcashTheme.dimens.screenHorizontalSpacingRegular)
.fillMaxWidth(),
pagerState = pagerState,
tabs =
state.map {
@ -265,11 +306,11 @@ private fun ColumnScope.QrCode(
is WalletAddress.Transparent -> R.string.receive_transparent_content_description
}
),
modifier = Modifier.align(Alignment.CenterHorizontally),
modifier =
Modifier
.align(Alignment.CenterHorizontally),
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingTiny))
Text(
text = walletAddress.address,
style = ZcashTheme.extendedTypography.addressStyle,
@ -278,13 +319,15 @@ private fun ColumnScope.QrCode(
modifier =
Modifier
.align(Alignment.CenterHorizontally)
.clip(RoundedCornerShape(ZcashTheme.dimens.regularRippleEffectCorner))
.clickable { onAddressCopyToClipboard(walletAddress.address) }
.padding(horizontal = ZcashTheme.dimens.spacingLarge)
.padding(
horizontal = ZcashTheme.dimens.spacingLarge,
vertical = ZcashTheme.dimens.spacingSmall
)
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center
@ -346,21 +389,4 @@ private fun QrCode(
)
}
@Preview
@Composable
private fun ComposablePreview() =
ZcashTheme(forceDarkMode = false) {
Receive(
screenBrightnessState = ScreenBrightnessState.NORMAL,
walletAddress = runBlocking { WalletAddressesFixture.new() },
snackbarHostState = SnackbarHostState(),
onSettings = {},
onAdjustBrightness = {},
onAddrCopyToClipboard = {},
onQrImageShare = {},
versionInfo = VersionInfoFixture.new(),
topAppBarSubTitleState = TopAppBarSubTitleState.None,
)
}
private val DEFAULT_QR_CODE_SIZE = 320.dp

View File

@ -6,7 +6,6 @@ import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
@ -21,10 +20,10 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
@ -45,7 +44,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
@ -86,9 +84,9 @@ import kotlinx.collections.immutable.ImmutableSet
import kotlinx.collections.immutable.persistentHashSetOf
import kotlinx.coroutines.launch
@Preview("Restore Seed")
@Preview
@Composable
private fun PreviewRestoreSeed() {
private fun RestoreSeedPreview() {
ZcashTheme(forceDarkMode = false) {
RestoreWallet(
ZcashNetwork.Mainnet,
@ -116,9 +114,39 @@ private fun PreviewRestoreSeed() {
}
}
@Preview("Restore Seed Birthday")
@Preview
@Composable
private fun PreviewRestoreBirthday() {
private fun RestoreSeedDarkPreview() {
ZcashTheme(forceDarkMode = true) {
RestoreWallet(
ZcashNetwork.Mainnet,
restoreState = RestoreState(RestoreStage.Seed),
completeWordList =
persistentHashSetOf(
"abandon",
"ability",
"able",
"about",
"above",
"absent",
"absorb",
"abstract",
"rib",
"ribbon"
),
userWordList = WordList(listOf("abandon", "absorb")),
restoreHeight = null,
setRestoreHeight = {},
onBack = {},
paste = { "" },
onFinished = {}
)
}
}
@Preview
@Composable
private fun RestoreBirthdayPreview() {
ZcashTheme(forceDarkMode = false) {
RestoreWallet(
ZcashNetwork.Mainnet,
@ -146,6 +174,36 @@ private fun PreviewRestoreBirthday() {
}
}
@Preview
@Composable
private fun RestoreBirthdayDarkPreview() {
ZcashTheme(forceDarkMode = true) {
RestoreWallet(
ZcashNetwork.Mainnet,
restoreState = RestoreState(RestoreStage.Birthday),
completeWordList =
persistentHashSetOf(
"abandon",
"ability",
"able",
"about",
"above",
"absent",
"absorb",
"abstract",
"rib",
"ribbon"
),
userWordList = WordList(listOf("abandon", "absorb")),
restoreHeight = null,
setRestoreHeight = {},
onBack = {},
paste = { "" },
onFinished = {}
)
}
}
/**
* Note that the restore review doesn't allow the user to go back once the seed is entered correctly.
*
@ -527,13 +585,14 @@ private fun SeedGridWithText(
isError = parseResult is ParseResult.Warn,
colors =
TextFieldDefaults.colors(
focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent,
cursorColor = ZcashTheme.colors.textPrimary,
disabledContainerColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent,
errorContainerColor = Color.Transparent,
focusedContainerColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent
)
)
}
@ -619,10 +678,8 @@ private fun Autocomplete(
items(it) {
ChipOnSurface(
text = it,
modifier =
Modifier
.testTag(RestoreTag.AUTOCOMPLETE_ITEM)
.clickable { onSuggestionSelected(it) }
onClick = { onSuggestionSelected(it) },
modifier = Modifier.testTag(RestoreTag.AUTOCOMPLETE_ITEM)
)
}
}
@ -636,21 +693,23 @@ private fun Warn(
) {
if (parseResult is ParseResult.Warn) {
Surface(
shape = RoundedCornerShape(size = ZcashTheme.dimens.tinyRippleEffectCorner),
modifier =
modifier.then(
Modifier.border(
border =
BorderStroke(
width = ZcashTheme.dimens.chipStroke,
color = ZcashTheme.colors.layoutStroke
)
color = ZcashTheme.colors.layoutStrokeSecondary
),
shape = RoundedCornerShape(size = ZcashTheme.dimens.tinyRippleEffectCorner),
)
),
shape = RectangleShape,
color = MaterialTheme.colorScheme.secondary,
color = ZcashTheme.colors.primaryColor,
shadowElevation = ZcashTheme.dimens.chipShadowElevation
) {
Text(
color = ZcashTheme.colors.textPrimary,
modifier =
Modifier
.fillMaxWidth()
@ -709,11 +768,12 @@ private fun RestoreBirthdayMainContent(
},
colors =
TextFieldDefaults.colors(
cursorColor = ZcashTheme.colors.textPrimary,
focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent,
disabledContainerColor = ZcashTheme.colors.textDisabled,
disabledContainerColor = Color.Transparent,
errorContainerColor = Color.Transparent,
focusedIndicatorColor = ZcashTheme.colors.darkDividerColor,
focusedIndicatorColor = ZcashTheme.colors.secondaryDividerColor,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent
),

View File

@ -18,8 +18,8 @@ import co.electriccoin.zcash.ui.common.model.SerializableAddress
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
import co.electriccoin.zcash.ui.screen.scan.util.SettingsUtil
import co.electriccoin.zcash.ui.screen.scan.view.Scan
import co.electriccoin.zcash.ui.util.SettingsUtil
import kotlinx.coroutines.launch
@Composable
@ -80,7 +80,7 @@ fun WrapScan(
context.startActivity(SettingsUtil.newSettingsIntent(context.packageName))
}.onFailure {
// This case should not really happen, as the Settings app should be available on every
// Android device, but we need to handle it somehow.
// Android device, but rather handle it.
scope.launch {
snackbarHostState.showSnackbar(
message = context.getString(R.string.scan_settings_open_failed)

View File

@ -29,7 +29,7 @@ class QrCodeAnalyzer(
if (image.format in supportedImageFormats) {
val bytes = image.planes.first().buffer.toByteArray()
Twig.debug {
Twig.verbose {
"Scan result: " +
"Frame: $framePosition, " +
"Info: ${image.imageInfo}, " +
@ -62,7 +62,7 @@ class QrCodeAnalyzer(
(binaryBmp.height * 0.4).toInt()
)
Twig.debug {
Twig.verbose {
"Scan result cropped: " +
"Image width: ${binaryBitmapCropped.width}, " +
"Image height: ${binaryBitmapCropped.height}"

View File

@ -80,9 +80,9 @@ import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.guava.await
import kotlin.math.roundToInt
@Preview("Scan")
@Preview
@Composable
private fun PreviewScan() {
private fun ScanPreview() {
ZcashTheme(forceDarkMode = false) {
BlankSurface {
Scan(
@ -98,6 +98,24 @@ private fun PreviewScan() {
}
}
@Preview
@Composable
private fun ScanDarkPreview() {
ZcashTheme(forceDarkMode = true) {
BlankSurface {
Scan(
snackbarHostState = SnackbarHostState(),
onBack = {},
onScanned = {},
onOpenSettings = {},
onScanStateChanged = {},
topAppBarSubTitleState = TopAppBarSubTitleState.None,
addressValidationResult = AddressType.Transparent,
)
}
}
}
@OptIn(ExperimentalPermissionsApi::class)
@Composable
@Suppress("LongParameterList", "UnusedMaterial3ScaffoldPaddingParameter")

View File

@ -1,6 +1,7 @@
package co.electriccoin.zcash.ui.screen.securitywarning.view
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
@ -24,15 +25,15 @@ import androidx.compose.ui.tooling.preview.Preview
import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.model.VersionInfo
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
import co.electriccoin.zcash.ui.design.component.CheckBox
import co.electriccoin.zcash.ui.design.component.GridBgScaffold
import co.electriccoin.zcash.ui.design.component.GridBgSmallTopAppBar
import co.electriccoin.zcash.ui.design.component.LabeledCheckBox
import co.electriccoin.zcash.ui.design.component.PrimaryButton
import co.electriccoin.zcash.ui.design.component.TopScreenLogoTitle
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.fixture.VersionInfoFixture
@Preview("Security Warning")
@Preview
@Composable
private fun SecurityWarningPreview() {
ZcashTheme(forceDarkMode = false) {
@ -45,11 +46,20 @@ private fun SecurityWarningPreview() {
}
}
// TODO [#998]: Check and enhance screen dark mode
// TODO [#998]: https://github.com/Electric-Coin-Company/zashi-android/issues/998
@Preview
@Composable
private fun SecurityWarningDarkPreview() {
ZcashTheme(forceDarkMode = true) {
SecurityWarning(
versionInfo = VersionInfoFixture.new(),
onBack = {},
onAcknowledged = {},
onConfirm = {},
)
}
}
@Composable
@Suppress("LongParameterList")
fun SecurityWarning(
versionInfo: VersionInfo,
onBack: () -> Unit,
@ -111,19 +121,17 @@ private fun SecurityWarningContent(
Spacer(Modifier.height(ZcashTheme.dimens.spacingLarge))
val checkedState = rememberSaveable { mutableStateOf(false) }
CheckBox(
modifier =
Modifier
.align(Alignment.Start)
.fillMaxWidth(),
checked = checkedState.value,
onCheckedChange = {
checkedState.value = it
onAcknowledged(it)
},
text = stringResource(R.string.security_warning_acknowledge),
checkBoxTestTag = SecurityScreenTag.ACKNOWLEDGE_CHECKBOX_TAG
)
Row(Modifier.fillMaxWidth()) {
LabeledCheckBox(
checked = checkedState.value,
onCheckedChange = {
checkedState.value = it
onAcknowledged(it)
},
text = stringResource(R.string.security_warning_acknowledge),
checkBoxTestTag = SecurityScreenTag.ACKNOWLEDGE_CHECKBOX_TAG
)
}
Spacer(
modifier =
@ -148,6 +156,7 @@ fun SecurityWarningContentText(versionInfo: VersionInfo) {
Column {
Text(
text = stringResource(id = R.string.security_warning_text, versionInfo.versionName),
color = ZcashTheme.colors.textPrimary,
style = ZcashTheme.extendedTypography.securityWarningText
)
@ -164,6 +173,7 @@ fun SecurityWarningContentText(versionInfo: VersionInfo) {
}
append(textPart2)
},
color = ZcashTheme.colors.textPrimary,
style = ZcashTheme.extendedTypography.footnote,
modifier = Modifier.fillMaxWidth()
)

View File

@ -70,9 +70,6 @@ private fun ComposablePreview() {
}
}
// TODO [#998]: Check and enhance screen dark mode
// TODO [#998]: https://github.com/Electric-Coin-Company/zashi-android/issues/998
/**
* @param onDone Callback when the user has confirmed viewing the seed phrase.
*/

View File

@ -326,7 +326,7 @@ private fun SendForm(
onReferenceClick = goBalances
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingUpLarge))
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
// TODO [#1256]: Consider Send.Form TextFields scrolling
// TODO [#1256]: https://github.com/Electric-Coin-Company/zashi-android/issues/1256
@ -535,7 +535,8 @@ fun SendFormAddressTextField(
content = {
Icon(
painter = painterResource(id = R.drawable.qr_code_icon),
contentDescription = stringResource(R.string.send_scan_content_description)
contentDescription = stringResource(R.string.send_scan_content_description),
tint = ZcashTheme.colors.secondaryColor,
)
}
)
@ -680,7 +681,7 @@ fun SendFormMemoTextField(
contentDescription = null,
tint =
if (isMemoFieldAvailable) {
ZcashTheme.colors.textCommon
ZcashTheme.colors.textPrimary
} else {
ZcashTheme.colors.textDisabled
}
@ -692,7 +693,7 @@ fun SendFormMemoTextField(
text = stringResource(id = R.string.send_memo_label),
color =
if (isMemoFieldAvailable) {
ZcashTheme.colors.textCommon
ZcashTheme.colors.textPrimary
} else {
ZcashTheme.colors.textDisabled
}
@ -806,13 +807,17 @@ private fun SendFailure(
Column(
Modifier.verticalScroll(rememberScrollState())
) {
Text(text = stringResource(id = R.string.send_dialog_error_text))
Text(
text = stringResource(id = R.string.send_dialog_error_text),
color = ZcashTheme.colors.textPrimary,
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
Text(
text = reason,
fontStyle = FontStyle.Italic
fontStyle = FontStyle.Italic,
color = ZcashTheme.colors.textPrimary,
)
}
},

View File

@ -4,7 +4,6 @@ package co.electriccoin.zcash.ui.screen.sendconfirmation.view
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@ -17,7 +16,6 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Icon
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
@ -25,6 +23,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
@ -50,6 +49,7 @@ import co.electriccoin.zcash.ui.design.component.Body
import co.electriccoin.zcash.ui.design.component.BubbleArrowAlignment
import co.electriccoin.zcash.ui.design.component.BubbleMessage
import co.electriccoin.zcash.ui.design.component.PrimaryButton
import co.electriccoin.zcash.ui.design.component.SecondaryButton
import co.electriccoin.zcash.ui.design.component.Small
import co.electriccoin.zcash.ui.design.component.SmallTopAppBar
import co.electriccoin.zcash.ui.design.component.StyledBalance
@ -59,8 +59,101 @@ import co.electriccoin.zcash.ui.screen.sendconfirmation.SendConfirmationTag
import co.electriccoin.zcash.ui.screen.sendconfirmation.model.SendConfirmationStage
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.runBlocking
@Preview
@Composable
private fun SendConfirmationPreview() {
ZcashTheme(forceDarkMode = false) {
SendConfirmation(
snackbarHostState = SnackbarHostState(),
zecSend =
ZecSend(
destination = runBlocking { WalletAddressFixture.sapling() },
amount = ZatoshiFixture.new(),
memo = MemoFixture.new(),
proposal = null,
),
onConfirmation = {},
onBack = {},
stage = SendConfirmationStage.Confirmation,
topAppBarSubTitleState = TopAppBarSubTitleState.None,
onContactSupport = {},
submissionResults = emptyList<TransactionSubmitResult>().toImmutableList()
)
}
}
@Preview
@Composable
private fun SendConfirmationDarkPreview() {
ZcashTheme(forceDarkMode = true) {
SendConfirmation(
snackbarHostState = SnackbarHostState(),
zecSend =
ZecSend(
destination = runBlocking { WalletAddressFixture.sapling() },
amount = ZatoshiFixture.new(),
memo = MemoFixture.new(),
proposal = null,
),
onConfirmation = {},
onBack = {},
stage = SendConfirmationStage.Confirmation,
topAppBarSubTitleState = TopAppBarSubTitleState.None,
onContactSupport = {},
submissionResults = emptyList<TransactionSubmitResult>().toImmutableList()
)
}
}
@Preview
@Composable
private fun SendMultipleErrorPreview() {
ZcashTheme(forceDarkMode = false) {
SendConfirmation(
snackbarHostState = SnackbarHostState(),
zecSend =
ZecSend(
destination = runBlocking { WalletAddressFixture.sapling() },
amount = ZatoshiFixture.new(),
memo = MemoFixture.new(),
proposal = null,
),
onConfirmation = {},
onBack = {},
stage = SendConfirmationStage.MultipleTrxFailure,
topAppBarSubTitleState = TopAppBarSubTitleState.None,
onContactSupport = {},
submissionResults = emptyList<TransactionSubmitResult>().toImmutableList()
)
}
}
@Preview
@Composable
private fun SendMultipleErrorDarkPreview() {
ZcashTheme(forceDarkMode = true) {
SendConfirmation(
snackbarHostState = SnackbarHostState(),
zecSend =
ZecSend(
destination = runBlocking { WalletAddressFixture.sapling() },
amount = ZatoshiFixture.new(),
memo = MemoFixture.new(),
proposal = null,
),
onConfirmation = {},
onBack = {},
stage = SendConfirmationStage.MultipleTrxFailure,
topAppBarSubTitleState = TopAppBarSubTitleState.None,
onContactSupport = {},
submissionResults = emptyList<TransactionSubmitResult>().toImmutableList()
)
}
}
@Composable
@Preview("SendConfirmation")
private fun PreviewSendConfirmation() {
@ -80,9 +173,9 @@ private fun PreviewSendConfirmation() {
}
}
@Preview
@Composable
@Preview("SendMultipleTransactionFailure")
private fun PreviewSendMultipleTransactionFailure() {
private fun SendMultipleTransactionFailurePreview() {
ZcashTheme(forceDarkMode = false) {
@Suppress("MagicNumber")
MultipleSubmissionFailure(
@ -107,6 +200,33 @@ private fun PreviewSendMultipleTransactionFailure() {
}
}
@Preview
@Composable
private fun SendMultipleTransactionFailureDarkPreview() {
ZcashTheme(forceDarkMode = true) {
@Suppress("MagicNumber")
MultipleSubmissionFailure(
onContactSupport = {},
// Rework this into a test fixture
submissionResults =
persistentListOf(
TransactionSubmitResult.Failure(
FirstClassByteArray("test_transaction_id_1".toByteArray()),
true,
123,
"test transaction id failure"
),
TransactionSubmitResult.NotAttempted(
FirstClassByteArray("test_transaction_id_2".toByteArray())
),
TransactionSubmitResult.NotAttempted(
FirstClassByteArray("test_transaction_id_3".toByteArray())
)
)
)
}
}
// TODO [#1260]: Cover Send screens UI with tests
// TODO [#1260]: https://github.com/Electric-Coin-Company/zashi-android/issues/1260
@ -337,6 +457,7 @@ fun SendConfirmationActionButtons(
enabled = !isSending,
showProgressBar = isSending,
minHeight = ZcashTheme.dimens.buttonHeightSmall,
buttonColors = ZcashTheme.colors.tertiaryButtonColors,
modifier =
Modifier
.testTag(SendConfirmationTag.SEND_CONFIRMATION_SEND_BUTTON)
@ -345,7 +466,7 @@ fun SendConfirmationActionButtons(
Spacer(modifier = Modifier.width(ZcashTheme.dimens.spacingLarge))
PrimaryButton(
SecondaryButton(
text = stringResource(R.string.send_confirmation_back_button),
onClick = onBack,
enabled = !isSending,
@ -386,14 +507,18 @@ private fun SendFailure(
Column(
Modifier.verticalScroll(rememberScrollState())
) {
Text(text = stringResource(id = R.string.send_confirmation_dialog_error_text))
Text(
text = stringResource(id = R.string.send_confirmation_dialog_error_text),
color = ZcashTheme.colors.textPrimary,
)
if (!reason.isNullOrEmpty()) {
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
Text(
text = reason,
fontStyle = FontStyle.Italic
fontStyle = FontStyle.Italic,
color = ZcashTheme.colors.textPrimary,
)
}
}
@ -418,19 +543,11 @@ fun MultipleSubmissionFailure(
) {
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
Box(
contentAlignment = Alignment.BottomEnd
) {
Image(
imageVector = ImageVector.vectorResource(R.drawable.zashi_logo_sign),
contentDescription = null,
)
Icon(
imageVector = ImageVector.vectorResource(R.drawable.ic_alert_circle_fill),
contentDescription = null,
modifier = Modifier.padding(bottom = ZcashTheme.dimens.spacingMid)
)
}
Image(
imageVector = ImageVector.vectorResource(R.drawable.ic_zashi_logo_sign_warn),
colorFilter = ColorFilter.tint(color = ZcashTheme.colors.secondaryColor),
contentDescription = null,
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingBig))

View File

@ -22,6 +22,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
@ -39,9 +40,9 @@ import co.electriccoin.zcash.ui.design.component.GridBgSmallTopAppBar
import co.electriccoin.zcash.ui.design.component.PrimaryButton
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
@Preview("Support")
@Preview
@Composable
private fun PreviewSupport() {
private fun SupportPreview() {
ZcashTheme(forceDarkMode = false) {
BlankSurface {
Support(
@ -56,6 +57,23 @@ private fun PreviewSupport() {
}
}
@Preview
@Composable
private fun SupportDarkPreview() {
ZcashTheme(forceDarkMode = true) {
BlankSurface {
Support(
isShowingDialog = false,
setShowDialog = {},
onBack = {},
onSend = {},
snackbarHostState = SnackbarHostState(),
topAppBarSubTitleState = TopAppBarSubTitleState.None,
)
}
}
}
@Preview("Support-Popup")
@Composable
private fun PreviewSupportPopup() {
@ -152,6 +170,7 @@ private fun SupportMainContent(
Image(
imageVector = ImageVector.vectorResource(R.drawable.zashi_logo_sign),
colorFilter = ColorFilter.tint(color = ZcashTheme.colors.secondaryColor),
contentDescription = null,
)
@ -185,6 +204,8 @@ private fun SupportMainContent(
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
// TODO [#1467]: Support screen - keep button above keyboard
// TODO [#1467]: https://github.com/Electric-Coin-Company/zashi-android/issues/1467
PrimaryButton(
onClick = { setShowDialog(true) },
text = stringResource(id = R.string.support_send),

View File

@ -83,7 +83,7 @@ class AppUpdateCheckerMock private constructor() : AppUpdateChecker {
): Flow<Int> =
flow {
// To simulate a real-world situation
delay(2000.milliseconds)
delay(4000.milliseconds)
emit(Activity.RESULT_OK)
}
}

View File

@ -2,11 +2,14 @@ package co.electriccoin.zcash.ui.screen.update.view
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
@ -19,8 +22,10 @@ import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
@ -32,6 +37,7 @@ import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.design.component.Body
import co.electriccoin.zcash.ui.design.component.GridBgScaffold
import co.electriccoin.zcash.ui.design.component.GridBgSmallTopAppBar
import co.electriccoin.zcash.ui.design.component.Header
import co.electriccoin.zcash.ui.design.component.PrimaryButton
import co.electriccoin.zcash.ui.design.component.Reference
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
@ -40,9 +46,9 @@ import co.electriccoin.zcash.ui.screen.update.UpdateTag
import co.electriccoin.zcash.ui.screen.update.model.UpdateInfo
import co.electriccoin.zcash.ui.screen.update.model.UpdateState
@Preview("Update")
@Preview
@Composable
private fun PreviewUpdate() {
private fun UpdatePreview() {
ZcashTheme(forceDarkMode = false) {
Update(
snackbarHostState = SnackbarHostState(),
@ -54,6 +60,48 @@ private fun PreviewUpdate() {
}
}
@Preview
@Composable
private fun UpdateRequiredPreview() {
ZcashTheme(forceDarkMode = false) {
Update(
snackbarHostState = SnackbarHostState(),
UpdateInfoFixture.new(force = true),
onDownload = {},
onLater = {},
onReference = {}
)
}
}
@Preview
@Composable
private fun UpdateAvailableDarkPreview() {
ZcashTheme(forceDarkMode = true) {
Update(
snackbarHostState = SnackbarHostState(),
UpdateInfoFixture.new(appUpdateInfo = null),
onDownload = {},
onLater = {},
onReference = {}
)
}
}
@Preview
@Composable
private fun UpdateRequiredDarkPreview() {
ZcashTheme(forceDarkMode = true) {
Update(
snackbarHostState = SnackbarHostState(),
UpdateInfoFixture.new(force = true),
onDownload = {},
onLater = {},
onReference = {}
)
}
}
@Composable
fun Update(
snackbarHostState: SnackbarHostState,
@ -101,14 +149,17 @@ fun UpdateOverlayRunning(updateInfo: UpdateInfo) {
if (updateInfo.state == UpdateState.Running) {
Column(
Modifier
.background(ZcashTheme.colors.overlay.copy(0.5f))
.fillMaxWidth()
.fillMaxHeight()
.background(ZcashTheme.colors.overlay.copy(0.65f))
.fillMaxSize()
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null // Set indication to null to disable ripple effect
) {}
.testTag(UpdateTag.PROGRESSBAR_DOWNLOADING),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
CircularProgressIndicator()
CircularProgressIndicator(color = ZcashTheme.colors.overlayProgressBar)
}
}
}
@ -143,7 +194,7 @@ private fun UpdateBottomAppBar(
) {
HorizontalDivider(
thickness = DividerDefaults.Thickness,
color = ZcashTheme.colors.dividerColor
color = ZcashTheme.colors.primaryDividerColor
)
Column(
@ -176,6 +227,7 @@ private fun UpdateBottomAppBar(
textAlign = TextAlign.Center,
style = ZcashTheme.typography.primary.bodyLarge,
fontWeight = FontWeight.SemiBold,
color = ZcashTheme.colors.textPrimary,
modifier =
Modifier
.padding(all = ZcashTheme.dimens.spacingDefault)
@ -227,23 +279,23 @@ private fun UpdateContent(
Image(
imageVector =
if (updateInfo.isForce) {
ImageVector.vectorResource(R.drawable.ic_zashi_logo_update_required)
ImageVector.vectorResource(R.drawable.ic_zashi_logo_sign_warn)
} else {
ImageVector.vectorResource(R.drawable.ic_zashi_logo_update_available)
},
colorFilter = ColorFilter.tint(color = ZcashTheme.colors.secondaryColor),
contentDescription = null
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingBig))
Text(
Header(
text =
if (updateInfo.isForce) {
stringResource(id = R.string.update_title_required)
} else {
stringResource(id = R.string.update_title_available, appName)
},
style = ZcashTheme.extendedTypography.updateTitleStyle,
textAlign = TextAlign.Center
)

View File

@ -2,27 +2,85 @@
package co.electriccoin.zcash.ui.screen.warning
import androidx.activity.ComponentActivity
import androidx.activity.compose.BackHandler
import androidx.activity.viewModels
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import co.electriccoin.zcash.ui.MainActivity
import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
import co.electriccoin.zcash.ui.screen.warning.view.NotEnoughSpaceView
import co.electriccoin.zcash.ui.screen.warning.viewmodel.StorageCheckViewModel
import co.electriccoin.zcash.ui.util.SettingsUtil
import kotlinx.coroutines.launch
@Composable
fun MainActivity.WrapNotEnoughSpace() {
WrapNotEnoughSpace(this)
}
fun MainActivity.WrapNotEnoughSpace(
goPrevious: () -> Unit,
goSettings: () -> Unit
) {
val walletViewModel by viewModels<WalletViewModel>()
@Composable
private fun WrapNotEnoughSpace(activity: ComponentActivity) {
val storageCheckViewModel by activity.viewModels<StorageCheckViewModel>()
val spaceRequiredToContinue by storageCheckViewModel.spaceRequiredToContinueMegabytes.collectAsStateWithLifecycle()
val storageCheckViewModel by viewModels<StorageCheckViewModel>()
NotEnoughSpaceView(
storageSpaceRequiredGigabytes = storageCheckViewModel.requiredStorageSpaceGigabytes,
spaceRequiredToContinueMegabytes = spaceRequiredToContinue ?: 0
val walletState = walletViewModel.walletStateInformation.collectAsStateWithLifecycle().value
val isEnoughFreeSpace = storageCheckViewModel.isEnoughSpace.collectAsStateWithLifecycle().value
if (isEnoughFreeSpace == true) {
goPrevious()
}
val requiredStorageSpaceGigabytes = storageCheckViewModel.requiredStorageSpaceGigabytes
val spaceAvailableMegabytes = storageCheckViewModel.spaceAvailableMegabytes.collectAsStateWithLifecycle()
BackHandler {
finish()
}
WrapNotEnoughFreeSpace(
goSettings = goSettings,
spaceAvailableMegabytes = spaceAvailableMegabytes.value ?: 0,
requiredStorageSpaceGigabytes = requiredStorageSpaceGigabytes,
walletState = walletState,
)
}
@Composable
private fun WrapNotEnoughFreeSpace(
goSettings: () -> Unit,
requiredStorageSpaceGigabytes: Int,
spaceAvailableMegabytes: Int,
walletState: TopAppBarSubTitleState,
) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() }
NotEnoughSpaceView(
onSettings = goSettings,
onSystemSettings = {
runCatching {
context.startActivity(SettingsUtil.newStorageSettingsIntent())
}.onFailure {
// This case should not really happen, as the Settings app should be available on every
// Android device, but we rather handle it.
scope.launch {
snackbarHostState.showSnackbar(
message = context.getString(R.string.not_enough_space_settings_open_failed)
)
}
}
},
snackbarHostState = snackbarHostState,
storageSpaceRequiredGigabytes = requiredStorageSpaceGigabytes,
spaceAvailableMegabytes = spaceAvailableMegabytes,
topAppBarSubTitleState = walletState,
)
}

View File

@ -1,77 +1,193 @@
package co.electriccoin.zcash.ui.screen.warning.view
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
import co.electriccoin.zcash.ui.common.test.CommonTag
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
import co.electriccoin.zcash.ui.design.component.Body
import co.electriccoin.zcash.ui.design.component.GridBgColumn
import co.electriccoin.zcash.ui.design.component.GridBgScaffold
import co.electriccoin.zcash.ui.design.component.Header
import co.electriccoin.zcash.ui.design.component.Small
import co.electriccoin.zcash.ui.design.component.PrimaryButton
import co.electriccoin.zcash.ui.design.component.SmallTopAppBar
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
@Preview("NotEnoughSpace")
@Preview
@Composable
private fun NotEnoughSpacePreview() {
ZcashTheme(forceDarkMode = false) {
NotEnoughSpaceView(
onSettings = {},
onSystemSettings = {},
snackbarHostState = SnackbarHostState(),
spaceAvailableMegabytes = 300,
storageSpaceRequiredGigabytes = 1,
spaceRequiredToContinueMegabytes = 300
topAppBarSubTitleState = TopAppBarSubTitleState.None,
)
}
}
@Preview
@Composable
private fun NotEnoughSpaceDarkPreview() {
ZcashTheme(forceDarkMode = true) {
NotEnoughSpaceView(
onSettings = {},
onSystemSettings = {},
snackbarHostState = SnackbarHostState(),
spaceAvailableMegabytes = 300,
storageSpaceRequiredGigabytes = 1,
topAppBarSubTitleState = TopAppBarSubTitleState.None,
)
}
}
@Composable
@Suppress("LongParameterList")
fun NotEnoughSpaceView(
onSettings: () -> Unit,
onSystemSettings: () -> Unit,
spaceAvailableMegabytes: Int,
storageSpaceRequiredGigabytes: Int,
spaceRequiredToContinueMegabytes: Int
topAppBarSubTitleState: TopAppBarSubTitleState,
snackbarHostState: SnackbarHostState,
) {
GridBgColumn(
Modifier
.fillMaxSize()
.padding(ZcashTheme.dimens.screenHorizontalSpacingRegular)
.verticalScroll(
rememberScrollState()
),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = painterResource(id = R.drawable.not_enough_space),
contentDescription = null,
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.height(ZcashTheme.dimens.spacingUpLarge))
Header(text = stringResource(id = R.string.not_enough_space_title))
Spacer(Modifier.height(ZcashTheme.dimens.spacingUpLarge))
Body(
text = stringResource(id = R.string.not_enough_space_description, storageSpaceRequiredGigabytes),
textAlign = TextAlign.Center
)
Spacer(Modifier.height(ZcashTheme.dimens.spacingHuge))
Small(
text = stringResource(id = R.string.space_required_to_continue, spaceRequiredToContinueMegabytes),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
GridBgScaffold(
topBar = {
NotEnoughSpaceTopAppBar(
onSettings = onSettings,
subTitleState = topAppBarSubTitleState,
)
},
snackbarHost = { SnackbarHost(snackbarHostState) },
) { paddingValues ->
NotEnoughSpaceMainContent(
onSystemSettings = onSystemSettings,
spaceRequiredToContinueMegabytes = spaceAvailableMegabytes,
storageSpaceRequiredGigabytes = storageSpaceRequiredGigabytes,
modifier =
Modifier
.padding(
top = paddingValues.calculateTopPadding(),
bottom = paddingValues.calculateBottomPadding(),
start = ZcashTheme.dimens.screenHorizontalSpacingBig,
end = ZcashTheme.dimens.screenHorizontalSpacingBig
)
)
}
}
@Composable
private fun NotEnoughSpaceTopAppBar(
onSettings: () -> Unit,
subTitleState: TopAppBarSubTitleState
) {
SmallTopAppBar(
subTitle =
when (subTitleState) {
TopAppBarSubTitleState.Disconnected -> stringResource(id = R.string.disconnected_label)
TopAppBarSubTitleState.Restoring -> stringResource(id = R.string.restoring_wallet_label)
TopAppBarSubTitleState.None -> null
},
titleText = stringResource(id = R.string.not_enough_space_title).uppercase(),
hamburgerMenuActions = {
IconButton(
onClick = onSettings,
modifier = Modifier.testTag(CommonTag.SETTINGS_TOP_BAR_BUTTON)
) {
Icon(
painter = painterResource(id = co.electriccoin.zcash.ui.design.R.drawable.hamburger_menu_icon),
contentDescription = stringResource(id = R.string.settings_menu_content_description)
)
}
}
)
}
@Composable
private fun NotEnoughSpaceMainContent(
onSystemSettings: () -> Unit,
spaceRequiredToContinueMegabytes: Int,
storageSpaceRequiredGigabytes: Int,
modifier: Modifier = Modifier
) {
Column(
modifier =
modifier.then(
Modifier
.fillMaxHeight()
.verticalScroll(
rememberScrollState()
)
),
horizontalAlignment = Alignment.CenterHorizontally
) {
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingBig))
Image(
painter = painterResource(id = R.drawable.ic_zashi_logo_sign_warn),
colorFilter = ColorFilter.tint(color = ZcashTheme.colors.secondaryColor),
contentDescription = null,
)
Spacer(Modifier.height(ZcashTheme.dimens.spacingBig))
Header(
text =
stringResource(
id = R.string.not_enough_space_description_1,
stringResource(id = R.string.app_name),
storageSpaceRequiredGigabytes,
spaceRequiredToContinueMegabytes
),
textAlign = TextAlign.Center
)
Spacer(Modifier.height(ZcashTheme.dimens.spacingLarge))
Body(
text =
stringResource(
id = R.string.not_enough_space_description_2,
stringResource(id = R.string.app_name)
),
textAlign = TextAlign.Center
)
Spacer(
modifier =
Modifier
.fillMaxHeight()
.weight(MINIMAL_WEIGHT)
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
PrimaryButton(
onClick = onSystemSettings,
text = stringResource(R.string.not_enough_space_system_settings_btn),
)
Spacer(Modifier.height(ZcashTheme.dimens.spacingHuge))
}
}

View File

@ -29,4 +29,12 @@ class StorageCheckViewModel : ViewModel() {
SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT),
null
)
val spaceAvailableMegabytes =
flow { emit(StorageChecker.checkAvailableStorageMegabytes()) }
.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT),
null
)
}

View File

@ -1,4 +1,4 @@
package co.electriccoin.zcash.ui.screen.scan.util
package co.electriccoin.zcash.ui.util
import android.content.Intent
import android.net.Uri
@ -26,4 +26,15 @@ object SettingsUtil {
flags = FLAGS
}
}
/**
* Returns an intent to the system Storage Settings page.
*
* @return Intent for launching the system Settings app
*/
internal fun newStorageSettingsIntent(): Intent {
return Intent(Settings.ACTION_INTERNAL_STORAGE_SETTINGS).apply {
flags = FLAGS
}
}
}

View File

@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="12dp"
android:height="11dp"
android:viewportWidth="12"
android:viewportHeight="11">
<path
android:pathData="M1,0.625h10v10h-10z"
android:strokeWidth="0.25"
android:fillColor="#00000000"
android:strokeColor="#C1C1C1"/>
<path
android:pathData="M6,4.084L8.02,6.105L7.313,6.812L6,5.499L4.687,6.812L3.98,6.105L6,4.084Z"
android:fillColor="#F4B728"
android:fillType="evenOdd"/>
</vector>

View File

@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="11dp"
android:height="12dp"
android:viewportWidth="11"
android:viewportHeight="12">
<path
android:strokeWidth="1"
android:pathData="M5.5,5.5m-5,0a5,5 0,1 1,10 0a5,5 0,1 1,-10 0"
android:fillColor="#ffffff"
android:strokeColor="#ffffff"/>
<path
android:pathData="M4.795,6.682V6.545C4.795,6.233 4.82,5.984 4.869,5.798C4.919,5.613 4.991,5.464 5.088,5.352C5.185,5.239 5.303,5.136 5.443,5.045C5.564,4.966 5.672,4.889 5.767,4.815C5.864,4.741 5.939,4.663 5.994,4.58C6.051,4.496 6.08,4.402 6.08,4.295C6.08,4.201 6.057,4.117 6.011,4.045C5.966,3.973 5.904,3.918 5.827,3.878C5.749,3.838 5.663,3.818 5.568,3.818C5.466,3.818 5.371,3.842 5.284,3.889C5.199,3.937 5.13,4.002 5.077,4.085C5.026,4.169 5,4.265 5,4.375H3.545C3.549,3.958 3.644,3.62 3.83,3.361C4.015,3.099 4.261,2.908 4.568,2.787C4.875,2.664 5.212,2.602 5.58,2.602C5.985,2.602 6.347,2.662 6.665,2.781C6.983,2.899 7.234,3.077 7.418,3.315C7.601,3.552 7.693,3.848 7.693,4.205C7.693,4.434 7.653,4.635 7.574,4.81C7.496,4.982 7.387,5.134 7.247,5.267C7.109,5.398 6.947,5.517 6.761,5.625C6.625,5.705 6.51,5.787 6.418,5.872C6.325,5.955 6.255,6.051 6.207,6.159C6.16,6.265 6.136,6.394 6.136,6.545V6.682H4.795ZM5.489,8.591C5.269,8.591 5.08,8.514 4.923,8.361C4.768,8.205 4.691,8.017 4.693,7.795C4.691,7.58 4.768,7.395 4.923,7.241C5.08,7.088 5.269,7.011 5.489,7.011C5.697,7.011 5.881,7.088 6.04,7.241C6.201,7.395 6.282,7.58 6.284,7.795C6.282,7.943 6.243,8.078 6.168,8.199C6.094,8.318 5.997,8.414 5.878,8.486C5.759,8.556 5.629,8.591 5.489,8.591Z"
android:fillColor="#181716"/>
</vector>

View File

@ -3,10 +3,13 @@
<string name="choose_server_back_content_description">Back</string>
<string name="choose_server_title">Server</string>
<string name="choose_server_default_label">default: <xliff:g id="server" example="example.com:123">%1$s</xliff:g></string>
<string name="choose_server_custom">custom</string>
<string name="choose_server_custom_delimiter">:</string>
<string name="choose_server_textfield_value"><xliff:g id="hostname" example="example.com">%1$s</xliff:g>:<xliff:g
id="port" example="508">%2$d</xliff:g></string>
<string name="choose_server_full_server_name">
<xliff:g id="hostname" example="example.com">%1$s</xliff:g>:
<xliff:g id="port" example="508">%2$d</xliff:g>
</string>
<string name="choose_server_textfield_hint">&lt;hostname&gt;:&lt;port&gt;</string>
<string name="choose_server_save">Save</string>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 708 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -5,7 +5,7 @@
place you trust and never share it with anyone!</string>
<string name="new_wallet_recovery_birthday_height" formatted="true">Wallet birthday height: <xliff:g example="419200"
id="birthday_height">%1$d</xliff:g></string>
<string name="new_wallet_recovery_button_finished">I got it!</string>
<string name="new_wallet_recovery_button_finished">I\'ve saved it</string>
<string name="new_wallet_recovery_copy">Tap to Copy</string>
<string name="new_wallet_recovery_seed_clipboard_tag">Zcash Seed Phrase</string>
<string name="new_wallet_recovery_birthday_clipboard_tag">Zcash Wallet Birthday</string>

View File

@ -1,5 +1,5 @@
<resources>
<string name="app_name">zcash-ui</string>
<string name="app_name">zashi-ui</string>
<string name="onboarding_header">A no-frills wallet for sending and receiving Zcash (ZEC)</string>

View File

@ -20,7 +20,7 @@
android:fillColor="#000000"/>
<path
android:pathData="M10,13.404C11.88,13.404 13.403,11.88 13.403,10C13.403,8.121 11.88,6.597 10,6.597V13.404Z"
android:fillColor="#ffffff"/>
android:fillColor="#000000"/>
<path
android:pathData="M3.095,10.49H0.49C0.219,10.49 0,10.27 0,10C0,9.73 0.219,9.51 0.49,9.51H3.095C3.365,9.51 3.585,9.73 3.585,10C3.585,10.27 3.365,10.49 3.095,10.49Z"
android:fillColor="#000000"/>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="25dp"
android:height="25dp"
android:viewportWidth="25"
android:viewportHeight="25">
<path
android:pathData="M12.359,22.587C6.836,22.587 2.359,18.11 2.359,12.587C2.359,7.065 6.836,2.587 12.359,2.587C17.882,2.587 22.359,7.065 22.359,12.587C22.359,18.11 17.882,22.587 12.359,22.587ZM12.359,7.587C12.094,7.587 11.839,7.692 11.652,7.88C11.464,8.067 11.359,8.322 11.359,8.587V13.587C11.359,13.852 11.464,14.106 11.652,14.294C11.839,14.481 12.094,14.587 12.359,14.587C12.624,14.587 12.878,14.481 13.066,14.294C13.253,14.106 13.359,13.852 13.359,13.587V8.587C13.359,8.322 13.253,8.067 13.066,7.88C12.878,7.692 12.624,7.587 12.359,7.587ZM12.359,17.587C12.624,17.587 12.878,17.481 13.066,17.294C13.253,17.106 13.359,16.852 13.359,16.587C13.359,16.322 13.253,16.067 13.066,15.88C12.878,15.692 12.624,15.587 12.359,15.587C12.094,15.587 11.839,15.692 11.652,15.88C11.464,16.067 11.359,16.322 11.359,16.587C11.359,16.852 11.464,17.106 11.652,17.294C11.839,17.481 12.094,17.587 12.359,17.587Z"
android:fillColor="#21272A"/>
</vector>

View File

@ -2,14 +2,14 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="update_header">Update available</string>
<string name="update_critical_header">Update required</string>
<string name="update_title_available"><xliff:g id="app_name" example="Zcash">%1$s</xliff:g> here.</string>
<string name="update_title_available"><xliff:g id="app_name" example="Zashi">%1$s</xliff:g> here.</string>
<string name="update_title_required">It\'s not you, it\'s me.</string>
<string name="update_description_required">
There is a required update for <xliff:g id="app_name" example="Zcash">%1$s</xliff:g> that makes major
There is a required update for <xliff:g id="app_name" example="Zashi">%1$s</xliff:g> that makes major
improvements to performance and/or security.
</string>
<string name="update_description_available">
There is a new version of <xliff:g id="app_name" example="Zcash">%1$s</xliff:g> that makes minor updates to
There is a new version of <xliff:g id="app_name" example="Zashi">%1$s</xliff:g> that makes minor updates to
improve performance and/or security.\n\nPlease take a moment to update to the latest version.
</string>
<string name="update_link_text">Learn more about this update here.</string>

View File

@ -1,12 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="123dp"
android:height="151dp"
android:viewportWidth="123"
android:viewportHeight="151">
<path
android:pathData="M61.5,151l-30.75,-16.25a47.25,47.25 0,0 1,-12.8 -10.14,65.56 65.56,0 0,1 -9.68,-14.14 76.37,76.37 0,0 1,-6.13 -16.25,67.59 67.59,0 0,1 -2.14,-16.48v-0.82h33.17L58.88,104l25.71,-27.06h38.41v0.82a67.59,67.59 0,0 1,-2.14 16.48,76.33 76.33,0 0,1 -6.13,16.25 65.52,65.52 0,0 1,-9.68 14.14,47.25 47.25,0 0,1 -12.8,10.14L61.5,151Z"
android:fillColor="#891c2f"/>
<path
android:pathData="M32.22,75.94h0l-32.22,0L0,24.36L61.5,0l61.5,24.36L123,75.94h-37.46L99,61.78 84.95,47l-26.07,27.44 -12.84,-13.51L32,75.71l0.22,0.23Z"
android:fillColor="#ff0000"/>
</vector>

View File

@ -1,9 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="not_enough_space_title">Not enough space!</string>
<string name="not_enough_space_description">You need approximately <xliff:g example="1" id="required_gigabytes">
%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>
<string name="space_required_to_continue"><xliff:g example="300" id="required_megabytes">~%1$d</xliff:g> Mbyte
required to continue </string>
<string name="not_enough_space_title">Not enough free space</string>
<string name="not_enough_space_description_1">
<xliff:g id="app_name" example="Zashi">%1$s</xliff:g> requires at least
<xliff:g example="1" id="required_gigabytes">%2$d</xliff:g> GB of space to operate but there is only
<xliff:g example="300" id="available_megabytes">%3$d</xliff:g> MB available.
</string>
<string name="not_enough_space_description_2">
Go to your device settings and make more space available if you wish to use the
<xliff:g id="app_name" example="Zashi">%1$s</xliff:g> app.
</string>
<string name="not_enough_space_system_settings_btn">System settings</string>
<string name="not_enough_space_settings_open_failed">Unable to launch Settings app.</string>
</resources>