From 35898a31cd9b44b45024344c05c83890905fadb0 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 20 Feb 2024 19:24:05 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../state/SendNotificationFactory.kt | 2 +- .../presentation/state/SendStateFactory.kt | 2 +- .../impl/presentation/state/SendUiState.kt | 8 ++- .../impl/presentation/state/StateRouter.kt | 55 +++++++++++-------- .../state/fee/FeeNotificationFactory.kt | 2 +- .../presentation/ui/SendNavigationButtons.kt | 45 +++++++++------ .../send/impl/presentation/ui/SendScreen.kt | 11 ++-- .../presentation/viewmodel/SendViewModel.kt | 10 ++-- 8 files changed, 82 insertions(+), 53 deletions(-) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotificationFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotificationFactory.kt index 05d56ca70b..cdfb8fc271 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotificationFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotificationFactory.kt @@ -27,7 +27,7 @@ internal class SendNotificationFactory( ) { fun create(): Flow> = currentStateProvider().currentState - .filter { it == SendUiStateType.Send } + .filter { it.type == SendUiStateType.Send } .map { val state = currentStateProvider() val feeState = state.feeState ?: return@map persistentListOf() diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt index 57a1a698ae..bbace2d0ac 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt @@ -78,7 +78,7 @@ internal class SendStateFactory( // region UI states fun getInitialState(): SendUiState = SendUiState( clickIntents = clickIntents, - currentState = MutableStateFlow(SendUiStateType.None), + currentState = MutableStateFlow(SendUiCurrentScreen(type = SendUiStateType.None, isFromConfirmation = false)), event = consumedEvent(), isEditingDisabled = false, isBalanceHidden = false, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt index 1828a6b3ed..9f1c13016c 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt @@ -33,7 +33,7 @@ internal data class SendUiState( val feeState: SendStates.FeeState? = null, val sendState: SendStates.SendState = SendStates.SendState(), val recipientList: MutableStateFlow> = MutableStateFlow(PagingData.empty()), - val currentState: StateFlow, + val currentState: StateFlow, val isBalanceHidden: Boolean, val event: StateEvent, ) @@ -97,10 +97,16 @@ internal sealed class SendStates { val transactionDate: Long = 0L, val txUrl: String = "", val ignoreAmountReduce: Boolean = false, + val isFromConfirmation: Boolean = true, val notifications: ImmutableList = persistentListOf(), ) : SendStates() } +data class SendUiCurrentScreen( + val type: SendUiStateType, + val isFromConfirmation: Boolean, +) + enum class SendUiStateType { None, Amount, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/StateRouter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/StateRouter.kt index ea62b4700d..21a6c3e9db 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/StateRouter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/StateRouter.kt @@ -14,58 +14,65 @@ internal class StateRouter( private val analyticsEventsHandler: AnalyticsEventHandler, private val isEditingDisabled: Boolean, ) { - private var mutableCurrentState: MutableStateFlow = MutableStateFlow( + private var mutableCurrentState: MutableStateFlow = MutableStateFlow( if (isEditingDisabled) { - SendUiStateType.None + SendUiCurrentScreen( + type = SendUiStateType.None, + isFromConfirmation = false, + ) } else { - SendUiStateType.Recipient + SendUiCurrentScreen( + type = SendUiStateType.Recipient, + isFromConfirmation = false, + ) }, ) - val currentState: StateFlow = mutableCurrentState + val currentState: StateFlow = mutableCurrentState fun popBackStack() { fragmentManager.get()?.popBackStack() } fun onBackClick(isSuccess: Boolean = false) { + val type = currentState.value.type when { isSuccess -> popBackStack() - isEditingDisabled -> when (currentState.value) { + isEditingDisabled -> when (type) { SendUiStateType.Send -> { analyticsEventsHandler.send(SendAnalyticEvents.BackButtonClicked(SendScreenSource.Fee)) showFee() } else -> popBackStack() } - else -> when (currentState.value) { + else -> when (type) { SendUiStateType.Amount -> { analyticsEventsHandler.send(SendAnalyticEvents.BackButtonClicked(SendScreenSource.Address)) - showRecipient() + continueToSend(::showRecipient) } SendUiStateType.Fee -> { analyticsEventsHandler.send(SendAnalyticEvents.BackButtonClicked(SendScreenSource.Amount)) - showAmount() + continueToSend(::showAmount) } SendUiStateType.Send -> { analyticsEventsHandler.send(SendAnalyticEvents.BackButtonClicked(SendScreenSource.Fee)) - showFee() + continueToSend(::showFee) } - else -> popBackStack() + else -> continueToSend(::popBackStack) } } } fun onNextClick(): SendUiStateType { - val prevState = currentState.value - when (currentState.value) { + val prevState = currentState.value.type + when (currentState.value.type) { SendUiStateType.Recipient -> { analyticsEventsHandler.send(SendAnalyticEvents.NextButtonClicked(SendScreenSource.Amount)) - showAmount() + continueToSend(::showAmount) } SendUiStateType.Amount -> { analyticsEventsHandler.send(SendAnalyticEvents.NextButtonClicked(SendScreenSource.Fee)) - showFee() + continueToSend(::showFee) } SendUiStateType.Fee -> { analyticsEventsHandler.send(SendAnalyticEvents.NextButtonClicked(SendScreenSource.Fee)) @@ -83,7 +90,7 @@ internal class StateRouter( if (isEditingDisabled) { popBackStack() } else { - when (currentState.value) { + when (currentState.value.type) { SendUiStateType.Amount -> { analyticsEventsHandler.send(SendAnalyticEvents.BackButtonClicked(SendScreenSource.Amount)) showRecipient() @@ -97,23 +104,27 @@ internal class StateRouter( } } - fun showAmount() { + fun showAmount(isFromConfirmation: Boolean = false) { analyticsEventsHandler.send(SendAnalyticEvents.AmountScreenOpened) - mutableCurrentState.update { SendUiStateType.Amount } + mutableCurrentState.update { SendUiCurrentScreen(SendUiStateType.Amount, isFromConfirmation) } } - fun showRecipient() { + fun showRecipient(isFromConfirmation: Boolean = false) { analyticsEventsHandler.send(SendAnalyticEvents.AddressScreenOpened) - mutableCurrentState.update { SendUiStateType.Recipient } + mutableCurrentState.update { SendUiCurrentScreen(SendUiStateType.Recipient, isFromConfirmation) } } - fun showFee() { + fun showFee(isFromConfirmation: Boolean = false) { analyticsEventsHandler.send(SendAnalyticEvents.FeeScreenOpened) - mutableCurrentState.update { SendUiStateType.Fee } + mutableCurrentState.update { SendUiCurrentScreen(SendUiStateType.Fee, isFromConfirmation) } + } + + private fun continueToSend(show: () -> Unit) { + if (currentState.value.isFromConfirmation) showSend() else show() } private fun showSend() { analyticsEventsHandler.send(SendAnalyticEvents.ConfirmationScreenOpened) - mutableCurrentState.update { SendUiStateType.Send } + mutableCurrentState.update { SendUiCurrentScreen(SendUiStateType.Send, isFromConfirmation = false) } } } \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeNotificationFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeNotificationFactory.kt index fd4fa1da94..3581ba0610 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeNotificationFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeNotificationFactory.kt @@ -32,7 +32,7 @@ internal class FeeNotificationFactory( ) { fun create() = currentStateProvider().currentState - .filter { it == SendUiStateType.Fee } + .filter { it.type == SendUiStateType.Fee } .map { val state = currentStateProvider() val feeState = state.feeState ?: return@map persistentListOf() diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt index b0462ca18f..6fe98a42ac 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt @@ -15,7 +15,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.runtime.State -import androidx.compose.runtime.collectAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -24,25 +23,29 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.tangem.core.ui.R import com.tangem.core.ui.components.* import com.tangem.core.ui.extensions.rememberHapticFeedback import com.tangem.core.ui.extensions.shareText import com.tangem.core.ui.res.TangemTheme +import com.tangem.features.send.impl.presentation.state.SendUiCurrentScreen import com.tangem.features.send.impl.presentation.state.SendUiState import com.tangem.features.send.impl.presentation.state.SendUiStateType @Composable -internal fun SendNavigationButtons(uiState: SendUiState) { +internal fun SendNavigationButtons(uiState: SendUiState, currentState: State) { Row( modifier = Modifier .fillMaxWidth() .padding(bottom = TangemTheme.dimens.spacing12), ) { - SendSecondaryNavigationButton(uiState) + SendSecondaryNavigationButton( + uiState = uiState, + currentState = currentState, + ) SendPrimaryNavigationButton( uiState = uiState, + currentState = currentState, modifier = Modifier .weight(1f) .padding(horizontal = TangemTheme.dimens.spacing16), @@ -51,12 +54,13 @@ internal fun SendNavigationButtons(uiState: SendUiState) { } @Composable -private fun SendSecondaryNavigationButton(uiState: SendUiState) { - val currentState = uiState.currentState.collectAsState() +private fun SendSecondaryNavigationButton(uiState: SendUiState, currentState: State) { val isEditingDisabled = uiState.isEditingDisabled - val isCorrectScreen = currentState.value == SendUiStateType.Amount || currentState.value == SendUiStateType.Fee + val isFromConfirmation = currentState.value.isFromConfirmation + val isCorrectScreen = + currentState.value.type == SendUiStateType.Amount || currentState.value.type == SendUiStateType.Fee AnimatedVisibility( - visible = !isEditingDisabled && isCorrectScreen, + visible = !isEditingDisabled && isCorrectScreen && !isFromConfirmation, enter = expandHorizontally(expandFrom = Alignment.End), exit = shrinkHorizontally(shrinkTowards = Alignment.End), ) { @@ -77,8 +81,11 @@ private fun SendSecondaryNavigationButton(uiState: SendUiState) { } @Composable -private fun SendPrimaryNavigationButton(uiState: SendUiState, modifier: Modifier = Modifier) { - val currentState = uiState.currentState.collectAsStateWithLifecycle() +private fun SendPrimaryNavigationButton( + uiState: SendUiState, + currentState: State, + modifier: Modifier = Modifier, +) { val isSuccess = uiState.sendState.isSuccess val isSending = uiState.sendState.isSending val txUrl = uiState.sendState.txUrl @@ -100,7 +107,7 @@ private fun SendPrimaryNavigationButton(uiState: SendUiState, modifier: Modifier modifier = modifier, ) { textId -> when { - currentState.value == SendUiStateType.Send && !isSuccess -> { + currentState.value.type == SendUiStateType.Send && !isSuccess -> { val hapticFeedback = rememberHapticFeedback(state = currentState, onAction = buttonClick) PrimaryButtonIconEnd( text = stringResource(textId), @@ -110,7 +117,7 @@ private fun SendPrimaryNavigationButton(uiState: SendUiState, modifier: Modifier showProgress = isSending, ) } - currentState.value == SendUiStateType.Send && isSuccess -> { + currentState.value.type == SendUiStateType.Send && isSuccess -> { PrimaryButtonsDone( textRes = textId, txUrl = txUrl, @@ -177,15 +184,19 @@ private fun PrimaryButtonsDone( private fun getButtonData( uiState: SendUiState, - currentState: State, + currentState: State, isSuccess: Boolean, ): Pair Unit> { - return when (currentState.value) { + return when (currentState.value.type) { SendUiStateType.None, SendUiStateType.Amount, SendUiStateType.Recipient, SendUiStateType.Fee, - -> R.string.common_next to uiState.clickIntents::onNextClick + -> if (currentState.value.isFromConfirmation) { + R.string.common_continue to uiState.clickIntents::onNextClick + } else { + R.string.common_next to uiState.clickIntents::onNextClick + } SendUiStateType.Send -> if (isSuccess) { R.string.common_close } else { @@ -194,8 +205,8 @@ private fun getButtonData( } } -private fun isButtonEnabled(currentState: State, uiState: SendUiState): Boolean { - return when (currentState.value) { +private fun isButtonEnabled(currentState: State, uiState: SendUiState): Boolean { + return when (currentState.value.type) { SendUiStateType.Amount -> uiState.amountState?.isPrimaryButtonEnabled ?: false SendUiStateType.Recipient -> uiState.recipientState?.isPrimaryButtonEnabled ?: false SendUiStateType.Fee -> uiState.feeState?.isPrimaryButtonEnabled ?: false diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendScreen.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendScreen.kt index 88c36f0d4c..6e862d9e07 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendScreen.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendScreen.kt @@ -19,6 +19,7 @@ import androidx.paging.compose.collectAsLazyPagingItems import com.tangem.core.ui.components.appbar.AppBarWithBackButtonAndIcon import com.tangem.core.ui.res.TangemTheme import com.tangem.features.send.impl.R +import com.tangem.features.send.impl.presentation.state.SendUiCurrentScreen import com.tangem.features.send.impl.presentation.state.SendUiState import com.tangem.features.send.impl.presentation.state.SendUiStateType import com.tangem.features.send.impl.presentation.ui.amount.SendAmountContent @@ -40,14 +41,14 @@ internal fun SendScreen(uiState: SendUiState) { .background(color = TangemTheme.colors.background.tertiary), horizontalAlignment = Alignment.CenterHorizontally, ) { - val titleRes = when (currentState.value) { + val titleRes = when (currentState.value.type) { SendUiStateType.Amount -> R.string.send_amount_label SendUiStateType.Recipient -> R.string.send_recipient_label SendUiStateType.Fee -> R.string.common_fee_selector_title SendUiStateType.Send -> if (!isSuccess) R.string.send_confirm_label else null else -> null } - val iconRes = if (currentState.value == SendUiStateType.Recipient) { + val iconRes = if (currentState.value.type == SendUiStateType.Recipient) { R.drawable.ic_qrcode_scan_24 } else { null @@ -67,7 +68,7 @@ internal fun SendScreen(uiState: SendUiState) { modifier = Modifier .weight(1f), ) - SendNavigationButtons(uiState) + SendNavigationButtons(uiState, currentState) } SendEventEffect( @@ -79,7 +80,7 @@ internal fun SendScreen(uiState: SendUiState) { @Composable private fun SendScreenContent( uiState: SendUiState, - currentState: State, + currentState: State, modifier: Modifier = Modifier, ) { val recipientList = uiState.recipientList.collectAsLazyPagingItems() @@ -88,7 +89,7 @@ private fun SendScreenContent( label = "Send Scree Navigation", modifier = modifier, ) { state -> - when (state) { + when (state.type) { SendUiStateType.Amount -> SendAmountContent( amountState = uiState.amountState, isBalanceHiding = uiState.isBalanceHidden, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt index c202ee727b..b1da2b4460 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt @@ -377,8 +377,8 @@ internal class SendViewModel @Inject constructor( private fun onStateActive() { uiState.currentState .onEach { - when (it) { - SendUiStateType.Fee -> loadFee() + when (it.type) { + SendUiStateType.Fee -> if (!it.isFromConfirmation) loadFee() SendUiStateType.Send -> sendIdleTimer = System.currentTimeMillis() else -> Unit } @@ -576,17 +576,17 @@ internal class SendViewModel @Inject constructor( } override fun showAmount() { - stateRouter.showAmount() + stateRouter.showAmount(isFromConfirmation = true) analyticsEventHandler.send(SendAnalyticEvents.ScreenReopened(SendScreenSource.Amount)) } override fun showRecipient() { - stateRouter.showRecipient() + stateRouter.showRecipient(isFromConfirmation = true) analyticsEventHandler.send(SendAnalyticEvents.ScreenReopened(SendScreenSource.Address)) } override fun showFee() { - stateRouter.showFee() + stateRouter.showFee(isFromConfirmation = true) analyticsEventHandler.send(SendAnalyticEvents.ScreenReopened(SendScreenSource.Fee)) }