Wallet backup message

This commit is contained in:
Milan Cerovsky 2025-04-01 13:06:24 +02:00
parent 9cd31dfee4
commit 0209bec72b
12 changed files with 390 additions and 220 deletions

View File

@ -551,8 +551,8 @@ val DarkZashiColorsInternal =
utilityEspresso600 = Espresso.`300`,
utilityEspresso500 = Espresso.`400`,
utilityEspresso200 = Espresso.`700`,
utilityEspresso50 = Espresso.`900`,
utilityEspresso100 = Espresso.`800`,
utilityEspresso50 = Espresso.`950`,
utilityEspresso100 = Espresso.`900`,
utilityEspresso400 = Espresso.`500`,
utilityEspresso300 = Espresso.`600`,
utilityEspresso900 = Espresso.`50`,

View File

@ -1,6 +1,7 @@
package co.electriccoin.zcash.ui.screen.home
import co.electriccoin.zcash.ui.design.component.BigIconButtonState
import co.electriccoin.zcash.ui.screen.home.messages.HomeMessageState
data class HomeState(
val firstButton: BigIconButtonState,
@ -10,11 +11,6 @@ data class HomeState(
val message: HomeMessageState?
)
data class HomeMessageState(
val text: String,
val onClick: () -> Unit
)
data class HomeRestoreDialogState(
val onClick: () -> Unit
)

View File

@ -1,13 +1,5 @@
package co.electriccoin.zcash.ui.screen.home
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@ -18,9 +10,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@ -28,20 +18,8 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.ClipOp
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.DefaultShadowColor
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.addOutline
import androidx.compose.ui.graphics.drawscope.clipPath
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.appbar.ZashiMainTopAppBarState
import co.electriccoin.zcash.ui.common.appbar.ZashiTopAppBarWithAccountSelection
@ -50,13 +28,14 @@ import co.electriccoin.zcash.ui.design.component.BlankBgScaffold
import co.electriccoin.zcash.ui.design.component.ZashiBigIconButton
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.design.theme.colors.ZashiColors
import co.electriccoin.zcash.ui.design.util.scaffoldPadding
import co.electriccoin.zcash.ui.design.util.stringRes
import co.electriccoin.zcash.ui.fixture.BalanceStateFixture
import co.electriccoin.zcash.ui.fixture.ZashiMainTopAppBarStateFixture
import co.electriccoin.zcash.ui.screen.balances.BalanceState
import co.electriccoin.zcash.ui.screen.balances.BalanceWidget
import co.electriccoin.zcash.ui.screen.home.messages.HomeMessage
import co.electriccoin.zcash.ui.screen.home.messages.HomeMessageState
import co.electriccoin.zcash.ui.screen.transactionhistory.widget.TransactionHistoryWidgetState
import co.electriccoin.zcash.ui.screen.transactionhistory.widget.TransactionHistoryWidgetStateFixture
import co.electriccoin.zcash.ui.screen.transactionhistory.widget.createTransactionHistoryWidgets
@ -110,7 +89,7 @@ private fun Content(
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
NavButtons(paddingValues, state)
Spacer(Modifier.height(16.dp))
Message(state.message)
HomeMessage(state.message)
LazyColumn(
modifier =
Modifier
@ -125,112 +104,6 @@ private fun Content(
}
}
@Composable
private fun Message(state: HomeMessageState?) {
val cutoutHeight = 16.dp
var normalizedState: HomeMessageState? by remember { mutableStateOf(state) }
var isVisible by remember { mutableStateOf(state != null) }
val bottomCornerSize by animateDpAsState(
if (isVisible) cutoutHeight else 0.dp,
animationSpec = tween(350)
)
Box(
modifier = Modifier
.background(Color.Gray)
.clickable(onClick = { normalizedState?.onClick?.invoke() })
) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(cutoutHeight)
.zIndex(2f)
.bottomOnlyShadow(
elevation = 2.dp,
shape = RoundedCornerShape(bottomStart = 32.dp, bottomEnd = 32.dp),
backgroundColor = ZashiColors.Surfaces.bgPrimary
)
,
)
Box(
modifier = Modifier
.fillMaxWidth()
.height(cutoutHeight)
.zIndex(1f)
.align(Alignment.BottomCenter)
.topOnlyShadow(
elevation = 2.dp,
shape = RoundedCornerShape(topStart = bottomCornerSize, topEnd = bottomCornerSize),
backgroundColor = ZashiColors.Surfaces.bgPrimary
),
)
}
LaunchedEffect(state) {
if (state != null) {
normalizedState = state
isVisible = true
} else {
isVisible = false
delay(350)
normalizedState = null
}
}
}
private fun Modifier.bottomOnlyShadow(
elevation: Dp,
shape: Shape,
backgroundColor: Color,
clip: Boolean = elevation > 0.dp,
ambientColor: Color = DefaultShadowColor,
spotColor: Color = DefaultShadowColor,
): Modifier = this
.drawWithCache {
// bottom shadow offset in Px based on elevation
val bottomOffsetPx = elevation.toPx()
// Adjust the size to extend the bottom by the bottom shadow offset
val adjustedSize = Size(size.width, size.height + bottomOffsetPx)
val outline = shape.createOutline(adjustedSize, layoutDirection, this)
val path = Path().apply { addOutline(outline) }
onDrawWithContent {
clipPath(path, ClipOp.Intersect) {
this@onDrawWithContent.drawContent()
}
}
}
.shadow(elevation, shape, clip, ambientColor, spotColor)
.background(
backgroundColor,
shape
)
private fun Modifier.topOnlyShadow(
elevation: Dp,
shape: Shape,
backgroundColor: Color,
clip: Boolean = elevation > 0.dp,
ambientColor: Color = DefaultShadowColor,
spotColor: Color = DefaultShadowColor,
): Modifier = this
.drawWithCache {
// Adjust the size to extend the bottom by the bottom shadow offset
val adjustedSize = Size(size.width, size.height)
val outline = shape.createOutline(adjustedSize, layoutDirection, this)
val path = Path().apply { addOutline(outline) }
onDrawWithContent {
clipPath(path, ClipOp.Intersect) {
this@onDrawWithContent.drawContent()
}
}
}
.shadow(elevation, shape, clip, ambientColor, spotColor)
.background(
backgroundColor,
shape
)
@Composable
private fun NavButtons(
paddingValues: PaddingValues,
@ -301,18 +174,7 @@ private fun Preview() {
icon = R.drawable.ic_warning,
onClick = {}
),
message = HomeMessageState(
text = "Test string",
onClick = {
isHomeMessageStateVisible = !isHomeMessageStateVisible
if (!isHomeMessageStateVisible) {
scope.launch {
delay(1000)
isHomeMessageStateVisible = true
}
}
}
).takeIf { isHomeMessageStateVisible }
message = null.takeIf { isHomeMessageStateVisible }
)
)
}

View File

@ -8,17 +8,20 @@ import co.electriccoin.zcash.ui.NavigationTargets
import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.model.DistributionDimension
import co.electriccoin.zcash.ui.common.model.KeystoneAccount
import co.electriccoin.zcash.ui.common.model.WalletAccount
import co.electriccoin.zcash.ui.common.provider.GetVersionInfoProvider
import co.electriccoin.zcash.ui.common.usecase.GetSelectedWalletAccountUseCase
import co.electriccoin.zcash.ui.common.usecase.IsRestoreSuccessDialogVisibleUseCase
import co.electriccoin.zcash.ui.common.usecase.NavigateToCoinbaseUseCase
import co.electriccoin.zcash.ui.design.component.BigIconButtonState
import co.electriccoin.zcash.ui.design.util.stringRes
import co.electriccoin.zcash.ui.screen.home.messages.WalletBackupMessageState
import co.electriccoin.zcash.ui.screen.integrations.DialogIntegrations
import co.electriccoin.zcash.ui.screen.receive.Receive
import co.electriccoin.zcash.ui.screen.receive.model.ReceiveAddressType
import co.electriccoin.zcash.ui.screen.scan.Scan
import co.electriccoin.zcash.ui.screen.scan.ScanFlow
import co.electriccoin.zcash.ui.screen.seed.backup.SeedBackup
import co.electriccoin.zcash.ui.screen.send.Send
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@ -28,7 +31,6 @@ import kotlinx.coroutines.flow.WhileSubscribed
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
class HomeViewModel(
@ -64,62 +66,71 @@ class HomeViewModel(
val state: StateFlow<HomeState?> =
combine(getSelectedWalletAccountUseCase.observe(), isMessageVisible) { selectedAccount, isMessageVisible ->
HomeState(
firstButton =
BigIconButtonState(
text = stringRes("Receive"),
icon = R.drawable.ic_home_receive,
onClick = ::onReceiveButtonClick,
),
secondButton =
BigIconButtonState(
text = stringRes("Send"),
icon = R.drawable.ic_home_send,
onClick = ::onSendButtonClick,
),
thirdButton =
BigIconButtonState(
text = stringRes("Scan"),
icon = R.drawable.ic_home_scan,
onClick = ::onScanButtonClick,
),
fourthButton =
when {
getVersionInfoProvider().distributionDimension == DistributionDimension.FOSS ->
BigIconButtonState(
text = stringRes("Request"),
icon = R.drawable.ic_home_request,
onClick = ::onRequestClick,
)
selectedAccount is KeystoneAccount ->
BigIconButtonState(
text = stringRes("Buy"),
icon = R.drawable.ic_home_buy,
onClick = ::onBuyClick,
)
else ->
BigIconButtonState(
text = stringRes("More"),
icon = R.drawable.ic_home_more,
onClick = ::onMoreButtonClick,
)
},
message = HomeMessageState(
text = "Test string",
onClick = {
this@HomeViewModel.isMessageVisible.update { !it }
}
).takeIf { isMessageVisible }
)
createState(getVersionInfoProvider, selectedAccount, isMessageVisible)
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT),
initialValue = null
)
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT),
initialValue = null
)
fun onRestoreDialogSeenClick() =
private fun createState(
getVersionInfoProvider: GetVersionInfoProvider,
selectedAccount: WalletAccount?,
isMessageVisible: Boolean
) = HomeState(
firstButton =
BigIconButtonState(
text = stringRes("Receive"),
icon = R.drawable.ic_home_receive,
onClick = ::onReceiveButtonClick,
),
secondButton =
BigIconButtonState(
text = stringRes("Send"),
icon = R.drawable.ic_home_send,
onClick = ::onSendButtonClick,
),
thirdButton =
BigIconButtonState(
text = stringRes("Scan"),
icon = R.drawable.ic_home_scan,
onClick = ::onScanButtonClick,
),
fourthButton =
when {
getVersionInfoProvider().distributionDimension == DistributionDimension.FOSS ->
BigIconButtonState(
text = stringRes("Request"),
icon = R.drawable.ic_home_request,
onClick = ::onRequestClick,
)
selectedAccount is KeystoneAccount ->
BigIconButtonState(
text = stringRes("Buy"),
icon = R.drawable.ic_home_buy,
onClick = ::onBuyClick,
)
else ->
BigIconButtonState(
text = stringRes("More"),
icon = R.drawable.ic_home_more,
onClick = ::onMoreButtonClick,
)
},
message = createWalletBackupMessageState().takeIf { isMessageVisible }
)
private fun createWalletBackupMessageState(): WalletBackupMessageState {
return WalletBackupMessageState(
onClick = {
navigationRouter.forward(SeedBackup)
}
)
}
private fun onRestoreDialogSeenClick() =
viewModelScope.launch {
isRestoreSuccessDialogVisible.setSeen()
}

View File

@ -0,0 +1,162 @@
package co.electriccoin.zcash.ui.screen.home.messages
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.tween
import androidx.compose.animation.expandIn
import androidx.compose.animation.shrinkOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.ClipOp
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.DefaultShadowColor
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.addOutline
import androidx.compose.ui.graphics.drawscope.clipPath
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import co.electriccoin.zcash.ui.design.theme.colors.ZashiColors
import kotlinx.coroutines.delay
@Composable
fun HomeMessage(state: HomeMessageState?) {
val cutoutHeight = 16.dp
var normalizedState: HomeMessageState? by remember { mutableStateOf(state) }
var isVisible by remember { mutableStateOf(state != null) }
val bottomCornerSize by animateDpAsState(
if (isVisible) cutoutHeight else 0.dp,
animationSpec = tween(350)
)
Box(
modifier = Modifier
.background(Color.Gray)
) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(cutoutHeight)
.zIndex(2f)
.bottomOnlyShadow(
elevation = 2.dp,
shape = RoundedCornerShape(bottomStart = 32.dp, bottomEnd = 32.dp),
backgroundColor = ZashiColors.Surfaces.bgPrimary
),
)
AnimatedVisibility(
modifier = Modifier
.fillMaxWidth()
.zIndex(0f),
visible = isVisible,
enter = expandIn(animationSpec = tween(350)),
exit = shrinkOut(animationSpec = tween(350))
) {
when (normalizedState) {
is WalletBackupMessageState -> WalletBackupMessage(
state = normalizedState as WalletBackupMessageState,
contentPadding = PaddingValues(
vertical = cutoutHeight
)
)
null -> {
// do nothing
}
}
}
Box(
modifier = Modifier
.fillMaxWidth()
.height(cutoutHeight)
.zIndex(1f)
.align(Alignment.BottomCenter)
.topOnlyShadow(
elevation = 2.dp,
shape = RoundedCornerShape(topStart = bottomCornerSize, topEnd = bottomCornerSize),
backgroundColor = ZashiColors.Surfaces.bgPrimary
),
)
}
LaunchedEffect(state) {
if (state != null) {
normalizedState = state
isVisible = true
} else {
isVisible = false
delay(350)
normalizedState = null
}
}
}
private fun Modifier.bottomOnlyShadow(
elevation: Dp,
shape: Shape,
backgroundColor: Color,
clip: Boolean = elevation > 0.dp,
ambientColor: Color = DefaultShadowColor,
spotColor: Color = DefaultShadowColor,
): Modifier = this
.drawWithCache {
// bottom shadow offset in Px based on elevation
val bottomOffsetPx = elevation.toPx()
// Adjust the size to extend the bottom by the bottom shadow offset
val adjustedSize = Size(size.width, size.height + bottomOffsetPx)
val outline = shape.createOutline(adjustedSize, layoutDirection, this)
val path = Path().apply { addOutline(outline) }
onDrawWithContent {
clipPath(path, ClipOp.Intersect) {
this@onDrawWithContent.drawContent()
}
}
}
.shadow(elevation, shape, clip, ambientColor, spotColor)
.background(
backgroundColor,
shape
)
private fun Modifier.topOnlyShadow(
elevation: Dp,
shape: Shape,
backgroundColor: Color,
clip: Boolean = elevation > 0.dp,
ambientColor: Color = DefaultShadowColor,
spotColor: Color = DefaultShadowColor,
): Modifier = this
.drawWithCache {
// Adjust the size to extend the bottom by the bottom shadow offset
val adjustedSize = Size(size.width, size.height)
val outline = shape.createOutline(adjustedSize, layoutDirection, this)
val path = Path().apply { addOutline(outline) }
onDrawWithContent {
clipPath(path, ClipOp.Intersect) {
this@onDrawWithContent.drawContent()
}
}
}
.shadow(elevation, shape, clip, ambientColor, spotColor)
.background(
backgroundColor,
shape
)

View File

@ -0,0 +1,3 @@
package co.electriccoin.zcash.ui.screen.home.messages
sealed interface HomeMessageState

View File

@ -0,0 +1,37 @@
package co.electriccoin.zcash.ui.screen.home.messages
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
@Composable
fun HomeMessageWrapper(
color: Color,
contentPadding: PaddingValues,
content: @Composable RowScope.() -> Unit,
) {
Surface(
color = color,
) {
Box(
modifier = Modifier.padding(contentPadding)
) {
Row(
modifier = Modifier.padding(
horizontal = 16.dp,
vertical = 14.dp
),
verticalAlignment = Alignment.CenterVertically,
content = content
)
}
}
}

View File

@ -0,0 +1,81 @@
package co.electriccoin.zcash.ui.screen.home.messages
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.height
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.design.component.BlankSurface
import co.electriccoin.zcash.ui.design.component.ButtonState
import co.electriccoin.zcash.ui.design.component.HorizontalSpacer
import co.electriccoin.zcash.ui.design.component.VerticalSpacer
import co.electriccoin.zcash.ui.design.component.ZashiButton
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.design.theme.colors.ZashiColors
import co.electriccoin.zcash.ui.design.theme.typography.ZashiTypography
import co.electriccoin.zcash.ui.design.util.stringRes
@Composable
fun WalletBackupMessage(state: WalletBackupMessageState, contentPadding: PaddingValues) {
HomeMessageWrapper(
color = ZashiColors.Utility.Espresso.utilityEspresso100,
contentPadding = contentPadding,
) {
Image(
painter = painterResource(R.drawable.ic_warning_triangle),
contentDescription = null
)
HorizontalSpacer(16.dp)
Column(
modifier = Modifier.weight(1f)
) {
Text(
stringResource(R.string.home_message_backup_required_title),
style = ZashiTypography.textSm,
fontWeight = FontWeight.Medium,
color = ZashiColors.Utility.Espresso.utilityEspresso900
)
VerticalSpacer(2.dp)
Text(
text = stringResource(R.string.home_message_backup_required_subtitle),
style = ZashiTypography.textXs,
fontWeight = FontWeight.Medium,
color = ZashiColors.Utility.Espresso.utilityEspresso700
)
}
ZashiButton(
modifier = Modifier.height(36.dp),
state = ButtonState(
onClick = state.onClick,
text = stringRes("Start")
)
)
}
}
@Immutable
data class WalletBackupMessageState(
val onClick: () -> Unit,
) : HomeMessageState
@PreviewScreens
@Composable
private fun Preview() = ZcashTheme {
BlankSurface {
WalletBackupMessage(
state = WalletBackupMessageState(
onClick = {}
),
contentPadding = PaddingValues()
)
}
}

View File

@ -6,6 +6,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.window.DialogWindowProvider
@ -21,7 +22,6 @@ import org.koin.compose.koinInject
fun AndroidSeedInfo() {
val parent = LocalView.current.parent
val navigationRouter = koinInject<NavigationRouter>()
val scope = rememberCoroutineScope()
SideEffect {
(parent as? DialogWindowProvider)?.window?.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
@ -40,21 +40,8 @@ fun AndroidSeedInfo() {
SeedInfoView(
sheetState = sheetState,
state =
SeedInfoState(
onBack = {
scope.launch {
// sheetState.hide()
navigationRouter.back()
}
}
),
onDismissRequest = {
scope.launch {
// sheetState.hide()
navigationRouter.back()
}
}
state = remember { SeedInfoState(onBack = { navigationRouter.back() }) },
onDismissRequest = { navigationRouter.back() }
)
LaunchedEffect(Unit) {

View File

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M10,7.5V10.833M10,14.167H10.009M8.846,3.243L1.992,15.082C1.612,15.739 1.422,16.067 1.45,16.336C1.474,16.571 1.598,16.785 1.789,16.924C2.008,17.083 2.387,17.083 3.146,17.083H16.854C17.613,17.083 17.992,17.083 18.212,16.924C18.403,16.785 18.526,16.571 18.55,16.336C18.578,16.067 18.388,15.739 18.008,15.082L11.154,3.243C10.775,2.589 10.586,2.262 10.339,2.152C10.123,2.056 9.877,2.056 9.662,2.152C9.414,2.262 9.225,2.589 8.846,3.243Z"
android:strokeLineJoin="round"
android:strokeWidth="1.66667"
android:fillColor="#00000000"
android:strokeColor="#EBE9E9"
android:strokeLineCap="round"/>
</vector>

View File

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M10,7.5V10.833M10,14.167H10.009M8.846,3.243L1.992,15.082C1.612,15.739 1.422,16.067 1.45,16.336C1.474,16.572 1.598,16.785 1.789,16.924C2.008,17.083 2.387,17.083 3.146,17.083H16.854C17.613,17.083 17.992,17.083 18.212,16.924C18.403,16.785 18.526,16.572 18.55,16.336C18.578,16.067 18.388,15.739 18.008,15.082L11.154,3.243C10.775,2.589 10.586,2.262 10.339,2.152C10.123,2.056 9.877,2.056 9.662,2.152C9.414,2.262 9.225,2.589 8.846,3.243Z"
android:strokeLineJoin="round"
android:strokeWidth="1.66667"
android:fillColor="#00000000"
android:strokeColor="#332424"
android:strokeLineCap="round"/>
</vector>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="home_message_backup_required_title">Wallet Backup Required</string>
<string name="home_message_backup_required_subtitle">Prevent potential loss of funds</string>
</resources>