Updated on 2026-08-14
This commit is contained in:
parent
eb73a64054
commit
00d55ff5a6
39 changed files with 195 additions and 272 deletions
|
|
@ -15,7 +15,6 @@
|
|||
<ID>MultilineLambdaItParameter:ChooseManagedTokenContent.kt${ add( CurrencyItemUM.Basic( id = ManagedCryptoCurrency.ID( value = "ID+$it", ), name = "Bitcoin", symbol = "BTC", icon = CurrencyIconState.Loading, networks = CurrencyItemUM.Basic.NetworksUM.Collapsed, onExpandClick = {}, ), ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:ChooseManagedTokensModel.kt$ChooseManagedTokensModel${ it.copy( notificationUM = null, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:CurrencyItemMapper.kt${ it.toCurrencyNetworkModel( isSelected = it.network in addedIn, isEditable = false, onSelectedStateChange = { _, _ -> }, onLongTap = { _ -> }, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:CurrencyNetworksMapper.kt${ it.toCurrencyNetworkModel( isSelected = it.network in addedIn, isEditable = isItemsEditable, onSelectedStateChange = onSelectedStateChange, onLongTap = onLongTap, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:CustomCurrencyFormOperations.kt${ it[Field.CONTRACT_ADDRESS] = it.getValue(Field.CONTRACT_ADDRESS).copy( error = when (exception) { CustomTokenFormValidationException.ContractAddress.Invalid -> { resourceReference(R.string.custom_token_creation_error_invalid_contract_address) } }, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:CustomCurrencyFormOperations.kt${ it[Field.DECIMALS] = it.getValue(Field.DECIMALS).copy( error = when (exception) { is CustomTokenFormValidationException.Decimals.Empty -> { null // Should not display this error } is CustomTokenFormValidationException.Decimals.Invalid -> { resourceReference( R.string.custom_token_creation_error_wrong_decimals, wrappedList(ValidateTokenFormUseCase.MAX_DECIMALS), ) } }, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:CustomTokenFormContent.kt$PreviewCustomTokenFormComponentProvider${ it[Field.CONTRACT_ADDRESS] = it[Field.CONTRACT_ADDRESS]!!.copy( label = stringReference("Contract address"), value = "0x1234567890", error = stringReference("Contract address is invalid"), placeholder = stringReference("0x1234567890"), ) }</ID>
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@
|
|||
<ID>MultilineLambdaItParameter:MarketsListBatchFlowManager.kt$MarketsListBatchFlowManager${ when (val status = it.status) { is PaginationStatus.Paginating -> { if (status.lastResult is BatchFetchResult.Success) { it.data.size == 1 } else { null } } is PaginationStatus.EndOfPagination -> { it.data.size == 1 } else -> null } }</ID>
|
||||
<ID>MultilineLambdaItParameter:MarketsListItem.kt${ if (Random.nextBoolean()) { it.first.inc() to PriceChangeType.UP } else { it.first.dec() to PriceChangeType.DOWN } }</ID>
|
||||
<ID>MultilineLambdaItParameter:MarketsListLazyColumn.kt${ (it.key as? String)?.split(TOKEN_LAZY_LIST_ID_SEPARATOR)?.first() ?.let { rawId -> CryptoCurrency.RawID(rawId) } }</ID>
|
||||
<ID>MultilineLambdaItParameter:MarketsListModel.kt$MarketsListModel${ if (it == BottomSheetState.EXPANDED) { analyticsEventHandler.send(MarketsListAnalyticsEvent.BottomSheetOpened) } }</ID>
|
||||
<ID>MultilineLambdaItParameter:MarketsListModel.kt$MarketsListModel${ if (it) { analyticsEventHandler.send(MarketsListAnalyticsEvent.TokenSearched(tokenFound = false)) } }</ID>
|
||||
<ID>MultilineLambdaItParameter:MarketsListModel.kt$MarketsListModel${ if (it.isNotEmpty()) { activeListManager.getBatchKeysByItemIds(visibleItemIds.value) } else { null } }</ID>
|
||||
<ID>MultilineLambdaItParameter:MarketsListModel.kt$MarketsListModel${ if (it.list !is ListUM.Content) { visibleItemIds.value = emptyList() } }</ID>
|
||||
|
|
|
|||
|
|
@ -98,7 +98,6 @@
|
|||
<ID>MultilineLambdaItParameter:OnboardingVisaModel.kt$OnboardingVisaModel${ val derivedKey = it.derivedKeys[VisaUtilities.visaDefaultDerivationPath] ?: return@any false VisaWalletPublicKeyUtility.validateExtendedPublicKey( targetAddress = targetAddress, extendedPublicKey = derivedKey, ).onLeft { return@any VisaWalletPublicKeyUtility.findKeyWithoutDerivation( targetAddress = targetAddress, card = wallet.scanResponse.card, ).isRight() }.isRight() }</ID>
|
||||
<ID>MultilineLambdaItParameter:OnboardingVisaOtherWalletModel.kt$OnboardingVisaOtherWalletModel${ if (it is VisaActivationRemoteState.AwaitingPinCode) { onDone.emit(it.activationOrderInfo) return@launch } }</ID>
|
||||
<ID>MultilineLambdaItParameter:OnboardingVisaOtherWalletModel.kt$OnboardingVisaOtherWalletModel${ uiMessageSender.showErrorDialog(it) analyticsEventHandler.send(VisaAnalyticsEvent.ErrorOnboarding(it)) delay(timeMillis = 60_000) }</ID>
|
||||
<ID>MultilineLambdaItParameter:OnboardingVisaPinCodeModel.kt$OnboardingVisaPinCodeModel${ it.copy( pinCode = pin, submitButtonEnabled = PinCodeValidation.validate(pin), error = if (isError) { analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.ErrorPinValidation) resourceReference(R.string.visa_onboarding_pin_validation_error_message) } else { null }, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:OnboardingVisaWelcomeModel.kt$OnboardingVisaWelcomeModel${ onError(it) return@launch }</ID>
|
||||
<ID>MultilineLambdaItParameter:SeedPhraseCheckUiStateBuilder.kt$SeedPhraseCheckUiStateBuilder${ checkWordField( word = it.word.text, shownIndex = it.index, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:TwinWalletArtwork.kt${ animationState = it val maxTime = maxOf( transition1.totalDurationNanos, transition2.totalDurationNanos, ) delay(TimeUnit.NANOSECONDS.toMillis(maxTime)) }</ID>
|
||||
|
|
@ -126,7 +125,6 @@
|
|||
<ID>UseEmptyCounterpart:OnboardingEvent.kt$OnboardingEvent$mapOf()</ID>
|
||||
<ID>UseEmptyCounterpart:OnboardingEvent.kt$OnboardingEvent.Backup$mapOf()</ID>
|
||||
<ID>UseEmptyCounterpart:OnboardingEvent.kt$OnboardingEvent.CreateWallet$mapOf()</ID>
|
||||
<ID>UseEmptyCounterpart:OnboardingEvent.kt$OnboardingEvent.Topup$mapOf()</ID>
|
||||
<ID>UseEmptyCounterpart:OnboardingEvent.kt$OnboardingEvent.Twins$mapOf()</ID>
|
||||
<ID>UseEmptyCounterpart:OnboardingVisaAnalyticsEvent.kt$OnboardingVisaAnalyticsEvent$mapOf()</ID>
|
||||
<ID>UseEmptyCounterpart:VisaAnalyticsEvent.kt$VisaAnalyticsEvent$mapOf()</ID>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
<ManuallySuppressedIssues/>
|
||||
<CurrentIssues>
|
||||
<ID>MultilineLambdaItParameter:AgreementText.kt${ val clickableSpanStyle = requireNotNull(agreementText.spanStyles.getOrNull(1)) if (it in clickableSpanStyle.start..clickableSpanStyle.end) { onClick() } }</ID>
|
||||
<ID>MultilineLambdaItParameter:ReferralModel.kt$ReferralModel${ analyticsEventHandler.send(ReferralEvents.ParticipateSuccessful) referralData.value = it }</ID>
|
||||
<ID>MultilineLambdaItParameter:ReferralScreen.kt${ // TODO: use StateEvent if (stateHolder.errorSnackbar != null) { TangemSnackbar(data = it, actionOnNewLine = true) } else { CopiedTextSnackbar(it) } }</ID>
|
||||
<ID>MultilineLambdaItParameter:ReferralScreen.kt${ ReferralContent( stateHolder = stateHolder, snackbarHostState = snackbarHostState, onAgreementClick = stateHolder.analytics.onAgreementClicked, modifier = Modifier.padding(it), ) }</ID>
|
||||
<ID>NamedArguments:ReferralScreen.kt$Text( formatAwardConditionsString( quantity = award, network = networkName, address = if (!address.isNullOrBlank()) " $address" else "", ), color = TangemTheme.colors.text.tertiary, style = TangemTheme.typography.body2, modifier = Modifier.testTag(ReferralProgramScreenTestTags.INFO_FOR_YOU_TEXT), )</ID>
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
<?xml version="1.0" ?>
|
||||
<SmellBaseline>
|
||||
<ManuallySuppressedIssues/>
|
||||
<CurrentIssues>
|
||||
<ID>BooleanPropertyNaming:ConfirmUM.kt$ConfirmUM.Content$val showTapHelp: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:SwapAmountModel.kt$SwapAmountModel$private var showBestRateAnimation: Boolean = false</ID>
|
||||
<ID>BooleanPropertyNaming:SwapAmountModel.kt$SwapAmountModel$val showSendViaSwapNotification = shouldShowNotificationUseCase( NotificationId.SendViaSwapTokenSelectorNotification.key, )</ID>
|
||||
<ID>BooleanPropertyNaming:SwapAmountPrimaryReadyStateTransformer.kt$SwapAmountPrimaryReadyStateTransformer$private val showBestRateAnimation: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:SwapAmountSecondaryReadyStateTransformer.kt$SwapAmountSecondaryReadyStateTransformer$private val showBestRateAnimation: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:SwapAmountSelectQuoteTransformer.kt$SwapAmountSelectQuoteTransformer$private val needApplyFCARestrictions: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:SwapAmountSetQuotesTransformer.kt$SwapAmountSetQuotesTransformer$private val needApplyFcaRestrictions: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:SwapAmountUM.kt$SwapAmountUM.Content$val showBestRateAnimation: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:SwapAmountUM.kt$SwapAmountUM.Content$val showFCAWarning: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:SwapChooseProviderModel.kt$SwapChooseProviderModel$private val needApplyFCARestrictions = params.userCountry.needApplyFCARestrictions()</ID>
|
||||
<ID>BooleanPropertyNaming:SwapProviderListItemConverter.kt$SwapProviderListItemConverter$private val needApplyFCARestrictions: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:SwapProviderStateConverter.kt$SwapProviderStateConverter$private val needApplyFCARestrictions: Boolean</ID>
|
||||
<ID>CouldBeSequence:SwapAmountModel.kt$SwapAmountModel$filter { it.currencyStatus.currency.id == toCryptoCurrency.id }</ID>
|
||||
<ID>MaxChainedCallsOnSameLine:SwapAlertFactory.kt$SwapAlertFactory$confirmData?.fee?.amount?.value?.toString().orEmpty()</ID>
|
||||
<ID>MultilineLambdaItParameter:SendWithSwapConfirmModel.kt$SendWithSwapConfirmModel${ it.copy( confirmUM = SendWithSwapConfirmInitialStateTransformer( isShowTapHelp = isShowTapHelp, ).transform(uiState.value.confirmUM), ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:SendWithSwapConfirmModel.kt$SendWithSwapConfirmModel${ val confirmUM = it.confirmUM as? ConfirmUM.Content it.copy(confirmUM = confirmUM?.copy(showTapHelp = showTapHelp) ?: it.confirmUM) }</ID>
|
||||
<ID>MultilineLambdaItParameter:SendWithSwapConfirmModel.kt$SendWithSwapConfirmModel${ val feeUM = it.feeSelectorUM as? FeeSelectorUM.Content it.copy( confirmUM = (it.confirmUM as? ConfirmUM.Content)?.copy( isPrimaryButtonEnabled = !hasError && feeUM != null, ) ?: it.confirmUM, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:SendWithSwapConfirmationNotificationsTransformer.kt$SendWithSwapConfirmationNotificationsTransformer${ ConfirmUM.Content.LegalUM( title = resourceReference(R.string.common_privacy_policy), link = it, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:SendWithSwapConfirmationNotificationsTransformer.kt$SendWithSwapConfirmationNotificationsTransformer${ ConfirmUM.Content.LegalUM( title = resourceReference(R.string.common_terms_of_use), link = it, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:SendWithSwapModel.kt$SendWithSwapModel${ Timber.w(it.toString()) swapAlertFactory.getGenericErrorState( expressError = ExpressError.UnknownError, onFailedTxEmailClick = { modelScope.launch { swapAlertFactory.onFailedTxEmailClick( userWallet = userWallet, cryptoCurrency = params.currency, errorMessage = it.toString(), ) } }, popBack = ::onBackClick, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:SendWithSwapModel.kt$SendWithSwapModel${ it.copy( destinationUM = DestinationUM.Empty(), feeSelectorUM = FeeSelectorUM.Loading, confirmUM = ConfirmUM.Empty, navigationUM = NavigationUM.Empty, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:SwapAmountSetQuotesTransformer.kt$SwapAmountSetQuotesTransformer${ it is SwapQuoteUM.Content || it is SwapQuoteUM.Allowance || (it as? SwapQuoteUM.Error)?.expressError is ExpressError.AmountError }</ID>
|
||||
<ID>MultilineLambdaItParameter:SwapChooseProviderModel.kt$SwapChooseProviderModel${ it is SwapQuoteUM.Content || it is SwapQuoteUM.Allowance || (it as? SwapQuoteUM.Error)?.expressError is ExpressError.AmountError }</ID>
|
||||
<ID>MultilineLambdaItParameter:SwapChooseTokenNetworkModel.kt$SwapChooseTokenNetworkModel${ Timber.e("Failed to get user wallet: $it") swapChooseTokenAlertFactory.getGenericErrorState(params.onDismiss) return }</ID>
|
||||
<ID>MultilineLambdaItParameter:SwapChooseTokenNetworkModel.kt$SwapChooseTokenNetworkModel${ Timber.e(it.toString()) uiState.update( SwapChooseErrorStateTransformer( tokenName = params.token.name, onDismiss = params.onDismiss, ), ) return@launch }</ID>
|
||||
<ID>MultilineLambdaItParameter:SwapTransactionSender.kt$SwapTransactionSender${ Timber.e(it, "Failed to create swap CEX tx data") onSendError(SendTransactionError.UnknownError(Exception(it))) return }</ID>
|
||||
<ID>MultilineLambdaItParameter:SwapTransactionSender.kt$SwapTransactionSender${ onExpressError(it); return }</ID>
|
||||
<ID>NamedArguments:SwapTransactionSender.kt$SwapTransactionSender$getSwapDataUseCase( userWallet = userWallet, fromCryptoCurrencyStatus = fromStatus, fromAmount = fromAmount.toStringWithRightOffset(fromStatus.currency.decimals), toCryptoCurrency = toStatus.currency, toAddress = destination, expressProvider = provider, rateType = rateType, expressOperationType, )</ID>
|
||||
<ID>NoNameShadowing:SendWithSwapContent.kt$navigationUM</ID>
|
||||
<ID>NoNameShadowing:SwapAmountContent.kt$amountFieldUM</ID>
|
||||
<ID>NullableToStringCall:SendWithSwapConfirmModel.kt$SendWithSwapConfirmModel$error.toString()</ID>
|
||||
<ID>NullableToStringCall:SwapAmountModel.kt$SwapAmountModel$$primaryStatus</ID>
|
||||
<ID>NullableToStringCall:SwapAmountModel.kt$SwapAmountModel$$secondaryStatus</ID>
|
||||
<ID>PropertyUsedBeforeDeclaration:SendWithSwapConfirmModel.kt$SendWithSwapConfirmModel$amountUM</ID>
|
||||
<ID>UnnecessaryEventHandlerParameter:SwapAmountContent.kt$onExpandEditField: (SwapAmountType) -> Unit</ID>
|
||||
<ID>UseEmptyCounterpart:SendWithSwapAnalyticEvents.kt$SendWithSwapAnalyticEvents$mapOf()</ID>
|
||||
<ID>UseEmptyCounterpart:SendWithSwapSuccessContent.kt$listOf()</ID>
|
||||
<ID>UseEmptyCounterpart:SwapAmountAnalyticEvents.kt$SwapAmountAnalyticEvents$mapOf()</ID>
|
||||
<ID>VarCouldBeVal:SwapAmountModel.kt$SwapAmountModel$private var primaryCryptoCurrency: CryptoCurrency = params.primaryCryptoCurrencyStatusFlow.value.currency</ID>
|
||||
<ID>VarCouldBeVal:SwapAmountModel.kt$SwapAmountModel$private var userWallet = params.userWallet</ID>
|
||||
</CurrentIssues>
|
||||
</SmellBaseline>
|
||||
|
|
@ -6,7 +6,7 @@ import com.tangem.core.analytics.models.AnalyticsParam.Key.PROVIDER
|
|||
internal sealed class SwapAmountAnalyticEvents(
|
||||
category: String,
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : AnalyticsEvent(category = category, event = event, params = params) {
|
||||
|
||||
data class ProviderSelectorClicked(
|
||||
|
|
|
|||
|
|
@ -48,11 +48,11 @@ internal sealed class SwapAmountUM {
|
|||
val swapCurrencies: SwapCurrencies,
|
||||
val swapQuotes: ImmutableList<SwapQuoteUM>,
|
||||
val selectedQuote: SwapQuoteUM,
|
||||
val showFCAWarning: Boolean,
|
||||
val isShowFCAWarning: Boolean,
|
||||
|
||||
// extra data
|
||||
val appCurrency: AppCurrency?,
|
||||
val showBestRateAnimation: Boolean,
|
||||
val isShowBestRateAnimation: Boolean,
|
||||
) : SwapAmountUM()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,11 +26,8 @@ import com.tangem.domain.notifications.ShouldShowNotificationUseCase
|
|||
import com.tangem.domain.settings.usercountry.GetUserCountryUseCase
|
||||
import com.tangem.domain.settings.usercountry.models.UserCountry
|
||||
import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions
|
||||
import com.tangem.domain.swap.models.SwapCurrencies
|
||||
import com.tangem.domain.swap.models.SwapDirection
|
||||
import com.tangem.domain.swap.models.*
|
||||
import com.tangem.domain.swap.models.SwapDirection.Companion.withSwapDirection
|
||||
import com.tangem.domain.swap.models.SwapQuoteModel
|
||||
import com.tangem.domain.swap.models.getGroupWithDirection
|
||||
import com.tangem.domain.swap.usecase.GetSwapQuoteUseCase
|
||||
import com.tangem.domain.swap.usecase.SelectInitialPairUseCase
|
||||
import com.tangem.domain.tokens.GetMinimumTransactionAmountSyncUseCase
|
||||
|
|
@ -99,9 +96,9 @@ internal class SwapAmountModel @Inject constructor(
|
|||
private val params: SwapAmountComponentParams = paramsContainer.require()
|
||||
private val swapDirection = params.swapDirection
|
||||
private var appCurrency = AppCurrency.Default
|
||||
private var userWallet = params.userWallet
|
||||
private val userWallet = params.userWallet
|
||||
|
||||
private var primaryCryptoCurrency: CryptoCurrency = params.primaryCryptoCurrencyStatusFlow.value.currency
|
||||
private val primaryCryptoCurrency: CryptoCurrency = params.primaryCryptoCurrencyStatusFlow.value.currency
|
||||
|
||||
private var primaryMaximumAmountBoundary: EnterAmountBoundary by Delegates.notNull()
|
||||
private var primaryMinimumAmountBoundary: EnterAmountBoundary by Delegates.notNull()
|
||||
|
|
@ -111,7 +108,7 @@ internal class SwapAmountModel @Inject constructor(
|
|||
private var userCountry: UserCountry = UserCountry.Other(Locale.getDefault().country)
|
||||
val bottomSheetNavigation: SlotNavigation<SwapChooseProviderConfig> = SlotNavigation()
|
||||
|
||||
private var showBestRateAnimation: Boolean = false
|
||||
private var isShowBestRateAnimation: Boolean = false
|
||||
|
||||
val uiState: StateFlow<SwapAmountUM>
|
||||
field = MutableStateFlow(params.amountUM)
|
||||
|
|
@ -124,7 +121,7 @@ internal class SwapAmountModel @Inject constructor(
|
|||
appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default }
|
||||
userCountry = getUserCountryUseCase.invokeSync().getOrNull()
|
||||
?: UserCountry.Other(Locale.getDefault().country)
|
||||
showBestRateAnimation = swapBestRateAnimationStore.getSyncOrNull()
|
||||
isShowBestRateAnimation = swapBestRateAnimationStore.getSyncOrNull()
|
||||
}
|
||||
configAmountNavigation()
|
||||
subscribeOnCryptoCurrencyStatusFlow()
|
||||
|
|
@ -169,7 +166,7 @@ internal class SwapAmountModel @Inject constructor(
|
|||
quoteUM = quoteUM,
|
||||
secondaryMaximumAmountBoundary = secondaryMaximumAmountBoundary,
|
||||
secondaryMinimumAmountBoundary = secondaryMinimumAmountBoundary,
|
||||
needApplyFCARestrictions = userCountry.needApplyFCARestrictions(),
|
||||
isNeedApplyFCARestrictions = userCountry.needApplyFCARestrictions(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -270,7 +267,7 @@ internal class SwapAmountModel @Inject constructor(
|
|||
override fun onSelectTokenClick() {
|
||||
val amountParams = params as? SwapAmountComponentParams.AmountParams ?: return
|
||||
modelScope.launch {
|
||||
val showSendViaSwapNotification = shouldShowNotificationUseCase(
|
||||
val isShowSendViaSwapNotification = shouldShowNotificationUseCase(
|
||||
NotificationId.SendViaSwapTokenSelectorNotification.key,
|
||||
)
|
||||
val isEditMode = amountParams.currentRoute.firstOrNull()?.isEditMode == true
|
||||
|
|
@ -281,7 +278,7 @@ internal class SwapAmountModel @Inject constructor(
|
|||
initialCurrency = primaryCryptoCurrency,
|
||||
selectedCurrency = selectedCurrency.takeIf { isEditMode },
|
||||
source = AppRoute.ChooseManagedTokens.Source.SendViaSwap,
|
||||
shouldShowSendViaSwapNotification = showSendViaSwapNotification,
|
||||
shouldShowSendViaSwapNotification = isShowSendViaSwapNotification,
|
||||
analyticsCategoryName = params.analyticsCategoryName,
|
||||
),
|
||||
)
|
||||
|
|
@ -306,7 +303,7 @@ internal class SwapAmountModel @Inject constructor(
|
|||
|
||||
fun onFinishAnimation() {
|
||||
uiState.update {
|
||||
(it as? SwapAmountUM.Content)?.copy(showBestRateAnimation = false) ?: it
|
||||
(it as? SwapAmountUM.Content)?.copy(isShowBestRateAnimation = false) ?: it
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -367,7 +364,7 @@ internal class SwapAmountModel @Inject constructor(
|
|||
swapDirection = swapDirection,
|
||||
clickIntents = this,
|
||||
isBalanceHidden = params.isBalanceHidingFlow.value,
|
||||
showBestRateAnimation = showBestRateAnimation,
|
||||
isShowBestRateAnimation = isShowBestRateAnimation,
|
||||
isSingleWallet = isOnlyOneWallet,
|
||||
isAccountsMode = params.isAccountModeFlow.value,
|
||||
account = params.accountFlow.value,
|
||||
|
|
@ -418,7 +415,7 @@ internal class SwapAmountModel @Inject constructor(
|
|||
swapDirection = swapDirection,
|
||||
clickIntents = this,
|
||||
isBalanceHidden = params.isBalanceHidingFlow.value,
|
||||
showBestRateAnimation = showBestRateAnimation,
|
||||
isShowBestRateAnimation = isShowBestRateAnimation,
|
||||
isSingleWallet = isOnlyOneWallet,
|
||||
isAccountsMode = isAccountsMode,
|
||||
account = account,
|
||||
|
|
@ -532,7 +529,7 @@ internal class SwapAmountModel @Inject constructor(
|
|||
swapDirection = swapDirection,
|
||||
clickIntents = this@SwapAmountModel,
|
||||
isBalanceHidden = params.isBalanceHidingFlow.value,
|
||||
showBestRateAnimation = showBestRateAnimation,
|
||||
isShowBestRateAnimation = isShowBestRateAnimation,
|
||||
isSingleWallet = isOnlyOneWallet,
|
||||
isAccountsMode = params.isAccountModeFlow.value,
|
||||
account = params.accountFlow.value,
|
||||
|
|
@ -540,6 +537,7 @@ internal class SwapAmountModel @Inject constructor(
|
|||
)
|
||||
startLoadingQuotesTask(isSilentReload = false)
|
||||
} else {
|
||||
@Suppress("NullableToStringCall")
|
||||
Timber.e(
|
||||
"""
|
||||
Invalid cryptocurrencies status:
|
||||
|
|
@ -596,50 +594,50 @@ internal class SwapAmountModel @Inject constructor(
|
|||
val isAmountScreen = params is SwapAmountComponentParams.AmountParams
|
||||
val isAmountError = fromAmount?.amountTextField?.isError == true || fromAmountValue.isNullOrZero()
|
||||
if (isAmountScreen && isAmountError) {
|
||||
uiState.transformerUpdate(SwapQuoteEmptyStateTransformer)
|
||||
return
|
||||
uiState.transformerUpdate(SwapQuoteEmptyStateTransformer); return
|
||||
}
|
||||
|
||||
if (!isSilentReload) uiState.transformerUpdate(SwapQuoteLoadingStateTransformer)
|
||||
|
||||
modelScope.launch {
|
||||
val quotes = state.swapCurrencies.getGroupWithDirection(state.swapDirection).available.filter {
|
||||
it.currencyStatus.currency.id == toCryptoCurrency.id
|
||||
}.flatMap {
|
||||
it.providers
|
||||
}.map { provider ->
|
||||
async {
|
||||
getSwapQuoteUseCase(
|
||||
userWallet = userWallet,
|
||||
fromCryptoCurrency = fromCryptoCurrency,
|
||||
toCryptoCurrency = toCryptoCurrency,
|
||||
fromAmount = fromAmountValue,
|
||||
provider = provider,
|
||||
).fold(
|
||||
ifLeft = { error ->
|
||||
SwapQuoteUM.Error(
|
||||
provider = provider,
|
||||
expressError = error,
|
||||
)
|
||||
},
|
||||
ifRight = { quote: SwapQuoteModel ->
|
||||
SwapQuoteUMConverter(
|
||||
primaryCurrency = fromCryptoCurrency,
|
||||
secondaryCurrency = toCryptoCurrency,
|
||||
swapDirection = swapDirection,
|
||||
allowanceContract = quote.allowanceContract,
|
||||
isApprovalNeeded = checkAllowance(state, quote),
|
||||
fromAmount = fromAmountValue,
|
||||
).convert(
|
||||
SwapQuoteUMConverter.Data(
|
||||
quote = quote,
|
||||
val quotes = state.swapCurrencies.getGroupWithDirection(state.swapDirection).available
|
||||
.asSequence()
|
||||
.filter { swapCurrencyStatus -> swapCurrencyStatus.currencyStatus.currency.id == toCryptoCurrency.id }
|
||||
.flatMap(SwapCryptoCurrency::providers)
|
||||
.toList()
|
||||
.map { provider ->
|
||||
async {
|
||||
getSwapQuoteUseCase(
|
||||
userWallet = userWallet,
|
||||
fromCryptoCurrency = fromCryptoCurrency,
|
||||
toCryptoCurrency = toCryptoCurrency,
|
||||
fromAmount = fromAmountValue,
|
||||
provider = provider,
|
||||
).fold(
|
||||
ifLeft = { error ->
|
||||
SwapQuoteUM.Error(
|
||||
provider = provider,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}.awaitAll()
|
||||
expressError = error,
|
||||
)
|
||||
},
|
||||
ifRight = { quote: SwapQuoteModel ->
|
||||
SwapQuoteUMConverter(
|
||||
primaryCurrency = fromCryptoCurrency,
|
||||
secondaryCurrency = toCryptoCurrency,
|
||||
swapDirection = swapDirection,
|
||||
allowanceContract = quote.allowanceContract,
|
||||
isApprovalNeeded = checkAllowance(state, quote),
|
||||
fromAmount = fromAmountValue,
|
||||
).convert(
|
||||
SwapQuoteUMConverter.Data(
|
||||
quote = quote,
|
||||
provider = provider,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}.awaitAll()
|
||||
|
||||
uiState.transformerUpdate(
|
||||
SwapAmountSetQuotesTransformer(
|
||||
|
|
@ -647,7 +645,7 @@ internal class SwapAmountModel @Inject constructor(
|
|||
secondaryMaximumAmountBoundary = secondaryMaximumAmountBoundary,
|
||||
secondaryMinimumAmountBoundary = secondaryMinimumAmountBoundary,
|
||||
isSilentReload = isSilentReload,
|
||||
needApplyFcaRestrictions = userCountry.needApplyFCARestrictions(),
|
||||
isNeedApplyFcaRestrictions = userCountry.needApplyFCARestrictions(),
|
||||
),
|
||||
)
|
||||
feeSelectorReloadTrigger.triggerUpdate()
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ internal class SwapAmountPrimaryReadyStateTransformer(
|
|||
private val clickIntents: AmountScreenClickIntents,
|
||||
private val swapDirection: SwapDirection,
|
||||
private val isBalanceHidden: Boolean,
|
||||
private val showBestRateAnimation: Boolean,
|
||||
private val isShowBestRateAnimation: Boolean,
|
||||
private val isSingleWallet: Boolean,
|
||||
private val isAccountsMode: Boolean,
|
||||
private val account: Account.CryptoPortfolio?,
|
||||
|
|
@ -60,8 +60,8 @@ internal class SwapAmountPrimaryReadyStateTransformer(
|
|||
swapQuotes = persistentListOf(),
|
||||
selectedQuote = SwapQuoteUM.Empty,
|
||||
appCurrency = appCurrency,
|
||||
showBestRateAnimation = showBestRateAnimation,
|
||||
showFCAWarning = false,
|
||||
isShowBestRateAnimation = isShowBestRateAnimation,
|
||||
isShowFCAWarning = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -25,7 +25,7 @@ internal class SwapAmountSecondaryReadyStateTransformer(
|
|||
private val clickIntents: AmountScreenClickIntents,
|
||||
private val swapDirection: SwapDirection,
|
||||
private val isBalanceHidden: Boolean,
|
||||
private val showBestRateAnimation: Boolean,
|
||||
private val isShowBestRateAnimation: Boolean,
|
||||
private val isSingleWallet: Boolean,
|
||||
private val isAccountsMode: Boolean,
|
||||
private val account: Account.CryptoPortfolio?,
|
||||
|
|
@ -59,8 +59,8 @@ internal class SwapAmountSecondaryReadyStateTransformer(
|
|||
swapQuotes = persistentListOf(),
|
||||
selectedQuote = SwapQuoteUM.Empty,
|
||||
appCurrency = appCurrency,
|
||||
showBestRateAnimation = showBestRateAnimation,
|
||||
showFCAWarning = false,
|
||||
isShowBestRateAnimation = isShowBestRateAnimation,
|
||||
isShowFCAWarning = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ internal class SwapAmountSelectQuoteTransformer(
|
|||
private val quoteUM: SwapQuoteUM,
|
||||
private val secondaryMaximumAmountBoundary: EnterAmountBoundary?,
|
||||
private val secondaryMinimumAmountBoundary: EnterAmountBoundary?,
|
||||
private val needApplyFCARestrictions: Boolean,
|
||||
private val isNeedApplyFCARestrictions: Boolean,
|
||||
) : Transformer<SwapAmountUM> {
|
||||
override fun transform(prevState: SwapAmountUM): SwapAmountUM {
|
||||
if (prevState !is SwapAmountUM.Content) return prevState
|
||||
|
|
@ -31,7 +31,7 @@ internal class SwapAmountSelectQuoteTransformer(
|
|||
return prevState.copy(
|
||||
isPrimaryButtonEnabled = quoteUM is SwapQuoteUM.Content,
|
||||
selectedQuote = quoteUM,
|
||||
showFCAWarning = needApplyFCARestrictions && quoteUM.provider?.isRestrictedByFCA() == true,
|
||||
isShowFCAWarning = isNeedApplyFCARestrictions && quoteUM.provider?.isRestrictedByFCA() == true,
|
||||
primaryAmount = if (prevState.selectedAmountType == SwapAmountType.From) {
|
||||
val swapAmountField = prevState.primaryAmount as? SwapAmountFieldUM.Content
|
||||
val amountField = swapAmountField?.amountField as? AmountState.Data
|
||||
|
|
|
|||
|
|
@ -22,14 +22,14 @@ internal class SwapAmountSetQuotesTransformer(
|
|||
private val secondaryMaximumAmountBoundary: EnterAmountBoundary?,
|
||||
private val secondaryMinimumAmountBoundary: EnterAmountBoundary?,
|
||||
private val isSilentReload: Boolean,
|
||||
private val needApplyFcaRestrictions: Boolean,
|
||||
private val isNeedApplyFcaRestrictions: Boolean,
|
||||
) : Transformer<SwapAmountUM> {
|
||||
override fun transform(prevState: SwapAmountUM): SwapAmountUM {
|
||||
if (prevState !is SwapAmountUM.Content) return prevState
|
||||
|
||||
val isSingleProvider = quotes.filter {
|
||||
it is SwapQuoteUM.Content || it is SwapQuoteUM.Allowance ||
|
||||
(it as? SwapQuoteUM.Error)?.expressError is ExpressError.AmountError
|
||||
val isSingleProvider = quotes.filter { swapQuoteUM ->
|
||||
swapQuoteUM is SwapQuoteUM.Content || swapQuoteUM is SwapQuoteUM.Allowance ||
|
||||
(swapQuoteUM as? SwapQuoteUM.Error)?.expressError is ExpressError.AmountError
|
||||
}.isSingleItem()
|
||||
|
||||
val sortedQuotes = quotes.sortedWith(SwapQuotesComparator)
|
||||
|
|
@ -49,7 +49,7 @@ internal class SwapAmountSetQuotesTransformer(
|
|||
quoteUM = selectedQuote,
|
||||
secondaryMaximumAmountBoundary = secondaryMaximumAmountBoundary,
|
||||
secondaryMinimumAmountBoundary = secondaryMinimumAmountBoundary,
|
||||
needApplyFCARestrictions = needApplyFcaRestrictions &&
|
||||
isNeedApplyFCARestrictions = isNeedApplyFcaRestrictions &&
|
||||
selectedQuote.provider?.isRestrictedByFCA() == true,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ internal fun SwapAmountBlockContent(
|
|||
SwapChooseProviderContent(
|
||||
isBestRate = isBestRate,
|
||||
isSingleProvider = quoteContent?.isSingleProvider == true,
|
||||
showBestRateAnimation = amountUM.showBestRateAnimation,
|
||||
showBestRateAnimation = amountUM.isShowBestRateAnimation,
|
||||
expressProvider = amountUM.selectedQuote.provider,
|
||||
onClick = onProviderSelectClick,
|
||||
onFinishAnimation = onFinishAnimation,
|
||||
|
|
@ -98,7 +98,7 @@ internal fun SwapAmountBlockContent(
|
|||
start.linkTo(parent.start)
|
||||
end.linkTo(parent.end)
|
||||
},
|
||||
showFCAWarning = amountUM.showFCAWarning,
|
||||
showFCAWarning = amountUM.isShowFCAWarning,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ private fun SwapAmountBlock(
|
|||
selectedQuote = selectedQuote,
|
||||
isSelectedAmountType = isSelectedAmountType,
|
||||
isFixedRate = isFixedRate,
|
||||
onExpandEditField = clickIntents::onExpandEditField,
|
||||
onExpandEditField = { clickIntents.onExpandEditField(amountFieldUM.amountType) },
|
||||
onSelectTokenClick = clickIntents::onSelectTokenClick,
|
||||
onMaxAmountClick = clickIntents::onMaxValueClick,
|
||||
)
|
||||
|
|
@ -195,14 +195,14 @@ private fun SwapAmountEditBlock(
|
|||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
modifier = modifier.padding(top = 48.dp, bottom = 28.dp),
|
||||
) {
|
||||
when (val amountFieldUM = amountFieldUM.amountField) {
|
||||
when (val amountField = amountFieldUM.amountField) {
|
||||
!is AmountState.Data -> {
|
||||
TextShimmer(
|
||||
style = TangemTheme.typography.caption2,
|
||||
modifier = Modifier.width(60.dp),
|
||||
)
|
||||
}
|
||||
else -> AccountTitle(amountFieldUM.accountTitleUM)
|
||||
else -> AccountTitle(amountField.accountTitleUM)
|
||||
}
|
||||
AmountFieldV2(
|
||||
amountUM = amountFieldUM.amountField,
|
||||
|
|
@ -221,7 +221,7 @@ private fun SwapAmountInfo(
|
|||
selectedQuote: SwapQuoteUM?,
|
||||
isSelectedAmountType: Boolean,
|
||||
isFixedRate: Boolean,
|
||||
onExpandEditField: (SwapAmountType) -> Unit,
|
||||
onExpandEditField: () -> Unit,
|
||||
onMaxAmountClick: () -> Unit,
|
||||
onSelectTokenClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
|
|
@ -237,7 +237,7 @@ private fun SwapAmountInfo(
|
|||
enabled = (amountFieldUM as? SwapAmountFieldUM.Content)?.isClickEnabled == true,
|
||||
onClick = {
|
||||
if (isFixedRate) {
|
||||
onExpandEditField(amountFieldUM.amountType)
|
||||
onExpandEditField()
|
||||
} else {
|
||||
onSelectTokenClick()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,8 +90,8 @@ internal data object SwapAmountContentPreview {
|
|||
secondaryCryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
swapRateType = ExpressRateType.Float,
|
||||
appCurrency = AppCurrency.Default,
|
||||
showBestRateAnimation = false,
|
||||
showFCAWarning = false,
|
||||
isShowBestRateAnimation = false,
|
||||
isShowFCAWarning = false,
|
||||
)
|
||||
|
||||
val defaultState = SwapAmountUM.Content(
|
||||
|
|
@ -129,8 +129,8 @@ internal data object SwapAmountContentPreview {
|
|||
secondaryCryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
swapRateType = ExpressRateType.Float,
|
||||
isPrimaryButtonEnabled = true,
|
||||
showBestRateAnimation = false,
|
||||
showFCAWarning = true,
|
||||
isShowBestRateAnimation = false,
|
||||
isShowFCAWarning = true,
|
||||
)
|
||||
|
||||
val defaultStateAccount: SwapAmountUM.Content
|
||||
|
|
|
|||
|
|
@ -25,13 +25,13 @@ internal class SwapChooseProviderModel @Inject constructor(
|
|||
|
||||
private val params: SwapChooseProviderComponent.Params = paramsContainer.require()
|
||||
|
||||
private val needApplyFCARestrictions = params.userCountry.needApplyFCARestrictions()
|
||||
private val isNeedApplyFCARestrictions = params.userCountry.needApplyFCARestrictions()
|
||||
|
||||
private val swapProviderListItemConverter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
SwapProviderListItemConverter(
|
||||
cryptoCurrency = params.cryptoCurrency,
|
||||
selectedProvider = params.selectedProvider,
|
||||
needApplyFCARestrictions = needApplyFCARestrictions,
|
||||
isNeedApplyFCARestrictions = isNeedApplyFCARestrictions,
|
||||
needBestRateBadge = params.providers.filterIsInstance<SwapQuoteUM.Content>().isSingleItem().not(),
|
||||
)
|
||||
}
|
||||
|
|
@ -45,13 +45,13 @@ internal class SwapChooseProviderModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun getInitialState(): SwapChooseProviderBottomSheetContent {
|
||||
val filteredProviderList = params.providers.filter {
|
||||
it is SwapQuoteUM.Content ||
|
||||
it is SwapQuoteUM.Allowance ||
|
||||
(it as? SwapQuoteUM.Error)?.expressError is ExpressError.AmountError
|
||||
val filteredProviderList = params.providers.filter { swapQuoteUM ->
|
||||
swapQuoteUM is SwapQuoteUM.Content ||
|
||||
swapQuoteUM is SwapQuoteUM.Allowance ||
|
||||
(swapQuoteUM as? SwapQuoteUM.Error)?.expressError is ExpressError.AmountError
|
||||
}
|
||||
return SwapChooseProviderBottomSheetContent(
|
||||
isApplyFCARestrictions = needApplyFCARestrictions && params.selectedProvider.isRestrictedByFCA(),
|
||||
isApplyFCARestrictions = isNeedApplyFCARestrictions && params.selectedProvider.isRestrictedByFCA(),
|
||||
providerList = swapProviderListItemConverter.convertList(filteredProviderList)
|
||||
.filterNotNull()
|
||||
.toPersistentList(),
|
||||
|
|
|
|||
|
|
@ -21,14 +21,14 @@ import com.tangem.utils.converter.Converter
|
|||
internal class SwapProviderListItemConverter(
|
||||
private val cryptoCurrency: CryptoCurrency,
|
||||
private val selectedProvider: ExpressProvider,
|
||||
private val needApplyFCARestrictions: Boolean,
|
||||
private val isNeedApplyFCARestrictions: Boolean,
|
||||
needBestRateBadge: Boolean,
|
||||
) : Converter<SwapQuoteUM, SwapProviderListItem?> {
|
||||
|
||||
private val providerStateConverter = SwapProviderStateConverter(
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
selectedProvider = selectedProvider,
|
||||
needApplyFCARestrictions = needApplyFCARestrictions,
|
||||
isNeedApplyFCARestrictions = isNeedApplyFCARestrictions,
|
||||
isNeedBestRateBadge = needBestRateBadge,
|
||||
)
|
||||
|
||||
|
|
@ -78,7 +78,7 @@ internal class SwapProviderListItemConverter(
|
|||
},
|
||||
)
|
||||
}
|
||||
is SwapQuoteUM.Content -> if (needApplyFCARestrictions && value.provider.isRestrictedByFCA()) {
|
||||
is SwapQuoteUM.Content -> if (isNeedApplyFCARestrictions && value.provider.isRestrictedByFCA()) {
|
||||
ProviderChooseUM.ExtraUM.Action(
|
||||
text = resourceReference(R.string.express_provider_fca_warning_list),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ internal class SwapProviderStateConverter(
|
|||
private val cryptoCurrency: CryptoCurrency,
|
||||
private val selectedProvider: ExpressProvider,
|
||||
private val isNeedBestRateBadge: Boolean,
|
||||
private val needApplyFCARestrictions: Boolean,
|
||||
private val isNeedApplyFCARestrictions: Boolean,
|
||||
) : Converter<SwapQuoteUM, SwapProviderState> {
|
||||
|
||||
override fun convert(value: SwapQuoteUM): SwapProviderState {
|
||||
|
|
@ -41,7 +41,7 @@ internal class SwapProviderStateConverter(
|
|||
}
|
||||
|
||||
val additionalBadge = when {
|
||||
needApplyFCARestrictions && provider.isRestrictedByFCA() -> AdditionalBadge.FCAWarningList
|
||||
isNeedApplyFCARestrictions && provider.isRestrictedByFCA() -> AdditionalBadge.FCAWarningList
|
||||
isNeedBestRateBadge && isBestRate -> AdditionalBadge.BestTrade
|
||||
else -> AdditionalBadge.Empty
|
||||
}
|
||||
|
|
@ -59,7 +59,7 @@ internal class SwapProviderStateConverter(
|
|||
|
||||
private fun SwapQuoteUM.Error.convertToErrorContent(): SwapProviderState {
|
||||
val additionalBadge = when {
|
||||
needApplyFCARestrictions && provider.isRestrictedByFCA() -> AdditionalBadge.FCAWarningList
|
||||
isNeedApplyFCARestrictions && provider.isRestrictedByFCA() -> AdditionalBadge.FCAWarningList
|
||||
else -> AdditionalBadge.Empty
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,8 +66,8 @@ internal class SwapChooseTokenNetworkModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun initContent() {
|
||||
val userWallet = getUserWalletUseCase(params.userWalletId).getOrElse {
|
||||
Timber.e("Failed to get user wallet: $it")
|
||||
val userWallet = getUserWalletUseCase(params.userWalletId).getOrElse { error ->
|
||||
Timber.e("Failed to get user wallet: $error")
|
||||
swapChooseTokenAlertFactory.getGenericErrorState(params.onDismiss)
|
||||
return
|
||||
}
|
||||
|
|
@ -87,8 +87,8 @@ internal class SwapChooseTokenNetworkModel @Inject constructor(
|
|||
cryptoCurrencyList = cryptoCurrencyList + params.initialCurrency,
|
||||
filterProviderTypes = SEND_WITH_SWAP_PROVIDER_TYPES,
|
||||
swapTxType = SwapTxType.SendWithSwap,
|
||||
).getOrElse {
|
||||
Timber.e(it.toString())
|
||||
).getOrElse { error ->
|
||||
Timber.e(error.toString())
|
||||
uiState.update(
|
||||
SwapChooseErrorStateTransformer(
|
||||
tokenName = params.token.name,
|
||||
|
|
|
|||
|
|
@ -91,7 +91,8 @@ internal class SwapAlertFactory @Inject constructor(
|
|||
destinationAddress = confirmData?.enteredDestination.orEmpty(),
|
||||
tokenSymbol = confirmData?.toCryptoCurrencyStatus?.currency?.symbol.orEmpty(),
|
||||
amount = confirmData?.enteredAmount?.toString().orEmpty(),
|
||||
fee = confirmData?.fee?.amount?.value?.toString().orEmpty(),
|
||||
fee = confirmData?.fee?.amount?.value?.toString()
|
||||
.orEmpty(),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ internal sealed class ConfirmUM {
|
|||
data class Content(
|
||||
override val isPrimaryButtonEnabled: Boolean = false,
|
||||
val isTransactionInProcess: Boolean,
|
||||
val showTapHelp: Boolean,
|
||||
val isShowTapHelp: Boolean,
|
||||
val sendingFooter: TextReference,
|
||||
val notifications: ImmutableList<NotificationUM>,
|
||||
val tosUM: TosUM?,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
|
|||
|
||||
internal sealed class SendWithSwapAnalyticEvents(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : AnalyticsEvent(category = CommonSendAnalyticEvents.SEND_CATEGORY, event = event, params = params) {
|
||||
|
||||
data class TransactionScreenOpened(
|
||||
|
|
|
|||
|
|
@ -94,11 +94,7 @@ internal class SendWithSwapConfirmModel @Inject constructor(
|
|||
field = MutableStateFlow(params.sendWithSwapUM)
|
||||
|
||||
val primaryCurrencyStatus: CryptoCurrencyStatus = params.primaryCryptoCurrencyStatusFlow.value
|
||||
val secondaryCurrencyStatus: CryptoCurrencyStatus? = amountUM?.secondaryCryptoCurrencyStatus
|
||||
val primaryFeePaidCurrencyStatus: CryptoCurrencyStatus = params.primaryFeePaidCurrencyStatusFlow.value
|
||||
val secondaryCurrency: CryptoCurrency = requireNotNull(amountUM?.secondaryCryptoCurrencyStatus?.currency) {
|
||||
"Crypto currency must not be null"
|
||||
}
|
||||
|
||||
private val swapTransactionSender = swapTransactionSenderFactory.create(params.userWallet)
|
||||
|
||||
|
|
@ -111,6 +107,11 @@ internal class SendWithSwapConfirmModel @Inject constructor(
|
|||
private val feeSelectorUM
|
||||
get() = uiState.value.feeSelectorUM as? FeeSelectorUM.Content
|
||||
|
||||
val secondaryCurrencyStatus: CryptoCurrencyStatus? = amountUM?.secondaryCryptoCurrencyStatus
|
||||
val secondaryCurrency: CryptoCurrency = requireNotNull(amountUM?.secondaryCryptoCurrencyStatus?.currency) {
|
||||
"Crypto currency must not be null"
|
||||
}
|
||||
|
||||
val confirmData: ConfirmData
|
||||
get() {
|
||||
val amountUM = amountUM
|
||||
|
|
@ -270,13 +271,13 @@ internal class SendWithSwapConfirmModel @Inject constructor(
|
|||
uiState.transformerUpdate(SendWithSwapConfirmSendingStateTransformer(false))
|
||||
swapAlertFactory.getSendTransactionErrorState(
|
||||
error = error,
|
||||
onFailedTxEmailClick = {
|
||||
onFailedTxEmailClick = { _ ->
|
||||
modelScope.launch {
|
||||
swapAlertFactory.onFailedTxEmailClick(
|
||||
userWallet = params.userWallet,
|
||||
cryptoCurrency = confirmData.fromCryptoCurrencyStatus?.currency,
|
||||
confirmData = confirmData,
|
||||
errorMessage = error.toString(),
|
||||
errorMessage = error?.toString().orEmpty(),
|
||||
)
|
||||
}
|
||||
},
|
||||
|
|
@ -320,8 +321,8 @@ internal class SendWithSwapConfirmModel @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 = SendWithSwapConfirmInitialStateTransformer(
|
||||
isShowTapHelp = isShowTapHelp,
|
||||
).transform(uiState.value.confirmUM),
|
||||
|
|
@ -335,9 +336,9 @@ internal class SendWithSwapConfirmModel @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)
|
||||
}
|
||||
|
|
@ -376,12 +377,12 @@ internal class SendWithSwapConfirmModel @Inject constructor(
|
|||
flow2 = swapNotificationsUpdateListener.hasErrorFlow,
|
||||
) { hasSendError, hasSwapError ->
|
||||
val hasError = hasSendError || hasSwapError
|
||||
uiState.update {
|
||||
val feeUM = it.feeSelectorUM as? FeeSelectorUM.Content
|
||||
it.copy(
|
||||
confirmUM = (it.confirmUM as? ConfirmUM.Content)?.copy(
|
||||
uiState.update { state ->
|
||||
val feeUM = state.feeSelectorUM as? FeeSelectorUM.Content
|
||||
state.copy(
|
||||
confirmUM = (state.confirmUM as? ConfirmUM.Content)?.copy(
|
||||
isPrimaryButtonEnabled = !hasError && feeUM != null,
|
||||
) ?: it.confirmUM,
|
||||
) ?: state.confirmUM,
|
||||
)
|
||||
}
|
||||
}.launchIn(modelScope)
|
||||
|
|
|
|||
|
|
@ -98,8 +98,8 @@ internal class SwapTransactionSender @AssistedInject constructor(
|
|||
toAddress = destination,
|
||||
expressProvider = provider,
|
||||
rateType = rateType,
|
||||
expressOperationType,
|
||||
).getOrElse { onExpressError(it); return }
|
||||
expressOperationType = expressOperationType,
|
||||
).getOrElse { error -> onExpressError(error); return }
|
||||
|
||||
createAndSendCexTransaction(
|
||||
fromAmount = fromAmount,
|
||||
|
|
@ -141,9 +141,9 @@ internal class SwapTransactionSender @AssistedInject constructor(
|
|||
destination = swapTransaction.txTo,
|
||||
userWalletId = userWallet.walletId,
|
||||
network = fromStatus.currency.network,
|
||||
).getOrElse {
|
||||
Timber.e(it, "Failed to create swap CEX tx data")
|
||||
onSendError(SendTransactionError.UnknownError(Exception(it)))
|
||||
).getOrElse { error ->
|
||||
Timber.e(error, "Failed to create swap CEX tx data")
|
||||
onSendError(SendTransactionError.UnknownError(Exception(error)))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ internal class SendWithSwapConfirmInitialStateTransformer(
|
|||
return ConfirmUM.Content(
|
||||
isPrimaryButtonEnabled = false,
|
||||
isTransactionInProcess = false,
|
||||
showTapHelp = isShowTapHelp,
|
||||
isShowTapHelp = isShowTapHelp,
|
||||
sendingFooter = TextReference.EMPTY,
|
||||
notifications = persistentListOf(),
|
||||
tosUM = null,
|
||||
|
|
|
|||
|
|
@ -109,16 +109,16 @@ internal class SendWithSwapConfirmationNotificationsTransformer : Transformer<Se
|
|||
val expressProvider = (swapAmountUM as? SwapAmountUM.Content)?.selectedQuote?.provider ?: return null
|
||||
|
||||
return ConfirmUM.Content.TosUM(
|
||||
tosLink = expressProvider.termsOfUse?.let {
|
||||
tosLink = expressProvider.termsOfUse?.let { termsOfUse ->
|
||||
ConfirmUM.Content.LegalUM(
|
||||
title = resourceReference(R.string.common_terms_of_use),
|
||||
link = it,
|
||||
link = termsOfUse,
|
||||
)
|
||||
},
|
||||
policyLink = expressProvider.privacyPolicy?.let {
|
||||
policyLink = expressProvider.privacyPolicy?.let { privacyPolicy ->
|
||||
ConfirmUM.Content.LegalUM(
|
||||
title = resourceReference(R.string.common_privacy_policy),
|
||||
link = it,
|
||||
link = privacyPolicy,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -132,8 +132,8 @@ internal class SendWithSwapModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun resetSendWithSwapNavigation(resetNavigation: Boolean) {
|
||||
uiState.update {
|
||||
it.copy(
|
||||
uiState.update { state ->
|
||||
state.copy(
|
||||
destinationUM = DestinationUM.Empty(),
|
||||
feeSelectorUM = FeeSelectorUM.Loading,
|
||||
confirmUM = ConfirmUM.Empty,
|
||||
|
|
@ -166,8 +166,8 @@ internal class SendWithSwapModel @Inject constructor(
|
|||
userWallet = wallet
|
||||
getPrimaryCurrencyStatusUpdates(params.currency)
|
||||
},
|
||||
ifLeft = {
|
||||
Timber.w(it.toString())
|
||||
ifLeft = { error ->
|
||||
Timber.w(error.toString())
|
||||
swapAlertFactory.getGenericErrorState(
|
||||
expressError = ExpressError.UnknownError,
|
||||
onFailedTxEmailClick = {
|
||||
|
|
@ -175,7 +175,7 @@ internal class SendWithSwapModel @Inject constructor(
|
|||
swapAlertFactory.onFailedTxEmailClick(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = params.currency,
|
||||
errorMessage = it.toString(),
|
||||
errorMessage = error.toString(),
|
||||
)
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -344,7 +344,7 @@ private fun SendWithSwapSuccessContent_Preview() {
|
|||
txUrl = "https://tangem.com",
|
||||
provider = ExpressProvider(
|
||||
providerId = "changelly",
|
||||
rateTypes = listOf(),
|
||||
rateTypes = emptyList(),
|
||||
name = "Changelly",
|
||||
type = ExpressProviderType.CEX,
|
||||
imageLarge = "https://s3.eu-central-1.amazonaws.com/tangem.api/express/changelly-1024.png",
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ internal fun SendWithSwapContent(
|
|||
stackState: ChildStack<SendWithSwapRoute, ComposableContentComponent>,
|
||||
onLinkClick: (String) -> Unit,
|
||||
) {
|
||||
val navigationUM = navigationUM as? NavigationUM.Content ?: return
|
||||
val navigationUMContent = navigationUM as? NavigationUM.Content ?: return
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
|
@ -47,9 +47,9 @@ internal fun SendWithSwapContent(
|
|||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
AppBarWithBackButton(
|
||||
text = navigationUM.title.resolveReference(),
|
||||
onBackClick = navigationUM.backIconClick,
|
||||
iconRes = navigationUM.additionalIconRes,
|
||||
text = navigationUMContent.title.resolveReference(),
|
||||
onBackClick = navigationUMContent.backIconClick,
|
||||
iconRes = navigationUMContent.additionalIconRes,
|
||||
modifier = Modifier.height(TangemTheme.dimens.size56),
|
||||
)
|
||||
Children(
|
||||
|
|
@ -93,7 +93,7 @@ internal fun SendWithSwapContent(
|
|||
)
|
||||
}
|
||||
NavigationPrimaryButton(
|
||||
navigationUM.primaryButton,
|
||||
navigationUMContent.primaryButton,
|
||||
modifier = Modifier.padding(
|
||||
start = 16.dp,
|
||||
end = 16.dp,
|
||||
|
|
|
|||
|
|
@ -22,12 +22,10 @@
|
|||
<ID>MultilineLambdaItParameter:TesterAccountsViewModel.kt$TesterAccountsViewModel${ it.copy( accountListBottomSheetConfig = it.accountListBottomSheetConfig.copy( isAccountsShown = false, ), ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:TesterAccountsViewModel.kt$TesterAccountsViewModel${ it.copy( walletSelector = it.walletSelector.copy(selected = userWallet), accountListBottomSheetConfig = it.accountListBottomSheetConfig.copy( accounts = getWalletAccounts(userWallet.walletId), ), ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:TesterActionsScreen.kt${ builder.setStream( FileProvider.getUriForFile(activity, "${activity.packageName}.provider", it), ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:TesterActivity.kt$TesterActivity${ val route = when (it) { ButtonUM.FEATURE_TOGGLES -> TesterScreen.FEATURE_TOGGLES ButtonUM.EXCLUDED_BLOCKCHAINS -> TesterScreen.EXCLUDED_BLOCKCHAINS ButtonUM.ENVIRONMENT_TOGGLES -> TesterScreen.ENVIRONMENTS_TOGGLES ButtonUM.BLOCKCHAIN_PROVIDERS -> TesterScreen.BLOCKCHAIN_PROVIDERS ButtonUM.TESTER_ACTIONS -> TesterScreen.TESTER_ACTIONS ButtonUM.TEST_PUSHES -> TesterScreen.TEST_PUSHES ButtonUM.ACCOUNTS -> TesterScreen.ACCOUNTS } innerTesterRouter.open(route) }</ID>
|
||||
<ID>NoNameShadowing:AccountsScreen.kt$content</ID>
|
||||
<ID>NoNameShadowing:BlockchainProvidersViewModel.kt$BlockchainProvidersViewModel${ onAddProviderClick(id = blockchain.id, url = it) }</ID>
|
||||
<ID>NoNameShadowing:BlockchainProvidersViewModel.kt$BlockchainProvidersViewModel${ onPublicProviderUrlChange(id = blockchain.id, url = it) }</ID>
|
||||
<ID>NoNameShadowing:EnvironmentsTogglesViewModel.kt$EnvironmentsTogglesViewModel${ it.environment == currentEnvironment }</ID>
|
||||
<ID>NoNameShadowing:TesterActivity.kt$TesterActivity${ val route = when (it) { ButtonUM.FEATURE_TOGGLES -> TesterScreen.FEATURE_TOGGLES ButtonUM.EXCLUDED_BLOCKCHAINS -> TesterScreen.EXCLUDED_BLOCKCHAINS ButtonUM.ENVIRONMENT_TOGGLES -> TesterScreen.ENVIRONMENTS_TOGGLES ButtonUM.BLOCKCHAIN_PROVIDERS -> TesterScreen.BLOCKCHAIN_PROVIDERS ButtonUM.TESTER_ACTIONS -> TesterScreen.TESTER_ACTIONS ButtonUM.TEST_PUSHES -> TesterScreen.TEST_PUSHES ButtonUM.ACCOUNTS -> TesterScreen.ACCOUNTS } innerTesterRouter.open(route) }</ID>
|
||||
<ID>PropertyUsedBeforeDeclaration:BlockchainProvidersViewModel.kt$BlockchainProvidersViewModel$_state</ID>
|
||||
<ID>PropertyUsedBeforeDeclaration:BlockchainProvidersViewModel.kt$BlockchainProvidersViewModel$searchQuery</ID>
|
||||
<ID>PropertyUsedBeforeDeclaration:EnvironmentsTogglesViewModel.kt$EnvironmentsTogglesViewModel$_uiState</ID>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
<ID>MultilineLambdaItParameter:TokenDetailsModel.kt$TokenDetailsModel${ internalUiState.value = stateFactory.getStateWithUpdatedHidden( isBalanceHidden = it.isBalanceHidden, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:TokenDetailsModel.kt$TokenDetailsModel${ sendButtonsEvents(it.states) internalUiState.value = stateFactory.getManageButtonsState(actions = it.states) }</ID>
|
||||
<ID>MultilineLambdaItParameter:TokenDetailsModel.kt$TokenDetailsModel${ val updatedState = stateFactory.getStateWithNotifications(it) notificationsAnalyticsSender.send(internalUiState.value, updatedState.notifications) internalUiState.value = updatedState }</ID>
|
||||
<ID>MultilineLambdaItParameter:TokenDetailsOnrampTransactionStateConverter.kt$TokenDetailsOnrampTransactionStateConverter${ analyticsEventHandler.send(TokenOnrampAnalyticsEvent.GoToProvider) clickIntents.onGoToProviderClick(it) }</ID>
|
||||
<ID>MultilineLambdaItParameter:TokenDetailsScreen.kt${ Notification( modifier = itemModifier.animateItem(), config = it.config, iconTint = when (it) { is TokenDetailsNotification.Informational -> TangemTheme.colors.icon.accent is TokenDetailsNotification.UsedOutdatedData -> TangemTheme.colors.text.attention else -> null }, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:TokenDetailsTopAppBar.kt${ TangemDropdownItem( item = it, dismissParent = { showDropdownMenu = false }, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:TokenStakingBlock.kt${ when (it) { is StakingBlockUM.TemporaryUnavailable -> StakingTemporaryUnavailableBlock() is StakingBlockUM.Loading -> StakingLoading() is StakingBlockUM.Staked -> StakingBalanceBlock( state = it, isBalanceHidden = isBalanceHidden, ) is StakingBlockUM.StakeAvailable -> StakingAvailableContent( state = it, ) } }</ID>
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@
|
|||
<ID>MultilineLambdaItParameter:SetRefreshStateTransformer.kt$SetRefreshStateTransformer${ it.mapNotNull { button -> when (button) { is WalletManageButton.Buy -> button.copy(enabled = isButtonsEnabled) is WalletManageButton.Send -> button.copy(enabled = isButtonsEnabled) is WalletManageButton.Sell -> button.copy(enabled = isButtonsEnabled) is WalletManageButton.Receive -> button is WalletManageButton.Stake -> null is WalletManageButton.Swap -> null } } }</ID>
|
||||
<ID>MultilineLambdaItParameter:SetVisaInfoTransformer.kt$SetVisaInfoTransformer${ if (it is RefreshTokenExpiredException) { return getRefreshTokenExpiredState(prevState) } return prevState.copy( buttons = createVisaButtonsDimmed(), walletCardState = getErrorWalletCardState(prevState.walletCardState), balancesAndLimitBlockState = BalancesAndLimitsBlockState.Error, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:SingleWalletExpressStatusesSubscriber.kt$SingleWalletExpressStatusesSubscriber${ Timber.e("Unable to get primary currency status: $it") return@onEach }</ID>
|
||||
<ID>MultilineLambdaItParameter:SingleWalletOnrampTransactionConverter.kt$SingleWalletOnrampTransactionConverter${ analyticsEventHandler.send(TokenOnrampAnalyticsEvent.GoToProvider) clickIntents.onGoToProviderClick(it) }</ID>
|
||||
<ID>MultilineLambdaItParameter:TokenListAnalyticsSender.kt$TokenListAnalyticsSender${ val status = it.value if (status is CryptoCurrencyStatus.Loaded) { sendTokenBalancesForSpecificBlockchains(it, status) } }</ID>
|
||||
<ID>MultilineLambdaItParameter:TokenListStateConverter.kt$TokenListStateConverter${ if (isExtend) { clickIntents.onAccountCollapseClick(it) } else { clickIntents.onAccountExpandClick(it) } }</ID>
|
||||
<ID>MultilineLambdaItParameter:TxHistorySubscriber.kt$TxHistorySubscriber${ SetTxHistoryCountErrorTransformer( userWallet = userWallet, error = it, pendingTransactions = status.value.pendingTransactions, clickIntents = clickIntents, ) }</ID>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue