diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt deleted file mode 100644 index ff5603d0eb..0000000000 --- a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt +++ /dev/null @@ -1,220 +0,0 @@ -package com.tangem.features.txhistory.converter - -import com.tangem.core.ui.components.transactions.state.TransactionState -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.format -import com.tangem.core.ui.utils.toTimeFormat -import com.tangem.domain.models.currency.CryptoCurrency -import com.tangem.domain.models.network.TxInfo -import com.tangem.domain.models.network.TxInfo.TransactionType -import com.tangem.features.txhistory.impl.R -import com.tangem.features.txhistory.utils.TxHistoryUiActions -import com.tangem.utils.StringsSigns -import com.tangem.utils.annotations.RemoveWithToggle -import com.tangem.utils.converter.Converter -import com.tangem.utils.extensions.isZero -import com.tangem.utils.toBriefAddressFormat - -@Deprecated("Remove with main toggle [DesignFeatureToggles.isRedesignEnabled]. Produces pre-redesign TransactionState.") -@RemoveWithToggle("APP_REDESIGN_ENABLED") -internal class TxHistoryItemToTransactionStateConverter( - private val currency: CryptoCurrency, - private val txHistoryUiActions: TxHistoryUiActions, -) : Converter { - override fun convert(value: TxInfo): TransactionState { - return TransactionState.Content( - txHash = value.txHash, - amount = value.getAmount(), - time = value.timestampInMillis.toTimeFormat(), - status = value.status.toUiStatus(), - direction = value.extractDirection(), - iconRes = value.extractIcon(), - title = value.extractTitle(), - subtitle = value.extractSubtitle(), - timestamp = value.timestampInMillis, - onClick = { txHistoryUiActions.openTxInExplorer(value.txHash) }, - ) - } - - private fun TxInfo.extractIcon(): Int = if (status == TxInfo.TransactionStatus.Failed) { - R.drawable.ic_close_24 - } else { - when (type) { - is TransactionType.YieldSupply.DeployContract, - is TransactionType.Approve, - -> R.drawable.ic_doc_24 - is TransactionType.Staking.Stake, - is TransactionType.Staking.Vote, - is TransactionType.Staking.Restake, - -> R.drawable.ic_transaction_history_staking_24 - is TransactionType.Staking.ClaimRewards, - -> R.drawable.ic_transaction_history_claim_rewards_24 - is TransactionType.Staking.Unstake, - is TransactionType.Staking.Withdraw, - -> R.drawable.ic_transaction_history_unstaking_24 - is TransactionType.YieldSupply.Enter -> R.drawable.ic_connect_24 - is TransactionType.YieldSupply.InitializeToken -> R.drawable.ic_gear_24 - is TransactionType.YieldSupply.ReactivateToken -> R.drawable.ic_refresh_24 - is TransactionType.YieldSupply.Exit -> R.drawable.ic_disconnect_24 - is TransactionType.Operation, - is TransactionType.Swap, - is TransactionType.Transfer, - is TransactionType.UnknownOperation, - is TransactionType.YieldSupply.Send, - TransactionType.YieldSupply.Topup, - TransactionType.GaslessFee, - -> if (isOutgoing) R.drawable.ic_arrow_up_24 else R.drawable.ic_arrow_down_24 - } - } - - @Suppress("CyclomaticComplexMethod") - private fun TxInfo.extractTitle(): TextReference = when (val type = type) { - is TransactionType.Approve -> resourceReference(R.string.common_approval) - is TransactionType.Operation -> stringReference(type.name) - is TransactionType.Swap -> resourceReference(R.string.common_swap) - is TransactionType.Transfer -> resourceReference(R.string.common_transfer) - is TransactionType.Staking.Stake -> resourceReference(R.string.common_stake) - is TransactionType.Staking.Unstake -> resourceReference(R.string.common_unstake) - is TransactionType.Staking.Vote -> resourceReference(R.string.staking_vote) - is TransactionType.Staking.ClaimRewards -> resourceReference(R.string.common_claim_rewards) - is TransactionType.Staking.Withdraw -> resourceReference(R.string.staking_withdraw) - is TransactionType.Staking.Restake -> resourceReference(R.string.staking_restake) - is TransactionType.YieldSupply -> when (type) { - is TransactionType.YieldSupply.Enter -> resourceReference(R.string.yield_module_transaction_enter) - is TransactionType.YieldSupply.Exit -> resourceReference(R.string.yield_module_transaction_exit) - TransactionType.YieldSupply.Topup -> resourceReference(R.string.yield_module_transaction_topup) - is TransactionType.YieldSupply.Send -> { - if (type.isYieldSupplyWithdraw || isOutgoing) { - resourceReference(R.string.yield_module_transaction_withdraw) - } else { - resourceReference(R.string.common_transfer) - } - } - is TransactionType.YieldSupply.DeployContract -> resourceReference( - R.string - .yield_module_transaction_deploy_contract, - ) - is TransactionType.YieldSupply.InitializeToken -> resourceReference( - R.string - .yield_module_transaction_initialize, - ) - is TransactionType.YieldSupply.ReactivateToken -> resourceReference( - R.string - .yield_module_transaction_reactivate, - ) - } - is TransactionType.UnknownOperation -> resourceReference(R.string.transaction_history_operation) - TransactionType.GaslessFee -> resourceReference(R.string.gasless_transaction_fee) - } - - private fun TxInfo.extractSubtitle(): TextReference { - return when (val type = this.type) { - is TransactionType.YieldSupply -> if (currency is CryptoCurrency.Coin) { - if (type is TransactionType.YieldSupply.Send) { - extractSubtitleByAddressType() - } else { - resourceReference( - R.string.transaction_history_transaction_for_address, - wrappedList(type.address?.toBriefAddressFormat().orEmpty()), - ) - } - } else { - when (type) { - is TransactionType.YieldSupply.Enter -> { - val amount = amount.format { crypto(symbol = currency.symbol, decimals = currency.decimals) } - resourceReference(R.string.yield_module_transaction_enter_subtitle, wrappedList(amount)) - } - TransactionType.YieldSupply.Topup -> { - val amount = amount.format { crypto(symbol = currency.symbol, decimals = currency.decimals) } - resourceReference(R.string.yield_module_transaction_topup_subtitle, wrappedList(amount)) - } - is TransactionType.YieldSupply.Exit -> { - val amount = amount.format { crypto(symbol = currency.symbol, decimals = currency.decimals) } - resourceReference(R.string.yield_module_transaction_exit_subtitle, wrappedList(amount)) - } - is TransactionType.YieldSupply.Send -> { - if (isOutgoing || !type.isYieldSupplyWithdraw) { - extractSubtitleByAddressType() - } else { - val amount = - amount.format { crypto(symbol = currency.symbol, decimals = currency.decimals) } - resourceReference( - R.string.yield_module_transaction_exit_subtitle, - wrappedList(amount), - ) - } - } - else -> extractSubtitleByAddressType() - } - } - else -> extractSubtitleByAddressType() - } - } - - private fun TxInfo.extractSubtitleByAddressType(): TextReference = - when (val interactionAddress = interactionAddressType) { - is TxInfo.InteractionAddressType.Contract -> resourceReference( - id = R.string.transaction_history_contract_address, - formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()), - ) - is TxInfo.InteractionAddressType.Multiple -> resourceReference( - id = if (isOutgoing) { - R.string.transaction_history_transaction_to_address - } else { - R.string.transaction_history_transaction_from_address - }, - formatArgs = wrappedList(resourceReference(R.string.transaction_history_multiple_addresses)), - ) - is TxInfo.InteractionAddressType.User -> resourceReference( - id = if (isOutgoing) { - R.string.transaction_history_transaction_to_address - } else { - R.string.transaction_history_transaction_from_address - }, - formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()), - ) - is TxInfo.InteractionAddressType.Validator -> resourceReference( - id = R.string.transaction_history_transaction_validator, - formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()), - ) - null -> { - TextReference.EMPTY - } - } - - private fun TxInfo.extractDirection() = - if (isOutgoing) TransactionState.Content.Direction.OUTGOING else TransactionState.Content.Direction.INCOMING - - @Suppress("ComplexCondition") - private fun TxInfo.getAmount(): String { - when (type) { - is TransactionType.Staking.Vote, - TransactionType.Staking.ClaimRewards, - TransactionType.Staking.Withdraw, - -> return "" - - is TransactionType.YieldSupply -> { - if (currency is CryptoCurrency.Token && type == TransactionType.YieldSupply.Send && !isOutgoing) { - return "" - } - } - else -> Unit - } - val prefix = when { - status == TxInfo.TransactionStatus.Failed -> "" - this.amount.isZero() -> "" - else -> if (isOutgoing) StringsSigns.MINUS else StringsSigns.PLUS - } - return prefix + amount.format { crypto(symbol = currency.symbol, decimals = currency.decimals) } - } - - private fun TxInfo.TransactionStatus.toUiStatus() = when (this) { - TxInfo.TransactionStatus.Confirmed -> TransactionState.Content.Status.Confirmed - TxInfo.TransactionStatus.Failed -> TransactionState.Content.Status.Failed - TxInfo.TransactionStatus.Unconfirmed -> TransactionState.Content.Status.Unconfirmed - } -} \ No newline at end of file diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/model/TxHistoryModel.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/model/TxHistoryModel.kt index d90ad6861b..04577d183f 100644 --- a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/model/TxHistoryModel.kt +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/model/TxHistoryModel.kt @@ -6,7 +6,6 @@ import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.navigation.url.UrlOpener -import com.tangem.core.ui.DesignFeatureToggles import com.tangem.core.ui.utils.toDateFormatWithTodayYesterday import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier import com.tangem.domain.account.status.utils.CryptoCurrencyStatusOperations.getCryptoCurrencyStatus @@ -27,7 +26,6 @@ import com.tangem.features.txhistory.component.TxHistoryComponent import com.tangem.features.txhistory.converter.ExpressTxToTransactionItemUMConverter import com.tangem.features.txhistory.converter.TxHistoryInfoToTransactionItemUMConverter import com.tangem.features.txhistory.converter.TxHistoryItemToTransactionItemUMConverter -import com.tangem.features.txhistory.converter.TxHistoryItemToTransactionStateConverter import com.tangem.features.txhistory.entity.TxHistoryItemsUM import com.tangem.features.txhistory.entity.TxHistoryUpdateListener import com.tangem.features.txhistory.state.TxHistoryItemsSnapshot @@ -56,7 +54,6 @@ internal class TxHistoryModel @Inject constructor( private val urlOpener: UrlOpener, private val txHistoryUpdateListener: TxHistoryUpdateListener, private val stateController: TxHistoryStateController, - private val designFeatureToggles: DesignFeatureToggles, private val txHistoryFeatureToggle: TxHistoryFeatureToggles, private val historyTxListManagerFactory: HistoryTxListManager.Factory, private val appTxHistoryFetcher: AppTxHistoryFetcher, @@ -67,17 +64,9 @@ internal class TxHistoryModel @Inject constructor( private val params: TxHistoryComponent.Params = paramsContainer.require() - private val lookupDataFlow: Flow = if (designFeatureToggles.isRedesignEnabled) { - ownerLookupProducer() - .flowOn(dispatchers.default) - .shareIn(modelScope, SharingStarted.WhileSubscribed(), replay = 1) - } else { - emptyFlow() - } - - @RemoveWithToggle("APP_REDESIGN_ENABLED") - private val legacyTxHistoryItemConverter = - TxHistoryItemToTransactionStateConverter(currency = params.currency, txHistoryUiActions = this) + private val lookupDataFlow: Flow = ownerLookupProducer() + .flowOn(dispatchers.default) + .shareIn(modelScope, SharingStarted.WhileSubscribed(), replay = 1) @RemoveWithToggle("AND_15767_NEW_TX_HISTORY_ENABLED") private val txHistoryListManager: TxHistoryListManager? = if (!txHistoryFeatureToggle.isNewTxHistoryEnabled) { @@ -86,10 +75,8 @@ internal class TxHistoryModel @Inject constructor( dispatchers = dispatchers, userWalletId = params.userWalletId, currency = params.currency, - designFeatureToggles = designFeatureToggles, txHistoryUiActions = this, lookupDataFlow = lookupDataFlow, - legacyTxHistoryItemConverter = legacyTxHistoryItemConverter, ) } else { null @@ -297,11 +284,7 @@ internal class TxHistoryModel @Inject constructor( .distinctUntilChanged() val combined: Flow, TxHistoryLookupContext?>> = - if (designFeatureToggles.isRedesignEnabled) { - combine(statusFlow, lookupDataFlow) { status, lookup -> status to lookup } - } else { - statusFlow.map { it to null } - } + combine(statusFlow, lookupDataFlow) { status, lookup -> status to lookup } combined .onEach { (status, lookup) -> handlePendingTxsChanges(status, lookup) } @@ -324,7 +307,6 @@ internal class TxHistoryModel @Inject constructor( ) pending.map(converter::convert).toPersistentList() }, - legacyPendingTxs = { pending.map(legacyTxHistoryItemConverter::convert).toPersistentList() }, ) } } diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/state/TxHistoryItemsSnapshot.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/state/TxHistoryItemsSnapshot.kt index 69c420f0a1..95bc2695ea 100644 --- a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/state/TxHistoryItemsSnapshot.kt +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/state/TxHistoryItemsSnapshot.kt @@ -1,17 +1,12 @@ package com.tangem.features.txhistory.state import com.tangem.features.txhistory.entity.TxHistoryItemsUM -import com.tangem.features.txhistory.entity.TxHistoryUM import kotlinx.collections.immutable.ImmutableList /** - * Snapshot of transaction history items emitted by [TxHistoryListManager]. Wraps either the - * primary or legacy item list so that one [Flow] can carry both pipelines, with the active - * variant chosen via the design feature toggle. + * Snapshot of transaction history items emitted by [TxHistoryListManager]. */ internal sealed interface TxHistoryItemsSnapshot { data class Items(val items: ImmutableList) : TxHistoryItemsSnapshot - - data class LegacyItems(val items: ImmutableList) : TxHistoryItemsSnapshot } \ No newline at end of file diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/state/TxHistoryStateController.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/state/TxHistoryStateController.kt index 1c4661b41b..d374c30cc3 100644 --- a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/state/TxHistoryStateController.kt +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/state/TxHistoryStateController.kt @@ -1,113 +1,71 @@ package com.tangem.features.txhistory.state import com.tangem.core.decompose.di.ModelScoped -import com.tangem.core.ui.DesignFeatureToggles import com.tangem.core.ui.components.transactions.state.TransactionItemUM -import com.tangem.core.ui.components.transactions.state.TransactionState import com.tangem.features.txhistory.entity.TxHistoryItemsUM import com.tangem.features.txhistory.entity.TxHistoryUM import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import javax.inject.Inject /** - * Owns the transaction history UI state and routes updates to either [legacyUiState] or - * [uiState] based on [DesignFeatureToggles.isRedesignEnabled]. Only the active pipeline gets - * emitted to; the inactive flow stays at its initial Loading value. + * Owns the transaction history UI state and routes updates to [uiState]. */ @ModelScoped -internal class TxHistoryStateController @Inject constructor( - private val designFeatureToggles: DesignFeatureToggles, -) { +internal class TxHistoryStateController @Inject constructor() { - private val _legacyUiState: MutableStateFlow = - MutableStateFlow(TxHistoryUM.Loading(isBalanceHidden = true, onExploreClick = {})) - val legacyUiState: StateFlow = _legacyUiState + /** + * Pre-redesign state. Kept only to satisfy consumers that still read the legacy UI (they are + * dead at runtime while the redesign is enabled); no longer populated. + */ + val legacyUiState: StateFlow = + MutableStateFlow(TxHistoryUM.Loading(isBalanceHidden = true, onExploreClick = {})).asStateFlow() private val _uiState: MutableStateFlow = MutableStateFlow(TxHistoryItemsUM.Loading(isBalanceHidden = true, onExploreClick = {})) val uiState: StateFlow = _uiState val isNotSupported: Boolean - get() = if (designFeatureToggles.isRedesignEnabled) { - _uiState.value is TxHistoryItemsUM.NotSupported - } else { - _legacyUiState.value is TxHistoryUM.NotSupported - } + get() = _uiState.value is TxHistoryItemsUM.NotSupported fun setLoading(isBalanceHidden: Boolean, onExploreClick: () -> Unit) { - if (designFeatureToggles.isRedesignEnabled) { - _uiState.value = TxHistoryItemsUM.Loading( - isBalanceHidden = isBalanceHidden, - onExploreClick = onExploreClick, - ) - } else { - _legacyUiState.value = TxHistoryUM.Loading( - isBalanceHidden = isBalanceHidden, - onExploreClick = onExploreClick, - ) - } + _uiState.value = TxHistoryItemsUM.Loading( + isBalanceHidden = isBalanceHidden, + onExploreClick = onExploreClick, + ) } fun setLoadingIfNotContent(onExploreClick: () -> Unit) { - if (designFeatureToggles.isRedesignEnabled) { - _uiState.update { state -> - state as? TxHistoryItemsUM.Content ?: TxHistoryItemsUM.Loading(state.isBalanceHidden, onExploreClick) - } - } else { - _legacyUiState.update { state -> - state as? TxHistoryUM.Content ?: TxHistoryUM.Loading(state.isBalanceHidden, onExploreClick) - } + _uiState.update { state -> + state as? TxHistoryItemsUM.Content ?: TxHistoryItemsUM.Loading(state.isBalanceHidden, onExploreClick) } } fun setError(onReloadClick: () -> Unit, onExploreClick: () -> Unit) { - if (designFeatureToggles.isRedesignEnabled) { - _uiState.value = TxHistoryItemsUM.Error( - isBalanceHidden = _uiState.value.isBalanceHidden, - onReloadClick = onReloadClick, - onExploreClick = onExploreClick, - ) - } else { - _legacyUiState.value = TxHistoryUM.Error( - isBalanceHidden = _legacyUiState.value.isBalanceHidden, - onReloadClick = onReloadClick, - onExploreClick = onExploreClick, - ) - } + _uiState.value = TxHistoryItemsUM.Error( + isBalanceHidden = _uiState.value.isBalanceHidden, + onReloadClick = onReloadClick, + onExploreClick = onExploreClick, + ) } fun setEmpty(onExploreClick: () -> Unit) { - if (designFeatureToggles.isRedesignEnabled) { - _uiState.value = TxHistoryItemsUM.Empty( - isBalanceHidden = _uiState.value.isBalanceHidden, - onExploreClick = onExploreClick, - ) - } else { - _legacyUiState.value = TxHistoryUM.Empty( - isBalanceHidden = _legacyUiState.value.isBalanceHidden, - onExploreClick = onExploreClick, - ) - } + _uiState.value = TxHistoryItemsUM.Empty( + isBalanceHidden = _uiState.value.isBalanceHidden, + onExploreClick = onExploreClick, + ) } fun setNotSupported(onExploreClick: () -> Unit) { - if (designFeatureToggles.isRedesignEnabled) { - _uiState.value = TxHistoryItemsUM.NotSupported( - isBalanceHidden = _uiState.value.isBalanceHidden, - pendingTransactions = persistentListOf(), - onExploreClick = onExploreClick, - ) - } else { - _legacyUiState.value = TxHistoryUM.NotSupported( - isBalanceHidden = _legacyUiState.value.isBalanceHidden, - pendingTransactions = persistentListOf(), - onExploreClick = onExploreClick, - ) - } + _uiState.value = TxHistoryItemsUM.NotSupported( + isBalanceHidden = _uiState.value.isBalanceHidden, + pendingTransactions = persistentListOf(), + onExploreClick = onExploreClick, + ) } fun setContent(snapshot: TxHistoryItemsSnapshot, loadMore: () -> Boolean, onExploreClick: () -> Unit) { @@ -129,27 +87,10 @@ internal class TxHistoryStateController @Inject constructor( ) } } - is TxHistoryItemsSnapshot.LegacyItems -> _legacyUiState.update { state -> - if (snapshot.items.none { it is TxHistoryUM.TxHistoryItemUM.Transaction }) { - TxHistoryUM.Empty( - isBalanceHidden = state.isBalanceHidden, - onExploreClick = onExploreClick, - ) - } else if (state is TxHistoryUM.Content) { - state.copy(items = snapshot.items) - } else { - TxHistoryUM.Content( - items = snapshot.items, - isBalanceHidden = state.isBalanceHidden, - loadMore = loadMore, - ) - } - } } } fun updateLoadingMore(isLoadingMore: Boolean) { - if (!designFeatureToggles.isRedesignEnabled) return _uiState.update { state -> if (state is TxHistoryItemsUM.Content && state.isLoadingMore != isLoadingMore) { state.copy(isLoadingMore = isLoadingMore) @@ -160,32 +101,15 @@ internal class TxHistoryStateController @Inject constructor( } fun updateBalanceHidden(isBalanceHidden: Boolean) { - if (designFeatureToggles.isRedesignEnabled) { - _uiState.update { state -> state.copySealed(isBalanceHidden = isBalanceHidden) } - } else { - _legacyUiState.update { state -> state.copySealed(isBalanceHidden = isBalanceHidden) } - } + _uiState.update { state -> state.copySealed(isBalanceHidden = isBalanceHidden) } } - fun updatePendingTransactions( - pendingTxs: () -> ImmutableList, - legacyPendingTxs: () -> ImmutableList, - ) { - if (designFeatureToggles.isRedesignEnabled) { - _uiState.update { state -> - if (state is TxHistoryItemsUM.NotSupported) { - state.copy(pendingTransactions = pendingTxs()) - } else { - state - } - } - } else { - _legacyUiState.update { state -> - if (state is TxHistoryUM.NotSupported) { - state.copy(pendingTransactions = legacyPendingTxs()) - } else { - state - } + fun updatePendingTransactions(pendingTxs: () -> ImmutableList) { + _uiState.update { state -> + if (state is TxHistoryItemsUM.NotSupported) { + state.copy(pendingTransactions = pendingTxs()) + } else { + state } } } diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryLegacyUiManager.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryLegacyUiManager.kt deleted file mode 100644 index a4e1c8b90d..0000000000 --- a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryLegacyUiManager.kt +++ /dev/null @@ -1,100 +0,0 @@ -package com.tangem.features.txhistory.utils - -import com.tangem.core.ui.utils.toDateFormatWithTodayYesterday -import com.tangem.domain.models.network.TxInfo -import com.tangem.domain.txhistory.models.PaginationWrapper -import com.tangem.features.txhistory.converter.TxHistoryItemToTransactionStateConverter -import com.tangem.features.txhistory.entity.TxHistoryUM -import com.tangem.pagination.Batch -import com.tangem.pagination.PaginationStatus -import com.tangem.utils.annotations.RemoveWithToggle -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.toImmutableList -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.* - -@Deprecated("Remove with main toggle [DesignFeatureToggles.isRedesignEnabled]. Renders pre-redesign tx-history UI.") -@RemoveWithToggle("APP_REDESIGN_ENABLED") -internal class TxHistoryLegacyUiManager( - private val state: MutableStateFlow, - private val txHistoryItemConverter: TxHistoryItemToTransactionStateConverter, - private val txHistoryUiActions: TxHistoryUiActions, -) { - - @OptIn(ExperimentalCoroutinesApi::class) - val items: Flow> = state - .filter { state -> - state.status !is PaginationStatus.None && - state.status !is PaginationStatus.InitialLoading && - state.status !is PaginationStatus.InitialLoadingError - } - .mapLatest { state -> - state.legacyUiBatches.asSequence() - .flatMap { it.data } - .toImmutableList() - } - .distinctUntilChanged() - - fun createOrUpdateUiBatches( - newCurrencyBatches: List>>, - shouldClearUiBatches: Boolean, - ): List>> { - val currentUiBatches = state.value.legacyUiBatches - val batches = if (shouldClearUiBatches) mutableListOf() else currentUiBatches.toMutableList() - - for ((key, data) in newCurrencyBatches) { - val existingBatchIndex = batches.indexOfFirst { it.key == key } - if (existingBatchIndex == -1) { - val items = generateUiItems(key, data) - batches.add(Batch(key = key, data = items)) - } else if (currentUiBatches[existingBatchIndex].data.transactionItemsSizeNotEqual(data.items)) { - val items = generateUiItems(key, data) - batches[existingBatchIndex] = Batch(key = key, data = items) - } - } - - return batches - } - - private fun generateUiItems(key: Int, data: PaginationWrapper): List { - val items = mutableListOf() - - if (key == 0) { - items.add(TxHistoryUM.TxHistoryItemUM.Title(onExploreClick = txHistoryUiActions::openExplorer)) - } - - if (data.items.isNotEmpty()) { - val firstItem = data.items.first() - val firstDate = firstItem.timestampInMillis.toDateFormatWithTodayYesterday() - - items.add( - TxHistoryUM.TxHistoryItemUM.GroupTitle( - title = firstDate, - itemKey = "$key-$firstDate", - ), - ) - items.add(TxHistoryUM.TxHistoryItemUM.Transaction(txHistoryItemConverter.convert(firstItem))) - - data.items.zipWithNext { current, next -> - val currentDate = current.timestampInMillis.toDateFormatWithTodayYesterday() - val nextDate = next.timestampInMillis.toDateFormatWithTodayYesterday() - - if (currentDate != nextDate) { - items.add( - TxHistoryUM.TxHistoryItemUM.GroupTitle( - title = nextDate, - itemKey = "$key-$nextDate", - ), - ) - } - items.add(TxHistoryUM.TxHistoryItemUM.Transaction(txHistoryItemConverter.convert(next))) - } - } - - return items - } - - private fun List.transactionItemsSizeNotEqual(txInfos: List): Boolean { - return this.filterIsInstance().size != txInfos.size - } -} \ No newline at end of file diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryListManager.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryListManager.kt index 748d8b5c2f..861967ad56 100644 --- a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryListManager.kt +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryListManager.kt @@ -1,6 +1,5 @@ package com.tangem.features.txhistory.utils -import com.tangem.core.ui.DesignFeatureToggles import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.network.TxInfo import com.tangem.domain.models.wallet.UserWalletId @@ -9,7 +8,6 @@ import com.tangem.domain.txhistory.model.TxHistoryListConfig import com.tangem.domain.txhistory.models.PaginationWrapper import com.tangem.domain.txhistory.repository.TxHistoryRepositoryV2 import com.tangem.features.txhistory.converter.TxHistoryItemToTransactionItemUMConverter -import com.tangem.features.txhistory.converter.TxHistoryItemToTransactionStateConverter import com.tangem.features.txhistory.model.TxHistoryLookupContext import com.tangem.features.txhistory.state.TxHistoryItemsSnapshot import com.tangem.pagination.BatchAction @@ -34,10 +32,8 @@ internal class TxHistoryListManager( private val dispatchers: CoroutineDispatcherProvider, private val userWalletId: UserWalletId, private val currency: CryptoCurrency, - private val designFeatureToggles: DesignFeatureToggles, private val txHistoryUiActions: TxHistoryUiActions, private val lookupDataFlow: Flow, - legacyTxHistoryItemConverter: TxHistoryItemToTransactionStateConverter, ) { private val jobHolder = JobHolder() @@ -48,17 +44,8 @@ internal class TxHistoryListManager( ) private val state: MutableStateFlow = MutableStateFlow(TxHistoryListState()) private val uiManager = TxHistoryUiManager(state = state) - private val legacyUiManager = TxHistoryLegacyUiManager( - state = state, - txHistoryItemConverter = legacyTxHistoryItemConverter, - txHistoryUiActions = txHistoryUiActions, - ) - val uiItems: Flow = if (designFeatureToggles.isRedesignEnabled) { - uiManager.items.map(TxHistoryItemsSnapshot::Items) - } else { - legacyUiManager.items.map(TxHistoryItemsSnapshot::LegacyItems) - } + val uiItems: Flow = uiManager.items.map(TxHistoryItemsSnapshot::Items) val paginationStatus: Flow> = state.map { it.status }.distinctUntilChanged() suspend fun init() = coroutineScope { @@ -76,24 +63,16 @@ internal class TxHistoryListManager( .launchIn(scope = this) .saveIn(autoLoadMoreJobHolder) - if (designFeatureToggles.isRedesignEnabled) { - var previousLookup: TxHistoryLookupContext? = null - combine(batchFlow.state, lookupDataFlow) { batchState, lookup -> batchState to lookup } - .onEach { (batchState, lookup) -> - val isLookupChanged = previousLookup != null && previousLookup != lookup - previousLookup = lookup - updateState(batchState, lookup, isLookupChanged) - } - .flowOn(dispatchers.default) - .launchIn(scope = this) - .saveIn(jobHolder) - } else { - batchFlow.state - .onEach { batchState -> updateState(batchState, lookupContext = null, isLookupChanged = false) } - .flowOn(dispatchers.default) - .launchIn(scope = this) - .saveIn(jobHolder) - } + var previousLookup: TxHistoryLookupContext? = null + combine(batchFlow.state, lookupDataFlow) { batchState, lookup -> batchState to lookup } + .onEach { (batchState, lookup) -> + val isLookupChanged = previousLookup != null && previousLookup != lookup + previousLookup = lookup + updateState(batchState, lookup, isLookupChanged) + } + .flowOn(dispatchers.default) + .launchIn(scope = this) + .saveIn(jobHolder) } suspend fun startLoading() { @@ -129,32 +108,19 @@ internal class TxHistoryListManager( val isInitialToPaginating = state.status is PaginationStatus.InitialLoading && batchListState.status is PaginationStatus.Paginating val shouldClearUiBatches = isInitialToPaginating || isLookupChanged - val isRedesignEnabled = designFeatureToggles.isRedesignEnabled + val converter = TxHistoryItemToTransactionItemUMConverter( + currency = currency, + txHistoryUiActions = txHistoryUiActions, + lookupContext = lookupContext, + ) state.copy( status = batchListState.status, rawBatches = batchListState.data, - uiBatches = if (isRedesignEnabled) { - val converter = TxHistoryItemToTransactionItemUMConverter( - currency = currency, - txHistoryUiActions = txHistoryUiActions, - lookupContext = lookupContext, - ) - uiManager.createOrUpdateUiBatches( - newCurrencyBatches = batchListState.data, - shouldClearUiBatches = shouldClearUiBatches, - converter = converter, - ) - } else { - state.uiBatches - }, - legacyUiBatches = if (isRedesignEnabled) { - state.legacyUiBatches - } else { - legacyUiManager.createOrUpdateUiBatches( - newCurrencyBatches = batchListState.data, - shouldClearUiBatches = shouldClearUiBatches, - ) - }, + uiBatches = uiManager.createOrUpdateUiBatches( + newCurrencyBatches = batchListState.data, + shouldClearUiBatches = shouldClearUiBatches, + converter = converter, + ), ) } } diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryListState.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryListState.kt index 3d4bd8ffcb..76cd99655d 100644 --- a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryListState.kt +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryListState.kt @@ -3,7 +3,6 @@ package com.tangem.features.txhistory.utils import com.tangem.domain.models.network.TxInfo import com.tangem.domain.txhistory.models.PaginationWrapper import com.tangem.features.txhistory.entity.TxHistoryItemsUM -import com.tangem.features.txhistory.entity.TxHistoryUM import com.tangem.pagination.Batch import com.tangem.pagination.PaginationStatus import com.tangem.utils.annotations.RemoveWithToggle @@ -14,5 +13,4 @@ internal data class TxHistoryListState( val status: PaginationStatus<*> = PaginationStatus.None, val rawBatches: List>> = emptyList(), val uiBatches: List>> = emptyList(), - val legacyUiBatches: List>> = emptyList(), ) \ No newline at end of file diff --git a/features/txhistory/impl/src/test/kotlin/com/tangem/features/txhistory/state/TxHistoryStateControllerTest.kt b/features/txhistory/impl/src/test/kotlin/com/tangem/features/txhistory/state/TxHistoryStateControllerTest.kt index ea13035c1f..afad659d6c 100644 --- a/features/txhistory/impl/src/test/kotlin/com/tangem/features/txhistory/state/TxHistoryStateControllerTest.kt +++ b/features/txhistory/impl/src/test/kotlin/com/tangem/features/txhistory/state/TxHistoryStateControllerTest.kt @@ -2,11 +2,7 @@ package com.tangem.features.txhistory.state import com.google.common.truth.Truth.assertThat import com.tangem.core.ui.components.transactions.state.TransactionItemUM -import com.tangem.core.ui.components.transactions.state.TransactionState import com.tangem.features.txhistory.entity.TxHistoryItemsUM -import com.tangem.features.txhistory.entity.TxHistoryUM -import io.mockk.every -import io.mockk.mockk import kotlinx.collections.immutable.persistentListOf import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance @@ -14,12 +10,7 @@ import org.junit.jupiter.api.TestInstance @TestInstance(TestInstance.Lifecycle.PER_CLASS) internal class TxHistoryStateControllerTest { - private val controller = TxHistoryStateController( - designFeatureToggles = mockk { every { isRedesignEnabled } returns true }, - ) - private val legacyController = TxHistoryStateController( - designFeatureToggles = mockk { every { isRedesignEnabled } returns false }, - ) + private val controller = TxHistoryStateController() @Test fun `GIVEN empty items snapshot WHEN setContent THEN Empty state with explorer action`() { @@ -79,41 +70,4 @@ internal class TxHistoryStateControllerTest { assertThat(controller.uiState.value).isInstanceOf(TxHistoryItemsUM.Empty::class.java) } - - // region Legacy (e.g. Solana: probe reports HasTransactions but the mapped page is empty) - - @Test - fun `GIVEN legacy snapshot with only a title WHEN setContent THEN legacy Empty state with explorer`() { - val onExploreClick = {} - - legacyController.setContent( - snapshot = TxHistoryItemsSnapshot.LegacyItems( - persistentListOf(TxHistoryUM.TxHistoryItemUM.Title(onExploreClick = {})), - ), - loadMore = { true }, - onExploreClick = onExploreClick, - ) - - val state = legacyController.legacyUiState.value - assertThat(state).isInstanceOf(TxHistoryUM.Empty::class.java) - assertThat((state as TxHistoryUM.Empty).onExploreClick).isEqualTo(onExploreClick) - } - - @Test - fun `GIVEN legacy snapshot with transactions WHEN setContent THEN legacy Content state`() { - legacyController.setContent( - snapshot = TxHistoryItemsSnapshot.LegacyItems( - persistentListOf( - TxHistoryUM.TxHistoryItemUM.Title(onExploreClick = {}), - TxHistoryUM.TxHistoryItemUM.Transaction(TransactionState.Loading("hash")), - ), - ), - loadMore = { true }, - onExploreClick = {}, - ) - - assertThat(legacyController.legacyUiState.value).isInstanceOf(TxHistoryUM.Content::class.java) - } - - // endregion } \ No newline at end of file diff --git a/features/txhistory/impl/src/test/kotlin/com/tangem/features/txhistory/utils/TxHistoryListManagerTest.kt b/features/txhistory/impl/src/test/kotlin/com/tangem/features/txhistory/utils/TxHistoryListManagerTest.kt index f9f999a5b2..b95f1c0b7c 100644 --- a/features/txhistory/impl/src/test/kotlin/com/tangem/features/txhistory/utils/TxHistoryListManagerTest.kt +++ b/features/txhistory/impl/src/test/kotlin/com/tangem/features/txhistory/utils/TxHistoryListManagerTest.kt @@ -12,14 +12,12 @@ import com.tangem.domain.txhistory.models.Page import com.tangem.domain.txhistory.models.PaginationWrapper import com.tangem.domain.txhistory.repository.ExpressHistoryPage import com.tangem.domain.txhistory.repository.TxHistoryRepositoryV2 -import com.tangem.features.txhistory.converter.TxHistoryItemToTransactionStateConverter import com.tangem.pagination.BatchFetchResult import com.tangem.pagination.BatchListSource import com.tangem.pagination.PaginationStatus import com.tangem.pagination.fetcher.BatchFetcher import com.tangem.pagination.toBatchFlow import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import io.mockk.every import io.mockk.mockk import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -152,10 +150,8 @@ internal class TxHistoryListManagerTest { dispatchers = repository.dispatchers, userWalletId = userWalletId, currency = currency, - designFeatureToggles = mockk { every { isRedesignEnabled } returns false }, txHistoryUiActions = mockk(relaxed = true), lookupDataFlow = emptyFlow(), - legacyTxHistoryItemConverter = mockk(relaxed = true), ) private fun page(itemCount: Int, isLast: Boolean): Page2Spec = Page2Spec(itemCount = itemCount, isLast = isLast)