Updated on 2026-08-14
This commit is contained in:
parent
41131e5b73
commit
f5eca5ab2a
23 changed files with 160 additions and 138 deletions
|
|
@ -1,46 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.selecttoken
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.child
|
||||
import com.tangem.feature.wallet.presentation.selecttoken.ui.SelectToken
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.TokenListComponent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultSelectTokenComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
tokenListComponentFactory: TokenListComponent.Factory,
|
||||
@Assisted private val params: SelectTokenComponent.Params,
|
||||
) : AppComponentContext by appComponentContext, SelectTokenComponent {
|
||||
|
||||
private val tokenListComponent: TokenListComponent = tokenListComponentFactory.create(
|
||||
context = child(key = "token_list"),
|
||||
params = TokenListComponent.Params(
|
||||
hasSearchBar = params.hasSearchBar,
|
||||
userWalletId = params.userWalletId,
|
||||
onTokenClick = params.onTokenClick,
|
||||
),
|
||||
)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
SelectToken(
|
||||
titleResId = params.titleResId,
|
||||
onBackClick = router::pop,
|
||||
tokenListComponent = tokenListComponent,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : SelectTokenComponent.Factory {
|
||||
|
||||
override fun create(
|
||||
context: AppComponentContext,
|
||||
params: SelectTokenComponent.Params,
|
||||
): DefaultSelectTokenComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.selecttoken
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
/**
|
||||
* Select token component
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface SelectTokenComponent : ComposableContentComponent {
|
||||
|
||||
interface Factory : ComponentFactory<Params, SelectTokenComponent>
|
||||
|
||||
/**
|
||||
* Params
|
||||
*
|
||||
* @property hasSearchBar flag that indicates if search bar should be shown
|
||||
* @property userWalletId id of multi-currency wallet
|
||||
* @property titleResId resource id of title
|
||||
* @property onTokenClick callback for token click
|
||||
*/
|
||||
data class Params(
|
||||
val hasSearchBar: Boolean,
|
||||
val userWalletId: UserWalletId,
|
||||
@StringRes val titleResId: Int,
|
||||
val onTokenClick: (CryptoCurrencyStatus) -> Unit,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.selecttoken.di
|
||||
|
||||
import com.tangem.feature.wallet.presentation.selecttoken.DefaultSelectTokenComponent
|
||||
import com.tangem.feature.wallet.presentation.selecttoken.SelectTokenComponent
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface SelectTokenComponentModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindSelectTokenComponentFactory(factory: DefaultSelectTokenComponent.Factory): SelectTokenComponent.Factory
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.selecttoken.ui
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.systemBarsPadding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.TokenListComponent
|
||||
|
||||
@Composable
|
||||
internal fun SelectToken(
|
||||
@StringRes titleResId: Int,
|
||||
onBackClick: () -> Unit,
|
||||
tokenListComponent: TokenListComponent,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
BackHandler(onBack = onBackClick)
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.background(TangemTheme.colors.background.secondary)
|
||||
.imePadding()
|
||||
.systemBarsPadding(),
|
||||
) {
|
||||
AppBarWithBackButton(
|
||||
onBackClick = onBackClick,
|
||||
text = stringResource(id = titleResId),
|
||||
iconRes = R.drawable.ic_close_24,
|
||||
)
|
||||
|
||||
tokenListComponent.Content(
|
||||
contentPadding = PaddingValues(vertical = 8.dp, horizontal = 16.dp),
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.tokenlist
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.model.TokenListModel
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.ui.TokenList
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
@Stable
|
||||
internal class DefaultTokenListComponent @AssistedInject constructor(
|
||||
@Assisted context: AppComponentContext,
|
||||
@Assisted params: TokenListComponent.Params,
|
||||
) : TokenListComponent, AppComponentContext by context {
|
||||
|
||||
private val model: TokenListModel = getOrCreateModel(params)
|
||||
|
||||
@Composable
|
||||
override fun Content(contentPadding: PaddingValues, modifier: Modifier) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
|
||||
TokenList(state = state, contentPadding = contentPadding, modifier = modifier)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : TokenListComponent.Factory {
|
||||
override fun create(context: AppComponentContext, params: TokenListComponent.Params): DefaultTokenListComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.tokenlist
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
/** Token list component that present list of token for multi-currency wallet */
|
||||
@Stable
|
||||
internal interface TokenListComponent {
|
||||
|
||||
@Composable
|
||||
fun Content(contentPadding: PaddingValues, modifier: Modifier)
|
||||
|
||||
/** Component factory */
|
||||
interface Factory : ComponentFactory<Params, TokenListComponent>
|
||||
|
||||
/**
|
||||
* Params
|
||||
*
|
||||
* @property hasSearchBar flag that indicates if search bar should be shown
|
||||
* @property userWalletId id of multi-currency wallet
|
||||
* @property onTokenClick callback for token click
|
||||
*/
|
||||
data class Params(
|
||||
val hasSearchBar: Boolean,
|
||||
val userWalletId: UserWalletId,
|
||||
val onTokenClick: (CryptoCurrencyStatus) -> Unit,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.tokenlist.di
|
||||
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.DefaultTokenListComponent
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.TokenListComponent
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface TokenListComponentModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindTokenListComponentFactory(factory: DefaultTokenListComponent.Factory): TokenListComponent.Factory
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.tokenlist.di
|
||||
|
||||
import com.tangem.core.decompose.di.DecomposeComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.model.TokenListModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(DecomposeComponent::class)
|
||||
internal interface TokenListModelModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(TokenListModel::class)
|
||||
fun provideTokenListModel(model: TokenListModel): Model
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.tokenlist.entity
|
||||
|
||||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
/**
|
||||
* Token list UM
|
||||
*
|
||||
* @property items items (search bar, tokens, headers)
|
||||
* @property isBalanceHidden flag that indicates if balance should be hidden
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal data class TokenListUM(
|
||||
val items: ImmutableList<TokensListItemUM>,
|
||||
val isBalanceHidden: Boolean,
|
||||
) {
|
||||
|
||||
/** Get search bar if it exists */
|
||||
fun getSearchBar(): TokensListItemUM.SearchBar? {
|
||||
return items.firstOrNull() as? TokensListItemUM.SearchBar
|
||||
}
|
||||
|
||||
/** Get tokens */
|
||||
fun getTokens(): ImmutableList<TokensListItemUM> {
|
||||
if (getSearchBar() == null) return items
|
||||
|
||||
return if (items.size > 1) {
|
||||
items.subList(fromIndex = 1, toIndex = items.size)
|
||||
} else {
|
||||
persistentListOf()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.tokenlist.entity
|
||||
|
||||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* [TokenListUM] controller
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class TokenListUMController @Inject constructor() {
|
||||
|
||||
val state: StateFlow<TokenListUM> get() = _state
|
||||
|
||||
private val _state: MutableStateFlow<TokenListUM> = MutableStateFlow(
|
||||
value = TokenListUM(
|
||||
items = persistentListOf(),
|
||||
isBalanceHidden = false,
|
||||
),
|
||||
)
|
||||
|
||||
fun update(transform: (TokenListUM) -> TokenListUM) {
|
||||
Timber.d("Applying non-name transformation")
|
||||
_state.update(transform)
|
||||
}
|
||||
|
||||
fun update(transformer: TokenListUMTransformer) {
|
||||
Timber.d("Applying ${transformer::class.simpleName}")
|
||||
_state.update(transformer::transform)
|
||||
}
|
||||
|
||||
/** Get search bar if it exists */
|
||||
fun getSearchBar(): TokensListItemUM.SearchBar? {
|
||||
return _state.value.getSearchBar()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.tokenlist.entity
|
||||
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
/**
|
||||
* Base [TokenListUM] transformer
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal interface TokenListUMTransformer : Transformer<TokenListUM>
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.tokenlist.entity.transformer
|
||||
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.entity.TokenListUM
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.entity.TokenListUMTransformer
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
/**
|
||||
* Base [SearchBarUM] transformer
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal abstract class SearchBarUMTransformer : TokenListUMTransformer {
|
||||
|
||||
abstract fun transform(prevState: SearchBarUM): SearchBarUM
|
||||
|
||||
override fun transform(prevState: TokenListUM): TokenListUM {
|
||||
val searchBarItem = prevState.getSearchBar()
|
||||
|
||||
return if (searchBarItem != null) {
|
||||
val updatedSearchBar = searchBarItem.copy(searchBarUM = transform(searchBarItem.searchBarUM))
|
||||
|
||||
prevState.copy(
|
||||
items = persistentListOf(
|
||||
updatedSearchBar,
|
||||
*prevState.getTokens().toTypedArray(),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
prevState
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.tokenlist.entity.transformer
|
||||
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
|
||||
internal class UpdateSearchBarActiveStateTransformer(private val isActive: Boolean) : SearchBarUMTransformer() {
|
||||
|
||||
override fun transform(prevState: SearchBarUM): SearchBarUM {
|
||||
val placeholderText = if (isActive) {
|
||||
TextReference.EMPTY
|
||||
} else {
|
||||
resourceReference(id = R.string.common_search)
|
||||
}
|
||||
|
||||
return prevState.copy(placeholderText = placeholderText, isActive = isActive)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.tokenlist.entity.transformer
|
||||
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
|
||||
internal class UpdateSearchQueryTransformer(private val newQuery: String) : SearchBarUMTransformer() {
|
||||
|
||||
override fun transform(prevState: SearchBarUM): SearchBarUM {
|
||||
return prevState.copy(query = newQuery)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.tokenlist.entity.transformer
|
||||
|
||||
import com.tangem.common.ui.tokens.TokenItemStateConverter
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.entity.TokenListUM
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.entity.TokenListUMTransformer
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
internal class UpdateTokenItemsTransformer(
|
||||
private val tokenItemStateConverter: TokenItemStateConverter,
|
||||
private val statuses: List<CryptoCurrencyStatus>,
|
||||
private val isBalanceHidden: Boolean,
|
||||
private val hasSearchBar: Boolean,
|
||||
private val onQueryChange: (String) -> Unit,
|
||||
private val onActiveChange: (Boolean) -> Unit,
|
||||
) : TokenListUMTransformer {
|
||||
|
||||
override fun transform(prevState: TokenListUM): TokenListUM {
|
||||
val items = tokenItemStateConverter.convertList(input = statuses).map(TokensListItemUM::Token)
|
||||
|
||||
val searchBarItem = if (hasSearchBar) {
|
||||
prevState.getSearchBar() ?: createSearchBarItem()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
return prevState.copy(
|
||||
items = (listOfNotNull(searchBarItem) + items).toImmutableList(),
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createSearchBarItem(): TokensListItemUM.SearchBar {
|
||||
return TokensListItemUM.SearchBar(
|
||||
searchBarUM = SearchBarUM(
|
||||
placeholderText = resourceReference(id = R.string.common_search),
|
||||
query = "",
|
||||
onQueryChange = onQueryChange,
|
||||
isActive = false,
|
||||
onActiveChange = onActiveChange,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.tokenlist.model
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.ui.tokens.TokenItemStateConverter
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.core.utils.getOrElse
|
||||
import com.tangem.domain.tokens.GetTokenListUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.TokenListComponent
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.entity.TokenListUM
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.entity.TokenListUMController
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.entity.transformer.UpdateSearchBarActiveStateTransformer
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.entity.transformer.UpdateSearchQueryTransformer
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.entity.transformer.UpdateTokenItemsTransformer
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.utils.SearchTokensManager
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class TokenListModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val tokenListUMController: TokenListUMController,
|
||||
private val searchTokensManager: SearchTokensManager,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
private val getTokenListUseCase: GetTokenListUseCase,
|
||||
) : Model() {
|
||||
|
||||
val state: StateFlow<TokenListUM> = tokenListUMController.state
|
||||
|
||||
private val params: TokenListComponent.Params = paramsContainer.require()
|
||||
|
||||
init {
|
||||
subscribeOnUpdateState()
|
||||
}
|
||||
|
||||
private fun subscribeOnUpdateState() {
|
||||
combine(
|
||||
flow = getTokenListUseCase.launch(userWalletId = params.userWalletId).distinctUntilChanged(),
|
||||
flow2 = getSelectedAppCurrencyUseCase().map { it.getOrElse { AppCurrency.Default } }.distinctUntilChanged(),
|
||||
flow3 = getBalanceHidingSettingsUseCase().map { it.isBalanceHidden }.distinctUntilChanged(),
|
||||
flow4 = searchTokensManager.query,
|
||||
) { maybeTokenList, appCurrency, isBalanceHidden, query ->
|
||||
val currencies = maybeTokenList.getOrElse(
|
||||
ifLoading = { it ?: TokenList.Empty },
|
||||
ifError = { TokenList.Empty },
|
||||
)
|
||||
.flattenCurrencies()
|
||||
|
||||
val filterTokenList = currencies
|
||||
.filterByQuery(query = query)
|
||||
.filterByAvailability()
|
||||
|
||||
UpdateTokenItemsTransformer(
|
||||
tokenItemStateConverter = TokenItemStateConverter(
|
||||
appCurrency = appCurrency,
|
||||
onItemClick = params.onTokenClick,
|
||||
),
|
||||
statuses = filterTokenList,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
hasSearchBar = params.hasSearchBar && currencies.isNotEmpty(),
|
||||
onQueryChange = ::onSearchQueryChange,
|
||||
onActiveChange = ::onSearchBarActiveChange,
|
||||
)
|
||||
}
|
||||
.onEach(tokenListUMController::update)
|
||||
.flowOn(dispatchers.main)
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun onSearchQueryChange(newQuery: String) {
|
||||
val searchBar = tokenListUMController.getSearchBar()
|
||||
if (searchBar?.searchBarUM?.query == newQuery) return
|
||||
|
||||
modelScope.launch {
|
||||
tokenListUMController.update(transformer = UpdateSearchQueryTransformer(newQuery))
|
||||
|
||||
searchTokensManager.update(newQuery)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onSearchBarActiveChange(isActive: Boolean) {
|
||||
tokenListUMController.update(transformer = UpdateSearchBarActiveStateTransformer(isActive))
|
||||
}
|
||||
|
||||
private fun List<CryptoCurrencyStatus>.filterByQuery(query: String): List<CryptoCurrencyStatus> {
|
||||
return filter {
|
||||
it.currency.name.contains(other = query, ignoreCase = true) ||
|
||||
it.currency.symbol.contains(other = query, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: [REDACTED_JIRA]
|
||||
private fun List<CryptoCurrencyStatus>.filterByAvailability(): List<CryptoCurrencyStatus> {
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.tokenlist.ui
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.tokenlist.TokenListItem
|
||||
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.entity.TokenListUM
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.ui.preview.PreviewTokenListUMProvider
|
||||
|
||||
/**
|
||||
* Token list
|
||||
*
|
||||
* @param state state
|
||||
* @param modifier modifier
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
internal fun TokenList(state: TokenListUM, contentPadding: PaddingValues, modifier: Modifier = Modifier) {
|
||||
LazyColumn(modifier = modifier, contentPadding = contentPadding) {
|
||||
itemsIndexed(
|
||||
items = state.items,
|
||||
key = { _, item -> item.id },
|
||||
contentType = { _, item -> item::class.java },
|
||||
itemContent = { index, item ->
|
||||
TokenListItem(
|
||||
state = item,
|
||||
isBalanceHidden = state.isBalanceHidden,
|
||||
modifier = Modifier
|
||||
.animateItem()
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = index,
|
||||
lastIndex = state.items.lastIndex,
|
||||
addDefaultPadding = false,
|
||||
backgroundColor = TangemTheme.colors.background.primary,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun Preview_TokenList(@PreviewParameter(PreviewTokenListUMProvider::class) state: TokenListUM) {
|
||||
TangemThemePreview {
|
||||
TokenList(
|
||||
state = state,
|
||||
contentPadding = PaddingValues(all = 16.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(color = TangemTheme.colors.background.secondary),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.tokenlist.ui.preview
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.tokenlist.entity.TokenListUM
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
internal class PreviewTokenListUMProvider : PreviewParameterProvider<TokenListUM> {
|
||||
|
||||
override val values: Sequence<TokenListUM> = sequenceOf(
|
||||
createTokensList(hasSearchBar = false, createDefaultTokenItem()),
|
||||
createTokensList(hasSearchBar = true, createDefaultTokenItem()),
|
||||
)
|
||||
|
||||
private fun createTokensList(hasSearchBar: Boolean, vararg items: TokensListItemUM): TokenListUM {
|
||||
return TokenListUM(
|
||||
items = buildList {
|
||||
if (hasSearchBar) {
|
||||
TokensListItemUM.SearchBar(
|
||||
searchBarUM = SearchBarUM(
|
||||
placeholderText = resourceReference(id = R.string.common_search),
|
||||
query = "",
|
||||
onQueryChange = {},
|
||||
isActive = false,
|
||||
onActiveChange = {},
|
||||
),
|
||||
)
|
||||
.let { add(element = it) }
|
||||
}
|
||||
|
||||
addAll(items)
|
||||
}
|
||||
.toImmutableList(),
|
||||
isBalanceHidden = false,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createDefaultTokenItem(): TokensListItemUM.Token {
|
||||
return TokensListItemUM.Token(
|
||||
state = TokenItemState.Content(
|
||||
id = "1",
|
||||
iconState = CurrencyIconState.Locked,
|
||||
titleState = TokenItemState.TitleState.Content(text = "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 = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.tokenlist.utils
|
||||
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.withDebounce
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Search tokens manager
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class SearchTokensManager @Inject constructor() {
|
||||
|
||||
val query: Flow<String>
|
||||
get() = _query
|
||||
|
||||
private val _query = MutableStateFlow(value = "")
|
||||
|
||||
private val jobHolder = JobHolder()
|
||||
|
||||
suspend fun update(value: String) {
|
||||
coroutineScope {
|
||||
if (value.isEmpty()) {
|
||||
_query.value = value
|
||||
} else {
|
||||
withDebounce(jobHolder) { _query.value = value }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue