Updated on 2026-08-14
This commit is contained in:
parent
2d0bc9d9e6
commit
ac9a3d15c3
28 changed files with 1528 additions and 127 deletions
|
|
@ -4,15 +4,17 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.common.ui.addtoken.AddTokenContent
|
||||
import com.tangem.common.ui.addtoken.AddTokenContentV2
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.AddTokenModel
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.SelectedNetwork
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.SelectedPortfolio
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.analytics.PortfolioAnalyticsEvent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.AddTokenModel
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -29,10 +31,17 @@ internal class AddTokenComponent @AssistedInject constructor(
|
|||
override fun Content(modifier: Modifier) {
|
||||
val state = model.uiState.collectAsStateWithLifecycle()
|
||||
val um = state.value ?: return
|
||||
AddTokenContent(
|
||||
modifier = modifier,
|
||||
state = um,
|
||||
)
|
||||
if (LocalRedesignEnabled.current) {
|
||||
AddTokenContentV2(
|
||||
modifier = modifier,
|
||||
state = um,
|
||||
)
|
||||
} else {
|
||||
AddTokenContent(
|
||||
modifier = modifier,
|
||||
state = um,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class Params(
|
||||
|
|
|
|||
|
|
@ -15,10 +15,12 @@ import com.tangem.core.decompose.factory.ComponentFactory
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.analytics.PortfolioAnalyticsEvent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.TokenActionsModel
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.TokenActionsContent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.TokenActionsContentV2
|
||||
import com.tangem.features.tokenreceive.TokenReceiveComponent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
|
|
@ -44,10 +46,17 @@ internal class TokenActionsComponent @AssistedInject constructor(
|
|||
val state = model.uiState.collectAsStateWithLifecycle()
|
||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||
val tokenActionsUM = state.value ?: return
|
||||
TokenActionsContent(
|
||||
modifier = modifier,
|
||||
state = tokenActionsUM,
|
||||
)
|
||||
if (LocalRedesignEnabled.current) {
|
||||
TokenActionsContentV2(
|
||||
modifier = modifier,
|
||||
state = tokenActionsUM,
|
||||
)
|
||||
} else {
|
||||
TokenActionsContent(
|
||||
modifier = modifier,
|
||||
state = tokenActionsUM,
|
||||
)
|
||||
}
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,9 +51,9 @@ private const val TOKEN_ACTIONS_DELAY = 500L
|
|||
@Suppress("LongParameterList", "LargeClass")
|
||||
internal class AddToPortfolioModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
designFeatureToggles: DesignFeatureToggles,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
val portfolioSelectorController: PortfolioSelectorController,
|
||||
private val designFeatureToggles: DesignFeatureToggles,
|
||||
private val callbackDelegate: AddToPortfolioCallbackDelegate,
|
||||
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCaseV2,
|
||||
private val getTokenMarketCryptoCurrency: GetTokenMarketCryptoCurrency,
|
||||
|
|
@ -441,7 +441,7 @@ internal class AddToPortfolioModel @Inject constructor(
|
|||
currency = addedToken.currency,
|
||||
accountId = selectedPortfolio.account.account.account.accountId,
|
||||
).onEach { state ->
|
||||
val requestedQuickActions = toQuickActions(state.states)
|
||||
val requestedQuickActions = toQuickActions(state.states, designFeatureToggles.isRedesignEnabled)
|
||||
when {
|
||||
requestedQuickActions.isNotEmpty() -> {
|
||||
timerJob.cancel()
|
||||
|
|
@ -458,6 +458,8 @@ internal class AddToPortfolioModel @Inject constructor(
|
|||
userWallet = selectedPortfolio.userWallet,
|
||||
status = actionsState.cryptoCurrencyStatus,
|
||||
actions = actionsState.states,
|
||||
isAccountMode = selectedPortfolio.isAccountMode,
|
||||
account = selectedPortfolio.account.account,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,17 +10,15 @@ 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.models.TokenReceiveConfig
|
||||
import com.tangem.domain.transaction.usecase.ReceiveAddressesFactory
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.TokenActionsComponent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state.TokenActionsUM
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -29,6 +27,7 @@ import javax.inject.Inject
|
|||
internal class TokenActionsModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
tokenActionsIntentsFactory: TokenActionsHandler.Factory,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val uiBuilder: TokenActionsUiBuilder,
|
||||
|
|
@ -52,13 +51,29 @@ internal class TokenActionsModel @Inject constructor(
|
|||
)
|
||||
|
||||
val bottomSheetNavigation: SlotNavigation<TokenReceiveConfig> = SlotNavigation()
|
||||
val uiState: StateFlow<TokenActionsUM?> = params.data
|
||||
.mapLatest { uiBuilder.build(it, tokenActionsHandler, analyticsEventBuilder.first()) }
|
||||
.stateIn(
|
||||
scope = modelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = null,
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val uiState: StateFlow<TokenActionsUM?> =
|
||||
combine(
|
||||
params.data,
|
||||
getBalanceHidingSettingsUseCase.isBalanceHidden(),
|
||||
) { cryptoCurrencyData, isBalanceHidden ->
|
||||
cryptoCurrencyData to isBalanceHidden
|
||||
}
|
||||
.mapLatest { (cryptoCurrencyData, isBalanceHidden) ->
|
||||
uiBuilder.build(
|
||||
cryptoCurrencyData = cryptoCurrencyData,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
eventBuilder = analyticsEventBuilder.first(),
|
||||
appCurrency = currentAppCurrency.value,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
)
|
||||
}
|
||||
.stateIn(
|
||||
scope = modelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = null,
|
||||
)
|
||||
|
||||
private fun handledQuickAction(handledAction: TokenActionsHandler.HandledQuickAction) = modelScope.launch {
|
||||
val event = analyticsEventBuilder.first().getTokenActionClick(actionUM = handledAction.action)
|
||||
|
|
|
|||
|
|
@ -1,32 +1,73 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.model
|
||||
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import com.tangem.common.getTotalCryptoAmount
|
||||
import com.tangem.common.getTotalFiatAmount
|
||||
import com.tangem.common.ui.account.*
|
||||
import com.tangem.common.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.common.ui.markets.action.CryptoCurrencyData
|
||||
import com.tangem.common.ui.markets.action.QuickActionsConverter.quickActions
|
||||
import com.tangem.common.ui.markets.action.TokenActionsHandler
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.common.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.core.ui.DesignFeatureToggles
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeIconPosition
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeShape
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeSize
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeUM
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.format.bigdecimal.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.TokenActionsComponent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.analytics.PortfolioAnalyticsEvent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state.TokenActionsUM
|
||||
import java.math.BigDecimal
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
internal class TokenActionsUiBuilder @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val designFeatureToggles: DesignFeatureToggles,
|
||||
) {
|
||||
private val params = paramsContainer.require<TokenActionsComponent.Params>()
|
||||
|
||||
fun build(
|
||||
data: CryptoCurrencyData,
|
||||
cryptoCurrencyData: CryptoCurrencyData,
|
||||
tokenActionsHandler: TokenActionsHandler,
|
||||
eventBuilder: PortfolioAnalyticsEvent.EventBuilder,
|
||||
appCurrency: AppCurrency,
|
||||
isBalanceHidden: Boolean,
|
||||
): TokenActionsUM {
|
||||
return if (designFeatureToggles.isRedesignEnabled) {
|
||||
buildV2(
|
||||
cryptoCurrencyData = cryptoCurrencyData,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
eventBuilder = eventBuilder,
|
||||
appCurrency = appCurrency,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
)
|
||||
} else {
|
||||
buildV1(
|
||||
cryptoCurrencyData = cryptoCurrencyData,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
eventBuilder = eventBuilder,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildV1(
|
||||
cryptoCurrencyData: CryptoCurrencyData,
|
||||
tokenActionsHandler: TokenActionsHandler,
|
||||
eventBuilder: PortfolioAnalyticsEvent.EventBuilder,
|
||||
): TokenActionsUM {
|
||||
val status = data.status
|
||||
val status = cryptoCurrencyData.status
|
||||
val tokenUM = TokenItemState.Content(
|
||||
id = status.currency.id.value,
|
||||
iconState = CryptoCurrencyToIconStateConverter().convert(status.currency),
|
||||
|
|
@ -39,11 +80,147 @@ internal class TokenActionsUiBuilder @Inject constructor(
|
|||
)
|
||||
return TokenActionsUM(
|
||||
token = tokenUM,
|
||||
quickActions = quickActions(
|
||||
cryptoData = cryptoCurrencyData,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
isRedesignEnabled = false,
|
||||
),
|
||||
onLaterClick = {
|
||||
analyticsEventHandler.send(eventBuilder.getTokenLater())
|
||||
params.callbacks.onLaterClick()
|
||||
},
|
||||
quickActions = quickActions(data, tokenActionsHandler),
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildV2(
|
||||
cryptoCurrencyData: CryptoCurrencyData,
|
||||
tokenActionsHandler: TokenActionsHandler,
|
||||
eventBuilder: PortfolioAnalyticsEvent.EventBuilder,
|
||||
appCurrency: AppCurrency,
|
||||
isBalanceHidden: Boolean,
|
||||
): TokenActionsUM {
|
||||
val status = cryptoCurrencyData.status
|
||||
val tokenUM = TokenItemState.Content(
|
||||
id = status.currency.id.value,
|
||||
iconState = CryptoCurrencyToIconStateConverter().convert(status.currency),
|
||||
titleState = TokenItemState.TitleState.Content(stringReference(status.currency.name)),
|
||||
fiatAmountState = createFiatAmountState(status, appCurrency),
|
||||
subtitle2State = createSubtitle2State(status),
|
||||
subtitleState = TokenItemState.SubtitleState.TextContent(stringReference(status.currency.symbol)),
|
||||
onItemClick = null,
|
||||
onItemLongClick = null,
|
||||
)
|
||||
return TokenActionsUM(
|
||||
token = tokenUM,
|
||||
quickActions = quickActions(
|
||||
cryptoData = cryptoCurrencyData,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
isRedesignEnabled = true,
|
||||
),
|
||||
onLaterClick = {
|
||||
analyticsEventHandler.send(eventBuilder.getTokenLater())
|
||||
params.callbacks.onLaterClick()
|
||||
},
|
||||
isBalancesHidden = isBalanceHidden,
|
||||
portfolioBadge = createPortfolioBadge(cryptoCurrencyData),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createPortfolioBadge(cryptoCurrencyData: CryptoCurrencyData): TangemBadgeUM {
|
||||
val icon: AccountIconUM?
|
||||
val name = if (cryptoCurrencyData.isAccountMode) {
|
||||
icon = CryptoPortfolioIconConverter.convert(cryptoCurrencyData.account.account.icon)
|
||||
cryptoCurrencyData
|
||||
.account
|
||||
.account
|
||||
.accountName
|
||||
.toUM()
|
||||
.value
|
||||
} else {
|
||||
icon = null
|
||||
stringReference(cryptoCurrencyData.userWallet.name)
|
||||
}
|
||||
return TangemBadgeUM(
|
||||
text = name,
|
||||
tangemIconUM = if (icon == null) {
|
||||
TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_key_card_20,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.tertiary },
|
||||
)
|
||||
} else {
|
||||
TangemIconUM.Icon(
|
||||
iconRes = icon.value.getResId(),
|
||||
tintReference = { icon.color.getUiColor() },
|
||||
)
|
||||
},
|
||||
size = TangemBadgeSize.X6,
|
||||
shape = TangemBadgeShape.Rounded,
|
||||
iconPosition = if (cryptoCurrencyData.isAccountMode) {
|
||||
TangemBadgeIconPosition.Start
|
||||
} else {
|
||||
TangemBadgeIconPosition.End
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun createSubtitle2State(status: CryptoCurrencyStatus): TokenItemState.Subtitle2State? {
|
||||
return when (status.value) {
|
||||
is CryptoCurrencyStatus.Loaded,
|
||||
is CryptoCurrencyStatus.Custom,
|
||||
is CryptoCurrencyStatus.NoQuote,
|
||||
is CryptoCurrencyStatus.NoAccount,
|
||||
-> {
|
||||
TokenItemState.Subtitle2State.TextContent(
|
||||
text = status.getTotalCryptoAmount().format {
|
||||
crypto(status.currency)
|
||||
},
|
||||
)
|
||||
}
|
||||
is CryptoCurrencyStatus.Loading,
|
||||
is CryptoCurrencyStatus.MissedDerivation,
|
||||
is CryptoCurrencyStatus.Unreachable,
|
||||
is CryptoCurrencyStatus.NoAmount,
|
||||
-> TokenItemState.Subtitle2State.TextContent(
|
||||
text = BigDecimal.ZERO.format {
|
||||
crypto(status.currency)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createFiatAmountState(
|
||||
status: CryptoCurrencyStatus,
|
||||
appCurrency: AppCurrency,
|
||||
): TokenItemState.FiatAmountState? {
|
||||
return when (status.value) {
|
||||
is CryptoCurrencyStatus.Loaded,
|
||||
is CryptoCurrencyStatus.Custom,
|
||||
is CryptoCurrencyStatus.NoQuote,
|
||||
is CryptoCurrencyStatus.NoAccount,
|
||||
-> {
|
||||
TokenItemState.FiatAmountState.AnnotatedContent(
|
||||
text = status.getTotalFiatAmount().formatStyled {
|
||||
fiat(
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
spanStyleReference = { SpanStyle(color = TangemTheme.colors2.text.neutral.secondary) },
|
||||
).price()
|
||||
},
|
||||
)
|
||||
}
|
||||
is CryptoCurrencyStatus.Unreachable,
|
||||
is CryptoCurrencyStatus.NoAmount,
|
||||
is CryptoCurrencyStatus.MissedDerivation,
|
||||
is CryptoCurrencyStatus.Loading,
|
||||
-> TokenItemState.FiatAmountState.AnnotatedContent(
|
||||
text = BigDecimal.ZERO.formatStyled {
|
||||
fiat(
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
spanStyleReference = { SpanStyle(color = TangemTheme.colors2.text.neutral.secondary) },
|
||||
).price()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +1,47 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.layout.layoutId
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.util.fastForEachIndexed
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import com.tangem.core.ui.components.label.Label
|
||||
import com.tangem.core.ui.components.label.entity.LabelStyle
|
||||
import com.tangem.core.ui.components.label.entity.LabelUM
|
||||
import com.tangem.core.ui.components.rows.BlockchainRow
|
||||
import com.tangem.core.ui.components.rows.model.BlockchainRowUM
|
||||
import com.tangem.core.ui.ds.badge.TangemBadge
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeShape
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeSize
|
||||
import com.tangem.core.ui.ds.row.TangemRowContainer
|
||||
import com.tangem.core.ui.ds.row.TangemRowLayoutId
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state.ChooseNetworkUM
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.features.commonfeatures.impl.R
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state.ChooseNetworkUM
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import java.util.UUID
|
||||
|
||||
|
|
@ -33,13 +49,28 @@ private const val DISABLED_ALPHA = 0.4f
|
|||
|
||||
@Composable
|
||||
internal fun ChooseNetworkContent(state: ChooseNetworkUM, modifier: Modifier = Modifier) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
ChooseNetworkContentV2(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
} else {
|
||||
ChooseNetworkContentV1(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun ChooseNetworkContentV1(state: ChooseNetworkUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(TangemTheme.dimens.radius14))
|
||||
.background(TangemTheme.colors.background.action),
|
||||
) {
|
||||
state.networks.fastForEachIndexed { index, model ->
|
||||
state.networks.fastForEach { model ->
|
||||
key(model.id) {
|
||||
BlockchainRow(
|
||||
model = model,
|
||||
|
|
@ -66,6 +97,120 @@ internal fun ChooseNetworkContent(state: ChooseNetworkUM, modifier: Modifier = M
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun ChooseNetworkContentV2(state: ChooseNetworkUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
color = TangemTheme.colors2.surface.level3,
|
||||
shape = RoundedCornerShape(34.dp),
|
||||
)
|
||||
.padding(horizontal = TangemTheme.dimens2.x4, vertical = TangemTheme.dimens2.x2),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(top = TangemTheme.dimens2.x4, bottom = TangemTheme.dimens2.x2),
|
||||
text = stringResourceSafe(R.string.common_choose_network),
|
||||
style = TangemTheme.typography2.subheadlineMedium14,
|
||||
color = TangemTheme.colors2.text.neutral.tertiary,
|
||||
)
|
||||
|
||||
state.networks.fastForEach { model ->
|
||||
key(model.id) {
|
||||
TangemRowContainer(
|
||||
modifier = Modifier.clickable(
|
||||
enabled = model.isEnabled,
|
||||
onClick = { state.onNetworkClick(model) },
|
||||
),
|
||||
contentPadding = PaddingValues(vertical = TangemTheme.dimens2.x3),
|
||||
content = {
|
||||
NetworkIcon(
|
||||
modifier = Modifier
|
||||
.layoutId(layoutId = TangemRowLayoutId.HEAD)
|
||||
.padding(end = TangemTheme.dimens2.x3),
|
||||
model = model,
|
||||
)
|
||||
|
||||
NetworkText(
|
||||
modifier = Modifier.layoutId(layoutId = TangemRowLayoutId.START_TOP),
|
||||
model = model,
|
||||
)
|
||||
if (!model.isEnabled) {
|
||||
TangemBadge(
|
||||
modifier = Modifier
|
||||
.layoutId(layoutId = TangemRowLayoutId.TAIL)
|
||||
.padding(start = TangemTheme.dimens2.x2),
|
||||
text = resourceReference(R.string.common_added),
|
||||
size = TangemBadgeSize.X6,
|
||||
shape = TangemBadgeShape.Rounded,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NetworkIcon(model: BlockchainRowUM, modifier: Modifier = Modifier) {
|
||||
if (model.isSelected && model.isEnabled) {
|
||||
Image(
|
||||
modifier = modifier
|
||||
.size(TangemTheme.dimens2.x10),
|
||||
painter = painterResource(id = model.iconResId),
|
||||
contentDescription = null,
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
modifier = modifier
|
||||
.background(
|
||||
color = TangemTheme.colors2.button.backgroundSecondary,
|
||||
shape = CircleShape,
|
||||
)
|
||||
.size(TangemTheme.dimens2.x10),
|
||||
painter = painterResource(id = model.iconResId),
|
||||
tint = TangemTheme.colors2.graphic.neutral.tertiary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NetworkText(model: BlockchainRowUM, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x1),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.weight(weight = 10f, fill = false),
|
||||
text = model.name,
|
||||
style = TangemTheme.typography2.bodyMedium16,
|
||||
color = when {
|
||||
model.isEnabled && model.isMainNetwork -> TangemTheme.colors2.text.neutral.primary
|
||||
model.isEnabled -> TangemTheme.colors2.text.neutral.secondary
|
||||
else -> TangemTheme.colors2.text.status.disabled
|
||||
},
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
|
||||
Text(
|
||||
modifier = Modifier.weight(weight = 5f, fill = false),
|
||||
text = model.type,
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
color = if (model.isEnabled) {
|
||||
TangemTheme.colors2.text.neutral.tertiary
|
||||
} else {
|
||||
TangemTheme.colors2.text.status.disabled
|
||||
},
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
|
|
@ -77,6 +222,19 @@ private fun Preview(@PreviewParameter(ChooseNetworkContentProvider::class) conte
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun PreviewV2(@PreviewParameter(ChooseNetworkContentProvider::class) content: ChooseNetworkUM) {
|
||||
TangemThemePreviewRedesign {
|
||||
CompositionLocalProvider(LocalRedesignEnabled provides true) {
|
||||
ChooseNetworkContent(
|
||||
state = content,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class ChooseNetworkContentProvider : PreviewParameterProvider<ChooseNetworkUM> {
|
||||
|
||||
private val blockchainRow = BlockchainRowUM(
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ private fun ActionRow(
|
|||
.size(36.dp)
|
||||
.drawWithContent {
|
||||
drawContent()
|
||||
if (state is QuickActionUM.Exchange && state.shouldShowBadge) {
|
||||
if (state is QuickActionUM.V1.Exchange && state.shouldShowBadge) {
|
||||
drawBadge(containerColor = containerColor, offset = 4.dp)
|
||||
}
|
||||
},
|
||||
|
|
@ -190,9 +190,9 @@ private class TokenActionsContentPreviewProvider : PreviewParameterProvider<Toke
|
|||
TokenActionsUM(
|
||||
quickActions = QuickActions(
|
||||
actions = persistentListOf(
|
||||
QuickActionUM.Buy,
|
||||
QuickActionUM.Exchange(shouldShowBadge = true),
|
||||
QuickActionUM.Receive,
|
||||
QuickActionUM.V1.Buy,
|
||||
QuickActionUM.V1.Exchange(shouldShowBadge = true),
|
||||
QuickActionUM.V1.Receive,
|
||||
),
|
||||
onQuickActionClick = {},
|
||||
onQuickActionLongClick = {},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,292 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.layoutId
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import com.tangem.common.ui.markets.action.QuickActionUM
|
||||
import com.tangem.common.ui.markets.action.QuickActions
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.ds.badge.*
|
||||
import com.tangem.core.ui.ds.button.SecondaryTangemButton
|
||||
import com.tangem.core.ui.ds.button.TangemButtonShape
|
||||
import com.tangem.core.ui.ds.button.TangemButtonSize
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.ds.row.TangemRowContainer
|
||||
import com.tangem.core.ui.ds.row.TangemRowLayoutId
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.formatStyled
|
||||
import com.tangem.core.ui.format.bigdecimal.price
|
||||
import com.tangem.core.ui.haptic.TangemHapticEffect
|
||||
import com.tangem.core.ui.res.*
|
||||
import com.tangem.features.commonfeatures.impl.R
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state.TokenActionsUM
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import java.math.BigDecimal
|
||||
import java.util.UUID
|
||||
|
||||
private const val ACTION_BACKGROUND_ALPHA = .1f
|
||||
|
||||
@Composable
|
||||
internal fun TokenActionsContentV2(state: TokenActionsUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
) {
|
||||
TokenHeader(
|
||||
addedToken = state.token,
|
||||
portfolioBadge = state.portfolioBadge,
|
||||
isBalanceHidden = state.isBalancesHidden,
|
||||
)
|
||||
|
||||
SpacerH(TangemTheme.dimens2.x2)
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
|
||||
) {
|
||||
state.quickActions.actions.fastForEach { actionUM ->
|
||||
key(actionUM.title) {
|
||||
ActionRow(
|
||||
state = actionUM,
|
||||
onClick = { state.quickActions.onQuickActionClick(actionUM) },
|
||||
onLongClick = { state.quickActions.onQuickActionLongClick(actionUM) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SpacerH(TangemTheme.dimens2.x2)
|
||||
|
||||
SecondaryTangemButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = state.onLaterClick,
|
||||
text = resourceReference(R.string.common_later),
|
||||
size = TangemButtonSize.X12,
|
||||
shape = TangemButtonShape.Rounded,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun ActionRow(
|
||||
state: QuickActionUM,
|
||||
onClick: () -> Unit,
|
||||
onLongClick: (() -> Unit),
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val hapticManager = LocalHapticManager.current
|
||||
val onLongClickInternal = {
|
||||
hapticManager.perform(TangemHapticEffect.View.LongPress)
|
||||
onLongClick()
|
||||
}
|
||||
|
||||
TangemRowContainer(
|
||||
modifier = modifier
|
||||
.combinedClickable(
|
||||
onLongClick = onLongClickInternal.takeIf { state.isLongClickAvailable },
|
||||
onClick = {
|
||||
hapticManager.perform(TangemHapticEffect.View.SegmentTick)
|
||||
onClick()
|
||||
},
|
||||
)
|
||||
.background(
|
||||
color = TangemTheme.colors2.surface.level3,
|
||||
shape = RoundedCornerShape(TangemTheme.dimens2.x5),
|
||||
),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.layoutId(TangemRowLayoutId.HEAD)
|
||||
.padding(end = TangemTheme.dimens2.x3)
|
||||
.size(40.dp)
|
||||
.background(
|
||||
color = TangemTheme.colors2.graphic.status.accent.copy(alpha = ACTION_BACKGROUND_ALPHA),
|
||||
shape = CircleShape,
|
||||
),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(20.dp),
|
||||
imageVector = ImageVector.vectorResource(id = state.icon),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors2.graphic.status.accent,
|
||||
)
|
||||
}
|
||||
Text(
|
||||
modifier = Modifier.layoutId(TangemRowLayoutId.START_TOP),
|
||||
text = state.title.resolveReference(),
|
||||
style = TangemTheme.typography2.bodyMedium16,
|
||||
color = TangemTheme.colors2.text.neutral.primary,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.layoutId(TangemRowLayoutId.START_BOTTOM),
|
||||
text = state.description.resolveReference(),
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
color = TangemTheme.colors2.text.neutral.secondary,
|
||||
)
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.layoutId(TangemRowLayoutId.TAIL)
|
||||
.padding(start = TangemTheme.dimens2.x2)
|
||||
.size(24.dp),
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_chevron_small_right_24),
|
||||
tint = TangemTheme.colors2.graphic.neutral.tertiary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TokenHeader(
|
||||
addedToken: TokenItemState,
|
||||
isBalanceHidden: Boolean,
|
||||
portfolioBadge: TangemBadgeUM?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = TangemTheme.dimens2.x8),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
CurrencyIcon(
|
||||
state = addedToken.iconState,
|
||||
iconSize = 70.dp,
|
||||
networkBadgeSize = 24.dp,
|
||||
)
|
||||
|
||||
SpacerH(TangemTheme.dimens2.x5)
|
||||
|
||||
when (val fiat = addedToken.fiatAmountState) {
|
||||
is TokenItemState.FiatAmountState.AnnotatedContent -> {
|
||||
Text(
|
||||
text = fiat.text.orMaskWithStars(isBalanceHidden).resolveAnnotatedReference(),
|
||||
style = TangemTheme.typography2.titleRegular44,
|
||||
color = TangemTheme.colors2.text.neutral.primary,
|
||||
)
|
||||
SpacerH(TangemTheme.dimens2.x2)
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
|
||||
when (val cryptoAmount = addedToken.subtitle2State) {
|
||||
is TokenItemState.Subtitle2State.TextContent -> {
|
||||
Text(
|
||||
text = cryptoAmount.text.orMaskWithStars(isBalanceHidden),
|
||||
style = TangemTheme.typography2.bodyMedium16,
|
||||
color = TangemTheme.colors2.text.neutral.secondary,
|
||||
)
|
||||
SpacerH(TangemTheme.dimens2.x2)
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
|
||||
SpacerH(TangemTheme.dimens2.x7)
|
||||
|
||||
if (portfolioBadge == null) return
|
||||
TangemBadge(portfolioBadge)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(widthDp = 360, showBackground = true)
|
||||
@Preview(widthDp = 360, showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview(@PreviewParameter(TokenActionsContentPreviewProviderV2::class) state: TokenActionsUM) {
|
||||
TangemThemePreviewRedesign {
|
||||
CompositionLocalProvider(LocalRedesignEnabled provides true) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(TangemTheme.colors2.surface.level2)
|
||||
.padding(horizontal = 16.dp),
|
||||
) {
|
||||
TokenActionsContentV2(
|
||||
state = state,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TokenActionsContentPreviewProviderV2 : PreviewParameterProvider<TokenActionsUM> {
|
||||
private val tokenState
|
||||
get() = TokenItemState.Content(
|
||||
id = UUID.randomUUID().toString(),
|
||||
iconState = CurrencyIconState.TokenIcon(
|
||||
url = null,
|
||||
topBadgeIconResId = R.drawable.img_eth_22,
|
||||
fallbackTint = TangemColorPalette.Black,
|
||||
fallbackBackground = TangemColorPalette.Meadow,
|
||||
isGrayscale = false,
|
||||
shouldShowCustomBadge = false,
|
||||
),
|
||||
titleState = TokenItemState.TitleState.Content(
|
||||
text = stringReference(value = "Tether"),
|
||||
),
|
||||
fiatAmountState = TokenItemState.FiatAmountState.AnnotatedContent(
|
||||
text = BigDecimal.ONE.formatStyled {
|
||||
fiat(
|
||||
fiatCurrencyCode = "USD",
|
||||
fiatCurrencySymbol = "$",
|
||||
spanStyleReference = { SpanStyle(color = TangemTheme.colors2.text.neutral.secondary) },
|
||||
).price()
|
||||
},
|
||||
),
|
||||
subtitle2State = TokenItemState.Subtitle2State.TextContent(
|
||||
"1.01 USDT",
|
||||
),
|
||||
subtitleState = TokenItemState.SubtitleState.TextContent(value = stringReference("USDT")),
|
||||
onItemClick = {},
|
||||
onItemLongClick = {},
|
||||
)
|
||||
|
||||
override val values: Sequence<TokenActionsUM>
|
||||
get() = sequenceOf(
|
||||
TokenActionsUM(
|
||||
quickActions = QuickActions(
|
||||
actions = persistentListOf(
|
||||
QuickActionUM.V2.Buy,
|
||||
QuickActionUM.V2.Exchange(shouldShowBadge = true),
|
||||
QuickActionUM.V2.Receive,
|
||||
),
|
||||
onQuickActionClick = {},
|
||||
onQuickActionLongClick = {},
|
||||
),
|
||||
token = tokenState,
|
||||
onLaterClick = {},
|
||||
portfolioBadge = TangemBadgeUM(
|
||||
text = stringReference("Wallet 2"),
|
||||
tangemIconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_key_card_20,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.tertiary },
|
||||
),
|
||||
size = TangemBadgeSize.X6,
|
||||
shape = TangemBadgeShape.Rounded,
|
||||
iconPosition = TangemBadgeIconPosition.End,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -2,9 +2,12 @@ package com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state
|
|||
|
||||
import com.tangem.common.ui.markets.action.QuickActions
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeUM
|
||||
|
||||
internal data class TokenActionsUM(
|
||||
val token: TokenItemState,
|
||||
val quickActions: QuickActions,
|
||||
val onLaterClick: () -> Unit,
|
||||
val isBalancesHidden: Boolean = false,
|
||||
val portfolioBadge: TangemBadgeUM? = null,
|
||||
)
|
||||
|
|
@ -7,9 +7,11 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorComponent
|
||||
import com.tangem.features.commonfeatures.impl.portfolioselector.ui.PortfolioSelectorBS
|
||||
import com.tangem.features.commonfeatures.impl.portfolioselector.ui.PortfolioSelectorContent
|
||||
import com.tangem.features.commonfeatures.impl.portfolioselector.ui.PortfolioSelectorContentV2
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -43,10 +45,17 @@ internal class DefaultPortfolioSelectorComponent @AssistedInject constructor(
|
|||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
PortfolioSelectorContent(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
if (LocalRedesignEnabled.current) {
|
||||
PortfolioSelectorContentV2(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
} else {
|
||||
PortfolioSelectorContent(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.content.res.Configuration
|
|||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
|
|
@ -12,8 +13,10 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
|||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.features.commonfeatures.impl.R
|
||||
import com.tangem.features.commonfeatures.impl.portfolioselector.entity.PortfolioSelectorUM
|
||||
|
||||
|
|
@ -41,11 +44,19 @@ internal fun PortfolioSelectorBS(
|
|||
)
|
||||
},
|
||||
content = {
|
||||
PortfolioSelectorContent(
|
||||
state = state,
|
||||
contentPadding = PaddingValues(bottom = 16.dp),
|
||||
modifier = modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
if (LocalRedesignEnabled.current) {
|
||||
PortfolioSelectorContentV2(
|
||||
state = state,
|
||||
contentPadding = PaddingValues(bottom = 16.dp),
|
||||
modifier = modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
} else {
|
||||
PortfolioSelectorContent(
|
||||
state = state,
|
||||
contentPadding = PaddingValues(bottom = 16.dp),
|
||||
modifier = modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -62,4 +73,20 @@ private fun Preview(@PreviewParameter(PortfolioSelectorPreviewStateProvider::cla
|
|||
onBack = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun PreviewV2(@PreviewParameter(PortfolioSelectorPreviewStateProvider::class) params: PortfolioSelectorUM) {
|
||||
TangemThemePreviewRedesign {
|
||||
CompositionLocalProvider(LocalRedesignEnabled provides true) {
|
||||
PortfolioSelectorBS(
|
||||
state = params,
|
||||
onDismiss = {},
|
||||
modifier = Modifier,
|
||||
onBack = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
package com.tangem.features.commonfeatures.impl.portfolioselector.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.layoutId
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.common.ui.userwallet.CardImage
|
||||
import com.tangem.common.ui.userwallet.getBalanceValueAndFlickerState
|
||||
import com.tangem.common.ui.userwallet.getInformationValue
|
||||
import com.tangem.common.ui.userwallet.state.UserWalletItemUM
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.TextShimmer
|
||||
import com.tangem.core.ui.components.text.applyBladeBrush
|
||||
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
|
||||
import com.tangem.core.ui.ds.row.TangemRowContainer
|
||||
import com.tangem.core.ui.ds.row.TangemRowLayoutId
|
||||
import com.tangem.core.ui.extensions.conditional
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.features.commonfeatures.impl.portfolioselector.entity.PortfolioSelectorItemUM
|
||||
import com.tangem.features.commonfeatures.impl.portfolioselector.entity.PortfolioSelectorUM
|
||||
import com.tangem.utils.StringsSigns.DOT
|
||||
|
||||
private const val DISABLED_WALLET_ALPHA = 0.5f
|
||||
|
||||
@Composable
|
||||
internal fun PortfolioSelectorContentV2(
|
||||
state: PortfolioSelectorUM,
|
||||
modifier: Modifier = Modifier,
|
||||
contentPadding: PaddingValues = PaddingValues(),
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = modifier,
|
||||
contentPadding = contentPadding,
|
||||
) {
|
||||
val items = state.items
|
||||
itemsIndexed(
|
||||
items = items,
|
||||
key = { _, item -> item.id },
|
||||
) { index, item ->
|
||||
when (item) {
|
||||
is PortfolioSelectorItemUM.Portfolio ->
|
||||
PortfolioSelectorItem(
|
||||
state = item.item,
|
||||
modifier = Modifier
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = index,
|
||||
lastIndex = state.items.lastIndex,
|
||||
backgroundColor = TangemTheme.colors2.surface.level3,
|
||||
radius = TangemTheme.dimens2.x5,
|
||||
addDefaultPadding = false,
|
||||
)
|
||||
.clickable(enabled = item.item.isEnabled, onClick = item.item.onClick)
|
||||
.conditional(!item.item.isEnabled) { alpha(DISABLED_WALLET_ALPHA) },
|
||||
)
|
||||
is PortfolioSelectorItemUM.GroupTitle -> WalletNameRow(
|
||||
model = item,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = index,
|
||||
lastIndex = state.items.lastIndex,
|
||||
backgroundColor = TangemTheme.colors2.surface.level3,
|
||||
radius = TangemTheme.dimens2.x5,
|
||||
addDefaultPadding = false,
|
||||
)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PortfolioSelectorItem(state: UserWalletItemUM, modifier: Modifier = Modifier) {
|
||||
TangemRowContainer(modifier = modifier) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.layoutId(TangemRowLayoutId.HEAD)
|
||||
.padding(end = TangemTheme.dimens2.x3),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
CardImage(
|
||||
modifier = Modifier.size(40.dp),
|
||||
imageState = state.imageState,
|
||||
)
|
||||
}
|
||||
|
||||
Text(
|
||||
modifier = Modifier.layoutId(layoutId = TangemRowLayoutId.START_TOP),
|
||||
text = state.name.resolveReference(),
|
||||
style = TangemTheme.typography2.bodyMedium16,
|
||||
color = TangemTheme.colors2.text.neutral.primary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
|
||||
InfoRow(
|
||||
modifier = Modifier.layoutId(layoutId = TangemRowLayoutId.START_BOTTOM),
|
||||
information = state.information,
|
||||
balance = state.balance,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun InfoRow(
|
||||
information: UserWalletItemUM.Information,
|
||||
balance: UserWalletItemUM.Balance,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
AnimatedContent(
|
||||
targetState = information,
|
||||
label = "Information content",
|
||||
) { information ->
|
||||
val informationValue = getInformationValue(information)
|
||||
|
||||
if (informationValue == null) {
|
||||
TextShimmer(
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
text = "aaaaa",
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
text = informationValue,
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
color = TangemTheme.colors2.text.neutral.secondary,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
Text(
|
||||
text = " $DOT ",
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
color = TangemTheme.colors2.text.neutral.secondary,
|
||||
maxLines = 1,
|
||||
)
|
||||
|
||||
val (balanceValue, isFlickering) = getBalanceValueAndFlickerState(balance)
|
||||
|
||||
if (balanceValue == null) {
|
||||
TextShimmer(
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
text = "aaaaa",
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
text = balanceValue,
|
||||
style = TangemTheme.typography2.captionMedium12.applyBladeBrush(
|
||||
isEnabled = isFlickering,
|
||||
textColor = TangemTheme.colors2.text.neutral.secondary,
|
||||
),
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WalletNameRow(model: PortfolioSelectorItemUM.GroupTitle, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier.padding(top = TangemTheme.dimens2.x4, bottom = TangemTheme.dimens2.x2),
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x1),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.align(Alignment.CenterVertically),
|
||||
text = model.name.resolveReference(),
|
||||
style = TangemTheme.typography2.subheadlineMedium14,
|
||||
color = TangemTheme.colors2.text.neutral.secondary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_key_card_20),
|
||||
modifier = Modifier
|
||||
.align(Alignment.Bottom)
|
||||
.size(TangemTheme.dimens2.x5),
|
||||
tint = TangemTheme.colors2.graphic.neutral.tertiary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview(@PreviewParameter(PortfolioSelectorPreviewStateProvider::class) params: PortfolioSelectorUM) {
|
||||
TangemThemePreviewRedesign {
|
||||
CompositionLocalProvider(LocalRedesignEnabled provides true) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
PortfolioSelectorContentV2(
|
||||
state = params,
|
||||
modifier = Modifier.background(color = TangemTheme.colors.background.tertiary),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import com.tangem.common.ui.account.CryptoPortfolioIconConverter
|
|||
import com.tangem.common.ui.account.toUM
|
||||
import com.tangem.common.ui.markets.action.CryptoCurrencyData
|
||||
import com.tangem.common.ui.markets.action.TokenActionsHandler
|
||||
import com.tangem.core.ui.DesignFeatureToggles
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.account.models.AccountStatusList
|
||||
|
|
@ -53,6 +54,7 @@ internal class MarketsPortfolioDelegate @AssistedInject constructor(
|
|||
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCaseV2,
|
||||
private val getUserWalletUseCase: GetUserWalletUseCase,
|
||||
private val yieldSupplyGetAvailabilityUseCase: YieldSupplyGetAvailabilityUseCase,
|
||||
private val designFeatureToggles: DesignFeatureToggles,
|
||||
isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||
@Assisted private val scope: CoroutineScope,
|
||||
@Assisted private val token: TokenMarketParams,
|
||||
|
|
@ -229,6 +231,7 @@ internal class MarketsPortfolioDelegate @AssistedInject constructor(
|
|||
isBalanceHidden = isBalanceHidden,
|
||||
onTokenItemClick = { },
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
isRedesignEnabled = designFeatureToggles.isRedesignEnabled,
|
||||
)
|
||||
|
||||
portfolio.portfolios.forEach { portfolioItem ->
|
||||
|
|
@ -253,6 +256,8 @@ internal class MarketsPortfolioDelegate @AssistedInject constructor(
|
|||
userWallet = userWallet,
|
||||
status = currencyStatus,
|
||||
actions = actions,
|
||||
isAccountMode = isAccountMode,
|
||||
account = accountWithAdded.accountStatus,
|
||||
)
|
||||
val expandedKey = portfolioItem.userWallet.walletId to currencyStatus.currency.id
|
||||
val isExpand = expanded.contains(expandedKey)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ internal class PortfolioTokenUMConverter(
|
|||
private val isBalanceHidden: Boolean,
|
||||
private val onTokenItemClick: (CryptoCurrencyStatus) -> Unit,
|
||||
private val tokenActionsHandler: TokenActionsHandler,
|
||||
private val isRedesignEnabled: Boolean,
|
||||
) : Converter<CryptoCurrencyData, PortfolioTokenUM> {
|
||||
|
||||
fun convertV2(
|
||||
|
|
@ -38,7 +39,11 @@ internal class PortfolioTokenUMConverter(
|
|||
walletId = value.userWallet.walletId,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
isQuickActionsShown = isQuickActionsShown,
|
||||
quickActions = quickActions(cryptoData = value, tokenActionsHandler = tokenActionsHandler),
|
||||
quickActions = quickActions(
|
||||
cryptoData = value,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
isRedesignEnabled = isRedesignEnabled,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -57,7 +62,11 @@ internal class PortfolioTokenUMConverter(
|
|||
walletId = value.userWallet.walletId,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
isQuickActionsShown = false,
|
||||
quickActions = quickActions(cryptoData = value, tokenActionsHandler = tokenActionsHandler),
|
||||
quickActions = quickActions(
|
||||
cryptoData = value,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
isRedesignEnabled = isRedesignEnabled,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -180,7 +180,7 @@ private fun AnimatedVisibilityScope.QuickActionIcon(state: QuickActionUM) {
|
|||
)
|
||||
.size(TangemTheme.dimens.size32)
|
||||
.semantics {
|
||||
contentDescription = if (state is QuickActionUM.Exchange && state.shouldShowBadge) {
|
||||
contentDescription = if (state is QuickActionUM.V1.Exchange && state.shouldShowBadge) {
|
||||
"Badge shown"
|
||||
} else {
|
||||
"Badge hidden"
|
||||
|
|
@ -188,7 +188,7 @@ private fun AnimatedVisibilityScope.QuickActionIcon(state: QuickActionUM) {
|
|||
}
|
||||
.drawWithContent {
|
||||
drawContent()
|
||||
if (state is QuickActionUM.Exchange && state.shouldShowBadge) {
|
||||
if (state is QuickActionUM.V1.Exchange && state.shouldShowBadge) {
|
||||
drawBadge(containerColor = containerColor, offset = 4.dp)
|
||||
}
|
||||
},
|
||||
|
|
@ -229,9 +229,9 @@ private fun Preview() {
|
|||
) {
|
||||
PortfolioQuickActions(
|
||||
actions = persistentListOf(
|
||||
QuickActionUM.Buy,
|
||||
QuickActionUM.Exchange(shouldShowBadge = true),
|
||||
QuickActionUM.Receive,
|
||||
QuickActionUM.V1.Buy,
|
||||
QuickActionUM.V1.Exchange(shouldShowBadge = true),
|
||||
QuickActionUM.V1.Receive,
|
||||
),
|
||||
isVisible = isVisible,
|
||||
onActionClick = {},
|
||||
|
|
@ -250,9 +250,9 @@ private fun PreviewRtl() {
|
|||
Box(modifier = Modifier.background(color = TangemTheme.colors.background.action)) {
|
||||
PortfolioQuickActions(
|
||||
actions = persistentListOf(
|
||||
QuickActionUM.Buy,
|
||||
QuickActionUM.Exchange(shouldShowBadge = true),
|
||||
QuickActionUM.Receive,
|
||||
QuickActionUM.V1.Buy,
|
||||
QuickActionUM.V1.Exchange(shouldShowBadge = true),
|
||||
QuickActionUM.V1.Receive,
|
||||
),
|
||||
isVisible = true,
|
||||
onActionClick = {},
|
||||
|
|
|
|||
|
|
@ -129,9 +129,9 @@ internal class PreviewMyPortfolioUMProvider : PreviewParameterProvider<MyPortfol
|
|||
isQuickActionsShown = false,
|
||||
quickActions = QuickActions(
|
||||
actions = persistentListOf(
|
||||
QuickActionUM.Buy,
|
||||
QuickActionUM.Exchange(shouldShowBadge = true),
|
||||
QuickActionUM.Receive,
|
||||
QuickActionUM.V1.Buy,
|
||||
QuickActionUM.V1.Exchange(shouldShowBadge = true),
|
||||
QuickActionUM.V1.Receive,
|
||||
),
|
||||
onQuickActionClick = {},
|
||||
onQuickActionLongClick = {},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue