Updated on 2026-08-14

This commit is contained in:
Tangem 2025-05-16 16:18:42 +05:00
commit 287fda11f9
7 changed files with 69 additions and 55 deletions

View file

@ -63,14 +63,19 @@ internal class DefaultOnrampTransactionRepository(
}.map(transactionConverter::convert)
}
override suspend fun updateTransactionStatus(txId: String, externalTxUrl: String, status: OnrampStatus.Status) =
withContext(dispatchers.io) {
val updatedTx = getTransactionById(txId)?.copy(
externalTxUrl = externalTxUrl,
status = status,
) ?: return@withContext
storeTransaction(updatedTx)
}
override suspend fun updateTransactionStatus(
txId: String,
externalTxId: String,
externalTxUrl: String,
status: OnrampStatus.Status,
) = withContext(dispatchers.io) {
val updatedTx = getTransactionById(txId)?.copy(
externalTxUrl = externalTxUrl,
externalTxId = externalTxId,
status = status,
) ?: return@withContext
storeTransaction(updatedTx)
}
override suspend fun removeTransaction(txId: String) {
withContext(dispatchers.io) {

View file

@ -10,9 +10,15 @@ class OnrampUpdateTransactionStatusUseCase(
private val errorResolver: OnrampErrorResolver,
) {
suspend operator fun invoke(txId: String, externalTxUrl: String, status: OnrampStatus.Status) = Either.catch {
suspend operator fun invoke(
txId: String,
externalTxId: String,
externalTxUrl: String,
status: OnrampStatus.Status,
) = Either.catch {
onrampTransactionRepository.updateTransactionStatus(
txId = txId,
externalTxId = externalTxId,
externalTxUrl = externalTxUrl,
status = status,
)

View file

@ -14,7 +14,12 @@ interface OnrampTransactionRepository {
fun getTransactions(userWalletId: UserWalletId, cryptoCurrencyId: CryptoCurrency.ID): Flow<List<OnrampTransaction>>
suspend fun updateTransactionStatus(txId: String, externalTxUrl: String, status: OnrampStatus.Status)
suspend fun updateTransactionStatus(
txId: String,
externalTxId: String,
externalTxUrl: String,
status: OnrampStatus.Status,
)
suspend fun removeTransaction(txId: String)
}

View file

@ -125,6 +125,7 @@ internal class OnrampStatusFactory @AssistedInject constructor(
onrampUpdateTransactionStatusUseCase(
txId = txId,
externalTxUrl = statusModel.externalTxUrl.orEmpty(),
externalTxId = statusModel.externalTxId.orEmpty(),
status = statusModel.status,
)
}

View file

@ -46,10 +46,8 @@ import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION
import com.tangem.features.pushnotifications.api.utils.getPushPermissionOrNull
import com.tangem.utils.Provider
import com.tangem.utils.coroutines.*
import kotlinx.coroutines.delay
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
import javax.inject.Inject
@ -92,7 +90,6 @@ internal class WalletModel @Inject constructor(
private val walletsUpdateJobHolder = JobHolder()
private val refreshWalletJobHolder = JobHolder()
private val expressStatusJobHolder = JobHolder()
private var needToRefreshWallet = false
private var expressTxStatusTaskScheduler = SingleTaskScheduler<Unit>()
@ -108,6 +105,7 @@ internal class WalletModel @Inject constructor(
subscribeToUserWalletsUpdates()
subscribeOnBalanceHiding()
subscribeOnSelectedWalletFlow()
subscribeToScreenBackgroundState()
subscribeOnPushNotificationsPermission()
clickIntents.initialize(innerWalletRouter, modelScope)
@ -226,7 +224,6 @@ internal class WalletModel @Inject constructor(
addReferralDeepLink(selectedWallet)
walletDeepLinksHandler.registerForWallet(scope = modelScope, userWallet = selectedWallet)
subscribeOnExpressTransactionsUpdates(selectedWallet)
subscribeToScreenBackgroundState(selectedWallet)
}
.flowOn(dispatchers.main)
.launchIn(modelScope)
@ -249,41 +246,38 @@ internal class WalletModel @Inject constructor(
// We need to update the current wallet quotes if the application was in the background for more than 10 seconds
// and then returned to the foreground
private fun subscribeToScreenBackgroundState(userWallet: UserWallet) {
private fun subscribeToScreenBackgroundState() {
screenLifecycleProvider.isBackgroundState
.onEach { isBackground ->
expressTxStatusTaskScheduler.cancelTask()
expressStatusJobHolder.cancel()
refreshWalletJobHolder.cancel()
when {
isBackground -> needToRefreshTimer()
needToRefreshWallet && !isBackground -> {
triggerRefreshWalletQuotes()
subscribeOnExpressTransactionsUpdates(userWallet)
}
!isBackground -> subscribeOnExpressTransactionsUpdates(userWallet)
}
}
.launchIn(modelScope)
.saveIn(expressStatusJobHolder)
}
private fun subscribeOnExpressTransactionsUpdates(userWallet: UserWallet) {
expressTxStatusTaskScheduler.cancelTask()
expressTxStatusTaskScheduler.scheduleTask(
modelScope,
PeriodicTask(
isDelayFirst = false,
delay = EXPRESS_STATUS_UPDATE_DELAY,
task = {
runCatching {
onrampStatusFactory.updateOnrmapTransactionStatuses(userWallet)
}
},
onSuccess = { /* no-op */ },
onError = { /* no-op */ },
),
)
if (!userWallet.isMultiCurrency) {
expressTxStatusTaskScheduler.cancelTask()
expressTxStatusTaskScheduler.scheduleTask(
modelScope,
PeriodicTask(
isDelayFirst = false,
delay = EXPRESS_STATUS_UPDATE_DELAY,
task = {
runCatching {
onrampStatusFactory.updateOnrmapTransactionStatuses(userWallet)
}
},
onSuccess = { /* no-op */ },
onError = { /* no-op */ },
),
)
}
}
private fun needToRefreshTimer() {
@ -298,9 +292,18 @@ internal class WalletModel @Inject constructor(
val state = stateHolder.uiState.value
val wallet = state.wallets.getOrNull(state.selectedWalletIndex) ?: return
modelScope.launch {
refreshMultiCurrencyWalletQuotesUseCase(wallet.walletCardState.id).getOrElse {
Timber.e("Failed to refreshMultiCurrencyWalletQuotesUseCase $it")
}
awaitAll(
async {
refreshMultiCurrencyWalletQuotesUseCase(wallet.walletCardState.id).getOrElse {
Timber.e("Failed to refreshMultiCurrencyWalletQuotesUseCase $it")
}
},
async {
getWalletsUseCase.invokeSync()
.firstOrNull { it.walletId == wallet.walletCardState.id }
?.let(::subscribeOnExpressTransactionsUpdates)
},
)
}.saveIn(refreshWalletJobHolder)
}

View file

@ -76,6 +76,7 @@ internal class OnrampStatusFactory @Inject constructor(
onrampUpdateTransactionStatusUseCase(
txId = txId,
externalTxUrl = statusModel.externalTxUrl.orEmpty(),
externalTxId = statusModel.externalTxId.orEmpty(),
status = statusModel.status,
)
}

View file

@ -157,7 +157,7 @@ internal class SingleWalletOnrampTransactionConverter(
return ExpressStatusUM(
title = resourceReference(R.string.common_transaction_status),
link = getStatusLink(status, externalTxUrl),
link = getStatusLink(externalTxUrl),
statuses = statuses,
)
}
@ -264,22 +264,15 @@ internal class SingleWalletOnrampTransactionConverter(
state = getStatusState(OnrampStatus.Status.Sending),
)
private fun getStatusLink(status: OnrampStatus.Status, externalTxUrl: String?): ExpressLinkUM {
private fun getStatusLink(externalTxUrl: String?): ExpressLinkUM {
if (externalTxUrl == null) return ExpressLinkUM.Empty
return when (status) {
OnrampStatus.Status.Verifying,
OnrampStatus.Status.Failed,
-> {
ExpressLinkUM.Content(
icon = R.drawable.ic_arrow_top_right_24,
text = resourceReference(R.string.common_go_to_provider),
onClick = {
clickIntents.onGoToProviderClick(externalTxUrl)
},
)
}
else -> ExpressLinkUM.Empty
}
return ExpressLinkUM.Content(
icon = R.drawable.ic_arrow_top_right_24,
text = resourceReference(R.string.common_go_to_provider),
onClick = {
clickIntents.onGoToProviderClick(externalTxUrl)
},
)
}
private fun OnrampStatus.Status.getStatusState(targetState: OnrampStatus.Status) = when {