Updated on 2026-08-14

This commit is contained in:
Tangem 2024-07-08 10:45:18 +01:00
commit 60d3745175
5 changed files with 52 additions and 10 deletions

View file

@ -26,6 +26,7 @@ data class SavedSwapTransactionListModelInner(
val transactions: List<SavedSwapTransactionModel>,
)
// TODO refactor to use separate models to store
data class SavedSwapTransactionModel(
val txId: String,
val timestamp: Long,

View file

@ -26,6 +26,9 @@ data class CryptoCurrencySwapInfo(
* @property providerId provider id
* @property rateTypes supported rate types
* @property isRecommended flag that indicates if this provider is recommended
*
* Uses to store transaction data in datastore, when extends - should always add default value
* to support backward compatibility
*/
data class SwapProvider(
val providerId: String,
@ -35,7 +38,7 @@ data class SwapProvider(
val imageLarge: String,
val termsOfUse: String?,
val privacyPolicy: String?,
val isRecommended: Boolean,
val isRecommended: Boolean = false,
)
enum class ExchangeProviderType(val providerName: String) {

View file

@ -896,8 +896,9 @@ internal class SwapInteractorImpl @Inject constructor(
txExternalUrl: String? = null,
txExternalId: String? = null,
) {
val selectedWallet = getSelectedWallet() ?: return
swapTransactionRepository.storeTransaction(
userWalletId = UserWalletId(userWalletManager.getWalletId()),
userWalletId = selectedWallet.walletId,
fromCryptoCurrency = currencyToSend.currency,
toCryptoCurrency = currencyToGet.currency,
transaction = SavedSwapTransactionModel(

View file

@ -6,6 +6,7 @@ import com.tangem.feature.swap.domain.models.ui.FeeType
import com.tangem.feature.swap.models.ApproveType
private const val SWAP_CATEGORY = "Swap"
private const val PROMO_CATEGORY = "Promo"
sealed class SwapEvents(
event: String,
@ -17,7 +18,7 @@ sealed class SwapEvents(
params = mapOf("Token" to token),
)
object SendTokenBalanceClicked : SwapEvents(event = "Send Token Balance Clicked")
data object SendTokenBalanceClicked : SwapEvents(event = "Send Token Balance Clicked")
data class ChooseTokenScreenOpened(val availableTokens: Boolean) : SwapEvents(
event = "Choose Token Screen Opened",
@ -37,7 +38,7 @@ sealed class SwapEvents(
params = mapOf("Send Token" to sendToken, "Receive Token" to receiveToken),
)
object ButtonGivePermissionClicked : SwapEvents(event = "Button - Give permission")
data object ButtonGivePermissionClicked : SwapEvents(event = "Button - Give permission")
data class ButtonPermissionApproveClicked(
val sendToken: String,
@ -52,9 +53,9 @@ sealed class SwapEvents(
),
)
object ButtonPermissionCancelClicked : SwapEvents(event = "Button - Permission Cancel")
data object ButtonPermissionCancelClicked : SwapEvents(event = "Button - Permission Cancel")
object ButtonSwipeClicked : SwapEvents(event = "Button - Swipe")
data object ButtonSwipeClicked : SwapEvents(event = "Button - Swipe")
data class SwapInProgressScreen(
val provider: SwapProvider,
@ -71,7 +72,7 @@ sealed class SwapEvents(
),
)
object ProviderClicked : SwapEvents("Provider Clicked")
data object ProviderClicked : SwapEvents("Provider Clicked")
data class ProviderChosen(val provider: SwapProvider) : SwapEvents(
event = "Provider Chosen",
@ -88,7 +89,7 @@ sealed class SwapEvents(
params = mapOf("Token" to token),
)
object NoticeNoAvailableTokensToSwap : SwapEvents("Notice - No Available Tokens To Swap")
data object NoticeNoAvailableTokensToSwap : SwapEvents("Notice - No Available Tokens To Swap")
data class NoticeNotEnoughFee(val token: String, val blockchain: String) : SwapEvents(
event = "Notice - Not Enough Fee",
@ -110,4 +111,20 @@ sealed class SwapEvents(
"Error code" to errorCode.toString(),
),
)
// region Promo activity
data class ChangellyActivity(
val promoState: PromoState,
) : AnalyticsEvent(
category = PROMO_CATEGORY,
event = "Changelly Activity",
params = mapOf(
"State" to promoState.name,
),
) {
sealed class PromoState(val name: String) {
data object Native : PromoState("Native")
data object Recommended : PromoState("Recommended")
}
}
}

View file

@ -430,8 +430,11 @@ internal class SwapViewModel @Inject constructor(
if (currentSelected != null && consideredProviders.keys.contains(currentSelected)) {
currentSelected
} else {
findBestQuoteProvider(consideredProviders.getLastLoadedSuccessStates())
?: consideredProviders.keys.first()
val successLoadedData = consideredProviders.getLastLoadedSuccessStates()
val recommendedProvider = successLoadedData.keys.firstOrNull { it.isRecommended }
val bestQuotesProvider = findBestQuoteProvider(successLoadedData)
triggerPromoProviderEvent(recommendedProvider, bestQuotesProvider)
recommendedProvider ?: bestQuotesProvider ?: consideredProviders.keys.first()
}
} else {
state.keys.first()
@ -1169,11 +1172,28 @@ internal class SwapViewModel @Inject constructor(
)
}
private fun triggerPromoProviderEvent(recommendedProvider: SwapProvider?, bestQuotesProvider: SwapProvider?) {
// for now send event only for changelly
if (recommendedProvider == null ||
recommendedProvider.providerId != CHANGELLY_PROVIDER_ID ||
bestQuotesProvider == null
) {
return
}
val event = if (recommendedProvider.providerId == bestQuotesProvider.providerId) {
SwapEvents.ChangellyActivity(SwapEvents.ChangellyActivity.PromoState.Native)
} else {
SwapEvents.ChangellyActivity(SwapEvents.ChangellyActivity.PromoState.Recommended)
}
analyticsEventHandler.send(event = event)
}
private companion object {
const val loggingTag = "SwapViewModel"
const val INITIAL_AMOUNT = ""
const val UPDATE_DELAY = 10000L
const val DEBOUNCE_AMOUNT_DELAY = 1000L
const val UPDATE_BALANCE_DELAY_MILLIS = 11000L
const val CHANGELLY_PROVIDER_ID = "changelly"
}
}