diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml
index 8805ebe16d..13ae7d8b04 100644
--- a/core/res/src/main/res/values-ru/strings.xml
+++ b/core/res/src/main/res/values-ru/strings.xml
@@ -198,9 +198,9 @@
Провайдеры проводят транзакции, обеспечивая плавный и эффективный обмен токенами
Выберите провайдера
Чтобы узнать причину, посетите сайт провайдера
- Операция не выполнена провайдером
+ Чтобы вернуть ваши деньги, посетите сайт провайдера
Посетите сайт провайдера для проверки
- Провайдер: требуется верификация
+ Провайдер запрашивает прохождение верификации
Список токенов в вашем кошельке
Получение наилучших курсов...
Провайдер
diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index 62304b3e12..44af8e6ed5 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -198,18 +198,22 @@
Choose provider
Estimated amount
Exchange by %s
- Visit provider’s website to see why
+ Visit provider’s website to refund your money
Operation failed by provider
Visit provider’s website for verification
KYC verification required by provider
Confirmed
Confirming
+ Confirming…
Exchanged
Exchanging
+ Exchanging…
Failed
Deposit received
Awaiting deposit
+ Awaiting deposit…
Sending to you
+ Sending to you…
Sent
Provider-sourced data. Estimated amount subject to change.
Exchange status
diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/models/analytics/TokenExchangeAnalyticsEvent.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/models/analytics/TokenExchangeAnalyticsEvent.kt
new file mode 100644
index 0000000000..a795ccd2af
--- /dev/null
+++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/models/analytics/TokenExchangeAnalyticsEvent.kt
@@ -0,0 +1,44 @@
+package com.tangem.domain.tokens.models.analytics
+
+import com.tangem.core.analytics.models.AnalyticsEvent
+
+class TokenExchangeAnalyticsEvent(
+ event: String,
+ params: Map = mapOf(),
+) : AnalyticsEvent("Token", event, params, null) {
+
+ class CexTx(token: String) : TokenScreenAnalyticsEvent(
+ event = "Notice - ChangeNow Swap",
+ params = mapOf("Token" to token),
+ )
+
+ class CexTxOpened(token: String, status: String) : TokenScreenAnalyticsEvent(
+ event = "ChangeNow Swap Opened",
+ params = mapOf("Token" to token, "Status" to status),
+ )
+
+ class Verification(token: String) : TokenScreenAnalyticsEvent(
+ event = "Notice - KYC required",
+ params = mapOf("Token" to token),
+ )
+
+ class Fail(token: String) : TokenScreenAnalyticsEvent(
+ event = "Notice - Operation Fail",
+ params = mapOf("Token" to token),
+ )
+
+ class GoToProviderStatus(token: String) : TokenScreenAnalyticsEvent(
+ event = "Button - Go To Provider",
+ params = mapOf("Token" to token, "Place" to "Status"),
+ )
+
+ class GoToProviderKYC(token: String) : TokenScreenAnalyticsEvent(
+ event = "Button - Go To Provider",
+ params = mapOf("Token" to token, "Place" to "KYC"),
+ )
+
+ class GoToProviderFail(token: String) : TokenScreenAnalyticsEvent(
+ event = "Button - Go To Provider",
+ params = mapOf("Token" to token, "Place" to "Fail"),
+ )
+}
\ No newline at end of file
diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt
index 63c8aecb72..d60d26a19e 100644
--- a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt
+++ b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt
@@ -97,11 +97,11 @@ class DefaultSwapTransactionRepository(
)
}
?.transactions
- ?.dropWhile { it.txId == txId }
+ ?.filterNot { it.txId == txId }
val editedList =
if (tokenTransactions.isNullOrEmpty()) {
- savedList?.dropWhile {
+ savedList?.filterNot {
it.checkId(
checkUserWalletId = userWalletId,
fromCurrencyId = fromCryptoCurrencyId,
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt
index 368164ce46..44e7b1f2c4 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt
@@ -22,6 +22,7 @@ import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.domain.txhistory.models.TxHistoryListError
import com.tangem.domain.txhistory.models.TxHistoryStateError
+import com.tangem.feature.tokendetails.presentation.tokendetails.state.SwapTransactionsState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsDialogConfig
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadedTxHistoryConverter
@@ -243,14 +244,13 @@ internal class TokenDetailsStateFactory(
return state.copy(notifications = notificationConverter.removeRentInfo(state))
}
- fun getStateWithExchangeStatusBottomSheet(txId: String): TokenDetailsState {
- val state = currentStateProvider()
- return state.copy(
+ fun getStateWithExchangeStatusBottomSheet(swapTxState: SwapTransactionsState): TokenDetailsState {
+ return currentStateProvider().copy(
bottomSheetConfig = TangemBottomSheetConfig(
isShow = true,
onDismissRequest = clickIntents::onDismissBottomSheet,
content = ExchangeStatusBottomSheetConfig(
- value = state.swapTxs.first { it.txId == txId },
+ value = swapTxState,
),
),
)
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt
index c0be53eb94..39d60d2436 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt
@@ -1,14 +1,16 @@
package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory
import com.tangem.common.Provider
+import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.ui.components.currency.tokenicon.converter.CryptoCurrencyToIconStateConverter
import com.tangem.core.ui.extensions.TextReference
-import com.tangem.core.ui.extensions.combinedReference
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.core.ui.utils.toDateFormat
import com.tangem.core.ui.utils.toTimeFormat
import com.tangem.domain.appcurrency.model.AppCurrency
+import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
+import com.tangem.domain.tokens.models.analytics.TokenExchangeAnalyticsEvent
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionListModel
import com.tangem.feature.tokendetails.presentation.tokendetails.state.ExchangeStatusState
@@ -26,6 +28,8 @@ import java.math.BigDecimal
internal class TokenDetailsSwapTransactionsStateConverter(
private val clickIntents: TokenDetailsClickIntents,
+ private val cryptoCurrency: CryptoCurrency,
+ private val analyticsEventsHandlerProvider: Provider,
appCurrencyProvider: Provider,
) : Converter> {
@@ -89,8 +93,13 @@ internal class TokenDetailsSwapTransactionsStateConverter(
fromCryptoSymbol = fromCurrency.currency.symbol,
fromFiatAmount = getFiatAmount(fromFiatAmount),
fromCurrencyIcon = iconStateConverter.convert(fromCurrency),
- onClick = { clickIntents.onSwapTransactionClick(transaction.txId) },
- onGoToProviderClick = { clickIntents.onGoToProviderClick(transaction.status?.txUrl.orEmpty()) },
+ onClick = { clickIntents.onSwapTransactionClick(transaction.txId, transaction.status?.status) },
+ onGoToProviderClick = {
+ analyticsEventsHandlerProvider().send(
+ TokenExchangeAnalyticsEvent.GoToProviderStatus(cryptoCurrency.symbol),
+ )
+ clickIntents.onGoToProviderClick(url = transaction.status?.txUrl.orEmpty())
+ },
),
)
}
@@ -116,11 +125,27 @@ internal class TokenDetailsSwapTransactionsStateConverter(
private fun getNotification(status: ExchangeStatus?, txUrl: String?): ExchangeStatusNotifications? {
if (txUrl == null) return null
return when (status) {
- ExchangeStatus.Failed -> ExchangeStatusNotifications.Failed {
- clickIntents.onGoToProviderClick(txUrl)
+ ExchangeStatus.Failed -> {
+ analyticsEventsHandlerProvider().send(
+ TokenExchangeAnalyticsEvent.Fail(cryptoCurrency.symbol),
+ )
+ ExchangeStatusNotifications.Failed {
+ analyticsEventsHandlerProvider().send(
+ TokenExchangeAnalyticsEvent.GoToProviderFail(cryptoCurrency.symbol),
+ )
+ clickIntents.onGoToProviderClick(txUrl)
+ }
}
- ExchangeStatus.Verifying -> ExchangeStatusNotifications.NeedVerification {
- clickIntents.onGoToProviderClick(txUrl)
+ ExchangeStatus.Verifying -> {
+ analyticsEventsHandlerProvider().send(
+ TokenExchangeAnalyticsEvent.Verification(cryptoCurrency.symbol),
+ )
+ ExchangeStatusNotifications.NeedVerification {
+ analyticsEventsHandlerProvider().send(
+ TokenExchangeAnalyticsEvent.GoToProviderKYC(cryptoCurrency.symbol),
+ )
+ clickIntents.onGoToProviderClick(txUrl)
+ }
}
else -> null
}
@@ -150,10 +175,7 @@ internal class TokenDetailsSwapTransactionsStateConverter(
private fun waitStep(isNew: Boolean, isNewDone: Boolean) = ExchangeStatusState(
status = ExchangeStatus.New,
text = when {
- isNew -> combinedReference(
- TextReference.Res(R.string.express_exchange_status_receiving),
- TextReference.Str(STATUS_ACTIVE_DOTS),
- )
+ isNew -> TextReference.Res(R.string.express_exchange_status_receiving_active)
else -> TextReference.Res(R.string.express_exchange_status_receiving)
},
isActive = isNew,
@@ -163,10 +185,7 @@ internal class TokenDetailsSwapTransactionsStateConverter(
private fun confirmStep(isConfirming: Boolean, isConfirmingDone: Boolean) = ExchangeStatusState(
status = ExchangeStatus.Confirming,
text = when {
- isConfirming -> combinedReference(
- TextReference.Res(R.string.express_exchange_status_confirming),
- TextReference.Str(STATUS_ACTIVE_DOTS),
- )
+ isConfirming -> TextReference.Res(R.string.express_exchange_status_confirming_active)
isConfirmingDone -> TextReference.Res(R.string.express_exchange_status_confirmed)
else -> TextReference.Res(R.string.express_exchange_status_confirming)
},
@@ -195,10 +214,7 @@ internal class TokenDetailsSwapTransactionsStateConverter(
else -> ExchangeStatusState(
status = ExchangeStatus.Exchanging,
text = when {
- isExchanging -> combinedReference(
- TextReference.Res(R.string.express_exchange_status_exchanging),
- TextReference.Str(STATUS_ACTIVE_DOTS),
- )
+ isExchanging -> TextReference.Res(R.string.express_exchange_status_exchanging_active)
isExchangingDone -> TextReference.Res(R.string.express_exchange_status_exchanged)
else -> TextReference.Res(R.string.express_exchange_status_exchanging)
},
@@ -210,18 +226,11 @@ internal class TokenDetailsSwapTransactionsStateConverter(
private fun sendStep(isSending: Boolean, isSendingDone: Boolean) = ExchangeStatusState(
status = ExchangeStatus.Sending,
text = when {
- isSending -> combinedReference(
- TextReference.Res(R.string.express_exchange_status_sending),
- TextReference.Str(STATUS_ACTIVE_DOTS),
- )
+ isSending -> TextReference.Res(R.string.express_exchange_status_sending_active)
isSendingDone -> TextReference.Res(R.string.express_exchange_status_sent)
else -> TextReference.Res(R.string.express_exchange_status_sending)
},
isActive = isSending,
isDone = isSendingDone,
)
-
- private companion object {
- private const val STATUS_ACTIVE_DOTS = "…"
- }
}
\ No newline at end of file
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/ExchangeStatusFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/ExchangeStatusFactory.kt
index d92306d03c..b1441a921a 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/ExchangeStatusFactory.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/ExchangeStatusFactory.kt
@@ -2,6 +2,7 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels
import arrow.core.getOrElse
import com.tangem.common.Provider
+import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.GetCryptoCurrencyStatusesSyncUseCase
import com.tangem.domain.tokens.model.CryptoCurrency
@@ -35,19 +36,22 @@ internal class ExchangeStatusFactory(
private val dispatchers: CoroutineDispatcherProvider,
private val clickIntents: TokenDetailsClickIntents,
private val appCurrencyProvider: Provider,
+ private val analyticsEventsHandlerProvider: Provider,
private val userWalletId: UserWalletId,
- private val cryptoCurrencyId: CryptoCurrency.ID,
+ private val cryptoCurrency: CryptoCurrency,
) {
private val swapTransactionsStateConverter by lazy {
TokenDetailsSwapTransactionsStateConverter(
clickIntents = clickIntents,
+ cryptoCurrency = cryptoCurrency,
appCurrencyProvider = appCurrencyProvider,
+ analyticsEventsHandlerProvider = analyticsEventsHandlerProvider,
)
}
operator fun invoke() = combine(
- flow = swapTransactionRepository.getTransactions(userWalletId, cryptoCurrencyId),
+ flow = swapTransactionRepository.getTransactions(userWalletId, cryptoCurrency.id),
flow2 = getWalletCryptoCurrencies().conflate(),
) { savedTransactions, cryptoCurrenciesStatusList ->
innerLoadSwapState(
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsClickIntents.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsClickIntents.kt
index 95093f7fdb..64a0d6dd2e 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsClickIntents.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsClickIntents.kt
@@ -2,6 +2,7 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels
import com.tangem.core.ui.components.bottomsheets.tokenreceive.AddressModel
import com.tangem.domain.tokens.model.CryptoCurrency
+import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
interface TokenDetailsClickIntents {
@@ -39,7 +40,7 @@ interface TokenDetailsClickIntents {
fun onCloseRentInfoNotification()
- fun onSwapTransactionClick(txId: String)
+ fun onSwapTransactionClick(txId: String, status: ExchangeStatus?)
fun onGoToProviderClick(url: String)
}
\ No newline at end of file
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt
index 126298c471..a730e6edd2 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt
@@ -23,6 +23,7 @@ import com.tangem.domain.tokens.*
import com.tangem.domain.tokens.legacy.TradeCryptoAction
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
+import com.tangem.domain.tokens.models.analytics.TokenExchangeAnalyticsEvent
import com.tangem.domain.tokens.models.analytics.TokenReceiveAnalyticsEvent
import com.tangem.domain.tokens.models.analytics.TokenScreenAnalyticsEvent
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
@@ -35,9 +36,11 @@ import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.feature.swap.domain.SwapRepository
import com.tangem.feature.swap.domain.SwapTransactionRepository
+import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
import com.tangem.feature.tokendetails.presentation.router.InnerTokenDetailsRouter
import com.tangem.feature.tokendetails.presentation.tokendetails.state.SwapTransactionsState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
+import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotifications
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsStateFactory
import com.tangem.features.tokendetails.impl.R
import com.tangem.features.tokendetails.navigation.TokenDetailsRouter
@@ -117,8 +120,9 @@ internal class TokenDetailsViewModel @Inject constructor(
dispatchers = dispatchers,
clickIntents = this,
appCurrencyProvider = Provider { selectedAppCurrencyFlow.value },
+ analyticsEventsHandlerProvider = Provider { analyticsEventsHandler },
userWalletId = userWalletId,
- cryptoCurrencyId = cryptoCurrency.id,
+ cryptoCurrency = cryptoCurrency,
)
}
@@ -212,6 +216,9 @@ internal class TokenDetailsViewModel @Inject constructor(
swapTxStatusTaskScheduler.cancelTask()
exchangeStatusFactory.invoke()
.onEach { swapTxs ->
+ if (swapTxs.isNotEmpty()) {
+ analyticsEventsHandler.send(TokenExchangeAnalyticsEvent.CexTx(cryptoCurrency.symbol))
+ }
swapTxStatusTaskScheduler.scheduleTask(
viewModelScope,
PeriodicTask(
@@ -533,8 +540,21 @@ internal class TokenDetailsViewModel @Inject constructor(
uiState = stateFactory.getStateWithRemovedRentNotification()
}
- override fun onSwapTransactionClick(txId: String) {
- uiState = stateFactory.getStateWithExchangeStatusBottomSheet(txId)
+ override fun onSwapTransactionClick(txId: String, status: ExchangeStatus?) {
+ val swapTxState = uiState.swapTxs.first { it.txId == txId }
+ analyticsEventsHandler.send(
+ TokenExchangeAnalyticsEvent.CexTxOpened(cryptoCurrency.symbol, status?.name.orEmpty()),
+ )
+ when (swapTxState.notification.value) {
+ is ExchangeStatusNotifications.NeedVerification -> {
+ analyticsEventsHandler.send(TokenExchangeAnalyticsEvent.Verification(cryptoCurrency.symbol))
+ }
+ is ExchangeStatusNotifications.Failed -> {
+ analyticsEventsHandler.send(TokenExchangeAnalyticsEvent.Fail(cryptoCurrency.symbol))
+ }
+ else -> Unit
+ }
+ uiState = stateFactory.getStateWithExchangeStatusBottomSheet(swapTxState)
}
override fun onGoToProviderClick(url: String) {