Updated on 2026-08-14
This commit is contained in:
commit
d6f9f59866
1729 changed files with 67614 additions and 9361 deletions
|
|
@ -145,7 +145,7 @@ dependencies {
|
|||
implementation(projects.features.walletSettings.api)
|
||||
implementation(projects.features.biometry.api)
|
||||
implementation(projects.features.nft.api)
|
||||
implementation(projects.features.sendV2.api)
|
||||
implementation(projects.features.send.api)
|
||||
implementation(projects.features.kyc.api)
|
||||
implementation(projects.features.tokenRecieve.api)
|
||||
implementation(projects.features.yieldSupply.api)
|
||||
|
|
@ -153,6 +153,7 @@ dependencies {
|
|||
implementation(projects.features.promoBanners.api)
|
||||
implementation(projects.features.tangempay.main.api)
|
||||
implementation(projects.features.tangempay.details.api)
|
||||
implementation(projects.features.virtualAccounts.main.api)
|
||||
|
||||
/** Common modules */
|
||||
implementation(projects.common)
|
||||
|
|
@ -160,7 +161,7 @@ dependencies {
|
|||
implementation(projects.common.ui)
|
||||
|
||||
/** Test libraries */
|
||||
testImplementation(deps.test.junit)
|
||||
testImplementation(deps.test.junit5)
|
||||
testImplementation(deps.test.coroutine)
|
||||
testImplementation(deps.test.truth)
|
||||
testImplementation(deps.test.mockk)
|
||||
|
|
|
|||
|
|
@ -4,11 +4,8 @@
|
|||
<CurrentIssues>
|
||||
<ID>BooleanPropertyNaming:DefaultUserWalletsFetcher.kt$DefaultUserWalletsFetcher$@Assisted("onlyMultiCurrency") private val onlyMultiCurrency: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:DraggableItem.kt$DraggableItem$abstract val showShadow: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:DraggableItem.kt$DraggableItem.RoundingMode$abstract val showGap: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:OrganizeTokensState.kt$OrganizeTokensState.ActionsConfig$val showApplyProgress: Boolean = false</ID>
|
||||
<ID>BooleanPropertyNaming:ScrollToWalletTransformer.kt$ScrollToWalletTransformer$private val withScrollAnimation: Boolean = true</ID>
|
||||
<ID>BooleanPropertyNaming:TangemPayState.kt$TangemPayState.Progress$val showProgress: Boolean = false</ID>
|
||||
<ID>BooleanPropertyNaming:TokenActionButtonConfig.kt$TokenActionButtonConfig$val enabled: Boolean = true</ID>
|
||||
<ID>BooleanPropertyNaming:UpdateMultiWalletActionButtonBadgeTransformer.kt$UpdateMultiWalletActionButtonBadgeTransformer$private val showSwapBadge: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:WalletAdditionalInfo.kt$WalletAdditionalInfo$val hideable: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:WalletCurrencyActionsClickIntents.kt$WalletCurrencyActionsClickIntentsImplementor$val showSwapStories = maybeSwapStories.getOrNull() != null</ID>
|
||||
|
|
@ -20,24 +17,15 @@
|
|||
<ID>BooleanPropertyNaming:WalletScreenState.kt$WalletScreenState$val showMarketsOnboarding: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:WalletWithFundsChecker.kt$WalletWithFundsChecker$val prevStatus = statusByWalletId.get(userWalletId)</ID>
|
||||
<ID>MaxChainedCallsOnSameLine:HasSingleWalletSignedHashesUseCase.kt$HasSingleWalletSignedHashesUseCase$userWallet.scanResponse.card.wallets.firstOrNull()?.totalSignedHashes</ID>
|
||||
<ID>MultilineLambdaItParameter:DefaultPromoDeeplinkHandler.kt$DefaultPromoDeeplinkHandler${ Timber.tag(LOG_TAG).e("Error on getting user wallet: $it") showAlert(Failed) }</ID>
|
||||
<ID>MultilineLambdaItParameter:DefaultUserWalletImageFetcher.kt$DefaultUserWalletImageFetcher${ it.fold( ifLeft = { emit(UserWalletItemUM.ImageState.Loading) }, ifRight = { wallet -> emitAll(walletImage(wallet, size)) }, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:OrganizeTokensModel.kt$OrganizeTokensModel${ isBalanceHidden = it.isBalanceHidden stateHolder.updateHiddenState(isBalanceHidden) }</ID>
|
||||
<ID>MultilineLambdaItParameter:SetRefreshStateTransformer.kt$SetRefreshStateTransformer${ it.mapNotNull { button -> when (button) { is WalletManageButton.Buy -> button.copy(enabled = isButtonsEnabled) is WalletManageButton.Send -> button.copy(enabled = isButtonsEnabled) is WalletManageButton.Sell -> button.copy(enabled = isButtonsEnabled) is WalletManageButton.Receive -> button is WalletManageButton.Stake -> null is WalletManageButton.Swap -> null } } }</ID>
|
||||
<ID>MultilineLambdaItParameter:TokenListAnalyticsSender.kt$TokenListAnalyticsSender${ val status = it.value if (status is CryptoCurrencyStatus.Loaded) { sendTokenBalancesForSpecificBlockchains(it, status) } }</ID>
|
||||
<ID>MultilineLambdaItParameter:TokenListStateConverter.kt$TokenListStateConverter${ if (isExtend) { clickIntents.onAccountCollapseClick(it) } else { clickIntents.onAccountExpandClick(it) } }</ID>
|
||||
<ID>MultilineLambdaItParameter:UseCaseExt.kt${ Timber.e("Impossible to get primary currency status $it") null }</ID>
|
||||
<ID>MultilineLambdaItParameter:UseCaseExt.kt${ Timber.e("Impossible to get selected wallet $it") null }</ID>
|
||||
<ID>MultilineLambdaItParameter:WalletCard.kt${ haptic.performHapticFeedback(HapticFeedbackType.LongPress) isMenuVisible = true pressOffset = DpOffset(x = it.x.toDp(), y = it.y.toDp()) }</ID>
|
||||
<ID>MultilineLambdaItParameter:WalletCard.kt${ val press = PressInteraction.Press(it) interactionSource.emit(press) tryAwaitRelease() interactionSource.emit(PressInteraction.Release(press)) }</ID>
|
||||
<ID>MultilineLambdaItParameter:WalletContentClickIntents.kt$WalletContentClickIntentsImplementor${ Timber.e( """ Unable to get user wallet |- ID: $userWalletId |- Exception: $it """.trimIndent(), ) return@launch }</ID>
|
||||
<ID>MultilineLambdaItParameter:WalletCurrencyActionsClickIntents.kt$WalletCurrencyActionsClickIntentsImplementor${ onAddressTypeSelected( userWalletId = userWalletId, currency = currency, addressModel = it, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:WalletNameMigrationUseCase.kt$WalletNameMigrationUseCase${ val defaultName = it.name val suggestedWalletName = suggestedWalletName(defaultName, existingNames) if (defaultName != suggestedWalletName) { userWalletsListRepository.saveWithoutLock(it.copy(name = suggestedWalletName), canOverride = true) } Timber.tag("Migrated names").e(it.walletId.toString() + " " + suggestedWalletName) }</ID>
|
||||
<ID>MultilineLambdaItParameter:WalletScreen.kt${ PaddingValues( bottom = it.calculateBottomPadding() + marketHintAproxHeight + 52.dp, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:WalletScreen.kt${ WalletSnackbarHost( snackbarHostState = it, event = state.event, modifier = Modifier .padding(bottom = TangemTheme.dimens.spacing4) .navigationBarsPadding(), ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:WalletScreen.kt${ it.organizeTokensButtonConfig?.let { config -> organizeTokensButton( modifier = itemModifier, isEnabled = config.isEnabled, onClick = config.onClick, ) } }</ID>
|
||||
<ID>MultilineLambdaItParameter:WalletScreen.kt${ nftCollections( modifier = itemModifier, state = it.nftState, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:WalletWarningsClickIntents.kt$WalletWarningsClickIntentsImplementor${ Timber.e( """ Unable to get user wallet |- ID: $userWalletId |- Exception: $it """.trimIndent(), ) null }</ID>
|
||||
<ID>MultilineLambdaItParameter:WalletWarningsClickIntents.kt$WalletWarningsClickIntentsImplementor${ router.openOnboardingScreen( scanResponse = it.scanResponse, continueBackup = true, ) }</ID>
|
||||
<ID>MultilineLambdaItParameter:WalletWithFundsChecker.kt$WalletWithFundsChecker${ val amount = it.value.amount ?: return@any false !amount.isZero() }</ID>
|
||||
<ID>NamedArguments:TangemSnapFlingBehavior.kt$HighVelocityApproachAnimation$animateDecay(offset, animationState, decayAnimationSpec, onAnimationStep)</ID>
|
||||
|
|
@ -46,19 +34,12 @@
|
|||
<ID>NamedArguments:TangemSnapFlingBehavior.kt$TangemSnapFlingBehavior$approach( initialTargetOffset, initialVelocity, animation, snapLayoutInfoProvider, density, onAnimationStep, )</ID>
|
||||
<ID>NamedArguments:TangemSnapFlingBehavior.kt$approachAnimation( this, initialTargetOffset, initialVelocity, onAnimationStep, )</ID>
|
||||
<ID>NamedArguments:WalletContent.kt$txHistoryItems(state.txHistoryState, txHistoryItems, isBalanceHidden, modifier)</ID>
|
||||
<ID>NestedScopeFunctions:WalletScreen.kt$let { config -> organizeTokensButton( modifier = itemModifier, isEnabled = config.isEnabled, onClick = config.onClick, ) }</ID>
|
||||
<ID>NestedScopeFunctions:WalletScreen.kt$let { it.organizeTokensButtonConfig?.let { config -> organizeTokensButton( modifier = itemModifier, isEnabled = config.isEnabled, onClick = config.onClick, ) } }</ID>
|
||||
<ID>NestedScopeFunctions:WalletScreen.kt$let { marketPriceBlockState -> marketPriceBlock(state = marketPriceBlockState, modifier = itemModifier) }</ID>
|
||||
<ID>NoNameShadowing:DefaultUserWalletsFetcher.kt$DefaultUserWalletsFetcher${ it.isMultiCurrency }</ID>
|
||||
<ID>NoNameShadowing:MultiCurrencyAccountContent.kt$modifier</ID>
|
||||
<ID>NoNameShadowing:WalletComponent.kt$WalletComponent$dialog</ID>
|
||||
<ID>NoNameShadowing:WalletCurrencyActionsClickIntents.kt$WalletCurrencyActionsClickIntentsImplementor${ it is TokensListItemUM.Token }</ID>
|
||||
<ID>NoNameShadowing:WalletNFTItem.kt$modifier</ID>
|
||||
<ID>NoNameShadowing:WalletScreen.kt${ it.organizeTokensButtonConfig?.let { config -> organizeTokensButton( modifier = itemModifier, isEnabled = config.isEnabled, onClick = config.onClick, ) } }</ID>
|
||||
<ID>PropertyUsedBeforeDeclaration:BaseWalletClickIntents.kt$BaseWalletClickIntents$_modelScope</ID>
|
||||
<ID>PropertyUsedBeforeDeclaration:BaseWalletClickIntents.kt$BaseWalletClickIntents$_router</ID>
|
||||
<ID>PropertyUsedBeforeDeclaration:OrganizeTokensModel.kt$OrganizeTokensModel$uiState</ID>
|
||||
<ID>PropertyUsedBeforeDeclaration:WalletScreenPreviewData.kt$WalletScreenPreviewData$buyButton</ID>
|
||||
<ID>PropertyUsedBeforeDeclaration:WalletStateController.kt$WalletStateController$mutableUiState</ID>
|
||||
<ID>ReusedModifierInstance:DefaultWalletEntryComponent.kt$DefaultWalletEntryComponent$Content(modifier)</ID>
|
||||
<ID>ReusedModifierInstance:WalletNFTItem.kt$Image( modifier = modifier .background(TangemTheme.colors.stroke.primary), painter = painterResource(R.drawable.ic_nft_preview_more_16), contentDescription = null, )</ID>
|
||||
|
|
@ -67,14 +48,10 @@
|
|||
<ID>SuspendFunSwallowedCancellation:WalletModel.kt$WalletModel$runCatching</ID>
|
||||
<ID>UnnecessaryLet:TangemSnapFlingBehavior.kt$TangemSnapFlingBehavior$let { abs(it) * sign(initialVelocity) // ensure offset sign is correct }</ID>
|
||||
<ID>UnnecessaryLet:WalletClickIntents.kt$WalletClickIntents$let(::add)</ID>
|
||||
<ID>UnnecessaryLet:WalletScreen.kt$let { (state.tokensListState as? WalletTokensListState.ContentState)?.let { it.organizeTokensButtonConfig?.let { config -> organizeTokensButton( modifier = itemModifier, isEnabled = config.isEnabled, onClick = config.onClick, ) } } }</ID>
|
||||
<ID>UnnecessaryLet:WalletScreen.kt$let { it.organizeTokensButtonConfig?.let { config -> organizeTokensButton( modifier = itemModifier, isEnabled = config.isEnabled, onClick = config.onClick, ) } }</ID>
|
||||
<ID>UseEmptyCounterpart:DefaultUserWalletImageFetcher.kt$DefaultUserWalletImageFetcher$mapOf<String, ArtworkUM>()</ID>
|
||||
<ID>UseEmptyCounterpart:ExpandedAccountsHolder.kt$ExpandedAccountsHolder$setOf()</ID>
|
||||
<ID>UseEmptyCounterpart:PortfolioOrganizeTokensAnalyticsEvent.kt$PortfolioOrganizeTokensAnalyticsEvent$mapOf()</ID>
|
||||
<ID>UseEmptyCounterpart:PromoActivationAnalytics.kt$PromoActivationAnalytics$mapOf()</ID>
|
||||
<ID>UseEmptyCounterpart:TokenListStateConverter.kt$TokenListStateConverter$listOf()</ID>
|
||||
<ID>UseEmptyCounterpart:WalletScreenAnalyticsEvent.kt$WalletScreenAnalyticsEvent.Basic$mapOf()</ID>
|
||||
<ID>UseEmptyCounterpart:WalletScreenAnalyticsEvent.kt$WalletScreenAnalyticsEvent.MainScreen$mapOf()</ID>
|
||||
<ID>UseEmptyCounterpart:WalletScreenAnalyticsEvent.kt$WalletScreenAnalyticsEvent.PushBannerPromo$mapOf()</ID>
|
||||
<ID>UseSumOfInsteadOfFlatMapSize:TokenListStateConverter.kt$TokenListStateConverter$flatMap(NetworkGroup::currencies)</ID>
|
||||
|
|
|
|||
|
|
@ -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,7 +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.portfolioselector.PortfolioSelectorComponent
|
||||
import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent
|
||||
import com.tangem.feature.wallet.child.tokenActions.DefaultTokenActionsComponent
|
||||
import com.tangem.feature.wallet.child.tokenActions.TokenActionsComponent
|
||||
import com.tangem.feature.wallet.child.wallet.model.WalletModel
|
||||
|
|
@ -36,14 +36,16 @@ import com.tangem.feature.wallet.presentation.wallet.ui.WalletScreen2
|
|||
import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.KycRejectedComponent
|
||||
import com.tangem.feature.walletsettings.component.RenameWalletComponent
|
||||
import com.tangem.features.biometry.AskBiometryComponent
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorComponent
|
||||
import com.tangem.features.feed.entry.components.FeedEntryComponent
|
||||
import com.tangem.features.promobanners.api.PromoBannersBlockComponent
|
||||
import com.tangem.features.pushnotifications.api.PushNotificationsBottomSheetComponent
|
||||
import com.tangem.features.pushnotifications.api.PushNotificationsParams
|
||||
import com.tangem.features.send.v2.api.NetworkSelectionComponent
|
||||
import com.tangem.features.send.api.NetworkSelectionComponent
|
||||
import com.tangem.features.tangempay.component.TangemPayMainBlockComponent
|
||||
import com.tangem.features.tangempay.components.TangemPayTransactionBottomSheetComponent
|
||||
import com.tangem.features.tokenreceive.TokenReceiveComponent
|
||||
import com.tangem.features.virtualaccount.main.component.VirtualAccountMainBlockComponent
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyDepositedWarningComponent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
|
|
@ -57,6 +59,7 @@ internal class WalletComponent @AssistedInject constructor(
|
|||
@Assisted navigate: (WalletRoute) -> Unit,
|
||||
feedEntryComponentFactory: FeedEntryComponent.Factory,
|
||||
tangemPayMainBlockComponentFactory: TangemPayMainBlockComponent.Factory,
|
||||
virtualAccountMainBlockComponentFactory: VirtualAccountMainBlockComponent.Factory,
|
||||
private val tangemPayTransactionBottomSheetComponentFactory: TangemPayTransactionBottomSheetComponent.Factory,
|
||||
private val renameWalletComponentFactory: RenameWalletComponent.Factory,
|
||||
private val askBiometryComponentFactory: AskBiometryComponent.Factory,
|
||||
|
|
@ -67,6 +70,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 {
|
||||
|
||||
|
|
@ -84,6 +88,12 @@ internal class WalletComponent @AssistedInject constructor(
|
|||
params = Unit,
|
||||
)
|
||||
}
|
||||
private val virtualAccountMainBlockComponent by lazy {
|
||||
virtualAccountMainBlockComponentFactory.create(
|
||||
context = child("virtualAccountMainBlockComponent"),
|
||||
params = Unit,
|
||||
)
|
||||
}
|
||||
|
||||
private val promoBannersBlockComponent: PromoBannersBlockComponent by lazy {
|
||||
promoBannersBlockComponentFactory.create(
|
||||
|
|
@ -180,6 +190,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),
|
||||
|
|
@ -270,7 +289,9 @@ internal class WalletComponent @AssistedInject constructor(
|
|||
if (designFeatureToggles.isRedesignEnabled) {
|
||||
WalletScreen2(
|
||||
state = uiState,
|
||||
promoBannersBlockComponent = promoBannersBlockComponent,
|
||||
tangemPayComponent = tangemPayMainBlockComponent,
|
||||
virtualAccountComponent = virtualAccountMainBlockComponent,
|
||||
bottomSheetContent = { onExpandSheet ->
|
||||
BottomSheetContent(
|
||||
bottomSheetState = bottomSheetState,
|
||||
|
|
@ -287,6 +308,7 @@ internal class WalletComponent @AssistedInject constructor(
|
|||
state = uiState,
|
||||
promoBannersBlockComponent = promoBannersBlockComponent,
|
||||
tangemPayComponent = tangemPayMainBlockComponent,
|
||||
virtualAccountComponent = virtualAccountMainBlockComponent,
|
||||
bottomSheetContent = { onExpandSheet ->
|
||||
BottomSheetContent(
|
||||
bottomSheetState = bottomSheetState,
|
||||
|
|
|
|||
|
|
@ -41,9 +41,9 @@ import com.tangem.domain.models.wallet.UserWallet
|
|||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.offramp.GetOfframpUrlUseCase
|
||||
import com.tangem.domain.onramp.model.OnrampSource
|
||||
import com.tangem.domain.staking.model.StakingOption
|
||||
import com.tangem.domain.stories.GetStoryContentUseCase
|
||||
import com.tangem.domain.stories.models.StoryContentIds
|
||||
import com.tangem.domain.staking.model.StakingOption
|
||||
import com.tangem.domain.tokens.NeedShowYieldSupplyDepositedWarningUseCase
|
||||
import com.tangem.domain.tokens.SaveViewedTokenReceiveWarningUseCase
|
||||
import com.tangem.domain.tokens.SaveViewedYieldSupplyWarningUseCase
|
||||
|
|
@ -61,12 +61,7 @@ import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
|||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.unwrap
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAlertUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletEvent
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.CloseBottomSheetTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -316,9 +311,10 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
|
||||
if (handleUnavailabilityReason(unavailabilityReason)) return
|
||||
|
||||
showErrorIfDemoModeOrElse {
|
||||
showErrorIfDemoModeOrElse { userWallet ->
|
||||
modelScope.launch(dispatchers.main) {
|
||||
getOfframpUrlUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
appCurrencyCode = getSelectedAppCurrencyUseCase.unwrap().code,
|
||||
).onRight { url ->
|
||||
|
|
@ -480,8 +476,8 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun openExplorer() {
|
||||
val userWalletId = stateHolder.getSelectedWalletId()
|
||||
private fun openExplorer(userWallet: UserWallet) {
|
||||
val userWalletId = userWallet.walletId
|
||||
|
||||
modelScope.launch(dispatchers.main) {
|
||||
val currencyStatus = singleAccountStatusListSupplier.unwrap(userWalletId) ?: return@launch
|
||||
|
|
@ -545,7 +541,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun showErrorIfDemoModeOrElse(action: () -> Unit) {
|
||||
private fun showErrorIfDemoModeOrElse(action: (UserWallet) -> Unit) {
|
||||
val selectedWallet = getSelectedWalletSyncUseCase.unwrap() ?: return
|
||||
|
||||
if (selectedWallet is UserWallet.Cold && isDemoCardUseCase(cardId = selectedWallet.cardId)) {
|
||||
|
|
@ -557,7 +553,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
),
|
||||
)
|
||||
} else {
|
||||
action()
|
||||
action(selectedWallet)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import com.tangem.feature.wallet.presentation.preview.WalletBalancePreview
|
|||
import com.tangem.feature.wallet.presentation.preview.WalletPreviewData
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.*
|
||||
import com.tangem.features.tangempay.entity.TangemPayMainUM
|
||||
import com.tangem.features.virtualaccount.main.entity.VirtualAccountMainUM
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
internal object WalletScreenPreviewData {
|
||||
|
|
@ -179,6 +180,7 @@ internal object WalletScreenPreviewData {
|
|||
onItemClick = {},
|
||||
),
|
||||
tangemPayMainUM = TangemPayMainUM.Loading,
|
||||
virtualAccountMainUM = VirtualAccountMainUM.Loading,
|
||||
)
|
||||
|
||||
private val walletEmpty = WalletUM.Content(
|
||||
|
|
@ -194,6 +196,7 @@ internal object WalletScreenPreviewData {
|
|||
tokensListUM = WalletTokensListUM.Empty(onEmptyClick = {}),
|
||||
nftState = WalletNFTItemUM.Hidden,
|
||||
tangemPayMainUM = TangemPayMainUM.Empty,
|
||||
virtualAccountMainUM = VirtualAccountMainUM.Empty,
|
||||
)
|
||||
|
||||
private val walletAccountDefault = walletDefault.copy(
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import com.tangem.core.analytics.models.AnalyticsParam
|
|||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.domain.tangempay.TangemPayAnalyticsEvents
|
||||
import com.tangem.feature.wallet.child.wallet.model.WalletActivationBannerType
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.MainScreen
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.MainScreen.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.PushBannerPromo.PushBanner
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.*
|
||||
|
|
@ -81,9 +80,9 @@ internal class WalletWarningsAnalyticsSender @Inject constructor(
|
|||
-> null
|
||||
is WalletNotification.FinishWalletActivation -> {
|
||||
val activationState = if (warning.isBackupExists) {
|
||||
MainScreen.NoticeFinishActivation.ActivationState.Unfinished
|
||||
NoticeFinishActivation.ActivationState.Unfinished
|
||||
} else {
|
||||
MainScreen.NoticeFinishActivation.ActivationState.NotStarted
|
||||
NoticeFinishActivation.ActivationState.NotStarted
|
||||
}
|
||||
val balanceState = when (warning.type) {
|
||||
WalletActivationBannerType.Attention -> AnalyticsParam.EmptyFull.Empty
|
||||
|
|
@ -135,6 +134,7 @@ internal class WalletWarningsAnalyticsSender @Inject constructor(
|
|||
}
|
||||
is WalletNotificationUM.PushNotifications -> PushBanner()
|
||||
is WalletNotificationUM.AddFunds -> NoticeAddFunds()
|
||||
is WalletNotificationUM.TangemPayPromo -> TangemPayAnalyticsEvents.PermanentBannerShowed()
|
||||
is WalletNotificationUM.UnlockWallets,
|
||||
is WalletNotificationUM.NoAccount,
|
||||
is WalletNotificationUM.LowSignatures,
|
||||
|
|
@ -143,6 +143,7 @@ internal class WalletWarningsAnalyticsSender @Inject constructor(
|
|||
is WalletNotificationUM.CloreMigration,
|
||||
is WalletNotificationUM.TangemPayRefreshNeeded,
|
||||
WalletNotificationUM.TangemPayUnreachable,
|
||||
is WalletNotificationUM.YieldBoostPromo,
|
||||
-> null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,11 @@ import com.tangem.domain.models.wallet.UserWallet
|
|||
import com.tangem.domain.notifications.repository.NotificationsRepository
|
||||
import com.tangem.domain.settings.IsReadyToShowRateAppUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.domain.yield.supply.promo.usecase.ShouldShowYieldBoostMainBannerUseCase
|
||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetShouldShowMainPromoUseCase
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotificationUM
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyFeatureToggles
|
||||
import com.tangem.utils.extensions.addIf
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
|
@ -28,6 +31,9 @@ internal class GetWalletNotificationsCarouselFactory @Inject constructor(
|
|||
private val isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase,
|
||||
private val getWalletsUseCase: GetWalletsUseCase,
|
||||
private val notificationsRepository: NotificationsRepository,
|
||||
private val shouldShowYieldBoostMainBannerUseCase: ShouldShowYieldBoostMainBannerUseCase,
|
||||
private val yieldSupplyGetShouldShowMainPromoUseCase: YieldSupplyGetShouldShowMainPromoUseCase,
|
||||
private val yieldSupplyFeatureToggles: YieldSupplyFeatureToggles,
|
||||
) {
|
||||
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents): Flow<ImmutableList<WalletNotificationUM>> {
|
||||
return combine(
|
||||
|
|
@ -36,7 +42,8 @@ internal class GetWalletNotificationsCarouselFactory @Inject constructor(
|
|||
).distinctUntilChanged(),
|
||||
flow2 = isReadyToShowRateAppUseCase().distinctUntilChanged(),
|
||||
flow3 = getWalletsUseCase().conflate(),
|
||||
) { showPushesNotification, showRateAppPromo, wallets ->
|
||||
flow4 = yieldSupplyGetShouldShowMainPromoUseCase().distinctUntilChanged(),
|
||||
) { showPushesNotification, showRateAppPromo, wallets, shouldShowYieldPromoLocal ->
|
||||
|
||||
buildList {
|
||||
addNoteMigrationNotification(userWallet, wallets, clickIntents)
|
||||
|
|
@ -47,10 +54,33 @@ internal class GetWalletNotificationsCarouselFactory @Inject constructor(
|
|||
isPushesAllowed = notificationsRepository.isUserAllowToSubscribeOnPushNotifications(),
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
|
||||
addYieldBoostBannerNotification(
|
||||
userWallet = userWallet,
|
||||
shouldShowLocal = shouldShowYieldPromoLocal,
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
}.sortedBy { it.type.ordinal }.toImmutableList()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun MutableList<WalletNotificationUM>.addYieldBoostBannerNotification(
|
||||
userWallet: UserWallet,
|
||||
shouldShowLocal: Boolean,
|
||||
clickIntents: WalletClickIntents,
|
||||
) {
|
||||
if (!shouldShowLocal) return
|
||||
if (!yieldSupplyFeatureToggles.isYieldPromoEnabled) return
|
||||
val shouldShow = shouldShowYieldBoostMainBannerUseCase(userWallet.walletId).getOrNull() == true
|
||||
if (!shouldShow) return
|
||||
add(
|
||||
WalletNotificationUM.YieldBoostPromo(
|
||||
onExploreClick = { clickIntents.onYieldBoostBannerClick(userWallet.walletId) },
|
||||
onLaterClick = { clickIntents.onDismissYieldBoostBanner(userWallet.walletId) },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotificationUM>.addRateAppNotification(
|
||||
isReadyToShowRating: Boolean,
|
||||
clickIntents: WalletClickIntents,
|
||||
|
|
|
|||
|
|
@ -255,7 +255,10 @@ internal class GetWalletNotificationsFactory @Inject constructor(
|
|||
onRefreshClick = { walletClickIntents.onRefreshPayToken(userWallet) },
|
||||
shouldShowProgress = false,
|
||||
)
|
||||
is PaymentAccountStatusValue.NotCreated -> null // TODO(Main redesign) and analytics PermanentBannerShowed
|
||||
is PaymentAccountStatusValue.NotCreated -> WalletNotificationUM.TangemPayPromo(
|
||||
onLaterClick = { walletClickIntents.onOnboardingBannerCloseClick(userWallet.walletId) },
|
||||
onLearnMoreClick = { walletClickIntents.onOnboardingBannerClick(userWallet.walletId) },
|
||||
)
|
||||
is PaymentAccountStatusValue.Error.Unavailable -> WalletNotificationUM.TangemPayUnreachable
|
||||
is PaymentAccountStatusValue.Error.CardIssueFailed,
|
||||
is PaymentAccountStatusValue.Error.ExposedDevice,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,12 @@ import com.tangem.core.ui.ds.image.TangemIconUM
|
|||
import com.tangem.core.ui.ds.message.TangemMessageButtonUM
|
||||
import com.tangem.core.ui.ds.message.TangemMessageEffect
|
||||
import com.tangem.core.ui.ds.message.TangemMessageUM
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.combinedReference
|
||||
import com.tangem.core.ui.extensions.pluralReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
|
@ -52,8 +57,8 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t
|
|||
data object UsedOutdatedData : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "UsedOutdatedDataNotification",
|
||||
title = resourceReference(com.tangem.core.res.R.string.warning_outdated_data_title),
|
||||
subtitle = resourceReference(com.tangem.core.res.R.string.warning_outdated_data_message),
|
||||
title = resourceReference(R.string.warning_outdated_data_title),
|
||||
subtitle = resourceReference(R.string.warning_outdated_data_message),
|
||||
iconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_error_sync_default_24,
|
||||
tintReference = { TangemTheme.colors2.graphic.status.attention },
|
||||
|
|
@ -383,6 +388,62 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t
|
|||
type = WalletNotificationType.Promo,
|
||||
)
|
||||
|
||||
data class TangemPayPromo(
|
||||
private val onLaterClick: () -> Unit,
|
||||
private val onLearnMoreClick: () -> Unit,
|
||||
) : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "TangemPayPromo",
|
||||
iconUM = TangemIconUM.Image(imageRes = R.drawable.ic_visa_in_banner),
|
||||
title = resourceReference(id = R.string.tangempay_onboarding_banner_title),
|
||||
subtitle = resourceReference(id = R.string.tangempay_get_banner_description),
|
||||
buttonsUM = persistentListOf(
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(id = R.string.common_later),
|
||||
onClick = onLaterClick,
|
||||
type = TangemButtonType.Secondary,
|
||||
),
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(id = R.string.common_learn_more),
|
||||
onClick = onLearnMoreClick,
|
||||
type = TangemButtonType.Primary,
|
||||
),
|
||||
),
|
||||
messageEffect = TangemMessageEffect.None,
|
||||
),
|
||||
type = WalletNotificationType.Promo,
|
||||
)
|
||||
|
||||
data class YieldBoostPromo(
|
||||
val onExploreClick: () -> Unit,
|
||||
val onLaterClick: () -> Unit,
|
||||
) : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "YieldBoostPromoNotification",
|
||||
title = combinedReference(
|
||||
resourceReference(CoreResR.string.yield_apy_boost_banner_title),
|
||||
stringReference(" · "),
|
||||
resourceReference(CoreResR.string.yield_apy_boost_banner_title_apy_multiplied),
|
||||
),
|
||||
subtitle = resourceReference(CoreResR.string.yield_apy_boost_banner_subtitle),
|
||||
iconUM = TangemIconUM.Image(imageRes = CoreUiR.drawable.ic_yield_32),
|
||||
messageEffect = TangemMessageEffect.Magic,
|
||||
buttonsUM = persistentListOf(
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(CoreResR.string.common_later),
|
||||
type = TangemButtonType.Secondary,
|
||||
onClick = onLaterClick,
|
||||
),
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(CoreResR.string.yield_apy_boost_banner_button_title),
|
||||
type = TangemButtonType.Primary,
|
||||
onClick = onExploreClick,
|
||||
),
|
||||
),
|
||||
),
|
||||
type = WalletNotificationType.Promo,
|
||||
)
|
||||
|
||||
// endregion
|
||||
|
||||
// region Survey
|
||||
|
|
@ -448,8 +509,8 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t
|
|||
) : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "CloreMigrationNotification",
|
||||
title = resourceReference(com.tangem.core.res.R.string.warning_clore_migration_title),
|
||||
subtitle = resourceReference(com.tangem.core.res.R.string.warning_clore_migration_description),
|
||||
title = resourceReference(R.string.warning_clore_migration_title),
|
||||
subtitle = resourceReference(R.string.warning_clore_migration_description),
|
||||
iconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_attention_default_24,
|
||||
tintReference = { TangemTheme.colors2.graphic.status.attention },
|
||||
|
|
@ -457,7 +518,7 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t
|
|||
messageEffect = TangemMessageEffect.None,
|
||||
buttonsUM = persistentListOf(
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(com.tangem.core.res.R.string.warning_clore_migration_button),
|
||||
text = resourceReference(R.string.warning_clore_migration_button),
|
||||
onClick = onStartMigrationClick,
|
||||
type = TangemButtonType.Secondary,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.model.holder.LockedWa
|
|||
import com.tangem.feature.wallet.presentation.wallet.state.model.holder.TxHistoryStateHolder
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.holder.WalletStateHolder
|
||||
import com.tangem.features.tangempay.entity.TangemPayMainUM
|
||||
import com.tangem.features.virtualaccount.main.entity.VirtualAccountMainUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
|
||||
|
|
@ -25,6 +26,7 @@ internal sealed interface WalletState : WalletStateHolder {
|
|||
abstract val nftState: WalletNFTItemUM
|
||||
abstract val type: WalletType
|
||||
abstract val tangemPayMainUM: TangemPayMainUM
|
||||
abstract val virtualAccountMainUM: VirtualAccountMainUM
|
||||
abstract val assetsDiscoveryProgressUM: AssetsDiscoveryProgressUM
|
||||
|
||||
data class Content(
|
||||
|
|
@ -37,6 +39,7 @@ internal sealed interface WalletState : WalletStateHolder {
|
|||
override val nftState: WalletNFTItemUM,
|
||||
override val type: WalletType,
|
||||
override val tangemPayMainUM: TangemPayMainUM,
|
||||
override val virtualAccountMainUM: VirtualAccountMainUM = VirtualAccountMainUM.Empty,
|
||||
override val assetsDiscoveryProgressUM: AssetsDiscoveryProgressUM = AssetsDiscoveryProgressUM.Idle,
|
||||
) : MultiCurrency()
|
||||
|
||||
|
|
@ -57,6 +60,7 @@ internal sealed interface WalletState : WalletStateHolder {
|
|||
override val tokensListState = WalletTokensListState.ContentState.Locked
|
||||
override val nftState: WalletNFTItemUM = WalletNFTItemUM.Hidden
|
||||
override val tangemPayMainUM: TangemPayMainUM = TangemPayMainUM.Empty
|
||||
override val virtualAccountMainUM: VirtualAccountMainUM = VirtualAccountMainUM.Empty
|
||||
override val assetsDiscoveryProgressUM: AssetsDiscoveryProgressUM = AssetsDiscoveryProgressUM.Idle
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import androidx.compose.runtime.Immutable
|
|||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.core.ui.ds.button.TangemButtonUM
|
||||
import com.tangem.features.tangempay.entity.TangemPayMainUM
|
||||
import com.tangem.features.virtualaccount.main.entity.VirtualAccountMainUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
|
@ -26,6 +27,8 @@ internal sealed interface WalletUM {
|
|||
|
||||
val tangemPayMainUM: TangemPayMainUM
|
||||
|
||||
val virtualAccountMainUM: VirtualAccountMainUM
|
||||
|
||||
data class Content(
|
||||
override val pullToRefreshConfig: PullToRefreshConfig,
|
||||
override val walletsBalanceUM: WalletBalanceUM,
|
||||
|
|
@ -36,6 +39,7 @@ internal sealed interface WalletUM {
|
|||
override val nftState: WalletNFTItemUM,
|
||||
override val type: WalletType,
|
||||
override val tangemPayMainUM: TangemPayMainUM,
|
||||
override val virtualAccountMainUM: VirtualAccountMainUM,
|
||||
) : WalletUM
|
||||
|
||||
data class Locked(
|
||||
|
|
@ -49,5 +53,6 @@ internal sealed interface WalletUM {
|
|||
override val tokensListUM: WalletTokensListUM = WalletTokensListUM.Locked
|
||||
override val nftState: WalletNFTItemUM = WalletNFTItemUM.Hidden
|
||||
override val tangemPayMainUM: TangemPayMainUM = TangemPayMainUM.Empty
|
||||
override val virtualAccountMainUM: VirtualAccountMainUM = VirtualAccountMainUM.Empty
|
||||
}
|
||||
}
|
||||
|
|
@ -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,8 +9,10 @@ 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.features.virtualaccount.main.entity.VirtualAccountMainUM
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
|
@ -35,6 +37,12 @@ internal class SetTokenListTransformer(
|
|||
)
|
||||
}
|
||||
|
||||
private val virtualAccountConverter by lazy {
|
||||
VirtualAccountMainBlockConverter(
|
||||
isRedesignEnabled = isRedesignEnabled,
|
||||
)
|
||||
}
|
||||
|
||||
override fun transform(prevState: WalletState): WalletState {
|
||||
return when (prevState) {
|
||||
is WalletState.MultiCurrency.Content -> {
|
||||
|
|
@ -42,6 +50,7 @@ internal class SetTokenListTransformer(
|
|||
walletCardState = prevState.walletCardState.toLoadedState(),
|
||||
tokensListState = prevState.tokensListState.toLoadedState(),
|
||||
tangemPayMainUM = prevState.tangemPayMainUM.toLoadedState(),
|
||||
virtualAccountMainUM = prevState.virtualAccountMainUM.toLoadedVirtualState(),
|
||||
buttons = prevState.enableButtons(),
|
||||
)
|
||||
}
|
||||
|
|
@ -60,11 +69,17 @@ 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(),
|
||||
virtualAccountMainUM = walletUM.virtualAccountMainUM.toLoadedVirtualState(),
|
||||
tokensListUM = tokensListUM,
|
||||
buttons = if (tokensListUM is WalletTokensListUM.Empty) {
|
||||
walletUM.disableButtons()
|
||||
} else {
|
||||
walletUM.enableButtons()
|
||||
},
|
||||
)
|
||||
}
|
||||
is WalletUM.Locked -> {
|
||||
|
|
@ -121,6 +136,17 @@ internal class SetTokenListTransformer(
|
|||
return tangemPayConverter.convert(paymentAccountStatus)
|
||||
}
|
||||
|
||||
private fun VirtualAccountMainUM.toLoadedVirtualState(): VirtualAccountMainUM {
|
||||
val virtualAccountStatus = when (params) {
|
||||
is TokenConverterParams.Account -> params.accountList.accountStatuses
|
||||
.filterIsInstance<AccountStatus.Virtual>()
|
||||
.firstOrNull()
|
||||
is TokenConverterParams.Wallet -> return VirtualAccountMainUM.Empty
|
||||
} ?: return this
|
||||
|
||||
return virtualAccountConverter.convert(virtualAccountStatus)
|
||||
}
|
||||
|
||||
private fun toLoadedState(): WalletTokensListUM {
|
||||
if (params !is TokenConverterParams.Account) {
|
||||
return WalletTokensListUM.Empty(
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ internal class SingleWalletOnrampTransactionConverter(
|
|||
timestampAgoFormatted = mapFormattedDate(value.timestamp),
|
||||
activeStatus = value.status.toActiveStatusText(currency.name),
|
||||
toAmount = stringReference(value.toAmount.format { crypto(currency) }),
|
||||
toAmountValue = value.toAmount,
|
||||
toFiatAmount = stringReference(
|
||||
status.fiatRate?.multiply(value.toAmount).format {
|
||||
fiat(
|
||||
|
|
@ -73,6 +74,7 @@ internal class SingleWalletOnrampTransactionConverter(
|
|||
),
|
||||
toAmountSymbol = currency.symbol,
|
||||
toCurrencyIcon = iconStateConverter.convert(currency),
|
||||
toAddress = status.networkAddress?.defaultAddress?.value.orEmpty(),
|
||||
fromAmount = stringReference(
|
||||
value.fromAmount.format {
|
||||
fiat(
|
||||
|
|
@ -81,12 +83,14 @@ internal class SingleWalletOnrampTransactionConverter(
|
|||
)
|
||||
},
|
||||
),
|
||||
fromAmountValue = value.fromAmount,
|
||||
fromFiatAmount = null,
|
||||
fromAmountSymbol = value.fromCurrency.code,
|
||||
fromCurrencyIcon = CurrencyIconState.FiatIcon(
|
||||
url = value.fromCurrency.image,
|
||||
fallbackResId = R.drawable.ic_currency_24,
|
||||
),
|
||||
fromAddress = null,
|
||||
iconState = value.status.toIconState(),
|
||||
onGoToProviderClick = { url ->
|
||||
analyticsEventHandler.send(TokenOnrampAnalyticsEvent.GoToProvider())
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -57,8 +58,8 @@ internal class TangemPayMainBlockConverter(
|
|||
subtitle = TextReference.Res(R.string.tangempay_status_deactivated),
|
||||
isBalanceFlickering = statusValue.source == StatusSource.CACHE,
|
||||
balance = getBalanceText(
|
||||
currencyCode = statusValue.fiatBalance.currency,
|
||||
balance = statusValue.fiatBalance.availableBalance,
|
||||
currencyCode = statusValue.balance.fiatBalance.currency,
|
||||
balance = statusValue.balance.fiatBalance.availableBalance,
|
||||
),
|
||||
balanceSubtitle = stringReference(statusValue.cryptoCurrency.symbol),
|
||||
shouldShowOnlyCacheWarning = statusValue.source == StatusSource.ONLY_CACHE,
|
||||
|
|
@ -67,15 +68,15 @@ 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}")
|
||||
},
|
||||
isBalanceFlickering = statusValue.source == StatusSource.CACHE,
|
||||
balance = getBalanceText(
|
||||
currencyCode = statusValue.currencyCode,
|
||||
balance = statusValue.fiatBalance.availableBalance,
|
||||
currencyCode = statusValue.balance.fiatBalance.currency,
|
||||
balance = statusValue.balance.fiatBalance.availableBalance,
|
||||
),
|
||||
balanceSubtitle = stringReference(statusValue.cryptoCurrency.symbol),
|
||||
shouldShowOnlyCacheWarning = statusValue.source == StatusSource.ONLY_CACHE,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers.converter
|
||||
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.format.bigdecimal.formatStyled
|
||||
import com.tangem.core.ui.format.bigdecimal.getJavaCurrencyByCode
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.account.AccountStatus
|
||||
import com.tangem.domain.models.account.VirtualAccountStatusValue
|
||||
import com.tangem.domain.models.kyc.KycStatus
|
||||
import com.tangem.features.virtualaccount.main.entity.VirtualAccountMainUM
|
||||
import com.tangem.utils.converter.Converter
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class VirtualAccountMainBlockConverter(
|
||||
private val isRedesignEnabled: Boolean,
|
||||
) : Converter<AccountStatus.Virtual, VirtualAccountMainUM> {
|
||||
|
||||
override fun convert(value: AccountStatus.Virtual): VirtualAccountMainUM {
|
||||
return when (val statusValue = value.value) {
|
||||
is VirtualAccountStatusValue.Empty -> VirtualAccountMainUM.Empty
|
||||
is VirtualAccountStatusValue.NotCreated -> VirtualAccountMainUM.Empty
|
||||
is VirtualAccountStatusValue.Loading -> VirtualAccountMainUM.Loading
|
||||
is VirtualAccountStatusValue.UnderReview -> VirtualAccountMainUM.UnderReview(
|
||||
subtitle = when (statusValue.kycStatus) {
|
||||
KycStatus.REJECTED -> TextReference.Res(R.string.tangempay_kyc_has_failed)
|
||||
else -> TextReference.Res(R.string.tangempay_kyc_in_progress)
|
||||
},
|
||||
onClick = {
|
||||
// TODO([REDACTED_TASK_KEY]): navigate to VA screen
|
||||
},
|
||||
)
|
||||
is VirtualAccountStatusValue.Provisioning -> VirtualAccountMainUM.Provisioning(
|
||||
onClick = {
|
||||
// TODO([REDACTED_TASK_KEY]): navigate to VA screen
|
||||
},
|
||||
)
|
||||
is VirtualAccountStatusValue.CountryNotSupported -> VirtualAccountMainUM.CountryNotSupported(
|
||||
onClick = {
|
||||
// TODO([REDACTED_TASK_KEY]): navigate to VA screen
|
||||
},
|
||||
)
|
||||
is VirtualAccountStatusValue.Active -> VirtualAccountMainUM.Content(
|
||||
subtitle = stringReference(statusValue.cryptoCurrency.symbol),
|
||||
isBalanceFlickering = statusValue.source == StatusSource.CACHE,
|
||||
balance = getBalanceText(
|
||||
currencyCode = statusValue.fiatBalance.currency,
|
||||
balance = statusValue.fiatBalance.availableBalance,
|
||||
),
|
||||
balanceSubtitle = stringReference(statusValue.cryptoCurrency.symbol),
|
||||
shouldShowOnlyCacheWarning = statusValue.source == StatusSource.ONLY_CACHE,
|
||||
onClick = {
|
||||
// TODO([REDACTED_TASK_KEY]): navigate to VA screen
|
||||
},
|
||||
)
|
||||
is VirtualAccountStatusValue.Error.Unavailable -> VirtualAccountMainUM.TemporaryUnavailable
|
||||
is VirtualAccountStatusValue.Error.NotSynced -> VirtualAccountMainUM.SyncNeeded
|
||||
is VirtualAccountStatusValue.Error.ExposedDevice -> VirtualAccountMainUM.ExposedDevice
|
||||
}
|
||||
}
|
||||
|
||||
private fun getBalanceText(currencyCode: String, balance: BigDecimal): TextReference {
|
||||
val currency = getJavaCurrencyByCode(currencyCode)
|
||||
val formattedBalance = if (isRedesignEnabled) {
|
||||
balance.formatStyled {
|
||||
fiat(
|
||||
fiatCurrencyCode = currency.currencyCode,
|
||||
fiatCurrencySymbol = currency.symbol,
|
||||
spanStyleReference = { SpanStyle(color = TangemTheme.colors2.text.neutral.secondary) },
|
||||
)
|
||||
}
|
||||
} else {
|
||||
stringReference(
|
||||
balance.format {
|
||||
fiat(fiatCurrencyCode = currency.currencyCode, fiatCurrencySymbol = currency.symbol)
|
||||
},
|
||||
)
|
||||
}
|
||||
return formattedBalance
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfo
|
|||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.*
|
||||
import com.tangem.features.tangempay.entity.TangemPayMainUM
|
||||
import com.tangem.features.virtualaccount.main.entity.VirtualAccountMainUM
|
||||
import com.tangem.utils.extensions.addIf
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
|
|
@ -70,6 +71,7 @@ internal class WalletLoadingStateFactory(
|
|||
is UserWallet.Hot -> WalletType.Hot
|
||||
},
|
||||
tangemPayMainUM = TangemPayMainUM.Empty,
|
||||
virtualAccountMainUM = VirtualAccountMainUM.Empty,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -185,6 +187,8 @@ internal class WalletLoadingStateFactory(
|
|||
}
|
||||
|
||||
private fun createWalletActions(userWallet: UserWallet): PersistentList<TangemButtonUM> {
|
||||
val isSingleWalletWithToken =
|
||||
userWallet is UserWallet.Cold && userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()
|
||||
return buildList {
|
||||
add(
|
||||
WalletActionButtons.AddFunds(
|
||||
|
|
@ -193,7 +197,7 @@ internal class WalletLoadingStateFactory(
|
|||
).buttonUM,
|
||||
)
|
||||
addIf(
|
||||
condition = !userWallet.isSingleWallet(),
|
||||
condition = !userWallet.isSingleWallet() && !isSingleWalletWithToken,
|
||||
element = WalletActionButtons.Swap(
|
||||
isEnabled = false,
|
||||
onClick = {
|
||||
|
|
|
|||
|
|
@ -85,15 +85,19 @@ import com.tangem.feature.wallet.presentation.wallet.ui.components.singlecurrenc
|
|||
import com.tangem.feature.wallet.presentation.wallet.ui.utils.changeWalletAnimator
|
||||
import com.tangem.features.tangempay.component.TangemPayMainBlockComponent
|
||||
import com.tangem.features.tangempay.entity.TangemPayMainUM
|
||||
import com.tangem.features.virtualaccount.main.component.VirtualAccountMainBlockComponent
|
||||
import com.tangem.features.virtualaccount.main.entity.VirtualAccountMainUM
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
internal fun WalletScreen(
|
||||
state: WalletScreenState,
|
||||
tangemPayComponent: TangemPayMainBlockComponent,
|
||||
virtualAccountComponent: VirtualAccountMainBlockComponent,
|
||||
promoBannersBlockComponent: ComposableContentComponent? = null,
|
||||
bottomSheetContent: @Composable (onExpandSheet: () -> Unit) -> Unit,
|
||||
bottomSheetHeaderHeightProvider: () -> Dp,
|
||||
|
|
@ -109,6 +113,7 @@ internal fun WalletScreen(
|
|||
WalletContent(
|
||||
state = state,
|
||||
tangemPayComponent = tangemPayComponent,
|
||||
virtualAccountComponent = virtualAccountComponent,
|
||||
walletsListState = walletsListState,
|
||||
snackbarHostState = snackbarHostState,
|
||||
isAutoScroll = isAutoScroll,
|
||||
|
|
@ -132,6 +137,7 @@ internal fun WalletScreen(
|
|||
private fun WalletContent(
|
||||
state: WalletScreenState,
|
||||
tangemPayComponent: TangemPayMainBlockComponent,
|
||||
virtualAccountComponent: VirtualAccountMainBlockComponent,
|
||||
walletsListState: LazyListState,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
isAutoScroll: State<Boolean>,
|
||||
|
|
@ -231,6 +237,13 @@ private fun WalletContent(
|
|||
tangemPayComponent = tangemPayComponent,
|
||||
)
|
||||
|
||||
virtualAccountItem(
|
||||
modifier = itemModifier,
|
||||
state = selectedWallet,
|
||||
isHidingMode = state.isHidingMode,
|
||||
virtualAccountComponent = virtualAccountComponent,
|
||||
)
|
||||
|
||||
(selectedWallet as? WalletState.SingleCurrency)?.let { walletState ->
|
||||
walletState.marketPriceBlockState?.let { marketPriceBlockState ->
|
||||
marketPriceBlock(state = marketPriceBlockState, modifier = itemModifier)
|
||||
|
|
@ -758,6 +771,23 @@ internal fun LazyListScope.tangemPayItem(
|
|||
}
|
||||
}
|
||||
|
||||
internal fun LazyListScope.virtualAccountItem(
|
||||
state: WalletState,
|
||||
isHidingMode: Boolean,
|
||||
virtualAccountComponent: VirtualAccountMainBlockComponent,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (state !is WalletState.MultiCurrency) return
|
||||
|
||||
with(virtualAccountComponent) {
|
||||
virtualAccountMainContent(
|
||||
modifier = modifier,
|
||||
state = state.virtualAccountMainUM,
|
||||
isBalanceHidden = isHidingMode,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ShowBottomSheet(bottomSheetConfig: TangemBottomSheetConfig?) {
|
||||
if (bottomSheetConfig != null) {
|
||||
|
|
@ -784,6 +814,14 @@ private fun WalletScreen_Preview(@PreviewParameter(WalletScreenPreviewProvider::
|
|||
) {
|
||||
}
|
||||
},
|
||||
virtualAccountComponent = object : VirtualAccountMainBlockComponent {
|
||||
override fun LazyListScope.virtualAccountMainContent(
|
||||
state: VirtualAccountMainUM,
|
||||
isBalanceHidden: Boolean,
|
||||
modifier: Modifier,
|
||||
) {
|
||||
}
|
||||
},
|
||||
bottomSheetContent = {
|
||||
Text("Markets Content")
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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,21 +45,22 @@ 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
|
||||
import com.tangem.core.ui.components.bottomsheets.state.BottomSheetState
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.TangemPullToRefreshSlidingContainer
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.getPullToRefreshIndicatorOffset
|
||||
import com.tangem.core.ui.components.haze.hazeEffectTangem
|
||||
import com.tangem.core.ui.components.haze.hazeSourceTangem
|
||||
import com.tangem.core.ui.components.rememberIsKeyboardVisible
|
||||
import com.tangem.core.ui.components.sheetscaffold.*
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
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
|
||||
|
|
@ -76,6 +76,8 @@ import com.tangem.feature.wallet.presentation.wallet.ui.components.common.Wallet
|
|||
import com.tangem.feature.wallet.presentation.wallet.ui.utils.lazyListStateMapSaver
|
||||
import com.tangem.features.tangempay.component.TangemPayMainBlockComponent
|
||||
import com.tangem.features.tangempay.entity.TangemPayMainUM
|
||||
import com.tangem.features.virtualaccount.main.component.VirtualAccountMainBlockComponent
|
||||
import com.tangem.features.virtualaccount.main.entity.VirtualAccountMainUM
|
||||
import dev.chrisbanes.haze.HazeProgressive
|
||||
import dev.chrisbanes.haze.HazeTint
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -84,11 +86,14 @@ import kotlin.math.abs
|
|||
private const val MARKET_HINT_THRESHOLD = 0.5f
|
||||
|
||||
@OptIn(ExperimentalDecomposeApi::class)
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
internal fun WalletScreen2(
|
||||
state: WalletScreenState,
|
||||
tangemPayComponent: TangemPayMainBlockComponent,
|
||||
virtualAccountComponent: VirtualAccountMainBlockComponent,
|
||||
modifier: Modifier = Modifier,
|
||||
promoBannersBlockComponent: ComposableContentComponent? = null,
|
||||
bottomSheetContent: @Composable (onExpandSheet: () -> Unit) -> Unit,
|
||||
bottomSheetHeaderHeightProvider: () -> Dp,
|
||||
onBottomSheetStateChange: (BottomSheetState) -> Unit,
|
||||
|
|
@ -133,6 +138,8 @@ internal fun WalletScreen2(
|
|||
state = state,
|
||||
walletsPagerState = walletsPagerState,
|
||||
tangemPayComponent = tangemPayComponent,
|
||||
promoBannersBlockComponent = promoBannersBlockComponent,
|
||||
virtualAccountComponent = virtualAccountComponent,
|
||||
behavior = behavior,
|
||||
bottomSheetContent = bottomSheetContent,
|
||||
bottomSheetHeaderHeightProvider = bottomSheetHeaderHeightProvider,
|
||||
|
|
@ -160,9 +167,11 @@ private fun WalletContent2(
|
|||
state: WalletScreenState,
|
||||
walletsPagerState: PagerState,
|
||||
tangemPayComponent: TangemPayMainBlockComponent,
|
||||
virtualAccountComponent: VirtualAccountMainBlockComponent,
|
||||
behavior: TangemCollapsingAppBarBehavior,
|
||||
listStates: Map<Int, LazyListState>,
|
||||
modifier: Modifier = Modifier,
|
||||
promoBannersBlockComponent: ComposableContentComponent? = null,
|
||||
bottomSheetHeaderHeightProvider: () -> Dp,
|
||||
onBottomSheetStateChange: (BottomSheetState) -> Unit,
|
||||
bottomSheetContent: @Composable (onExpandSheet: () -> Unit) -> Unit,
|
||||
|
|
@ -176,6 +185,7 @@ private fun WalletContent2(
|
|||
state.wallets2.getOrNull(state.selectedWalletIndex)?.pullToRefreshConfig,
|
||||
)
|
||||
}
|
||||
var subtitleBottom by remember { mutableStateOf(0.dp) }
|
||||
|
||||
BaseScaffoldWithMarkets(
|
||||
modifier = modifier,
|
||||
|
|
@ -208,7 +218,7 @@ private fun WalletContent2(
|
|||
|
||||
val pullToRefreshState = rememberPullToRefreshState()
|
||||
|
||||
Box(
|
||||
BoxWithConstraints(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.hazeSourceTangem(zIndex = -2f),
|
||||
|
|
@ -240,6 +250,7 @@ private fun WalletContent2(
|
|||
pullToRefreshState = pullToRefreshState,
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
behavior = behavior,
|
||||
topOffset = subtitleBottom + TangemTheme.dimens2.x2,
|
||||
)
|
||||
|
||||
val overlay = TangemTheme.colors2.overlay.overlayPrimary
|
||||
|
|
@ -286,6 +297,11 @@ private fun WalletContent2(
|
|||
|
||||
val pageSlideAlpha by rememberPageAlpha(walletsPagerState, currentWalletIndex)
|
||||
|
||||
val pullToRefreshContentOffset = getPullToRefreshIndicatorOffset(
|
||||
pullToRefreshConfig = currentWallet.pullToRefreshConfig,
|
||||
pullToRefreshState = pullToRefreshState,
|
||||
)
|
||||
|
||||
TangemSharedTransitionLayout(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
|
|
@ -301,11 +317,20 @@ private fun WalletContent2(
|
|||
TangemCollapsingTopBar(
|
||||
state = behavior.state,
|
||||
collapsingPart = {
|
||||
val balanceBlockHeight = with(LocalDensity.current) {
|
||||
-behavior.state.heightOffsetLimit.toDp()
|
||||
}
|
||||
WalletBalance(
|
||||
behavior = behavior,
|
||||
walletBalanceUM = currentWallet.walletsBalanceUM,
|
||||
buttons = currentWallet.buttons,
|
||||
isBalanceHidden = state.isHidingMode,
|
||||
modifier = Modifier.height(balanceBlockHeight),
|
||||
onSubtitleBottomChange = { newValue ->
|
||||
if (pullToRefreshContentOffset == 0.dp && newValue > subtitleBottom) {
|
||||
subtitleBottom = newValue
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
body = {
|
||||
|
|
@ -315,6 +340,8 @@ private fun WalletContent2(
|
|||
isBalanceHidden = state.isHidingMode,
|
||||
contentPadding = contentPadding,
|
||||
tangemPayComponent = tangemPayComponent,
|
||||
promoBannersBlockComponent = promoBannersBlockComponent,
|
||||
virtualAccountComponent = virtualAccountComponent,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.nestedScroll(behavior.nestedScrollConnection),
|
||||
|
|
@ -337,11 +364,12 @@ private fun WalletContent2(
|
|||
MarketsTooltip(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.padding(bottom = 24.dp)
|
||||
.padding(bottom = 8.dp)
|
||||
.padding(horizontal = 12.dp)
|
||||
.fillMaxWidth(),
|
||||
isVisible = state.showMarketsOnboarding,
|
||||
availableHeight = LocalWindowSize.current.height,
|
||||
availableHeight = maxHeight,
|
||||
sheetTopInset = TangemTheme.dimens2.x3,
|
||||
bottomSheetState = bottomSheetState,
|
||||
onCloseClick = state.onDismissMarketsTooltip,
|
||||
)
|
||||
|
|
@ -494,26 +522,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),
|
||||
|
|
@ -651,6 +667,14 @@ private fun WalletScreen2_Preview(@PreviewParameter(WalletScreen2PreviewProvider
|
|||
) {
|
||||
}
|
||||
},
|
||||
virtualAccountComponent = object : VirtualAccountMainBlockComponent {
|
||||
override fun LazyListScope.virtualAccountMainContent(
|
||||
state: VirtualAccountMainUM,
|
||||
isBalanceHidden: Boolean,
|
||||
modifier: Modifier,
|
||||
) {
|
||||
}
|
||||
},
|
||||
bottomSheetContent = {
|
||||
Text("Markets Content")
|
||||
},
|
||||
|
|
|
|||
|
|
@ -10,19 +10,17 @@ import androidx.compose.animation.fadeOut
|
|||
import androidx.compose.animation.slideIn
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.geometry.*
|
||||
import androidx.compose.ui.geometry.CornerRadius
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.geometry.RoundRect
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Outline
|
||||
import androidx.compose.ui.graphics.Path
|
||||
|
|
@ -31,12 +29,7 @@ import androidx.compose.ui.platform.LocalDensity
|
|||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Density
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.*
|
||||
import com.tangem.core.ui.components.sheetscaffold.TangemSheetState
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
|
@ -53,10 +46,11 @@ internal fun MarketsTooltip(
|
|||
bottomSheetState: TangemSheetState,
|
||||
isVisible: Boolean,
|
||||
onCloseClick: () -> Unit,
|
||||
sheetTopInset: Dp,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
val tooltipOffset by remember {
|
||||
val tooltipOffset by remember(availableHeight, sheetTopInset) {
|
||||
derivedStateOf {
|
||||
val bottomSheetOffset = try {
|
||||
// Can throw exception during the first composition
|
||||
|
|
@ -64,8 +58,7 @@ internal fun MarketsTooltip(
|
|||
} catch (e: Exception) {
|
||||
0.dp
|
||||
}
|
||||
|
||||
bottomSheetOffset - availableHeight
|
||||
bottomSheetOffset + sheetTopInset - availableHeight
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,16 @@ 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
|
||||
import com.tangem.features.virtualaccount.main.component.VirtualAccountMainBlockComponent
|
||||
import com.tangem.features.virtualaccount.main.entity.VirtualAccountMainUM
|
||||
|
||||
internal fun LazyListScope.nftCollections2(state: WalletUM, itemModifier: Modifier) {
|
||||
(state as? WalletUM.Content)?.let { content ->
|
||||
|
|
@ -25,9 +31,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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -42,4 +53,15 @@ internal fun LazyListScope.tangemPay(
|
|||
with(tangemPayComponent) {
|
||||
tangemPayMainContent(modifier = modifier, state = tangemPayUM, isBalanceHidden = isBalanceHidden)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun LazyListScope.virtualAccount(
|
||||
virtualAccountComponent: VirtualAccountMainBlockComponent,
|
||||
virtualAccountUM: VirtualAccountMainUM,
|
||||
isBalanceHidden: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
with(virtualAccountComponent) {
|
||||
virtualAccountMainContent(modifier = modifier, state = virtualAccountUM, isBalanceHidden = isBalanceHidden)
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -152,6 +167,7 @@ private fun SubtitleRow(walletBalanceUM: WalletBalanceUM, modifier: Modifier = M
|
|||
private fun Balance(walletBalanceUM: WalletBalanceUM, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
|
||||
AnimatedContent(
|
||||
targetState = walletBalanceUM,
|
||||
contentKey = { it::class },
|
||||
label = "Update the balance",
|
||||
modifier = modifier.testTag(MainScreenTestTags.WALLET_BALANCE),
|
||||
transitionSpec = {
|
||||
|
|
|
|||
|
|
@ -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,15 @@ 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.decompose.ComposableContentComponent
|
||||
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
|
||||
|
|
@ -22,17 +25,22 @@ import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency
|
|||
import com.tangem.feature.wallet.presentation.wallet.ui.components.nftCollections2
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.organizeTokens2
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.tangemPay
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.virtualAccount
|
||||
import com.tangem.features.tangempay.component.TangemPayMainBlockComponent
|
||||
import com.tangem.features.virtualaccount.main.component.VirtualAccountMainBlockComponent
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
internal fun WalletListContent(
|
||||
currentWallet: WalletUM,
|
||||
isBalanceHidden: Boolean,
|
||||
listState: LazyListState,
|
||||
tangemPayComponent: TangemPayMainBlockComponent,
|
||||
virtualAccountComponent: VirtualAccountMainBlockComponent,
|
||||
contentPadding: PaddingValues,
|
||||
modifier: Modifier = Modifier,
|
||||
promoBannersBlockComponent: ComposableContentComponent? = null,
|
||||
) {
|
||||
val containerColor = TangemTheme.colors2.surface.level1
|
||||
|
||||
|
|
@ -40,7 +48,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,
|
||||
|
|
@ -57,6 +65,12 @@ internal fun WalletListContent(
|
|||
notifications = currentWallet.notificationsCarousel.map { it.messageUM }.toPersistentList(),
|
||||
)
|
||||
|
||||
promoBannersBlockComponent?.let { component ->
|
||||
item(key = "PromoBannersBlock") {
|
||||
component.Content(modifier = itemModifier)
|
||||
}
|
||||
}
|
||||
|
||||
tangemPay(
|
||||
tangemPayComponent = tangemPayComponent,
|
||||
tangemPayUM = currentWallet.tangemPayMainUM,
|
||||
|
|
@ -64,6 +78,13 @@ internal fun WalletListContent(
|
|||
modifier = itemModifier,
|
||||
)
|
||||
|
||||
virtualAccount(
|
||||
virtualAccountComponent = virtualAccountComponent,
|
||||
virtualAccountUM = currentWallet.virtualAccountMainUM,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
|
||||
tokensListItems2(
|
||||
walletTokensListUM = currentWallet.tokensListUM,
|
||||
modifier = movableItemModifier,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ private fun LazyListScope.accountItem(
|
|||
|
||||
val portfolioModifier = modifier
|
||||
.padding(top = if (index != 0) TangemTheme.dimens2.x2 else TangemTheme.dimens2.x3)
|
||||
.testTag(MainScreenTestTags.TOKEN_LIST_ITEM)
|
||||
.testTag(MainScreenTestTags.ACCOUNT_LIST_ITEM)
|
||||
.semantics { lazyListItemPosition = index }
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = 0,
|
||||
|
|
@ -522,7 +522,7 @@ private fun LazyListScope.nonContentAccountItem(listItem: TokensListItemUM2.Port
|
|||
@Composable
|
||||
internal fun NonContentItemContentV2(textColor: Color, modifier: Modifier = Modifier, onClick: () -> Unit) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
modifier = modifier.testTag(MainScreenTestTags.EMPTY_TOKENS_PLACEHOLDER),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Icon(
|
||||
|
|
@ -545,7 +545,7 @@ internal fun NonContentItemContentV2(textColor: Color, modifier: Modifier = Modi
|
|||
onClick = onClick,
|
||||
size = TangemButtonSize.X8,
|
||||
shape = TangemButtonShape.Rounded,
|
||||
modifier = Modifier,
|
||||
modifier = Modifier.testTag(MainScreenTestTags.EMPTY_TOKENS_ADD_BUTTON),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,190 @@
|
|||
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 com.tangem.features.virtualaccount.main.entity.VirtualAccountMainUM
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import org.junit.jupiter.api.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,
|
||||
virtualAccountMainUM = VirtualAccountMainUM.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)
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ import com.tangem.domain.models.network.NetworkAddress
|
|||
import com.tangem.domain.models.tokenlist.TokenList
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.models.yield.supply.YieldSupplyStatus
|
||||
import org.junit.Test
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.math.BigDecimal
|
||||
|
||||
class YieldSupplyPromoBannerConverterTest {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import io.mockk.verify
|
|||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
internal class AddAndManageModelTest {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import io.mockk.verify
|
|||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
internal class WalletContentClickIntentsAnalyticsTest {
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@ import kotlinx.coroutines.test.StandardTestDispatcher
|
|||
import kotlinx.coroutines.test.TestCoroutineScheduler
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class DefaultPromoDeeplinkHandlerTest {
|
||||
|
|
@ -76,7 +76,7 @@ class DefaultPromoDeeplinkHandlerTest {
|
|||
|
||||
private lateinit var messages: MutableList<UiMessage>
|
||||
|
||||
@Before
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
MockKAnnotations.init(this)
|
||||
every { analyticsEventHandler.send(any()) } returns Unit
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.domain
|
||||
|
||||
import arrow.core.Either
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.notifications.repository.NotificationsRepository
|
||||
import com.tangem.domain.settings.IsReadyToShowRateAppUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.domain.yield.supply.promo.usecase.ShouldShowYieldBoostMainBannerUseCase
|
||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetShouldShowMainPromoUseCase
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotificationUM
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyFeatureToggles
|
||||
import io.mockk.clearMocks
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.MethodSource
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
internal class GetWalletNotificationsCarouselFactoryTest {
|
||||
|
||||
private val isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase = mockk()
|
||||
private val getWalletsUseCase: GetWalletsUseCase = mockk()
|
||||
private val notificationsRepository: NotificationsRepository = mockk()
|
||||
private val shouldShowYieldBoostMainBannerUseCase: ShouldShowYieldBoostMainBannerUseCase = mockk()
|
||||
private val yieldSupplyGetShouldShowMainPromoUseCase: YieldSupplyGetShouldShowMainPromoUseCase = mockk()
|
||||
private val yieldSupplyFeatureToggles: YieldSupplyFeatureToggles = mockk()
|
||||
private val clickIntents: WalletClickIntents = mockk(relaxed = true)
|
||||
private val userWallet: UserWallet.Hot = mockk(relaxed = true)
|
||||
|
||||
private val factory = GetWalletNotificationsCarouselFactory(
|
||||
isReadyToShowRateAppUseCase = isReadyToShowRateAppUseCase,
|
||||
getWalletsUseCase = getWalletsUseCase,
|
||||
notificationsRepository = notificationsRepository,
|
||||
shouldShowYieldBoostMainBannerUseCase = shouldShowYieldBoostMainBannerUseCase,
|
||||
yieldSupplyGetShouldShowMainPromoUseCase = yieldSupplyGetShouldShowMainPromoUseCase,
|
||||
yieldSupplyFeatureToggles = yieldSupplyFeatureToggles,
|
||||
)
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
clearMocks(
|
||||
isReadyToShowRateAppUseCase,
|
||||
getWalletsUseCase,
|
||||
notificationsRepository,
|
||||
shouldShowYieldBoostMainBannerUseCase,
|
||||
yieldSupplyGetShouldShowMainPromoUseCase,
|
||||
yieldSupplyFeatureToggles,
|
||||
clickIntents,
|
||||
userWallet,
|
||||
)
|
||||
// Defaults: only the yield boost banner can appear; every other notification is suppressed.
|
||||
every { userWallet.walletId } returns WALLET_ID
|
||||
every { notificationsRepository.getShouldShowNotification(any()) } returns flowOf(false)
|
||||
coEvery { notificationsRepository.isUserAllowToSubscribeOnPushNotifications() } returns true
|
||||
every { isReadyToShowRateAppUseCase() } returns flowOf(false)
|
||||
every { getWalletsUseCase() } returns flowOf(emptyList())
|
||||
every { yieldSupplyGetShouldShowMainPromoUseCase() } returns flowOf(true)
|
||||
every { yieldSupplyFeatureToggles.isYieldPromoEnabled } returns true
|
||||
coEvery { shouldShowYieldBoostMainBannerUseCase(any()) } returns Either.Right(true)
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideTestModels")
|
||||
fun `GIVEN gating conditions WHEN create THEN yield boost banner visibility matches`(model: Model) = runTest {
|
||||
// Arrange
|
||||
every { yieldSupplyFeatureToggles.isYieldPromoEnabled } returns model.toggleEnabled
|
||||
every { yieldSupplyGetShouldShowMainPromoUseCase() } returns flowOf(model.shouldShowLocal)
|
||||
coEvery { shouldShowYieldBoostMainBannerUseCase(WALLET_ID) } returns model.mainBanner
|
||||
|
||||
// Act
|
||||
val result = factory.create(userWallet, clickIntents).first()
|
||||
|
||||
// Assert
|
||||
assertThat(result.any { it is WalletNotificationUM.YieldBoostPromo }).isEqualTo(model.expectedShown)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN banner shown WHEN buttons clicked THEN routes to click intents`() = runTest {
|
||||
// Arrange
|
||||
val banner = factory.create(userWallet, clickIntents).first()
|
||||
.filterIsInstance<WalletNotificationUM.YieldBoostPromo>()
|
||||
.first()
|
||||
|
||||
// Act
|
||||
banner.onExploreClick()
|
||||
banner.onLaterClick()
|
||||
|
||||
// Assert
|
||||
verify { clickIntents.onYieldBoostBannerClick(WALLET_ID) }
|
||||
verify { clickIntents.onDismissYieldBoostBanner(WALLET_ID) }
|
||||
}
|
||||
|
||||
internal data class Model(
|
||||
val toggleEnabled: Boolean,
|
||||
val shouldShowLocal: Boolean,
|
||||
val mainBanner: Either<Throwable, Boolean>,
|
||||
val expectedShown: Boolean,
|
||||
)
|
||||
|
||||
private fun provideTestModels() = listOf(
|
||||
Model(toggleEnabled = true, shouldShowLocal = true, mainBanner = Either.Right(true), expectedShown = true),
|
||||
Model(toggleEnabled = false, shouldShowLocal = true, mainBanner = Either.Right(true), expectedShown = false),
|
||||
Model(toggleEnabled = true, shouldShowLocal = false, mainBanner = Either.Right(true), expectedShown = false),
|
||||
Model(toggleEnabled = true, shouldShowLocal = true, mainBanner = Either.Right(false), expectedShown = false),
|
||||
Model(
|
||||
toggleEnabled = true,
|
||||
shouldShowLocal = true,
|
||||
mainBanner = Either.Left(RuntimeException("boom")),
|
||||
expectedShown = false,
|
||||
),
|
||||
)
|
||||
|
||||
private companion object {
|
||||
val WALLET_ID = UserWalletId("01")
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.domain
|
|||
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import org.junit.Test
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.domain
|
||||
|
||||
import com.google.common.truth.Truth
|
||||
import org.junit.Test
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import com.tangem.domain.models.currency.CryptoCurrency
|
|||
import com.tangem.domain.models.network.Network
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.Test
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class QrContentClassifierTest {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue