Updated on 2026-08-14
This commit is contained in:
parent
e5c732e19d
commit
adaa72f359
6 changed files with 184 additions and 52 deletions
|
|
@ -28,9 +28,58 @@ internal data class SendUiState(
|
|||
val recipientState: SendStates.RecipientState? = null,
|
||||
val feeState: SendStates.FeeState? = null,
|
||||
val sendState: SendStates.SendState? = null,
|
||||
val editAmountState: SendStates.AmountState? = null,
|
||||
val editRecipientState: SendStates.RecipientState? = null,
|
||||
val editFeeState: SendStates.FeeState? = null,
|
||||
val isBalanceHidden: Boolean,
|
||||
val event: StateEvent<SendEvent>,
|
||||
)
|
||||
) {
|
||||
|
||||
fun getAmountState(isEditState: Boolean): SendStates.AmountState? {
|
||||
return if (isEditState) {
|
||||
editAmountState
|
||||
} else {
|
||||
amountState
|
||||
}
|
||||
}
|
||||
|
||||
fun getRecipientState(isEditState: Boolean): SendStates.RecipientState? {
|
||||
return if (isEditState) {
|
||||
editRecipientState
|
||||
} else {
|
||||
recipientState
|
||||
}
|
||||
}
|
||||
|
||||
fun getFeeState(isEditState: Boolean): SendStates.FeeState? {
|
||||
return if (isEditState) {
|
||||
editFeeState
|
||||
} else {
|
||||
feeState
|
||||
}
|
||||
}
|
||||
|
||||
fun copyWrapped(
|
||||
isEditState: Boolean,
|
||||
amountState: SendStates.AmountState? = this.amountState,
|
||||
feeState: SendStates.FeeState? = this.feeState,
|
||||
recipientState: SendStates.RecipientState? = this.recipientState,
|
||||
sendState: SendStates.SendState? = this.sendState,
|
||||
): SendUiState = if (isEditState) {
|
||||
copy(
|
||||
editAmountState = amountState,
|
||||
editFeeState = feeState,
|
||||
editRecipientState = recipientState,
|
||||
)
|
||||
} else {
|
||||
copy(
|
||||
amountState = amountState,
|
||||
feeState = feeState,
|
||||
recipientState = recipientState,
|
||||
sendState = sendState,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
internal sealed class SendStates {
|
||||
|
|
@ -105,6 +154,9 @@ enum class SendUiStateType {
|
|||
None,
|
||||
Recipient,
|
||||
Amount,
|
||||
Send,
|
||||
Fee,
|
||||
Send,
|
||||
EditAmount,
|
||||
EditRecipient,
|
||||
EditFee,
|
||||
}
|
||||
|
|
@ -18,6 +18,9 @@ internal class StateRouter(
|
|||
val currentState: StateFlow<SendUiCurrentScreen>
|
||||
get() = mutableCurrentState
|
||||
|
||||
val isEditState: Boolean
|
||||
get() = currentState.value.isFromConfirmation
|
||||
|
||||
fun clear() {
|
||||
mutableCurrentState.update { getInitState() }
|
||||
}
|
||||
|
|
@ -35,21 +38,29 @@ internal class StateRouter(
|
|||
else -> popBackStack()
|
||||
}
|
||||
else -> when (type) {
|
||||
SendUiStateType.Amount -> continueToSend(::showRecipient)
|
||||
SendUiStateType.Amount -> showRecipient()
|
||||
SendUiStateType.Fee -> showSend()
|
||||
SendUiStateType.Send -> continueToSend(::showAmount)
|
||||
else -> continueToSend(::popBackStack)
|
||||
SendUiStateType.Send -> showAmount()
|
||||
SendUiStateType.Recipient -> popBackStack()
|
||||
SendUiStateType.EditAmount -> showSend()
|
||||
SendUiStateType.EditRecipient -> showSend()
|
||||
SendUiStateType.EditFee -> showSend()
|
||||
else -> popBackStack()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onNextClick() {
|
||||
when (currentState.value.type) {
|
||||
SendUiStateType.Recipient -> continueToSend(::showAmount)
|
||||
SendUiStateType.Recipient -> showAmount()
|
||||
SendUiStateType.Amount,
|
||||
SendUiStateType.Fee,
|
||||
SendUiStateType.EditAmount,
|
||||
SendUiStateType.EditRecipient,
|
||||
SendUiStateType.EditFee,
|
||||
-> showSend()
|
||||
SendUiStateType.Send -> onBackClick()
|
||||
|
||||
else -> popBackStack()
|
||||
}
|
||||
}
|
||||
|
|
@ -67,17 +78,35 @@ internal class StateRouter(
|
|||
|
||||
fun showAmount(isFromConfirmation: Boolean = false) {
|
||||
analyticsEventsHandler.send(SendAnalyticEvents.AmountScreenOpened)
|
||||
mutableCurrentState.update { SendUiCurrentScreen(SendUiStateType.Amount, isFromConfirmation) }
|
||||
mutableCurrentState.update {
|
||||
if (isFromConfirmation) {
|
||||
SendUiCurrentScreen(SendUiStateType.EditAmount, true)
|
||||
} else {
|
||||
SendUiCurrentScreen(SendUiStateType.Amount, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun showRecipient(isFromConfirmation: Boolean = false) {
|
||||
analyticsEventsHandler.send(SendAnalyticEvents.AddressScreenOpened)
|
||||
mutableCurrentState.update { SendUiCurrentScreen(SendUiStateType.Recipient, isFromConfirmation) }
|
||||
mutableCurrentState.update {
|
||||
if (isFromConfirmation) {
|
||||
SendUiCurrentScreen(SendUiStateType.EditRecipient, true)
|
||||
} else {
|
||||
SendUiCurrentScreen(SendUiStateType.Recipient, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun showFee(isFromConfirmation: Boolean = false) {
|
||||
analyticsEventsHandler.send(SendAnalyticEvents.FeeScreenOpened)
|
||||
mutableCurrentState.update { SendUiCurrentScreen(SendUiStateType.Fee, isFromConfirmation) }
|
||||
mutableCurrentState.update {
|
||||
if (isFromConfirmation) {
|
||||
SendUiCurrentScreen(SendUiStateType.EditFee, true)
|
||||
} else {
|
||||
SendUiCurrentScreen(SendUiStateType.Fee, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun showSend() {
|
||||
|
|
@ -85,10 +114,6 @@ internal class StateRouter(
|
|||
mutableCurrentState.update { SendUiCurrentScreen(SendUiStateType.Send, isFromConfirmation = false) }
|
||||
}
|
||||
|
||||
private fun continueToSend(show: () -> Unit) {
|
||||
if (currentState.value.isFromConfirmation) showSend() else show()
|
||||
}
|
||||
|
||||
private fun getInitState() = if (isEditingDisabled) {
|
||||
SendUiCurrentScreen(
|
||||
type = SendUiStateType.None,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.features.send.impl.presentation.state.common
|
||||
|
||||
import com.tangem.features.send.impl.presentation.state.SendUiState
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class SendSyncEditConverter(
|
||||
private val currentStateProvider: Provider<SendUiState>,
|
||||
) : Converter<Boolean, SendUiState> {
|
||||
override fun convert(value: Boolean): SendUiState {
|
||||
val state = currentStateProvider()
|
||||
return if (value) {
|
||||
state.copy(
|
||||
amountState = state.editAmountState,
|
||||
feeState = state.editFeeState,
|
||||
recipientState = state.editRecipientState,
|
||||
)
|
||||
} else {
|
||||
state.copy(
|
||||
editAmountState = state.amountState,
|
||||
editRecipientState = state.recipientState,
|
||||
editFeeState = state.feeState,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@ internal object SendClickIntentsStub : SendClickIntents {
|
|||
|
||||
override fun onBackClick() {}
|
||||
|
||||
override fun onNextClick() {}
|
||||
override fun onNextClick(isFromEdit: Boolean) {}
|
||||
|
||||
override fun onPrevClick() {}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
package com.tangem.features.send.impl.presentation.ui
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedContentTransitionScope
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
|
|
@ -23,12 +26,13 @@ import com.tangem.features.send.impl.presentation.ui.fee.SendSpeedAndFeeContent
|
|||
import com.tangem.features.send.impl.presentation.ui.recipient.SendRecipientContent
|
||||
import com.tangem.features.send.impl.presentation.ui.send.SendContent
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.withIndex
|
||||
|
||||
@Composable
|
||||
internal fun SendScreen(uiState: SendUiState, currentState: SendUiCurrentScreen) {
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val sendState = uiState.sendState ?: return
|
||||
BackHandler { uiState.clickIntents.onBackClick() }
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
|
@ -38,38 +42,9 @@ internal fun SendScreen(uiState: SendUiState, currentState: SendUiCurrentScreen)
|
|||
.background(color = TangemTheme.colors.background.tertiary),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
val titleRes = when (currentState.type) {
|
||||
SendUiStateType.Amount -> resourceReference(R.string.send_amount_label)
|
||||
SendUiStateType.Recipient -> resourceReference(R.string.send_recipient_label)
|
||||
SendUiStateType.Fee -> resourceReference(R.string.common_fee_selector_title)
|
||||
SendUiStateType.Send -> if (!sendState.isSuccess) {
|
||||
resourceReference(R.string.send_summary_title, wrappedList(uiState.cryptoCurrencyName))
|
||||
} else {
|
||||
null
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
val isSending = currentState.type == SendUiStateType.Send && !uiState.sendState.isSuccess
|
||||
val subtitleRes = if (isSending) {
|
||||
uiState.amountState?.walletName
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val iconRes = if (currentState.type == SendUiStateType.Recipient) {
|
||||
R.drawable.ic_qrcode_scan_24
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
AppBarWithBackButtonAndIcon(
|
||||
text = titleRes?.resolveReference(),
|
||||
subtitle = subtitleRes,
|
||||
onBackClick = uiState.clickIntents::popBackStack,
|
||||
onIconClick = uiState.clickIntents::onQrCodeScanClick,
|
||||
backIconRes = R.drawable.ic_close_24,
|
||||
iconRes = iconRes,
|
||||
backgroundColor = TangemTheme.colors.background.tertiary,
|
||||
modifier = Modifier.height(TangemTheme.dimens.size56),
|
||||
SendAppBar(
|
||||
uiState = uiState,
|
||||
currentState = currentState,
|
||||
)
|
||||
SendScreenContent(
|
||||
uiState = uiState,
|
||||
|
|
@ -88,6 +63,50 @@ internal fun SendScreen(uiState: SendUiState, currentState: SendUiCurrentScreen)
|
|||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SendAppBar(uiState: SendUiState, currentState: SendUiCurrentScreen) {
|
||||
val (titleRes, subtitleRes) = when (currentState.type) {
|
||||
SendUiStateType.Amount,
|
||||
SendUiStateType.EditAmount,
|
||||
-> resourceReference(R.string.send_amount_label) to null
|
||||
SendUiStateType.Recipient,
|
||||
SendUiStateType.EditRecipient,
|
||||
-> resourceReference(R.string.send_recipient_label) to null
|
||||
SendUiStateType.Fee,
|
||||
SendUiStateType.EditFee,
|
||||
-> resourceReference(R.string.common_fee_selector_title) to null
|
||||
SendUiStateType.Send -> if (uiState.sendState?.isSuccess == false) {
|
||||
resourceReference(R.string.send_summary_title, wrappedList(uiState.cryptoCurrencyName)) to
|
||||
uiState.amountState?.walletName
|
||||
} else {
|
||||
null to null
|
||||
}
|
||||
else -> null to null
|
||||
}
|
||||
val iconRes = if (currentState.type == SendUiStateType.Recipient) {
|
||||
R.drawable.ic_qrcode_scan_24
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val (backIcon, backClick) = when (currentState.type) {
|
||||
SendUiStateType.EditAmount,
|
||||
SendUiStateType.EditFee,
|
||||
SendUiStateType.EditRecipient,
|
||||
-> R.drawable.ic_back_24 to uiState.clickIntents::onBackClick
|
||||
else -> R.drawable.ic_close_24 to uiState.clickIntents::popBackStack
|
||||
}
|
||||
AppBarWithBackButtonAndIcon(
|
||||
text = titleRes?.resolveReference(),
|
||||
subtitle = subtitleRes,
|
||||
onBackClick = backClick,
|
||||
onIconClick = uiState.clickIntents::onQrCodeScanClick,
|
||||
backIconRes = backIcon,
|
||||
iconRes = iconRes,
|
||||
backgroundColor = TangemTheme.colors.background.tertiary,
|
||||
modifier = Modifier.height(TangemTheme.dimens.size56),
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalAnimationApi::class)
|
||||
@Composable
|
||||
private fun SendScreenContent(uiState: SendUiState, currentState: SendUiCurrentScreen, modifier: Modifier = Modifier) {
|
||||
|
|
@ -135,13 +154,23 @@ private fun SendScreenContent(uiState: SendUiState, currentState: SendUiCurrentS
|
|||
isBalanceHiding = uiState.isBalanceHidden,
|
||||
clickIntents = uiState.clickIntents,
|
||||
)
|
||||
SendUiStateType.EditAmount -> SendAmountContent(
|
||||
amountState = uiState.editAmountState,
|
||||
isBalanceHiding = uiState.isBalanceHidden,
|
||||
clickIntents = uiState.clickIntents,
|
||||
)
|
||||
SendUiStateType.Recipient -> SendRecipientContent(
|
||||
uiState = uiState.recipientState,
|
||||
clickIntents = uiState.clickIntents,
|
||||
isBalanceHidden = uiState.isBalanceHidden,
|
||||
)
|
||||
SendUiStateType.Fee -> SendSpeedAndFeeContent(
|
||||
state = uiState.feeState,
|
||||
SendUiStateType.EditRecipient -> SendRecipientContent(
|
||||
uiState = uiState.editRecipientState,
|
||||
clickIntents = uiState.clickIntents,
|
||||
isBalanceHidden = uiState.isBalanceHidden,
|
||||
)
|
||||
SendUiStateType.EditFee -> SendSpeedAndFeeContent(
|
||||
state = uiState.editFeeState,
|
||||
clickIntents = uiState.clickIntents,
|
||||
)
|
||||
SendUiStateType.Send -> SendContent(uiState)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ internal interface SendClickIntents {
|
|||
|
||||
fun onBackClick()
|
||||
|
||||
fun onNextClick()
|
||||
fun onNextClick(isFromEdit: Boolean = false)
|
||||
|
||||
fun onPrevClick()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue