Updated on 2026-08-14
This commit is contained in:
commit
d0b35bc331
680 changed files with 26556 additions and 2709 deletions
|
|
@ -96,6 +96,7 @@ internal fun OrganizeTokensContent(
|
|||
onClick = { isShowDropdownMenu = true },
|
||||
ghostModeProgress = 0f,
|
||||
),
|
||||
modifier = Modifier.testTag(OrganizeTokensScreenTestTags.MENU_BUTTON),
|
||||
type = TangemTopBarType.BottomSheet,
|
||||
)
|
||||
OrganizeDropDownMenu(
|
||||
|
|
@ -161,8 +162,7 @@ private fun TokenList(
|
|||
modifier = Modifier
|
||||
.align(Alignment.TopCenter)
|
||||
.reorderable(reorderableListState)
|
||||
.testTag(OrganizeTokensScreenTestTags.TOKENS_LAZY_LIST)
|
||||
.hazeSourceTangem(zIndex = 1f),
|
||||
.testTag(OrganizeTokensScreenTestTags.TOKENS_LAZY_LIST),
|
||||
state = reorderableListState.listState,
|
||||
contentPadding = listContentPadding,
|
||||
) {
|
||||
|
|
@ -221,7 +221,7 @@ private fun LazyItemScope.DraggableItem(
|
|||
|
||||
when (item) {
|
||||
is OrganizeRowItemUM.Network -> TangemHeaderRow(
|
||||
modifier = modifierWithBackground,
|
||||
modifier = modifierWithBackground.testTag(OrganizeTokensScreenTestTags.GROUP_TITLE_ITEM),
|
||||
reorderableState = reorderableState,
|
||||
headerRowUM = item.headerRowUM,
|
||||
)
|
||||
|
|
@ -231,7 +231,7 @@ private fun LazyItemScope.DraggableItem(
|
|||
isBalanceHidden = isBalanceHidden,
|
||||
)
|
||||
is OrganizeRowItemUM.Token -> OrganizeTokenRow(
|
||||
modifier = modifierWithBackground,
|
||||
modifier = modifierWithBackground.testTag(OrganizeTokensScreenTestTags.TOKEN_LIST_ITEM),
|
||||
tokenRowUM = item.tokenRowUM,
|
||||
reorderableState = reorderableState,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
|
|
@ -262,11 +262,15 @@ private fun BoxScope.BottomButtons(organizeTokensUM: OrganizeTokensUM) {
|
|||
) {
|
||||
TangemButton(
|
||||
buttonUM = organizeTokensUM.cancelButton,
|
||||
modifier = Modifier.weight(1f),
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.testTag(OrganizeTokensScreenTestTags.CANCEL_BUTTON),
|
||||
)
|
||||
TangemButton(
|
||||
buttonUM = organizeTokensUM.applyButton,
|
||||
modifier = Modifier.weight(1f),
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.testTag(OrganizeTokensScreenTestTags.APPLY_BUTTON),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import com.tangem.core.ui.test.BaseBottomSheetTestTags
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.DpOffset
|
||||
|
|
@ -101,6 +103,7 @@ private fun TokenActionContextMenuContent(actions: ImmutableList<TokenActionButt
|
|||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
|
||||
modifier = Modifier
|
||||
.testTag(BaseBottomSheetTestTags.ACTION_BUTTON)
|
||||
.clickable(
|
||||
enabled = item.isEnabled,
|
||||
onClick = {
|
||||
|
|
@ -123,7 +126,9 @@ private fun TokenActionContextMenuContent(actions: ImmutableList<TokenActionButt
|
|||
} else {
|
||||
TangemTheme.colors2.graphic.neutral.primary
|
||||
},
|
||||
modifier = Modifier.size(TangemTheme.dimens2.x5),
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens2.x5)
|
||||
.testTag(BaseBottomSheetTestTags.ACTION_ICON),
|
||||
)
|
||||
Text(
|
||||
text = item.text.resolveReference(),
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import com.tangem.core.ui.utils.parseBigDecimal
|
|||
import com.tangem.domain.tokens.model.details.TokenAction
|
||||
import com.tangem.feature.wallet.child.managetokens.AddAndManageBottomSheetComponent
|
||||
import com.tangem.feature.wallet.child.organizetokens.OrganizeTokensComponent
|
||||
import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorComponent
|
||||
import com.tangem.feature.wallet.child.tokenActions.DefaultTokenActionsComponent
|
||||
import com.tangem.feature.wallet.child.tokenActions.TokenActionsComponent
|
||||
|
|
@ -67,6 +68,7 @@ internal class WalletComponent @AssistedInject constructor(
|
|||
private val networkSelectionComponentFactory: NetworkSelectionComponent.Factory,
|
||||
private val tokenActionsComponentFactory: TokenActionsComponent.Factory,
|
||||
private val portfolioSelectorComponentFactory: PortfolioSelectorComponent.Factory,
|
||||
private val addFundsComponentFactory: AddFundsComponent.Factory,
|
||||
private val designFeatureToggles: DesignFeatureToggles,
|
||||
) : ComposableContentComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
|
|
@ -180,6 +182,15 @@ internal class WalletComponent @AssistedInject constructor(
|
|||
),
|
||||
)
|
||||
}
|
||||
is WalletDialogConfig.AddFunds -> {
|
||||
addFundsComponentFactory.create(
|
||||
context = childByContext(componentContext),
|
||||
params = AddFundsComponent.Params(
|
||||
launchMode = AddFundsComponent.LaunchMode.ChooseToken(dialogConfig.userWalletId),
|
||||
onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
|
||||
),
|
||||
)
|
||||
}
|
||||
is WalletDialogConfig.AddAndManage -> {
|
||||
AddAndManageBottomSheetComponent(
|
||||
appComponentContext = childByContext(componentContext),
|
||||
|
|
|
|||
|
|
@ -120,7 +120,9 @@ internal class DefaultWalletRouter @Inject constructor(
|
|||
}
|
||||
|
||||
override fun openAddFunds(userWalletId: UserWalletId) {
|
||||
router.push(AppRoute.AddFunds(userWalletId = userWalletId))
|
||||
dialogNavigation.activate(
|
||||
configuration = WalletDialogConfig.AddFunds(userWalletId = userWalletId),
|
||||
)
|
||||
}
|
||||
|
||||
override fun isWalletLastScreen(): Boolean {
|
||||
|
|
|
|||
|
|
@ -62,6 +62,9 @@ internal sealed interface WalletDialogConfig {
|
|||
val customerId: String,
|
||||
) : WalletDialogConfig
|
||||
|
||||
@Serializable
|
||||
data class AddFunds(val userWalletId: UserWalletId) : WalletDialogConfig
|
||||
|
||||
@Serializable
|
||||
data class OrganizeTokens(val userWalletId: UserWalletId) : WalletDialogConfig
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
|||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.utils.disableButtons
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.utils.enableButtons
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.mutate
|
||||
|
|
@ -34,11 +35,18 @@ internal class SetRefreshStateTransformer(
|
|||
|
||||
override fun transform(walletUM: WalletUM): WalletUM {
|
||||
return when (walletUM) {
|
||||
is WalletUM.Content -> walletUM.copy(
|
||||
pullToRefreshConfig = walletUM.pullToRefreshConfig.toUpdatedState(isRefreshing),
|
||||
tokensListUM = walletUM.tokensListUM.toUpdatedState(),
|
||||
buttons = walletUM.enableButtons(),
|
||||
)
|
||||
is WalletUM.Content -> {
|
||||
val tokensListUM = walletUM.tokensListUM.toUpdatedState()
|
||||
walletUM.copy(
|
||||
pullToRefreshConfig = walletUM.pullToRefreshConfig.toUpdatedState(isRefreshing),
|
||||
tokensListUM = tokensListUM,
|
||||
buttons = if (tokensListUM is WalletTokensListUM.Empty) {
|
||||
walletUM.disableButtons()
|
||||
} else {
|
||||
walletUM.enableButtons()
|
||||
},
|
||||
)
|
||||
}
|
||||
is WalletUM.Locked -> walletUM
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import com.tangem.domain.staking.model.StakingAvailability
|
|||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.utils.disableButtons
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.utils.enableButtons
|
||||
import com.tangem.features.tangempay.entity.TangemPayMainUM
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
|
|
@ -60,11 +61,16 @@ internal class SetTokenListTransformer(
|
|||
override fun transform(walletUM: WalletUM): WalletUM {
|
||||
return when (walletUM) {
|
||||
is WalletUM.Content -> {
|
||||
val tokensListUM = toLoadedState()
|
||||
walletUM.copy(
|
||||
walletsBalanceUM = walletUM.walletsBalanceUM.toLoadedState2(),
|
||||
tangemPayMainUM = walletUM.tangemPayMainUM.toLoadedState(),
|
||||
tokensListUM = toLoadedState(),
|
||||
buttons = walletUM.enableButtons(),
|
||||
tokensListUM = tokensListUM,
|
||||
buttons = if (tokensListUM is WalletTokensListUM.Empty) {
|
||||
walletUM.disableButtons()
|
||||
} else {
|
||||
walletUM.enableButtons()
|
||||
},
|
||||
)
|
||||
}
|
||||
is WalletUM.Locked -> {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import com.tangem.domain.models.StatusSource
|
|||
import com.tangem.domain.models.account.AccountStatus
|
||||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||
import com.tangem.domain.models.kyc.KycStatus
|
||||
import com.tangem.domain.models.pay.TangemPayCardState
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.TangemPayIntents
|
||||
import com.tangem.features.tangempay.entity.TangemPayMainUM
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
|
@ -67,7 +68,7 @@ internal class TangemPayMainBlockConverter(
|
|||
is PaymentAccountStatusValue.Loaded -> {
|
||||
val card = statusValue.cards.firstOrNull() ?: return TangemPayMainUM.TemporaryUnavailable
|
||||
TangemPayMainUM.Content(
|
||||
subtitle = if (card.isReissuing) {
|
||||
subtitle = if (card.state == TangemPayCardState.Reissuing) {
|
||||
resourceReference(R.string.tangempay_status_replacing)
|
||||
} else {
|
||||
stringReference("*${card.lastDigits}")
|
||||
|
|
|
|||
|
|
@ -193,20 +193,22 @@ internal class WalletTokenCurrencyItemConverter(
|
|||
is CryptoCurrencyStatus.MissedDerivation -> TangemTokenRowUM.EndContentUM.Content(
|
||||
text = stringReference(StringsSigns.DASH_SIGN),
|
||||
)
|
||||
is CryptoCurrencyStatus.Unreachable -> TangemTokenRowUM.EndContentUM.Content(
|
||||
text = styledResourceReference(
|
||||
id = R.string.common_unreachable,
|
||||
spanStyleReference = { SpanStyle(color = TangemTheme.colors2.text.status.attention) },
|
||||
),
|
||||
endIcons = persistentListOf(
|
||||
TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_attention_default_24,
|
||||
tintReference = { TangemTheme.colors2.graphic.status.attention },
|
||||
),
|
||||
),
|
||||
)
|
||||
is CryptoCurrencyStatus.Unreachable,
|
||||
is CryptoCurrencyStatus.NoAmount,
|
||||
-> TangemTokenRowUM.EndContentUM.Empty
|
||||
-> {
|
||||
TangemTokenRowUM.EndContentUM.Content(
|
||||
text = styledResourceReference(
|
||||
id = R.string.common_unreachable,
|
||||
spanStyleReference = { SpanStyle(color = TangemTheme.colors2.text.status.attention) },
|
||||
),
|
||||
endIcons = persistentListOf(
|
||||
TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_attention_default_24,
|
||||
tintReference = { TangemTheme.colors2.graphic.status.attention },
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ internal class WalletTokensListUMConverter(
|
|||
} else {
|
||||
R.drawable.ic_filter_24
|
||||
}
|
||||
return if (accountList.flattenCurrencies().size > 1 && !selectedWallet.isSingleWalletWithToken()) {
|
||||
return if (accountList.flattenCurrencies().isNotEmpty() && !selectedWallet.isSingleWalletWithToken()) {
|
||||
TangemButtonUM(
|
||||
text = resourceReference(textRes),
|
||||
isEnabled = accountList.totalFiatBalance !is TotalFiatBalance.Loading,
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ import androidx.compose.ui.draw.alpha
|
|||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.focus.FocusState
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
|
|
@ -46,7 +45,6 @@ import androidx.compose.ui.unit.Dp
|
|||
import androidx.compose.ui.unit.DpOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.arkivanov.decompose.ExperimentalDecomposeApi
|
||||
import com.tangem.core.ui.components.BottomFade
|
||||
import com.tangem.core.ui.components.atoms.handComposableComponentHeight
|
||||
import com.tangem.core.ui.components.background.northernlights.NorthernLightsBackground
|
||||
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheetDraggableHeader
|
||||
|
|
@ -59,8 +57,8 @@ import com.tangem.core.ui.components.sheetscaffold.*
|
|||
import com.tangem.core.ui.ds.topbar.collapsing.TangemCollapsingAppBarBehavior
|
||||
import com.tangem.core.ui.ds.topbar.collapsing.TangemCollapsingTopBar
|
||||
import com.tangem.core.ui.ds.topbar.collapsing.rememberTangemExitUntilCollapsedScrollBehavior
|
||||
import com.tangem.core.ui.extensions.softLayerShadow
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.softLayerShadow
|
||||
import com.tangem.core.ui.res.*
|
||||
import com.tangem.core.ui.utils.TangemSharedTransitionLayout
|
||||
import com.tangem.feature.wallet.presentation.common.preview.WalletScreenPreviewData
|
||||
|
|
@ -176,6 +174,7 @@ private fun WalletContent2(
|
|||
state.wallets2.getOrNull(state.selectedWalletIndex)?.pullToRefreshConfig,
|
||||
)
|
||||
}
|
||||
var subtitleBottom by remember { mutableStateOf(0.dp) }
|
||||
|
||||
BaseScaffoldWithMarkets(
|
||||
modifier = modifier,
|
||||
|
|
@ -240,6 +239,7 @@ private fun WalletContent2(
|
|||
pullToRefreshState = pullToRefreshState,
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
behavior = behavior,
|
||||
topOffset = subtitleBottom + TangemTheme.dimens2.x2,
|
||||
)
|
||||
|
||||
val overlay = TangemTheme.colors2.overlay.overlayPrimary
|
||||
|
|
@ -306,6 +306,9 @@ private fun WalletContent2(
|
|||
walletBalanceUM = currentWallet.walletsBalanceUM,
|
||||
buttons = currentWallet.buttons,
|
||||
isBalanceHidden = state.isHidingMode,
|
||||
onSubtitleBottomChange = { newValue ->
|
||||
if (newValue > subtitleBottom) subtitleBottom = maxOf(subtitleBottom, newValue)
|
||||
},
|
||||
)
|
||||
},
|
||||
body = {
|
||||
|
|
@ -494,26 +497,14 @@ private fun BottomSheet(
|
|||
.sizeIn(maxHeight = maxHeight - statusBarHeight),
|
||||
) {
|
||||
Box(modifier = Modifier.fillMaxWidth()) {
|
||||
BottomFade(
|
||||
gradientBrush = Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
TangemTheme.colors2.shadow.min,
|
||||
TangemTheme.colors2.shadow.max,
|
||||
),
|
||||
),
|
||||
modifier = Modifier
|
||||
.offset(y = TangemTheme.dimens2.x5.unaryMinus()),
|
||||
)
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
TangemBottomSheetDraggableHeader()
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.softLayerShadow(
|
||||
radius = 16.dp,
|
||||
radius = 8.dp,
|
||||
spread = 0.dp,
|
||||
color = Color.Black.copy(alpha = if (LocalIsInDarkTheme.current) .24f else .12f),
|
||||
shape = shape,
|
||||
offset = DpOffset(x = 0.dp, y = (-6).dp),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,11 @@ package com.tangem.feature.wallet.presentation.wallet.ui.components
|
|||
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import com.tangem.core.ui.ds.button.TangemButton
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.test.MainScreenTestTags
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
|
||||
import com.tangem.features.tangempay.component.TangemPayMainBlockComponent
|
||||
import com.tangem.features.tangempay.entity.TangemPayMainUM
|
||||
|
|
@ -25,9 +29,14 @@ internal fun LazyListScope.organizeTokens2(state: WalletUM, itemModifier: Modifi
|
|||
key = "OrganizeTokensButton",
|
||||
contentType = "OrganizeTokensButton",
|
||||
) {
|
||||
val testTag = if (organizeButton.text == resourceReference(R.string.main_add_and_manage_tokens)) {
|
||||
MainScreenTestTags.ADD_AND_MANAGE_BUTTON
|
||||
} else {
|
||||
MainScreenTestTags.ORGANIZE_TOKENS_BUTTON
|
||||
}
|
||||
TangemButton(
|
||||
buttonUM = organizeButton,
|
||||
modifier = itemModifier,
|
||||
modifier = itemModifier.testTag(testTag),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,11 +16,15 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.layout.boundsInRoot
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.testTag
|
||||
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.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.TextShimmer
|
||||
|
|
@ -32,11 +36,7 @@ import com.tangem.core.ui.ds.placeholder.TextPlaceholder
|
|||
import com.tangem.core.ui.ds.topbar.collapsing.TangemCollapsingAppBarBehavior
|
||||
import com.tangem.core.ui.ds.topbar.collapsing.rememberTangemExitUntilCollapsedScrollBehavior
|
||||
import com.tangem.core.ui.ds.topbar.collapsing.snapToExitUntilCollapsed
|
||||
import com.tangem.core.ui.extensions.orMaskWithStars
|
||||
import com.tangem.core.ui.extensions.resolveAnnotatedReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.core.ui.test.MainScreenTestTags
|
||||
|
|
@ -58,14 +58,17 @@ internal fun WalletBalance(
|
|||
buttons: ImmutableList<TangemButtonUM>,
|
||||
isBalanceHidden: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
onSubtitleBottomChange: (Dp) -> Unit = {},
|
||||
) {
|
||||
val collapsedFraction = behavior.state.collapsedFraction
|
||||
val alpha = 1f - collapsedFraction
|
||||
val scale = alpha.coerceIn(MIN_SCALE, MAX_SCALE)
|
||||
val density = LocalDensity.current
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = modifier
|
||||
.testTag(MainScreenTestTags.WALLET_LIST_ITEM)
|
||||
.alpha(alpha)
|
||||
.scale(scale)
|
||||
.snapToExitUntilCollapsed(behavior)
|
||||
|
|
@ -85,7 +88,15 @@ internal fun WalletBalance(
|
|||
isBalanceHidden = isBalanceHidden,
|
||||
)
|
||||
SpacerH(TangemTheme.dimens2.x3)
|
||||
SubtitleRow(walletBalanceUM = walletBalanceUM)
|
||||
Box(
|
||||
modifier = Modifier.onGloballyPositioned { coordinates ->
|
||||
val rawBottomPx = coordinates.boundsInRoot().bottom
|
||||
if (rawBottomPx <= 0f) return@onGloballyPositioned
|
||||
onSubtitleBottomChange(with(density) { rawBottomPx.toDp() })
|
||||
},
|
||||
) {
|
||||
SubtitleRow(walletBalanceUM = walletBalanceUM)
|
||||
}
|
||||
}
|
||||
SpacerH(TangemTheme.dimens2.x2)
|
||||
ActionButtons(buttons)
|
||||
|
|
@ -140,8 +151,12 @@ private fun SubtitleRow(walletBalanceUM: WalletBalanceUM, modifier: Modifier = M
|
|||
text = walletBalanceUM.name,
|
||||
style = TangemTheme.typography2.bodyRegular14,
|
||||
color = TangemTheme.colors2.text.neutral.tertiary,
|
||||
modifier = Modifier.testTag(MainScreenTestTags.CARD_TITLE),
|
||||
)
|
||||
TangemDeviceIcon(
|
||||
state = walletBalanceUM.deviceIcon,
|
||||
modifier = Modifier.testTag(MainScreenTestTags.CARD_IMAGE),
|
||||
)
|
||||
TangemDeviceIcon(state = walletBalanceUM.deviceIcon)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -337,6 +337,7 @@ private fun AdditionalInfo(
|
|||
id = R.string.initial_wallet_sync_restore_progress,
|
||||
formatArgs = wrappedList(animatedContent.progressPercent),
|
||||
),
|
||||
testTag = MainScreenTestTags.SYNC_PROGRESS_TEXT,
|
||||
)
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size16),
|
||||
|
|
@ -353,14 +354,14 @@ private fun AdditionalInfo(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun AdditionalInfoText(text: TextReference) {
|
||||
private fun AdditionalInfoText(text: TextReference, testTag: String = MainScreenTestTags.DEVICES_COUNT) {
|
||||
Text(
|
||||
text = text.resolveReference(),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = TangemTheme.typography.caption2,
|
||||
modifier = Modifier.testTag(MainScreenTestTags.DEVICES_COUNT),
|
||||
modifier = Modifier.testTag(testTag),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,12 +9,14 @@ import androidx.compose.foundation.rememberOverscrollEffect
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.paging.compose.LazyPagingItems
|
||||
import com.tangem.common.ui.notifications.notifications
|
||||
import com.tangem.common.ui.notifications.notificationsCarousel
|
||||
import com.tangem.core.ui.components.transactions.state.TxHistoryState
|
||||
import com.tangem.core.ui.components.transactions.txHistoryItems
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.test.MainScreenTestTags
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency.tokensListItems
|
||||
|
|
@ -40,7 +42,7 @@ internal fun WalletListContent(
|
|||
val itemModifier = movableItemModifier.padding(top = TangemTheme.dimens2.x3)
|
||||
|
||||
LazyColumn(
|
||||
modifier = modifier,
|
||||
modifier = modifier.testTag(MainScreenTestTags.SCREEN_CONTAINER),
|
||||
state = listState,
|
||||
contentPadding = contentPadding,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components.common
|
||||
|
||||
import androidx.compose.foundation.lazy.LazyItemScope
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
|
|
@ -16,6 +18,7 @@ import com.tangem.core.ui.extensions.resourceReference
|
|||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.ForceDarkTheme
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.test.WalletNotificationTestTags
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -73,26 +76,35 @@ internal fun LazyListScope.notifications(configs: ImmutableList<WalletNotificati
|
|||
subtitle = resourceReference(R.string.tangempay_onboarding_banner_description),
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
Notification(
|
||||
config = item.config,
|
||||
modifier = modifier.animateItem(fadeInSpec = null, fadeOutSpec = null),
|
||||
iconTint = when (item) {
|
||||
is WalletNotification.Critical -> TangemTheme.colors.icon.warning
|
||||
is WalletNotification.Informational -> TangemTheme.colors.icon.accent
|
||||
is WalletNotification.RateApp -> TangemTheme.colors.icon.attention
|
||||
is WalletNotification.UnlockWallets -> TangemTheme.colors.icon.primary1
|
||||
is WalletNotification.UsedOutdatedData -> TangemTheme.colors.text.attention
|
||||
else -> null
|
||||
},
|
||||
subtitleColor = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
}
|
||||
else -> DefaultWalletNotification(item = item, modifier = modifier)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LazyItemScope.DefaultWalletNotification(item: WalletNotification, modifier: Modifier = Modifier) {
|
||||
val itemModifier = modifier.animateItem(fadeInSpec = null, fadeOutSpec = null)
|
||||
val taggedModifier = when (item) {
|
||||
is WalletNotification.AssetsDiscoveryCompleted ->
|
||||
itemModifier.testTag(WalletNotificationTestTags.ASSETS_DISCOVERY_BANNER)
|
||||
else -> itemModifier
|
||||
}
|
||||
Notification(
|
||||
config = item.config,
|
||||
modifier = taggedModifier,
|
||||
iconTint = when (item) {
|
||||
is WalletNotification.Critical -> TangemTheme.colors.icon.warning
|
||||
is WalletNotification.Informational -> TangemTheme.colors.icon.accent
|
||||
is WalletNotification.RateApp -> TangemTheme.colors.icon.attention
|
||||
is WalletNotification.UnlockWallets -> TangemTheme.colors.icon.primary1
|
||||
is WalletNotification.UsedOutdatedData -> TangemTheme.colors.text.attention
|
||||
else -> null
|
||||
},
|
||||
subtitleColor = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun yieldBoostPromoTitle(): AnnotatedString {
|
||||
val accent = TangemTheme.colors.text.accent
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import androidx.compose.ui.draw.alpha
|
|||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.getPullToRefreshIndicatorOffset
|
||||
import com.tangem.core.ui.ds.TangemPagerIndicator
|
||||
|
|
@ -23,7 +24,6 @@ import com.tangem.core.ui.ds.topbar.collapsing.TangemCollapsingAppBarBehavior
|
|||
|
||||
private const val MIN_SCALE = 0.75f
|
||||
private const val MAX_SCALE = 1f
|
||||
private const val WALLET_INDICATOR_OFFSET = 0.6f
|
||||
|
||||
@Composable
|
||||
internal fun WalletPagerIndicator(
|
||||
|
|
@ -31,6 +31,7 @@ internal fun WalletPagerIndicator(
|
|||
behavior: TangemCollapsingAppBarBehavior,
|
||||
pullToRefreshConfig: PullToRefreshConfig?,
|
||||
pullToRefreshState: PullToRefreshState,
|
||||
topOffset: Dp,
|
||||
) {
|
||||
val collapsedFraction = behavior.state.collapsedFraction
|
||||
val alpha = MAX_SCALE - collapsedFraction
|
||||
|
|
@ -43,7 +44,6 @@ internal fun WalletPagerIndicator(
|
|||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
pullToRefreshState = pullToRefreshState,
|
||||
)
|
||||
val padding = height * WALLET_INDICATOR_OFFSET
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = pagerState.pageCount > 1,
|
||||
|
|
@ -64,7 +64,7 @@ internal fun WalletPagerIndicator(
|
|||
TangemPagerIndicator(
|
||||
pagerState = pagerState,
|
||||
modifier = Modifier
|
||||
.padding(top = padding)
|
||||
.padding(top = topOffset)
|
||||
.scale(scaleY = 1f, scaleX = scale),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,7 +93,10 @@ internal fun WalletTopBar(
|
|||
),
|
||||
) {
|
||||
topBarConfig.endActions.forEach { action ->
|
||||
TangemTopBarActionContent(action)
|
||||
TangemTopBarActionContent(
|
||||
action,
|
||||
modifier = Modifier.testTag(MainScreenTestTags.MORE_BUTTON),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,188 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.tangem.common.ui.tokens.TokenConverterParams
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.core.ui.ds.button.TangemButtonType
|
||||
import com.tangem.core.ui.ds.button.TangemButtonUM
|
||||
import com.tangem.core.ui.ds.image.DeviceIconUM
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.account.models.AccountStatusList
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.core.utils.lceError
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.TokensGroupType
|
||||
import com.tangem.domain.models.TokensSortType
|
||||
import com.tangem.domain.models.TotalFiatBalance
|
||||
import com.tangem.domain.models.account.Account.CryptoPortfolio.Companion.createMainAccount
|
||||
import com.tangem.domain.models.account.AccountStatus
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.network.NetworkAddress
|
||||
import com.tangem.domain.models.tokenlist.TokenList
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.*
|
||||
import com.tangem.features.tangempay.entity.TangemPayMainUM
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import org.junit.Test
|
||||
import java.math.BigDecimal
|
||||
|
||||
class SetTokenListTransformerTest {
|
||||
|
||||
private val userWalletId = UserWalletId("00")
|
||||
|
||||
@Test
|
||||
fun `GIVEN empty account list WHEN transform THEN tokens are Empty and buttons disabled`() {
|
||||
val transformer = createTransformer(accountList = emptyAccountList())
|
||||
|
||||
val result = transformer.transform(walletUM(buttonEnabled = true)) as WalletUM.Content
|
||||
|
||||
assertThat(result.tokensListUM).isInstanceOf(WalletTokensListUM.Empty::class.java)
|
||||
assertThat(result.buttons).hasSize(1)
|
||||
assertThat(result.buttons.single().isEnabled).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN non-empty account list WHEN transform THEN tokens not Empty and buttons enabled`() {
|
||||
val transformer = createTransformer(accountList = nonEmptyAccountList())
|
||||
|
||||
val result = transformer.transform(walletUM(buttonEnabled = false)) as WalletUM.Content
|
||||
|
||||
assertThat(result.tokensListUM).isNotInstanceOf(WalletTokensListUM.Empty::class.java)
|
||||
assertThat(result.buttons).hasSize(1)
|
||||
assertThat(result.buttons.single().isEnabled).isTrue()
|
||||
}
|
||||
|
||||
private fun createTransformer(accountList: AccountStatusList): SetTokenListTransformer {
|
||||
val userWallet = mockk<UserWallet.Hot>(relaxed = true) {
|
||||
every { walletId } returns userWalletId
|
||||
}
|
||||
return SetTokenListTransformer(
|
||||
params = TokenConverterParams.Account(
|
||||
accountList = accountList,
|
||||
expandedAccounts = emptySet(),
|
||||
),
|
||||
userWallet = userWallet,
|
||||
appCurrency = AppCurrency.Default,
|
||||
clickIntents = mockk<WalletClickIntents>(relaxed = true),
|
||||
shouldShowMainPromo = false,
|
||||
isAccountsModeEnabled = false,
|
||||
isRedesignEnabled = true,
|
||||
isAddAndManageTokensEnabled = false,
|
||||
)
|
||||
}
|
||||
|
||||
private fun emptyAccountList(): AccountStatusList = AccountStatusList(
|
||||
userWalletId = userWalletId,
|
||||
accountStatuses = listOf(mainCryptoPortfolioStatus(tokenList = TokenList.Empty)),
|
||||
totalAccounts = 1,
|
||||
totalArchivedAccounts = 0,
|
||||
totalFiatBalance = TotalFiatBalance.Loading,
|
||||
sortType = TokensSortType.NONE,
|
||||
groupType = TokensGroupType.NONE,
|
||||
)
|
||||
|
||||
private fun nonEmptyAccountList(): AccountStatusList {
|
||||
val token = createToken()
|
||||
val tokenList = TokenList.Ungrouped(
|
||||
currencies = listOf(createLoadedStatus(token)),
|
||||
totalFiatBalance = TotalFiatBalance.Loaded(BigDecimal.ZERO, StatusSource.ACTUAL),
|
||||
sortedBy = TokensSortType.NONE,
|
||||
)
|
||||
return AccountStatusList(
|
||||
userWalletId = userWalletId,
|
||||
accountStatuses = listOf(mainCryptoPortfolioStatus(tokenList = tokenList)),
|
||||
totalAccounts = 1,
|
||||
totalArchivedAccounts = 0,
|
||||
totalFiatBalance = TotalFiatBalance.Loading,
|
||||
sortType = TokensSortType.NONE,
|
||||
groupType = TokensGroupType.NONE,
|
||||
)
|
||||
}
|
||||
|
||||
private fun mainCryptoPortfolioStatus(tokenList: TokenList): AccountStatus.CryptoPortfolio =
|
||||
AccountStatus.CryptoPortfolio(
|
||||
account = createMainAccount(userWalletId),
|
||||
tokenList = tokenList,
|
||||
priceChangeLce = Unit.lceError(),
|
||||
)
|
||||
|
||||
private fun walletUM(buttonEnabled: Boolean): WalletUM.Content = WalletUM.Content(
|
||||
pullToRefreshConfig = PullToRefreshConfig(isRefreshing = false, onRefresh = {}),
|
||||
walletsBalanceUM = WalletBalanceUM.Loading(
|
||||
id = userWalletId,
|
||||
name = "test",
|
||||
deviceIcon = DeviceIconUM.Mobile,
|
||||
),
|
||||
buttons = persistentListOf(
|
||||
TangemButtonUM(
|
||||
text = stringReference(value = "Buy"),
|
||||
type = TangemButtonType.Secondary,
|
||||
onClick = {},
|
||||
isEnabled = buttonEnabled,
|
||||
),
|
||||
),
|
||||
notifications = persistentListOf(),
|
||||
notificationsCarousel = persistentListOf(),
|
||||
tokensListUM = WalletTokensListUM.Loading,
|
||||
nftState = WalletNFTItemUM.Hidden,
|
||||
type = WalletType.Hot,
|
||||
tangemPayMainUM = TangemPayMainUM.Empty,
|
||||
)
|
||||
|
||||
private fun createToken(): CryptoCurrency.Token {
|
||||
val network = Network(
|
||||
id = Network.ID(value = "ethereum", derivationPath = Network.DerivationPath.None),
|
||||
name = "ethereum",
|
||||
currencySymbol = "ETH",
|
||||
derivationPath = Network.DerivationPath.None,
|
||||
isTestnet = false,
|
||||
standardType = Network.StandardType.ERC20,
|
||||
hasFiatFeeRate = false,
|
||||
canHandleTokens = true,
|
||||
transactionExtrasType = Network.TransactionExtrasType.NONE,
|
||||
nameResolvingType = Network.NameResolvingType.NONE,
|
||||
)
|
||||
return CryptoCurrency.Token(
|
||||
id = CryptoCurrency.ID(
|
||||
prefix = CryptoCurrency.ID.Prefix.TOKEN_PREFIX,
|
||||
body = CryptoCurrency.ID.Body.NetworkId(rawId = "ethereum"),
|
||||
suffix = CryptoCurrency.ID.Suffix.ContractAddress(contractAddress = "0xABCDEF"),
|
||||
),
|
||||
network = network,
|
||||
name = "Token",
|
||||
symbol = "TKN",
|
||||
decimals = 18,
|
||||
iconUrl = null,
|
||||
isCustom = false,
|
||||
contractAddress = "0xABCDEF",
|
||||
)
|
||||
}
|
||||
|
||||
private fun createLoadedStatus(token: CryptoCurrency.Token): CryptoCurrencyStatus {
|
||||
val networkAddress = NetworkAddress.Single(
|
||||
defaultAddress = NetworkAddress.Address(
|
||||
value = "addr",
|
||||
type = NetworkAddress.Address.Type.Primary,
|
||||
),
|
||||
)
|
||||
val value = CryptoCurrencyStatus.Loaded(
|
||||
amount = BigDecimal.ONE,
|
||||
fiatAmount = BigDecimal.ZERO,
|
||||
fiatRate = BigDecimal.ONE,
|
||||
priceChange = BigDecimal.ZERO,
|
||||
stakingBalance = null,
|
||||
yieldSupplyStatus = null,
|
||||
hasCurrentNetworkTransactions = false,
|
||||
pendingTransactions = emptySet(),
|
||||
networkAddress = networkAddress,
|
||||
sources = CryptoCurrencyStatus.Sources(),
|
||||
)
|
||||
return CryptoCurrencyStatus(currency = token, value = value)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue