Updated on 2026-08-14
This commit is contained in:
commit
7c629b68d1
1179 changed files with 24718 additions and 16703 deletions
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.features.markets.deeplink
|
||||
|
||||
interface MarketsDeepLinkHandler {
|
||||
|
||||
interface Factory {
|
||||
fun create(): MarketsDeepLinkHandler
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.features.markets.deeplink
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
interface MarketsTokenDetailDeepLinkHandler {
|
||||
|
||||
interface Factory {
|
||||
fun create(coroutineScope: CoroutineScope, params: Map<String, String>): MarketsTokenDetailDeepLinkHandler
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ package com.tangem.features.markets.token.block
|
|||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Stable
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
package com.tangem.features.markets.tokenlist
|
||||
|
||||
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.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.features.markets.entry.BottomSheetState
|
||||
|
||||
@Stable
|
||||
interface MarketsTokenListComponent : ComposableContentComponent {
|
||||
|
||||
@Composable
|
||||
fun BottomSheetContent(
|
||||
bottomSheetState: State<BottomSheetState>,
|
||||
onHeaderSizeChange: (Dp) -> Unit,
|
||||
modifier: Modifier,
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Unit, MarketsTokenListComponent>
|
||||
}
|
||||
|
|
@ -17,6 +17,9 @@ dependencies {
|
|||
api(projects.features.onramp.api)
|
||||
implementation(projects.core.navigation)
|
||||
|
||||
/* Data */
|
||||
implementation(projects.data.common)
|
||||
|
||||
/* Domain */
|
||||
implementation(projects.domain.appCurrency)
|
||||
implementation(projects.domain.appCurrency.models)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.features.markets.deeplink
|
||||
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultMarketsDeepLinkHandler @AssistedInject constructor(
|
||||
appRouter: AppRouter,
|
||||
) : MarketsDeepLinkHandler {
|
||||
|
||||
init {
|
||||
appRouter.push(AppRoute.Markets)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : MarketsDeepLinkHandler.Factory {
|
||||
override fun create(): DefaultMarketsDeepLinkHandler
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package com.tangem.features.markets.deeplink
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.data.common.currency.getTokenIconUrlFromDefaultHost
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.markets.GetTokenMarketInfoUseCase
|
||||
import com.tangem.domain.markets.TokenMarketParams
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
internal class DefaultMarketsTokenDetailDeepLinkHandler @AssistedInject constructor(
|
||||
@Assisted scope: CoroutineScope,
|
||||
@Assisted queryParams: Map<String, String>,
|
||||
appRouter: AppRouter,
|
||||
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
getTokenMarketInfoUseCase: GetTokenMarketInfoUseCase,
|
||||
) : MarketsTokenDetailDeepLinkHandler {
|
||||
|
||||
init {
|
||||
val tokenId = queryParams[TOKEN_ID_KEY]
|
||||
|
||||
val rawTokenId = CryptoCurrency.RawID(tokenId.orEmpty())
|
||||
|
||||
scope.launch {
|
||||
val appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse {
|
||||
AppCurrency.Default
|
||||
}
|
||||
val tokenInfo = getTokenMarketInfoUseCase(
|
||||
appCurrency = appCurrency,
|
||||
tokenId = rawTokenId,
|
||||
tokenSymbol = TOKEN_SYMBOL_KEY,
|
||||
).getOrElse {
|
||||
Timber.e("Failed to get market token info")
|
||||
return@launch
|
||||
}
|
||||
|
||||
appRouter.push(
|
||||
AppRoute.MarketsTokenDetails(
|
||||
token = TokenMarketParams(
|
||||
id = rawTokenId,
|
||||
name = tokenInfo.name,
|
||||
symbol = tokenInfo.symbol,
|
||||
tokenQuotes = TokenMarketParams.Quotes(
|
||||
currentPrice = tokenInfo.quotes.currentPrice,
|
||||
h24Percent = tokenInfo.quotes.h24ChangePercent,
|
||||
weekPercent = tokenInfo.quotes.weekChangePercent,
|
||||
monthPercent = tokenInfo.quotes.monthChangePercent,
|
||||
),
|
||||
imageUrl = getTokenIconUrlFromDefaultHost(rawTokenId),
|
||||
),
|
||||
appCurrency = appCurrency,
|
||||
showPortfolio = true,
|
||||
analyticsParams = null,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : MarketsTokenDetailDeepLinkHandler.Factory {
|
||||
override fun create(
|
||||
coroutineScope: CoroutineScope,
|
||||
queryParams: Map<String, String>,
|
||||
): DefaultMarketsTokenDetailDeepLinkHandler
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val TOKEN_ID_KEY = "token_id"
|
||||
const val TOKEN_SYMBOL_KEY = "token_symbol"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.features.markets.deeplink.di
|
||||
|
||||
import com.tangem.features.markets.deeplink.DefaultMarketsDeepLinkHandler
|
||||
import com.tangem.features.markets.deeplink.DefaultMarketsTokenDetailDeepLinkHandler
|
||||
import com.tangem.features.markets.deeplink.MarketsDeepLinkHandler
|
||||
import com.tangem.features.markets.deeplink.MarketsTokenDetailDeepLinkHandler
|
||||
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 MarketsDeepLinkModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindMarketsDeepLinkHandlerFactory(impl: DefaultMarketsDeepLinkHandler.Factory): MarketsDeepLinkHandler.Factory
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindMarketsTokenDetailDeepLinkHandlerFactory(
|
||||
impl: DefaultMarketsTokenDetailDeepLinkHandler.Factory,
|
||||
): MarketsTokenDetailDeepLinkHandler.Factory
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ import com.tangem.core.decompose.context.child
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.res.LocalMainBottomSheetColor
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.markets.details.MarketsTokenDetailsComponent
|
||||
import com.tangem.features.markets.details.MarketsTokenDetailsComponent.Params
|
||||
import com.tangem.features.markets.details.impl.analytics.MarketDetailsAnalyticsEvent
|
||||
|
|
|
|||
|
|
@ -1,117 +0,0 @@
|
|||
package com.tangem.features.markets.details.impl.ui.components
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.components.TextShimmer
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
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.utils.PreviewShimmerContainer
|
||||
import com.tangem.features.markets.impl.R
|
||||
import com.tangem.utils.StringsSigns
|
||||
|
||||
@Composable
|
||||
internal fun Description(
|
||||
description: TextReference,
|
||||
hasFullDescription: Boolean,
|
||||
onReadMoreClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (hasFullDescription) {
|
||||
val text = buildAnnotatedString {
|
||||
withStyle(SpanStyle(color = TangemTheme.colors.text.secondary)) {
|
||||
append(description.resolveReference())
|
||||
}
|
||||
withStyle(SpanStyle(color = TangemTheme.colors.text.accent)) {
|
||||
append(
|
||||
" " + stringResourceSafe(R.string.common_read_more).replace(
|
||||
' ',
|
||||
StringsSigns.NON_BREAKING_SPACE,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Text(
|
||||
modifier = modifier
|
||||
.clickable(
|
||||
interactionSource = null,
|
||||
indication = null,
|
||||
onClick = onReadMoreClick,
|
||||
),
|
||||
text = text,
|
||||
style = TangemTheme.typography.body2,
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
modifier = modifier,
|
||||
text = description.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun DescriptionPlaceholder(modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
) {
|
||||
TextShimmer(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
style = TangemTheme.typography.body2,
|
||||
textSizeHeight = true,
|
||||
)
|
||||
TextShimmer(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
style = TangemTheme.typography.body2,
|
||||
textSizeHeight = true,
|
||||
)
|
||||
TextShimmer(
|
||||
modifier = Modifier.fillMaxWidth(fraction = 0.8f),
|
||||
style = TangemTheme.typography.body2,
|
||||
textSizeHeight = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun ContentPreview() {
|
||||
TangemThemePreview {
|
||||
Description(
|
||||
description = stringReference(
|
||||
"XRP (XRP) is a cryptocurrency launched in January 2009, where the first " +
|
||||
"genesis block was mined on 9th January 2009",
|
||||
),
|
||||
hasFullDescription = true,
|
||||
onReadMoreClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun PreviewPlaceholder() {
|
||||
TangemThemePreview {
|
||||
PreviewShimmerContainer(
|
||||
actualContent = {
|
||||
ContentPreview()
|
||||
},
|
||||
shimmerContent = {
|
||||
DescriptionPlaceholder()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,8 @@ import androidx.compose.ui.Modifier
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.markets.details.impl.ui.state.MarketsTokenDetailsUM
|
||||
import com.tangem.core.ui.components.UnableToLoadData
|
||||
import com.tangem.core.ui.components.items.DescriptionItem
|
||||
import com.tangem.core.ui.components.items.DescriptionPlaceholder
|
||||
|
||||
internal fun LazyListScope.tokenMarketDetailsBody(
|
||||
state: MarketsTokenDetailsUM.Body,
|
||||
|
|
@ -69,7 +71,7 @@ private fun LazyListScope.error(state: MarketsTokenDetailsUM.Body.Error) {
|
|||
|
||||
private fun LazyListScope.description(description: MarketsTokenDetailsUM.Description) {
|
||||
item("description") {
|
||||
Description(
|
||||
DescriptionItem(
|
||||
modifier = Modifier.blockPaddings(),
|
||||
description = description.shortDescription,
|
||||
hasFullDescription = description.fullDescription != null,
|
||||
|
|
|
|||
|
|
@ -5,20 +5,15 @@ import androidx.compose.runtime.Stable
|
|||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import com.arkivanov.decompose.ExperimentalDecomposeApi
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
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.pushNew
|
||||
import com.arkivanov.decompose.router.stack.popWhile
|
||||
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.navigation.Router
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.markets.TokenMarket
|
||||
import com.tangem.domain.markets.toSerializableParam
|
||||
import com.tangem.features.markets.details.MarketsTokenDetailsComponent
|
||||
import com.tangem.core.decompose.navigation.inner.InnerRouter
|
||||
import com.tangem.features.markets.entry.BottomSheetState
|
||||
import com.tangem.features.markets.entry.MarketsEntryComponent
|
||||
import com.tangem.features.markets.entry.impl.MarketsEntryChildFactory.Child
|
||||
|
|
@ -35,7 +30,12 @@ internal class DefaultMarketsEntryComponent @AssistedInject constructor(
|
|||
|
||||
private val stackNavigation = StackNavigation<Child>()
|
||||
|
||||
val stack: Value<ChildStack<Child, Any>> = childStack(
|
||||
private val innerRouter = InnerRouter<Child>(
|
||||
stackNavigation = stackNavigation,
|
||||
popCallback = { onChildBack() },
|
||||
)
|
||||
|
||||
private val stack: Value<ChildStack<Child, Any>> = childStack(
|
||||
key = "main",
|
||||
source = stackNavigation,
|
||||
serializer = Child.serializer(),
|
||||
|
|
@ -46,9 +46,8 @@ internal class DefaultMarketsEntryComponent @AssistedInject constructor(
|
|||
child = configuration,
|
||||
appComponentContext = childByContext(
|
||||
componentContext = factoryContext,
|
||||
router = createRouter(configuration),
|
||||
router = innerRouter,
|
||||
),
|
||||
onTokenSelected = ::marketsListTokenSelected,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
@ -68,32 +67,9 @@ internal class DefaultMarketsEntryComponent @AssistedInject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalDecomposeApi::class)
|
||||
private fun marketsListTokenSelected(token: TokenMarket, appCurrency: AppCurrency) {
|
||||
stackNavigation.pushNew(
|
||||
configuration = Child.TokenDetails(
|
||||
params = MarketsTokenDetailsComponent.Params(
|
||||
token = token.toSerializableParam(),
|
||||
appCurrency = appCurrency,
|
||||
showPortfolio = true,
|
||||
analyticsParams = MarketsTokenDetailsComponent.AnalyticsParams(
|
||||
blockchain = null,
|
||||
source = "Market",
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun AppComponentContext.createRouter(child: Child): Router {
|
||||
return when (child) {
|
||||
is Child.TokenDetails -> {
|
||||
MarketTokenDetailsRouter(
|
||||
contextRouter = this.router,
|
||||
stackNavigation = stackNavigation,
|
||||
)
|
||||
}
|
||||
else -> this.router
|
||||
private fun onChildBack() {
|
||||
if (stack.value.active.configuration !is Child.TokenList) {
|
||||
stackNavigation.popWhile { it != Child.TokenList }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
package com.tangem.features.markets.entry.impl
|
||||
|
||||
import com.arkivanov.decompose.router.stack.StackNavigation
|
||||
import com.arkivanov.decompose.router.stack.popWhile
|
||||
import com.tangem.core.decompose.navigation.Route
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
internal class MarketTokenDetailsRouter(
|
||||
private val contextRouter: Router,
|
||||
private val stackNavigation: StackNavigation<MarketsEntryChildFactory.Child>,
|
||||
) : Router by contextRouter {
|
||||
|
||||
override fun pop(onComplete: (isSuccess: Boolean) -> Unit) {
|
||||
stackNavigation.popWhile({ it != MarketsEntryChildFactory.Child.TokenList }, onComplete)
|
||||
}
|
||||
|
||||
override fun popTo(route: Route, onComplete: (isSuccess: Boolean) -> Unit) {
|
||||
/** Not allowed */
|
||||
}
|
||||
|
||||
override fun popTo(routeClass: KClass<out Route>, onComplete: (isSuccess: Boolean) -> Unit) {
|
||||
/** Not allowed */
|
||||
}
|
||||
}
|
||||
|
|
@ -2,11 +2,9 @@ package com.tangem.features.markets.entry.impl
|
|||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.markets.TokenMarket
|
||||
import com.tangem.core.decompose.navigation.Route
|
||||
import com.tangem.features.markets.details.MarketsTokenDetailsComponent
|
||||
import com.tangem.features.markets.entry.impl.MarketsEntryChildFactory.Child
|
||||
import com.tangem.features.markets.tokenlist.api.MarketsTokenListComponent
|
||||
import com.tangem.features.markets.tokenlist.MarketsTokenListComponent
|
||||
import kotlinx.serialization.Serializable
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -17,7 +15,7 @@ internal class MarketsEntryChildFactory @Inject constructor(
|
|||
|
||||
@Serializable
|
||||
@Immutable
|
||||
sealed interface Child {
|
||||
sealed interface Child : Route {
|
||||
|
||||
@Serializable
|
||||
@Immutable
|
||||
|
|
@ -28,11 +26,7 @@ internal class MarketsEntryChildFactory @Inject constructor(
|
|||
data class TokenDetails(val params: MarketsTokenDetailsComponent.Params) : Child
|
||||
}
|
||||
|
||||
fun createChild(
|
||||
child: Child,
|
||||
appComponentContext: AppComponentContext,
|
||||
onTokenSelected: (TokenMarket, AppCurrency) -> Unit,
|
||||
): Any {
|
||||
fun createChild(child: Child, appComponentContext: AppComponentContext): Any {
|
||||
return when (child) {
|
||||
is Child.TokenDetails -> {
|
||||
tokenDetailsComponentFactory.create(
|
||||
|
|
@ -43,7 +37,7 @@ internal class MarketsEntryChildFactory @Inject constructor(
|
|||
is Child.TokenList -> {
|
||||
tokenListComponentFactory.create(
|
||||
context = appComponentContext,
|
||||
onTokenSelected = onTokenSelected,
|
||||
params = Unit,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
import com.tangem.features.markets.details.MarketsTokenDetailsComponent
|
||||
import com.tangem.features.markets.entry.BottomSheetState
|
||||
import com.tangem.features.markets.entry.impl.MarketsEntryChildFactory
|
||||
import com.tangem.features.markets.tokenlist.api.MarketsTokenListComponent
|
||||
import com.tangem.features.markets.tokenlist.MarketsTokenListComponent
|
||||
|
||||
@Composable
|
||||
internal fun EntryBottomSheetContent(
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
|||
import com.tangem.domain.core.lce.Lce
|
||||
import com.tangem.domain.markets.FilterAvailableNetworksForWalletUseCase
|
||||
import com.tangem.domain.markets.TokenMarketInfo
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.tokens.GetAllWalletsCryptoCurrencyStatusesUseCase
|
||||
import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase
|
||||
import com.tangem.domain.tokens.GetWalletTotalBalanceUseCase
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.TotalFiatBalance
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.tangem.domain.models.ArtworkModel
|
|||
import com.tangem.domain.tokens.model.TotalFiatBalance
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.models.isMultiCurrency
|
||||
import com.tangem.features.markets.portfolio.impl.loader.PortfolioData
|
||||
import com.tangem.features.markets.portfolio.impl.ui.state.AddToPortfolioBSContentUM
|
||||
import com.tangem.features.markets.portfolio.impl.ui.state.WalletSelectorBSContentUM
|
||||
|
|
|
|||
|
|
@ -21,9 +21,11 @@ import com.tangem.domain.managetokens.model.CurrencyUnsupportedState
|
|||
import com.tangem.domain.markets.SaveMarketTokensUseCase
|
||||
import com.tangem.domain.markets.TokenMarketInfo
|
||||
import com.tangem.domain.models.ArtworkModel
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.models.isMultiCurrency
|
||||
import com.tangem.domain.wallets.models.requireColdWallet
|
||||
import com.tangem.domain.wallets.usecase.GetCardImageUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
|
||||
import com.tangem.features.markets.impl.R
|
||||
|
|
@ -195,6 +197,7 @@ internal class MarketsPortfolioModel @Inject constructor(
|
|||
modelScope.launch {
|
||||
loadArtworksMutex.withLock {
|
||||
wallets.forEach { wallet ->
|
||||
wallet.requireColdWallet() // TODO [REDACTED_TASK_KEY]
|
||||
if (!loadedArtworks.containsKey(wallet.walletId)) {
|
||||
val artwork = getCardImageUseCase(
|
||||
cardId = wallet.cardId,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.domain.models.ArtworkModel
|
|||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.models.isMultiCurrency
|
||||
import com.tangem.features.markets.portfolio.impl.loader.PortfolioData
|
||||
import com.tangem.features.markets.portfolio.impl.ui.state.MyPortfolioUM
|
||||
import com.tangem.features.markets.portfolio.impl.ui.state.MyPortfolioUM.Tokens.AddButtonState
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ import com.tangem.core.ui.message.DialogMessage
|
|||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.onramp.model.OnrampSource
|
||||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.domain.tokens.legacy.TradeCryptoAction
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.tokens.model.TokenActionsState
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.features.markets.impl.R
|
||||
|
|
@ -59,7 +59,8 @@ internal class TokenActionsHandler @AssistedInject constructor(
|
|||
cryptoCurrencyData = cryptoCurrencyData,
|
||||
),
|
||||
)
|
||||
if (handleDemoMode(action, cryptoCurrencyData.userWallet)) return
|
||||
val userWallet = cryptoCurrencyData.userWallet
|
||||
if (userWallet is UserWallet.Cold && handleDemoMode(action, userWallet)) return
|
||||
|
||||
when (action) {
|
||||
TokenActionsBSContentUM.Action.Buy -> onBuyClick(cryptoCurrencyData)
|
||||
|
|
@ -72,7 +73,7 @@ internal class TokenActionsHandler @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleDemoMode(action: TokenActionsBSContentUM.Action, userWallet: UserWallet): Boolean {
|
||||
private fun handleDemoMode(action: TokenActionsBSContentUM.Action, userWallet: UserWallet.Cold): Boolean {
|
||||
val demoCard = isDemoCardUseCase.invoke(userWallet.cardId)
|
||||
val needShowDemoWarning = demoCard && disabledActionsInDemoMode.contains(action)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
|||
import com.tangem.common.ui.userwallet.state.UserWalletItemUM
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.rows.model.BlockchainRowUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.markets.impl.R
|
||||
|
|
@ -25,7 +26,7 @@ internal class PreviewAddToPortfolioBSContentProvider : PreviewParameterProvider
|
|||
val userWallet = UserWalletItemUM(
|
||||
id = UserWalletId("1"),
|
||||
name = stringReference("Wallet 1"),
|
||||
information = stringReference("3 cards"),
|
||||
information = UserWalletItemUM.Information.Loaded(TextReference.Str("3 cards")),
|
||||
balance = UserWalletItemUM.Balance.Loading,
|
||||
isEnabled = true,
|
||||
endIcon = UserWalletItemUM.EndIcon.Arrow,
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
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.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.markets.TokenMarket
|
||||
import com.tangem.features.markets.entry.BottomSheetState
|
||||
|
||||
@Stable
|
||||
interface MarketsTokenListComponent {
|
||||
|
||||
@Composable
|
||||
fun BottomSheetContent(
|
||||
bottomSheetState: State<BottomSheetState>,
|
||||
onHeaderSizeChange: (Dp) -> Unit,
|
||||
modifier: Modifier,
|
||||
)
|
||||
|
||||
interface Factory {
|
||||
fun create(
|
||||
context: AppComponentContext,
|
||||
onTokenSelected: (TokenMarket, AppCurrency) -> Unit,
|
||||
): MarketsTokenListComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +1,58 @@
|
|||
package com.tangem.features.markets.tokenlist.impl
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.lifecycle.compose.LifecycleStartEffect
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRoute.MarketsTokenDetails.AnalyticsParams
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.markets.TokenMarket
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.utils.WindowInsetsZero
|
||||
import com.tangem.domain.markets.toSerializableParam
|
||||
import com.tangem.features.markets.entry.BottomSheetState
|
||||
import com.tangem.features.markets.tokenlist.api.MarketsTokenListComponent
|
||||
import com.tangem.features.markets.tokenlist.MarketsTokenListComponent
|
||||
import com.tangem.features.markets.tokenlist.impl.model.MarketsListModel
|
||||
import com.tangem.features.markets.tokenlist.impl.ui.MarketsList
|
||||
import com.tangem.features.markets.tokenlist.impl.ui.MarketsListWithBack
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
class DefaultMarketsTokenListComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted private val onTokenSelected: (TokenMarket, AppCurrency) -> Unit,
|
||||
@Assisted params: Unit,
|
||||
) : AppComponentContext by appComponentContext, MarketsTokenListComponent {
|
||||
|
||||
private val model: MarketsListModel = getOrCreateModel()
|
||||
|
||||
init {
|
||||
model.tokenSelected
|
||||
.onEach { onTokenSelected(it.first, it.second) }
|
||||
.onEach { (token, appCurrency) ->
|
||||
router.push(
|
||||
AppRoute.MarketsTokenDetails(
|
||||
token = token.toSerializableParam(),
|
||||
appCurrency = appCurrency,
|
||||
showPortfolio = true,
|
||||
analyticsParams = AnalyticsParams(
|
||||
blockchain = null,
|
||||
source = "Market",
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
.launchIn(componentScope)
|
||||
}
|
||||
|
||||
|
|
@ -60,11 +84,35 @@ class DefaultMarketsTokenListComponent @AssistedInject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
LifecycleStartEffect(Unit) {
|
||||
model.isVisibleOnScreen.value = true
|
||||
onStopOrDispose {
|
||||
model.isVisibleOnScreen.value = false
|
||||
}
|
||||
}
|
||||
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
|
||||
Scaffold(
|
||||
contentWindowInsets = WindowInsetsZero,
|
||||
containerColor = TangemTheme.colors.background.primary,
|
||||
) {
|
||||
MarketsListWithBack(
|
||||
modifier = Modifier
|
||||
.statusBarsPadding()
|
||||
.imePadding()
|
||||
.padding(it),
|
||||
state = state,
|
||||
bottomSheetState = BottomSheetState.EXPANDED,
|
||||
onBackClick = router::pop,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : MarketsTokenListComponent.Factory {
|
||||
override fun create(
|
||||
context: AppComponentContext,
|
||||
onTokenSelected: (TokenMarket, AppCurrency) -> Unit,
|
||||
): DefaultMarketsTokenListComponent
|
||||
override fun create(context: AppComponentContext, params: Unit): DefaultMarketsTokenListComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.features.markets.tokenlist.impl.di
|
||||
|
||||
import com.tangem.features.markets.tokenlist.api.MarketsTokenListComponent
|
||||
import com.tangem.features.markets.tokenlist.MarketsTokenListComponent
|
||||
import com.tangem.features.markets.tokenlist.impl.DefaultMarketsTokenListComponent
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ import com.tangem.domain.appcurrency.model.AppCurrency
|
|||
import com.tangem.domain.markets.GetMarketsTokenListFlowUseCase
|
||||
import com.tangem.domain.markets.GetStakingNotificationMaxApyUseCase
|
||||
import com.tangem.domain.markets.TokenMarket
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.promo.PromoRepository
|
||||
import com.tangem.domain.settings.usercountry.GetUserCountryUseCase
|
||||
import com.tangem.domain.settings.usercountry.models.UserCountry
|
||||
import com.tangem.domain.settings.usercountry.models.UserCountryError
|
||||
import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.features.markets.entry.BottomSheetState
|
||||
import com.tangem.features.markets.tokenlist.impl.analytics.MarketsListAnalyticsEvent
|
||||
import com.tangem.features.markets.tokenlist.impl.model.statemanager.MarketsListBatchFlowManager
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package com.tangem.features.markets.tokenlist.impl.model.statemanager
|
|||
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.markets.*
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
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
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
|||
import com.tangem.core.ui.event.consumedEvent
|
||||
import com.tangem.core.ui.event.triggeredEvent
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.markets.impl.R
|
||||
import com.tangem.features.markets.tokenlist.impl.ui.state.*
|
||||
import com.tangem.utils.Provider
|
||||
|
|
|
|||
|
|
@ -3,22 +3,29 @@ package com.tangem.features.markets.tokenlist.impl.ui
|
|||
import android.content.res.Configuration
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import com.tangem.core.ui.components.Keyboard
|
||||
import com.tangem.core.ui.components.SpacerH12
|
||||
import com.tangem.core.ui.components.SpacerH8
|
||||
|
|
@ -38,7 +45,7 @@ import com.tangem.core.ui.format.bigdecimal.percent
|
|||
import com.tangem.core.ui.res.LocalMainBottomSheetColor
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.markets.entry.BottomSheetState
|
||||
import com.tangem.features.markets.impl.R
|
||||
import com.tangem.features.markets.tokenlist.impl.ui.components.MarketsListLazyColumn
|
||||
|
|
@ -62,26 +69,8 @@ internal fun MarketsList(
|
|||
bottomSheetState: BottomSheetState,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Content(
|
||||
modifier = modifier,
|
||||
state = state,
|
||||
onHeaderSizeChange = onHeaderSizeChange,
|
||||
)
|
||||
MarketsListSortByBottomSheet(config = state.sortByBottomSheet)
|
||||
KeyboardEvents(
|
||||
isSortByBottomSheetShown = state.sortByBottomSheet.isShown,
|
||||
bottomSheetState = bottomSheetState,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun Content(state: MarketsListUM, onHeaderSizeChange: (Dp) -> Unit, modifier: Modifier = Modifier) {
|
||||
val density = LocalDensity.current
|
||||
val background = LocalMainBottomSheetColor.current.value
|
||||
val strokeColor = TangemTheme.colors.stroke.primary
|
||||
val scrolledState = remember { mutableStateOf(false) }
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
|
|
@ -106,85 +95,148 @@ private fun Content(state: MarketsListUM, onHeaderSizeChange: (Dp) -> Unit, modi
|
|||
.padding(bottom = 4.dp),
|
||||
state = state.searchBar,
|
||||
)
|
||||
Column(Modifier.padding(horizontal = TangemTheme.dimens.size16)) {
|
||||
AnimatedVisibility(
|
||||
visible = scrolledState.value.not(),
|
||||
) {
|
||||
Column {
|
||||
SpacerH8()
|
||||
Title(isInSearchMode = state.isInSearchMode)
|
||||
SpacerH12()
|
||||
}
|
||||
}
|
||||
Content(state = state)
|
||||
}
|
||||
MarketsListSortByBottomSheet(config = state.sortByBottomSheet)
|
||||
KeyboardEvents(
|
||||
isSortByBottomSheetShown = state.sortByBottomSheet.isShown,
|
||||
bottomSheetState = bottomSheetState,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun MarketsListWithBack(
|
||||
state: MarketsListUM,
|
||||
bottomSheetState: BottomSheetState,
|
||||
onBackClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val background = LocalMainBottomSheetColor.current.value
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.imePadding()
|
||||
.drawBehind { drawRect(background) },
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(
|
||||
painter = rememberVectorPainter(
|
||||
ImageVector.vectorResource(R.drawable.ic_close_24),
|
||||
),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.icon.primary1,
|
||||
modifier = Modifier
|
||||
.padding(16.dp)
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = ripple(bounded = false),
|
||||
onClick = onBackClick,
|
||||
),
|
||||
)
|
||||
SearchBar(
|
||||
modifier = Modifier
|
||||
.drawBehind { drawRect(background) }
|
||||
.padding(
|
||||
end = 16.dp,
|
||||
),
|
||||
state = state.searchBar,
|
||||
)
|
||||
}
|
||||
Content(state = state)
|
||||
}
|
||||
MarketsListSortByBottomSheet(config = state.sortByBottomSheet)
|
||||
KeyboardEvents(
|
||||
isSortByBottomSheetShown = state.sortByBottomSheet.isShown,
|
||||
bottomSheetState = bottomSheetState,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun ColumnScope.Content(state: MarketsListUM, modifier: Modifier = Modifier) {
|
||||
val strokeColor = TangemTheme.colors.stroke.primary
|
||||
val scrolledState = remember { mutableStateOf(false) }
|
||||
|
||||
Column(modifier.padding(horizontal = TangemTheme.dimens.size16)) {
|
||||
AnimatedVisibility(
|
||||
visible = scrolledState.value.not(),
|
||||
) {
|
||||
Column {
|
||||
AnimatedVisibility(state.isInSearchMode.not()) {
|
||||
Options(
|
||||
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12),
|
||||
sortByTypeUM = state.selectedSortBy,
|
||||
trendInterval = state.selectedInterval,
|
||||
onIntervalClick = state.onIntervalClick,
|
||||
onSortByClick = state.onSortByButtonClick,
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
state.isInSearchMode.not() &&
|
||||
state.stakingNotificationMaxApy != null &&
|
||||
state.selectedSortBy != SortByTypeUM.Staking,
|
||||
) {
|
||||
val showMore = stringResourceSafe(R.string.common_show_more)
|
||||
val description = stringResourceSafe(
|
||||
R.string.markets_staking_banner_description_placeholder,
|
||||
showMore,
|
||||
)
|
||||
|
||||
val clickableDescription = buildAnnotatedString {
|
||||
append(description.substringBefore(showMore))
|
||||
|
||||
pushStringAnnotation(SHOW_MORE_KEY, "")
|
||||
appendColored(showMore, TangemTheme.colors.text.accent)
|
||||
pop()
|
||||
}
|
||||
|
||||
StakingInMarketsPromoNotification(
|
||||
config = NotificationConfig(
|
||||
iconResId = R.drawable.img_staking_in_market_notification,
|
||||
title = resourceReference(
|
||||
R.string.markets_staking_banner_title,
|
||||
wrappedList(state.stakingNotificationMaxApy.format { percent() }),
|
||||
),
|
||||
subtitle = annotatedReference(clickableDescription),
|
||||
onClick = state.onStakingNotificationClick,
|
||||
onCloseClick = state.onStakingNotificationCloseClick,
|
||||
),
|
||||
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12),
|
||||
)
|
||||
}
|
||||
SpacerH8()
|
||||
Title(isInSearchMode = state.isInSearchMode)
|
||||
SpacerH12()
|
||||
}
|
||||
}
|
||||
Column {
|
||||
AnimatedVisibility(state.isInSearchMode.not()) {
|
||||
Options(
|
||||
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12),
|
||||
sortByTypeUM = state.selectedSortBy,
|
||||
trendInterval = state.selectedInterval,
|
||||
onIntervalClick = state.onIntervalClick,
|
||||
onSortByClick = state.onSortByButtonClick,
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
state.isInSearchMode.not() &&
|
||||
state.stakingNotificationMaxApy != null &&
|
||||
state.selectedSortBy != SortByTypeUM.Staking,
|
||||
) {
|
||||
val showMore = stringResourceSafe(R.string.common_show_more)
|
||||
val description = stringResourceSafe(
|
||||
R.string.markets_staking_banner_description_placeholder,
|
||||
showMore,
|
||||
)
|
||||
|
||||
val clickableDescription = buildAnnotatedString {
|
||||
append(description.substringBefore(showMore))
|
||||
|
||||
pushStringAnnotation(SHOW_MORE_KEY, "")
|
||||
appendColored(showMore, TangemTheme.colors.text.accent)
|
||||
pop()
|
||||
}
|
||||
|
||||
StakingInMarketsPromoNotification(
|
||||
config = NotificationConfig(
|
||||
iconResId = R.drawable.img_staking_in_market_notification,
|
||||
title = resourceReference(
|
||||
R.string.markets_staking_banner_title,
|
||||
wrappedList(state.stakingNotificationMaxApy.format { percent() }),
|
||||
),
|
||||
subtitle = annotatedReference(clickableDescription),
|
||||
onClick = state.onStakingNotificationClick,
|
||||
onCloseClick = state.onStakingNotificationCloseClick,
|
||||
),
|
||||
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12),
|
||||
)
|
||||
}
|
||||
}
|
||||
val strokeWidth = TangemTheme.dimens.size0_5
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.height(strokeWidth)
|
||||
.drawBehind {
|
||||
// draw horizontal line
|
||||
if (scrolledState.value) {
|
||||
drawLine(
|
||||
color = strokeColor,
|
||||
start = Offset(0f, size.height),
|
||||
end = Offset(size.width, size.height),
|
||||
strokeWidth = strokeWidth.toPx(),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
ItemsList(
|
||||
scrolledState = scrolledState,
|
||||
isInSearchMode = state.isInSearchMode,
|
||||
state = state.list,
|
||||
)
|
||||
}
|
||||
val strokeWidth = TangemTheme.dimens.size0_5
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.height(strokeWidth)
|
||||
.drawBehind {
|
||||
// draw horizontal line
|
||||
if (scrolledState.value) {
|
||||
drawLine(
|
||||
color = strokeColor,
|
||||
start = Offset(0f, size.height),
|
||||
end = Offset(size.width, size.height),
|
||||
strokeWidth = strokeWidth.toPx(),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
ItemsList(
|
||||
scrolledState = scrolledState,
|
||||
isInSearchMode = state.isInSearchMode,
|
||||
state = state.list,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import com.tangem.core.ui.event.EventEffect
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.markets.impl.R
|
||||
import com.tangem.features.markets.tokenlist.impl.ui.state.ListUM
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
@file:Suppress("MagicNumber")
|
||||
|
||||
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.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.markets.tokenlist.impl.ui.state.MarketsListItemUM
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import com.tangem.common.ui.charts.state.MarketChartLook
|
|||
import com.tangem.common.ui.charts.state.MarketChartRawData
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
|
||||
@Immutable
|
||||
data class MarketsListItemUM(
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
|||
import com.tangem.core.ui.event.StateEvent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.markets.impl.R
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import java.math.BigDecimal
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue