Restore estimation design added

This commit is contained in:
Milan Cerovsky 2025-03-13 09:41:20 +01:00
parent 43e1c36dfb
commit 3ee0934e52
15 changed files with 314 additions and 20 deletions

View File

@ -1,5 +1,7 @@
package co.electriccoin.zcash.ui.design.component package co.electriccoin.zcash.ui.design.component
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
@ -12,6 +14,16 @@ fun VerticalSpacer(height: Dp) {
Spacer(Modifier.height(height)) Spacer(Modifier.height(height))
} }
@Composable
fun ColumnScope.VerticalSpacer(weight: Float) {
Spacer(Modifier.weight(weight))
}
@Composable
fun RowScope.VerticalSpacer(weight: Float) {
Spacer(Modifier.weight(weight))
}
@Composable @Composable
fun HorizontalSpacer(width: Dp) { fun HorizontalSpacer(width: Dp) {
Spacer(Modifier.width(width)) Spacer(Modifier.width(width))

View File

@ -20,6 +20,7 @@ import co.electriccoin.zcash.ui.screen.qrcode.viewmodel.QrCodeViewModel
import co.electriccoin.zcash.ui.screen.receive.viewmodel.ReceiveViewModel import co.electriccoin.zcash.ui.screen.receive.viewmodel.ReceiveViewModel
import co.electriccoin.zcash.ui.screen.request.viewmodel.RequestViewModel import co.electriccoin.zcash.ui.screen.request.viewmodel.RequestViewModel
import co.electriccoin.zcash.ui.screen.restore.date.RestoreBDDateViewModel import co.electriccoin.zcash.ui.screen.restore.date.RestoreBDDateViewModel
import co.electriccoin.zcash.ui.screen.restore.estimation.RestoreBDEstimationViewModel
import co.electriccoin.zcash.ui.screen.restore.height.RestoreBDHeightViewModel import co.electriccoin.zcash.ui.screen.restore.height.RestoreBDHeightViewModel
import co.electriccoin.zcash.ui.screen.restore.seed.RestoreSeedViewModel import co.electriccoin.zcash.ui.screen.restore.seed.RestoreSeedViewModel
import co.electriccoin.zcash.ui.screen.restoresuccess.viewmodel.RestoreSuccessViewModel import co.electriccoin.zcash.ui.screen.restoresuccess.viewmodel.RestoreSuccessViewModel
@ -158,4 +159,5 @@ val viewModelModule =
viewModelOf(::HomeViewModel) viewModelOf(::HomeViewModel)
viewModelOf(::RestoreBDHeightViewModel) viewModelOf(::RestoreBDHeightViewModel)
viewModelOf(::RestoreBDDateViewModel) viewModelOf(::RestoreBDDateViewModel)
viewModelOf(::RestoreBDEstimationViewModel)
} }

View File

@ -31,6 +31,8 @@ import co.electriccoin.zcash.ui.screen.flexa.FlexaViewModel
import co.electriccoin.zcash.ui.screen.onboarding.view.Onboarding import co.electriccoin.zcash.ui.screen.onboarding.view.Onboarding
import co.electriccoin.zcash.ui.screen.restore.date.AndroidRestoreBDDate import co.electriccoin.zcash.ui.screen.restore.date.AndroidRestoreBDDate
import co.electriccoin.zcash.ui.screen.restore.date.RestoreBDDate import co.electriccoin.zcash.ui.screen.restore.date.RestoreBDDate
import co.electriccoin.zcash.ui.screen.restore.estimation.AndroidRestoreBDEstimation
import co.electriccoin.zcash.ui.screen.restore.estimation.RestoreBDEstimation
import co.electriccoin.zcash.ui.screen.restore.height.AndroidRestoreBDHeight import co.electriccoin.zcash.ui.screen.restore.height.AndroidRestoreBDHeight
import co.electriccoin.zcash.ui.screen.restore.height.RestoreBDHeight import co.electriccoin.zcash.ui.screen.restore.height.RestoreBDHeight
import co.electriccoin.zcash.ui.screen.restore.seed.AndroidRestoreSeed import co.electriccoin.zcash.ui.screen.restore.seed.AndroidRestoreSeed
@ -106,6 +108,9 @@ fun MainActivity.RestoreNavigation() {
composable<RestoreBDDate> { composable<RestoreBDDate> {
AndroidRestoreBDDate() AndroidRestoreBDDate()
} }
composable<RestoreBDEstimation> {
AndroidRestoreBDEstimation()
}
} }
} }

View File

@ -218,7 +218,7 @@ private fun QrCodeBottomBar(
ZashiButton( ZashiButton(
text = stringResource(id = R.string.qr_code_copy_btn), text = stringResource(id = R.string.qr_code_copy_btn),
icon = R.drawable.ic_copy, icon = R.drawable.ic_qr_copy,
onClick = { state.onAddressCopy(state.walletAddress.address) }, onClick = { state.onAddressCopy(state.walletAddress.address) },
colors = ZashiButtonDefaults.secondaryColors(), colors = ZashiButtonDefaults.secondaryColors(),
modifier = modifier =

View File

@ -9,6 +9,7 @@ import co.electriccoin.zcash.ui.design.component.ButtonState
import co.electriccoin.zcash.ui.design.component.IconButtonState import co.electriccoin.zcash.ui.design.component.IconButtonState
import co.electriccoin.zcash.ui.design.util.stringRes import co.electriccoin.zcash.ui.design.util.stringRes
import co.electriccoin.zcash.ui.screen.restore.RestoreSeedDialogState import co.electriccoin.zcash.ui.screen.restore.RestoreSeedDialogState
import co.electriccoin.zcash.ui.screen.restore.estimation.RestoreBDEstimation
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@ -46,7 +47,7 @@ class RestoreBDDateViewModel(
) )
private fun onEstimateClick() { private fun onEstimateClick() {
// do nothing navigationRouter.forward(RestoreBDEstimation)
} }
private fun onBack() { private fun onBack() {

View File

@ -0,0 +1,24 @@
package co.electriccoin.zcash.ui.screen.restore.estimation
import androidx.activity.compose.BackHandler
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import co.electriccoin.zcash.ui.screen.restore.RestoreSeedDialog
import kotlinx.serialization.Serializable
import org.koin.androidx.compose.koinViewModel
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AndroidRestoreBDEstimation() {
val vm = koinViewModel<RestoreBDEstimationViewModel>()
val state by vm.state.collectAsStateWithLifecycle()
val dialogState by vm.dialogState.collectAsStateWithLifecycle()
RestoreBDEstimationView(state)
BackHandler { state.onBack() }
RestoreSeedDialog(dialogState)
}
@Serializable
data object RestoreBDEstimation

View File

@ -0,0 +1,13 @@
package co.electriccoin.zcash.ui.screen.restore.estimation
import co.electriccoin.zcash.ui.design.component.ButtonState
import co.electriccoin.zcash.ui.design.component.IconButtonState
import co.electriccoin.zcash.ui.design.util.StringResource
data class RestoreBDEstimationState(
val text: StringResource,
val onBack: () -> Unit,
val dialogButton: IconButtonState,
val copy: ButtonState,
val restore: ButtonState,
)

View File

@ -0,0 +1,141 @@
@file:Suppress("TooManyFunctions")
package co.electriccoin.zcash.ui.screen.restore.estimation
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.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Text
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.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.appbar.ZashiTopAppBarTags
import co.electriccoin.zcash.ui.design.component.BlankBgScaffold
import co.electriccoin.zcash.ui.design.component.ButtonState
import co.electriccoin.zcash.ui.design.component.IconButtonState
import co.electriccoin.zcash.ui.design.component.VerticalSpacer
import co.electriccoin.zcash.ui.design.component.ZashiButton
import co.electriccoin.zcash.ui.design.component.ZashiButtonDefaults
import co.electriccoin.zcash.ui.design.component.ZashiIconButton
import co.electriccoin.zcash.ui.design.component.ZashiSmallTopAppBar
import co.electriccoin.zcash.ui.design.component.ZashiTopAppBarBackNavigation
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.getValue
import co.electriccoin.zcash.ui.design.util.orDark
import co.electriccoin.zcash.ui.design.util.scaffoldPadding
import co.electriccoin.zcash.ui.design.util.stringRes
@Composable
fun RestoreBDEstimationView(state: RestoreBDEstimationState) {
BlankBgScaffold(
topBar = { AppBar(state) },
bottomBar = {},
content = { padding ->
Content(
state = state,
modifier =
Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.scaffoldPadding(padding)
)
}
)
}
@Composable
private fun Content(
state: RestoreBDEstimationState,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
) {
Text(
text = stringResource(R.string.restore_bd_estimation_subtitle),
style = ZashiTypography.header6,
color = ZashiColors.Text.textPrimary,
fontWeight = FontWeight.SemiBold
)
VerticalSpacer(8.dp)
Text(
text = stringResource(R.string.restore_bd_estimation_message),
style = ZashiTypography.textSm,
color = ZashiColors.Text.textPrimary
)
VerticalSpacer(56.dp)
Text(
modifier = Modifier.fillMaxWidth(),
text = state.text.getValue(),
color = ZashiColors.Text.textPrimary,
style = ZashiTypography.header2,
fontWeight = FontWeight.SemiBold,
textAlign = TextAlign.Center
)
VerticalSpacer(12.dp)
ZashiButton(
modifier = Modifier.align(Alignment.CenterHorizontally),
state = state.copy,
colors = ZashiButtonDefaults.tertiaryColors()
)
VerticalSpacer(24.dp)
VerticalSpacer(1f)
ZashiButton(
state = state.restore,
modifier = Modifier.fillMaxWidth(),
)
}
}
@Composable
private fun AppBar(state: RestoreBDEstimationState) {
ZashiSmallTopAppBar(
title = stringResource(R.string.restore_title),
navigationAction = {
ZashiTopAppBarBackNavigation(
onBack = state.onBack,
modifier = Modifier.testTag(ZashiTopAppBarTags.BACK)
)
},
regularActions = {
ZashiIconButton(state.dialogButton, modifier = Modifier.size(40.dp))
Spacer(Modifier.width(20.dp))
},
colors =
ZcashTheme.colors.topAppBarColors orDark
ZcashTheme.colors.topAppBarColors.copyColors(
containerColor = Color.Transparent
),
)
}
@PreviewScreens
@Composable
private fun Preview() =
ZcashTheme {
RestoreBDEstimationView(
state =
RestoreBDEstimationState(
restore = ButtonState(stringRes("Estimate")) {},
dialogButton = IconButtonState(R.drawable.ic_restore_dialog) {},
onBack = {},
text = stringRes("123456"),
copy = ButtonState(stringRes("Copy"), icon = R.drawable.ic_copy) {}
)
)
}

View File

@ -0,0 +1,65 @@
package co.electriccoin.zcash.ui.screen.restore.estimation
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.design.component.ButtonState
import co.electriccoin.zcash.ui.design.component.IconButtonState
import co.electriccoin.zcash.ui.design.util.stringRes
import co.electriccoin.zcash.ui.screen.restore.RestoreSeedDialogState
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.WhileSubscribed
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
class RestoreBDEstimationViewModel(
private val navigationRouter: NavigationRouter
) : ViewModel() {
private val isDialogVisible = MutableStateFlow(false)
val dialogState =
isDialogVisible
.map { isDialogVisible ->
RestoreSeedDialogState(
::onCloseDialogClick
).takeIf { isDialogVisible }
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT),
initialValue = null
)
val state: StateFlow<RestoreBDEstimationState> = MutableStateFlow(createState()).asStateFlow()
private fun createState() =
RestoreBDEstimationState(
dialogButton = IconButtonState(icon = R.drawable.ic_info, onClick = ::onInfoButtonClick),
onBack = ::onBack,
text = stringRes("123456"),
copy = ButtonState(stringRes(R.string.restore_bd_estimation_copy), icon = R.drawable.ic_copy) {},
restore = ButtonState(stringRes(R.string.restore_bd_estimation_restore), onClick = ::onRestoreClick),
)
private fun onRestoreClick() {
// do nothing
}
private fun onBack() {
navigationRouter.back()
}
private fun onInfoButtonClick() {
isDialogVisible.update { true }
}
private fun onCloseDialogClick() {
isDialogVisible.update { false }
}
}

View File

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="21dp"
android:height="20dp"
android:viewportWidth="21"
android:viewportHeight="20">
<path
android:pathData="M4.667,12.5C3.89,12.5 3.502,12.5 3.196,12.373C2.787,12.204 2.463,11.879 2.294,11.471C2.167,11.165 2.167,10.776 2.167,10V4.333C2.167,3.4 2.167,2.933 2.348,2.577C2.508,2.263 2.763,2.008 3.077,1.848C3.433,1.666 3.9,1.666 4.833,1.666H10.5C11.277,1.666 11.665,1.666 11.971,1.793C12.38,1.963 12.704,2.287 12.873,2.695C13,3.002 13,3.39 13,4.167M10.667,18.333H16.167C17.1,18.333 17.567,18.333 17.923,18.152C18.237,17.992 18.492,17.737 18.652,17.423C18.833,17.067 18.833,16.6 18.833,15.667V10.167C18.833,9.233 18.833,8.766 18.652,8.41C18.492,8.096 18.237,7.841 17.923,7.681C17.567,7.5 17.1,7.5 16.167,7.5H10.667C9.733,7.5 9.267,7.5 8.91,7.681C8.596,7.841 8.342,8.096 8.182,8.41C8,8.766 8,9.233 8,10.167V15.667C8,16.6 8,17.067 8.182,17.423C8.342,17.737 8.596,17.992 8.91,18.152C9.267,18.333 9.733,18.333 10.667,18.333Z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#D2D1D2"
android:strokeLineCap="round"/>
</vector>

View File

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="21dp"
android:height="20dp"
android:viewportWidth="21"
android:viewportHeight="20">
<path
android:pathData="M4.667,12.5C3.89,12.5 3.502,12.5 3.196,12.373C2.787,12.204 2.463,11.88 2.294,11.471C2.167,11.165 2.167,10.777 2.167,10V4.333C2.167,3.4 2.167,2.933 2.348,2.577C2.508,2.263 2.763,2.008 3.077,1.848C3.433,1.667 3.9,1.667 4.833,1.667H10.5C11.277,1.667 11.665,1.667 11.971,1.794C12.38,1.963 12.704,2.287 12.873,2.696C13,3.002 13,3.39 13,4.167M10.667,18.333H16.167C17.1,18.333 17.567,18.333 17.923,18.152C18.237,17.992 18.492,17.737 18.652,17.423C18.833,17.067 18.833,16.6 18.833,15.667V10.167C18.833,9.233 18.833,8.767 18.652,8.41C18.492,8.096 18.237,7.842 17.923,7.682C17.567,7.5 17.1,7.5 16.167,7.5H10.667C9.733,7.5 9.267,7.5 8.91,7.682C8.596,7.842 8.342,8.096 8.182,8.41C8,8.767 8,9.233 8,10.167V15.667C8,16.6 8,17.067 8.182,17.423C8.342,17.737 8.596,17.992 8.91,18.152C9.267,18.333 9.733,18.333 10.667,18.333Z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#4D4941"
android:strokeLineCap="round"/>
</vector>

View File

@ -32,4 +32,9 @@
<string name="restore_bd_date_note">If youre not sure, choose an earlier date.</string> <string name="restore_bd_date_note">If youre not sure, choose an earlier date.</string>
<string name="restore_bd_date_next">Next</string> <string name="restore_bd_date_next">Next</string>
<string name="restore_bd_estimation_subtitle">Estimated Block Height</string>
<string name="restore_bd_estimation_message">Zashi will scan and recover all transactions made after the following block number.</string>
<string name="restore_bd_estimation_copy">Copy</string>
<string name="restore_bd_estimation_restore">Restore</string>
</resources> </resources>