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 4edb445226..f29ae7acb7 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 @@ -15,12 +15,16 @@ internal class StateRouter( fragmentManager.get()?.popBackStack() } - fun onBackClick() { - when (currentState.value) { - SendUiStateType.Recipient -> popBackStack() - SendUiStateType.Amount -> showRecipient() - SendUiStateType.Fee -> showAmount() - SendUiStateType.Send -> showFee() + fun onBackClick(isSuccess: Boolean = false) { + if (isSuccess) { + popBackStack() + } else { + when (currentState.value) { + SendUiStateType.Recipient -> popBackStack() + SendUiStateType.Amount -> showRecipient() + SendUiStateType.Fee -> showAmount() + SendUiStateType.Send -> showFee() + } } } @@ -54,7 +58,7 @@ internal class StateRouter( currentState.update { SendUiStateType.Fee } } - private fun showSend() { + fun showSend() { currentState.update { SendUiStateType.Send } } } \ 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 244ed17cdd..d95031bd4e 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 @@ -70,7 +70,7 @@ internal class FeeNotificationFactory( val customAmount = customFee.firstOrNull() ?: return val customValue = customAmount.value.parseToBigDecimal(customAmount.decimals) if (selectedFee == FeeType.CUSTOM && minimumValue > customValue) { - add(SendFeeNotification.Informational.TooLow) + add(SendFeeNotification.Warning.TooLow) } } diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeNotification.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeNotification.kt index d58cb3cd98..f895fb4921 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeNotification.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeNotification.kt @@ -8,22 +8,6 @@ import com.tangem.features.send.impl.R sealed class SendFeeNotification(val config: NotificationConfig) { - sealed class Informational( - val title: TextReference, - val subtitle: TextReference, - ) : SendFeeNotification( - config = NotificationConfig( - title = title, - subtitle = subtitle, - iconResId = R.drawable.ic_alert_circle_24, - ), - ) { - object TooLow : Informational( - title = resourceReference(id = R.string.send_notification_transaction_delay_title), - subtitle = resourceReference(id = R.string.send_notification_transaction_delay_text), - ) - } - sealed class Warning( val title: TextReference, val subtitle: TextReference, @@ -36,6 +20,11 @@ sealed class SendFeeNotification(val config: NotificationConfig) { buttonsState = buttonsState, ), ) { + object TooLow : Warning( + title = resourceReference(id = R.string.send_notification_transaction_delay_title), + subtitle = resourceReference(id = R.string.send_notification_transaction_delay_text), + ) + data class TooHigh( val value: String, ) : Warning( diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedAndFeeContent.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedAndFeeContent.kt index b253efe2e5..0c1316c178 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedAndFeeContent.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedAndFeeContent.kt @@ -15,14 +15,15 @@ import com.tangem.core.ui.components.notifications.Notification import com.tangem.core.ui.res.TangemTheme import com.tangem.features.send.impl.presentation.state.SendStates import com.tangem.features.send.impl.presentation.state.fee.FeeSelectorState +import com.tangem.features.send.impl.presentation.state.fee.FeeType import com.tangem.features.send.impl.presentation.state.fee.SendFeeNotification import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList private const val FEE_SELECTOR_KEY = "FEE_SELECTOR_KEY" private const val FEE_CUSTOM_KEY = "FEE_CUSTOM_KEY" -@OptIn(ExperimentalFoundationApi::class) @Composable internal fun SendSpeedAndFeeContent(state: SendStates.FeeState?, clickIntents: SendClickIntents) { if (state == null) return @@ -36,46 +37,92 @@ internal fun SendSpeedAndFeeContent(state: SendStates.FeeState?, clickIntents: S horizontal = TangemTheme.dimens.spacing16, ), ) { - item( - key = FEE_SELECTOR_KEY, - ) { - SendSpeedSelector( - state = state, - clickIntents = clickIntents, - modifier = Modifier.animateItemPlacement(), - ) - } + feeSelector(state, clickIntents) + topNotifications(notifications) customFee(feeSendState) - notifications(notifications) - subtractButton( - receivedAmount = state.receivedAmount, - isSubtract = state.isSubtract, - isSubtractAvailable = state.isSubtractAvailable, - clickIntents = clickIntents, - ) + middleNotifications(notifications) + subtractButton(state, clickIntents) + bottomNotifications(notifications) } } @OptIn(ExperimentalFoundationApi::class) -internal fun LazyListScope.notifications(configs: ImmutableList, modifier: Modifier = Modifier) { +private fun LazyListScope.feeSelector(state: SendStates.FeeState, clickIntents: SendClickIntents) { + item( + key = FEE_SELECTOR_KEY, + ) { + SendSpeedSelector( + state = state, + clickIntents = clickIntents, + modifier = Modifier.animateItemPlacement(), + ) + } +} + +private fun LazyListScope.topNotifications( + configs: ImmutableList, + modifier: Modifier = Modifier, +) { + notifications( + configs = configs.filter { + it is SendFeeNotification.Error.ExceedsBalance || + it is SendFeeNotification.Warning.NetworkFeeUnreachable + }.toImmutableList(), + modifier = modifier, + ) +} + +private fun LazyListScope.middleNotifications( + configs: ImmutableList, + modifier: Modifier = Modifier, +) { + notifications( + configs = configs.filter { + it is SendFeeNotification.Warning.TooLow || + it is SendFeeNotification.Warning.TooHigh + }.toImmutableList(), + modifier = modifier, + ) +} + +private fun LazyListScope.bottomNotifications( + configs: ImmutableList, + modifier: Modifier = Modifier, +) { + notifications( + configs = configs.filterIsInstance().toImmutableList(), + isLast = true, + modifier = modifier, + ) +} + +@OptIn(ExperimentalFoundationApi::class) +private fun LazyListScope.notifications( + configs: ImmutableList, + modifier: Modifier = Modifier, + isLast: Boolean = false, +) { items( items = configs, key = { it::class.java }, contentType = { it::class.java }, itemContent = { + val bottomPadding = if (isLast) TangemTheme.dimens.spacing12 else TangemTheme.dimens.spacing0 Notification( config = it.config, modifier = modifier - .padding(top = TangemTheme.dimens.spacing12) + .padding( + top = TangemTheme.dimens.spacing12, + bottom = bottomPadding, + ) .animateItemPlacement(), containerColor = when (it) { is SendFeeNotification.Error.ExceedsBalance, is SendFeeNotification.Warning.NetworkFeeUnreachable, - -> TangemTheme.colors.background.primary + -> TangemTheme.colors.background.action else -> TangemTheme.colors.button.disabled }, iconTint = when (it) { - is SendFeeNotification.Informational -> TangemTheme.colors.icon.accent is SendFeeNotification.Error.ExceedsBalance -> { if (it.config.buttonsState == null) { TangemTheme.colors.icon.warning @@ -116,20 +163,30 @@ internal fun LazyListScope.customFee(feeSendState: FeeSelectorState, modifier: M @OptIn(ExperimentalFoundationApi::class) internal fun LazyListScope.subtractButton( - receivedAmount: String, - isSubtract: Boolean, - isSubtractAvailable: Boolean, + state: SendStates.FeeState, clickIntents: SendClickIntents, modifier: Modifier = Modifier, ) { + val receivedAmount = state.receivedAmount + val isSubtract = state.isSubtract + val isSubtractAvailable = state.isSubtractAvailable + val feeSendState = state.feeSelectorState if (isSubtractAvailable) { item { + val feeStateContent = feeSendState as? FeeSelectorState.Content + val isCustomAvailable = feeStateContent?.customValues.isNullOrEmpty().not() + val isCustomSelected = feeStateContent?.selectedFee == FeeType.CUSTOM + val topPadding = if (isCustomSelected && isCustomAvailable) { + TangemTheme.dimens.spacing12 + } else { + TangemTheme.dimens.spacing20 + } SendSpeedSubtract( receivingAmount = receivedAmount, isSubtract = isSubtract, onSelectClick = clickIntents::onSubtractSelect, modifier = modifier - .padding(vertical = TangemTheme.dimens.spacing12) + .padding(top = topPadding) .animateItemPlacement(), ) } diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelector.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelector.kt index db73ae5c7e..2721c1698e 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelector.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelector.kt @@ -4,6 +4,9 @@ import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* @@ -39,6 +42,7 @@ import com.tangem.features.send.impl.R import com.tangem.features.send.impl.presentation.state.SendStates import com.tangem.features.send.impl.presentation.state.fee.FeeSelectorState import com.tangem.features.send.impl.presentation.state.fee.FeeType +import com.tangem.features.send.impl.presentation.state.fee.SendFeeNotification import com.tangem.features.send.impl.presentation.ui.common.FooterContainer import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents import java.math.BigDecimal @@ -112,12 +116,17 @@ internal fun SendSpeedSelector( visible = fees.normal is Fee.Ethereum, label = "Custom fee appearance animation", ) { + val showWarning = state.notifications.any { + it is SendFeeNotification.Warning.TooHigh || + it is SendFeeNotification.Warning.TooLow + } SendSpeedSelectorItem( titleRes = R.string.common_fee_selector_option_custom, iconRes = R.drawable.ic_edit_24, isSelected = isSelected == FeeType.CUSTOM, onSelect = { clickIntents.onFeeSelectorClick(FeeType.CUSTOM) }, showDivider = fees.normal !is Fee.Ethereum, + showWarning = showWarning, ) } } @@ -224,6 +233,7 @@ private fun SendSpeedSelectorItem( symbolLength: Int? = null, isSelected: Boolean = false, showDivider: Boolean = true, + showWarning: Boolean = false, ) { val iconTint by animateColorAsState( targetValue = if (isSelected) { @@ -259,7 +269,10 @@ private fun SendSpeedSelectorItem( symbolLength = symbolLength, textStyle = textStyle, ) + } else { + SpacerWMax() } + WarningIcon(showWarning = showWarning) } if (showDivider) { Box( @@ -340,6 +353,26 @@ private fun RowScope.SelectorValueContent( ) } +@Composable +private fun WarningIcon(showWarning: Boolean = false) { + AnimatedVisibility( + visible = showWarning, + label = "Custom fee warning indicator", + enter = fadeIn(), + exit = fadeOut(), + ) { + Image( + painter = painterResource(R.drawable.ic_alert_triangle_20), + contentDescription = null, + modifier = Modifier + .padding( + vertical = TangemTheme.dimens.spacing12, + horizontal = TangemTheme.dimens.spacing14, + ), + ) + } +} + //region preview @Preview @Composable diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/SendContent.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/SendContent.kt index d014f71caa..694dac7048 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/SendContent.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/SendContent.kt @@ -67,16 +67,16 @@ internal fun SendContent(uiState: SendUiState) { walletBalance = amountState.walletBalance.resolveReference(), ) } - AmountBlock( - amountState = amountState, - isSuccess = isSuccess, - onClick = uiState.clickIntents::showAmount, - ) RecipientBlock( recipientState = recipientState, isSuccess = isSuccess, onClick = uiState.clickIntents::showRecipient, ) + AmountBlock( + amountState = amountState, + isSuccess = isSuccess, + onClick = uiState.clickIntents::showAmount, + ) FeeBlock( feeState = feeState, isSuccess = isSuccess, 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 b02ffb58d7..a675d41dad 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 @@ -352,7 +352,7 @@ internal class SendViewModel @Inject constructor( // region screen state navigation override fun popBackStack() = stateRouter.popBackStack() - override fun onBackClick() = stateRouter.onBackClick() + override fun onBackClick() = stateRouter.onBackClick(uiState.sendState.isSuccess) override fun onNextClick() = stateRouter.onNextClick() override fun onPrevClick() = stateRouter.onPrevClick()