Updated on 2026-08-14

This commit is contained in:
Tangem 2024-07-29 14:14:28 +03:00
parent 258af22842
commit eeec58e676
47 changed files with 658 additions and 123 deletions

View file

@ -1,6 +1,7 @@
package com.tangem.tap.di.domain
import com.tangem.domain.markets.GetMarketsTokenListFlowUseCase
import com.tangem.domain.markets.GetTokenPriceChartUseCase
import com.tangem.domain.markets.repositories.MarketsTokenRepository
import dagger.Module
import dagger.Provides
@ -19,4 +20,10 @@ object MarketsDomainModule {
): GetMarketsTokenListFlowUseCase {
return GetMarketsTokenListFlowUseCase(marketsTokenRepository = marketsTokenRepository)
}
@Provides
@Singleton
fun provideGetTokenPriceChartUseCase(marketsTokenRepository: MarketsTokenRepository): GetTokenPriceChartUseCase {
return GetTokenPriceChartUseCase(marketsTokenRepository = marketsTokenRepository)
}
}

View file

@ -70,9 +70,9 @@ private const val GUIDELINES_COUNT = 3
fun MarketChart(
modifier: Modifier = Modifier,
state: MarketChartState = rememberMarketChartState(),
splitChartSegmentColor: Color,
@FloatRange(from = 0.0, to = 1.0) backgroundSplitChartSegmentColorAlpha: Float,
@FloatRange(from = 0.0, to = 1.0) backgroundColorAlpha: Float,
splitChartSegmentColor: Color = TangemTheme.colors.icon.inactive,
@FloatRange(from = 0.0, to = 1.0) backgroundSplitChartSegmentColorAlpha: Float = 0.24f,
@FloatRange(from = 0.0, to = 1.0) backgroundColorAlpha: Float = 0.24f,
noChartContent: @Composable BoxScope.() -> Unit,
) {
var canvasWidth by remember { mutableIntStateOf(0) }
@ -358,41 +358,47 @@ private fun MarketChartPreview(
text = "Change marker highlight side",
)
}
Button(onClick = {
coroutineScope.launch {
dataProducer.runTransactionSuspend {
updateData {
MarketChartData.Data(
x = it.x,
y = it.y.reversed(),
)
Button(
onClick = {
coroutineScope.launch {
dataProducer.runTransactionSuspend {
updateData {
MarketChartData.Data(
x = it.x,
y = it.y.reversed(),
)
}
}
}
}
},) {
},
) {
Text("Change Data")
}
Button(onClick = {
dataProducer.runTransaction {
updateLook { it.copy(animationOnDataChange = it.animationOnDataChange.not()) }
}
},) {
Button(
onClick = {
dataProducer.runTransaction {
updateLook { it.copy(animationOnDataChange = it.animationOnDataChange.not()) }
}
},
) {
Text("Change animationOnDataChange = ${look.animationOnDataChange}")
}
Button(onClick = {
dataProducer.runTransaction {
updateLook {
it.copy(
type = if (it.type == MarketChartLook.Type.Growing) {
MarketChartLook.Type.Falling
} else {
MarketChartLook.Type.Growing
},
)
Button(
onClick = {
dataProducer.runTransaction {
updateLook {
it.copy(
type = if (it.type == MarketChartLook.Type.Growing) {
MarketChartLook.Type.Falling
} else {
MarketChartLook.Type.Growing
},
)
}
}
}
},) {
},
) {
Text("Change color type")
}
}

View file

@ -19,6 +19,7 @@ internal class DefaultMarketsTokenRepository(
) : MarketsTokenRepository {
private val tokenListConverter = TokenMarketListConverter()
private val tokenChartConverter = TokenChartConverter()
private fun createTokenMarketsFetcher(firstBatchSize: Int, nextBatchSize: Int) = LimitOffsetBatchFetcher(
prefetchDistance = firstBatchSize,
@ -89,4 +90,13 @@ internal class DefaultMarketsTokenRepository(
updateFetcher = tokenMarketsUpdateFetcher,
).toBatchFlow()
}
override suspend fun getChart(interval: PriceChangeInterval, tokenId: String): TokenChart {
val response = marketsApi.getCoinChart(
currency = tokenId,
interval = interval.toRequestParam(),
)
return tokenChartConverter.convert(interval, response.getOrThrow())
}
}

View file

@ -1,6 +1,6 @@
package com.tangem.data.markets
import com.tangem.data.markets.converters.TokenListChartConverter
import com.tangem.data.markets.converters.TokenChartConverter
import com.tangem.data.markets.converters.TokenMarketChartsConverter
import com.tangem.data.markets.converters.TokenQuotesConverter
import com.tangem.data.markets.converters.toRequestParam
@ -21,7 +21,7 @@ internal class MarketsBatchUpdateFetcher(
private val tangemTechApi: TangemTechApi,
) : BatchUpdateFetcher<Int, List<TokenMarket>, TokenMarketUpdateRequest> {
private val tokenListChartsConverter = TokenMarketChartsConverter(TokenListChartConverter())
private val tokenListChartsConverter = TokenMarketChartsConverter(TokenChartConverter())
private val tokenQuotesConverter = TokenQuotesConverter()
override suspend fun BatchUpdateFetcher.UpdateContext<Int, List<TokenMarket>>.fetchUpdateAsync(

View file

@ -4,13 +4,13 @@ import com.tangem.datasource.api.markets.models.response.TokenMarketChartRespons
import com.tangem.domain.markets.PriceChangeInterval
import com.tangem.domain.markets.TokenChart
class TokenListChartConverter {
class TokenChartConverter {
fun convert(interval: PriceChangeInterval, value: TokenMarketChartResponse): TokenChart {
return TokenChart(
interval = interval,
priceY = value.prices.values.toList(),
timeStamp = value.prices.keys.toList(),
timeStamps = value.prices.keys.toList(),
)
}
}

View file

@ -5,7 +5,7 @@ import com.tangem.domain.markets.PriceChangeInterval
import com.tangem.domain.markets.TokenMarket
class TokenMarketChartsConverter(
private val tokenListChartConverter: TokenListChartConverter,
private val tokenChartConverter: TokenChartConverter,
) {
fun convert(
@ -19,13 +19,13 @@ class TokenMarketChartsConverter(
}
return when (interval) {
PriceChangeInterval.H24 -> chartsToCopy.copy(
h24 = tokenListChartConverter.convert(interval, prices),
h24 = tokenChartConverter.convert(interval, prices),
)
PriceChangeInterval.WEEK -> chartsToCopy.copy(
week = tokenListChartConverter.convert(interval, prices),
week = tokenChartConverter.convert(interval, prices),
)
PriceChangeInterval.MONTH -> chartsToCopy.copy(
month = tokenListChartConverter.convert(interval, prices),
month = tokenChartConverter.convert(interval, prices),
)
else -> error("unsupported interval=$interval. This shouldn't have happened.")
}

View file

@ -5,9 +5,9 @@ import java.math.BigDecimal
data class TokenChart(
val interval: PriceChangeInterval,
val priceY: List<BigDecimal>,
val timeStamp: List<Long>,
val timeStamps: List<Long>,
) {
init {
require(priceY.size == timeStamp.size)
require(priceY.size == timeStamps.size)
}
}

View file

@ -16,6 +16,7 @@ class GetMarketsTokenListFlowUseCase(
firstBatchSize = batchFlowType.firstBatchSize,
nextBatchSize = batchFlowType.nextBatchSize,
)
// TODO listen quotes updates flow and update them in other parts of the application
}
enum class BatchFlowType(

View file

@ -0,0 +1,15 @@
package com.tangem.domain.markets
import arrow.core.Either
import com.tangem.domain.markets.repositories.MarketsTokenRepository
class GetTokenPriceChartUseCase(
private val marketsTokenRepository: MarketsTokenRepository,
) {
suspend operator fun invoke(interval: PriceChangeInterval, tokenId: String): Either<Unit, TokenChart> {
return Either.catch {
marketsTokenRepository.getChart(interval = interval, tokenId = tokenId)
}.mapLeft {}
}
}

View file

@ -9,4 +9,6 @@ interface MarketsTokenRepository {
firstBatchSize: Int,
nextBatchSize: Int,
): TokenListBatchFlow
suspend fun getChart(interval: PriceChangeInterval, tokenId: String): TokenChart
}

View file

@ -8,7 +8,7 @@ import androidx.compose.ui.unit.Dp
import com.tangem.core.decompose.context.AppComponentContext
@Stable
interface MarketsListComponent {
interface MarketsEntryComponent {
@Composable
fun BottomSheetContent(
@ -18,6 +18,6 @@ interface MarketsListComponent {
)
interface Factory {
fun create(context: AppComponentContext): MarketsListComponent
fun create(context: AppComponentContext): MarketsEntryComponent
}
}

View file

@ -37,6 +37,7 @@ dependencies {
/* Other */
implementation(deps.kotlin.immutable.collections)
implementation(deps.timber)
implementation(deps.decompose.ext.compose)
/* Core */
implementation(projects.core.decompose)

View file

@ -0,0 +1,85 @@
package com.tangem.features.markets
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import com.arkivanov.decompose.extensions.compose.jetpack.stack.Children
import com.arkivanov.decompose.router.stack.ChildStack
import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.childStack
import com.arkivanov.decompose.router.stack.push
import com.arkivanov.decompose.value.Value
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.domain.markets.TokenMarket
import com.tangem.features.markets.component.BottomSheetState
import com.tangem.features.markets.component.MarketsEntryComponent
import com.tangem.features.markets.details.api.MarketsTokenDetailsComponent
import com.tangem.features.markets.details.api.toSerializable
import com.tangem.features.markets.tokenlist.api.MarketsTokenListComponent
import com.tangem.features.markets.tokenlist.impl.model.MarketsListModel
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
internal class DefaultMarketsEntryComponent @AssistedInject constructor(
@Assisted context: AppComponentContext,
private val marketsEntryChildFactory: MarketsEntryChildFactory,
) : MarketsEntryComponent, AppComponentContext by context {
private val model: MarketsListModel = getOrCreateModel()
private val stackNavigation = StackNavigation<MarketsEntryChildFactory.Child>()
val stack: Value<ChildStack<MarketsEntryChildFactory.Child, Any>> = childStack(
key = "main",
source = stackNavigation,
serializer = MarketsEntryChildFactory.Child.serializer(),
initialConfiguration = MarketsEntryChildFactory.Child.TokenList,
handleBackButton = true,
childFactory = { configuration, componentContext ->
marketsEntryChildFactory.createChild(
child = configuration,
appComponentContext = childByContext(componentContext),
onTokenSelected = ::marketsListTokenSelected,
)
},
)
@Composable
override fun BottomSheetContent(
bottomSheetState: State<BottomSheetState>,
onHeaderSizeChange: (Dp) -> Unit,
modifier: Modifier,
) {
Children(stack) {
when (it.configuration) {
is MarketsEntryChildFactory.Child.TokenDetails -> {
(it.instance as MarketsTokenDetailsComponent).Content(modifier)
}
MarketsEntryChildFactory.Child.TokenList -> {
(it.instance as MarketsTokenListComponent).BottomSheetContent(
bottomSheetState = bottomSheetState,
onHeaderSizeChange = onHeaderSizeChange,
modifier = modifier,
)
}
}
}
}
private fun marketsListTokenSelected(token: TokenMarket) {
stackNavigation.push(
configuration = MarketsEntryChildFactory.Child.TokenDetails(
params = MarketsTokenDetailsComponent.Params(token.toSerializable()),
),
)
}
@AssistedFactory
interface Factory : MarketsEntryComponent.Factory {
override fun create(context: AppComponentContext): DefaultMarketsEntryComponent
}
}

View file

@ -0,0 +1,45 @@
package com.tangem.features.markets
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.domain.markets.TokenMarket
import com.tangem.features.markets.details.api.MarketsTokenDetailsComponent
import com.tangem.features.markets.tokenlist.api.MarketsTokenListComponent
import kotlinx.serialization.Serializable
import javax.inject.Inject
internal class MarketsEntryChildFactory @Inject constructor(
private val tokenListComponentFactory: MarketsTokenListComponent.Factory,
private val tokenDetailsComponentFactory: MarketsTokenDetailsComponent.Factory,
) {
@Serializable
sealed interface Child {
@Serializable
data object TokenList : Child
@Serializable
data class TokenDetails(val params: MarketsTokenDetailsComponent.Params) : Child
}
fun createChild(
child: Child,
appComponentContext: AppComponentContext,
onTokenSelected: (TokenMarket) -> Unit,
): Any {
return when (child) {
is Child.TokenDetails -> {
tokenDetailsComponentFactory.create(
context = appComponentContext,
params = child.params,
)
}
is Child.TokenList -> {
tokenListComponentFactory.create(
context = appComponentContext,
onTokenSelected = onTokenSelected,
)
}
}
}
}

View file

@ -0,0 +1,15 @@
package com.tangem.features.markets.details.api
import androidx.compose.runtime.Stable
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableContentComponent
import kotlinx.serialization.Serializable
@Stable
interface MarketsTokenDetailsComponent : ComposableContentComponent {
@Serializable
data class Params(val token: TokenMarketSerializable)
interface Factory : ComponentFactory<Params, MarketsTokenDetailsComponent>
}

View file

@ -0,0 +1,40 @@
package com.tangem.features.markets.details.api
import com.tangem.domain.core.serialization.SerializedBigDecimal
import com.tangem.domain.markets.TokenMarket
import kotlinx.serialization.Serializable
@Serializable
data class TokenMarketSerializable(
val id: String,
val name: String,
val symbol: String,
val marketCap: SerializedBigDecimal?,
val tokenQuotes: Quotes,
val imageUrl: String,
) {
@Serializable
data class Quotes(
val currentPrice: SerializedBigDecimal,
val h24Percent: SerializedBigDecimal,
val weekPercent: SerializedBigDecimal,
val monthPercent: SerializedBigDecimal,
)
}
fun TokenMarket.toSerializable(): TokenMarketSerializable {
return TokenMarketSerializable(
id = id,
name = name,
symbol = symbol,
marketCap = marketCap,
tokenQuotes = TokenMarketSerializable.Quotes(
currentPrice = tokenQuotes.currentPrice,
h24Percent = tokenQuotes.h24Percent(),
weekPercent = tokenQuotes.weekPercent(),
monthPercent = tokenQuotes.monthPercent(),
),
imageUrl = imageUrlLarge,
)
}

View file

@ -0,0 +1,43 @@
package com.tangem.features.markets.details.impl
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.features.markets.details.api.MarketsTokenDetailsComponent
import com.tangem.features.markets.details.impl.model.MarketsTokenDetailsModel
import com.tangem.features.markets.details.impl.ui.MarketsTokenDetailsContent
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@Stable
internal class DefaultMarketsTokenDetailsComponent @AssistedInject constructor(
@Assisted appComponentContext: AppComponentContext,
@Assisted params: MarketsTokenDetailsComponent.Params,
) : AppComponentContext by appComponentContext, MarketsTokenDetailsComponent {
private val model: MarketsTokenDetailsModel = getOrCreateModel(params)
@Composable
override fun Content(modifier: Modifier) {
val state by model.state.collectAsStateWithLifecycle()
MarketsTokenDetailsContent(
state = state,
onBackClick = {},
modifier = modifier,
)
}
@AssistedFactory
interface Factory : MarketsTokenDetailsComponent.Factory {
override fun create(
context: AppComponentContext,
params: MarketsTokenDetailsComponent.Params,
): DefaultMarketsTokenDetailsComponent
}
}

View file

@ -0,0 +1,20 @@
package com.tangem.features.markets.details.impl.di
import com.tangem.features.markets.details.api.MarketsTokenDetailsComponent
import com.tangem.features.markets.details.impl.DefaultMarketsTokenDetailsComponent
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 ComponentModule {
@Binds
@Singleton
fun bindMarketsTokenDetailsComponent(
factory: DefaultMarketsTokenDetailsComponent.Factory,
): MarketsTokenDetailsComponent.Factory
}

View file

@ -0,0 +1,20 @@
package com.tangem.features.markets.details.impl.di
import com.tangem.core.decompose.di.DecomposeComponent
import com.tangem.core.decompose.model.Model
import com.tangem.features.markets.details.impl.model.MarketsTokenDetailsModel
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
@Module
@InstallIn(DecomposeComponent::class)
internal interface ModelModule {
@Binds
@IntoMap
@ClassKey(MarketsTokenDetailsModel::class)
fun provideMarketsTokenDetailsModel(model: MarketsTokenDetailsModel): Model
}

View file

@ -0,0 +1,60 @@
package com.tangem.features.markets.details.impl.model
import com.tangem.common.ui.charts.state.MarketChartData
import com.tangem.common.ui.charts.state.MarketChartDataProducer
import com.tangem.common.ui.charts.state.MarketChartLook
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.ui.components.marketprice.PriceChangeType
import com.tangem.domain.markets.GetTokenPriceChartUseCase
import com.tangem.domain.markets.PriceChangeInterval
import com.tangem.features.markets.details.api.MarketsTokenDetailsComponent
import com.tangem.features.markets.details.impl.ui.entity.MarketsTokenDetailsUM
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import java.math.BigDecimal
import javax.inject.Inject
internal class MarketsTokenDetailsModel @Inject constructor(
paramsContainer: ParamsContainer,
override val dispatchers: CoroutineDispatcherProvider,
private val getTokenPriceChartUseCase: GetTokenPriceChartUseCase,
) : Model() {
val params = paramsContainer.require<MarketsTokenDetailsComponent.Params>()
private val chartDataProducer = MarketChartDataProducer.build(dispatcher = dispatchers.default) {
chartData = MarketChartData.NoData.Loading
}
val state = MutableStateFlow(
MarketsTokenDetailsUM(
tokenName = params.token.name,
dateTimeText = "datetime",
priceChangePercentText = params.token.tokenQuotes.h24Percent.toString(),
priceChangeType = if (params.token.tokenQuotes.h24Percent < BigDecimal.ZERO) {
PriceChangeType.DOWN
} else {
PriceChangeType.UP
},
chartState = MarketsTokenDetailsUM.ChartState(
dataProducer = chartDataProducer,
chartLook = MarketChartLook(),
onLoadRetryClick = {},
),
),
)
init {
modelScope.launch {
val chart = getTokenPriceChartUseCase.invoke(PriceChangeInterval.H24, params.token.id)
chart.onRight {
chartDataProducer.runTransactionSuspend {
chartData = MarketChartData.Data()
}
}
}
}
}

View file

@ -0,0 +1,31 @@
package com.tangem.features.markets.details.impl.ui
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.tangem.core.ui.components.appbar.TangemTopAppBar
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
import com.tangem.features.markets.details.impl.ui.entity.MarketsTokenDetailsUM
@Suppress("UnusedPrivateMember")
@Composable
internal fun MarketsTokenDetailsContent(
state: MarketsTokenDetailsUM,
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
) {
// TODO
}
@Suppress("UnusedPrivateMember")
@Composable
private fun Content(state: MarketsTokenDetailsUM, onBackClick: () -> Unit, modifier: Modifier = Modifier) {
Column {
TangemTopAppBar(
title = state.tokenName,
startButton = TopAppBarButtonUM.Back(onBackClick),
)
}
// TODO
}

View file

@ -0,0 +1,29 @@
package com.tangem.features.markets.details.impl.ui.components
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import com.tangem.common.ui.charts.MarketChart
import com.tangem.common.ui.charts.state.rememberMarketChartState
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.markets.details.impl.ui.entity.MarketsTokenDetailsUM
import com.tangem.features.markets.tokenlist.impl.ui.components.UnableToLoadData
@Composable
fun MarketTokenDetailsChart(state: MarketsTokenDetailsUM.ChartState, modifier: Modifier = Modifier) {
val chartState = rememberMarketChartState(state.dataProducer)
MarketChart(
modifier = modifier,
state = chartState,
noChartContent = {
UnableToLoadData(
modifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing16, vertical = TangemTheme.dimens.spacing12)
.align(Alignment.Center),
onRetryClick = state.onLoadRetryClick,
)
},
)
}

View file

@ -0,0 +1,20 @@
package com.tangem.features.markets.details.impl.ui.entity
import com.tangem.common.ui.charts.state.MarketChartDataProducer
import com.tangem.common.ui.charts.state.MarketChartLook
import com.tangem.core.ui.components.marketprice.PriceChangeType
data class MarketsTokenDetailsUM(
val tokenName: String,
val dateTimeText: String,
val priceChangePercentText: String,
val priceChangeType: PriceChangeType,
val chartState: ChartState,
) {
data class ChartState(
val dataProducer: MarketChartDataProducer,
val chartLook: MarketChartLook,
val onLoadRetryClick: () -> Unit,
)
}

View file

@ -1,7 +1,7 @@
package com.tangem.features.markets.di
import com.tangem.features.markets.component.MarketsListComponent
import com.tangem.features.markets.component.impl.DefaultMarketsListComponent
import com.tangem.features.markets.component.MarketsEntryComponent
import com.tangem.features.markets.DefaultMarketsEntryComponent
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
@ -14,5 +14,5 @@ internal interface ComponentModule {
@Binds
@Singleton
fun bindMarketsListComponent(factory: DefaultMarketsListComponent.Factory): MarketsListComponent.Factory
fun bindMarketsListComponent(factory: DefaultMarketsEntryComponent.Factory): MarketsEntryComponent.Factory
}

View file

@ -0,0 +1,25 @@
package com.tangem.features.markets.tokenlist.api
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.domain.markets.TokenMarket
import com.tangem.features.markets.component.BottomSheetState
@Stable
interface MarketsTokenListComponent {
@Composable
fun BottomSheetContent(
bottomSheetState: State<BottomSheetState>,
onHeaderSizeChange: (Dp) -> Unit,
modifier: Modifier,
)
interface Factory {
fun create(context: AppComponentContext, onTokenSelected: (TokenMarket) -> Unit): MarketsTokenListComponent
}
}

View file

@ -1,4 +1,4 @@
package com.tangem.features.markets.component.impl
package com.tangem.features.markets.tokenlist.impl
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@ -9,20 +9,30 @@ import androidx.compose.ui.unit.Dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.domain.markets.TokenMarket
import com.tangem.features.markets.component.BottomSheetState
import com.tangem.features.markets.component.MarketsListComponent
import com.tangem.features.markets.model.MarketsListModel
import com.tangem.features.markets.ui.MarketsList
import com.tangem.features.markets.tokenlist.api.MarketsTokenListComponent
import com.tangem.features.markets.tokenlist.impl.model.MarketsListModel
import com.tangem.features.markets.tokenlist.impl.ui.MarketsList
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
internal class DefaultMarketsListComponent @AssistedInject constructor(
@Assisted context: AppComponentContext,
) : MarketsListComponent, AppComponentContext by context {
class DefaultMarketsTokenListComponent @AssistedInject constructor(
@Assisted appComponentContext: AppComponentContext,
@Assisted private val onTokenSelected: (TokenMarket) -> Unit,
) : AppComponentContext by appComponentContext, MarketsTokenListComponent {
private val model: MarketsListModel = getOrCreateModel()
init {
model.tokenSelected
.onEach { onTokenSelected(it) }
.launchIn(componentScope)
}
@Composable
override fun BottomSheetContent(
bottomSheetState: State<BottomSheetState>,
@ -45,7 +55,10 @@ internal class DefaultMarketsListComponent @AssistedInject constructor(
}
@AssistedFactory
interface Factory : MarketsListComponent.Factory {
override fun create(context: AppComponentContext): DefaultMarketsListComponent
interface Factory : MarketsTokenListComponent.Factory {
override fun create(
context: AppComponentContext,
onTokenSelected: (TokenMarket) -> Unit,
): DefaultMarketsTokenListComponent
}
}

View file

@ -0,0 +1,20 @@
package com.tangem.features.markets.tokenlist.impl.di
import com.tangem.features.markets.tokenlist.api.MarketsTokenListComponent
import com.tangem.features.markets.tokenlist.impl.DefaultMarketsTokenListComponent
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 ComponentModule {
@Binds
@Singleton
fun bindMarketsTokenListComponent(
factory: DefaultMarketsTokenListComponent.Factory,
): MarketsTokenListComponent.Factory
}

View file

@ -1,8 +1,8 @@
package com.tangem.features.markets.di
package com.tangem.features.markets.tokenlist.impl.di
import com.tangem.core.decompose.di.DecomposeComponent
import com.tangem.core.decompose.model.Model
import com.tangem.features.markets.model.MarketsListModel
import com.tangem.features.markets.tokenlist.impl.model.MarketsListModel
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn

View file

@ -1,4 +1,4 @@
package com.tangem.features.markets.model
package com.tangem.features.markets.tokenlist.impl.model
import androidx.compose.runtime.Stable
import arrow.core.getOrElse
@ -7,11 +7,13 @@ import com.tangem.core.decompose.model.Model
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.markets.GetMarketsTokenListFlowUseCase
import com.tangem.domain.markets.TokenMarket
import com.tangem.features.markets.component.BottomSheetState
import com.tangem.features.markets.model.statemanager.MarketsListUMStateManager
import com.tangem.features.markets.model.statemanager.MarketsListBatchFlowManager
import com.tangem.features.markets.ui.entity.ListUM
import com.tangem.features.markets.ui.entity.SortByTypeUM
import com.tangem.features.markets.tokenlist.impl.model.statemanager.MarketsListUMStateManager
import com.tangem.features.markets.tokenlist.impl.model.statemanager.MarketsListBatchFlowManager
import com.tangem.features.markets.tokenlist.impl.ui.entity.ListUM
import com.tangem.features.markets.tokenlist.impl.ui.entity.MarketsListItemUM
import com.tangem.features.markets.tokenlist.impl.ui.entity.SortByTypeUM
import com.tangem.utils.Provider
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.JobHolder
@ -32,6 +34,8 @@ internal class MarketsListModel @Inject constructor(
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
) : Model() {
private var updateQuotesJob = JobHolder()
private val currentAppCurrency = getSelectedAppCurrencyUseCase()
.map { maybeAppCurrency ->
maybeAppCurrency.getOrElse { AppCurrency.Default }
@ -47,8 +51,8 @@ internal class MarketsListModel @Inject constructor(
onLoadMoreUiItems = { activeListManager.loadMore() },
visibleItemsChanged = { visibleItemIds.value = it },
onRetryButtonClicked = { activeListManager.reload() },
onTokenClick = { onTokenUIClicked(it) },
)
private val mainMarketsListManager = MarketsListBatchFlowManager(
getMarketsTokenListFlowUseCase = getMarketsTokenListFlowUseCase,
batchFlowType = GetMarketsTokenListFlowUseCase.BatchFlowType.Main,
@ -59,6 +63,7 @@ internal class MarketsListModel @Inject constructor(
modelScope = modelScope,
dispatchers = dispatchers,
)
private val searchMarketsListManager = MarketsListBatchFlowManager(
getMarketsTokenListFlowUseCase = getMarketsTokenListFlowUseCase,
batchFlowType = GetMarketsTokenListFlowUseCase.BatchFlowType.Search,
@ -72,6 +77,10 @@ internal class MarketsListModel @Inject constructor(
private var activeListManager: MarketsListBatchFlowManager = mainMarketsListManager
private val _tokenSelected = MutableSharedFlow<TokenMarket>()
val tokenSelected = _tokenSelected.asSharedFlow()
val containerBottomSheetState = MutableStateFlow(BottomSheetState.COLLAPSED)
val state = marketsListUMStateManager.state.asStateFlow()
@ -169,6 +178,7 @@ internal class MarketsListModel @Inject constructor(
}
.distinctUntilChanged()
.collectLatest { visibleBatchKeys ->
// TODO load batch on scroll heat area
activeListManager.loadCharts(visibleBatchKeys, marketsListUMStateManager.selectedInterval)
}
}
@ -210,7 +220,13 @@ internal class MarketsListModel @Inject constructor(
mainMarketsListManager.reload()
}
private var updateQuotesJob = JobHolder()
private fun onTokenUIClicked(token: MarketsListItemUM) {
modelScope.launch {
activeListManager.getTokenById(token.id)?.let { found ->
_tokenSelected.emit(found)
}
}
}
private fun CoroutineScope.loadQuotesWithTimer(timeMillis: Long) {
launch {
while (true) {

View file

@ -1,4 +1,4 @@
package com.tangem.features.markets.model.converters
package com.tangem.features.markets.tokenlist.impl.model.converters
import com.tangem.common.ui.charts.state.DefaultPointValuesConverter
import com.tangem.common.ui.charts.state.MarketChartData
@ -7,8 +7,8 @@ import com.tangem.core.ui.components.marketprice.PriceChangeType
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.markets.TokenMarket
import com.tangem.features.markets.ui.entity.MarketsListItemUM
import com.tangem.features.markets.ui.entity.MarketsListUM.TrendInterval
import com.tangem.features.markets.tokenlist.impl.ui.entity.MarketsListItemUM
import com.tangem.features.markets.tokenlist.impl.ui.entity.MarketsListUM.TrendInterval
import com.tangem.utils.converter.Converter
import java.math.BigDecimal
import java.math.RoundingMode
@ -110,7 +110,7 @@ internal class MarketsTokenItemConverter(
DefaultPointValuesConverter.convert(
MarketChartData.Data(
y = ct.priceY,
x = ct.timeStamp.map { it.toBigDecimal() },
x = ct.timeStamps.map { it.toBigDecimal() },
),
)
}

View file

@ -1,14 +1,14 @@
package com.tangem.features.markets.model.statemanager
package com.tangem.features.markets.tokenlist.impl.model.statemanager
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.markets.*
import com.tangem.features.markets.model.converters.MarketsTokenItemConverter
import com.tangem.features.markets.model.utils.logAction
import com.tangem.features.markets.model.utils.logStatus
import com.tangem.features.markets.model.utils.logUpdateResults
import com.tangem.features.markets.ui.entity.MarketsListItemUM
import com.tangem.features.markets.ui.entity.MarketsListUM.TrendInterval
import com.tangem.features.markets.ui.entity.SortByTypeUM
import com.tangem.features.markets.tokenlist.impl.model.converters.MarketsTokenItemConverter
import com.tangem.features.markets.tokenlist.impl.model.utils.logAction
import com.tangem.features.markets.tokenlist.impl.model.utils.logStatus
import com.tangem.features.markets.tokenlist.impl.model.utils.logUpdateResults
import com.tangem.features.markets.tokenlist.impl.ui.entity.MarketsListItemUM
import com.tangem.features.markets.tokenlist.impl.ui.entity.MarketsListUM.TrendInterval
import com.tangem.features.markets.tokenlist.impl.ui.entity.SortByTypeUM
import com.tangem.pagination.*
import com.tangem.utils.Provider
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
@ -281,6 +281,10 @@ internal class MarketsListBatchFlowManager(
.toSet()
}
fun getTokenById(id: String): TokenMarket? {
return batchFlow.state.value.data.map { it.data }.flatten().find { it.id == id }
}
private fun SortByTypeUM.toRequestOrder(): TokenMarketListConfig.Order {
return when (this) {
SortByTypeUM.Rating -> TokenMarketListConfig.Order.ByRating

View file

@ -1,4 +1,4 @@
package com.tangem.features.markets.model.statemanager
package com.tangem.features.markets.tokenlist.impl.model.statemanager
import androidx.compose.runtime.Stable
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
@ -7,11 +7,11 @@ import com.tangem.core.ui.event.consumedEvent
import com.tangem.core.ui.event.triggeredEvent
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.features.markets.impl.R
import com.tangem.features.markets.ui.entity.SortByBottomSheetContentUM
import com.tangem.features.markets.ui.entity.ListUM
import com.tangem.features.markets.ui.entity.MarketsListItemUM
import com.tangem.features.markets.ui.entity.MarketsListUM
import com.tangem.features.markets.ui.entity.SortByTypeUM
import com.tangem.features.markets.tokenlist.impl.ui.entity.SortByBottomSheetContentUM
import com.tangem.features.markets.tokenlist.impl.ui.entity.ListUM
import com.tangem.features.markets.tokenlist.impl.ui.entity.MarketsListItemUM
import com.tangem.features.markets.tokenlist.impl.ui.entity.MarketsListUM
import com.tangem.features.markets.tokenlist.impl.ui.entity.SortByTypeUM
import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.flow.*
@ -20,6 +20,7 @@ internal class MarketsListUMStateManager(
private val onLoadMoreUiItems: () -> Unit,
private val visibleItemsChanged: (itemsKeys: List<String>) -> Unit,
private val onRetryButtonClicked: () -> Unit,
private val onTokenClick: (MarketsListItemUM) -> Unit,
) {
private var sortByBottomSheetIsShown
@ -106,6 +107,7 @@ internal class MarketsListUMStateManager(
showUnder100kTokens = true,
onShowTokensUnder100kClicked = { },
triggerScrollReset = consumedEvent(),
onItemClick = onTokenClick,
),
)
}

View file

@ -1,4 +1,4 @@
package com.tangem.features.markets.model.utils
package com.tangem.features.markets.tokenlist.impl.model.utils
import com.tangem.domain.markets.TokenMarket
import com.tangem.domain.markets.TokenMarketListConfig

View file

@ -1,4 +1,4 @@
package com.tangem.features.markets.ui
package com.tangem.features.markets.tokenlist.impl.ui
import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedVisibility
@ -36,13 +36,13 @@ import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.markets.component.BottomSheetState
import com.tangem.features.markets.impl.R
import com.tangem.features.markets.ui.components.MarketsListLazyColumn
import com.tangem.features.markets.ui.components.MarketsListSortByBottomSheet
import com.tangem.features.markets.ui.entity.ListUM
import com.tangem.features.markets.ui.entity.MarketsListUM
import com.tangem.features.markets.ui.entity.SortByBottomSheetContentUM
import com.tangem.features.markets.ui.entity.SortByTypeUM
import com.tangem.features.markets.ui.preview.MarketChartListItemPreviewDataProvider
import com.tangem.features.markets.tokenlist.impl.ui.components.MarketsListLazyColumn
import com.tangem.features.markets.tokenlist.impl.ui.components.MarketsListSortByBottomSheet
import com.tangem.features.markets.tokenlist.impl.ui.entity.ListUM
import com.tangem.features.markets.tokenlist.impl.ui.entity.MarketsListUM
import com.tangem.features.markets.tokenlist.impl.ui.entity.SortByBottomSheetContentUM
import com.tangem.features.markets.tokenlist.impl.ui.entity.SortByTypeUM
import com.tangem.features.markets.tokenlist.impl.ui.preview.MarketChartListItemPreviewDataProvider
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
@ -242,6 +242,7 @@ private fun Preview() {
visibleIdsChanged = {},
onShowTokensUnder100kClicked = {},
triggerScrollReset = consumedEvent(),
onItemClick = {},
),
searchBar = SearchBarUM(
placeholderText = resourceReference(R.string.manage_tokens_search_placeholder),

View file

@ -1,4 +1,4 @@
package com.tangem.features.markets.ui.components
package com.tangem.features.markets.tokenlist.impl.ui.components
import android.content.res.Configuration
import androidx.compose.animation.Animatable
@ -45,8 +45,8 @@ import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.windowsize.WindowSizeType
import com.tangem.features.markets.impl.R
import com.tangem.features.markets.ui.entity.MarketsListItemUM
import com.tangem.features.markets.ui.preview.MarketChartListItemPreviewDataProvider
import com.tangem.features.markets.tokenlist.impl.ui.entity.MarketsListItemUM
import com.tangem.features.markets.tokenlist.impl.ui.preview.MarketChartListItemPreviewDataProvider
import com.tangem.utils.StringsSigns.MINUS
import kotlinx.coroutines.launch
import kotlin.math.roundToInt

View file

@ -1,4 +1,4 @@
package com.tangem.features.markets.ui.components
package com.tangem.features.markets.tokenlist.impl.ui.components
import android.content.res.Configuration
import androidx.compose.foundation.background

View file

@ -1,4 +1,4 @@
package com.tangem.features.markets.ui.components
package com.tangem.features.markets.tokenlist.impl.ui.components
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
@ -21,7 +21,7 @@ import com.tangem.core.ui.event.EventEffect
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.markets.impl.R
import com.tangem.features.markets.ui.entity.ListUM
import com.tangem.features.markets.tokenlist.impl.ui.entity.ListUM
import kotlinx.coroutines.launch
private const val LOAD_NEXT_PAGE_ON_END_INDEX = 50
@ -91,7 +91,10 @@ internal fun MarketsListLazyColumn(
items = state.items,
key = { it.id },
) { item ->
MarketsListItem(model = item)
MarketsListItem(
model = item,
onClick = { state.onItemClick(item) },
)
}
if (isInSearchMode && state.showUnder100kTokens.not()) {

View file

@ -1,4 +1,4 @@
package com.tangem.features.markets.ui.components
package com.tangem.features.markets.tokenlist.impl.ui.components
import android.content.res.Configuration
import androidx.compose.foundation.background
@ -19,8 +19,8 @@ import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.markets.impl.R
import com.tangem.features.markets.ui.entity.SortByBottomSheetContentUM
import com.tangem.features.markets.ui.entity.SortByTypeUM
import com.tangem.features.markets.tokenlist.impl.ui.entity.SortByBottomSheetContentUM
import com.tangem.features.markets.tokenlist.impl.ui.entity.SortByTypeUM
@Composable
fun MarketsListSortByBottomSheet(config: TangemBottomSheetConfig) {

View file

@ -1,4 +1,4 @@
package com.tangem.features.markets.ui.components
package com.tangem.features.markets.tokenlist.impl.ui.components
import android.content.res.Configuration
import androidx.compose.foundation.layout.Arrangement

View file

@ -1,4 +1,4 @@
package com.tangem.features.markets.ui.entity
package com.tangem.features.markets.tokenlist.impl.ui.entity
import androidx.compose.runtime.Immutable
import com.tangem.common.ui.charts.state.MarketChartLook

View file

@ -1,4 +1,4 @@
package com.tangem.features.markets.ui.entity
package com.tangem.features.markets.tokenlist.impl.ui.entity
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
@ -46,6 +46,7 @@ sealed class ListUM {
val visibleIdsChanged: (List<String>) -> Unit,
val onShowTokensUnder100kClicked: () -> Unit,
val triggerScrollReset: StateEvent<Unit>,
val onItemClick: (MarketsListItemUM) -> Unit,
) : ListUM()
data object Loading : ListUM()

View file

@ -1,4 +1,4 @@
package com.tangem.features.markets.ui.entity
package com.tangem.features.markets.tokenlist.impl.ui.entity
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent

View file

@ -1,10 +1,10 @@
@file:Suppress("MagicNumber")
package com.tangem.features.markets.ui.preview
package com.tangem.features.markets.tokenlist.impl.ui.preview
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import com.tangem.common.ui.charts.state.MarketChartRawData
import com.tangem.core.ui.components.marketprice.PriceChangeType
import com.tangem.features.markets.ui.entity.MarketsListItemUM
import com.tangem.features.markets.tokenlist.impl.ui.entity.MarketsListItemUM
internal class MarketChartListItemPreviewDataProvider : CollectionPreviewParameterProvider<MarketsListItemUM>(
collection = listOf(

View file

@ -10,7 +10,7 @@ import com.tangem.core.ui.UiDependencies
import com.tangem.core.ui.screen.ComposeFragment
import com.tangem.feature.wallet.presentation.router.InnerWalletRouter
import com.tangem.features.markets.MarketsFeatureToggles
import com.tangem.features.markets.component.MarketsListComponent
import com.tangem.features.markets.component.MarketsEntryComponent
import com.tangem.features.wallet.navigation.WalletRouter
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.hilt.android.AndroidEntryPoint
@ -32,7 +32,7 @@ internal class WalletFragment : ComposeFragment() {
internal lateinit var walletRouter: WalletRouter
@Inject
internal lateinit var marketsListComponentFactory: MarketsListComponent.Factory
internal lateinit var marketsEntryComponentFactory: MarketsEntryComponent.Factory
@Inject
internal lateinit var coroutineDispatcherProvider: CoroutineDispatcherProvider
@ -43,7 +43,7 @@ internal class WalletFragment : ComposeFragment() {
@Inject
internal lateinit var marketsFeatureToggles: MarketsFeatureToggles
private var marketsListComponent: MarketsListComponent? = null
private var marketsEntryComponent: MarketsEntryComponent? = null
private val _walletRouter: InnerWalletRouter
get() = requireNotNull(walletRouter as? InnerWalletRouter) {
@ -61,7 +61,7 @@ internal class WalletFragment : ComposeFragment() {
hiltComponentBuilder = componentBuilder,
)
marketsListComponent = marketsListComponentFactory.create(appContext)
marketsEntryComponent = marketsEntryComponentFactory.create(appContext)
}
}
@ -69,7 +69,7 @@ internal class WalletFragment : ComposeFragment() {
override fun ScreenContent(modifier: Modifier) {
_walletRouter.Initialize(
onFinish = requireActivity()::finish,
marketsListComponent = marketsListComponent,
marketsEntryComponent = marketsEntryComponent,
)
}

View file

@ -25,7 +25,7 @@ import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensScree
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensViewModel
import com.tangem.feature.wallet.presentation.wallet.ui.WalletScreen
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletViewModel
import com.tangem.features.markets.component.MarketsListComponent
import com.tangem.features.markets.component.MarketsEntryComponent
import kotlin.properties.Delegates
/** Default implementation of wallet feature router */
@ -41,7 +41,7 @@ internal class DefaultWalletRouter(
override fun getEntryFragment(): Fragment = WalletFragment.create()
@Composable
override fun Initialize(onFinish: () -> Unit, marketsListComponent: MarketsListComponent?) {
override fun Initialize(onFinish: () -> Unit, marketsEntryComponent: MarketsEntryComponent?) {
this.onFinish = onFinish
NavHost(
@ -56,7 +56,7 @@ internal class DefaultWalletRouter(
WalletScreen(
state = viewModel.uiState.collectAsStateWithLifecycle().value,
marketsListComponent = marketsListComponent,
marketsEntryComponent = marketsEntryComponent,
)
}

View file

@ -4,7 +4,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.features.markets.component.MarketsListComponent
import com.tangem.features.markets.component.MarketsEntryComponent
import com.tangem.features.wallet.navigation.WalletRouter
/**
@ -24,7 +24,7 @@ internal interface InnerWalletRouter : WalletRouter {
* @param onFinish finish activity callback
*/
@Composable
fun Initialize(onFinish: () -> Unit, marketsListComponent: MarketsListComponent?)
fun Initialize(onFinish: () -> Unit, marketsEntryComponent: MarketsEntryComponent?)
/** Pop back stack */
fun popBackStack()

View file

@ -70,12 +70,12 @@ import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.balances
import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.depositButton
import com.tangem.feature.wallet.presentation.wallet.ui.utils.changeWalletAnimator
import com.tangem.features.markets.component.BottomSheetState
import com.tangem.features.markets.component.MarketsListComponent
import com.tangem.features.markets.component.MarketsEntryComponent
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.launch
@Composable
internal fun WalletScreen(state: WalletScreenState, marketsListComponent: MarketsListComponent?) {
internal fun WalletScreen(state: WalletScreenState, marketsEntryComponent: MarketsEntryComponent?) {
BackHandler(onBack = state.onBackClick)
// It means that screen is still initializing
@ -98,7 +98,7 @@ internal fun WalletScreen(state: WalletScreenState, marketsListComponent: Market
snackbarHostState = snackbarHostState,
isAutoScroll = isAutoScroll,
onAutoScrollReset = { isAutoScroll.value = false },
marketsListComponent = marketsListComponent,
marketsEntryComponent = marketsEntryComponent,
alertConfig = alertConfig,
)
@ -119,7 +119,7 @@ private fun WalletContent(
walletsListState: LazyListState,
snackbarHostState: SnackbarHostState,
isAutoScroll: State<Boolean>,
marketsListComponent: MarketsListComponent?,
marketsEntryComponent: MarketsEntryComponent?,
alertConfig: WalletAlertState?,
onAutoScrollReset: () -> Unit,
) {
@ -216,7 +216,7 @@ private fun WalletContent(
)
}
if (marketsListComponent != null) {
if (marketsEntryComponent != null) {
val bottomSheetState = remember {
mutableStateOf(BottomSheetState.COLLAPSED)
}
@ -232,7 +232,7 @@ private fun WalletContent(
alertConfig = alertConfig,
onBottomSheetStateChange = { bottomSheetState.value = it },
bottomSheetContent = {
marketsListComponent.BottomSheetContent(
marketsEntryComponent.BottomSheetContent(
bottomSheetState = bottomSheetState,
onHeaderSizeChange = { headerSize = it },
modifier = Modifier,
@ -638,7 +638,7 @@ private fun WalletScreen_Preview(@PreviewParameter(WalletScreenPreviewProvider::
TangemThemePreview {
WalletScreen(
state = data,
marketsListComponent = null,
marketsEntryComponent = null,
)
}
}