Updated on 2026-08-14

This commit is contained in:
Tangem 2023-10-30 18:31:14 +03:00
parent 6796e868c6
commit ef389a6735
22 changed files with 867 additions and 36 deletions

View file

@ -9,9 +9,9 @@ import androidx.hilt.navigation.compose.hiltViewModel
import com.tangem.core.ui.components.SystemBarsEffect
import com.tangem.core.ui.screen.ComposeBottomSheetFragment
import com.tangem.core.ui.theme.AppThemeModeHolder
import com.tangem.features.send.impl.presentation.send.state.SendUiState
import com.tangem.features.send.impl.presentation.send.ui.SendScreen
import com.tangem.features.send.impl.presentation.send.viewmodel.SendViewModel
import com.tangem.features.send.impl.presentation.state.SendUiState
import com.tangem.features.send.impl.presentation.ui.SendScreen
import com.tangem.features.send.impl.presentation.viewmodel.SendViewModel
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

View file

@ -1,4 +1,4 @@
package com.tangem.features.send.impl.presentation.send.state
package com.tangem.features.send.impl.presentation.state
import arrow.core.Either
import com.tangem.common.Provider
@ -7,9 +7,10 @@ import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.error.CurrencyStatusError
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.features.send.impl.presentation.send.state.fields.SendAmountFieldChangeConverter
import com.tangem.features.send.impl.presentation.send.state.fields.SendAmountFieldConverter
import com.tangem.features.send.impl.presentation.send.viewmodel.SendClickIntents
import com.tangem.features.send.impl.presentation.state.amount.SendAmountStateConverter
import com.tangem.features.send.impl.presentation.state.fields.SendAmountFieldChangeConverter
import com.tangem.features.send.impl.presentation.state.fields.SendAmountFieldConverter
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
internal class SendStateFactory(
private val clickIntents: SendClickIntents,

View file

@ -1,11 +1,12 @@
package com.tangem.features.send.impl.presentation.send.state
package com.tangem.features.send.impl.presentation.state
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.send.impl.presentation.send.state.fields.SendTextField
import com.tangem.features.send.impl.presentation.send.viewmodel.SendClickIntents
import com.tangem.features.send.impl.presentation.state.amount.SendAmountSegmentedButtonsConfig
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import kotlinx.collections.immutable.PersistentList
/**

View file

@ -1,4 +1,4 @@
package com.tangem.features.send.impl.presentation.send.state
package com.tangem.features.send.impl.presentation.state.amount
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.components.currency.tokenicon.TokenIconState

View file

@ -1,4 +1,4 @@
package com.tangem.features.send.impl.presentation.send.state
package com.tangem.features.send.impl.presentation.state.amount
import arrow.core.Either
import com.tangem.common.Provider
@ -10,8 +10,9 @@ import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.error.CurrencyStatusError
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.features.send.impl.presentation.send.state.fields.SendAmountFieldConverter
import com.tangem.features.send.impl.presentation.send.viewmodel.SendClickIntents
import com.tangem.features.send.impl.presentation.state.SendUiState
import com.tangem.features.send.impl.presentation.state.fields.SendAmountFieldConverter
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.persistentListOf

View file

@ -1,7 +1,7 @@
package com.tangem.features.send.impl.presentation.send.state.fields
package com.tangem.features.send.impl.presentation.state.fields
import com.tangem.common.Provider
import com.tangem.features.send.impl.presentation.send.state.SendUiState
import com.tangem.features.send.impl.presentation.state.SendUiState
import com.tangem.utils.converter.Converter
import java.text.DecimalFormatSymbols
import java.text.NumberFormat

View file

@ -1,11 +1,11 @@
package com.tangem.features.send.impl.presentation.send.state.fields
package com.tangem.features.send.impl.presentation.state.fields
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import com.tangem.core.ui.extensions.TextReference
import com.tangem.features.send.impl.R
import com.tangem.features.send.impl.presentation.send.viewmodel.SendClickIntents
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import com.tangem.utils.converter.Converter
import java.text.NumberFormat

View file

@ -1,4 +1,4 @@
package com.tangem.features.send.impl.presentation.send.state.fields
package com.tangem.features.send.impl.presentation.state.fields
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.runtime.Immutable

View file

@ -1,4 +1,4 @@
package com.tangem.features.send.impl.presentation.send.ui
package com.tangem.features.send.impl.presentation.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
@ -18,9 +18,9 @@ import com.tangem.core.ui.components.currency.tokenicon.TokenIcon
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.send.impl.R
import com.tangem.features.send.impl.presentation.send.state.SendAmountSegmentedButtonsConfig
import com.tangem.features.send.impl.presentation.send.state.SendUiState
import com.tangem.features.send.impl.presentation.send.ui.amount.AmountFieldContainer
import com.tangem.features.send.impl.presentation.state.amount.SendAmountSegmentedButtonsConfig
import com.tangem.features.send.impl.presentation.state.SendUiState
import com.tangem.features.send.impl.presentation.ui.amount.AmountFieldContainer
@Composable
internal fun SendAmountContent(amountState: SendUiState.Content.AmountState) {

View file

@ -1,4 +1,4 @@
package com.tangem.features.send.impl.presentation.send.ui
package com.tangem.features.send.impl.presentation.ui
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
@ -18,7 +18,7 @@ import com.tangem.core.ui.R
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.PrimaryButtonIconEnd
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.send.impl.presentation.send.state.SendUiState
import com.tangem.features.send.impl.presentation.state.SendUiState
@Composable
internal fun SendNavigationButtons(uiState: SendUiState.Content) {

View file

@ -1,4 +1,4 @@
package com.tangem.features.send.impl.presentation.send.ui
package com.tangem.features.send.impl.presentation.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation
@ -13,7 +13,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetDraggableHeader
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.send.impl.presentation.send.state.SendUiState
import com.tangem.features.send.impl.presentation.state.SendUiState
@Composable
internal fun SendScreen(uiState: SendUiState.Content) {

View file

@ -1,4 +1,4 @@
package com.tangem.features.send.impl.presentation.send.ui.amount
package com.tangem.features.send.impl.presentation.ui.amount
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
@ -27,7 +27,7 @@ import androidx.compose.ui.text.style.TextAlign
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.send.impl.presentation.send.state.fields.SendTextField
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
@Composable
internal fun ColumnScope.AmountField(

View file

@ -1,4 +1,4 @@
package com.tangem.features.send.impl.presentation.send.ui.amount
package com.tangem.features.send.impl.presentation.ui.amount
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
@ -13,7 +13,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.text.style.TextAlign
import com.tangem.core.ui.components.currency.tokenicon.TokenIcon
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.send.impl.presentation.send.state.SendUiState
import com.tangem.features.send.impl.presentation.state.SendUiState
@Composable
internal fun AmountFieldContainer(amountState: SendUiState.Content.AmountState, modifier: Modifier = Modifier) {

View file

@ -0,0 +1,154 @@
package com.tangem.features.send.impl.presentation.ui.recipient
import androidx.annotation.DrawableRes
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import com.tangem.core.ui.components.MiddleEllipsisText
import com.tangem.core.ui.components.icons.identicon.IdentIcon
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.send.impl.R
/**
* Row item with title and subtitle
*
* @param title title
* @param subtitle subtitle
* @param onClick click listener
* @param modifier modifier
* @param subtitleIconRes icon
*/
@Composable
fun ListItemWithIcon(
title: String,
subtitle: String,
onClick: () -> Unit,
modifier: Modifier = Modifier,
@DrawableRes subtitleIconRes: Int? = null,
) {
Row(
modifier = modifier
.fillMaxWidth()
.background(TangemTheme.colors.background.action)
.clickable { onClick() }
.padding(
vertical = TangemTheme.dimens.spacing8,
horizontal = TangemTheme.dimens.spacing12,
),
) {
IdentIcon(
address = title,
modifier = Modifier
.size(TangemTheme.dimens.size40)
.clip(RoundedCornerShape(TangemTheme.dimens.radius20)),
)
Column(
modifier = Modifier
.fillMaxWidth()
.padding(
start = TangemTheme.dimens.spacing12,
top = TangemTheme.dimens.spacing2,
bottom = TangemTheme.dimens.spacing2,
),
) {
MiddleEllipsisText(
text = title,
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.Justify,
modifier = Modifier.fillMaxSize(),
)
Row {
subtitleIconRes?.let { iconRes ->
Icon(
painter = painterResource(id = iconRes),
contentDescription = null,
tint = TangemTheme.colors.icon.informative,
modifier = Modifier
.size(TangemTheme.dimens.size16)
.background(TangemTheme.colors.background.tertiary, CircleShape)
.padding(TangemTheme.dimens.spacing3),
)
}
Text(
text = subtitle,
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
maxLines = 1,
modifier = Modifier
.then(
if (subtitleIconRes != null) {
Modifier.padding(start = TangemTheme.dimens.spacing4)
} else {
Modifier
},
),
)
}
}
}
}
// region preview
@Preview
@Composable
private fun ListItemWithIconPreview_Light(
@PreviewParameter(ListItemWithIconPreviewProvider::class) config: ListItemWithIconPreviewConfig,
) {
TangemTheme {
ListItemWithIcon(
title = config.title,
subtitle = config.subtitle,
subtitleIconRes = config.iconRes,
onClick = {},
)
}
}
@Preview
@Composable
private fun ListItemWithIconPreview_Dark(
@PreviewParameter(ListItemWithIconPreviewProvider::class) config: ListItemWithIconPreviewConfig,
) {
TangemTheme(isDark = true) {
ListItemWithIcon(
title = config.title,
subtitle = config.subtitle,
subtitleIconRes = config.iconRes,
onClick = {},
)
}
}
private data class ListItemWithIconPreviewConfig(
val title: String,
val subtitle: String,
val iconRes: Int? = null,
)
private class ListItemWithIconPreviewProvider : CollectionPreviewParameterProvider<ListItemWithIconPreviewConfig>(
collection = listOf(
ListItemWithIconPreviewConfig(
title = "0x34B4492A412D84A6E606288f3Bd714b89135D4dE",
subtitle = "Wallet",
iconRes = R.drawable.ic_arrow_down_24,
),
ListItemWithIconPreviewConfig(
title = "0x34B4492A412D84A6E606288f3Bd714b89135D4dE",
subtitle = "Wallet",
),
),
)
//endregion

View file

@ -0,0 +1,380 @@
package com.tangem.features.send.impl.presentation.ui.recipient
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Alignment.Companion.CenterVertically
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import com.tangem.core.ui.components.SpacerH8
import com.tangem.core.ui.components.icons.identicon.IdentIcon
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.send.impl.R
@Composable
internal fun TextFieldWithPasteAndIcon(
value: String,
placeholder: TextReference,
label: TextReference,
onValueChange: (String) -> Unit,
onPasteClick: (String) -> Unit,
modifier: Modifier = Modifier,
footer: String? = null,
singleLine: Boolean = false,
) {
FooterContainer(modifier, footer) {
Column(
modifier = Modifier
.fillMaxWidth()
.background(
color = TangemTheme.colors.background.action,
shape = TangemTheme.shapes.roundedCornersXMedium,
),
) {
Text(
text = label.resolveReference(),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.secondary,
modifier = Modifier
.padding(
start = TangemTheme.dimens.spacing12,
end = TangemTheme.dimens.spacing12,
top = TangemTheme.dimens.spacing12,
),
)
Row {
IdentIcon(
address = value,
modifier = Modifier
.padding(
start = TangemTheme.dimens.spacing16,
top = TangemTheme.dimens.spacing8,
bottom = TangemTheme.dimens.spacing10,
)
.clip(RoundedCornerShape(TangemTheme.dimens.radius20))
.size(TangemTheme.dimens.size40)
.background(TangemTheme.colors.background.tertiary),
)
SimpleTextField(
value = value,
placeholder = placeholder,
onValueChange = onValueChange,
singleLine = singleLine,
modifier = Modifier
.padding(
start = TangemTheme.dimens.spacing12,
top = TangemTheme.dimens.spacing8,
bottom = TangemTheme.dimens.spacing10,
)
.weight(1f)
.align(CenterVertically),
)
PasteButton(
isPasteButtonVisible = value.isBlank(),
onClick = onPasteClick,
modifier = Modifier
.align(CenterVertically)
.padding(
start = TangemTheme.dimens.spacing4,
end = TangemTheme.dimens.spacing16,
),
)
}
}
}
}
@Composable
internal fun TextFieldWithPaste(
value: String,
placeholder: TextReference,
label: TextReference,
onValueChange: (String) -> Unit,
onPasteClick: (String) -> Unit,
modifier: Modifier = Modifier,
footer: String? = null,
) {
FooterContainer(modifier, footer) {
Row(
modifier = Modifier
.background(
color = TangemTheme.colors.background.action,
shape = TangemTheme.shapes.roundedCornersXMedium,
),
) {
Column(
modifier = Modifier
.weight(1f)
.padding(TangemTheme.dimens.spacing12),
) {
Text(
text = label.resolveReference(),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.secondary,
)
SimpleTextField(
value = value,
placeholder = placeholder,
onValueChange = onValueChange,
modifier = Modifier
.padding(top = TangemTheme.dimens.spacing6),
)
}
PasteButton(
isPasteButtonVisible = value.isBlank(),
onClick = onPasteClick,
modifier = Modifier
.align(CenterVertically)
.padding(end = TangemTheme.dimens.spacing16),
)
}
}
}
@Composable
internal fun TextFieldWithInfo(
value: String,
label: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
info: TextReference? = null,
footer: String? = null,
) {
FooterContainer(
footer = footer,
footerTopPadding = TangemTheme.dimens.spacing6,
modifier = modifier,
) {
Column(
modifier = Modifier
.fillMaxWidth()
.background(
color = TangemTheme.colors.background.action,
shape = TangemTheme.shapes.roundedCornersXMedium,
)
.padding(
start = TangemTheme.dimens.spacing16,
end = TangemTheme.dimens.spacing16,
top = TangemTheme.dimens.spacing12,
bottom = TangemTheme.dimens.spacing14,
),
) {
Text(
text = label,
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.secondary,
)
Row {
SimpleTextField(
value = value,
onValueChange = onValueChange,
modifier = Modifier
.padding(top = TangemTheme.dimens.spacing6)
.weight(1f),
)
info?.let {
Text(
text = it.resolveReference(),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,
modifier = Modifier
.padding(start = TangemTheme.dimens.spacing8)
.align(Alignment.Bottom),
)
}
}
}
}
}
@Composable
private fun FooterContainer(
modifier: Modifier = Modifier,
footer: String? = null,
footerTopPadding: Dp = TangemTheme.dimens.spacing8,
content: @Composable () -> Unit,
) {
Column(modifier = modifier) {
content()
footer?.let {
Text(
text = it,
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
modifier = Modifier
.padding(top = footerTopPadding),
)
}
}
}
@Composable
private fun PasteButton(isPasteButtonVisible: Boolean, onClick: (String) -> Unit, modifier: Modifier = Modifier) {
val clipboardManager = LocalClipboardManager.current
val hapticFeedback = LocalHapticFeedback.current
if (isPasteButtonVisible) {
Box(modifier = modifier) {
Text(
text = "Paste",
style = TangemTheme.typography.button,
color = TangemTheme.colors.text.primary2,
modifier = Modifier
.background(
color = TangemTheme.colors.button.primary,
shape = TangemTheme.shapes.roundedCornersXMedium,
)
.padding(
horizontal = TangemTheme.dimens.spacing10,
vertical = TangemTheme.dimens.spacing2,
)
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(radius = TangemTheme.dimens.radius8),
onClick = {
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
onClick(
clipboardManager
.getText()
?.toString()
.orEmpty(),
)
},
),
)
}
} else {
Icon(
painter = painterResource(id = R.drawable.ic_close_24),
tint = TangemTheme.colors.icon.informative,
contentDescription = stringResource(R.string.common_close),
modifier = modifier
.size(TangemTheme.dimens.size20)
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(radius = TangemTheme.dimens.radius10),
onClick = { onClick("") },
),
)
}
}
@Composable
private fun SimpleTextField(
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
placeholder: TextReference? = null,
singleLine: Boolean = false,
) {
val focusRequester = remember { FocusRequester() }
BasicTextField(
value = value,
onValueChange = onValueChange,
textStyle = TangemTheme.typography.body2,
cursorBrush = SolidColor(TangemTheme.colors.text.primary1),
singleLine = singleLine,
decorationBox = { textValue ->
Box {
if (value.isBlank() && placeholder != null) {
Text(
text = placeholder.resolveReference(),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.disabled,
modifier = Modifier,
)
}
textValue()
}
},
modifier = modifier
.focusRequester(focusRequester),
)
}
//region preview
@Preview
@Composable
private fun TextFieldPreview_Light() {
TangemTheme {
Column {
TextFieldWithPaste(
value = "",
label = TextReference.Res(R.string.send_recipient),
placeholder = TextReference.Res(R.string.send_enter_address_field),
onValueChange = {},
onPasteClick = {},
)
SpacerH8()
TextFieldWithPasteAndIcon(
value = "",
label = TextReference.Res(R.string.send_extras_hint_memo),
placeholder = TextReference.Res(R.string.send_optional_field),
onValueChange = {},
onPasteClick = {},
)
SpacerH8()
TextFieldWithInfo(
value = "Text",
label = stringResource(R.string.send_extras_hint_memo),
info = TextReference.Res(R.string.send_optional_field),
footer = stringResource(R.string.send_max_fee),
onValueChange = {},
)
}
}
}
@Preview
@Composable
private fun TextFieldPreview_Dark() {
TangemTheme(isDark = true) {
Column {
TextFieldWithPaste(
value = "",
label = TextReference.Res(R.string.send_recipient),
placeholder = TextReference.Res(R.string.send_enter_address_field),
onValueChange = {},
onPasteClick = {},
)
SpacerH8()
TextFieldWithPasteAndIcon(
value = "",
label = TextReference.Res(R.string.send_extras_hint_memo),
placeholder = TextReference.Res(R.string.send_optional_field),
onValueChange = {},
onPasteClick = {},
)
SpacerH8()
TextFieldWithInfo(
value = "Text",
label = stringResource(R.string.send_extras_hint_memo),
info = TextReference.Res(R.string.send_optional_field),
footer = stringResource(R.string.send_max_fee),
onValueChange = {},
)
}
}
}
//endregion

View file

@ -1,4 +1,4 @@
package com.tangem.features.send.impl.presentation.send.viewmodel
package com.tangem.features.send.impl.presentation.viewmodel
interface SendClickIntents {

View file

@ -1,4 +1,4 @@
package com.tangem.features.send.impl.presentation.send.viewmodel
package com.tangem.features.send.impl.presentation.viewmodel
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -14,8 +14,8 @@ import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.features.send.api.navigation.SendRouter
import com.tangem.features.send.impl.presentation.send.state.SendStateFactory
import com.tangem.features.send.impl.presentation.send.state.SendUiState
import com.tangem.features.send.impl.presentation.state.SendStateFactory
import com.tangem.features.send.impl.presentation.state.SendUiState
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.JobHolder
import com.tangem.utils.coroutines.saveIn