Updated on 2026-08-14
This commit is contained in:
commit
43c11d0460
384 changed files with 19228 additions and 3308 deletions
|
|
@ -2,6 +2,7 @@ package com.tangem.feature.wallet.child.managetokens
|
|||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.slot.childSlot
|
||||
|
|
@ -48,9 +49,11 @@ internal class AddAndManageBottomSheetComponent(
|
|||
@Composable
|
||||
override fun BottomSheet() {
|
||||
val portfolioSelectorSlot by portfolioSelectorSlot.subscribeAsState()
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
|
||||
AddAndManageBottomSheetContent(
|
||||
onAddTokensClick = model::onAddTokensClick,
|
||||
shouldShowOrganizeButton = state.shouldShowOrganize,
|
||||
onOrganizeTokensClick = model::onOrganizeTokensClick,
|
||||
onDismiss = ::dismiss,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
|
|||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.domain.account.models.hasMultiCurrencyAccount
|
||||
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
||||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.feature.wallet.child.managetokens.AddAndManageBottomSheetComponent
|
||||
import com.tangem.feature.wallet.child.managetokens.analytics.PortfolioAnalyticsEvent
|
||||
|
|
@ -14,7 +16,10 @@ import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioFetcher
|
|||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorComponent
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorController
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -25,18 +30,20 @@ internal class AddAndManageModel @Inject constructor(
|
|||
private val portfolioFetcherFactory: PortfolioFetcher.Factory,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
val portfolioSelectorController: PortfolioSelectorController,
|
||||
private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<AddAndManageBottomSheetComponent.Params>()
|
||||
|
||||
val portfolioSelectorNavigation: SlotNavigation<Unit> = SlotNavigation()
|
||||
|
||||
val portfolioFetcher: PortfolioFetcher by lazy {
|
||||
portfolioFetcherFactory.create(
|
||||
mode = PortfolioFetcher.Mode.Wallet(params.userWalletId),
|
||||
scope = modelScope,
|
||||
)
|
||||
}
|
||||
val state: StateFlow<AddAndManageState>
|
||||
field = MutableStateFlow(AddAndManageState(shouldShowOrganize = true))
|
||||
|
||||
val portfolioSelectorCallback = object : PortfolioSelectorComponent.BottomSheetCallback {
|
||||
override val onDismiss: () -> Unit = { portfolioSelectorNavigation.dismiss() }
|
||||
|
|
@ -45,6 +52,7 @@ internal class AddAndManageModel @Inject constructor(
|
|||
|
||||
init {
|
||||
observeAccountSelection()
|
||||
updateShouldShowOrganizeButtonState()
|
||||
}
|
||||
|
||||
fun onAddTokensClick() {
|
||||
|
|
@ -85,4 +93,12 @@ internal class AddAndManageModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateShouldShowOrganizeButtonState() {
|
||||
modelScope.launch {
|
||||
val accountStatusesList = singleAccountStatusListSupplier.getSyncOrNull(params.userWalletId)
|
||||
val hasMultiCurrencyAccount = accountStatusesList?.hasMultiCurrencyAccount() == true
|
||||
state.update { it.copy(shouldShowOrganize = hasMultiCurrencyAccount) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.tangem.feature.wallet.child.managetokens.model
|
||||
|
||||
data class AddAndManageState(
|
||||
val shouldShowOrganize: Boolean,
|
||||
)
|
||||
|
|
@ -31,6 +31,7 @@ import com.tangem.core.ui.res.TangemThemePreview
|
|||
@Composable
|
||||
internal fun AddAndManageBottomSheetContent(
|
||||
onAddTokensClick: () -> Unit,
|
||||
shouldShowOrganizeButton: Boolean,
|
||||
onOrganizeTokensClick: () -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
|
|
@ -53,6 +54,7 @@ internal fun AddAndManageBottomSheetContent(
|
|||
content = {
|
||||
AddAndManageContent(
|
||||
onAddTokensClick = onAddTokensClick,
|
||||
shouldShowOrganizeButton = shouldShowOrganizeButton,
|
||||
onOrganizeTokensClick = onOrganizeTokensClick,
|
||||
)
|
||||
},
|
||||
|
|
@ -60,7 +62,11 @@ internal fun AddAndManageBottomSheetContent(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun AddAndManageContent(onAddTokensClick: () -> Unit, onOrganizeTokensClick: () -> Unit) {
|
||||
private fun AddAndManageContent(
|
||||
onAddTokensClick: () -> Unit,
|
||||
shouldShowOrganizeButton: Boolean,
|
||||
onOrganizeTokensClick: () -> Unit,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(
|
||||
start = 16.dp,
|
||||
|
|
@ -75,23 +81,25 @@ private fun AddAndManageContent(onAddTokensClick: () -> Unit, onOrganizeTokensCl
|
|||
onClick = onAddTokensClick,
|
||||
modifier = Modifier.roundedShapeItemDecoration(
|
||||
currentIndex = 0,
|
||||
lastIndex = 1,
|
||||
addDefaultPadding = false,
|
||||
backgroundColor = TangemTheme.colors.background.action,
|
||||
),
|
||||
)
|
||||
AddAndManageRow(
|
||||
iconRes = R.drawable.ic_filter_default_24,
|
||||
title = ResR.string.add_and_manage_sheet_organize_title,
|
||||
subtitle = ResR.string.add_and_manage_sheet_organize_subtitle,
|
||||
onClick = onOrganizeTokensClick,
|
||||
modifier = Modifier.roundedShapeItemDecoration(
|
||||
currentIndex = 1,
|
||||
lastIndex = 1,
|
||||
lastIndex = if (shouldShowOrganizeButton) 1 else 0,
|
||||
addDefaultPadding = false,
|
||||
backgroundColor = TangemTheme.colors.background.action,
|
||||
),
|
||||
)
|
||||
if (shouldShowOrganizeButton) {
|
||||
AddAndManageRow(
|
||||
iconRes = R.drawable.ic_filter_default_24,
|
||||
title = ResR.string.add_and_manage_sheet_organize_title,
|
||||
subtitle = ResR.string.add_and_manage_sheet_organize_subtitle,
|
||||
onClick = onOrganizeTokensClick,
|
||||
modifier = Modifier.roundedShapeItemDecoration(
|
||||
currentIndex = 1,
|
||||
lastIndex = 1,
|
||||
addDefaultPadding = false,
|
||||
backgroundColor = TangemTheme.colors.background.action,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -152,6 +160,7 @@ private fun AddAndManageBottomSheetContent_Preview() {
|
|||
TangemThemePreview {
|
||||
AddAndManageContent(
|
||||
onAddTokensClick = {},
|
||||
shouldShowOrganizeButton = true,
|
||||
onOrganizeTokensClick = {},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import com.tangem.core.analytics.models.AnalyticsParam
|
|||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.ui.ds.button.TangemButtonShape
|
||||
import com.tangem.core.ui.ds.button.TangemButtonSize
|
||||
import com.tangem.core.ui.ds.button.TangemButtonType
|
||||
import com.tangem.core.ui.ds.button.TangemButtonUM
|
||||
import com.tangem.core.ui.event.consumedEvent
|
||||
|
|
@ -268,11 +270,15 @@ internal class OrganizeTokensModel @Inject constructor(
|
|||
text = resourceReference(R.string.common_cancel),
|
||||
onClick = ::onCancelClick,
|
||||
type = TangemButtonType.Secondary,
|
||||
shape = TangemButtonShape.Rounded,
|
||||
size = TangemButtonSize.X12,
|
||||
),
|
||||
applyButton = TangemButtonUM(
|
||||
text = resourceReference(R.string.common_apply),
|
||||
onClick = ::onApplyClick,
|
||||
type = TangemButtonType.Primary,
|
||||
shape = TangemButtonShape.Rounded,
|
||||
size = TangemButtonSize.X12,
|
||||
),
|
||||
scrollListToTop = consumedEvent(),
|
||||
isBalanceHidden = true,
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ internal class OrganizeTokensListConverter(
|
|||
return value.accountStatuses
|
||||
.asSequence()
|
||||
.filterCryptoPortfolio()
|
||||
.filter { it.tokenList !is TokenList.Empty }
|
||||
.flatMap { accountStatus ->
|
||||
buildList {
|
||||
addIf(
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import androidx.compose.ui.draw.shadow
|
|||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.layout.layoutId
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.platform.testTag
|
||||
|
|
@ -33,8 +34,14 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
|||
import com.tangem.core.ui.components.haze.hazeEffectTangem
|
||||
import com.tangem.core.ui.components.haze.hazeSourceTangem
|
||||
import com.tangem.core.ui.ds.button.TangemButton
|
||||
import com.tangem.core.ui.ds.image.TangemIcon
|
||||
import com.tangem.core.ui.ds.row.TangemRowContainer
|
||||
import com.tangem.core.ui.ds.row.TangemRowLayoutId
|
||||
import com.tangem.core.ui.ds.row.header.TangemHeaderRow
|
||||
import com.tangem.core.ui.ds.row.token.TangemTokenRow
|
||||
import com.tangem.core.ui.ds.row.internal.TangemRowTail
|
||||
import com.tangem.core.ui.ds.row.token.TangemTokenRowUM
|
||||
import com.tangem.core.ui.ds.row.token.internal.TokenRowEndContent
|
||||
import com.tangem.core.ui.ds.row.token.internal.TokenRowTitle
|
||||
import com.tangem.core.ui.ds.topbar.TangemTopBar
|
||||
import com.tangem.core.ui.ds.topbar.TangemTopBarActionContent
|
||||
import com.tangem.core.ui.ds.topbar.TangemTopBarActionUM
|
||||
|
|
@ -44,6 +51,7 @@ import com.tangem.core.ui.reordarable.ReorderableItem
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.core.ui.test.OrganizeTokensScreenTestTags
|
||||
import com.tangem.core.ui.test.TokenElementsTestTags
|
||||
import com.tangem.core.ui.utils.lazyListItemPosition
|
||||
import com.tangem.feature.wallet.child.organizetokens.entity.DraggableItem
|
||||
import com.tangem.feature.wallet.child.organizetokens.entity.OrganizeRowItemUM
|
||||
|
|
@ -219,7 +227,7 @@ private fun LazyItemScope.DraggableItem(
|
|||
headerRowUM = item.headerRowUM,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
)
|
||||
is OrganizeRowItemUM.Token -> TangemTokenRow(
|
||||
is OrganizeRowItemUM.Token -> OrganizeTokenRow(
|
||||
modifier = modifierWithBackground,
|
||||
tokenRowUM = item.tokenRowUM,
|
||||
reorderableState = reorderableState,
|
||||
|
|
@ -291,6 +299,55 @@ private fun Modifier.applyShapeAndShadow(roundingMode: RoundingModeUM, showShado
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun OrganizeTokenRow(
|
||||
tokenRowUM: TangemTokenRowUM,
|
||||
isBalanceHidden: Boolean,
|
||||
reorderableState: ReorderableLazyListState?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
TangemRowContainer(
|
||||
content = {
|
||||
TangemIcon(
|
||||
tangemIconUM = tokenRowUM.headIconUM,
|
||||
modifier = Modifier
|
||||
.layoutId(layoutId = TangemRowLayoutId.HEAD)
|
||||
.padding(end = TangemTheme.dimens2.x3)
|
||||
.size(TangemTheme.dimens2.x10)
|
||||
.testTag(tag = TokenElementsTestTags.TOKEN_ICON),
|
||||
)
|
||||
|
||||
TokenRowTitle(
|
||||
titleUM = tokenRowUM.titleUM,
|
||||
modifier = Modifier
|
||||
.layoutId(layoutId = TangemRowLayoutId.START_TOP)
|
||||
.padding(end = TangemTheme.dimens2.x2)
|
||||
.testTag(tag = TokenElementsTestTags.TOKEN_TITLE),
|
||||
)
|
||||
|
||||
TokenRowEndContent(
|
||||
endContentUM = tokenRowUM.topEndContentUM,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
textStyle = TangemTheme.typography2.captionSemibold12,
|
||||
textColor = TangemTheme.colors2.text.neutral.secondary,
|
||||
placeholderWidth = TangemTheme.dimens2.x11,
|
||||
modifier = Modifier
|
||||
.layoutId(layoutId = TangemRowLayoutId.START_BOTTOM)
|
||||
.testTag(tag = TokenElementsTestTags.TOKEN_FIAT_AMOUNT),
|
||||
)
|
||||
|
||||
TangemRowTail(
|
||||
tangemRowTailUM = tokenRowUM.tailUM,
|
||||
reorderableState = reorderableState,
|
||||
modifier = Modifier
|
||||
.layoutId(layoutId = TangemRowLayoutId.TAIL)
|
||||
.testTag(tag = TokenElementsTestTags.TOKEN_NON_FIAT_BLOCK),
|
||||
)
|
||||
},
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
private fun getItemGap(roundingMode: RoundingModeUM): PaddingValues {
|
||||
|
|
|
|||
|
|
@ -243,10 +243,6 @@ internal class WalletModel @Inject constructor(
|
|||
} else {
|
||||
null
|
||||
}
|
||||
val isBackedUp = when (selectedWallet) {
|
||||
is UserWallet.Cold -> selectedWallet.scanResponse.card.backupStatus?.isActive == true
|
||||
is UserWallet.Hot -> selectedWallet.backedUp
|
||||
}
|
||||
val result = getAppThemeModeUseCase().firstOrNull()
|
||||
val theme = result?.getOrElse { AppThemeMode.FOLLOW_SYSTEM } ?: AppThemeMode.FOLLOW_SYSTEM
|
||||
val appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default }.code
|
||||
|
|
@ -254,7 +250,7 @@ internal class WalletModel @Inject constructor(
|
|||
WalletScreenAnalyticsEvent.MainScreen.ScreenOpened(
|
||||
hasMobileWallet = hasMobileWallet,
|
||||
accountsCount = accountsCount,
|
||||
isBackedUp = isBackedUp,
|
||||
isBackedUp = selectedWallet.isBackedUpForAnalytics(),
|
||||
theme = theme.value,
|
||||
isImported = selectedWallet.isImported(),
|
||||
referralId = appsFlyerStore.get()?.refcode,
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ import com.tangem.domain.feedback.GetWalletMetaInfoUseCase
|
|||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.domain.feedback.models.WalletMetaInfo
|
||||
import com.tangem.domain.models.account.AccountStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.TangemPayDetailsConfig
|
||||
import com.tangem.domain.pay.TangemPayEligibilityManager
|
||||
import com.tangem.domain.pay.flow.PaymentAccountStatusFetcher
|
||||
import com.tangem.domain.pay.model.TangemPayEntryPoint
|
||||
|
|
@ -40,7 +40,7 @@ internal interface TangemPayIntents {
|
|||
|
||||
fun onRefreshPayToken(userWallet: UserWallet)
|
||||
|
||||
fun openDetails(userWalletId: UserWalletId, config: TangemPayDetailsConfig)
|
||||
fun openDetails(status: AccountStatus.Payment)
|
||||
|
||||
fun onKycProgressClicked(userWalletId: UserWalletId)
|
||||
|
||||
|
|
@ -110,11 +110,8 @@ internal class TangemPayClickIntentsImplementor @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun openDetails(userWalletId: UserWalletId, config: TangemPayDetailsConfig) {
|
||||
router.openTangemPayDetails(
|
||||
userWalletId = userWalletId,
|
||||
config = config,
|
||||
)
|
||||
override fun openDetails(status: AccountStatus.Payment) {
|
||||
router.openTangemPayDetails(status = status)
|
||||
}
|
||||
|
||||
override fun onKycProgressClicked(userWalletId: UserWalletId) {
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@ import com.tangem.core.ui.DesignFeatureToggles
|
|||
import com.tangem.core.ui.ds.row.token.TangemTokenRowUM
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.models.account.AccountId
|
||||
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.scan.ScanResponse
|
||||
import com.tangem.domain.qrscanning.models.QrSendTarget
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.TangemPayDetailsConfig
|
||||
import com.tangem.domain.qrscanning.models.QrSendTarget
|
||||
import com.tangem.domain.tokens.model.details.NavigationAction
|
||||
import com.tangem.domain.tokens.model.details.TokenAction
|
||||
import com.tangem.feature.wallet.child.organizetokens.OrganizeTokensComponent
|
||||
|
|
@ -142,8 +142,8 @@ internal class DefaultWalletRouter @Inject constructor(
|
|||
router.push(route = AppRoute.TangemPayOnboarding(mode = mode))
|
||||
}
|
||||
|
||||
override fun openTangemPayDetails(userWalletId: UserWalletId, config: TangemPayDetailsConfig) {
|
||||
router.push(AppRoute.TangemPayDetails(userWalletId = userWalletId, config = config))
|
||||
override fun openTangemPayDetails(status: AccountStatus.Payment) {
|
||||
router.push(AppRoute.TangemPayDetails(status = status))
|
||||
}
|
||||
|
||||
override fun openYieldSupplyBottomSheet(
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ import com.tangem.common.routing.AppRoute
|
|||
import com.tangem.core.ui.ds.row.token.TangemTokenRowUM
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.models.account.AccountId
|
||||
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.scan.ScanResponse
|
||||
import com.tangem.domain.qrscanning.models.QrSendTarget
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.TangemPayDetailsConfig
|
||||
import com.tangem.domain.qrscanning.models.QrSendTarget
|
||||
import com.tangem.domain.tokens.model.details.NavigationAction
|
||||
import com.tangem.domain.tokens.model.details.TokenAction
|
||||
import com.tangem.feature.wallet.child.organizetokens.OrganizeTokensComponent
|
||||
|
|
@ -82,7 +82,7 @@ internal interface InnerWalletRouter {
|
|||
|
||||
fun openTangemPayOnboarding(mode: AppRoute.TangemPayOnboarding.Mode)
|
||||
|
||||
fun openTangemPayDetails(userWalletId: UserWalletId, config: TangemPayDetailsConfig)
|
||||
fun openTangemPayDetails(status: AccountStatus.Payment)
|
||||
|
||||
/** Open BS abput yield supply active and all money deposited in AAVE */
|
||||
fun openYieldSupplyBottomSheet(
|
||||
|
|
|
|||
|
|
@ -1,56 +1,14 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.analytics
|
||||
|
||||
import com.tangem.core.analytics.models.*
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
||||
sealed class WalletScreenAnalyticsEvent {
|
||||
|
||||
sealed class Basic(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
) : AnalyticsEvent(category = "Basic", event = event, params = params) {
|
||||
|
||||
class WalletToppedUp(userWalletId: UserWalletId, walletType: AnalyticsParam.WalletType) :
|
||||
Basic(
|
||||
event = "Topped up",
|
||||
params = mapOf(AnalyticsParam.CURRENCY to walletType.value),
|
||||
),
|
||||
OneTimeAnalyticsEvent, AppsFlyerIncludedEvent {
|
||||
|
||||
override val oneTimeEventId: String = id + userWalletId.stringValue
|
||||
}
|
||||
|
||||
class CardWasScanned(source: AnalyticsParam.ScreensSources) : Basic(
|
||||
event = "Card Was Scanned",
|
||||
params = mapOf(
|
||||
AnalyticsParam.SOURCE to source.value,
|
||||
),
|
||||
)
|
||||
|
||||
class BalanceLoaded(balance: AnalyticsParam.CardBalanceState, tokensCount: Int?) : Basic(
|
||||
event = "Balance Loaded",
|
||||
params = buildMap {
|
||||
put(AnalyticsParam.BALANCE, balance.value)
|
||||
tokensCount?.let { put(AnalyticsParam.TOKENS_COUNT, it.toString()) }
|
||||
},
|
||||
), AppsFlyerIncludedEvent
|
||||
|
||||
class TokenBalance(balance: AnalyticsParam.EmptyFull, token: String) : Basic(
|
||||
event = "Token Balance",
|
||||
params = mapOf(
|
||||
AnalyticsParam.STATE to balance.value,
|
||||
AnalyticsParam.TOKEN_PARAM to token,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
sealed class MainScreen(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
) : AnalyticsEvent(category = "Main Screen", event = event, params = params) {
|
||||
|
||||
class ScreenOpenedLegacy : MainScreen(event = "Screen opened")
|
||||
|
||||
data class ScreenOpened(
|
||||
private val hasMobileWallet: Boolean,
|
||||
private val accountsCount: Int?,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import com.tangem.blockchainsdk.utils.fromNetworkId
|
|||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.domain.analytics.CheckIsWalletToppedUpUseCase
|
||||
|
|
@ -18,7 +19,6 @@ import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
|||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.models.wallet.isMultiCurrency
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.Basic
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.MainScreen
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider
|
||||
|
|
@ -206,7 +206,12 @@ internal class TokenListAnalyticsSender @Inject constructor(
|
|||
AnalyticsParam.WalletType.SingleCurrency(currency.currency.name)
|
||||
}
|
||||
|
||||
analyticsEventHandler.send(Basic.WalletToppedUp(userWallet.walletId, walletType))
|
||||
analyticsEventHandler.send(
|
||||
Basic.ToppedUp(
|
||||
userWalletId = userWallet.walletId.stringValue,
|
||||
walletType = walletType,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,16 +12,12 @@ 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.pay.TangemPayDetailsConfig
|
||||
import com.tangem.domain.visa.model.TangemPayCardFrozenState
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.TangemPayIntents
|
||||
import com.tangem.features.tangempay.entity.TangemPayMainUM
|
||||
import com.tangem.utils.converter.Converter
|
||||
import java.math.BigDecimal
|
||||
import java.util.Currency
|
||||
|
||||
private const val POLYGON_CHAIN_ID = 137
|
||||
|
||||
internal class TangemPayMainBlockConverter(
|
||||
private val tangemPayClickIntents: TangemPayIntents,
|
||||
private val isRedesignEnabled: Boolean,
|
||||
|
|
@ -63,24 +59,9 @@ internal class TangemPayMainBlockConverter(
|
|||
currencyCode = statusValue.fiatBalance.currency,
|
||||
balance = statusValue.fiatBalance.availableBalance,
|
||||
),
|
||||
balanceSubtitle = stringReference("USDC"), // TODO hardcode for now
|
||||
balanceSubtitle = stringReference(statusValue.cryptoCurrency.symbol),
|
||||
shouldShowOnlyCacheWarning = statusValue.source == StatusSource.ONLY_CACHE,
|
||||
onClick = {
|
||||
// Dummy config for deactivated account just to open details screen
|
||||
tangemPayClickIntents.openDetails(
|
||||
userWalletId = value.account.userWalletId,
|
||||
config = TangemPayDetailsConfig(
|
||||
customerId = "",
|
||||
cardId = "",
|
||||
isPinSet = false,
|
||||
cardFrozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
cardNumberEnd = "",
|
||||
chainId = POLYGON_CHAIN_ID,
|
||||
displayName = null,
|
||||
isTangemPayDeactivated = true,
|
||||
),
|
||||
)
|
||||
},
|
||||
onClick = { tangemPayClickIntents.openDetails(value) },
|
||||
)
|
||||
is PaymentAccountStatusValue.Loaded -> {
|
||||
val card = statusValue.cards.firstOrNull() ?: return TangemPayMainUM.TemporaryUnavailable
|
||||
|
|
@ -91,27 +72,9 @@ internal class TangemPayMainBlockConverter(
|
|||
currencyCode = statusValue.currencyCode,
|
||||
balance = statusValue.fiatBalance.availableBalance,
|
||||
),
|
||||
balanceSubtitle = stringReference("USDC"), // TODO hardcode for now
|
||||
balanceSubtitle = stringReference(statusValue.cryptoCurrency.symbol),
|
||||
shouldShowOnlyCacheWarning = statusValue.source == StatusSource.ONLY_CACHE,
|
||||
onClick = {
|
||||
tangemPayClickIntents.openDetails(
|
||||
value.account.userWalletId,
|
||||
TangemPayDetailsConfig(
|
||||
customerId = statusValue.customerId,
|
||||
cardId = card.id,
|
||||
isPinSet = card.hasPinCode,
|
||||
cardFrozenState = if (card.isFrozen) {
|
||||
TangemPayCardFrozenState.Frozen
|
||||
} else {
|
||||
TangemPayCardFrozenState.Unfrozen
|
||||
},
|
||||
cardNumberEnd = card.lastDigits,
|
||||
chainId = POLYGON_CHAIN_ID,
|
||||
displayName = card.displayName,
|
||||
isTangemPayDeactivated = false,
|
||||
),
|
||||
)
|
||||
},
|
||||
onClick = { tangemPayClickIntents.openDetails(value) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import com.tangem.core.ui.components.tokenlist.state.PortfolioTokensListItemUM
|
|||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.account.models.AccountStatusList
|
||||
import com.tangem.domain.account.models.hasMultiCurrencyAccount
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.TotalFiatBalance
|
||||
|
|
@ -40,7 +41,7 @@ internal class TokenListStateConverter(
|
|||
private val clickIntents: WalletClickIntents,
|
||||
private val yieldModuleApyMap: Map<String, BigDecimal>,
|
||||
private val stakingAvailabilityMap: Map<CryptoCurrency, StakingAvailability>,
|
||||
private val shouldShowMainPromo: Boolean,
|
||||
shouldShowMainPromo: Boolean,
|
||||
private val isAddAndManageTokensEnabled: Boolean,
|
||||
) : Converter<WalletTokensListState, WalletTokensListState> {
|
||||
|
||||
|
|
@ -169,7 +170,8 @@ internal class TokenListStateConverter(
|
|||
}
|
||||
|
||||
private fun getOrganizeTokensButtonStateV2(accountList: AccountStatusList): WalletOrganizeTokensButtonConfig? {
|
||||
return if (accountList.flattenCurrencies().size > 1 && !isSingleCurrencyWalletWithToken()) {
|
||||
val shouldShowOrganizeIfOldButton = accountList.hasMultiCurrencyAccount() || isAddAndManageTokensEnabled
|
||||
return if (shouldShowOrganizeIfOldButton && !isSingleCurrencyWalletWithToken()) {
|
||||
WalletOrganizeTokensButtonConfig(
|
||||
textRes = organizeButtonTextRes(),
|
||||
iconRes = organizeButtonIconRes(),
|
||||
|
|
|
|||
|
|
@ -84,15 +84,11 @@ internal class WalletTokensListUMConverter(
|
|||
.asSequence()
|
||||
.flatMap { accountStatus ->
|
||||
if (isAccountsModeEnabled) {
|
||||
val currencies = accountStatus.tokenList.flattenCurrencies()
|
||||
val isCollapsable = currencies.isNotEmpty()
|
||||
val isExpanded =
|
||||
currencies.isEmpty() || expandedAccounts.contains(accountStatus.account.accountId)
|
||||
sequenceOf(
|
||||
TokensListItemUM2.Portfolio(
|
||||
tokenRowUM = accountRowConverter.convert(accountStatus),
|
||||
isExpanded = isExpanded,
|
||||
isCollapsable = isCollapsable,
|
||||
isExpanded = expandedAccounts.contains(accountStatus.account.accountId),
|
||||
isCollapsable = true,
|
||||
onEmptyClick = { clickIntents.onManageTokensClick(accountStatus.account.accountId) },
|
||||
tokenList = getTokenListItems(
|
||||
accountStatus,
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@ package com.tangem.feature.wallet.presentation.wallet.subscribers
|
|||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetPrimaryCurrencyTransformer
|
||||
import dagger.assisted.Assisted
|
||||
|
|
@ -70,7 +70,7 @@ internal class PrimaryCurrencySubscriber @AssistedInject constructor(
|
|||
cardBalanceState?.let { balanceState ->
|
||||
// do not send tokens count for single currency wallet
|
||||
analyticsEventHandler.send(
|
||||
event = WalletScreenAnalyticsEvent.Basic.BalanceLoaded(
|
||||
event = Basic.BalanceLoaded(
|
||||
balance = balanceState,
|
||||
tokensCount = null,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ import com.tangem.common.ui.bottomsheet.chooseaddress.ChooseAddressBottomSheet
|
|||
import com.tangem.common.ui.bottomsheet.chooseaddress.ChooseAddressBottomSheetConfig
|
||||
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheet
|
||||
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig
|
||||
import com.tangem.common.ui.expressStatus.expressTransactionsItems
|
||||
import com.tangem.common.ui.expressStatus.expressTransactionsItemsLegacy
|
||||
import com.tangem.core.ui.components.atoms.handComposableComponentHeight
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheetDraggableHeaderLegacy
|
||||
|
|
@ -236,7 +236,7 @@ private fun WalletContent(
|
|||
marketPriceBlock(state = marketPriceBlockState, modifier = itemModifier)
|
||||
}
|
||||
if (walletState is WalletState.SingleCurrency.Content) {
|
||||
expressTransactionsItems(
|
||||
expressTransactionsItemsLegacy(
|
||||
expressTxs = walletState.expressTxsToDisplay,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.ui
|
|||
import android.content.res.Configuration
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.spring
|
||||
|
|
@ -42,6 +43,7 @@ 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.DpOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.arkivanov.decompose.ExperimentalDecomposeApi
|
||||
import com.tangem.core.ui.components.BottomFade
|
||||
|
|
@ -57,6 +59,7 @@ 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.res.*
|
||||
import com.tangem.core.ui.utils.TangemSharedTransitionLayout
|
||||
|
|
@ -209,16 +212,27 @@ private fun WalletContent2(
|
|||
.fillMaxSize()
|
||||
.hazeSourceTangem(zIndex = -2f),
|
||||
) {
|
||||
NorthernLightsBackground(
|
||||
containerColor = if (LocalIsInDarkTheme.current) {
|
||||
TangemTheme.colors2.surface.level1
|
||||
} else {
|
||||
TangemTheme.colors2.surface.level2
|
||||
},
|
||||
val backgroundColor = if (LocalIsInDarkTheme.current) {
|
||||
TangemTheme.colors2.surface.level1
|
||||
} else {
|
||||
TangemTheme.colors2.surface.level2
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.graphicsLayer { alpha = 1 - behavior.state.collapsedFraction * 2 }
|
||||
.matchParentSize(),
|
||||
.matchParentSize()
|
||||
.background(backgroundColor),
|
||||
)
|
||||
val isSheetExpanded by remember {
|
||||
derivedStateOf { bottomSheetState.targetValue == TangemSheetValue.Expanded }
|
||||
}
|
||||
if (!isSheetExpanded) {
|
||||
NorthernLightsBackground(
|
||||
containerColor = backgroundColor,
|
||||
modifier = Modifier
|
||||
.graphicsLayer { alpha = 1 - behavior.state.collapsedFraction * 2 }
|
||||
.matchParentSize(),
|
||||
)
|
||||
}
|
||||
|
||||
WalletPagerIndicator(
|
||||
pagerState = walletsPagerState,
|
||||
|
|
@ -351,13 +365,23 @@ private inline fun BaseScaffoldWithMarkets(
|
|||
val peekHeight = bottomSheetHeaderHeightProvider() + TangemTheme.dimens2.x3 + bottomBarHeight
|
||||
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val background = TangemTheme.colors2.surface.level2
|
||||
|
||||
val bottomSheetState = rememberTangemStandardBottomSheetState()
|
||||
val scaffoldState = rememberTangemBottomSheetScaffoldState(bottomSheetState = bottomSheetState)
|
||||
|
||||
val expandedBackground = TangemTheme.colors2.surface.level2
|
||||
val collapsedBackground = TangemTheme.colors2.surface.level3
|
||||
val background by animateColorAsState(
|
||||
targetValue = if (bottomSheetState.targetValue == TangemSheetValue.Expanded) {
|
||||
expandedBackground
|
||||
} else {
|
||||
collapsedBackground
|
||||
},
|
||||
label = "bottomSheetBackground",
|
||||
)
|
||||
|
||||
CompositionLocalProvider(
|
||||
LocalMainBottomSheetColor provides remember(background) { mutableStateOf(background) },
|
||||
LocalMainBottomSheetColor provides remember { mutableStateOf(background) }.apply { value = background },
|
||||
) {
|
||||
val backgroundColor by LocalMainBottomSheetColor.current
|
||||
var isSearchFieldFocused by remember { mutableStateOf(false) }
|
||||
|
|
@ -487,6 +511,13 @@ private fun BottomSheet(
|
|||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.softLayerShadow(
|
||||
radius = 16.dp,
|
||||
color = Color.Black.copy(alpha = if (LocalIsInDarkTheme.current) .24f else .12f),
|
||||
shape = shape,
|
||||
offset = DpOffset(x = 0.dp, y = (-6).dp),
|
||||
isAlphaContentClip = true,
|
||||
)
|
||||
.clip(shape)
|
||||
.background(backgroundColor)
|
||||
.onFocusChanged(onFocusChange),
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.tangem.feature.wallet.presentation.wallet.ui.components.common
|
|||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
|
|
@ -80,7 +79,6 @@ internal fun WalletTopBar(
|
|||
},
|
||||
endContent = {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x5),
|
||||
modifier = Modifier
|
||||
.clip(CircleShape)
|
||||
.background(
|
||||
|
|
|
|||
|
|
@ -34,12 +34,13 @@ import com.tangem.common.ui.tokens.NonContentItemContent
|
|||
import com.tangem.common.ui.tokens.SlideInItemVisibility
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.account.AccountIconSize
|
||||
import com.tangem.core.ui.components.account.toBoxSize
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.tokenlist.NON_CONTENT_TOKENS_LIST_KEY
|
||||
import com.tangem.core.ui.components.tokenlist.TokenListItem
|
||||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
|
||||
import com.tangem.core.ui.ds.button.PrimaryInverseTangemButton
|
||||
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.TangemIcon
|
||||
|
|
@ -205,8 +206,6 @@ private fun LazyListScope.portfolioItem(
|
|||
if (listItem.tokenList.isEmpty()) {
|
||||
nonContentAccountItem(
|
||||
listItem = listItem,
|
||||
index = index,
|
||||
lastIndex = lastIndex,
|
||||
modifier = modifier,
|
||||
)
|
||||
} else {
|
||||
|
|
@ -221,7 +220,7 @@ private fun LazyListScope.portfolioItem(
|
|||
modifier = modifier
|
||||
.animateItem(fadeInSpec = null, placementSpec = null, fadeOutSpec = null)
|
||||
.roundedShapeItemDecoration(
|
||||
radius = 18.dp,
|
||||
radius = if (listItem.isExpanded) TangemTheme.dimens2.x6 else TangemTheme.dimens2.x5,
|
||||
currentIndex = tokenIndex + 1,
|
||||
addDefaultPadding = false,
|
||||
lastIndex = lastIndex,
|
||||
|
|
@ -293,7 +292,7 @@ private fun LazyListScope.accountItem(
|
|||
.semantics { lazyListItemPosition = index }
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = 0,
|
||||
radius = 18.dp,
|
||||
radius = if (listItem.isExpanded) TangemTheme.dimens2.x6 else TangemTheme.dimens2.x5,
|
||||
addDefaultPadding = false,
|
||||
lastIndex = effectiveLastIndex,
|
||||
backgroundColor = TangemTheme.colors2.surface.level3,
|
||||
|
|
@ -382,12 +381,14 @@ internal fun PortfolioRowItem(
|
|||
headIcon
|
||||
}
|
||||
|
||||
val iconBoxSize = when (headIcon) {
|
||||
is TangemIconUM.Empty -> TangemTheme.dimens2.x9
|
||||
else -> size.toBoxSize()
|
||||
}
|
||||
TangemIcon(
|
||||
tangemIconUM = sizedHeadIcon,
|
||||
modifier = modifier
|
||||
.conditionalCompose(headIcon is TangemIconUM.Empty) {
|
||||
size(TangemTheme.dimens2.x9)
|
||||
}
|
||||
.size(iconBoxSize)
|
||||
.sharedBounds(
|
||||
sharedContentState = iconSharedContentState,
|
||||
animatedVisibilityScope = animatedContentScope,
|
||||
|
|
@ -489,23 +490,18 @@ private fun LazyListScope.nonContentItem2(onEmptyClick: () -> Unit, modifier: Mo
|
|||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.nonContentAccountItem(
|
||||
listItem: TokensListItemUM2.Portfolio,
|
||||
index: Int,
|
||||
lastIndex: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
private fun LazyListScope.nonContentAccountItem(listItem: TokensListItemUM2.Portfolio, modifier: Modifier = Modifier) {
|
||||
item(
|
||||
key = "$NON_CONTENT_TOKENS_LIST_KEY account-${listItem.tokenRowUM.id}",
|
||||
contentType = "$NON_CONTENT_TOKENS_LIST_KEY account-${listItem.tokenRowUM.id}",
|
||||
) {
|
||||
SlideInItemVisibility(
|
||||
currentIndex = index + 1,
|
||||
lastIndex = lastIndex,
|
||||
currentIndex = 1,
|
||||
lastIndex = 1,
|
||||
modifier = modifier
|
||||
.animateItem(fadeInSpec = null, placementSpec = null, fadeOutSpec = null)
|
||||
.roundedShapeItemDecoration(
|
||||
radius = 18.dp,
|
||||
radius = if (listItem.isExpanded) TangemTheme.dimens2.x6 else TangemTheme.dimens2.x5,
|
||||
addDefaultPadding = false,
|
||||
currentIndex = 1,
|
||||
lastIndex = 1,
|
||||
|
|
@ -542,8 +538,8 @@ internal fun NonContentItemContentV2(textColor: Color, modifier: Modifier = Modi
|
|||
textAlign = TextAlign.Center,
|
||||
style = TangemTheme.typography2.bodyRegular14,
|
||||
)
|
||||
SpacerH(TangemTheme.dimens2.x2)
|
||||
PrimaryInverseTangemButton(
|
||||
SpacerH(TangemTheme.dimens2.x4)
|
||||
SecondaryTangemButton(
|
||||
text = resourceReference(id = R.string.common_add_tokens),
|
||||
onClick = onClick,
|
||||
size = TangemButtonSize.X8,
|
||||
|
|
|
|||
|
|
@ -4,12 +4,18 @@ import com.google.common.truth.Truth.assertThat
|
|||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.decompose.model.MutableParamsContainer
|
||||
import com.tangem.domain.account.models.AccountStatusList
|
||||
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
||||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.domain.models.account.AccountStatus
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.tokenlist.TokenList
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.child.managetokens.AddAndManageBottomSheetComponent
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioFetcher
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorController
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.slot
|
||||
|
|
@ -38,6 +44,9 @@ internal class AddAndManageModelTest {
|
|||
private val portfolioSelectorController: PortfolioSelectorController = mockk(relaxed = true) {
|
||||
every { selectedAccount } returns flowOf(null)
|
||||
}
|
||||
private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier = mockk(relaxed = true) {
|
||||
coEvery { getSyncOrNull(any<UserWalletId>()) } returns null
|
||||
}
|
||||
|
||||
private val onDismiss: () -> Unit = mockk(relaxed = true)
|
||||
private val onOrganizeTokensClick: () -> Unit = mockk(relaxed = true)
|
||||
|
|
@ -58,6 +67,7 @@ internal class AddAndManageModelTest {
|
|||
portfolioFetcherFactory = portfolioFetcherFactory,
|
||||
analyticsEventHandler = analyticsEventHandler,
|
||||
portfolioSelectorController = portfolioSelectorController,
|
||||
singleAccountStatusListSupplier = singleAccountStatusListSupplier,
|
||||
)
|
||||
|
||||
@Test
|
||||
|
|
@ -98,4 +108,38 @@ internal class AddAndManageModelTest {
|
|||
verify(exactly = 1) { onDismiss() }
|
||||
verify(exactly = 1) { onOrganizeTokensClick() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN wallet has multi currency account WHEN model is created THEN shouldShowOrganize is true`() = runTest {
|
||||
coEvery { singleAccountStatusListSupplier.getSyncOrNull(userWalletId) } returns
|
||||
accountStatusListWithCurrencyCounts(2)
|
||||
|
||||
val model = createModel()
|
||||
|
||||
assertThat(model.state.value.shouldShowOrganize).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN wallet has no multi currency account WHEN model is created THEN shouldShowOrganize is false`() = runTest {
|
||||
coEvery { singleAccountStatusListSupplier.getSyncOrNull(userWalletId) } returns
|
||||
accountStatusListWithCurrencyCounts(1)
|
||||
|
||||
val model = createModel()
|
||||
|
||||
assertThat(model.state.value.shouldShowOrganize).isFalse()
|
||||
}
|
||||
|
||||
private fun accountStatusListWithCurrencyCounts(vararg currencyCounts: Int): AccountStatusList {
|
||||
val statuses: List<AccountStatus> = currencyCounts.map { count ->
|
||||
val tokenList = mockk<TokenList> {
|
||||
every { flattenCurrencies() } returns List(count) { mockk<CryptoCurrencyStatus>() }
|
||||
}
|
||||
mockk<AccountStatus.CryptoPortfolio> {
|
||||
every { this@mockk.tokenList } returns tokenList
|
||||
}
|
||||
}
|
||||
return mockk {
|
||||
every { accountStatuses } returns statuses
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue