Updated on 2026-08-14
This commit is contained in:
parent
d5cbaf22cf
commit
f5be772c91
53 changed files with 219 additions and 276 deletions
|
|
@ -85,14 +85,14 @@ internal fun SendContent(
|
|||
|
||||
@Composable
|
||||
private fun SendAppBar(navigationUM: NavigationUM) {
|
||||
val navigationUM = navigationUM as? NavigationUM.Content ?: return
|
||||
val navigationUMContent = navigationUM as? NavigationUM.Content ?: return
|
||||
AppBarWithBackButtonAndIcon(
|
||||
text = navigationUM.title.resolveReference(),
|
||||
subtitle = navigationUM.subtitle?.resolveReference(),
|
||||
onBackClick = navigationUM.backIconClick,
|
||||
onIconClick = navigationUM.additionalIconClick,
|
||||
backIconRes = navigationUM.backIconRes,
|
||||
iconRes = navigationUM.additionalIconRes,
|
||||
text = navigationUMContent.title.resolveReference(),
|
||||
subtitle = navigationUMContent.subtitle?.resolveReference(),
|
||||
onBackClick = navigationUMContent.backIconClick,
|
||||
onIconClick = navigationUMContent.additionalIconClick,
|
||||
backIconRes = navigationUMContent.backIconRes,
|
||||
iconRes = navigationUMContent.additionalIconRes,
|
||||
backgroundColor = TangemTheme.colors.background.tertiary,
|
||||
modifier = Modifier.height(TangemTheme.dimens.size56),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -22,14 +22,14 @@ private const val TAP_HELP_ANIMATION_DELAY = 500L
|
|||
|
||||
internal fun LazyListScope.tapHelp(isDisplay: Boolean, modifier: Modifier = Modifier) {
|
||||
item(key = TAP_HELP_KEY) {
|
||||
var wrappedIsDisplay by remember { mutableStateOf(false) }
|
||||
var isWrappedDisplay by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(key1 = isDisplay) {
|
||||
delay(TAP_HELP_ANIMATION_DELAY)
|
||||
wrappedIsDisplay = isDisplay
|
||||
isWrappedDisplay = isDisplay
|
||||
}
|
||||
|
||||
if (wrappedIsDisplay) {
|
||||
if (isWrappedDisplay) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = modifier
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ internal sealed class ConfirmUM {
|
|||
override val isPrimaryButtonEnabled: Boolean = false,
|
||||
val walletName: TextReference,
|
||||
val isSending: Boolean,
|
||||
val showTapHelp: Boolean,
|
||||
val isShowTapHelp: Boolean,
|
||||
val sendingFooter: TextReference,
|
||||
val notifications: ImmutableList<NotificationUM>,
|
||||
) : ConfirmUM()
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ internal class DefaultSellRedirectDeepLinkHandler @AssistedInject constructor(
|
|||
}
|
||||
|
||||
scope.launch {
|
||||
val cryptoCurrency = getCryptoCurrencyUseCase(userWallet, currencyId).getOrElse {
|
||||
Timber.e("Error on getting cryptoCurrency: $it")
|
||||
val cryptoCurrency = getCryptoCurrencyUseCase(userWallet, currencyId).getOrElse { error ->
|
||||
Timber.e("Error on getting cryptoCurrency: $error")
|
||||
return@launch
|
||||
}
|
||||
// Convert using universal parser to account for regional separators
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ internal class DefaultSendEntryPointComponent @AssistedInject constructor(
|
|||
|
||||
Children(
|
||||
stack = childStackValue,
|
||||
modifier = modifier,
|
||||
animation = stackAnimation { child ->
|
||||
when (child.configuration) {
|
||||
SendEntryRoute.Send,
|
||||
|
|
@ -115,7 +116,7 @@ internal class DefaultSendEntryPointComponent @AssistedInject constructor(
|
|||
}
|
||||
},
|
||||
) { child ->
|
||||
child.instance.Content(modifier.fillMaxSize())
|
||||
child.instance.Content(Modifier.fillMaxSize())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -125,7 +126,7 @@ internal class DefaultSendEntryPointComponent @AssistedInject constructor(
|
|||
): ComposableContentComponent = when (configuration) {
|
||||
is SendEntryRoute.ChooseToken -> getManagedTokensComponent(
|
||||
componentContext = factoryContext,
|
||||
showSendViaSwapNotification = configuration.showSendViaSwapNotification,
|
||||
showSendViaSwapNotification = configuration.isShowSendViaSwapNotification,
|
||||
)
|
||||
SendEntryRoute.Send -> sendComponent
|
||||
SendEntryRoute.SendWithSwap -> sendWithSwapComponent
|
||||
|
|
|
|||
|
|
@ -42,12 +42,12 @@ internal class SendEntryPointModel @Inject constructor(
|
|||
lastSavedAmount = lastAmount
|
||||
isEnterInFiat = isEnterInFiatSelected
|
||||
modelScope.launch {
|
||||
val showSendViaSwapNotification = shouldShowNotificationUseCase(
|
||||
val isShowSendViaSwapNotification = shouldShowNotificationUseCase(
|
||||
NotificationId.SendViaSwapTokenSelectorNotification.key,
|
||||
)
|
||||
router.push(
|
||||
SendEntryRoute.ChooseToken(
|
||||
showSendViaSwapNotification = showSendViaSwapNotification,
|
||||
isShowSendViaSwapNotification = isShowSendViaSwapNotification,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@ internal class FeeSelectorAlertFactory @Inject constructor(
|
|||
) {
|
||||
|
||||
fun checkAndShowAlerts(feeSelectorUM: FeeSelectorUM.Content, onConfirmClick: () -> Unit) {
|
||||
val showFeeTooLow = checkAndShowFeeTooLow(feeSelectorUM, onConfirmClick)
|
||||
val showFeeTooHigh = checkAndShowFeeTooHigh(feeSelectorUM, onConfirmClick)
|
||||
val isShowFeeTooLow = checkAndShowFeeTooLow(feeSelectorUM, onConfirmClick)
|
||||
val isShowFeeTooHigh = checkAndShowFeeTooHigh(feeSelectorUM, onConfirmClick)
|
||||
|
||||
if (!showFeeTooLow && !showFeeTooHigh) {
|
||||
if (!isShowFeeTooLow && !isShowFeeTooHigh) {
|
||||
onConfirmClick()
|
||||
}
|
||||
}
|
||||
|
|
@ -78,20 +78,20 @@ internal class FeeSelectorAlertFactory @Inject constructor(
|
|||
}
|
||||
|
||||
fun getFeeUpdatedAlert(
|
||||
newFee: TransactionFee,
|
||||
newTransactionFee: TransactionFee,
|
||||
feeSelectorUM: FeeSelectorUM,
|
||||
proceedAction: () -> Unit,
|
||||
stopAction: () -> Unit,
|
||||
) {
|
||||
if (feeSelectorUM !is FeeSelectorUM.Content) return
|
||||
val newFee = when (newFee) {
|
||||
is TransactionFee.Single -> newFee.normal
|
||||
val newFee = when (newTransactionFee) {
|
||||
is TransactionFee.Single -> newTransactionFee.normal
|
||||
is TransactionFee.Choosable -> {
|
||||
when (feeSelectorUM.selectedFeeItem) {
|
||||
is FeeItem.Suggested -> feeSelectorUM.selectedFeeItem.fee
|
||||
is FeeItem.Slow -> newFee.minimum
|
||||
is FeeItem.Market -> newFee.normal
|
||||
is FeeItem.Fast -> newFee.priority
|
||||
is FeeItem.Slow -> newTransactionFee.minimum
|
||||
is FeeItem.Market -> newTransactionFee.normal
|
||||
is FeeItem.Fast -> newTransactionFee.priority
|
||||
is FeeItem.Custom -> return
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ internal class FeeSelectorModel @Inject constructor(
|
|||
private fun subscribeOnFeeReloadTriggerUpdates() {
|
||||
feeSelectorReloadListener.reloadTriggerFlow
|
||||
.onEach { data ->
|
||||
if (data.removeSuggestedFee) {
|
||||
if (data.isRemoveSuggestedFee) {
|
||||
uiState.update(FeeSelectorRemoveSuggestedTransformer)
|
||||
}
|
||||
loadFee()
|
||||
|
|
@ -220,9 +220,9 @@ internal class FeeSelectorModel @Inject constructor(
|
|||
private fun checkLoadFee() {
|
||||
modelScope.launch {
|
||||
params.onLoadFee().fold(
|
||||
ifRight = {
|
||||
ifRight = { newFee ->
|
||||
feeSelectorAlertFactory.getFeeUpdatedAlert(
|
||||
newFee = it,
|
||||
newTransactionFee = newFee,
|
||||
feeSelectorUM = uiState.value,
|
||||
proceedAction = {
|
||||
modelScope.launch {
|
||||
|
|
|
|||
|
|
@ -107,10 +107,10 @@ internal class FeeSelectorCustomFieldConverter(
|
|||
when (val fees = feeSelectorState.fees) {
|
||||
is TransactionFee.Choosable -> fees.minimum
|
||||
is TransactionFee.Single -> fees.normal
|
||||
}.let {
|
||||
when (it) {
|
||||
}.let { fee ->
|
||||
when (fee) {
|
||||
is Fee.Kaspa -> kaspaCustomFeeConverter.tryAutoFixValue(
|
||||
minimumFee = it,
|
||||
minimumFee = fee,
|
||||
customValues = customValues,
|
||||
)
|
||||
else -> customValues
|
||||
|
|
|
|||
|
|
@ -27,7 +27,12 @@ internal class FeeSelectorCustomValueChangedTransformer(
|
|||
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
|
||||
normalFee = state.selectedFeeItem.fee,
|
||||
)
|
||||
val updatedCustomValues = customFeeConverter.onValueChange(state, customFee.customValues, index, value)
|
||||
val updatedCustomValues = customFeeConverter.onValueChange(
|
||||
feeSelectorState = state,
|
||||
customValues = customFee.customValues,
|
||||
index = index,
|
||||
value = value,
|
||||
)
|
||||
val newCustomFee = customFee.copy(
|
||||
fee = customFeeConverter.convertBack(updatedCustomValues),
|
||||
customValues = updatedCustomValues,
|
||||
|
|
|
|||
|
|
@ -172,12 +172,13 @@ private fun FeeContent(state: FeeSelectorUM.Content, modifier: Modifier = Modifi
|
|||
approximate = state.feeExtraInfo.isFeeApproximate,
|
||||
)
|
||||
} else {
|
||||
state.selectedFeeItem.fee.amount.value.format {
|
||||
crypto(
|
||||
symbol = state.selectedFeeItem.fee.amount.currencySymbol,
|
||||
decimals = state.selectedFeeItem.fee.amount.decimals,
|
||||
).fee(canBeLower = state.feeExtraInfo.isFeeApproximate)
|
||||
}
|
||||
state.selectedFeeItem.fee.amount.value
|
||||
.format {
|
||||
crypto(
|
||||
symbol = state.selectedFeeItem.fee.amount.currencySymbol,
|
||||
decimals = state.selectedFeeItem.fee.amount.decimals,
|
||||
).fee(canBeLower = state.feeExtraInfo.isFeeApproximate)
|
||||
}
|
||||
},
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ private fun FeeSelectorItems(
|
|||
val feeFiatRateUM = state.feeFiatRateUM
|
||||
state.feeItems.fastForEachIndexed { index, item ->
|
||||
val isSelected = item.isSameClass(state.selectedFeeItem)
|
||||
val lastItem = index == state.feeItems.size - 1
|
||||
val isLastItem = index == state.feeItems.size - 1
|
||||
val iconTint by animateColorAsState(
|
||||
targetValue = if (isSelected) TangemTheme.colors.icon.accent else TangemTheme.colors.text.tertiary,
|
||||
label = "Fee selector icon tint change",
|
||||
|
|
@ -180,7 +180,7 @@ private fun FeeSelectorItems(
|
|||
null
|
||||
},
|
||||
ellipsizeOffset = item.fee.amount.currencySymbol.length,
|
||||
showDivider = !isSelected && !lastItem,
|
||||
showDivider = !isSelected && !isLastItem,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -243,7 +243,7 @@ private fun ExpandedCustomFeeItems(
|
|||
) {
|
||||
Column(modifier = modifier) {
|
||||
customFeeFields.fastForEachIndexed { index, field ->
|
||||
val showDivider = index != customFeeFields.size - 1 || nonce is FeeNonce.Nonce
|
||||
val isShowDivider = index != customFeeFields.size - 1 || nonce is FeeNonce.Nonce
|
||||
if (field.label != null) {
|
||||
InputRowEnterInfoAmountV2(
|
||||
text = field.value,
|
||||
|
|
@ -256,7 +256,7 @@ private fun ExpandedCustomFeeItems(
|
|||
keyboardOptions = field.keyboardOptions,
|
||||
keyboardActions = field.keyboardActions,
|
||||
onValueChange = { onValueChange(index, it) },
|
||||
showDivider = showDivider,
|
||||
showDivider = isShowDivider,
|
||||
isReadOnly = field.isReadonly,
|
||||
)
|
||||
} else {
|
||||
|
|
@ -270,7 +270,7 @@ private fun ExpandedCustomFeeItems(
|
|||
onValueChange = { onValueChange(index, it) },
|
||||
keyboardOptions = field.keyboardOptions,
|
||||
keyboardActions = field.keyboardActions,
|
||||
showDivider = showDivider,
|
||||
showDivider = isShowDivider,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
|
|||
*/
|
||||
internal sealed class SendAnalyticEvents(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : AnalyticsEvent(category = CommonSendAnalyticEvents.SEND_CATEGORY, event = event, params = params) {
|
||||
|
||||
/** Transaction send screen opened */
|
||||
|
|
@ -23,7 +23,7 @@ internal sealed class SendAnalyticEvents(
|
|||
val token: String,
|
||||
val feeType: AnalyticsParam.FeeType,
|
||||
val blockchain: String,
|
||||
val nonceNotEmpty: Boolean,
|
||||
val isNonceNotEmpty: Boolean,
|
||||
private val ensStatus: AnalyticsParam.EmptyFull,
|
||||
) : SendAnalyticEvents(
|
||||
event = "Transaction Sent Screen Opened",
|
||||
|
|
@ -31,7 +31,7 @@ internal sealed class SendAnalyticEvents(
|
|||
TOKEN_PARAM to token,
|
||||
FEE_TYPE to feeType.value,
|
||||
BLOCKCHAIN to blockchain,
|
||||
NONCE to nonceNotEmpty.toString().capitalize(),
|
||||
NONCE to isNonceNotEmpty.toString().capitalize(),
|
||||
ENS_ADDRESS to when (ensStatus) {
|
||||
AnalyticsParam.EmptyFull.Empty -> false.toString().capitalize()
|
||||
AnalyticsParam.EmptyFull.Full -> true.toString().capitalize()
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ internal class SendAnalyticHelper @Inject constructor(
|
|||
token = cryptoCurrency.symbol,
|
||||
feeType = feeType,
|
||||
blockchain = cryptoCurrency.network.name,
|
||||
nonceNotEmpty = feeSelectorUM.feeNonce is FeeNonce.Nonce,
|
||||
isNonceNotEmpty = feeSelectorUM.feeNonce is FeeNonce.Nonce,
|
||||
ensStatus = getEnsStatus(sendUM),
|
||||
),
|
||||
)
|
||||
|
|
@ -54,9 +54,9 @@ internal class SendAnalyticHelper @Inject constructor(
|
|||
}
|
||||
|
||||
private fun getEnsStatus(sendUM: SendUM): AnalyticsParam.EmptyFull {
|
||||
val blockchainAddressForEns =
|
||||
val isBlockchainAddressForEns =
|
||||
(sendUM.destinationUM as? DestinationUM.Content)?.addressTextField?.isAddressEns
|
||||
return if (blockchainAddressForEns == true) {
|
||||
return if (isBlockchainAddressForEns == true) {
|
||||
AnalyticsParam.EmptyFull.Full
|
||||
} else {
|
||||
AnalyticsParam.EmptyFull.Empty
|
||||
|
|
|
|||
|
|
@ -306,8 +306,8 @@ internal class SendConfirmModel @Inject constructor(
|
|||
modelScope.launch {
|
||||
val isShowTapHelp = isSendTapHelpEnabledUseCase.invokeSync().getOrElse { false }
|
||||
if (confirmUM is ConfirmUM.Empty) {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
_uiState.update { state ->
|
||||
state.copy(
|
||||
confirmUM = SendConfirmInitialStateTransformer(
|
||||
isShowTapHelp = isShowTapHelp,
|
||||
walletName = stringReference(userWallet.name),
|
||||
|
|
@ -323,9 +323,9 @@ internal class SendConfirmModel @Inject constructor(
|
|||
private fun subscribeOnTapHelpUpdates() {
|
||||
isSendTapHelpEnabledUseCase().getOrNull()
|
||||
?.onEach { showTapHelp ->
|
||||
_uiState.update {
|
||||
val confirmUM = it.confirmUM as? ConfirmUM.Content
|
||||
it.copy(confirmUM = confirmUM?.copy(showTapHelp = showTapHelp) ?: it.confirmUM)
|
||||
_uiState.update { state ->
|
||||
val confirmUM = state.confirmUM as? ConfirmUM.Content
|
||||
state.copy(confirmUM = confirmUM?.copy(isShowTapHelp = showTapHelp) ?: state.confirmUM)
|
||||
}
|
||||
}?.launchIn(modelScope)
|
||||
}
|
||||
|
|
@ -333,12 +333,12 @@ internal class SendConfirmModel @Inject constructor(
|
|||
private fun subscribeOnNotificationsUpdateTrigger() {
|
||||
notificationsUpdateListener.hasErrorFlow
|
||||
.onEach { hasError ->
|
||||
_uiState.update {
|
||||
val feeUM = it.feeSelectorUM as? FeeSelectorUMRedesigned.Content
|
||||
it.copy(
|
||||
confirmUM = (it.confirmUM as? ConfirmUM.Content)?.copy(
|
||||
_uiState.update { state ->
|
||||
val feeUM = state.feeSelectorUM as? FeeSelectorUMRedesigned.Content
|
||||
state.copy(
|
||||
confirmUM = (state.confirmUM as? ConfirmUM.Content)?.copy(
|
||||
isPrimaryButtonEnabled = !hasError && feeUM != null,
|
||||
) ?: it.confirmUM,
|
||||
) ?: state.confirmUM,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -495,8 +495,8 @@ internal class SendConfirmModel @Inject constructor(
|
|||
feeError = confirmData.feeError,
|
||||
),
|
||||
)
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
_uiState.update { state ->
|
||||
state.copy(
|
||||
confirmUM = SendConfirmationNotificationsTransformerV2(
|
||||
feeSelectorUM = uiState.value.feeSelectorUM,
|
||||
amountUM = uiState.value.amountUM,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ internal class SendConfirmInitialStateTransformer(
|
|||
return ConfirmUM.Content(
|
||||
walletName = walletName,
|
||||
isSending = false,
|
||||
showTapHelp = isShowTapHelp,
|
||||
isShowTapHelp = isShowTapHelp,
|
||||
sendingFooter = TextReference.EMPTY,
|
||||
notifications = persistentListOf(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ internal fun SendConfirmContent(
|
|||
feeSelectorBlockComponent = feeSelectorBlockComponent,
|
||||
)
|
||||
if (confirmUM != null) {
|
||||
tapHelp(isDisplay = confirmUM.showTapHelp)
|
||||
tapHelp(isDisplay = confirmUM.isShowTapHelp)
|
||||
with(notificationsComponent) {
|
||||
content(
|
||||
state = notificationsUM,
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ internal class SendModel @Inject constructor(
|
|||
var appCurrency: AppCurrency = AppCurrency.Default
|
||||
var predefinedValues: PredefinedValues = PredefinedValues.Empty
|
||||
|
||||
private var balanceHidingJobHolder = JobHolder()
|
||||
private val balanceHidingJobHolder = JobHolder()
|
||||
|
||||
init {
|
||||
subscribeOnBalanceHidden()
|
||||
|
|
@ -226,8 +226,8 @@ internal class SendModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun resetSendNavigation() {
|
||||
uiState.update {
|
||||
it.copy(
|
||||
uiState.update { state ->
|
||||
state.copy(
|
||||
destinationUM = SendDestinationInitialStateTransformer(
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
).transform(DestinationUM.Empty()),
|
||||
|
|
@ -358,8 +358,8 @@ internal class SendModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
},
|
||||
ifLeft = {
|
||||
Timber.w(it.toString())
|
||||
ifLeft = { error ->
|
||||
Timber.w(error.toString())
|
||||
showAlertError()
|
||||
return@launch
|
||||
},
|
||||
|
|
|
|||
|
|
@ -29,17 +29,17 @@ import kotlinx.coroutines.delay
|
|||
|
||||
@Composable
|
||||
internal fun SendConfirmSuccessContent(sendUM: SendUM, destinationBlockComponent: SendDestinationBlockComponent) {
|
||||
var visible by remember { mutableStateOf(false) }
|
||||
var isVisible by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
delay(ANIMATION_DELAY)
|
||||
visible = true
|
||||
isVisible = true
|
||||
}
|
||||
|
||||
val height = ANIMATION_OFFSET.toPx().toInt()
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = visible,
|
||||
visible = isVisible,
|
||||
enter = slideInVertically(
|
||||
initialOffsetY = { height },
|
||||
).plus(fadeIn()),
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
|
|||
*/
|
||||
internal sealed class NFTSendAnalyticEvents(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : AnalyticsEvent(category = CommonSendAnalyticEvents.NFT_SEND_CATEGORY, event = event, params = params) {
|
||||
|
||||
/** Transaction send screen opened */
|
||||
|
|
@ -22,14 +22,14 @@ internal sealed class NFTSendAnalyticEvents(
|
|||
val token: String,
|
||||
val feeType: AnalyticsParam.FeeType,
|
||||
val blockchain: String,
|
||||
val nonceNotEmpty: Boolean,
|
||||
val isNonceNotEmpty: Boolean,
|
||||
) : NFTSendAnalyticEvents(
|
||||
event = "NFT Sent Screen Opened",
|
||||
params = mapOf(
|
||||
TOKEN_PARAM to token,
|
||||
FEE_TYPE to feeType.value,
|
||||
BLOCKCHAIN to blockchain,
|
||||
NONCE to nonceNotEmpty.toString().capitalize(),
|
||||
NONCE to isNonceNotEmpty.toString().capitalize(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ internal class NFTSendAnalyticHelper @Inject constructor(
|
|||
token = cryptoCurrency.symbol,
|
||||
feeType = feeType,
|
||||
blockchain = cryptoCurrency.network.name,
|
||||
nonceNotEmpty = feeSelectorUM.feeNonce is FeeNonce.Nonce,
|
||||
isNonceNotEmpty = feeSelectorUM.feeNonce is FeeNonce.Nonce,
|
||||
),
|
||||
)
|
||||
analyticsEventHandler.send(
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ internal class NFTSendConfirmModel @Inject constructor(
|
|||
derivationPath = cryptoCurrency.network.derivationPath.value,
|
||||
destinationAddress = confirmData.enteredDestination.orEmpty(),
|
||||
tokenSymbol = null,
|
||||
amount = params.nftAsset.amount.toString(),
|
||||
amount = params.nftAsset.amount?.toString().orEmpty(),
|
||||
fee = confirmData.fee?.amount?.value?.stripZeroPlainString(),
|
||||
),
|
||||
)
|
||||
|
|
@ -213,8 +213,8 @@ internal class NFTSendConfirmModel @Inject constructor(
|
|||
modelScope.launch {
|
||||
val isShowTapHelp = isSendTapHelpEnabledUseCase.invokeSync().getOrElse { false }
|
||||
if (confirmUM is ConfirmUM.Empty || isEmptyFee) {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
_uiState.update { state ->
|
||||
state.copy(
|
||||
confirmUM = NFTSendConfirmInitialStateTransformer(
|
||||
isShowTapHelp = isShowTapHelp,
|
||||
walletName = stringReference(userWallet.name),
|
||||
|
|
@ -229,9 +229,9 @@ internal class NFTSendConfirmModel @Inject constructor(
|
|||
private fun subscribeOnTapHelpUpdates() {
|
||||
isSendTapHelpEnabledUseCase().getOrNull()
|
||||
?.onEach { showTapHelp ->
|
||||
_uiState.update {
|
||||
val confirmUM = it.confirmUM as? ConfirmUM.Content
|
||||
it.copy(confirmUM = confirmUM?.copy(showTapHelp = showTapHelp) ?: it.confirmUM)
|
||||
_uiState.update { state ->
|
||||
val confirmUM = state.confirmUM as? ConfirmUM.Content
|
||||
state.copy(confirmUM = confirmUM?.copy(isShowTapHelp = showTapHelp) ?: state.confirmUM)
|
||||
}
|
||||
}?.launchIn(modelScope)
|
||||
}
|
||||
|
|
@ -239,13 +239,13 @@ internal class NFTSendConfirmModel @Inject constructor(
|
|||
private fun subscribeOnNotificationsUpdateTrigger() {
|
||||
notificationsUpdateListener.hasErrorFlow
|
||||
.onEach { hasError ->
|
||||
_uiState.update {
|
||||
val isFeeNotNull = it.feeSelectorUM is FeeSelectorUMRedesigned.Content
|
||||
_uiState.update { state ->
|
||||
val isFeeNotNull = state.feeSelectorUM is FeeSelectorUMRedesigned.Content
|
||||
|
||||
it.copy(
|
||||
confirmUM = (it.confirmUM as? ConfirmUM.Content)?.copy(
|
||||
state.copy(
|
||||
confirmUM = (state.confirmUM as? ConfirmUM.Content)?.copy(
|
||||
isPrimaryButtonEnabled = !hasError && isFeeNotNull,
|
||||
) ?: it.confirmUM,
|
||||
) ?: state.confirmUM,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -353,8 +353,8 @@ internal class NFTSendConfirmModel @Inject constructor(
|
|||
),
|
||||
)
|
||||
}
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
_uiState.update { state ->
|
||||
state.copy(
|
||||
confirmUM = NFTSendConfirmationNotificationsTransformerV2(
|
||||
feeSelectorUM = uiState.value.feeSelectorUM,
|
||||
analyticsEventHandler = analyticsEventHandler,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ internal class NFTSendConfirmInitialStateTransformer(
|
|||
override fun transform(prevState: ConfirmUM): ConfirmUM {
|
||||
return ConfirmUM.Content(
|
||||
isSending = false,
|
||||
showTapHelp = isShowTapHelp,
|
||||
isShowTapHelp = isShowTapHelp,
|
||||
sendingFooter = TextReference.EMPTY,
|
||||
walletName = walletName,
|
||||
notifications = persistentListOf(),
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ internal fun NFTSendConfirmContent(
|
|||
feeSelectorBlockComponent = feeSelectorBlockComponent,
|
||||
)
|
||||
if (confirmUM != null) {
|
||||
tapHelp(isDisplay = confirmUM.showTapHelp)
|
||||
tapHelp(isDisplay = confirmUM.isShowTapHelp)
|
||||
with(notificationsComponent) {
|
||||
content(
|
||||
state = notificationsUM,
|
||||
|
|
|
|||
|
|
@ -34,17 +34,17 @@ internal fun NFTSendSuccessContent(
|
|||
nftDetailsBlockComponent: NFTDetailsBlockComponent,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var visible by remember { mutableStateOf(false) }
|
||||
var isVisible by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
delay(ANIMATION_DELAY)
|
||||
visible = true
|
||||
isVisible = true
|
||||
}
|
||||
|
||||
val height = ANIMATION_OFFSET.toPx().toInt()
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = visible,
|
||||
visible = isVisible,
|
||||
enter = slideInVertically(
|
||||
initialOffsetY = { height },
|
||||
).plus(fadeIn()),
|
||||
|
|
|
|||
|
|
@ -155,9 +155,9 @@ internal class SendAmountModel @Inject constructor(
|
|||
minAmountBoundary = getMinimumTransactionAmountSyncUseCase(
|
||||
userWalletId = params.userWalletId,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
).getOrNull()?.let {
|
||||
).getOrNull()?.let { amount ->
|
||||
EnterAmountBoundary(
|
||||
amount = it,
|
||||
amount = amount,
|
||||
fiatRate = cryptoCurrencyStatus.value.fiatRate.orZero(),
|
||||
)
|
||||
}
|
||||
|
|
@ -183,6 +183,7 @@ internal class SendAmountModel @Inject constructor(
|
|||
account: Account.CryptoPortfolio?,
|
||||
isAccountsMode: Boolean,
|
||||
) {
|
||||
val userWallet = userWallet
|
||||
if (uiState.value is AmountState.Empty && userWallet != null) {
|
||||
val isOnlyOneWallet = getWalletsUseCase.invokeSync().size == 1
|
||||
val walletTitle = if (isOnlyOneWallet) {
|
||||
|
|
@ -190,7 +191,7 @@ internal class SendAmountModel @Inject constructor(
|
|||
} else {
|
||||
resourceReference(
|
||||
R.string.send_from_wallet_name,
|
||||
WrappedList(listOf(userWallet?.name.orEmpty())), // TODO [REDACTED_TASK_KEY]
|
||||
WrappedList(listOf(userWallet.name)), // TODO [REDACTED_TASK_KEY]
|
||||
)
|
||||
}
|
||||
_uiState.update {
|
||||
|
|
@ -297,10 +298,10 @@ internal class SendAmountModel @Inject constructor(
|
|||
private fun confirmConvertToToken() {
|
||||
val amountParams = params as? SendAmountComponentParams.AmountParams ?: return
|
||||
val amountFieldData = uiState.value as? AmountState.Data
|
||||
_uiState.update {
|
||||
(it as? AmountState.Data)?.copy(
|
||||
_uiState.update { state ->
|
||||
(state as? AmountState.Data)?.copy(
|
||||
isPrimaryButtonEnabled = false,
|
||||
) ?: it
|
||||
) ?: state
|
||||
}
|
||||
|
||||
val isEnterInFiatSelected = amountFieldData?.amountTextField?.isFiatValue == true
|
||||
|
|
@ -352,7 +353,9 @@ internal class SendAmountModel @Inject constructor(
|
|||
private fun subscribeOnAmountUpdateTriggerUpdates() {
|
||||
sendAmountUpdateListener.updateAmountTriggerFlow
|
||||
.onEach { (amount, isEnterInFiat) ->
|
||||
isEnterInFiat?.let { onCurrencyChangeClick(isEnterInFiat) }
|
||||
if (isEnterInFiat != null) {
|
||||
onCurrencyChangeClick(isEnterInFiat)
|
||||
}
|
||||
onAmountValueChange(amount)
|
||||
saveResult()
|
||||
}.launchIn(modelScope)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
|
|||
internal sealed class SendDestinationAnalyticEvents(
|
||||
category: String,
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : AnalyticsEvent(category = category, event = event, params = params) {
|
||||
|
||||
abstract val categoryName: String
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ internal class SendDestinationModel @Inject constructor(
|
|||
|
||||
private val senderAddresses = MutableStateFlow<List<CryptoCurrencyAddress>>(emptyList())
|
||||
|
||||
private var validationJobHolder = JobHolder()
|
||||
private val validationJobHolder = JobHolder()
|
||||
|
||||
init {
|
||||
configDestinationNavigation()
|
||||
|
|
@ -234,11 +234,11 @@ internal class SendDestinationModel @Inject constructor(
|
|||
.map { wallet ->
|
||||
async {
|
||||
val addresses = if (!wallet.isMultiCurrency) {
|
||||
getCryptoCurrencyUseCase(wallet.walletId).getOrNull()?.let {
|
||||
if (it.network.rawId == cryptoCurrencyNetwork.rawId) {
|
||||
getCryptoCurrencyUseCase(wallet.walletId).getOrNull()?.let { cryptoCurrency ->
|
||||
if (cryptoCurrency.network.rawId == cryptoCurrencyNetwork.rawId) {
|
||||
getNetworkAddressesUseCase.invokeSync(
|
||||
userWalletId = wallet.walletId,
|
||||
networkRawId = it.network.id.rawId,
|
||||
networkRawId = cryptoCurrency.network.id.rawId,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
|
@ -323,12 +323,12 @@ internal class SendDestinationModel @Inject constructor(
|
|||
network = cryptoCurrency.network,
|
||||
)
|
||||
|
||||
type?.let {
|
||||
if (type != null) {
|
||||
analyticsEventHandler.send(
|
||||
SendDestinationAnalyticEvents.AddressEntered(
|
||||
categoryName = analyticsCategoryName,
|
||||
source = params.analyticsSendSource,
|
||||
method = it,
|
||||
method = type,
|
||||
isValid = addressValidationResult.isRight(),
|
||||
),
|
||||
)
|
||||
|
|
@ -339,12 +339,14 @@ internal class SendDestinationModel @Inject constructor(
|
|||
memoValidationResult,
|
||||
),
|
||||
)
|
||||
autoNextFromRecipient(type, addressValidationResult.isRight(), memoValidationResult.isRight())
|
||||
if (type != null) {
|
||||
autoNextFromRecipient(type, addressValidationResult.isRight(), memoValidationResult.isRight())
|
||||
}
|
||||
}.saveIn(validationJobHolder)
|
||||
}
|
||||
|
||||
private fun autoNextFromRecipient(type: EnterAddressSource?, isValidAddress: Boolean, isValidMemo: Boolean) {
|
||||
if (type?.isAutoNext == true && isValidAddress && isValidMemo) {
|
||||
private fun autoNextFromRecipient(type: EnterAddressSource, isValidAddress: Boolean, isValidMemo: Boolean) {
|
||||
if (type.isAutoNext && isValidAddress && isValidMemo) {
|
||||
saveResult()
|
||||
(params as? SendDestinationComponentParams.DestinationParams)?.callback?.onNextClick()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ internal class SendRecipientHistoryListConverter(
|
|||
} else {
|
||||
item.sourceType is TxInfo.SourceType.Single
|
||||
}
|
||||
val notZero = !item.amount.isZero()
|
||||
isTransfer && isSingleAddress && isNotContract && item.isOutgoing && notZero
|
||||
val isNotZero = !item.amount.isZero()
|
||||
isTransfer && isSingleAddress && isNotContract && item.isOutgoing && isNotZero
|
||||
}
|
||||
.take(RECENT_LIST_SIZE)
|
||||
.mapIndexed { index, tx ->
|
||||
|
|
|
|||
|
|
@ -30,10 +30,10 @@ internal class SendRecipientWalletListConverter(
|
|||
var walletsCounter = 0
|
||||
|
||||
return this.filterNotNull()
|
||||
.filter {
|
||||
val isCoin = it.cryptoCurrency is CryptoCurrency.Coin
|
||||
val isNotSameAddress = it.address != senderAddress
|
||||
val isNotBlankAddress = it.address.isNotBlank()
|
||||
.filter { destinationWallet ->
|
||||
val isCoin = destinationWallet.cryptoCurrency is CryptoCurrency.Coin
|
||||
val isNotSameAddress = destinationWallet.address != senderAddress
|
||||
val isNotBlankAddress = destinationWallet.address.isNotBlank()
|
||||
|
||||
isNotBlankAddress && isCoin && (isNotSameAddress || isSelfSendAvailable)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ internal const val WALLET_KEY_TAG = "wallet"
|
|||
internal const val RECENT_KEY_TAG = "recent"
|
||||
|
||||
internal fun loadingListState(tag: String, count: Int) = buildList {
|
||||
repeat(count) {
|
||||
repeat(count) { i ->
|
||||
add(
|
||||
DestinationRecipientListUM(
|
||||
id = "$tag$it",
|
||||
id = "$tag$i",
|
||||
isLoading = true,
|
||||
),
|
||||
)
|
||||
|
|
@ -20,10 +20,10 @@ internal fun loadingListState(tag: String, count: Int) = buildList {
|
|||
}.toPersistentList()
|
||||
|
||||
internal fun emptyListState(tag: String, count: Int) = buildList {
|
||||
repeat(count) {
|
||||
repeat(count) { i ->
|
||||
add(
|
||||
DestinationRecipientListUM(
|
||||
id = "$tag$it",
|
||||
id = "$tag$i",
|
||||
isLoading = false,
|
||||
isVisible = false,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ internal class SendDestinationValidationResultTransformer(
|
|||
val isValidAddress = addressValidationResult.isRight()
|
||||
val isValidMemo = memoValidationResult.isRight()
|
||||
|
||||
val addressErrorText = addressValidationResult.mapLeft {
|
||||
when (it) {
|
||||
val addressErrorText = addressValidationResult.mapLeft { error ->
|
||||
when (error) {
|
||||
is AddressValidation.Error.DataError,
|
||||
AddressValidation.Error.InvalidAddress,
|
||||
-> R.string.send_recipient_address_error
|
||||
|
|
|
|||
|
|
@ -67,10 +67,13 @@ internal fun SendDestinationContent(
|
|||
onAddressChange = clickIntents::onRecipientAddressValueChange,
|
||||
onQrCodeClick = clickIntents::onQrCodeScanClick,
|
||||
)
|
||||
memoField(
|
||||
memoField = state.memoTextField,
|
||||
onMemoChange = clickIntents::onRecipientMemoValueChange,
|
||||
)
|
||||
val memoTextField = state.memoTextField
|
||||
if (memoTextField != null) {
|
||||
memoField(
|
||||
memoField = memoTextField,
|
||||
onMemoChange = clickIntents::onRecipientMemoValueChange,
|
||||
)
|
||||
}
|
||||
listHeaderItem(
|
||||
titleRes = if (state.isAccountsMode == true) {
|
||||
R.string.common_accounts
|
||||
|
|
@ -153,40 +156,38 @@ private fun LazyListScope.addressItem(
|
|||
}
|
||||
|
||||
private fun LazyListScope.memoField(
|
||||
memoField: DestinationTextFieldUM.RecipientMemo?,
|
||||
memoField: DestinationTextFieldUM.RecipientMemo,
|
||||
onMemoChange: (String, Boolean) -> Unit,
|
||||
) {
|
||||
if (memoField != null) {
|
||||
item(key = MEMO_FIELD_KEY) {
|
||||
val placeholder = if (memoField.isEnabled) memoField.placeholder else memoField.disabledText
|
||||
TextFieldWithPaste(
|
||||
value = memoField.value,
|
||||
label = memoField.label,
|
||||
placeholder = placeholder,
|
||||
footer = annotatedReference(
|
||||
buildAnnotatedString {
|
||||
append(stringResourceSafe(R.string.send_recipient_memo_footer_v2))
|
||||
append("\n")
|
||||
withStyle(SpanStyle(fontWeight = FontWeight.Medium)) {
|
||||
appendColored(
|
||||
text = stringResourceSafe(
|
||||
R.string.send_recipient_memo_footer_v2_highlighted,
|
||||
),
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
}
|
||||
},
|
||||
),
|
||||
onValueChange = { onMemoChange(it, false) },
|
||||
onPasteClick = { onMemoChange(it, true) },
|
||||
modifier = Modifier.padding(top = 20.dp),
|
||||
labelStyle = TangemTheme.typography.subtitle2,
|
||||
isError = memoField.isError,
|
||||
error = memoField.error,
|
||||
isReadOnly = !memoField.isEnabled,
|
||||
isValuePasted = memoField.isValuePasted,
|
||||
)
|
||||
}
|
||||
item(key = MEMO_FIELD_KEY) {
|
||||
val placeholder = if (memoField.isEnabled) memoField.placeholder else memoField.disabledText
|
||||
TextFieldWithPaste(
|
||||
value = memoField.value,
|
||||
label = memoField.label,
|
||||
placeholder = placeholder,
|
||||
footer = annotatedReference(
|
||||
buildAnnotatedString {
|
||||
append(stringResourceSafe(R.string.send_recipient_memo_footer_v2))
|
||||
append("\n")
|
||||
withStyle(SpanStyle(fontWeight = FontWeight.Medium)) {
|
||||
appendColored(
|
||||
text = stringResourceSafe(
|
||||
R.string.send_recipient_memo_footer_v2_highlighted,
|
||||
),
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
}
|
||||
},
|
||||
),
|
||||
onValueChange = { onMemoChange(it, false) },
|
||||
onPasteClick = { onMemoChange(it, true) },
|
||||
modifier = Modifier.padding(top = 20.dp),
|
||||
labelStyle = TangemTheme.typography.subtitle2,
|
||||
isError = memoField.isError,
|
||||
error = memoField.error,
|
||||
isReadOnly = !memoField.isEnabled,
|
||||
isValuePasted = memoField.isValuePasted,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -297,8 +298,8 @@ private fun AnimateRecentAppearance(isVisible: Boolean, content: @Composable ()
|
|||
(slideInHorizontally() + fadeIn())
|
||||
.togetherWith(slideOutVertically() + fadeOut())
|
||||
},
|
||||
) {
|
||||
if (it) {
|
||||
) { currentVisibility ->
|
||||
if (currentVisibility) {
|
||||
content()
|
||||
} else {
|
||||
Box(modifier = Modifier.fillMaxWidth())
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ internal class BitcoinCustomFeeConverter(
|
|||
amount = feeValue,
|
||||
decimals = value.amount.decimals,
|
||||
txSize = value.txSize,
|
||||
).toString(),
|
||||
)?.toString().orEmpty(),
|
||||
decimals = SATOSHI_DECIMALS,
|
||||
symbol = "",
|
||||
title = resourceReference(R.string.send_satoshi_per_byte_title),
|
||||
|
|
|
|||
|
|
@ -39,14 +39,16 @@ internal class EthereumCustomFeeConverter(
|
|||
|
||||
override fun convert(value: Fee.Ethereum): ImmutableList<CustomFeeFieldUM> {
|
||||
return buildList {
|
||||
convertFeeValue(value).let(::add)
|
||||
add(convertFeeValue(value))
|
||||
|
||||
when (value) {
|
||||
is Fee.Ethereum.EIP1559 -> eipFeeConverter.convert(value)
|
||||
is Fee.Ethereum.Legacy -> legacyFeeConverter.convert(value)
|
||||
}.let(::addAll)
|
||||
addAll(
|
||||
when (value) {
|
||||
is Fee.Ethereum.EIP1559 -> eipFeeConverter.convert(value)
|
||||
is Fee.Ethereum.Legacy -> legacyFeeConverter.convert(value)
|
||||
},
|
||||
)
|
||||
|
||||
convertGasLimitValue(value).let(::add)
|
||||
add(convertGasLimitValue(value))
|
||||
}
|
||||
.toImmutableList()
|
||||
}
|
||||
|
|
@ -72,8 +74,18 @@ internal class EthereumCustomFeeConverter(
|
|||
value: String,
|
||||
): ImmutableList<CustomFeeFieldUM> {
|
||||
return when (feeValue) {
|
||||
is Fee.Ethereum.EIP1559 -> eipFeeConverter.onValueChange(feeValue, customValues, index, value)
|
||||
is Fee.Ethereum.Legacy -> legacyFeeConverter.onValueChange(feeValue, customValues, index, value)
|
||||
is Fee.Ethereum.EIP1559 -> eipFeeConverter.onValueChange(
|
||||
feeValue = feeValue,
|
||||
customValues = customValues,
|
||||
index = index,
|
||||
value = value,
|
||||
)
|
||||
is Fee.Ethereum.Legacy -> legacyFeeConverter.onValueChange(
|
||||
feeValue = feeValue,
|
||||
customValues = customValues,
|
||||
index = index,
|
||||
value = value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -101,15 +101,16 @@ internal class KaspaCustomFeeConverter(
|
|||
// check that there is reveal transaction info (= krc-20 token transfer)
|
||||
// return without changes otherwise
|
||||
if (minimumFee.revealTransactionFee != null && minimumFeeAmountValue != null) {
|
||||
getOrNull(FEE_AMOUNT_INDEX)?.let {
|
||||
val valueDecimal = it.value.parseToBigDecimal(it.decimals)
|
||||
val customFeeFieldUM = getOrNull(FEE_AMOUNT_INDEX)
|
||||
if (customFeeFieldUM != null) {
|
||||
val valueDecimal = customFeeFieldUM.value.parseToBigDecimal(customFeeFieldUM.decimals)
|
||||
// krc-20 transaction will be failed if custom fee value is less than minimum,
|
||||
// so we set value to minimum in this case
|
||||
if (valueDecimal < minimumFee.amount.value) {
|
||||
val fixedValue = minimumFeeAmountValue.parseBigDecimal(it.decimals)
|
||||
val fixedValue = minimumFeeAmountValue.parseBigDecimal(customFeeFieldUM.decimals)
|
||||
set(
|
||||
FEE_AMOUNT_INDEX,
|
||||
it.copy(
|
||||
customFeeFieldUM.copy(
|
||||
value = fixedValue,
|
||||
label = getFiatReference(
|
||||
rate = currencyStatus.fiatRate,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM
|
|||
internal sealed class NotificationsAnalyticEvents(
|
||||
category: String,
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : AnalyticsEvent(category = category, event = event, params = params) {
|
||||
|
||||
abstract val categoryName: String
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ class NFTSendConfirmationNotificationsTransformerV2Test {
|
|||
isPrimaryButtonEnabled = true,
|
||||
walletName = mockk(relaxed = true),
|
||||
isSending = false,
|
||||
showTapHelp = false,
|
||||
isShowTapHelp = false,
|
||||
sendingFooter = mockk(relaxed = true),
|
||||
notifications = persistentListOf(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ class SendConfirmationNotificationsTransformerV2Test {
|
|||
isPrimaryButtonEnabled = true,
|
||||
walletName = mockk(relaxed = true),
|
||||
isSending = false,
|
||||
showTapHelp = false,
|
||||
isShowTapHelp = false,
|
||||
sendingFooter = mockk(relaxed = true),
|
||||
notifications = persistentListOf(),
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue