Updated on 2026-08-14
This commit is contained in:
parent
7095ceec0f
commit
82506a1c9c
29 changed files with 239 additions and 997 deletions
|
|
@ -1,25 +1,19 @@
|
|||
package com.tangem.feature.swap.choosetoken.api
|
||||
package com.tangem.features.commonfeatures.api.choosetoken
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.account.AccountStatus
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenBridgeInternal.SearchQuery
|
||||
import com.tangem.feature.swap.choosetoken.api.model.ChooseTokenPortfolioFullBlockUM
|
||||
import com.tangem.feature.swap.domain.models.ui.CurrenciesGroup
|
||||
import com.tangem.feature.swap.presentation.R
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.model.ChooseTokenPortfolioFullBlockUM
|
||||
import com.tangem.features.commonfeatures.api.R
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
// todo swap move to common-features module
|
||||
interface ChooseTokenBridge : ChooseTokenBridgeLegacy, ChooseTokenBridgeInternal {
|
||||
interface ChooseTokenBridge : ChooseTokenBridgeInternal {
|
||||
|
||||
val onCurrencyChosen: Channel<ChooseTokenResult>
|
||||
val onClose: Channel<Unit>
|
||||
|
|
@ -84,33 +78,6 @@ interface ChooseTokenBridgeInternal {
|
|||
}
|
||||
}
|
||||
|
||||
// todo swap legacy api, remove
|
||||
interface ChooseTokenBridgeLegacy : ChooseTokenBridgeInternal {
|
||||
|
||||
val onTokenSelected: Channel<ChooseTokenResultOld>
|
||||
val onNewTokenAdded: Channel<Pair<CryptoCurrency, ChooseTokenAnalyticsPayload.IsSearched>>
|
||||
|
||||
val currenciesGroup: Flow<CurrenciesGroup>
|
||||
|
||||
fun onTokenSelected(result: ChooseTokenResultOld) {
|
||||
onTokenSelected.trySend(result)
|
||||
onSearchQuery(SearchQuery.Empty)
|
||||
}
|
||||
|
||||
fun onNewTokenAdded(addedToken: Pair<CryptoCurrency, ChooseTokenAnalyticsPayload.IsSearched>) {
|
||||
onNewTokenAdded.trySend(addedToken)
|
||||
onSearchQuery(SearchQuery.Empty)
|
||||
}
|
||||
|
||||
fun updateCurrenciesGroup(currenciesGroup: CurrenciesGroup)
|
||||
}
|
||||
|
||||
data class ChooseTokenResultOld(
|
||||
val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
val account: Account,
|
||||
val isSearched: Boolean,
|
||||
)
|
||||
|
||||
data class ChooseTokenResult(
|
||||
val currency: CryptoCurrencyStatus,
|
||||
val account: AccountStatus,
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
package com.tangem.feature.swap.choosetoken.api
|
||||
package com.tangem.features.commonfeatures.api.choosetoken
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
|
||||
internal interface ChooseTokenComponent : ComposableContentComponent {
|
||||
interface ChooseTokenComponent : ComposableContentComponent {
|
||||
|
||||
data class Params(
|
||||
val bridge: ChooseTokenBridge,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.swap.choosetoken.api.model
|
||||
package com.tangem.features.commonfeatures.api.choosetoken.model
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
|
|
@ -18,8 +18,6 @@ tasks.withType<Test>().configureEach {
|
|||
dependencies {
|
||||
/** Api */
|
||||
implementation(projects.features.commonFeatures.api)
|
||||
// todo swap delete after move portfolio selector
|
||||
implementation(projects.features.account.api)
|
||||
implementation(projects.features.wallet.api)
|
||||
implementation(projects.features.tokenRecieve.api)
|
||||
|
||||
|
|
@ -57,6 +55,7 @@ dependencies {
|
|||
|
||||
/** Common */
|
||||
implementation(projects.common.ui)
|
||||
implementation(projects.common.uiCharts)
|
||||
implementation(projects.common.uiMarkets)
|
||||
implementation(projects.common.routing)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,17 @@
|
|||
package com.tangem.feature.swap.choosetoken.impl
|
||||
package com.tangem.features.commonfeatures.impl.choosetoken
|
||||
|
||||
import com.tangem.domain.models.account.AccountStatus
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenAnalyticsPayload
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenBridge
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenBridge.Settings
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenBridgeInternal.SearchQuery
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenResult
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenResultOld
|
||||
import com.tangem.feature.swap.choosetoken.api.model.ChooseTokenPortfolioFullBlockUM
|
||||
import com.tangem.feature.swap.choosetoken.impl.model.ChooseTokenModel.Companion.DEBOUNCE_SEARCH_DELAY
|
||||
import com.tangem.feature.swap.choosetoken.impl.model.PortfolioFullBlockDelegate
|
||||
import com.tangem.feature.swap.choosetoken.impl.model.PortfolioListBlockDelegate
|
||||
import com.tangem.feature.swap.domain.models.ui.CurrenciesGroup
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenAnalyticsPayload
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridge
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridge.Settings
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridgeInternal.SearchQuery
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenResult
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.model.ChooseTokenPortfolioFullBlockUM
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.model.PortfolioFullBlockDelegate
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.model.PortfolioListBlockDelegate
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.model.ChooseTokenModel
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -31,14 +28,11 @@ internal class DefaultChooseTokenBridge @AssistedInject constructor(
|
|||
) : ChooseTokenBridge {
|
||||
|
||||
override val onCurrencyChosen: Channel<ChooseTokenResult> = Channel()
|
||||
|
||||
override val onTokenSelected: Channel<ChooseTokenResultOld> = Channel()
|
||||
override val onNewTokenAdded: Channel<Pair<CryptoCurrency, ChooseTokenAnalyticsPayload.IsSearched>> = Channel()
|
||||
override val onClose: Channel<Unit> = Channel()
|
||||
|
||||
private val onSearchQuery: Channel<SearchQuery> = Channel()
|
||||
override val searchQueryState: StateFlow<SearchQuery> = onSearchQuery.receiveAsFlow()
|
||||
.debounce(DEBOUNCE_SEARCH_DELAY)
|
||||
.debounce(ChooseTokenModel.Companion.DEBOUNCE_SEARCH_DELAY)
|
||||
.stateIn(modelScope, SharingStarted.Eagerly, initialValue = SearchQuery.Empty)
|
||||
|
||||
private val portfolioListBlockDelegate: PortfolioListBlockDelegate = portfolioListBlockDelegateFactory.create(
|
||||
|
|
@ -59,9 +53,6 @@ internal class DefaultChooseTokenBridge @AssistedInject constructor(
|
|||
override val fullPortfolioBlock: StateFlow<ChooseTokenPortfolioFullBlockUM?>
|
||||
get() = portfolioFullBlockDelegate.fullPortfolioBlock
|
||||
|
||||
private val _currenciesGroupFlow = MutableStateFlow<CurrenciesGroup?>(null)
|
||||
override val currenciesGroup: Flow<CurrenciesGroup> = _currenciesGroupFlow.filterNotNull()
|
||||
|
||||
init {
|
||||
portfolioListBlockDelegate.onTokenChosen.receiveAsFlow()
|
||||
.onEach { chooseResult -> onCurrencyChosen(chooseResult) }
|
||||
|
|
@ -86,10 +77,6 @@ internal class DefaultChooseTokenBridge @AssistedInject constructor(
|
|||
onSearchQuery(SearchQuery.Empty)
|
||||
}
|
||||
|
||||
override fun updateCurrenciesGroup(currenciesGroup: CurrenciesGroup) {
|
||||
_currenciesGroupFlow.update { currenciesGroup }
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : ChooseTokenBridge.Factory {
|
||||
override fun create(
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.swap.choosetoken.impl
|
||||
package com.tangem.features.commonfeatures.impl.choosetoken
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
|
|
@ -10,16 +10,16 @@ import com.arkivanov.decompose.router.slot.childSlot
|
|||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.decompose.navigation.Route
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenComponent
|
||||
import com.tangem.feature.swap.choosetoken.impl.model.ChooseTokenModel
|
||||
import com.tangem.feature.swap.choosetoken.impl.ui.ChooseTokenScreen
|
||||
import com.tangem.feature.swap.models.AddToPortfolioRoute
|
||||
import com.tangem.feature.swap.ui.SwapSelectTokenScreen
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenComponent
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.model.ChooseTokenModel
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.ui.ChooseTokenScreen
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioComponent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
internal class DefaultChooseTokenComponent @AssistedInject constructor(
|
||||
private val addToPortfolioComponentFactory: AddToPortfolioComponent.Factory,
|
||||
|
|
@ -39,15 +39,7 @@ internal class DefaultChooseTokenComponent @AssistedInject constructor(
|
|||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val stateOld by model.stateOld.collectAsStateWithLifecycle()
|
||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||
stateOld?.let { stateHolder ->
|
||||
SwapSelectTokenScreen(state = stateHolder, onBack = { model.onBackClicked() })
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
// if old shown we should not show new screen
|
||||
return
|
||||
}
|
||||
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
ChooseTokenScreen(state = state)
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
|
|
@ -74,4 +66,7 @@ internal class DefaultChooseTokenComponent @AssistedInject constructor(
|
|||
private companion object {
|
||||
const val BOTTOM_SHEET_SLOT_KEY = "choosePortfolioTokenBottomSheetSlot"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
internal data object AddToPortfolioRoute : Route
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.swap.choosetoken.api
|
||||
package com.tangem.features.commonfeatures.impl.choosetoken
|
||||
|
||||
import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
|
|
@ -10,7 +10,6 @@ import kotlinx.coroutines.flow.distinctUntilChanged
|
|||
import kotlinx.coroutines.flow.first
|
||||
import javax.inject.Inject
|
||||
|
||||
// todo swap move to some common module
|
||||
class SettingContextUseCase @Inject constructor(
|
||||
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.swap.choosetoken.impl.converter
|
||||
package com.tangem.features.commonfeatures.impl.choosetoken.converter
|
||||
|
||||
import com.tangem.common.ui.account.AccountCryptoPortfolioItemStateConverter
|
||||
import com.tangem.common.ui.account.TokensListPortfolioItemConverter
|
||||
|
|
@ -23,11 +23,11 @@ import com.tangem.domain.models.account.AccountStatus
|
|||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.tokenlist.TokenList
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenBridgeInternal.SearchQuery
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenBridgeInternal.SearchQuery.Companion.isSearchingState
|
||||
import com.tangem.feature.swap.choosetoken.api.model.TokenListUMData
|
||||
import com.tangem.feature.swap.choosetoken.impl.model.ClickIntents
|
||||
import com.tangem.feature.swap.presentation.R
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridgeInternal.SearchQuery
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridgeInternal.SearchQuery.Companion.isSearchingState
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.model.TokenListUMData
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.model.ClickIntents
|
||||
import com.tangem.features.commonfeatures.impl.R
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
internal class ChooseTokenListItemConverter(
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.feature.swap.choosetoken.impl.converter
|
||||
package com.tangem.features.commonfeatures.impl.choosetoken.converter
|
||||
|
||||
import com.tangem.feature.swap.choosetoken.impl.ui.ChooseTokenInitialUM
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.ui.ChooseTokenInitialUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class SearchBarToggleTransformer(private val isActive: Boolean) : Transformer<ChooseTokenInitialUM> {
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.feature.swap.choosetoken.impl.converter
|
||||
package com.tangem.features.commonfeatures.impl.choosetoken.converter
|
||||
|
||||
import com.tangem.feature.swap.choosetoken.impl.ui.ChooseTokenInitialUM
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.ui.ChooseTokenInitialUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class SearchBarUpdateQueryTransformer(private val newQuery: String) : Transformer<ChooseTokenInitialUM> {
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
package com.tangem.feature.swap.choosetoken.impl.di
|
||||
package com.tangem.features.commonfeatures.impl.choosetoken.di
|
||||
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenBridge
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenComponent
|
||||
import com.tangem.feature.swap.choosetoken.impl.DefaultChooseTokenBridge
|
||||
import com.tangem.feature.swap.choosetoken.impl.DefaultChooseTokenComponent
|
||||
import com.tangem.feature.swap.choosetoken.impl.model.ChooseTokenModel
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridge
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenComponent
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.DefaultChooseTokenBridge
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.DefaultChooseTokenComponent
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.model.ChooseTokenModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
package com.tangem.feature.swap.models.market
|
||||
package com.tangem.features.commonfeatures.impl.choosetoken.market
|
||||
|
||||
import com.tangem.common.ui.markets.models.MarketsListItemUM
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.markets.*
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.feature.swap.models.market.converter.SwapMarketsTokenItemConverter
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.market.converter.SwapMarketsTokenItemConverter
|
||||
import com.tangem.pagination.Batch
|
||||
import com.tangem.pagination.BatchAction
|
||||
import com.tangem.pagination.PaginationStatus
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.swap.models.market.converter
|
||||
package com.tangem.features.commonfeatures.impl.choosetoken.market.converter
|
||||
|
||||
import com.tangem.common.ui.charts.state.MarketChartData
|
||||
import com.tangem.common.ui.charts.state.MarketChartRawData
|
||||
|
|
@ -16,7 +16,7 @@ import com.tangem.core.ui.format.bigdecimal.percent
|
|||
import com.tangem.core.ui.format.bigdecimal.price
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.markets.TokenMarket
|
||||
import com.tangem.feature.swap.presentation.R
|
||||
import com.tangem.features.commonfeatures.impl.R
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import java.math.BigDecimal
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.swap.models.market.state
|
||||
package com.tangem.features.commonfeatures.impl.choosetoken.market.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.common.ui.markets.models.MarketsListItemUM
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.swap.choosetoken.impl.model
|
||||
package com.tangem.features.commonfeatures.impl.choosetoken.model
|
||||
|
||||
import com.arkivanov.decompose.router.slot.dismiss
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
|
|
@ -6,18 +6,18 @@ import com.tangem.core.decompose.model.Model
|
|||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.feature.swap.choosetoken.api.*
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenBridgeInternal.SearchQuery
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenBridgeInternal.SearchQuery.Companion.isSearchingState
|
||||
import com.tangem.feature.swap.choosetoken.impl.converter.SearchBarToggleTransformer
|
||||
import com.tangem.feature.swap.choosetoken.impl.converter.SearchBarUpdateQueryTransformer
|
||||
import com.tangem.feature.swap.choosetoken.impl.ui.ChooseTokenFullUM
|
||||
import com.tangem.feature.swap.choosetoken.impl.ui.ChooseTokenInitialUM
|
||||
import com.tangem.feature.swap.converters.TokensDataConverter
|
||||
import com.tangem.feature.swap.models.SwapSelectTokenStateHolder
|
||||
import com.tangem.feature.swap.models.market.state.SwapMarketState
|
||||
import com.tangem.feature.swap.presentation.R
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenAnalyticsPayload
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridge
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridgeInternal.SearchQuery
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridgeInternal.SearchQuery.Companion.isSearchingState
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenComponent
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenResult
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.converter.SearchBarToggleTransformer
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.converter.SearchBarUpdateQueryTransformer
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.ui.ChooseTokenFullUM
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.ui.ChooseTokenInitialUM
|
||||
import com.tangem.features.commonfeatures.api.R
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.market.state.SwapMarketState
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
import javax.inject.Inject
|
||||
|
|
@ -26,7 +26,6 @@ import javax.inject.Inject
|
|||
@ModelScoped
|
||||
internal class ChooseTokenModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val settingContextUseCase: SettingContextUseCase,
|
||||
marketBlockDelegateFactory: MarketBlockDelegate.Factory,
|
||||
paramsContainer: ParamsContainer,
|
||||
) : Model() {
|
||||
|
|
@ -52,10 +51,6 @@ internal class ChooseTokenModel @Inject constructor(
|
|||
flowOf(null)
|
||||
}
|
||||
|
||||
private val expandedAccountsFlow: MutableStateFlow<Map<AccountId, Boolean>> = MutableStateFlow(emptyMap())
|
||||
|
||||
val stateOld: StateFlow<SwapSelectTokenStateHolder?> = combineUIOld()
|
||||
|
||||
private val initialState: MutableStateFlow<ChooseTokenInitialUM> = MutableStateFlow(getInitState())
|
||||
val state: StateFlow<ChooseTokenFullUM> = combine(
|
||||
flow = initialState,
|
||||
|
|
@ -85,8 +80,6 @@ internal class ChooseTokenModel @Inject constructor(
|
|||
addToPortfolioManager.onSuccessAdded.receiveAsFlow()
|
||||
.onEach { addedResult ->
|
||||
val isSearched = ChooseTokenAnalyticsPayload.IsSearched(isSearchingState)
|
||||
val newToken = addedResult.addedCurrency.currency to isSearched
|
||||
bridge.onNewTokenAdded(newToken)
|
||||
val chooseTokenResult = ChooseTokenResult(
|
||||
currency = addedResult.addedCurrency,
|
||||
account = addedResult.account,
|
||||
|
|
@ -99,46 +92,6 @@ internal class ChooseTokenModel @Inject constructor(
|
|||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
private fun combineUIOld(): StateFlow<SwapSelectTokenStateHolder?> = combine(
|
||||
flow = bridge.currenciesGroup,
|
||||
flow2 = settingContextUseCase.invoke(),
|
||||
flow3 = marketsStateFlow,
|
||||
flow4 = expandedAccountsFlow,
|
||||
transform = { currenciesGroup, settingContext, marketState, expandedAccounts ->
|
||||
val isAccountsMode = settingContext.isAccountsMode
|
||||
val appCurrency = settingContext.appCurrency
|
||||
val isBalanceHidden = settingContext.isBalanceHidden
|
||||
|
||||
TokensDataConverter(
|
||||
onSearchEntered = { query -> bridge.onSearchQuery(query) },
|
||||
onTokenClick = { account, cryptoCurrencyStatus ->
|
||||
val result = ChooseTokenResultOld(
|
||||
account = account,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
isSearched = searchQueryState.isSearchingState,
|
||||
)
|
||||
bridge.onTokenSelected(result)
|
||||
},
|
||||
onAccountClick = { account ->
|
||||
expandedAccountsFlow.update { expandedList ->
|
||||
val hasSavedAccount = expandedList[account.accountId]
|
||||
val isExpanded = hasSavedAccount == true
|
||||
expandedList + (account.accountId to !isExpanded)
|
||||
}
|
||||
},
|
||||
expandedAccounts = expandedAccounts,
|
||||
tokensDataState = currenciesGroup,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
isAccountsMode = isAccountsMode,
|
||||
appCurrency = appCurrency,
|
||||
marketState = requireNotNull(marketState),
|
||||
).transform()
|
||||
},
|
||||
)
|
||||
.flowOn(dispatchers.default)
|
||||
.stateIn(modelScope, SharingStarted.Eagerly, initialValue = null)
|
||||
|
||||
fun onBackClicked() {
|
||||
bridge.onClose()
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.swap.choosetoken.impl.model
|
||||
package com.tangem.features.commonfeatures.impl.choosetoken.model
|
||||
|
||||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
|
|
@ -14,12 +14,12 @@ import com.tangem.domain.markets.toSerializableParam
|
|||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenBridgeInternal.SearchQuery
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenBridgeInternal.SearchQuery.Companion.isSearchingState
|
||||
import com.tangem.feature.swap.models.AddToPortfolioRoute
|
||||
import com.tangem.feature.swap.models.market.MarketsListBatchFlowManager
|
||||
import com.tangem.feature.swap.models.market.state.SwapMarketState
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridgeInternal.SearchQuery
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridgeInternal.SearchQuery.Companion.isSearchingState
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioManager
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.AddToPortfolioRoute
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.market.MarketsListBatchFlowManager
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.market.state.SwapMarketState
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
import com.tangem.utils.Provider
|
||||
import dagger.assisted.Assisted
|
||||
|
|
@ -27,6 +27,9 @@ import dagger.assisted.AssistedFactory
|
|||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlin.collections.filter
|
||||
import kotlin.collections.map
|
||||
import kotlin.collections.orEmpty
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class MarketBlockDelegate @AssistedInject constructor(
|
||||
|
|
@ -1,19 +1,20 @@
|
|||
package com.tangem.feature.swap.choosetoken.impl.model
|
||||
package com.tangem.features.commonfeatures.impl.choosetoken.model
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.models.wallet.isLocked
|
||||
import com.tangem.domain.models.wallet.isMultiCurrency
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenBridgeInternal.SearchQuery
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenBridgeInternal.SearchQuery.Companion.isSearchingState
|
||||
import com.tangem.feature.swap.choosetoken.api.SettingContextUseCase
|
||||
import com.tangem.feature.swap.choosetoken.api.model.ChooseTokenPortfolioFullBlockUM
|
||||
import com.tangem.feature.swap.choosetoken.api.model.WalletListUM
|
||||
import com.tangem.feature.swap.choosetoken.api.model.WalletTabUM
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridgeInternal.SearchQuery
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridgeInternal.SearchQuery.Companion.isSearchingState
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.model.ChooseTokenPortfolioFullBlockUM
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.model.WalletListUM
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.model.WalletTabUM
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.SettingContextUseCase
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
|
|
@ -60,8 +61,10 @@ internal class PortfolioFullBlockDelegate @AssistedInject constructor(
|
|||
}
|
||||
|
||||
private fun buildFlow() = flow {
|
||||
val walletsFlow = getWalletsUseCase.invokeAsMap()
|
||||
.map { wallets -> wallets.filterNot { (_, wallet) -> wallet.isLocked } }
|
||||
val fullPortfolioBlockFlow = combine(
|
||||
flow = getWalletsUseCase.invokeAsMap(),
|
||||
flow = walletsFlow,
|
||||
flow2 = portfolioListBlockDelegate.portfolioList,
|
||||
flow3 = selectedWalletFlow.map { wallet -> wallet.walletId }.distinctUntilChanged(),
|
||||
flow4 = settingContextUseCase.invoke(),
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.swap.choosetoken.impl.model
|
||||
package com.tangem.features.commonfeatures.impl.choosetoken.model
|
||||
|
||||
import com.tangem.common.ui.tokens.TokenConverterParams
|
||||
import com.tangem.domain.account.models.AccountStatusList
|
||||
|
|
@ -11,14 +11,14 @@ import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
|||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenAnalyticsPayload
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenBridge
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenBridgeInternal.SearchQuery
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenBridgeInternal.SearchQuery.Companion.isSearchingState
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenResult
|
||||
import com.tangem.feature.swap.choosetoken.api.SettingContextUseCase
|
||||
import com.tangem.feature.swap.choosetoken.api.model.TokenListUMData
|
||||
import com.tangem.feature.swap.choosetoken.impl.converter.ChooseTokenListItemConverter
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenAnalyticsPayload
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridge
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridgeInternal.SearchQuery
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridgeInternal.SearchQuery.Companion.isSearchingState
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenResult
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.model.TokenListUMData
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.SettingContextUseCase
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.converter.ChooseTokenListItemConverter
|
||||
import com.tangem.utils.extensions.mapNotNullValues
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.swap.choosetoken.impl.ui
|
||||
package com.tangem.features.commonfeatures.impl.choosetoken.ui
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
|
|
@ -45,14 +45,12 @@ import com.tangem.core.ui.test.BuyTokenScreenTestTags
|
|||
import com.tangem.core.ui.utils.TangemSharedTransitionLayout
|
||||
import com.tangem.core.ui.utils.lazyListItemPosition
|
||||
import com.tangem.core.ui.utils.rememberHideKeyboardNestedScrollConnection
|
||||
import com.tangem.feature.swap.choosetoken.api.model.ChooseTokenPortfolioFullBlockUM
|
||||
import com.tangem.feature.swap.choosetoken.api.model.TokenListUMData
|
||||
import com.tangem.feature.swap.choosetoken.api.model.WalletListUM
|
||||
import com.tangem.feature.swap.choosetoken.api.model.WalletTabUM
|
||||
import com.tangem.feature.swap.models.market.state.SwapMarketState
|
||||
import com.tangem.feature.swap.presentation.R
|
||||
import com.tangem.feature.swap.ui.market.swapMarketsListItems
|
||||
import com.tangem.feature.swap.ui.preview.SwapSelectTokenPreviewProvider
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.model.ChooseTokenPortfolioFullBlockUM
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.model.TokenListUMData
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.model.WalletListUM
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.model.WalletTabUM
|
||||
import com.tangem.features.commonfeatures.impl.R
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.market.state.SwapMarketState
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
|
@ -254,7 +252,8 @@ private fun WalletTabItem(state: WalletTabUM, modifier: Modifier = Modifier) {
|
|||
style = TangemTheme.typography.button,
|
||||
)
|
||||
|
||||
if (state.count != null) {
|
||||
val count = state.count
|
||||
if (count != null) {
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
|
||||
Box(
|
||||
|
|
@ -265,7 +264,7 @@ private fun WalletTabItem(state: WalletTabUM, modifier: Modifier = Modifier) {
|
|||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text(
|
||||
text = state.count.resolveReference(),
|
||||
text = count.resolveReference(),
|
||||
color = countTextColor,
|
||||
style = TangemTheme.typography.caption1,
|
||||
)
|
||||
|
|
@ -483,7 +482,7 @@ private class ChooseTokenScreenPreviewProvider : PreviewParameterProvider<Choose
|
|||
accounts.size,
|
||||
),
|
||||
),
|
||||
marketsBlock = SwapSelectTokenPreviewProvider.defaultState.marketsState,
|
||||
marketsBlock = SwapSelectTokenPreviewProvider.marketState,
|
||||
),
|
||||
ChooseTokenFullUM(
|
||||
initialUM = initialUM,
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
package com.tangem.feature.swap.choosetoken.impl.ui
|
||||
package com.tangem.features.commonfeatures.impl.choosetoken.ui
|
||||
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.feature.swap.choosetoken.api.model.ChooseTokenPortfolioFullBlockUM
|
||||
import com.tangem.feature.swap.models.market.state.SwapMarketState
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.model.ChooseTokenPortfolioFullBlockUM
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.market.state.SwapMarketState
|
||||
|
||||
internal data class ChooseTokenFullUM(
|
||||
val initialUM: ChooseTokenInitialUM,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.swap.ui.market
|
||||
package com.tangem.features.commonfeatures.impl.choosetoken.ui
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
|
|
@ -17,8 +17,8 @@ import com.tangem.core.ui.decorations.roundedShapeItemDecoration
|
|||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.swap.models.market.state.SwapMarketState
|
||||
import com.tangem.feature.swap.presentation.R
|
||||
import com.tangem.features.commonfeatures.impl.R
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.market.state.SwapMarketState
|
||||
|
||||
internal fun LazyListScope.swapMarketsListItems(state: SwapMarketState) {
|
||||
item {
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
package com.tangem.features.commonfeatures.impl.choosetoken.ui
|
||||
|
||||
import com.tangem.common.ui.charts.state.MarketChartRawData
|
||||
import com.tangem.common.ui.markets.models.MarketsListItemUM
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.market.state.SwapMarketState
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal object SwapSelectTokenPreviewProvider {
|
||||
|
||||
private const val CHART_VALUE_1 = 0.4
|
||||
private const val CHART_VALUE_2 = 0.2
|
||||
private const val CHART_VALUE_3 = 0.1
|
||||
private const val CHART_VALUE_4 = 2.0
|
||||
private const val CHART_VALUE_5 = 5.0
|
||||
private const val CHART_VALUE_6 = 3.0
|
||||
private const val TOTAL_ITEMS = 322
|
||||
|
||||
private val PREVIEW_CHART_DATA = MarketChartRawData(
|
||||
y = persistentListOf(
|
||||
CHART_VALUE_1,
|
||||
CHART_VALUE_2,
|
||||
CHART_VALUE_1,
|
||||
CHART_VALUE_3,
|
||||
CHART_VALUE_1,
|
||||
CHART_VALUE_4,
|
||||
CHART_VALUE_5,
|
||||
CHART_VALUE_3,
|
||||
CHART_VALUE_4,
|
||||
CHART_VALUE_4,
|
||||
CHART_VALUE_6,
|
||||
),
|
||||
)
|
||||
|
||||
val marketState = SwapMarketState.Content(
|
||||
items = createPreviewMarketItems(),
|
||||
loadMore = { },
|
||||
onItemClick = { },
|
||||
visibleIdsChanged = { },
|
||||
total = TOTAL_ITEMS,
|
||||
marketsTitle = TextReference.Res(R.string.feed_trending_now),
|
||||
shouldAssetsCount = false,
|
||||
)
|
||||
|
||||
private fun createPreviewMarketItems() = listOf(
|
||||
createMarketItem(
|
||||
id = "1",
|
||||
iconUrl = "",
|
||||
ratingPosition = "10",
|
||||
marketCap = "$6.233 B",
|
||||
trendType = PriceChangeType.UP,
|
||||
chartData = PREVIEW_CHART_DATA,
|
||||
),
|
||||
createMarketItem(
|
||||
id = "2",
|
||||
ratingPosition = "10",
|
||||
marketCap = "$6.233 B",
|
||||
trendType = PriceChangeType.NEUTRAL,
|
||||
chartData = null,
|
||||
),
|
||||
createMarketItem(
|
||||
id = "3",
|
||||
name = "Bitcoin Bitcoin Bitcoin Bitcoin Bitcoin Bitcoin Bitcoin",
|
||||
ratingPosition = "10",
|
||||
marketCap = "$6.23348172384781234 B",
|
||||
trendType = PriceChangeType.DOWN,
|
||||
chartData = PREVIEW_CHART_DATA,
|
||||
),
|
||||
createMarketItem(
|
||||
id = "4",
|
||||
ratingPosition = "10",
|
||||
marketCap = null,
|
||||
trendType = PriceChangeType.UP,
|
||||
chartData = PREVIEW_CHART_DATA,
|
||||
),
|
||||
createMarketItem(
|
||||
id = "5",
|
||||
ratingPosition = null,
|
||||
marketCap = "$6.233 B",
|
||||
trendType = PriceChangeType.UP,
|
||||
chartData = PREVIEW_CHART_DATA,
|
||||
),
|
||||
createMarketItem(
|
||||
id = "6",
|
||||
ratingPosition = null,
|
||||
marketCap = null,
|
||||
trendType = PriceChangeType.UP,
|
||||
chartData = PREVIEW_CHART_DATA,
|
||||
),
|
||||
).toImmutableList()
|
||||
|
||||
private fun createMarketItem(
|
||||
id: String,
|
||||
name: String = "Bitcoin",
|
||||
iconUrl: String? = null,
|
||||
ratingPosition: String?,
|
||||
marketCap: String?,
|
||||
trendType: PriceChangeType,
|
||||
chartData: MarketChartRawData?,
|
||||
) = MarketsListItemUM(
|
||||
id = CryptoCurrency.RawID(id),
|
||||
name = name,
|
||||
currencySymbol = "BTC",
|
||||
iconUrl = iconUrl,
|
||||
ratingPosition = ratingPosition,
|
||||
marketCap = marketCap,
|
||||
price = MarketsListItemUM.Price(
|
||||
text = "31 285.72$",
|
||||
annotated = stringReference("31 285.72$"),
|
||||
fiatPrice = BigDecimal("123123"),
|
||||
),
|
||||
trendPercentText = "12.43%",
|
||||
trendType = trendType,
|
||||
chartData = chartData,
|
||||
isUnder100kMarketCap = false,
|
||||
stakingRate = stringReference("APY 12.34%"),
|
||||
updateTimestamp = 0,
|
||||
)
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ import com.tangem.core.ui.extensions.wrappedList
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.isHotWallet
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenComponent
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenComponent
|
||||
import com.tangem.feature.swap.component.SwapFeeSelectorBlockComponent
|
||||
import com.tangem.feature.swap.model.SwapModel
|
||||
import com.tangem.feature.swap.models.SwapPermissionUM
|
||||
|
|
|
|||
|
|
@ -1,81 +0,0 @@
|
|||
package com.tangem.feature.swap.converters
|
||||
|
||||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.feature.swap.choosetoken.api.model.TokenListUMData
|
||||
import com.tangem.feature.swap.domain.models.ui.CurrenciesGroup
|
||||
import com.tangem.feature.swap.models.SwapSelectTokenStateHolder
|
||||
import com.tangem.feature.swap.models.market.state.SwapMarketState
|
||||
import com.tangem.feature.swap.presentation.R
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.plus
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class TokensDataConverter(
|
||||
onTokenClick: (Account, CryptoCurrencyStatus) -> Unit,
|
||||
onAccountClick: (Account) -> Unit,
|
||||
private val expandedAccounts: Map<AccountId, Boolean>,
|
||||
private val onSearchEntered: (String) -> Unit,
|
||||
private val tokensDataState: CurrenciesGroup,
|
||||
private val isBalanceHidden: Boolean,
|
||||
private val isAccountsMode: Boolean,
|
||||
private val appCurrency: AppCurrency,
|
||||
private val marketState: SwapMarketState,
|
||||
) {
|
||||
|
||||
private val accountListItemConverter = AccountTokenItemConverter(
|
||||
appCurrency = appCurrency,
|
||||
unavailableErrorText = resourceReference(R.string.tokens_list_unavailable_to_swap_source_header),
|
||||
onTokenItemClick = onTokenClick,
|
||||
onAccountItemClick = onAccountClick,
|
||||
expandedAccounts = expandedAccounts,
|
||||
)
|
||||
|
||||
fun transform(): SwapSelectTokenStateHolder {
|
||||
val accountList = tokensDataState.accountCurrencyList
|
||||
return SwapSelectTokenStateHolder(
|
||||
tokensListData = if (isAccountsMode) {
|
||||
val portfolioList = accountListItemConverter.convertList(accountList).toPersistentList()
|
||||
val totalTokensCount = portfolioList.sumOf { it.tokens.size }
|
||||
if (totalTokensCount > 0) {
|
||||
TokenListUMData.AccountList(
|
||||
tokensList = portfolioList,
|
||||
totalTokensCount = totalTokensCount,
|
||||
)
|
||||
} else {
|
||||
TokenListUMData.EmptyList
|
||||
}
|
||||
} else {
|
||||
val tokensList = accountList.flatMap { (_, currencyList) ->
|
||||
currencyList.asSequence().map { accountSwapCurrency ->
|
||||
accountListItemConverter.createAvailableItemConverter(accountSwapCurrency.account)
|
||||
.convert(accountSwapCurrency.cryptoCurrencyStatus)
|
||||
}.map(TokensListItemUM::Token).toPersistentList()
|
||||
}.toPersistentList()
|
||||
|
||||
if (tokensList.isNotEmpty()) {
|
||||
TokenListUMData.TokenList(
|
||||
tokensList = persistentListOf(
|
||||
TokensListItemUM.GroupTitle(
|
||||
id = "available_tokens_title",
|
||||
text = resourceReference(R.string.exchange_tokens_available_tokens_header),
|
||||
),
|
||||
) + tokensList,
|
||||
totalTokensCount = tokensList.size,
|
||||
)
|
||||
} else {
|
||||
TokenListUMData.EmptyList
|
||||
}
|
||||
},
|
||||
marketsState = marketState,
|
||||
onSearchEntered = onSearchEntered,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
isAfterSearch = tokensDataState.isAfterSearch,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -69,9 +69,9 @@ import com.tangem.domain.transaction.usecase.gasless.IsGaslessFeeSupportedForNet
|
|||
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
|
||||
import com.tangem.feature.swap.analytics.SwapEvents
|
||||
import com.tangem.feature.swap.analytics.SwapQuotePerformanceTracker
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenAnalyticsPayload
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenBridge
|
||||
import com.tangem.feature.swap.choosetoken.api.ChooseTokenResult
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenAnalyticsPayload
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridge
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenResult
|
||||
import com.tangem.feature.swap.component.SwapFeeSelectorBlockComponent
|
||||
import com.tangem.feature.swap.converters.SwapTransactionErrorStateConverter
|
||||
import com.tangem.feature.swap.domain.AllowPermissionsHandler
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
package com.tangem.feature.swap.models
|
||||
|
||||
import com.tangem.core.decompose.navigation.Route
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
internal data object AddToPortfolioRoute : Route
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package com.tangem.feature.swap.models
|
||||
|
||||
import com.tangem.feature.swap.choosetoken.api.model.TokenListUMData
|
||||
import com.tangem.feature.swap.models.market.state.SwapMarketState
|
||||
|
||||
internal data class SwapSelectTokenStateHolder(
|
||||
val marketsState: SwapMarketState,
|
||||
val tokensListData: TokenListUMData,
|
||||
val isBalanceHidden: Boolean,
|
||||
val isAfterSearch: Boolean,
|
||||
val onSearchEntered: (String) -> Unit,
|
||||
)
|
||||
|
||||
internal val SwapSelectTokenStateHolder.isNotFoundState: Boolean
|
||||
get() =
|
||||
tokensListData.tokensList.isEmpty() && isAfterSearch &&
|
||||
marketsState !is SwapMarketState.Content && marketsState !is SwapMarketState.Loading
|
||||
|
||||
internal val SwapSelectTokenStateHolder.isEmptyState: Boolean
|
||||
get() =
|
||||
tokensListData.tokensList.isEmpty() && !isAfterSearch &&
|
||||
marketsState !is SwapMarketState.Content && marketsState !is SwapMarketState.Loading
|
||||
|
|
@ -1,457 +0,0 @@
|
|||
package com.tangem.feature.swap.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.core.*
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.*
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.appbar.ExpandableSearchView
|
||||
import com.tangem.core.ui.components.list.InfiniteListHandler
|
||||
import com.tangem.core.ui.components.tokenlist.PortfolioListItem
|
||||
import com.tangem.core.ui.components.tokenlist.PortfolioTokensListItem
|
||||
import com.tangem.core.ui.components.tokenlist.TokenListItem
|
||||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.BuyTokenScreenTestTags
|
||||
import com.tangem.core.ui.test.MainScreenTestTags
|
||||
import com.tangem.core.ui.utils.lazyListItemPosition
|
||||
import com.tangem.feature.swap.choosetoken.api.model.TokenListUMData
|
||||
import com.tangem.feature.swap.models.SwapSelectTokenStateHolder
|
||||
import com.tangem.feature.swap.models.isEmptyState
|
||||
import com.tangem.feature.swap.models.isNotFoundState
|
||||
import com.tangem.feature.swap.models.market.state.SwapMarketState
|
||||
import com.tangem.feature.swap.presentation.R
|
||||
import com.tangem.feature.swap.ui.market.swapMarketsListItems
|
||||
import com.tangem.feature.swap.ui.preview.SwapSelectTokenPreviewProvider
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
private const val LOAD_MORE_BUFFER = 25
|
||||
|
||||
@Composable
|
||||
internal fun SwapSelectTokenScreen(state: SwapSelectTokenStateHolder, onBack: () -> Unit) {
|
||||
BackHandler(onBack = onBack)
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier
|
||||
.systemBarsPadding()
|
||||
.background(color = TangemTheme.colors.background.secondary),
|
||||
content = { padding ->
|
||||
val modifier = Modifier.padding(padding)
|
||||
when {
|
||||
state.isNotFoundState -> TokensNotFound(modifier)
|
||||
state.isEmptyState -> EmptyTokensList(modifier)
|
||||
state.marketsState != null -> ListOfTokensWithMarkets(
|
||||
state = state,
|
||||
marketsState = state.marketsState,
|
||||
modifier = modifier,
|
||||
)
|
||||
else -> ListOfTokens(state = state, modifier = modifier)
|
||||
}
|
||||
},
|
||||
topBar = {
|
||||
ExpandableSearchView(
|
||||
title = stringResourceSafe(R.string.common_choose_token),
|
||||
onBackClick = onBack,
|
||||
placeholderSearchText = stringResourceSafe(id = R.string.common_search_tokens),
|
||||
onSearchChange = state.onSearchEntered,
|
||||
onSearchDisplayClose = { state.onSearchEntered("") },
|
||||
subtitle = stringResourceSafe(id = R.string.express_exchange_token_list_subtitle),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EmptyTokensList(modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.background(TangemTheme.colors.background.secondary)
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
Column(modifier = Modifier.align(Alignment.Center)) {
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size64)
|
||||
.align(Alignment.CenterHorizontally),
|
||||
painter = painterResource(id = R.drawable.ic_no_token_44),
|
||||
colorFilter = ColorFilter.tint(TangemTheme.colors.icon.inactive),
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(top = TangemTheme.dimens.spacing16)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing30)
|
||||
.align(Alignment.CenterHorizontally),
|
||||
text = stringResourceSafe(id = R.string.exchange_tokens_empty_tokens),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TokensNotFound(modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.background(TangemTheme.colors.background.secondary)
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(top = TangemTheme.dimens.spacing32)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing30)
|
||||
.align(Alignment.TopCenter),
|
||||
text = stringResourceSafe(id = R.string.express_token_list_empty_search),
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ListOfTokens(state: SwapSelectTokenStateHolder, modifier: Modifier = Modifier) {
|
||||
val screenBackgroundColor = TangemTheme.colors.background.secondary
|
||||
|
||||
LazyColumn(
|
||||
modifier = modifier
|
||||
.background(color = screenBackgroundColor)
|
||||
.fillMaxSize()
|
||||
.imePadding(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
tokensListItems(
|
||||
tokensListData = state.tokensListData,
|
||||
isBalanceHidden = state.isBalanceHidden,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ListOfTokensWithMarkets(
|
||||
state: SwapSelectTokenStateHolder,
|
||||
marketsState: SwapMarketState,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val screenBackgroundColor = TangemTheme.colors.background.secondary
|
||||
val lazyListState = rememberLazyListState()
|
||||
|
||||
LazyColumn(
|
||||
modifier = modifier
|
||||
.background(color = screenBackgroundColor)
|
||||
.fillMaxSize()
|
||||
.imePadding(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
state = lazyListState,
|
||||
) {
|
||||
if (state.tokensListData !is TokenListUMData.EmptyList) {
|
||||
assetsTitle(count = state.tokensListData.totalTokensCount, showCount = marketsState.shouldAssetsCount)
|
||||
}
|
||||
|
||||
tokensListItems(
|
||||
tokensListData = state.tokensListData,
|
||||
isBalanceHidden = state.isBalanceHidden,
|
||||
)
|
||||
|
||||
item("spacer_before_markets") {
|
||||
SpacerH(32.dp)
|
||||
}
|
||||
|
||||
swapMarketsListItems(marketsState)
|
||||
}
|
||||
|
||||
(marketsState as? SwapMarketState.Content)?.let { content ->
|
||||
VisibleItemsTracker(
|
||||
lazyListState = lazyListState,
|
||||
marketState = content,
|
||||
)
|
||||
|
||||
InfiniteListHandler(
|
||||
listState = lazyListState,
|
||||
buffer = LOAD_MORE_BUFFER,
|
||||
triggerLoadMoreCheckOnItemsCountChange = true,
|
||||
onLoadMore = remember(content) {
|
||||
{
|
||||
content.loadMore()
|
||||
true
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun VisibleItemsTracker(lazyListState: LazyListState, marketState: SwapMarketState.Content) {
|
||||
val visibleItems by remember {
|
||||
derivedStateOf {
|
||||
lazyListState.layoutInfo.visibleItemsInfo
|
||||
.mapNotNull { itemInfo ->
|
||||
marketState.items.find { it.getComposeKey() == itemInfo.key }?.id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(visibleItems) {
|
||||
marketState.visibleIdsChanged(visibleItems)
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.assetsTitle(count: Int, showCount: Boolean) {
|
||||
item(key = "assets_title") {
|
||||
Text(
|
||||
text = buildAnnotatedString {
|
||||
append(stringResourceSafe(R.string.swap_your_assets_title))
|
||||
if (showCount) {
|
||||
withStyle(SpanStyle(color = TangemTheme.colors.text.tertiary)) {
|
||||
append(" $count")
|
||||
}
|
||||
}
|
||||
},
|
||||
style = TangemTheme.typography.h3,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing16,
|
||||
end = TangemTheme.dimens.spacing16,
|
||||
top = TangemTheme.dimens.spacing12,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.tokensListItems(tokensListData: TokenListUMData, isBalanceHidden: Boolean) {
|
||||
when (tokensListData) {
|
||||
is TokenListUMData.AccountList -> {
|
||||
tokensListData.tokensList.forEachIndexed { index, item ->
|
||||
portfolioTokensList(
|
||||
portfolio = item,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
portfolioIndex = index,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
is TokenListUMData.TokenList -> {
|
||||
tokensList(
|
||||
items = tokensListData.tokensList,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
)
|
||||
}
|
||||
TokenListUMData.EmptyList -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.tokensList(items: ImmutableList<TokensListItemUM>, isBalanceHidden: Boolean) {
|
||||
itemsIndexed(
|
||||
items = items,
|
||||
key = { _, item -> item.id },
|
||||
contentType = { _, item -> item::class.java },
|
||||
itemContent = { index, item ->
|
||||
TokenListItem(
|
||||
state = item,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
modifier = Modifier
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = index,
|
||||
lastIndex = items.lastIndex,
|
||||
backgroundColor = TangemTheme.colors.background.primary,
|
||||
)
|
||||
.testTag(BuyTokenScreenTestTags.LAZY_LIST_ITEM)
|
||||
.semantics { lazyListItemPosition = index },
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
internal fun LazyListScope.portfolioTokensList(
|
||||
portfolio: TokensListItemUM.Portfolio,
|
||||
modifier: Modifier,
|
||||
portfolioIndex: Int,
|
||||
isBalanceHidden: Boolean,
|
||||
) {
|
||||
val tokens = portfolio.tokens
|
||||
val isExpanded = portfolio.isExpanded
|
||||
val lastIndex = tokens.lastIndex.inc()
|
||||
|
||||
portfolioItem(
|
||||
portfolio = portfolio,
|
||||
modifier = modifier,
|
||||
portfolioIndex = portfolioIndex,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
)
|
||||
itemsIndexed(
|
||||
items = tokens,
|
||||
key = { _, item -> item.id.toString() + "-portfolio-${portfolio.id}" },
|
||||
contentType = { _, item -> item::class.java },
|
||||
itemContent = { tokenIndex, token ->
|
||||
val indexWithHeader = tokenIndex.inc()
|
||||
SlideInItemVisibility(
|
||||
currentIndex = tokenIndex,
|
||||
lastIndex = lastIndex,
|
||||
modifier = modifier
|
||||
.testModifier(indexWithHeader)
|
||||
.animateItem(fadeInSpec = null, placementSpec = null, fadeOutSpec = null)
|
||||
.roundedShapeItemDecoration(
|
||||
radius = TangemTheme.dimens.radius14,
|
||||
currentIndex = indexWithHeader,
|
||||
lastIndex = lastIndex,
|
||||
backgroundColor = TangemTheme.colors.background.primary,
|
||||
),
|
||||
visible = isExpanded,
|
||||
) {
|
||||
val innerModifier = if (indexWithHeader == lastIndex) Modifier.padding(bottom = 8.dp) else Modifier
|
||||
PortfolioTokensListItem(
|
||||
state = token,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
modifier = innerModifier,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
private fun LazyListScope.portfolioItem(
|
||||
portfolio: TokensListItemUM.Portfolio,
|
||||
modifier: Modifier,
|
||||
portfolioIndex: Int,
|
||||
isBalanceHidden: Boolean,
|
||||
) {
|
||||
val tokens = portfolio.tokens
|
||||
val isExpanded = portfolio.isExpanded
|
||||
val lastIndex = when {
|
||||
isExpanded && tokens.isEmpty() -> 1
|
||||
isExpanded -> tokens.lastIndex.inc()
|
||||
else -> 0
|
||||
}
|
||||
|
||||
item(
|
||||
key = "account-${portfolio.id}",
|
||||
contentType = "account-content",
|
||||
) {
|
||||
// Snap immediately on expand; on collapse, hold until all child items finish
|
||||
// their shrink animation, then snap to fully-rounded shape.
|
||||
val effectiveLastIndex by animateIntAsState(
|
||||
targetValue = lastIndex,
|
||||
animationSpec = if (lastIndex != 0) {
|
||||
snap()
|
||||
} else {
|
||||
snap(delayMillis = minOf(50 * tokens.lastIndex, 250) + 150)
|
||||
},
|
||||
label = "lastIndex",
|
||||
)
|
||||
|
||||
PortfolioListItem(
|
||||
state = portfolio,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
modifier = modifier
|
||||
.testModifier(portfolioIndex)
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = 0,
|
||||
radius = TangemTheme.dimens.radius14,
|
||||
lastIndex = effectiveLastIndex,
|
||||
backgroundColor = TangemTheme.colors.background.primary,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Modifier.testModifier(index: Int): Modifier = this
|
||||
.testTag(MainScreenTestTags.TOKEN_LIST_ITEM)
|
||||
.semantics { lazyListItemPosition = index }
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
@Composable
|
||||
internal fun SlideInItemVisibility(
|
||||
visible: Boolean,
|
||||
currentIndex: Int,
|
||||
lastIndex: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
val maxDelay = 250
|
||||
val delayEnter = minOf(50 * currentIndex, maxDelay)
|
||||
val delayExit = minOf(50 * (lastIndex - currentIndex - 1), maxDelay)
|
||||
|
||||
AnimatedVisibility(
|
||||
modifier = modifier,
|
||||
visible = visible,
|
||||
enter = expandVertically(
|
||||
tween(200, delayMillis = delayEnter, easing = LinearOutSlowInEasing),
|
||||
expandFrom = Alignment.Top,
|
||||
) + fadeIn(tween(200, delayMillis = delayEnter, easing = LinearOutSlowInEasing)),
|
||||
exit = shrinkVertically(
|
||||
tween(150, delayMillis = delayExit, easing = FastOutLinearInEasing),
|
||||
shrinkTowards = Alignment.Top,
|
||||
) + fadeOut(tween(150, delayMillis = delayExit, easing = FastOutLinearInEasing)),
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun SwapSelectTokenScreen_Preview(
|
||||
@PreviewParameter(SwapSelectTokenScreenPreviewProvider::class) params: SwapSelectTokenStateHolder,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
SwapSelectTokenScreen(
|
||||
state = params,
|
||||
onBack = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class SwapSelectTokenScreenPreviewProvider : PreviewParameterProvider<SwapSelectTokenStateHolder> {
|
||||
override val values: Sequence<SwapSelectTokenStateHolder>
|
||||
get() = sequenceOf(
|
||||
// Content state with tokens and markets
|
||||
SwapSelectTokenPreviewProvider.defaultState,
|
||||
// Empty state
|
||||
SwapSelectTokenStateHolder(
|
||||
tokensListData = TokenListUMData.EmptyList,
|
||||
marketsState = SwapMarketState.DefaultLoading,
|
||||
isAfterSearch = false,
|
||||
isBalanceHidden = false,
|
||||
onSearchEntered = {},
|
||||
),
|
||||
// Not found state
|
||||
SwapSelectTokenStateHolder(
|
||||
tokensListData = TokenListUMData.EmptyList,
|
||||
marketsState = SwapMarketState.SearchLoading,
|
||||
isAfterSearch = true,
|
||||
isBalanceHidden = false,
|
||||
onSearchEntered = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -1,221 +0,0 @@
|
|||
package com.tangem.feature.swap.ui.preview
|
||||
|
||||
import com.tangem.common.ui.charts.state.MarketChartRawData
|
||||
import com.tangem.common.ui.markets.models.MarketsListItemUM
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
import com.tangem.core.ui.components.token.AccountItemPreviewData
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.components.tokenlist.state.PortfolioItemContentUM
|
||||
import com.tangem.core.ui.components.tokenlist.state.PortfolioTokensListItemUM
|
||||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.feature.swap.choosetoken.api.model.TokenListUMData
|
||||
import com.tangem.feature.swap.models.SwapSelectTokenStateHolder
|
||||
import com.tangem.feature.swap.models.market.state.SwapMarketState
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal object SwapSelectTokenPreviewProvider {
|
||||
|
||||
private const val CHART_VALUE_1 = 0.4
|
||||
private const val CHART_VALUE_2 = 0.2
|
||||
private const val CHART_VALUE_3 = 0.1
|
||||
private const val CHART_VALUE_4 = 2.0
|
||||
private const val CHART_VALUE_5 = 5.0
|
||||
private const val CHART_VALUE_6 = 3.0
|
||||
private const val TOTAL_ITEMS = 322
|
||||
|
||||
private val PREVIEW_CHART_DATA = MarketChartRawData(
|
||||
y = persistentListOf(
|
||||
CHART_VALUE_1,
|
||||
CHART_VALUE_2,
|
||||
CHART_VALUE_1,
|
||||
CHART_VALUE_3,
|
||||
CHART_VALUE_1,
|
||||
CHART_VALUE_4,
|
||||
CHART_VALUE_5,
|
||||
CHART_VALUE_3,
|
||||
CHART_VALUE_4,
|
||||
CHART_VALUE_4,
|
||||
CHART_VALUE_6,
|
||||
),
|
||||
)
|
||||
|
||||
private val tokenItemState = TokenItemState.Content(
|
||||
id = "1",
|
||||
iconState = CurrencyIconState.Locked,
|
||||
titleState = TokenItemState.TitleState.Content(text = stringReference(value = "Bitcoin")),
|
||||
fiatAmountState = TokenItemState.FiatAmountState.Content(text = "12 368,14 \$"),
|
||||
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "0,35853044 BTC"),
|
||||
subtitleState = TokenItemState.SubtitleState.CryptoPriceContent(
|
||||
price = "34 496,75 \$",
|
||||
priceChangePercent = "0,43 %",
|
||||
type = PriceChangeType.DOWN,
|
||||
),
|
||||
onItemClick = {},
|
||||
onItemLongClick = {},
|
||||
)
|
||||
|
||||
private val textContentTokensState = persistentListOf(
|
||||
TokensListItemUM.GroupTitle(id = 111, text = stringReference("Network Bitcoin")),
|
||||
TokensListItemUM.Token(state = tokenItemState),
|
||||
TokensListItemUM.GroupTitle(id = 222, text = stringReference("Network Ethereum")),
|
||||
TokensListItemUM.Token(
|
||||
state = tokenItemState.copy(
|
||||
id = "2",
|
||||
titleState = TokenItemState.TitleState.Content(text = stringReference("Ethereum")),
|
||||
fiatAmountState = TokenItemState.FiatAmountState.Content(text = "3 340,79 \$"),
|
||||
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "1,856660295 ETH"),
|
||||
subtitleState = TokenItemState.SubtitleState.CryptoPriceContent(
|
||||
price = "1 799,41 \$",
|
||||
priceChangePercent = "5,16 %",
|
||||
type = PriceChangeType.UP,
|
||||
),
|
||||
),
|
||||
),
|
||||
TokensListItemUM.Token(
|
||||
state = TokenItemState.Unreachable(
|
||||
id = "3",
|
||||
iconState = CurrencyIconState.Locked,
|
||||
titleState = TokenItemState.TitleState.Content(text = stringReference(value = "Polygon")),
|
||||
onItemClick = {},
|
||||
onItemLongClick = {},
|
||||
),
|
||||
),
|
||||
TokensListItemUM.Token(
|
||||
state = tokenItemState.copy(
|
||||
id = "4",
|
||||
titleState = TokenItemState.TitleState.Content(text = stringReference(value = "Shiba Inu")),
|
||||
fiatAmountState = TokenItemState.FiatAmountState.Content(text = "48,64 \$"),
|
||||
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "6 200 220,00 SHIB"),
|
||||
subtitleState = TokenItemState.SubtitleState.CryptoPriceContent(
|
||||
price = "0.01 \$",
|
||||
priceChangePercent = "1,34 %",
|
||||
type = PriceChangeType.DOWN,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
private val marketState = SwapMarketState.Content(
|
||||
items = createPreviewMarketItems(),
|
||||
loadMore = { },
|
||||
onItemClick = { },
|
||||
visibleIdsChanged = { },
|
||||
total = TOTAL_ITEMS,
|
||||
marketsTitle = TextReference.Res(R.string.feed_trending_now),
|
||||
shouldAssetsCount = false,
|
||||
)
|
||||
|
||||
val defaultState = SwapSelectTokenStateHolder(
|
||||
tokensListData = TokenListUMData.AccountList(
|
||||
tokensList = persistentListOf(
|
||||
TokensListItemUM.Portfolio(
|
||||
content = PortfolioItemContentUM.Tokens(
|
||||
tokens = textContentTokensState.filterIsInstance<PortfolioTokensListItemUM>()
|
||||
.toPersistentList(),
|
||||
),
|
||||
isExpanded = false,
|
||||
isCollapsable = true,
|
||||
tokenItemUM = AccountItemPreviewData.accountItem
|
||||
.copy(iconState = AccountItemPreviewData.accountLetterIcon),
|
||||
),
|
||||
TokensListItemUM.Portfolio(
|
||||
content = PortfolioItemContentUM.Tokens(
|
||||
tokens = textContentTokensState.filterIsInstance<PortfolioTokensListItemUM>()
|
||||
.toPersistentList(),
|
||||
),
|
||||
isExpanded = true,
|
||||
isCollapsable = true,
|
||||
tokenItemUM = AccountItemPreviewData.accountItem,
|
||||
),
|
||||
),
|
||||
totalTokensCount = TOTAL_ITEMS,
|
||||
),
|
||||
isAfterSearch = false,
|
||||
isBalanceHidden = false,
|
||||
onSearchEntered = {},
|
||||
marketsState = marketState,
|
||||
)
|
||||
|
||||
private fun createPreviewMarketItems() = listOf(
|
||||
createMarketItem(
|
||||
id = "1",
|
||||
iconUrl = "",
|
||||
ratingPosition = "10",
|
||||
marketCap = "$6.233 B",
|
||||
trendType = PriceChangeType.UP,
|
||||
chartData = PREVIEW_CHART_DATA,
|
||||
),
|
||||
createMarketItem(
|
||||
id = "2",
|
||||
ratingPosition = "10",
|
||||
marketCap = "$6.233 B",
|
||||
trendType = PriceChangeType.NEUTRAL,
|
||||
chartData = null,
|
||||
),
|
||||
createMarketItem(
|
||||
id = "3",
|
||||
name = "Bitcoin Bitcoin Bitcoin Bitcoin Bitcoin Bitcoin Bitcoin",
|
||||
ratingPosition = "10",
|
||||
marketCap = "$6.23348172384781234 B",
|
||||
trendType = PriceChangeType.DOWN,
|
||||
chartData = PREVIEW_CHART_DATA,
|
||||
),
|
||||
createMarketItem(
|
||||
id = "4",
|
||||
ratingPosition = "10",
|
||||
marketCap = null,
|
||||
trendType = PriceChangeType.UP,
|
||||
chartData = PREVIEW_CHART_DATA,
|
||||
),
|
||||
createMarketItem(
|
||||
id = "5",
|
||||
ratingPosition = null,
|
||||
marketCap = "$6.233 B",
|
||||
trendType = PriceChangeType.UP,
|
||||
chartData = PREVIEW_CHART_DATA,
|
||||
),
|
||||
createMarketItem(
|
||||
id = "6",
|
||||
ratingPosition = null,
|
||||
marketCap = null,
|
||||
trendType = PriceChangeType.UP,
|
||||
chartData = PREVIEW_CHART_DATA,
|
||||
),
|
||||
).toImmutableList()
|
||||
|
||||
private fun createMarketItem(
|
||||
id: String,
|
||||
name: String = "Bitcoin",
|
||||
iconUrl: String? = null,
|
||||
ratingPosition: String?,
|
||||
marketCap: String?,
|
||||
trendType: PriceChangeType,
|
||||
chartData: MarketChartRawData?,
|
||||
) = MarketsListItemUM(
|
||||
id = CryptoCurrency.RawID(id),
|
||||
name = name,
|
||||
currencySymbol = "BTC",
|
||||
iconUrl = iconUrl,
|
||||
ratingPosition = ratingPosition,
|
||||
marketCap = marketCap,
|
||||
price = MarketsListItemUM.Price(
|
||||
text = "31 285.72$",
|
||||
annotated = stringReference("31 285.72$"),
|
||||
fiatPrice = BigDecimal("123123"),
|
||||
),
|
||||
trendPercentText = "12.43%",
|
||||
trendType = trendType,
|
||||
chartData = chartData,
|
||||
isUnder100kMarketCap = false,
|
||||
stakingRate = stringReference("APY 12.34%"),
|
||||
updateTimestamp = 0,
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue