Updated on 2026-08-14
This commit is contained in:
commit
94af682f08
27 changed files with 583 additions and 593 deletions
|
|
@ -54,9 +54,14 @@ internal object OnrampDomainModule {
|
|||
@Singleton
|
||||
fun provideGetOnrampStatusUseCase(
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampTransactionRepository: OnrampTransactionRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): GetOnrampStatusUseCase {
|
||||
return GetOnrampStatusUseCase(onrampRepository, onrampErrorResolver)
|
||||
return GetOnrampStatusUseCase(
|
||||
onrampRepository,
|
||||
onrampTransactionRepository,
|
||||
onrampErrorResolver,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
package com.tangem.common.ui.expressStatus
|
||||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.common.ui.notifications.ExpressNotificationsUM
|
||||
|
|
@ -12,21 +13,20 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
|
||||
@Composable
|
||||
fun ExpressStatusNotificationBlock(state: NotificationUM?) {
|
||||
AnimatedContent(
|
||||
targetState = state,
|
||||
AnimatedVisibility(
|
||||
visible = state?.config != null,
|
||||
modifier = Modifier.padding(top = 12.dp),
|
||||
label = "Express Status Notification Change",
|
||||
) { notification ->
|
||||
if (notification?.config != null) {
|
||||
Notification(
|
||||
config = notification.config,
|
||||
iconTint = when (state) {
|
||||
is ExpressNotificationsUM.NeedVerification -> TangemTheme.colors.icon.attention
|
||||
is ExpressNotificationsUM.FailedByProvider -> TangemTheme.colors.icon.warning
|
||||
else -> null
|
||||
},
|
||||
containerColor = TangemTheme.colors.background.action,
|
||||
)
|
||||
}
|
||||
) {
|
||||
val wrappedNotification = remember(this) { requireNotNull(state?.config) }
|
||||
Notification(
|
||||
config = wrappedNotification,
|
||||
iconTint = when (state) {
|
||||
is ExpressNotificationsUM.NeedVerification -> TangemTheme.colors.icon.attention
|
||||
is ExpressNotificationsUM.FailedByProvider -> TangemTheme.colors.icon.warning
|
||||
else -> null
|
||||
},
|
||||
containerColor = TangemTheme.colors.background.action,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import com.tangem.datasource.local.preferences.AppPreferencesStore
|
|||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
import com.tangem.datasource.local.preferences.utils.getObjectSet
|
||||
import com.tangem.datasource.local.preferences.utils.getObjectSetSync
|
||||
import com.tangem.domain.onramp.model.OnrampStatus
|
||||
import com.tangem.domain.onramp.model.cache.OnrampTransaction
|
||||
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
|
@ -62,6 +63,12 @@ internal class DefaultOnrampTransactionRepository(
|
|||
}.map(transactionConverter::convert)
|
||||
}
|
||||
|
||||
override suspend fun updateTransactionStatus(txId: String, status: OnrampStatus.Status) =
|
||||
withContext(dispatchers.io) {
|
||||
val updatedTx = getTransactionById(txId)?.copy(status = status) ?: return@withContext
|
||||
storeTransaction(updatedTx)
|
||||
}
|
||||
|
||||
override suspend fun removeTransaction(txId: String) {
|
||||
withContext(dispatchers.io) {
|
||||
appPreferencesStore.editData { mutablePreferences ->
|
||||
|
|
|
|||
|
|
@ -5,15 +5,19 @@ import com.tangem.domain.onramp.model.OnrampError
|
|||
import com.tangem.domain.onramp.model.OnrampStatus
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
|
||||
|
||||
class GetOnrampStatusUseCase(
|
||||
private val onrampRepository: OnrampRepository,
|
||||
private val onrampTransactionRepository: OnrampTransactionRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(txId: String): Either<OnrampError, OnrampStatus> {
|
||||
return Either.catch {
|
||||
onrampRepository.getStatus(txId)
|
||||
val status = onrampRepository.getStatus(txId)
|
||||
onrampTransactionRepository.updateTransactionStatus(txId = txId, status = status.status)
|
||||
status
|
||||
}.mapLeft {
|
||||
errorResolver.resolve(it)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,17 @@
|
|||
package com.tangem.domain.onramp
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.domain.onramp.model.OnrampError
|
||||
import com.tangem.domain.onramp.model.cache.OnrampTransaction
|
||||
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEmpty
|
||||
|
||||
class GetOnrampTransactionsUseCase(
|
||||
private val onrampTransactionRepository: OnrampTransactionRepository,
|
||||
|
|
@ -15,14 +20,12 @@ class GetOnrampTransactionsUseCase(
|
|||
operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencyId: CryptoCurrency.ID,
|
||||
): Either<OnrampError, Flow<List<OnrampTransaction>>> {
|
||||
return Either.catch {
|
||||
onrampTransactionRepository.getTransactions(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrencyId = cryptoCurrencyId,
|
||||
)
|
||||
}.mapLeft {
|
||||
OnrampError.UnknownError
|
||||
}
|
||||
): Flow<Either<OnrampError, List<OnrampTransaction>>> {
|
||||
return onrampTransactionRepository.getTransactions(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrencyId = cryptoCurrencyId,
|
||||
).map { it.right() }
|
||||
.catch { OnrampError.UnknownError.left() }
|
||||
.onEmpty { OnrampError.UnknownError.left() }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.domain.onramp.repositories
|
||||
|
||||
import com.tangem.domain.onramp.model.OnrampStatus
|
||||
import com.tangem.domain.onramp.model.cache.OnrampTransaction
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
@ -13,5 +14,7 @@ interface OnrampTransactionRepository {
|
|||
|
||||
fun getTransactions(userWalletId: UserWalletId, cryptoCurrencyId: CryptoCurrency.ID): Flow<List<OnrampTransaction>>
|
||||
|
||||
suspend fun updateTransactionStatus(txId: String, status: OnrampStatus.Status)
|
||||
|
||||
suspend fun removeTransaction(txId: String)
|
||||
}
|
||||
|
|
@ -307,8 +307,7 @@ internal object TokenDetailsPreviewData {
|
|||
),
|
||||
dialogConfig = null,
|
||||
pendingTxs = persistentListOf(),
|
||||
swapTxs = persistentListOf(),
|
||||
onrampTxs = persistentListOf(),
|
||||
expressTxs = persistentListOf(),
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
bottomSheetConfig = null,
|
||||
isBalanceHidden = false,
|
||||
|
|
@ -338,8 +337,7 @@ internal object TokenDetailsPreviewData {
|
|||
),
|
||||
dialogConfig = null,
|
||||
pendingTxs = persistentListOf(),
|
||||
swapTxs = persistentListOf(),
|
||||
onrampTxs = persistentListOf(),
|
||||
expressTxs = persistentListOf(),
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
bottomSheetConfig = null,
|
||||
isBalanceHidden = false,
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
|
||||
import com.tangem.feature.swap.domain.models.domain.SwapProvider
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotifications
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
internal data class SwapTransactionsState(
|
||||
val txId: String,
|
||||
val provider: SwapProvider,
|
||||
val txUrl: String? = null,
|
||||
val txExternalId: String? = null,
|
||||
val timestamp: TextReference,
|
||||
val fiatSymbol: String,
|
||||
val activeStatus: ExchangeStatus?,
|
||||
val hasFailed: Boolean,
|
||||
val statuses: ImmutableList<ExchangeStatusState>,
|
||||
val notification: ExchangeStatusNotifications? = null,
|
||||
val toCryptoCurrency: CryptoCurrency,
|
||||
val toCryptoAmount: String,
|
||||
val toFiatAmount: String,
|
||||
val toCurrencyIcon: CurrencyIconState,
|
||||
val fromCryptoCurrency: CryptoCurrency,
|
||||
val fromCryptoAmount: TextReference,
|
||||
val fromFiatAmount: String,
|
||||
val fromCurrencyIcon: CurrencyIconState,
|
||||
val showProviderLink: Boolean,
|
||||
val isRefundTerminalStatus: Boolean = true,
|
||||
val onClick: () -> Unit,
|
||||
val onGoToProviderClick: (String) -> Unit,
|
||||
)
|
||||
|
||||
@Immutable
|
||||
internal data class ExchangeStatusState(
|
||||
val status: ExchangeStatus,
|
||||
val text: TextReference,
|
||||
val isActive: Boolean,
|
||||
val isDone: Boolean,
|
||||
)
|
||||
|
|
@ -21,8 +21,7 @@ internal data class TokenDetailsState(
|
|||
val stakingBlocksState: StakingBlockUM?,
|
||||
val notifications: ImmutableList<TokenDetailsNotification>,
|
||||
val pendingTxs: PersistentList<TransactionState>,
|
||||
val swapTxs: PersistentList<SwapTransactionsState>,
|
||||
val onrampTxs: PersistentList<ExpressTransactionStateUM.OnrampUM>,
|
||||
val expressTxs: PersistentList<ExpressTransactionStateUM>,
|
||||
val txHistoryState: TxHistoryState,
|
||||
val dialogConfig: TokenDetailsDialogConfig?,
|
||||
val pullToRefreshConfig: PullToRefreshConfig,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.state.express
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
|
||||
import javax.annotation.concurrent.Immutable
|
||||
|
||||
@Deprecated("Use ExpressStatusBlock from common")
|
||||
@Immutable
|
||||
internal data class ExchangeStatusState(
|
||||
val status: ExchangeStatus,
|
||||
val text: TextReference,
|
||||
val isActive: Boolean,
|
||||
val isDone: Boolean,
|
||||
)
|
||||
|
|
@ -5,9 +5,9 @@ import com.tangem.common.ui.notifications.NotificationUM
|
|||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.onramp.model.OnrampStatus
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
|
||||
import com.tangem.feature.swap.domain.models.domain.SwapProvider
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.ExchangeStatusState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotifications
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
|
|
@ -23,6 +23,8 @@ internal sealed class ExpressTransactionStateUM {
|
|||
val notification: ExchangeStatusNotifications? = null,
|
||||
val showProviderLink: Boolean,
|
||||
val isRefundTerminalStatus: Boolean,
|
||||
val fromCryptoCurrency: CryptoCurrency,
|
||||
val toCryptoCurrency: CryptoCurrency,
|
||||
) : ExpressTransactionStateUM()
|
||||
|
||||
data class OnrampUM(
|
||||
|
|
@ -30,20 +32,22 @@ internal sealed class ExpressTransactionStateUM {
|
|||
val providerName: String, // todo onramp fix after SwapProvider moved to own module
|
||||
val providerImageUrl: String, // todo onramp fix after SwapProvider moved to own module
|
||||
val providerType: String, // todo onramp fix after SwapProvider moved to own module
|
||||
val cryptoCurrencyName: String,
|
||||
val activeStatus: OnrampStatus.Status,
|
||||
) : ExpressTransactionStateUM()
|
||||
}
|
||||
|
||||
internal data class ExpressTransactionStateInfoUM(
|
||||
val title: TextReference,
|
||||
val status: ExpressStatusUM,
|
||||
val notification: NotificationUM?,
|
||||
val txId: String,
|
||||
val txUrl: String?,
|
||||
val txExternalId: String?,
|
||||
val timestamp: TextReference,
|
||||
val txExternalUrl: String?,
|
||||
val timestamp: Long,
|
||||
val timestampFormatted: TextReference,
|
||||
val onGoToProviderClick: (String) -> Unit,
|
||||
val onClick: () -> Unit,
|
||||
val iconState: ExpressTransactionStateIconUM,
|
||||
|
||||
val toAmount: TextReference,
|
||||
val toFiatAmount: TextReference?,
|
||||
|
|
@ -54,4 +58,10 @@ internal data class ExpressTransactionStateInfoUM(
|
|||
val fromFiatAmount: TextReference?,
|
||||
val fromAmountSymbol: String,
|
||||
val fromCurrencyIcon: CurrencyIconState,
|
||||
)
|
||||
)
|
||||
|
||||
internal enum class ExpressTransactionStateIconUM {
|
||||
Warning,
|
||||
Error,
|
||||
None,
|
||||
}
|
||||
|
|
@ -14,13 +14,14 @@ import com.tangem.core.ui.extensions.wrappedList
|
|||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.utils.DateTimeFormatters
|
||||
import com.tangem.core.ui.utils.toDateFormatWithTodayYesterday
|
||||
import com.tangem.core.ui.utils.toTimeFormat
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.onramp.model.OnrampStatus
|
||||
import com.tangem.domain.onramp.model.cache.OnrampTransaction
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExpressTransactionStateIconUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExpressTransactionStateInfoUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExpressTransactionStateUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents
|
||||
|
|
@ -43,15 +44,17 @@ internal class TokenDetailsOnrampTransactionStateConverter(
|
|||
val appCurrency = appCurrencyProvider()
|
||||
return ExpressTransactionStateUM.OnrampUM(
|
||||
info = ExpressTransactionStateInfoUM(
|
||||
title = resourceReference(id = R.string.express_status_buying, wrappedList(cryptoCurrency.name)),
|
||||
status = convertStatuses(value.status, value.externalTxUrl),
|
||||
notification = getNotification(value.status, value.externalTxUrl),
|
||||
txId = value.txId,
|
||||
txExternalId = value.externalTxId,
|
||||
txUrl = value.externalTxUrl,
|
||||
timestamp = resourceReference(
|
||||
txExternalUrl = value.externalTxUrl,
|
||||
timestamp = value.timestamp,
|
||||
timestampFormatted = resourceReference(
|
||||
R.string.send_date_format,
|
||||
wrappedList(
|
||||
value.timestamp.toTimeFormat(DateTimeFormatters.dateFormatter),
|
||||
value.timestamp.toDateFormatWithTodayYesterday(),
|
||||
value.timestamp.toTimeFormat(),
|
||||
),
|
||||
),
|
||||
|
|
@ -82,13 +85,13 @@ internal class TokenDetailsOnrampTransactionStateConverter(
|
|||
url = value.fromCurrency.image,
|
||||
fallbackResId = R.drawable.ic_currency_24,
|
||||
),
|
||||
iconState = getIconState(value.status),
|
||||
onGoToProviderClick = clickIntents::onGoToProviderClick,
|
||||
onClick = { clickIntents.onOnrampTransactionClick(value.txId) },
|
||||
onClick = { clickIntents.onExpressTransactionClick(value.txId) },
|
||||
),
|
||||
providerName = value.providerName,
|
||||
providerImageUrl = value.providerImageUrl,
|
||||
providerType = value.providerType,
|
||||
cryptoCurrencyName = cryptoCurrency.name,
|
||||
activeStatus = value.status,
|
||||
)
|
||||
}
|
||||
|
|
@ -110,6 +113,14 @@ internal class TokenDetailsOnrampTransactionStateConverter(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getIconState(status: OnrampStatus.Status): ExpressTransactionStateIconUM {
|
||||
return when (status) {
|
||||
OnrampStatus.Status.Verifying -> ExpressTransactionStateIconUM.Warning
|
||||
OnrampStatus.Status.Failed -> ExpressTransactionStateIconUM.Error
|
||||
else -> ExpressTransactionStateIconUM.None
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertStatuses(status: OnrampStatus.Status, externalTxUrl: String?): ExpressStatusUM {
|
||||
val statuses = with(status) {
|
||||
persistentListOf(
|
||||
|
|
|
|||
|
|
@ -66,8 +66,7 @@ internal class TokenDetailsSkeletonStateConverter(
|
|||
stakingBlocksState = StakingBlockUM.Loading(iconState).takeIf { isSupportedInMobileApp },
|
||||
notifications = persistentListOf(),
|
||||
pendingTxs = persistentListOf(),
|
||||
swapTxs = persistentListOf(),
|
||||
onrampTxs = persistentListOf(),
|
||||
expressTxs = persistentListOf(),
|
||||
txHistoryState = TxHistoryState.Content(
|
||||
contentItems = MutableStateFlow(
|
||||
value = TxHistoryState.getDefaultLoadingTransactions(clickIntents::onExploreClick),
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ import com.tangem.domain.txhistory.models.TxHistoryListError
|
|||
import com.tangem.domain.txhistory.models.TxHistoryStateError
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.SwapTransactionsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenBalanceSegmentedButtonConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsAppBarMenuConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
||||
|
|
@ -36,7 +35,6 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.component
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadedTxHistoryConverter
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadingTxHistoryConverter
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadingTxHistoryConverter.TokenDetailsLoadingTxHistoryModel
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.exchange.ExchangeStatusBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
import com.tangem.utils.Provider
|
||||
|
|
@ -301,31 +299,6 @@ internal class TokenDetailsStateFactory(
|
|||
return state.copy(notifications = notificationConverter.removeHederaAssociateWarning(state))
|
||||
}
|
||||
|
||||
fun getStateWithExchangeStatusBottomSheet(swapTxState: SwapTransactionsState): TokenDetailsState {
|
||||
return currentStateProvider().copy(
|
||||
bottomSheetConfig = TangemBottomSheetConfig(
|
||||
isShow = true,
|
||||
onDismissRequest = clickIntents::onDismissBottomSheet,
|
||||
content = ExchangeStatusBottomSheetConfig(
|
||||
value = swapTxState,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun updateStateWithExchangeStatusBottomSheet(swapTxState: SwapTransactionsState): TangemBottomSheetConfig? {
|
||||
val state = currentStateProvider()
|
||||
val bottomSheetConfig = state.bottomSheetConfig
|
||||
val currentConfig = bottomSheetConfig?.content as? ExchangeStatusBottomSheetConfig ?: return bottomSheetConfig
|
||||
return bottomSheetConfig.copy(
|
||||
content = if (currentConfig.value != swapTxState) {
|
||||
ExchangeStatusBottomSheetConfig(swapTxState)
|
||||
} else {
|
||||
currentConfig
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fun getStateAndTriggerEvent(
|
||||
state: TokenDetailsState,
|
||||
errorMessage: TextReference,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory
|
||||
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressLinkUM
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressStatusUM
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.core.ui.utils.toDateFormatWithTodayYesterday
|
||||
import com.tangem.core.ui.utils.toTimeFormat
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
|
|
@ -17,9 +20,12 @@ import com.tangem.domain.tokens.model.analytics.TokenExchangeAnalyticsEvent
|
|||
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
|
||||
import com.tangem.feature.swap.domain.models.domain.ExchangeStatusModel
|
||||
import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionListModel
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.ExchangeStatusState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.SwapTransactionsState
|
||||
import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionModel
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotifications
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeStatusState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExpressTransactionStateIconUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExpressTransactionStateInfoUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExpressTransactionStateUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
import com.tangem.utils.Provider
|
||||
|
|
@ -32,25 +38,27 @@ import timber.log.Timber
|
|||
import java.math.BigDecimal
|
||||
import java.util.Locale
|
||||
|
||||
// Fixme [REDACTED_JIRA]
|
||||
@Suppress("LargeClass")
|
||||
internal class TokenDetailsSwapTransactionsStateConverter(
|
||||
private val clickIntents: TokenDetailsClickIntents,
|
||||
private val cryptoCurrency: CryptoCurrency,
|
||||
private val analyticsEventsHandlerProvider: Provider<AnalyticsEventHandler>,
|
||||
appCurrencyProvider: Provider<AppCurrency>,
|
||||
) : Converter<Unit, PersistentList<SwapTransactionsState>> {
|
||||
) : Converter<Unit, PersistentList<ExpressTransactionStateUM.ExchangeUM>> {
|
||||
|
||||
private val iconStateConverter = CryptoCurrencyToIconStateConverter()
|
||||
private val appCurrency = appCurrencyProvider()
|
||||
|
||||
override fun convert(value: Unit): PersistentList<SwapTransactionsState> {
|
||||
override fun convert(value: Unit): PersistentList<ExpressTransactionStateUM.ExchangeUM> {
|
||||
return persistentListOf()
|
||||
}
|
||||
|
||||
fun convert(
|
||||
savedTransactions: List<SavedSwapTransactionListModel>,
|
||||
quotes: Set<Quote>,
|
||||
): PersistentList<SwapTransactionsState> {
|
||||
val result = mutableListOf<SwapTransactionsState>()
|
||||
): PersistentList<ExpressTransactionStateUM.ExchangeUM> {
|
||||
val result = mutableListOf<ExpressTransactionStateUM.ExchangeUM>()
|
||||
|
||||
savedTransactions
|
||||
.forEach { swapTransaction ->
|
||||
|
|
@ -72,42 +80,26 @@ internal class TokenDetailsSwapTransactionsStateConverter(
|
|||
fromFiatAmount = quote.fiatRate.multiply(fromAmount)
|
||||
}
|
||||
}
|
||||
val timestamp = transaction.timestamp
|
||||
val notifications =
|
||||
getNotification(transaction.status?.status, transaction.status?.txExternalUrl, null)
|
||||
val showProviderLink = getShowProviderLink(notifications, transaction.status)
|
||||
result.add(
|
||||
SwapTransactionsState(
|
||||
txId = transaction.txId,
|
||||
ExpressTransactionStateUM.ExchangeUM(
|
||||
provider = transaction.provider,
|
||||
txUrl = transaction.status?.txExternalUrl,
|
||||
txExternalId = transaction.status?.txExternalId,
|
||||
timestamp = TextReference.Str(
|
||||
"${timestamp.toDateFormatWithTodayYesterday()}, ${timestamp.toTimeFormat()}",
|
||||
),
|
||||
fiatSymbol = appCurrency.symbol,
|
||||
statuses = getStatuses(transaction.status?.status),
|
||||
hasFailed = transaction.status?.status == ExchangeStatus.Failed,
|
||||
activeStatus = transaction.status?.status,
|
||||
notification = notifications,
|
||||
toCryptoCurrency = toCryptoCurrency,
|
||||
toCryptoAmount = toAmount.format { crypto(toCryptoCurrency) },
|
||||
toFiatAmount = getFiatAmount(toFiatAmount),
|
||||
toCurrencyIcon = iconStateConverter.convert(toCryptoCurrency),
|
||||
fromCryptoCurrency = fromCryptoCurrency,
|
||||
fromCryptoAmount = stringReference(
|
||||
fromAmount.format { crypto(fromCryptoCurrency) },
|
||||
),
|
||||
fromFiatAmount = getFiatAmount(fromFiatAmount),
|
||||
fromCurrencyIcon = iconStateConverter.convert(fromCryptoCurrency),
|
||||
activeStatus = transaction.status?.status,
|
||||
showProviderLink = showProviderLink,
|
||||
onClick = { clickIntents.onSwapTransactionClick(transaction.txId) },
|
||||
onGoToProviderClick = { url ->
|
||||
analyticsEventsHandlerProvider().send(
|
||||
TokenExchangeAnalyticsEvent.GoToProviderStatus(cryptoCurrency.symbol),
|
||||
)
|
||||
clickIntents.onGoToProviderClick(url = url)
|
||||
},
|
||||
isRefundTerminalStatus = true,
|
||||
fromCryptoCurrency = fromCryptoCurrency,
|
||||
toCryptoCurrency = toCryptoCurrency,
|
||||
info = createStateInfo(
|
||||
transaction,
|
||||
toCryptoCurrency,
|
||||
fromCryptoCurrency,
|
||||
toFiatAmount,
|
||||
fromFiatAmount,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -116,37 +108,79 @@ internal class TokenDetailsSwapTransactionsStateConverter(
|
|||
}
|
||||
|
||||
fun updateTxStatus(
|
||||
tx: SwapTransactionsState,
|
||||
tx: ExpressTransactionStateUM.ExchangeUM,
|
||||
statusModel: ExchangeStatusModel?,
|
||||
refundToken: CryptoCurrency?,
|
||||
isRefundTerminalStatus: Boolean,
|
||||
): SwapTransactionsState {
|
||||
): ExpressTransactionStateUM.ExchangeUM {
|
||||
if (statusModel == null || tx.activeStatus == statusModel.status) {
|
||||
Timber.e("UpdateTxStatus isn't required. Current status isn't changed")
|
||||
return tx
|
||||
}
|
||||
val hasFailed = tx.hasFailed || statusModel.status == ExchangeStatus.Failed
|
||||
val hasFailed = statusModel.status == ExchangeStatus.Failed
|
||||
val notifications = getNotification(statusModel.status, statusModel.txExternalUrl, refundToken)
|
||||
val showProviderLink = getShowProviderLink(notifications, statusModel)
|
||||
return tx.copy(
|
||||
activeStatus = statusModel.status,
|
||||
hasFailed = hasFailed,
|
||||
notification = notifications,
|
||||
statuses = getStatuses(statusModel.status, hasFailed),
|
||||
txUrl = statusModel.txExternalUrl,
|
||||
showProviderLink = showProviderLink,
|
||||
isRefundTerminalStatus = isRefundTerminalStatus,
|
||||
info = tx.info.copy(txExternalUrl = statusModel.txExternalUrl),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getFiatAmount(toFiatAmount: BigDecimal?): String {
|
||||
return BigDecimalFormatter.formatFiatAmount(
|
||||
fiatAmount = toFiatAmount,
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
private fun createStateInfo(
|
||||
transaction: SavedSwapTransactionModel,
|
||||
toCryptoCurrency: CryptoCurrency,
|
||||
fromCryptoCurrency: CryptoCurrency,
|
||||
toFiatAmount: BigDecimal?,
|
||||
fromFiatAmount: BigDecimal?,
|
||||
): ExpressTransactionStateInfoUM {
|
||||
val timestamp = transaction.timestamp
|
||||
return ExpressTransactionStateInfoUM(
|
||||
title = resourceReference(R.string.express_exchange_by, wrappedList(transaction.provider.name)),
|
||||
txId = transaction.txId,
|
||||
txExternalUrl = transaction.status?.txExternalUrl,
|
||||
txExternalId = transaction.status?.txExternalId,
|
||||
timestamp = timestamp,
|
||||
timestampFormatted = stringReference(
|
||||
"${timestamp.toDateFormatWithTodayYesterday()}, ${timestamp.toTimeFormat()}",
|
||||
),
|
||||
toAmount = getCryptoAmount(transaction.toCryptoAmount, toCryptoCurrency),
|
||||
toFiatAmount = getFiatAmount(toFiatAmount),
|
||||
toCurrencyIcon = iconStateConverter.convert(toCryptoCurrency),
|
||||
toAmountSymbol = toCryptoCurrency.symbol,
|
||||
fromAmount = getCryptoAmount(transaction.fromCryptoAmount, fromCryptoCurrency),
|
||||
fromFiatAmount = getFiatAmount(fromFiatAmount),
|
||||
fromCurrencyIcon = iconStateConverter.convert(fromCryptoCurrency),
|
||||
fromAmountSymbol = fromCryptoCurrency.symbol,
|
||||
onClick = { clickIntents.onExpressTransactionClick(transaction.txId) },
|
||||
onGoToProviderClick = { url ->
|
||||
analyticsEventsHandlerProvider().send(
|
||||
TokenExchangeAnalyticsEvent.GoToProviderStatus(cryptoCurrency.symbol),
|
||||
)
|
||||
clickIntents.onGoToProviderClick(url = url)
|
||||
},
|
||||
iconState = getIconState(transaction.status?.status),
|
||||
status = getStatusState(),
|
||||
notification = null, // fixme [REDACTED_JIRA]
|
||||
)
|
||||
}
|
||||
|
||||
private fun getCryptoAmount(amount: BigDecimal?, cryptoCurrency: CryptoCurrency) = stringReference(
|
||||
amount.format { crypto(cryptoCurrency) },
|
||||
)
|
||||
|
||||
private fun getFiatAmount(toFiatAmount: BigDecimal?) = stringReference(
|
||||
toFiatAmount.format {
|
||||
fiat(
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
private fun getNotification(
|
||||
status: ExchangeStatus?,
|
||||
txUrl: String?,
|
||||
|
|
@ -186,6 +220,21 @@ internal class TokenDetailsSwapTransactionsStateConverter(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getIconState(status: ExchangeStatus?): ExpressTransactionStateIconUM {
|
||||
return when (status) {
|
||||
ExchangeStatus.Verifying -> ExpressTransactionStateIconUM.Warning
|
||||
ExchangeStatus.Failed, ExchangeStatus.Cancelled -> ExpressTransactionStateIconUM.Error
|
||||
else -> ExpressTransactionStateIconUM.None
|
||||
}
|
||||
}
|
||||
|
||||
// Fixme [REDACTED_JIRA]
|
||||
private fun getStatusState() = ExpressStatusUM(
|
||||
title = resourceReference(R.string.express_exchange_status_title),
|
||||
link = ExpressLinkUM.Empty,
|
||||
statuses = persistentListOf(),
|
||||
)
|
||||
|
||||
private fun getShowProviderLink(notifications: ExchangeStatusNotifications?, status: ExchangeStatusModel?) =
|
||||
notifications == null && status?.txExternalUrl != null && status.status != ExchangeStatus.Cancelled
|
||||
|
||||
|
|
|
|||
|
|
@ -14,39 +14,36 @@ import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
|||
import com.tangem.feature.swap.domain.SwapTransactionRepository
|
||||
import com.tangem.feature.swap.domain.api.SwapRepository
|
||||
import com.tangem.feature.swap.domain.models.domain.*
|
||||
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.express.ExpressTransactionStateUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsSwapTransactionsStateConverter
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.exchange.ExchangeStatusBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.ExpressStatusBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class ExchangeStatusFactory(
|
||||
internal class ExchangeStatusFactory @AssistedInject constructor(
|
||||
private val swapTransactionRepository: SwapTransactionRepository,
|
||||
private val swapRepository: SwapRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
|
||||
private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase,
|
||||
private val swapTransactionStatusStore: SwapTransactionStatusStore,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val clickIntents: TokenDetailsClickIntents,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val analyticsEventsHandlerProvider: Provider<AnalyticsEventHandler>,
|
||||
private val currentStateProvider: Provider<TokenDetailsState>,
|
||||
private val userWalletId: UserWalletId,
|
||||
private val cryptoCurrency: CryptoCurrency,
|
||||
@Assisted private val clickIntents: TokenDetailsClickIntents,
|
||||
@Assisted private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
@Assisted private val analyticsEventsHandlerProvider: Provider<AnalyticsEventHandler>,
|
||||
@Assisted private val currentStateProvider: Provider<TokenDetailsState>,
|
||||
@Assisted private val userWalletId: UserWalletId,
|
||||
@Assisted private val cryptoCurrency: CryptoCurrency,
|
||||
) {
|
||||
|
||||
private val swapTransactionsStateConverter by lazy {
|
||||
|
|
@ -58,7 +55,7 @@ internal class ExchangeStatusFactory(
|
|||
)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(): Flow<PersistentList<SwapTransactionsState>> {
|
||||
suspend operator fun invoke(): Flow<PersistentList<ExpressTransactionStateUM.ExchangeUM>> {
|
||||
val selectedWallet = getSelectedWalletSyncUseCase().fold(
|
||||
ifLeft = { return emptyFlow() },
|
||||
ifRight = { it },
|
||||
|
|
@ -82,50 +79,39 @@ internal class ExchangeStatusFactory(
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun removeTransactionOnBottomSheetClosed(isForceTerminal: Boolean = false): TokenDetailsState {
|
||||
suspend fun removeTransactionOnBottomSheetClosed(isForceTerminal: Boolean = false) {
|
||||
val state = currentStateProvider()
|
||||
val bottomSheetConfig = state.bottomSheetConfig?.content as? ExchangeStatusBottomSheetConfig ?: return state
|
||||
val selectedTx = bottomSheetConfig.value
|
||||
val bottomSheetConfig = state.bottomSheetConfig?.content as? ExpressStatusBottomSheetConfig ?: return
|
||||
val selectedTx = bottomSheetConfig.value as? ExpressTransactionStateUM.ExchangeUM ?: return
|
||||
|
||||
val shouldTerminate = selectedTx.activeStatus.isTerminal(selectedTx.isRefundTerminalStatus) || isForceTerminal
|
||||
return if (shouldTerminate) {
|
||||
if (shouldTerminate) {
|
||||
swapTransactionRepository.removeTransaction(
|
||||
userWalletId = userWalletId,
|
||||
fromCryptoCurrency = selectedTx.fromCryptoCurrency,
|
||||
toCryptoCurrency = selectedTx.toCryptoCurrency,
|
||||
txId = selectedTx.txId,
|
||||
txId = selectedTx.info.txId,
|
||||
)
|
||||
val filteredTxs = state.swapTxs
|
||||
.filterNot { it.txId == selectedTx.txId }
|
||||
.toPersistentList()
|
||||
state.copy(swapTxs = filteredTxs)
|
||||
} else {
|
||||
state
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateSwapTxStatuses(swapTxList: PersistentList<SwapTransactionsState>) = withContext(dispatchers.io) {
|
||||
swapTxList.map { tx ->
|
||||
async {
|
||||
val statusModel = getExchangeStatus(tx.txId, tx.provider)
|
||||
val isRefundTerminalStatus = statusModel?.refundNetwork == null &&
|
||||
statusModel?.refundContractAddress == null &&
|
||||
tx.provider.type != ExchangeProviderType.DEX_BRIDGE
|
||||
if (tx.activeStatus.isTerminal(isRefundTerminalStatus)) {
|
||||
tx
|
||||
} else {
|
||||
val addedRefundToken = addRefundCurrencyIfNeeded(statusModel, tx.provider.type)
|
||||
swapTransactionsStateConverter.updateTxStatus(
|
||||
tx = tx,
|
||||
statusModel = statusModel,
|
||||
refundToken = addedRefundToken,
|
||||
isRefundTerminalStatus = isRefundTerminalStatus,
|
||||
)
|
||||
}
|
||||
}
|
||||
suspend fun updateSwapTxStatus(swapTx: ExpressTransactionStateUM.ExchangeUM): ExpressTransactionStateUM.ExchangeUM {
|
||||
return if (swapTx.activeStatus.isTerminal(swapTx.isRefundTerminalStatus)) {
|
||||
swapTx
|
||||
} else {
|
||||
val statusModel = getExchangeStatus(swapTx.info.txId, swapTx.provider)
|
||||
val isRefundTerminalStatus = statusModel?.refundNetwork == null &&
|
||||
statusModel?.refundContractAddress == null &&
|
||||
swapTx.provider.type != ExchangeProviderType.DEX_BRIDGE
|
||||
|
||||
val addedRefundToken = addRefundCurrencyIfNeeded(statusModel, swapTx.provider.type)
|
||||
swapTransactionsStateConverter.updateTxStatus(
|
||||
tx = swapTx,
|
||||
statusModel = statusModel,
|
||||
refundToken = addedRefundToken,
|
||||
isRefundTerminalStatus = isRefundTerminalStatus,
|
||||
)
|
||||
}
|
||||
.awaitAll()
|
||||
.toPersistentList()
|
||||
}
|
||||
|
||||
private suspend fun getExchangeStatus(txId: String, provider: SwapProvider): ExchangeStatusModel? {
|
||||
|
|
@ -177,7 +163,7 @@ internal class ExchangeStatusFactory(
|
|||
private fun getExchangeStatusState(
|
||||
savedTransactions: List<SavedSwapTransactionListModel>?,
|
||||
quotes: Set<Quote>,
|
||||
): PersistentList<SwapTransactionsState> {
|
||||
): PersistentList<ExpressTransactionStateUM.ExchangeUM> {
|
||||
if (savedTransactions == null) {
|
||||
return persistentListOf()
|
||||
}
|
||||
|
|
@ -224,4 +210,16 @@ internal class ExchangeStatusFactory(
|
|||
emptySet()
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(
|
||||
clickIntents: TokenDetailsClickIntents,
|
||||
appCurrencyProvider: Provider<AppCurrency>,
|
||||
analyticsEventsHandlerProvider: Provider<AnalyticsEventHandler>,
|
||||
currentStateProvider: Provider<TokenDetailsState>,
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): ExchangeStatusFactory
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.express
|
||||
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
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.model.analytics.TokenExchangeAnalyticsEvent
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExpressTransactionStateUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.ExpressStatusBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class ExpressStatusFactory @AssistedInject constructor(
|
||||
@Assisted private val currentStateProvider: Provider<TokenDetailsState>,
|
||||
@Assisted private val clickIntents: TokenDetailsClickIntents,
|
||||
@Assisted private val cryptoCurrency: CryptoCurrency,
|
||||
@Assisted appCurrencyProvider: Provider<AppCurrency>,
|
||||
@Assisted analyticsEventsHandlerProvider: Provider<AnalyticsEventHandler>,
|
||||
@Assisted userWalletId: UserWalletId,
|
||||
@Assisted cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus?>,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val analyticsEventsHandler: AnalyticsEventHandler,
|
||||
onrampStatusFactory: OnrampStatusFactory.Factory,
|
||||
exchangeStatusFactory: ExchangeStatusFactory.Factory,
|
||||
) {
|
||||
|
||||
private val exchangeStatusFactory by lazy(mode = LazyThreadSafetyMode.NONE) {
|
||||
exchangeStatusFactory.create(
|
||||
clickIntents = clickIntents,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
analyticsEventsHandlerProvider = analyticsEventsHandlerProvider,
|
||||
currentStateProvider = currentStateProvider,
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
)
|
||||
}
|
||||
|
||||
private val onrampStatusFactory by lazy(LazyThreadSafetyMode.NONE) {
|
||||
onrampStatusFactory.create(
|
||||
currentStateProvider = currentStateProvider,
|
||||
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
clickIntents = clickIntents,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
userWalletId = userWalletId,
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun getExpressStatuses(): Flow<PersistentList<ExpressTransactionStateUM>> = combine(
|
||||
flow = exchangeStatusFactory(),
|
||||
flow2 = onrampStatusFactory(),
|
||||
) { maybeExchange, maybeOnramp ->
|
||||
persistentListOf(
|
||||
maybeOnramp,
|
||||
maybeExchange,
|
||||
).flatten()
|
||||
.sortedByDescending { it.info.timestamp }
|
||||
.toPersistentList()
|
||||
}
|
||||
|
||||
suspend fun getUpdatedExpressStatuses(expressTxs: PersistentList<ExpressTransactionStateUM>) =
|
||||
withContext(dispatchers.io) {
|
||||
expressTxs.map { tx ->
|
||||
async {
|
||||
when (tx) {
|
||||
is ExpressTransactionStateUM.ExchangeUM -> exchangeStatusFactory.updateSwapTxStatus(tx)
|
||||
is ExpressTransactionStateUM.OnrampUM -> onrampStatusFactory.updateOnrmapTxStatus(tx)
|
||||
}
|
||||
}
|
||||
}.awaitAll()
|
||||
.toPersistentList()
|
||||
}
|
||||
|
||||
fun getStateWithUpdatedExpressTxs(
|
||||
expressTxs: PersistentList<ExpressTransactionStateUM>,
|
||||
updateBalance: (CryptoCurrency) -> Unit,
|
||||
): TokenDetailsState {
|
||||
val state = currentStateProvider()
|
||||
val config = state.bottomSheetConfig
|
||||
val expressBottomSheet = config?.content as? ExpressStatusBottomSheetConfig
|
||||
val currentTx = expressTxs.firstOrNull { it.info.txId == expressBottomSheet?.value?.info?.txId }
|
||||
if (currentTx is ExpressTransactionStateUM.ExchangeUM && currentTx.activeStatus == ExchangeStatus.Finished) {
|
||||
updateBalance(currentTx.toCryptoCurrency)
|
||||
}
|
||||
return state.copy(
|
||||
expressTxs = expressTxs,
|
||||
bottomSheetConfig = currentTx?.let(
|
||||
::updateStateWithExpressStatusBottomSheet,
|
||||
) ?: config,
|
||||
)
|
||||
}
|
||||
|
||||
fun getStateWithExpressStatusBottomSheet(expressState: ExpressTransactionStateUM): TokenDetailsState {
|
||||
analyticsEventsHandler.send(TokenExchangeAnalyticsEvent.CexTxStatusOpened(cryptoCurrency.symbol))
|
||||
|
||||
return currentStateProvider().copy(
|
||||
bottomSheetConfig = TangemBottomSheetConfig(
|
||||
isShow = true,
|
||||
onDismissRequest = clickIntents::onDismissBottomSheet,
|
||||
content = ExpressStatusBottomSheetConfig(
|
||||
value = expressState,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun updateStateWithExpressStatusBottomSheet(expressState: ExpressTransactionStateUM): TangemBottomSheetConfig? {
|
||||
val state = currentStateProvider()
|
||||
val bottomSheetConfig = state.bottomSheetConfig
|
||||
val currentConfig = bottomSheetConfig?.content as? ExpressStatusBottomSheetConfig ?: return bottomSheetConfig
|
||||
return bottomSheetConfig.copy(
|
||||
content = if (currentConfig.value != expressState) {
|
||||
ExpressStatusBottomSheetConfig(expressState)
|
||||
} else {
|
||||
currentConfig
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun removeTransactionOnBottomSheetClosed(
|
||||
expressState: ExpressTransactionStateUM,
|
||||
isForceTerminal: Boolean = false,
|
||||
) {
|
||||
when (expressState) {
|
||||
is ExpressTransactionStateUM.ExchangeUM -> exchangeStatusFactory.removeTransactionOnBottomSheetClosed(
|
||||
isForceTerminal,
|
||||
)
|
||||
is ExpressTransactionStateUM.OnrampUM -> onrampStatusFactory.removeTransactionOnBottomSheetClosed()
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
@Suppress("LongParameterList")
|
||||
fun create(
|
||||
clickIntents: TokenDetailsClickIntents,
|
||||
appCurrencyProvider: Provider<AppCurrency>,
|
||||
analyticsEventsHandlerProvider: Provider<AnalyticsEventHandler>,
|
||||
currentStateProvider: Provider<TokenDetailsState>,
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus?>,
|
||||
): ExpressStatusFactory
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +1,37 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.express
|
||||
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.onramp.GetOnrampStatusUseCase
|
||||
import com.tangem.domain.onramp.GetOnrampTransactionsUseCase
|
||||
import com.tangem.domain.onramp.OnrampRemoveTransactionUseCase
|
||||
import com.tangem.domain.onramp.OnrampSaveTransactionUseCase
|
||||
import com.tangem.domain.onramp.model.cache.OnrampTransaction
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExpressTransactionStateUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsOnrampTransactionStateConverter
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.onramp.OnrampStatusBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.ExpressStatusBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.flow.map
|
||||
import timber.log.Timber
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class OnrampStatusFactory(
|
||||
private val stateProvider: Provider<TokenDetailsState>,
|
||||
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus?>,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val clickIntents: TokenDetailsClickIntents,
|
||||
private val cryptoCurrency: CryptoCurrency,
|
||||
private val userWalletId: UserWalletId,
|
||||
internal class OnrampStatusFactory @AssistedInject constructor(
|
||||
private val getOnrampTransactionsUseCase: GetOnrampTransactionsUseCase,
|
||||
private val onrampSaveTransactionUseCase: OnrampSaveTransactionUseCase,
|
||||
private val getOnrampStatusUseCase: GetOnrampStatusUseCase,
|
||||
private val onrampRemoveTransactionUseCase: OnrampRemoveTransactionUseCase,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
@Assisted private val currentStateProvider: Provider<TokenDetailsState>,
|
||||
@Assisted private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus?>,
|
||||
@Assisted private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
@Assisted private val clickIntents: TokenDetailsClickIntents,
|
||||
@Assisted private val cryptoCurrency: CryptoCurrency,
|
||||
@Assisted private val userWalletId: UserWalletId,
|
||||
) {
|
||||
|
||||
private val onrampTransactionStateConverter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
|
|
@ -49,80 +43,53 @@ internal class OnrampStatusFactory(
|
|||
)
|
||||
}
|
||||
|
||||
operator fun invoke(): Flow<List<OnrampTransaction>> {
|
||||
operator fun invoke(): Flow<List<ExpressTransactionStateUM.OnrampUM>> {
|
||||
return getOnrampTransactionsUseCase(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrencyId = cryptoCurrency.id,
|
||||
).fold(
|
||||
ifRight = { savedTransactions ->
|
||||
savedTransactions
|
||||
},
|
||||
ifLeft = { flowOf(persistentListOf()) },
|
||||
)
|
||||
).map { maybeTransaction ->
|
||||
maybeTransaction.fold(
|
||||
ifRight = onrampTransactionStateConverter::convertList,
|
||||
ifLeft = { persistentListOf() },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun getStateWithOnrampStatusBottomSheet(onrampTxState: ExpressTransactionStateUM.OnrampUM): TokenDetailsState {
|
||||
return stateProvider().copy(
|
||||
bottomSheetConfig = TangemBottomSheetConfig(
|
||||
isShow = true,
|
||||
onDismissRequest = clickIntents::onDismissBottomSheet,
|
||||
content = OnrampStatusBottomSheetConfig(onrampTxState),
|
||||
),
|
||||
)
|
||||
}
|
||||
suspend fun removeTransactionOnBottomSheetClosed() {
|
||||
val state = currentStateProvider()
|
||||
val bottomSheetConfig = state.bottomSheetConfig?.content as? ExpressStatusBottomSheetConfig ?: return
|
||||
val selectedTx = bottomSheetConfig.value as? ExpressTransactionStateUM.OnrampUM ?: return
|
||||
|
||||
fun updateOnrampStatusBottomSheet(onrampTxs: List<OnrampTransaction>): TokenDetailsState {
|
||||
val state = stateProvider()
|
||||
val bottomSheetConfig = state.bottomSheetConfig
|
||||
val onrampBottomSheet = bottomSheetConfig?.content as? OnrampStatusBottomSheetConfig
|
||||
|
||||
val updatedOnrampTxState = onrampTransactionStateConverter.convertList(onrampTxs).toPersistentList()
|
||||
val currentOnrampTxState =
|
||||
updatedOnrampTxState.firstOrNull { it.info.txId == onrampBottomSheet?.value?.info?.txId }
|
||||
|
||||
return state.copy(
|
||||
onrampTxs = updatedOnrampTxState,
|
||||
bottomSheetConfig = bottomSheetConfig?.copy(
|
||||
content = if (currentOnrampTxState != null && currentOnrampTxState != onrampBottomSheet?.value) {
|
||||
OnrampStatusBottomSheetConfig(currentOnrampTxState)
|
||||
} else {
|
||||
onrampBottomSheet
|
||||
} ?: bottomSheetConfig.content,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun removeTransactionOnBottomSheetClosed(): TokenDetailsState {
|
||||
val state = stateProvider()
|
||||
val bottomSheetConfig = state.bottomSheetConfig?.content as? OnrampStatusBottomSheetConfig ?: return state
|
||||
val selectedTx = bottomSheetConfig.value
|
||||
|
||||
return if (selectedTx.activeStatus.isTerminal()) {
|
||||
if (selectedTx.activeStatus.isTerminal()) {
|
||||
onrampRemoveTransactionUseCase(txId = selectedTx.info.txId)
|
||||
val filteredTxs = state.onrampTxs
|
||||
.filterNot { it.info.txId == selectedTx.info.txId }
|
||||
.toPersistentList()
|
||||
state.copy(onrampTxs = filteredTxs)
|
||||
} else {
|
||||
state
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateOnrmapTxStatuses(onrampTxList: List<OnrampTransaction>) = withContext(dispatchers.io) {
|
||||
onrampTxList.map { tx ->
|
||||
async {
|
||||
getOnrampStatusUseCase(tx.txId).fold(
|
||||
ifLeft = { null },
|
||||
ifRight = { statusModel ->
|
||||
val updatedStatus = tx.copy(status = statusModel.status)
|
||||
onrampSaveTransactionUseCase(updatedStatus)
|
||||
updatedStatus
|
||||
},
|
||||
)
|
||||
}
|
||||
suspend fun updateOnrmapTxStatus(onrampTx: ExpressTransactionStateUM.OnrampUM): ExpressTransactionStateUM.OnrampUM {
|
||||
return if (onrampTx.activeStatus.isTerminal()) {
|
||||
onrampTx
|
||||
} else {
|
||||
getOnrampStatusUseCase(onrampTx.info.txId).fold(
|
||||
ifLeft = {
|
||||
Timber.e("Couldn't update onramp status. $it")
|
||||
onrampTx
|
||||
},
|
||||
ifRight = { statusModel ->
|
||||
onrampTx.copy(activeStatus = statusModel.status)
|
||||
},
|
||||
)
|
||||
}
|
||||
.awaitAll()
|
||||
.filterNotNull()
|
||||
.toPersistentList()
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(
|
||||
currentStateProvider: Provider<TokenDetailsState>,
|
||||
cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus?>,
|
||||
appCurrencyProvider: Provider<AppCurrency>,
|
||||
clickIntents: TokenDetailsClickIntents,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
userWalletId: UserWalletId,
|
||||
): OnrampStatusFactory
|
||||
}
|
||||
}
|
||||
|
|
@ -48,12 +48,9 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.T
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsDialogs
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsTopAppBar
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenInfoBlock
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.exchange.ExchangeStatusBottomSheet
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.exchange.ExchangeStatusBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.exchange.swapTransactionsItems
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.onramp.OnrampStatusBottomSheet
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.onramp.OnrampStatusBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.onramp.onrampTransactionsItems
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.ExpressStatusBottomSheet
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.ExpressStatusBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.expressTransactionsItems
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.staking.TokenStakingBlock
|
||||
import com.tangem.features.markets.token.block.TokenMarketBlockComponent
|
||||
|
||||
|
|
@ -180,13 +177,8 @@ internal fun TokenDetailsScreen(state: TokenDetailsState, tokenMarketBlockCompon
|
|||
)
|
||||
}
|
||||
|
||||
swapTransactionsItems(
|
||||
swapTxs = state.swapTxs,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
|
||||
onrampTransactionsItems(
|
||||
onrampTxs = state.onrampTxs,
|
||||
expressTransactionsItems(
|
||||
expressTxs = state.expressTxs,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
|
||||
|
|
@ -214,11 +206,8 @@ internal fun TokenDetailsScreen(state: TokenDetailsState, tokenMarketBlockCompon
|
|||
is ChooseAddressBottomSheetConfig -> {
|
||||
ChooseAddressBottomSheet(config = config)
|
||||
}
|
||||
is ExchangeStatusBottomSheetConfig -> {
|
||||
ExchangeStatusBottomSheet(config = config)
|
||||
}
|
||||
is OnrampStatusBottomSheetConfig -> {
|
||||
OnrampStatusBottomSheet(config = config)
|
||||
is ExpressStatusBottomSheetConfig -> {
|
||||
ExpressStatusBottomSheet(config = config)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExpressTransactionStateUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.exchange.ExchangeStatusBottomSheetContent
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.onramp.OnrampStatusBottomSheetContent
|
||||
|
||||
internal data class ExpressStatusBottomSheetConfig(
|
||||
val value: ExpressTransactionStateUM,
|
||||
) : TangemBottomSheetConfigContent
|
||||
|
||||
@Composable
|
||||
internal fun ExpressStatusBottomSheet(config: TangemBottomSheetConfig) {
|
||||
TangemBottomSheet(
|
||||
config = config,
|
||||
containerColor = TangemTheme.colors.background.tertiary,
|
||||
) { content: ExpressStatusBottomSheetConfig ->
|
||||
when (val state = content.value) {
|
||||
is ExpressTransactionStateUM.OnrampUM -> OnrampStatusBottomSheetContent(state)
|
||||
is ExpressTransactionStateUM.ExchangeUM -> ExchangeStatusBottomSheetContent(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +1,42 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.onramp
|
||||
package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express
|
||||
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.onramp.model.OnrampStatus
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExpressTransactionStateIconUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExpressTransactionStateUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.ExpressStatusItem
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
|
||||
internal fun LazyListScope.onrampTransactionsItems(
|
||||
onrampTxs: PersistentList<ExpressTransactionStateUM.OnrampUM>,
|
||||
internal fun LazyListScope.expressTransactionsItems(
|
||||
expressTxs: PersistentList<ExpressTransactionStateUM>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
items(
|
||||
count = onrampTxs.size,
|
||||
key = { onrampTxs[it].info.txId },
|
||||
contentType = { onrampTxs[it]::class.java },
|
||||
count = expressTxs.size,
|
||||
key = { expressTxs[it].info.txId },
|
||||
contentType = { expressTxs[it]::class.java },
|
||||
) {
|
||||
val item = onrampTxs[it]
|
||||
val itemInfo = item.info
|
||||
|
||||
val (iconRes, tint) = when (item.activeStatus) {
|
||||
OnrampStatus.Status.Verifying -> R.drawable.ic_alert_triangle_20 to TangemTheme.colors.icon.attention
|
||||
OnrampStatus.Status.Failed -> {
|
||||
val itemInfo = expressTxs[it].info
|
||||
val (iconRes, tint) = when (itemInfo.iconState) {
|
||||
ExpressTransactionStateIconUM.Warning -> {
|
||||
R.drawable.ic_alert_triangle_20 to TangemTheme.colors.icon.attention
|
||||
}
|
||||
ExpressTransactionStateIconUM.Error -> {
|
||||
R.drawable.ic_alert_circle_24 to TangemTheme.colors.icon.warning
|
||||
}
|
||||
else -> null to null
|
||||
ExpressTransactionStateIconUM.None -> null to null
|
||||
}
|
||||
|
||||
ExpressStatusItem(
|
||||
title = resourceReference(id = R.string.express_status_buying, wrappedList(item.cryptoCurrencyName)),
|
||||
title = itemInfo.title,
|
||||
fromTokenIconState = itemInfo.fromCurrencyIcon,
|
||||
toTokenIconState = itemInfo.toCurrencyIcon,
|
||||
fromAmount = itemInfo.fromAmount,
|
||||
fromSymbol = itemInfo.fromAmountSymbol,
|
||||
toAmount = itemInfo.toAmount,
|
||||
toSymbol = itemInfo.toAmountSymbol,
|
||||
onClick = item.info.onClick,
|
||||
onClick = itemInfo.onClick,
|
||||
infoIconRes = iconRes,
|
||||
infoIconTint = tint,
|
||||
modifier = modifier.animateItem(),
|
||||
|
|
@ -25,7 +25,7 @@ import com.tangem.core.ui.extensions.resourceReference
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.ExchangeStatusState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeStatusState
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
|
|
|||
|
|
@ -14,30 +14,17 @@ import com.tangem.core.ui.components.SpacerH10
|
|||
import com.tangem.core.ui.components.SpacerH12
|
||||
import com.tangem.core.ui.components.SpacerH16
|
||||
import com.tangem.core.ui.components.SpacerH24
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.notifications.CurrencyNotification
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.SwapTransactionsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotifications
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExpressTransactionStateUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.ExpressEstimate
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.ExpressProvider
|
||||
|
||||
@Composable
|
||||
internal fun ExchangeStatusBottomSheet(config: TangemBottomSheetConfig) {
|
||||
TangemBottomSheet(
|
||||
config = config,
|
||||
containerColor = TangemTheme.colors.background.tertiary,
|
||||
) { content: ExchangeStatusBottomSheetConfig ->
|
||||
ExchangeStatusBottomSheetContent(config = content.value)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ExchangeStatusBottomSheetContent(config: SwapTransactionsState) {
|
||||
internal fun ExchangeStatusBottomSheetContent(state: ExpressTransactionStateUM.ExchangeUM) {
|
||||
Column(modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16)) {
|
||||
SpacerH10()
|
||||
Text(
|
||||
|
|
@ -57,31 +44,31 @@ private fun ExchangeStatusBottomSheetContent(config: SwapTransactionsState) {
|
|||
)
|
||||
SpacerH16()
|
||||
ExpressEstimate(
|
||||
timestamp = config.timestamp,
|
||||
fromTokenIconState = config.fromCurrencyIcon,
|
||||
toTokenIconState = config.toCurrencyIcon,
|
||||
fromCryptoAmount = config.fromCryptoAmount,
|
||||
fromCryptoSymbol = config.fromCryptoCurrency.symbol,
|
||||
toCryptoAmount = TextReference.Str(config.toCryptoAmount),
|
||||
toCryptoSymbol = config.toCryptoCurrency.symbol,
|
||||
fromFiatAmount = TextReference.Str(config.fromFiatAmount),
|
||||
toFiatAmount = TextReference.Str(config.toFiatAmount),
|
||||
timestamp = state.info.timestampFormatted,
|
||||
fromTokenIconState = state.info.fromCurrencyIcon,
|
||||
toTokenIconState = state.info.toCurrencyIcon,
|
||||
fromCryptoAmount = state.info.fromAmount,
|
||||
fromCryptoSymbol = state.info.fromAmountSymbol,
|
||||
toCryptoAmount = state.info.toAmount,
|
||||
toCryptoSymbol = state.info.toAmountSymbol,
|
||||
fromFiatAmount = state.info.fromFiatAmount,
|
||||
toFiatAmount = state.info.toFiatAmount,
|
||||
)
|
||||
SpacerH12()
|
||||
ExpressProvider(
|
||||
providerName = TextReference.Str(config.provider.name),
|
||||
providerType = TextReference.Str(config.provider.type.providerName),
|
||||
providerTxId = config.txExternalId,
|
||||
imageUrl = config.provider.imageLarge,
|
||||
providerName = TextReference.Str(state.provider.name),
|
||||
providerType = TextReference.Str(state.provider.type.providerName),
|
||||
providerTxId = state.info.txExternalId,
|
||||
imageUrl = state.provider.imageLarge,
|
||||
)
|
||||
SpacerH12()
|
||||
ExchangeStatusBlock(
|
||||
statuses = config.statuses,
|
||||
showLink = config.showProviderLink,
|
||||
onClick = { config.onGoToProviderClick(config.txUrl.orEmpty()) },
|
||||
statuses = state.statuses,
|
||||
showLink = state.showProviderLink,
|
||||
onClick = { state.info.onGoToProviderClick(state.info.txExternalUrl.orEmpty()) },
|
||||
)
|
||||
if (config.notification != null) {
|
||||
Notification(state = config.notification, activeStatus = config.activeStatus)
|
||||
if (state.notification != null) {
|
||||
Notification(state = state.notification, activeStatus = state.activeStatus)
|
||||
}
|
||||
SpacerH24()
|
||||
}
|
||||
|
|
@ -114,8 +101,4 @@ private fun Notification(state: ExchangeStatusNotifications, activeStatus: Excha
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal data class ExchangeStatusBottomSheetConfig(
|
||||
val value: SwapTransactionsState,
|
||||
) : TangemBottomSheetConfigContent
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.exchange
|
||||
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.SwapTransactionsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.ExpressStatusItem
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
|
||||
internal fun LazyListScope.swapTransactionsItems(
|
||||
swapTxs: PersistentList<SwapTransactionsState>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (swapTxs.isNotEmpty()) {
|
||||
items(
|
||||
count = swapTxs.size,
|
||||
key = { swapTxs[it].txId },
|
||||
contentType = { swapTxs[it]::class.java },
|
||||
) {
|
||||
val item = swapTxs[it]
|
||||
val (iconRes, tint) = when (item.activeStatus) {
|
||||
ExchangeStatus.Verifying -> R.drawable.ic_alert_triangle_20 to TangemTheme.colors.icon.attention
|
||||
ExchangeStatus.Failed, ExchangeStatus.Cancelled -> {
|
||||
R.drawable.ic_alert_circle_24 to TangemTheme.colors.icon.warning
|
||||
}
|
||||
else -> null to null
|
||||
}
|
||||
|
||||
ExpressStatusItem(
|
||||
title = resourceReference(id = R.string.express_exchange_by, wrappedList(item.provider.name)),
|
||||
fromTokenIconState = item.fromCurrencyIcon,
|
||||
toTokenIconState = item.toCurrencyIcon,
|
||||
fromAmount = item.fromCryptoAmount,
|
||||
fromSymbol = item.fromCryptoCurrency.symbol,
|
||||
toSymbol = item.toCryptoCurrency.symbol,
|
||||
onClick = item.onClick,
|
||||
infoIconRes = iconRes,
|
||||
infoIconTint = tint,
|
||||
modifier = modifier.animateItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,9 +15,6 @@ import com.tangem.core.ui.components.SpacerH10
|
|||
import com.tangem.core.ui.components.SpacerH12
|
||||
import com.tangem.core.ui.components.SpacerH16
|
||||
import com.tangem.core.ui.components.SpacerH24
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExpressTransactionStateUM
|
||||
|
|
@ -25,17 +22,7 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.e
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.ExpressProvider
|
||||
|
||||
@Composable
|
||||
internal fun OnrampStatusBottomSheet(config: TangemBottomSheetConfig) {
|
||||
TangemBottomSheet(
|
||||
config = config,
|
||||
containerColor = TangemTheme.colors.background.tertiary,
|
||||
) { content: OnrampStatusBottomSheetConfig ->
|
||||
OnrampStatusBottomSheetContent(config = content.value)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun OnrampStatusBottomSheetContent(config: ExpressTransactionStateUM.OnrampUM) {
|
||||
internal fun OnrampStatusBottomSheetContent(state: ExpressTransactionStateUM.OnrampUM) {
|
||||
Column(modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16)) {
|
||||
SpacerH10()
|
||||
Text(
|
||||
|
|
@ -55,33 +42,27 @@ private fun OnrampStatusBottomSheetContent(config: ExpressTransactionStateUM.Onr
|
|||
)
|
||||
SpacerH16()
|
||||
ExpressEstimate(
|
||||
timestamp = config.info.timestamp,
|
||||
fromTokenIconState = config.info.fromCurrencyIcon,
|
||||
toTokenIconState = config.info.toCurrencyIcon,
|
||||
fromCryptoAmount = config.info.fromAmount,
|
||||
fromCryptoSymbol = config.info.fromAmountSymbol,
|
||||
toCryptoAmount = config.info.toAmount,
|
||||
toCryptoSymbol = config.info.toAmountSymbol,
|
||||
fromFiatAmount = config.info.fromFiatAmount,
|
||||
toFiatAmount = config.info.toFiatAmount,
|
||||
timestamp = state.info.timestampFormatted,
|
||||
fromTokenIconState = state.info.fromCurrencyIcon,
|
||||
toTokenIconState = state.info.toCurrencyIcon,
|
||||
fromCryptoAmount = state.info.fromAmount,
|
||||
fromCryptoSymbol = state.info.fromAmountSymbol,
|
||||
toCryptoAmount = state.info.toAmount,
|
||||
toCryptoSymbol = state.info.toAmountSymbol,
|
||||
fromFiatAmount = state.info.fromFiatAmount,
|
||||
toFiatAmount = state.info.toFiatAmount,
|
||||
)
|
||||
SpacerH12()
|
||||
|
||||
ExpressProvider(
|
||||
providerName = stringReference(config.providerName),
|
||||
providerType = stringReference(config.providerType),
|
||||
providerTxId = config.info.txExternalId,
|
||||
imageUrl = config.providerImageUrl,
|
||||
providerName = stringReference(state.providerName),
|
||||
providerType = stringReference(state.providerType),
|
||||
providerTxId = state.info.txExternalId,
|
||||
imageUrl = state.providerImageUrl,
|
||||
)
|
||||
SpacerH12()
|
||||
ExpressStatusBlock(state = config.info.status)
|
||||
if (config.info.notification != null) {
|
||||
ExpressStatusNotificationBlock(state = config.info.notification)
|
||||
}
|
||||
ExpressStatusBlock(state = state.info.status)
|
||||
ExpressStatusNotificationBlock(state = state.info.notification)
|
||||
SpacerH24()
|
||||
}
|
||||
}
|
||||
|
||||
internal data class OnrampStatusBottomSheetConfig(
|
||||
val value: ExpressTransactionStateUM.OnrampUM,
|
||||
) : TangemBottomSheetConfigContent
|
||||
}
|
||||
|
|
@ -45,9 +45,7 @@ interface TokenDetailsClickIntents {
|
|||
|
||||
fun onCloseRentInfoNotification()
|
||||
|
||||
fun onSwapTransactionClick(txId: String)
|
||||
|
||||
fun onOnrampTransactionClick(txId: String)
|
||||
fun onExpressTransactionClick(txId: String)
|
||||
|
||||
fun onGoToProviderClick(url: String)
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import com.tangem.core.ui.extensions.stringReference
|
|||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.haptic.TangemHapticEffect
|
||||
import com.tangem.core.ui.haptic.VibratorHapticManager
|
||||
import com.tangem.datasource.local.swaptx.SwapTransactionStatusStore
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
|
|
@ -30,11 +29,6 @@ import com.tangem.domain.card.GetExtendedPublicKeyForCurrencyUseCase
|
|||
import com.tangem.domain.card.NetworkHasDerivationUseCase
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.onramp.GetOnrampStatusUseCase
|
||||
import com.tangem.domain.onramp.GetOnrampTransactionsUseCase
|
||||
import com.tangem.domain.onramp.OnrampRemoveTransactionUseCase
|
||||
import com.tangem.domain.onramp.OnrampSaveTransactionUseCase
|
||||
import com.tangem.domain.onramp.model.cache.OnrampTransaction
|
||||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.domain.settings.ShouldShowSwapPromoTokenUseCase
|
||||
import com.tangem.domain.staking.GetStakingAvailabilityUseCase
|
||||
|
|
@ -50,12 +44,10 @@ import com.tangem.domain.tokens.model.CryptoCurrency
|
|||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.NetworkAddress
|
||||
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
|
||||
import com.tangem.domain.tokens.model.analytics.TokenExchangeAnalyticsEvent
|
||||
import com.tangem.domain.tokens.model.analytics.TokenReceiveAnalyticsEvent
|
||||
import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent
|
||||
import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent.Companion.toReasonAnalyticsText
|
||||
import com.tangem.domain.tokens.model.analytics.TokenSwapPromoAnalyticsEvent
|
||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||
import com.tangem.domain.transaction.error.AssociateAssetError
|
||||
import com.tangem.domain.transaction.usecase.AssociateAssetUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
|
||||
|
|
@ -64,22 +56,16 @@ import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
|
|||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.GetExploreUrlUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.feature.swap.domain.SwapTransactionRepository
|
||||
import com.tangem.feature.swap.domain.api.SwapRepository
|
||||
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
|
||||
import com.tangem.feature.tokendetails.presentation.router.InnerTokenDetailsRouter
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.analytics.TokenDetailsCurrencyStatusAnalyticsSender
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.analytics.TokenDetailsNotificationsAnalyticsSender
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.SwapTransactionsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenBalanceSegmentedButtonConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExpressTransactionStateUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsStateFactory
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.express.ExchangeStatusFactory
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.express.OnrampStatusFactory
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.exchange.ExchangeStatusBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.onramp.OnrampStatusBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.express.ExpressStatusFactory
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.ExpressStatusBottomSheetConfig
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.*
|
||||
|
|
@ -111,8 +97,6 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
private val getCurrencyWarningsUseCase: GetCurrencyWarningsUseCase,
|
||||
private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase,
|
||||
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
|
||||
private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase,
|
||||
private val shouldShowSwapPromoTokenUseCase: ShouldShowSwapPromoTokenUseCase,
|
||||
private val updateDelayedCurrencyStatusUseCase: UpdateDelayedNetworkStatusUseCase,
|
||||
private val getExtendedPublicKeyForCurrencyUseCase: GetExtendedPublicKeyForCurrencyUseCase,
|
||||
|
|
@ -120,20 +104,13 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
private val getStakingAvailabilityUseCase: GetStakingAvailabilityUseCase,
|
||||
private val getYieldUseCase: GetYieldUseCase,
|
||||
private val networkHasDerivationUseCase: NetworkHasDerivationUseCase,
|
||||
private val swapRepository: SwapRepository,
|
||||
private val swapTransactionRepository: SwapTransactionRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val swapTransactionStatusStore: SwapTransactionStatusStore,
|
||||
private val isDemoCardUseCase: IsDemoCardUseCase,
|
||||
private val associateAssetUseCase: AssociateAssetUseCase,
|
||||
private val reduxStateHolder: ReduxStateHolder,
|
||||
private val analyticsEventsHandler: AnalyticsEventHandler,
|
||||
private val vibratorHapticManager: VibratorHapticManager,
|
||||
private val clipboardManager: ClipboardManager,
|
||||
private val getOnrampTransactionsUseCase: GetOnrampTransactionsUseCase,
|
||||
private val onrampSaveTransactionUseCase: OnrampSaveTransactionUseCase,
|
||||
private val onrampRemoveTransactionUseCase: OnrampRemoveTransactionUseCase,
|
||||
private val getOnrampStatusUseCase: GetOnrampStatusUseCase,
|
||||
expressStatusFactory: ExpressStatusFactory.Factory,
|
||||
getUserWalletUseCase: GetUserWalletUseCase,
|
||||
getStakingIntegrationIdUseCase: GetStakingIntegrationIdUseCase,
|
||||
deepLinksRegistry: DeepLinksRegistry,
|
||||
|
|
@ -157,15 +134,13 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
private val marketPriceJobHolder = JobHolder()
|
||||
private val refreshStateJobHolder = JobHolder()
|
||||
private val warningsJobHolder = JobHolder()
|
||||
private val swapTxJobHolder = JobHolder()
|
||||
private val onrampTxJobHolder = JobHolder()
|
||||
private val expressTxJobHolder = JobHolder()
|
||||
private val selectedAppCurrencyFlow: StateFlow<AppCurrency> = createSelectedAppCurrencyFlow()
|
||||
|
||||
private var cryptoCurrencyStatus: CryptoCurrencyStatus? = null
|
||||
private var stakingEntryInfo: StakingEntryInfo? = null
|
||||
private var stakingAvailability: StakingAvailability = StakingAvailability.Unavailable
|
||||
private var swapTxStatusTaskScheduler = SingleTaskScheduler<PersistentList<SwapTransactionsState>>()
|
||||
private var onrampTxStatusTaskScheduler = SingleTaskScheduler<PersistentList<OnrampTransaction>>()
|
||||
private var expressTxStatusTaskScheduler = SingleTaskScheduler<PersistentList<ExpressTransactionStateUM>>()
|
||||
|
||||
private val stateFactory = TokenDetailsStateFactory(
|
||||
currentStateProvider = Provider { uiState.value },
|
||||
|
|
@ -182,37 +157,15 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
decimals = cryptoCurrency.decimals,
|
||||
)
|
||||
|
||||
private val exchangeStatusFactory by lazy(mode = LazyThreadSafetyMode.NONE) {
|
||||
ExchangeStatusFactory(
|
||||
swapTransactionRepository = swapTransactionRepository,
|
||||
swapRepository = swapRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
|
||||
addCryptoCurrenciesUseCase = addCryptoCurrenciesUseCase,
|
||||
swapTransactionStatusStore = swapTransactionStatusStore,
|
||||
dispatchers = dispatchers,
|
||||
private val expressStatusFactory by lazy(mode = LazyThreadSafetyMode.NONE) {
|
||||
expressStatusFactory.create(
|
||||
clickIntents = this,
|
||||
appCurrencyProvider = Provider { selectedAppCurrencyFlow.value },
|
||||
analyticsEventsHandlerProvider = Provider { analyticsEventsHandler },
|
||||
currentStateProvider = Provider { uiState.value },
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
)
|
||||
}
|
||||
|
||||
private val onrampStatusFactory by lazy(LazyThreadSafetyMode.NONE) {
|
||||
OnrampStatusFactory(
|
||||
stateProvider = Provider { uiState.value },
|
||||
appCurrencyProvider = Provider { selectedAppCurrencyFlow.value },
|
||||
cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus },
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
clickIntents = this,
|
||||
getOnrampTransactionsUseCase = getOnrampTransactionsUseCase,
|
||||
onrampSaveTransactionUseCase = onrampSaveTransactionUseCase,
|
||||
onrampRemoveTransactionUseCase = onrampRemoveTransactionUseCase,
|
||||
getOnrampStatusUseCase = getOnrampStatusUseCase,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -255,16 +208,14 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onCleared() {
|
||||
swapTxStatusTaskScheduler.cancelTask()
|
||||
onrampTxStatusTaskScheduler.cancelTask()
|
||||
onrampTxJobHolder.cancel()
|
||||
expressTxStatusTaskScheduler.cancelTask()
|
||||
expressTxJobHolder.cancel()
|
||||
super.onCleared()
|
||||
}
|
||||
|
||||
private fun updateContent() {
|
||||
subscribeOnCurrencyStatusUpdates()
|
||||
subscribeOnExchangeTransactionsUpdates()
|
||||
subscribeOnOnrampTransactionsUpdates()
|
||||
subscribeOnExpressTransactionsUpdates()
|
||||
updateTxHistory(refresh = false, showItemsLoading = true)
|
||||
|
||||
updateStakingInfo()
|
||||
|
|
@ -337,55 +288,31 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun subscribeOnExchangeTransactionsUpdates() {
|
||||
private fun subscribeOnExpressTransactionsUpdates() {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
swapTxStatusTaskScheduler.cancelTask()
|
||||
exchangeStatusFactory.invoke()
|
||||
expressTxStatusTaskScheduler.cancelTask()
|
||||
expressStatusFactory
|
||||
.getExpressStatuses()
|
||||
.distinctUntilChanged()
|
||||
.filterNot { it.isEmpty() }
|
||||
.onEach { swapTxs ->
|
||||
updateSwapTx(swapTxs)
|
||||
swapTxStatusTaskScheduler.scheduleTask(
|
||||
viewModelScope,
|
||||
PeriodicTask(
|
||||
delay = EXCHANGE_STATUS_UPDATE_DELAY,
|
||||
task = {
|
||||
runCatching {
|
||||
exchangeStatusFactory.updateSwapTxStatuses(internalUiState.value.swapTxs)
|
||||
}
|
||||
},
|
||||
onSuccess = ::updateSwapTx,
|
||||
onError = { /* no-op */ },
|
||||
),
|
||||
.onEach { expressTxs ->
|
||||
internalUiState.value = expressStatusFactory.getStateWithUpdatedExpressTxs(
|
||||
expressTxs,
|
||||
::updateNetworkToSwapBalance,
|
||||
)
|
||||
}
|
||||
.flowOn(dispatchers.main)
|
||||
.launchIn(viewModelScope)
|
||||
.saveIn(swapTxJobHolder)
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeOnOnrampTransactionsUpdates() {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
onrampTxStatusTaskScheduler.cancelTask()
|
||||
onrampStatusFactory.invoke().distinctUntilChanged()
|
||||
.filterNot { it.isEmpty() }
|
||||
.onEach { onrampTxs ->
|
||||
internalUiState.value = onrampStatusFactory.updateOnrampStatusBottomSheet(onrampTxs)
|
||||
onrampTxStatusTaskScheduler.scheduleTask(
|
||||
expressTxStatusTaskScheduler.scheduleTask(
|
||||
viewModelScope,
|
||||
PeriodicTask(
|
||||
delay = EXCHANGE_STATUS_UPDATE_DELAY,
|
||||
delay = EXPRESS_STATUS_UPDATE_DELAY,
|
||||
task = {
|
||||
runCatching {
|
||||
val onrampTxsToUpdate = onrampTxs.filter { onrampTx ->
|
||||
internalUiState.value.onrampTxs.any { it.info.txId == onrampTx.txId }
|
||||
}
|
||||
onrampStatusFactory.updateOnrmapTxStatuses(onrampTxsToUpdate)
|
||||
expressStatusFactory.getUpdatedExpressStatuses(internalUiState.value.expressTxs)
|
||||
}
|
||||
},
|
||||
onSuccess = {
|
||||
internalUiState.value = onrampStatusFactory.updateOnrampStatusBottomSheet(onrampTxs)
|
||||
onSuccess = { updatedTxs ->
|
||||
internalUiState.value = expressStatusFactory.getStateWithUpdatedExpressTxs(
|
||||
updatedTxs,
|
||||
::updateNetworkToSwapBalance,
|
||||
)
|
||||
},
|
||||
onError = { /* no-op */ },
|
||||
),
|
||||
|
|
@ -393,25 +320,10 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
}
|
||||
.flowOn(dispatchers.main)
|
||||
.launchIn(viewModelScope)
|
||||
.saveIn(onrampTxJobHolder)
|
||||
.saveIn(expressTxJobHolder)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSwapTx(swapTxs: PersistentList<SwapTransactionsState>) {
|
||||
val config = internalUiState.value.bottomSheetConfig
|
||||
val exchangeBottomSheet = config?.content as? ExchangeStatusBottomSheetConfig
|
||||
val currentTx = swapTxs.firstOrNull { it.txId == exchangeBottomSheet?.value?.txId }
|
||||
if (currentTx?.activeStatus == ExchangeStatus.Finished) {
|
||||
updateNetworkToSwapBalance(currentTx.toCryptoCurrency)
|
||||
}
|
||||
internalUiState.value = internalUiState.value.copy(
|
||||
swapTxs = swapTxs,
|
||||
bottomSheetConfig = currentTx?.let(
|
||||
stateFactory::updateStateWithExchangeStatusBottomSheet,
|
||||
) ?: config,
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateNetworkToSwapBalance(toCryptoCurrency: CryptoCurrency) {
|
||||
viewModelScope.launch {
|
||||
updateDelayedCurrencyStatusUseCase(
|
||||
|
|
@ -835,8 +747,7 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
refresh = true,
|
||||
showItemsLoading = internalUiState.value.txHistoryState !is TxHistoryState.Content,
|
||||
)
|
||||
subscribeOnExchangeTransactionsUpdates()
|
||||
subscribeOnOnrampTransactionsUpdates()
|
||||
subscribeOnExpressTransactionsUpdates()
|
||||
},
|
||||
).awaitAll()
|
||||
internalUiState.value = stateFactory.getRefreshedState()
|
||||
|
|
@ -844,16 +755,10 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onDismissBottomSheet() {
|
||||
val bsContent = internalUiState.value.bottomSheetConfig?.content
|
||||
when (bsContent) {
|
||||
is ExchangeStatusBottomSheetConfig -> {
|
||||
when (val bsContent = internalUiState.value.bottomSheetConfig?.content) {
|
||||
is ExpressStatusBottomSheetConfig -> {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
internalUiState.value = exchangeStatusFactory.removeTransactionOnBottomSheetClosed()
|
||||
}
|
||||
}
|
||||
is OnrampStatusBottomSheetConfig -> {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
internalUiState.value = onrampStatusFactory.removeTransactionOnBottomSheetClosed()
|
||||
expressStatusFactory.removeTransactionOnBottomSheetClosed(bsContent.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -864,15 +769,9 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
internalUiState.value = stateFactory.getStateWithRemovedRentNotification()
|
||||
}
|
||||
|
||||
override fun onSwapTransactionClick(txId: String) {
|
||||
val swapTxState = internalUiState.value.swapTxs.first { it.txId == txId }
|
||||
analyticsEventsHandler.send(TokenExchangeAnalyticsEvent.CexTxStatusOpened(cryptoCurrency.symbol))
|
||||
internalUiState.value = stateFactory.getStateWithExchangeStatusBottomSheet(swapTxState)
|
||||
}
|
||||
|
||||
override fun onOnrampTransactionClick(txId: String) {
|
||||
val onrampTxState = internalUiState.value.onrampTxs.first { it.info.txId == txId }
|
||||
internalUiState.value = onrampStatusFactory.getStateWithOnrampStatusBottomSheet(onrampTxState)
|
||||
override fun onExpressTransactionClick(txId: String) {
|
||||
val expressTxState = internalUiState.value.expressTxs.first { it.info.txId == txId }
|
||||
internalUiState.value = expressStatusFactory.getStateWithExpressStatusBottomSheet(expressTxState)
|
||||
}
|
||||
|
||||
override fun onGoToProviderClick(url: String) {
|
||||
|
|
@ -880,9 +779,13 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onGoToRefundedTokenClick(cryptoCurrency: CryptoCurrency) {
|
||||
if (internalUiState.value.bottomSheetConfig?.content is ExchangeStatusBottomSheetConfig) {
|
||||
val bottomSheetState = internalUiState.value.bottomSheetConfig?.content
|
||||
if (bottomSheetState is ExpressStatusBottomSheetConfig) {
|
||||
viewModelScope.launch {
|
||||
internalUiState.value = exchangeStatusFactory.removeTransactionOnBottomSheetClosed(true)
|
||||
expressStatusFactory.removeTransactionOnBottomSheetClosed(
|
||||
expressState = bottomSheetState.value,
|
||||
isForceTerminal = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
internalUiState.value = stateFactory.getStateWithClosedBottomSheet()
|
||||
|
|
@ -1005,6 +908,6 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private companion object {
|
||||
const val EXCHANGE_STATUS_UPDATE_DELAY = 10_000L
|
||||
const val EXPRESS_STATUS_UPDATE_DELAY = 10_000L
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue