Updated on 2026-08-14
This commit is contained in:
parent
1437c14019
commit
3f671e3e0f
46 changed files with 1454 additions and 43 deletions
|
|
@ -17,6 +17,8 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDeta
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreen
|
||||
import com.tangem.features.markets.token.block.TokenMarketBlockComponent
|
||||
import com.tangem.features.tokendetails.TokenDetailsComponent
|
||||
import com.tangem.features.txhistory.TxHistoryFeatureToggles
|
||||
import com.tangem.features.txhistory.component.TxHistoryComponent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -25,10 +27,20 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
|||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted params: TokenDetailsComponent.Params,
|
||||
tokenMarketBlockComponentFactory: TokenMarketBlockComponent.Factory,
|
||||
txHistoryComponentFactory: TxHistoryComponent.Factory,
|
||||
txHistoryFeatureToggles: TxHistoryFeatureToggles,
|
||||
deepLinksRegistry: DeepLinksRegistry,
|
||||
) : TokenDetailsComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: TokenDetailsModel = getOrCreateModel(params)
|
||||
private val txHistoryComponent = txHistoryComponentFactory.create(
|
||||
context = child("txHistoryComponent"),
|
||||
params = TxHistoryComponent.Params(
|
||||
userWalletId = params.userWalletId,
|
||||
currency = params.currency,
|
||||
openExplorer = { model.onExploreClick() },
|
||||
),
|
||||
).takeIf { txHistoryFeatureToggles.isFeatureEnabled }
|
||||
|
||||
init {
|
||||
lifecycle.subscribe(
|
||||
|
|
@ -54,11 +66,11 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
|||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
NavigationBar3ButtonsScrim()
|
||||
TokenDetailsScreen(
|
||||
state = state,
|
||||
tokenMarketBlockComponent = tokenMarketBlockComponent,
|
||||
txHistoryComponent = txHistoryComponent,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig
|
|||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.di.GlobalUiMessageSender
|
||||
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.decompose.ui.UiMessageSender
|
||||
|
|
@ -76,6 +76,8 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.e
|
|||
import com.tangem.features.onramp.OnrampFeatureToggles
|
||||
import com.tangem.features.tokendetails.TokenDetailsComponent
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
import com.tangem.features.txhistory.TxHistoryFeatureToggles
|
||||
import com.tangem.features.txhistory.entity.TxHistoryContentUpdateEmitter
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.*
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
|
|
@ -122,6 +124,8 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
private val onrampFeatureToggles: OnrampFeatureToggles,
|
||||
private val shareManager: ShareManager,
|
||||
@GlobalUiMessageSender private val uiMessageSender: UiMessageSender,
|
||||
private val txHistoryFeatureToggles: TxHistoryFeatureToggles,
|
||||
private val txHistoryContentUpdateEmitter: TxHistoryContentUpdateEmitter,
|
||||
paramsContainer: ParamsContainer,
|
||||
expressStatusFactory: ExpressStatusFactory.Factory,
|
||||
getUserWalletUseCase: GetUserWalletUseCase,
|
||||
|
|
@ -240,7 +244,7 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
private fun updateContent() {
|
||||
subscribeOnCurrencyStatusUpdates()
|
||||
subscribeOnExpressTransactionsUpdates()
|
||||
updateTxHistory(refresh = false, showItemsLoading = true)
|
||||
updateTxHistory(refresh = false, showItemsLoading = true, initialUpdating = true)
|
||||
|
||||
updateStakingInfo()
|
||||
}
|
||||
|
|
@ -362,29 +366,33 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
* @param refresh - invalidate cache and get data from remote
|
||||
* @param showItemsLoading - show loading items placeholder.
|
||||
*/
|
||||
private fun updateTxHistory(refresh: Boolean, showItemsLoading: Boolean) {
|
||||
modelScope.launch(dispatchers.main) {
|
||||
val txHistoryItemsCountEither = txHistoryItemsCountUseCase(
|
||||
userWalletId = userWalletId,
|
||||
currency = cryptoCurrency,
|
||||
)
|
||||
|
||||
// if countEither is left, handling error state run inside getLoadingTxHistoryState
|
||||
if (showItemsLoading || txHistoryItemsCountEither.isLeft()) {
|
||||
internalUiState.value = stateFactory.getLoadingTxHistoryState(
|
||||
itemsCountEither = txHistoryItemsCountEither,
|
||||
pendingTransactions = internalUiState.value.pendingTxs,
|
||||
)
|
||||
}
|
||||
|
||||
txHistoryItemsCountEither.onRight {
|
||||
val maybeTxHistory = txHistoryItemsUseCase(
|
||||
private fun updateTxHistory(refresh: Boolean, showItemsLoading: Boolean, initialUpdating: Boolean = false) {
|
||||
if (txHistoryFeatureToggles.isFeatureEnabled && !initialUpdating) {
|
||||
modelScope.launch { txHistoryContentUpdateEmitter.triggerUpdate() }
|
||||
} else {
|
||||
modelScope.launch(dispatchers.main) {
|
||||
val txHistoryItemsCountEither = txHistoryItemsCountUseCase(
|
||||
userWalletId = userWalletId,
|
||||
currency = cryptoCurrency,
|
||||
refresh = refresh,
|
||||
).map { it.cachedIn(modelScope) }
|
||||
)
|
||||
|
||||
internalUiState.value = stateFactory.getLoadedTxHistoryState(maybeTxHistory)
|
||||
// if countEither is left, handling error state run inside getLoadingTxHistoryState
|
||||
if (showItemsLoading || txHistoryItemsCountEither.isLeft()) {
|
||||
internalUiState.value = stateFactory.getLoadingTxHistoryState(
|
||||
itemsCountEither = txHistoryItemsCountEither,
|
||||
pendingTransactions = internalUiState.value.pendingTxs,
|
||||
)
|
||||
}
|
||||
|
||||
txHistoryItemsCountEither.onRight {
|
||||
val maybeTxHistory = txHistoryItemsUseCase(
|
||||
userWalletId = userWalletId,
|
||||
currency = cryptoCurrency,
|
||||
refresh = refresh,
|
||||
).map { it.cachedIn(modelScope) }
|
||||
|
||||
internalUiState.value = stateFactory.getLoadedTxHistoryState(maybeTxHistory)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,18 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.ui
|
|||
import android.content.res.Configuration
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.*
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.ScaffoldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.paging.compose.LazyPagingItems
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig
|
||||
import com.tangem.common.ui.expressStatus.expressTransactionsItems
|
||||
|
|
@ -39,11 +41,18 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.T
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.ExpressStatusBottomSheet
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.staking.TokenStakingBlock
|
||||
import com.tangem.features.markets.token.block.TokenMarketBlockComponent
|
||||
import com.tangem.features.txhistory.component.TxHistoryComponent
|
||||
import com.tangem.features.txhistory.entity.TxHistoryUM
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
// TODO: Split to blocks [REDACTED_JIRA]
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
internal fun TokenDetailsScreen(state: TokenDetailsState, tokenMarketBlockComponent: TokenMarketBlockComponent?) {
|
||||
internal fun TokenDetailsScreen(
|
||||
state: TokenDetailsState,
|
||||
tokenMarketBlockComponent: TokenMarketBlockComponent?,
|
||||
txHistoryComponent: TxHistoryComponent?,
|
||||
) {
|
||||
BackHandler(onBack = state.topAppBarConfig.onBackClick)
|
||||
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||
|
||||
|
|
@ -57,6 +66,8 @@ internal fun TokenDetailsScreen(state: TokenDetailsState, tokenMarketBlockCompon
|
|||
} else {
|
||||
null
|
||||
}
|
||||
val listState = rememberLazyListState()
|
||||
val txHistoryComponentState by txHistoryComponent?.txHistoryState?.collectAsStateWithLifecycle()
|
||||
val betweenItemsPadding = TangemTheme.dimens.spacing12
|
||||
val horizontalPadding = TangemTheme.dimens.spacing16
|
||||
val itemModifier = Modifier
|
||||
|
|
@ -69,6 +80,7 @@ internal fun TokenDetailsScreen(state: TokenDetailsState, tokenMarketBlockCompon
|
|||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
state = listState,
|
||||
contentPadding = PaddingValues(
|
||||
bottom = TangemTheme.dimens.spacing16 + bottomBarHeight,
|
||||
),
|
||||
|
|
@ -145,9 +157,12 @@ internal fun TokenDetailsScreen(state: TokenDetailsState, tokenMarketBlockCompon
|
|||
)
|
||||
|
||||
txHistoryItems(
|
||||
state = state.txHistoryState,
|
||||
isBalanceHidden = state.isBalanceHidden,
|
||||
listState = listState,
|
||||
txHistoryComponent = txHistoryComponent,
|
||||
txHistoryComponentState = txHistoryComponentState,
|
||||
txHistoryState = state.txHistoryState,
|
||||
txHistoryItems = txHistoryItems,
|
||||
isBalanceHidden = state.isBalanceHidden,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -170,6 +185,28 @@ internal fun TokenDetailsScreen(state: TokenDetailsState, tokenMarketBlockCompon
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
private fun LazyListScope.txHistoryItems(
|
||||
listState: LazyListState,
|
||||
txHistoryComponent: TxHistoryComponent?,
|
||||
txHistoryComponentState: TxHistoryUM?,
|
||||
txHistoryState: TxHistoryState,
|
||||
txHistoryItems: LazyPagingItems<TxHistoryState.TxHistoryItemState>?,
|
||||
isBalanceHidden: Boolean,
|
||||
) {
|
||||
if (txHistoryComponent != null && txHistoryComponentState != null) {
|
||||
with(txHistoryComponent) { txHistoryContent(listState = listState, state = txHistoryComponentState) }
|
||||
} else {
|
||||
txHistoryItems(
|
||||
state = txHistoryState,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
txHistoryItems = txHistoryItems,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private inline operator fun <T> State<T>?.getValue(thisObj: Any?, property: KProperty<*>): T? = this?.value
|
||||
|
||||
// region Preview
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
|
|
@ -181,6 +218,7 @@ private fun TokenDetailsScreenPreview(
|
|||
TokenDetailsScreen(
|
||||
state = state,
|
||||
tokenMarketBlockComponent = null,
|
||||
txHistoryComponent = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue