Updated on 2026-08-14
This commit is contained in:
commit
1146554992
1461 changed files with 62266 additions and 17096 deletions
|
|
@ -7,7 +7,5 @@ package com.tangem.features.wallet.featuretoggles
|
|||
*/
|
||||
interface WalletFeatureToggles {
|
||||
|
||||
val isWalletReorderFeatureEnabled: Boolean
|
||||
|
||||
val isMainScreenQrScanningEnabled: Boolean
|
||||
val isAddAndManageTokensEnabled: Boolean
|
||||
}
|
||||
|
|
@ -41,7 +41,6 @@ dependencies {
|
|||
implementation(deps.googlePlay.review)
|
||||
implementation(deps.jodatime)
|
||||
implementation(deps.kotlin.immutable.collections)
|
||||
implementation(deps.reKotlin)
|
||||
implementation(tangemDeps.hot.core)
|
||||
implementation(tangemDeps.card.core)
|
||||
implementation(tangemDeps.blockchain)
|
||||
|
|
@ -125,9 +124,11 @@ dependencies {
|
|||
implementation(projects.domain.yieldSupply.models)
|
||||
implementation(projects.domain.appTheme)
|
||||
implementation(projects.domain.appTheme.models)
|
||||
implementation(projects.domain.tokensync)
|
||||
implementation(projects.domain.assetsdiscovery)
|
||||
|
||||
/** Feature Apis */
|
||||
implementation(projects.features.commonFeatures.api)
|
||||
implementation(projects.features.account.api)
|
||||
implementation(projects.features.details.api)
|
||||
implementation(projects.features.hotWallet.api)
|
||||
implementation(projects.features.manageTokens.api)
|
||||
|
|
@ -146,7 +147,6 @@ dependencies {
|
|||
implementation(projects.features.kyc.api)
|
||||
implementation(projects.features.tokenRecieve.api)
|
||||
implementation(projects.features.yieldSupply.api)
|
||||
implementation(projects.features.tangempay.details.api)
|
||||
implementation(projects.features.feed.api)
|
||||
implementation(projects.features.promoBanners.api)
|
||||
implementation(projects.features.tangempay.main.api)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
package com.tangem.feature.wallet.child.managetokens
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.slot.childSlot
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.child.managetokens.model.AddAndManageModel
|
||||
import com.tangem.feature.wallet.child.managetokens.ui.AddAndManageBottomSheetContent
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorComponent
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
|
||||
internal class AddAndManageBottomSheetComponent(
|
||||
appComponentContext: AppComponentContext,
|
||||
private val params: Params,
|
||||
private val portfolioSelectorComponentFactory: PortfolioSelectorComponent.Factory,
|
||||
) : ComposableBottomSheetComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: AddAndManageModel = getOrCreateModel(params)
|
||||
|
||||
private val portfolioSelectorSlot = childSlot(
|
||||
source = model.portfolioSelectorNavigation,
|
||||
serializer = Unit.serializer(),
|
||||
handleBackButton = false,
|
||||
childFactory = { _, context -> portfolioSelectorChild(context) },
|
||||
)
|
||||
|
||||
private fun portfolioSelectorChild(componentContext: ComponentContext): ComposableBottomSheetComponent =
|
||||
portfolioSelectorComponentFactory.create(
|
||||
context = childByContext(componentContext),
|
||||
params = PortfolioSelectorComponent.Params(
|
||||
portfolioFetcher = model.portfolioFetcher,
|
||||
controller = model.portfolioSelectorController,
|
||||
bsCallback = model.portfolioSelectorCallback,
|
||||
),
|
||||
)
|
||||
|
||||
override fun dismiss() {
|
||||
params.onDismiss()
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun BottomSheet() {
|
||||
val portfolioSelectorSlot by portfolioSelectorSlot.subscribeAsState()
|
||||
|
||||
AddAndManageBottomSheetContent(
|
||||
onAddTokensClick = model::onAddTokensClick,
|
||||
onOrganizeTokensClick = model::onOrganizeTokensClick,
|
||||
onDismiss = ::dismiss,
|
||||
)
|
||||
|
||||
portfolioSelectorSlot.child?.instance?.BottomSheet()
|
||||
}
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
val onDismiss: () -> Unit,
|
||||
val onOrganizeTokensClick: () -> Unit,
|
||||
val onManageTokensClick: (AccountId) -> Unit,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.feature.wallet.child.managetokens.analytics
|
||||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
||||
internal sealed class PortfolioAnalyticsEvent(
|
||||
event: String,
|
||||
) : AnalyticsEvent(category = "Portfolio", event = event) {
|
||||
|
||||
class ButtonAddManage : PortfolioAnalyticsEvent(event = "Button - Add Manage")
|
||||
|
||||
class ButtonAddTokens : PortfolioAnalyticsEvent(event = "Button - Add tokens")
|
||||
|
||||
class ButtonOrganizeTokens : PortfolioAnalyticsEvent(event = "Button - Organize Tokens")
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.feature.wallet.child.managetokens.di
|
||||
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.feature.wallet.child.managetokens.model.AddAndManageModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(ModelComponent::class)
|
||||
internal interface AddAndManageModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(AddAndManageModel::class)
|
||||
fun bindAddAndManageModel(model: AddAndManageModel): Model
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
package com.tangem.feature.wallet.child.managetokens.model
|
||||
|
||||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.arkivanov.decompose.router.slot.dismiss
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.feature.wallet.child.managetokens.AddAndManageBottomSheetComponent
|
||||
import com.tangem.feature.wallet.child.managetokens.analytics.PortfolioAnalyticsEvent
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioFetcher
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorComponent
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorController
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
internal class AddAndManageModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val portfolioFetcherFactory: PortfolioFetcher.Factory,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
val portfolioSelectorController: PortfolioSelectorController,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<AddAndManageBottomSheetComponent.Params>()
|
||||
|
||||
val portfolioSelectorNavigation: SlotNavigation<Unit> = SlotNavigation()
|
||||
|
||||
val portfolioFetcher: PortfolioFetcher by lazy {
|
||||
portfolioFetcherFactory.create(
|
||||
mode = PortfolioFetcher.Mode.Wallet(params.userWalletId),
|
||||
scope = modelScope,
|
||||
)
|
||||
}
|
||||
|
||||
val portfolioSelectorCallback = object : PortfolioSelectorComponent.BottomSheetCallback {
|
||||
override val onDismiss: () -> Unit = { portfolioSelectorNavigation.dismiss() }
|
||||
override val onBack: () -> Unit = { portfolioSelectorNavigation.dismiss() }
|
||||
}
|
||||
|
||||
init {
|
||||
observeAccountSelection()
|
||||
}
|
||||
|
||||
fun onAddTokensClick() {
|
||||
analyticsEventHandler.send(PortfolioAnalyticsEvent.ButtonAddTokens())
|
||||
modelScope.launch {
|
||||
val data = portfolioFetcher.data.first()
|
||||
val isSingleAccount = data.isSingleChoice(params.userWalletId)
|
||||
|
||||
if (isSingleAccount) {
|
||||
val mainAccountId = data.balances[params.userWalletId]
|
||||
?.accountsBalance
|
||||
?.mainAccount
|
||||
?.accountId
|
||||
?: AccountId.forMainCryptoPortfolio(params.userWalletId)
|
||||
|
||||
params.onDismiss()
|
||||
params.onManageTokensClick(mainAccountId)
|
||||
} else {
|
||||
portfolioSelectorNavigation.activate(Unit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onOrganizeTokensClick() {
|
||||
analyticsEventHandler.send(PortfolioAnalyticsEvent.ButtonOrganizeTokens())
|
||||
params.onDismiss()
|
||||
params.onOrganizeTokensClick()
|
||||
}
|
||||
|
||||
private fun observeAccountSelection() {
|
||||
modelScope.launch {
|
||||
portfolioSelectorController.selectedAccount.collect { accountId ->
|
||||
if (accountId != null) {
|
||||
portfolioSelectorNavigation.dismiss()
|
||||
params.onDismiss()
|
||||
params.onManageTokensClick(accountId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
package com.tangem.feature.wallet.child.managetokens.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.res.R as ResR
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
|
||||
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
||||
@Composable
|
||||
internal fun AddAndManageBottomSheetContent(
|
||||
onAddTokensClick: () -> Unit,
|
||||
onOrganizeTokensClick: () -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
val config = TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = onDismiss,
|
||||
content = AddAndManageBottomSheetConfigContent,
|
||||
)
|
||||
|
||||
TangemModalBottomSheet<AddAndManageBottomSheetConfigContent>(
|
||||
config = config,
|
||||
containerColor = TangemTheme.colors.background.primary,
|
||||
title = {
|
||||
TangemModalBottomSheetTitle(
|
||||
title = resourceReference(ResR.string.main_add_and_manage_tokens),
|
||||
endIconRes = R.drawable.ic_close_24,
|
||||
onEndClick = onDismiss,
|
||||
)
|
||||
},
|
||||
content = {
|
||||
AddAndManageContent(
|
||||
onAddTokensClick = onAddTokensClick,
|
||||
onOrganizeTokensClick = onOrganizeTokensClick,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AddAndManageContent(onAddTokensClick: () -> Unit, onOrganizeTokensClick: () -> Unit) {
|
||||
Column(
|
||||
modifier = Modifier.padding(
|
||||
start = 16.dp,
|
||||
end = 16.dp,
|
||||
bottom = 16.dp,
|
||||
),
|
||||
) {
|
||||
AddAndManageRow(
|
||||
iconRes = R.drawable.ic_plus_24,
|
||||
title = ResR.string.add_and_manage_sheet_manage_title,
|
||||
subtitle = ResR.string.add_and_manage_sheet_manage_subtitle,
|
||||
onClick = onAddTokensClick,
|
||||
modifier = Modifier.roundedShapeItemDecoration(
|
||||
currentIndex = 0,
|
||||
lastIndex = 1,
|
||||
addDefaultPadding = false,
|
||||
backgroundColor = TangemTheme.colors.background.action,
|
||||
),
|
||||
)
|
||||
AddAndManageRow(
|
||||
iconRes = R.drawable.ic_filter_default_24,
|
||||
title = ResR.string.add_and_manage_sheet_organize_title,
|
||||
subtitle = ResR.string.add_and_manage_sheet_organize_subtitle,
|
||||
onClick = onOrganizeTokensClick,
|
||||
modifier = Modifier.roundedShapeItemDecoration(
|
||||
currentIndex = 1,
|
||||
lastIndex = 1,
|
||||
addDefaultPadding = false,
|
||||
backgroundColor = TangemTheme.colors.background.action,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AddAndManageRow(
|
||||
iconRes: Int,
|
||||
title: Int,
|
||||
subtitle: Int,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = onClick)
|
||||
.padding(horizontal = 12.dp, vertical = 15.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier
|
||||
.size(36.dp)
|
||||
.clip(CircleShape)
|
||||
.background(TangemTheme.colors.icon.accent.copy(alpha = 0.1f)),
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(18.dp),
|
||||
painter = rememberVectorPainter(ImageVector.vectorResource(id = iconRes)),
|
||||
tint = TangemTheme.colors.icon.accent,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringResourceSafe(id = title),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
Text(
|
||||
text = stringResourceSafe(id = subtitle),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private object AddAndManageBottomSheetConfigContent : TangemBottomSheetConfigContent
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun AddAndManageBottomSheetContent_Preview() {
|
||||
TangemThemePreview {
|
||||
AddAndManageContent(
|
||||
onAddTokensClick = {},
|
||||
onOrganizeTokensClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.feature.wallet.child.organizetokens.model.converter.items
|
||||
|
||||
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.common.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.format.bigdecimal.BigDecimalFormatConstants
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.feature.wallet.child.organizetokens.model.converter.items
|
|||
import androidx.compose.ui.text.SpanStyle
|
||||
import com.tangem.common.getTotalCryptoAmount
|
||||
import com.tangem.common.getTotalFiatAmount
|
||||
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.common.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.ds.row.internal.TangemRowTailUM
|
||||
import com.tangem.core.ui.ds.row.token.TangemTokenRowUM
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ import com.tangem.core.ui.decompose.ComposableContentComponent
|
|||
import com.tangem.core.ui.decompose.ComposableDialogComponent
|
||||
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.feature.wallet.child.tokenActions.DefaultTokenActionsComponent
|
||||
import com.tangem.feature.wallet.child.tokenActions.TokenActionsComponent
|
||||
import com.tangem.feature.wallet.child.wallet.model.WalletModel
|
||||
|
|
@ -64,6 +66,7 @@ internal class WalletComponent @AssistedInject constructor(
|
|||
private val newPromoBannersFeatureToggles: NewPromoBannersFeatureToggles,
|
||||
private val networkSelectionComponentFactory: NetworkSelectionComponent.Factory,
|
||||
private val tokenActionsComponentFactory: TokenActionsComponent.Factory,
|
||||
private val portfolioSelectorComponentFactory: PortfolioSelectorComponent.Factory,
|
||||
private val designFeatureToggles: DesignFeatureToggles,
|
||||
) : ComposableContentComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
|
|
@ -178,6 +181,25 @@ internal class WalletComponent @AssistedInject constructor(
|
|||
),
|
||||
)
|
||||
}
|
||||
is WalletDialogConfig.AddAndManage -> {
|
||||
AddAndManageBottomSheetComponent(
|
||||
appComponentContext = childByContext(componentContext),
|
||||
params = AddAndManageBottomSheetComponent.Params(
|
||||
userWalletId = dialogConfig.userWalletId,
|
||||
onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
|
||||
onOrganizeTokensClick = {
|
||||
model.innerWalletRouter.openOrganizeTokensScreen(dialogConfig.userWalletId)
|
||||
},
|
||||
onManageTokensClick = { accountId ->
|
||||
model.innerWalletRouter.openManageTokensScreen(
|
||||
accountId = accountId,
|
||||
source = AppRoute.ManageTokens.Source.WALLET,
|
||||
)
|
||||
},
|
||||
),
|
||||
portfolioSelectorComponentFactory = portfolioSelectorComponentFactory,
|
||||
)
|
||||
}
|
||||
is WalletDialogConfig.OrganizeTokens -> {
|
||||
OrganizeTokensComponent(
|
||||
appComponentContext = childByContext(componentContext),
|
||||
|
|
@ -238,10 +260,11 @@ internal class WalletComponent @AssistedInject constructor(
|
|||
WalletScreen2(
|
||||
state = uiState,
|
||||
tangemPayComponent = tangemPayMainBlockComponent,
|
||||
bottomSheetContent = {
|
||||
bottomSheetContent = { onExpandSheet ->
|
||||
BottomSheetContent(
|
||||
bottomSheetState = bottomSheetState,
|
||||
onHeaderSizeChange = { headerSize = it },
|
||||
onExpandSheet = onExpandSheet,
|
||||
modifier = modifier,
|
||||
)
|
||||
},
|
||||
|
|
@ -253,10 +276,11 @@ internal class WalletComponent @AssistedInject constructor(
|
|||
state = uiState,
|
||||
promoBannersBlockComponent = promoBannersBlockComponent,
|
||||
tangemPayComponent = tangemPayMainBlockComponent,
|
||||
bottomSheetContent = {
|
||||
bottomSheetContent = { onExpandSheet ->
|
||||
BottomSheetContent(
|
||||
bottomSheetState = bottomSheetState,
|
||||
onHeaderSizeChange = { headerSize = it },
|
||||
onExpandSheet = onExpandSheet,
|
||||
modifier = modifier,
|
||||
)
|
||||
},
|
||||
|
|
@ -283,11 +307,13 @@ internal class WalletComponent @AssistedInject constructor(
|
|||
private fun BottomSheetContent(
|
||||
bottomSheetState: State<BottomSheetState>,
|
||||
onHeaderSizeChange: (Dp) -> Unit,
|
||||
onExpandSheet: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
feedEntryComponent.BottomSheetContent(
|
||||
bottomSheetState = bottomSheetState,
|
||||
onHeaderSizeChange = onHeaderSizeChange,
|
||||
onExpandSheet = onExpandSheet,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,12 +14,13 @@ import com.tangem.core.decompose.model.Model
|
|||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.ui.utils.parseBigDecimal
|
||||
import com.tangem.datasource.local.appsflyer.AppsFlyerStore
|
||||
import com.tangem.domain.account.supplier.SingleAccountListSupplier
|
||||
import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase
|
||||
import com.tangem.domain.account.supplier.SingleAccountListSupplier
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.apptheme.GetAppThemeModeUseCase
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
import com.tangem.domain.assetsdiscovery.usecase.StartAssetsDiscoveryUseCase
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.models.wallet.*
|
||||
|
|
@ -27,7 +28,6 @@ import com.tangem.domain.notifications.GetIsHuaweiDeviceWithoutGoogleServicesUse
|
|||
import com.tangem.domain.notifications.repository.NotificationsRepository
|
||||
import com.tangem.domain.pay.flow.PaymentAccountStatusFetcher
|
||||
import com.tangem.domain.pay.repository.OnboardingRepository
|
||||
import com.tangem.domain.pay.usecase.TangemPayMainScreenCustomerInfoUseCase
|
||||
import com.tangem.domain.qrscanning.models.ClassifiedQrContent
|
||||
import com.tangem.domain.qrscanning.models.QrResultSource
|
||||
import com.tangem.domain.qrscanning.models.QrSendTarget
|
||||
|
|
@ -38,8 +38,6 @@ import com.tangem.domain.settings.*
|
|||
import com.tangem.domain.tokens.RefreshMultiCurrencyWalletQuotesUseCase
|
||||
import com.tangem.domain.walletconnect.WcPairService
|
||||
import com.tangem.domain.walletconnect.model.WcPairRequest
|
||||
import com.tangem.domain.tokensync.usecase.StartTokenSyncUseCase
|
||||
import com.tangem.features.hotwallet.HotWalletFeatureToggles
|
||||
import com.tangem.domain.wallets.usecase.*
|
||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyUpdateUseCase
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
|
|
@ -62,16 +60,15 @@ import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSend
|
|||
import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.KycRejectedCallbacks
|
||||
import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider
|
||||
import com.tangem.features.biometry.AskBiometryComponent
|
||||
import com.tangem.features.hotwallet.HotWalletFeatureToggles
|
||||
import com.tangem.features.pushnotifications.api.PushNotificationsModelCallbacks
|
||||
import com.tangem.features.tangempay.TangemPayFeatureToggles
|
||||
import com.tangem.features.wallet.deeplink.WalletDeepLinkActionListener
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.*
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.*
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val TANGEM_PAY_UPDATE_INTERVAL = 60_000L
|
||||
|
|
@ -109,7 +106,6 @@ internal class WalletModel @Inject constructor(
|
|||
private val userWalletsListRepository: UserWalletsListRepository,
|
||||
private val yieldSupplyApyUpdateUseCase: YieldSupplyApyUpdateUseCase,
|
||||
private val tangemPayOnboardingRepository: OnboardingRepository,
|
||||
private val tangemPayMainScreenCustomerInfoUseCase: TangemPayMainScreenCustomerInfoUseCase,
|
||||
private val getAppThemeModeUseCase: GetAppThemeModeUseCase,
|
||||
private val trackingContextProxy: TrackingContextProxy,
|
||||
private val singleAccountListSupplier: SingleAccountListSupplier,
|
||||
|
|
@ -118,15 +114,13 @@ internal class WalletModel @Inject constructor(
|
|||
private val appsFlyerStore: AppsFlyerStore,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||
private val walletFeatureToggles: WalletFeatureToggles,
|
||||
private val listenToQrScanningUseCase: ListenToQrScanningUseCase,
|
||||
private val wcPairService: WcPairService,
|
||||
private val resolveQrSendTargetsUseCase: ResolveQrSendTargetsUseCase,
|
||||
private val paymentAccountStatusFetcher: PaymentAccountStatusFetcher,
|
||||
private val tangemPayFeatureToggles: TangemPayFeatureToggles,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
||||
private val startTokenSyncUseCase: StartTokenSyncUseCase,
|
||||
private val startAssetsDiscoveryUseCase: StartAssetsDiscoveryUseCase,
|
||||
val screenLifecycleProvider: ScreenLifecycleProvider,
|
||||
val innerWalletRouter: InnerWalletRouter,
|
||||
) : Model() {
|
||||
|
|
@ -159,7 +153,7 @@ internal class WalletModel @Inject constructor(
|
|||
subscribeTangemPayOnWalletState()
|
||||
subscribeToMainScreenQrScanning()
|
||||
enableNotificationsIfNeeded()
|
||||
applyPendingTokenSyncs()
|
||||
applyPendingAssetsDiscovery()
|
||||
|
||||
clickIntents.initialize(innerWalletRouter, modelScope)
|
||||
|
||||
|
|
@ -438,17 +432,14 @@ internal class WalletModel @Inject constructor(
|
|||
if (isShouldLaunchPeriodicUpdate) {
|
||||
updateTangemPayJobHolder.cancel()
|
||||
modelScope.launch {
|
||||
tangemPayMainScreenCustomerInfoUseCase.fetch(userWalletId)
|
||||
paymentAccountStatusFetcher.invoke(PaymentAccountStatusFetcher.Params(userWalletId))
|
||||
while (isActive) {
|
||||
delay(TANGEM_PAY_UPDATE_INTERVAL)
|
||||
tangemPayMainScreenCustomerInfoUseCase.fetch(userWalletId)
|
||||
paymentAccountStatusFetcher.invoke(PaymentAccountStatusFetcher.Params(userWalletId))
|
||||
}
|
||||
}.saveIn(updateTangemPayJobHolder)
|
||||
} else {
|
||||
// Don't refresh customer info periodically if the card was already issued, only update on swipe to refresh
|
||||
tangemPayMainScreenCustomerInfoUseCase.fetch(userWalletId)
|
||||
paymentAccountStatusFetcher.invoke(PaymentAccountStatusFetcher.Params(userWalletId))
|
||||
}
|
||||
}.launchIn(modelScope)
|
||||
|
|
@ -556,9 +547,7 @@ internal class WalletModel @Inject constructor(
|
|||
wallets = action.wallets,
|
||||
clickIntents = clickIntents,
|
||||
walletImageResolver = walletImageResolver,
|
||||
isMainScreenQrScanningEnabled = walletFeatureToggles.isMainScreenQrScanningEnabled,
|
||||
getWalletIconUseCase = getWalletIconUseCase,
|
||||
isTangemPayRefactorEnabled = tangemPayFeatureToggles.isTangemPayAccountsRefactorEnabled,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -605,7 +594,6 @@ internal class WalletModel @Inject constructor(
|
|||
clickIntents = clickIntents,
|
||||
walletImageResolver = walletImageResolver,
|
||||
getWalletIconUseCase = getWalletIconUseCase,
|
||||
isTangemPayRefactorEnabled = tangemPayFeatureToggles.isTangemPayAccountsRefactorEnabled,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -627,7 +615,6 @@ internal class WalletModel @Inject constructor(
|
|||
clickIntents = clickIntents,
|
||||
walletImageResolver = walletImageResolver,
|
||||
getWalletIconUseCase = getWalletIconUseCase,
|
||||
isTangemPayRefactorEnabled = tangemPayFeatureToggles.isTangemPayAccountsRefactorEnabled,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -642,7 +629,6 @@ internal class WalletModel @Inject constructor(
|
|||
clickIntents = clickIntents,
|
||||
walletImageResolver = walletImageResolver,
|
||||
getWalletIconUseCase = getWalletIconUseCase,
|
||||
isTangemPayRefactorEnabled = tangemPayFeatureToggles.isTangemPayAccountsRefactorEnabled,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -704,7 +690,6 @@ internal class WalletModel @Inject constructor(
|
|||
clickIntents = clickIntents,
|
||||
walletImageResolver = walletImageResolver,
|
||||
getWalletIconUseCase = getWalletIconUseCase,
|
||||
isTangemPayRefactorEnabled = tangemPayFeatureToggles.isTangemPayAccountsRefactorEnabled,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -844,9 +829,9 @@ internal class WalletModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun applyPendingTokenSyncs() {
|
||||
if (hotWalletFeatureToggles.isTokenSyncEnabled) {
|
||||
startTokenSyncUseCase.applyPendingSyncs()
|
||||
private fun applyPendingAssetsDiscovery() {
|
||||
if (hotWalletFeatureToggles.isAssetsDiscoveryEnabled) {
|
||||
startAssetsDiscoveryUseCase.applyPendingAssetsDiscovery()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,11 +22,10 @@ import com.tangem.domain.models.wallet.UserWallet
|
|||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.TangemPayDetailsConfig
|
||||
import com.tangem.domain.pay.TangemPayEligibilityManager
|
||||
import com.tangem.domain.pay.model.TangemPayEntryPoint
|
||||
import com.tangem.domain.pay.flow.PaymentAccountStatusFetcher
|
||||
import com.tangem.domain.pay.model.TangemPayEntryPoint
|
||||
import com.tangem.domain.pay.repository.OnboardingRepository
|
||||
import com.tangem.domain.pay.usecase.ProduceTangemPayInitialDataUseCase
|
||||
import com.tangem.domain.pay.usecase.TangemPayMainScreenCustomerInfoUseCase
|
||||
import com.tangem.domain.tangempay.TangemPayAnalyticsEvents
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDialogConfig
|
||||
|
|
@ -72,7 +71,6 @@ internal class TangemPayClickIntentsImplementor @Inject constructor(
|
|||
private val produceInitialDataTangemPay: ProduceTangemPayInitialDataUseCase,
|
||||
private val getWalletMetainfoUseCase: GetWalletMetaInfoUseCase,
|
||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||
private val tangemPayMainScreenCustomerInfoUseCase: TangemPayMainScreenCustomerInfoUseCase,
|
||||
private val tangemPayOnboardingRepository: OnboardingRepository,
|
||||
private val tangemPayEligibilityManager: TangemPayEligibilityManager,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
|
|
@ -85,7 +83,6 @@ internal class TangemPayClickIntentsImplementor @Inject constructor(
|
|||
if (!onboardingRepository.isTangemPayInitialDataProduced(userWalletId)) {
|
||||
return
|
||||
}
|
||||
tangemPayMainScreenCustomerInfoUseCase.fetch(userWalletId)
|
||||
paymentAccountStatusFetcher.invoke(PaymentAccountStatusFetcher.Params(userWalletId))
|
||||
}
|
||||
|
||||
|
|
@ -100,7 +97,6 @@ internal class TangemPayClickIntentsImplementor @Inject constructor(
|
|||
modelScope.launch {
|
||||
produceInitialDataTangemPay.invoke(userWallet.walletId)
|
||||
.onRight {
|
||||
tangemPayMainScreenCustomerInfoUseCase.fetch(userWallet.walletId)
|
||||
paymentAccountStatusFetcher.invoke(PaymentAccountStatusFetcher.Params(userWallet.walletId))
|
||||
}
|
||||
.onLeft {
|
||||
|
|
@ -277,7 +273,6 @@ internal class TangemPayClickIntentsImplementor @Inject constructor(
|
|||
modelScope.launch {
|
||||
tangemPayOnboardingRepository.disableTangemPay(userWalletId)
|
||||
.onRight {
|
||||
tangemPayMainScreenCustomerInfoUseCase.fetch(userWalletId)
|
||||
paymentAccountStatusFetcher.invoke(PaymentAccountStatusFetcher.Params(userWalletId))
|
||||
}
|
||||
.onLeft { uiMessageSender.send(ToastMessage(resourceReference(R.string.common_something_went_wrong))) }
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase
|
|||
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.domain.yield.supply.usecase.YieldSupplySetShouldShowMainPromoUseCase
|
||||
import com.tangem.feature.wallet.child.managetokens.analytics.PortfolioAnalyticsEvent
|
||||
import com.tangem.feature.wallet.presentation.account.AccountDependencies
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.OnrampStatusFactory
|
||||
|
|
@ -36,6 +37,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.transformers.CloseBot
|
|||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.OpenBottomSheetTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.MultiWalletCurrencyActionsConverter
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
|
|
@ -112,6 +114,7 @@ internal class WalletContentClickIntentsImplementor @Inject constructor(
|
|||
private val yieldSupplySetShouldShowMainPromoUseCase: YieldSupplySetShouldShowMainPromoUseCase,
|
||||
private val tokenListAnalyticsSender: TokenListAnalyticsSender,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
private val walletFeatureToggles: WalletFeatureToggles,
|
||||
) : BaseWalletClickIntents(), WalletContentClickIntents {
|
||||
|
||||
override fun onDetailsClick() {
|
||||
|
|
@ -119,7 +122,13 @@ internal class WalletContentClickIntentsImplementor @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onOrganizeTokensClick() {
|
||||
router.openOrganizeTokensScreen(userWalletId = stateHolder.getSelectedWalletId())
|
||||
val userWalletId = stateHolder.getSelectedWalletId()
|
||||
if (walletFeatureToggles.isAddAndManageTokensEnabled) {
|
||||
analyticsEventHandler.send(PortfolioAnalyticsEvent.ButtonAddManage())
|
||||
router.openAddAndManageBottomSheet(userWalletId = userWalletId)
|
||||
} else {
|
||||
router.openOrganizeTokensScreen(userWalletId = userWalletId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDismissMarketsTooltip() {
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@ import com.tangem.core.decompose.di.ModelScoped
|
|||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
import com.tangem.core.ui.clipboard.ClipboardManager
|
||||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.haptic.TangemHapticEffect
|
||||
import com.tangem.core.ui.haptic.VibratorHapticManager
|
||||
import com.tangem.core.ui.message.DialogMessage
|
||||
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
||||
import com.tangem.domain.account.status.usecase.IsCryptoCurrencyCouldHideUseCase
|
||||
import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.extenstions.unwrap
|
||||
|
|
@ -44,7 +44,6 @@ import com.tangem.domain.onramp.model.OnrampSource
|
|||
import com.tangem.domain.promo.GetStoryContentUseCase
|
||||
import com.tangem.domain.promo.models.StoryContentIds
|
||||
import com.tangem.domain.staking.model.StakingOption
|
||||
import com.tangem.domain.account.status.usecase.IsCryptoCurrencyCouldHideUseCase
|
||||
import com.tangem.domain.tokens.NeedShowYieldSupplyDepositedWarningUseCase
|
||||
import com.tangem.domain.tokens.SaveViewedTokenReceiveWarningUseCase
|
||||
import com.tangem.domain.tokens.SaveViewedYieldSupplyWarningUseCase
|
||||
|
|
@ -455,13 +454,10 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
|
||||
override fun onMultiWalletSwapClick(userWalletId: UserWalletId) {
|
||||
val selectedWallet = stateHolder.getSelectedWallet() as? WalletState.MultiCurrency.Content ?: return
|
||||
when (val tokenListState = selectedWallet.tokensListState) {
|
||||
is WalletTokensListState.ContentState.Content -> checkSwapCryptoAvailability(
|
||||
tokenCount = tokenListState.items.count { it is TokensListItemUM.Token },
|
||||
)
|
||||
is WalletTokensListState.ContentState.PortfolioContent -> checkSwapCryptoAvailability(
|
||||
tokenCount = tokenListState.items.sumOf { it.tokens.count { it is TokensListItemUM.Token } },
|
||||
)
|
||||
when (selectedWallet.tokensListState) {
|
||||
is WalletTokensListState.ContentState.Content,
|
||||
is WalletTokensListState.ContentState.PortfolioContent,
|
||||
-> Unit
|
||||
WalletTokensListState.ContentState.Loading,
|
||||
WalletTokensListState.ContentState.Locked,
|
||||
WalletTokensListState.Empty,
|
||||
|
|
@ -470,7 +466,10 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
|
||||
modelScope.launch {
|
||||
val swapRoute = getSwapRoute(
|
||||
AppRoute.SwapCrypto(userWalletId = userWalletId),
|
||||
AppRoute.Swap(
|
||||
userWalletId = userWalletId,
|
||||
screenSource = AnalyticsParam.ScreensSources.Main.value,
|
||||
),
|
||||
)
|
||||
onMultiWalletActionClick(
|
||||
statusFlow = rampStateManager.getExpressInitializationStatus(userWalletId),
|
||||
|
|
@ -660,7 +659,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
private fun navigateToSwap(cryptoCurrencyStatus: CryptoCurrencyStatus, userWalletId: UserWalletId) {
|
||||
appRouter.push(
|
||||
AppRoute.Swap(
|
||||
currencyFrom = cryptoCurrencyStatus.currency,
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency,
|
||||
userWalletId = userWalletId,
|
||||
screenSource = AnalyticsParam.ScreensSources.LongTap.value,
|
||||
),
|
||||
|
|
@ -675,11 +674,4 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkSwapCryptoAvailability(tokenCount: Int) {
|
||||
if (tokenCount < 2) {
|
||||
analyticsEventHandler.send(event = MainScreenAnalyticsEvent.ButtonSwap(AnalyticsParam.Status.Error))
|
||||
uiMessageSender.send(WalletAlertUM.insufficientTokensCountForSwapping())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.feature.wallet.child.wallet.model.intents
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import com.tangem.common.routing.AppRoute.*
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.ui.notifications.NotificationId
|
||||
|
|
@ -9,10 +8,12 @@ import com.tangem.common.ui.userwallet.handle
|
|||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic.ButtonSupport
|
||||
import com.tangem.core.analytics.models.event.AssetsDiscoveryAnalyticsEvent
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.navigation.review.ReviewManager
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
import com.tangem.domain.assetsdiscovery.usecase.AcknowledgeAssetsDiscoveryCompletionUseCase
|
||||
import com.tangem.domain.card.SetCardWasScannedUseCase
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.feedback.GetWalletMetaInfoUseCase
|
||||
|
|
@ -40,16 +41,15 @@ import com.tangem.domain.tokens.model.analytics.PromoAnalyticsEvent
|
|||
import com.tangem.domain.tokens.model.analytics.PromoAnalyticsEvent.Program
|
||||
import com.tangem.domain.tokens.model.analytics.PromoAnalyticsEvent.PromotionBannerClicked
|
||||
import com.tangem.domain.tokens.model.details.NavigationAction
|
||||
import com.tangem.domain.tokensync.usecase.AcknowledgeTokenSyncCompletionUseCase
|
||||
import com.tangem.domain.wallets.usecase.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.Basic
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.MainScreen
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletEvent
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender
|
||||
import com.tangem.features.pushnotifications.api.analytics.PushNotificationAnalyticEvents
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
|
|
@ -97,9 +97,9 @@ internal interface WalletWarningsClickIntents {
|
|||
|
||||
fun onCloseUpgradeBannerClick(userWalletId: UserWalletId)
|
||||
|
||||
fun onDismissTokenSyncNotification(userWalletId: UserWalletId)
|
||||
fun onDismissAssetsDiscoveryNotification(userWalletId: UserWalletId)
|
||||
|
||||
fun onTokenSyncManageClick(userWalletId: UserWalletId)
|
||||
fun onAssetsDiscoveryManageClick(userWalletId: UserWalletId)
|
||||
}
|
||||
|
||||
@Suppress("LargeClass", "LongParameterList", "TooManyFunctions")
|
||||
|
|
@ -132,7 +132,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
|
|||
private val uiMessageSender: UiMessageSender,
|
||||
private val reviewManager: ReviewManager,
|
||||
private val closeHotWalletUpgradeBannerUseCase: CloseHotWalletUpgradeBannerUseCase,
|
||||
private val acknowledgeTokenSyncCompletionUseCase: AcknowledgeTokenSyncCompletionUseCase,
|
||||
private val acknowledgeAssetsDiscoveryCompletionUseCase: AcknowledgeAssetsDiscoveryCompletionUseCase,
|
||||
) : BaseWalletClickIntents(), WalletWarningsClickIntents {
|
||||
|
||||
override fun onAddBackupCardClick() {
|
||||
|
|
@ -173,7 +173,6 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onGenerateMissedAddressesClick(missedAddressCurrencies: List<CryptoCurrency>) {
|
||||
analyticsEventHandler.send(Basic.CardWasScanned(AnalyticsParam.ScreensSources.Main))
|
||||
analyticsEventHandler.send(MainScreen.NoticeScanYourCardTapped())
|
||||
|
||||
modelScope.launch {
|
||||
|
|
@ -198,7 +197,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
|
|||
userWalletsListRepository.unlockAllWallets()
|
||||
.onLeft {
|
||||
val selectedUserWalletId = stateHolder.getSelectedWalletId()
|
||||
nonBiometricUnlockWalletUseCase(selectedUserWalletId)
|
||||
nonBiometricUnlockWalletUseCase(selectedUserWalletId, AnalyticsParam.ScreensSources.Main)
|
||||
.onLeft { error ->
|
||||
error.handle(
|
||||
onAlreadyUnlocked = {},
|
||||
|
|
@ -508,12 +507,14 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onDismissTokenSyncNotification(userWalletId: UserWalletId) {
|
||||
acknowledgeTokenSyncCompletionUseCase(userWalletId)
|
||||
override fun onDismissAssetsDiscoveryNotification(userWalletId: UserWalletId) {
|
||||
analyticsEventHandler.send(AssetsDiscoveryAnalyticsEvent.ButtonCloseBanner())
|
||||
acknowledgeAssetsDiscoveryCompletionUseCase(userWalletId)
|
||||
}
|
||||
|
||||
override fun onTokenSyncManageClick(userWalletId: UserWalletId) {
|
||||
acknowledgeTokenSyncCompletionUseCase(userWalletId)
|
||||
override fun onAssetsDiscoveryManageClick(userWalletId: UserWalletId) {
|
||||
analyticsEventHandler.send(AssetsDiscoveryAnalyticsEvent.ButtonManageTokens())
|
||||
acknowledgeAssetsDiscoveryCompletionUseCase(userWalletId)
|
||||
router.openManageTokensScreen(
|
||||
AccountId.forMainCryptoPortfolio(userWalletId),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,9 +9,6 @@ internal class DefaultWalletFeatureToggles @Inject constructor(
|
|||
private val featureToggles: FeatureTogglesManager,
|
||||
) : WalletFeatureToggles {
|
||||
|
||||
override val isWalletReorderFeatureEnabled: Boolean
|
||||
get() = featureToggles.isFeatureEnabled(FeatureToggles.WALLET_REORDER_FEATURE_ENABLED)
|
||||
|
||||
override val isMainScreenQrScanningEnabled: Boolean
|
||||
get() = featureToggles.isFeatureEnabled(FeatureToggles.MAIN_SCREEN_QR_SCANNING_ENABLED)
|
||||
override val isAddAndManageTokensEnabled: Boolean
|
||||
get() = featureToggles.isFeatureEnabled(FeatureToggles.ADD_AND_MANAGE_TOKENS_ENABLED)
|
||||
}
|
||||
|
|
@ -3,14 +3,14 @@ package com.tangem.feature.wallet.presentation.account
|
|||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
||||
import com.tangem.domain.account.status.supplier.SingleAccountStatusSupplier
|
||||
import com.tangem.domain.account.status.utils.ExpandedAccountsHolder
|
||||
import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase
|
||||
import com.tangem.domain.account.status.utils.MainExpandedAccountsHolder
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
internal class AccountDependencies @Inject constructor(
|
||||
val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||
val expandedAccountsHolder: ExpandedAccountsHolder,
|
||||
val expandedAccountsHolder: MainExpandedAccountsHolder,
|
||||
val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
|
||||
val singleAccountStatusSupplier: SingleAccountStatusSupplier,
|
||||
)
|
||||
|
|
@ -91,6 +91,8 @@ internal object WalletScreenPreviewDataLegacy {
|
|||
),
|
||||
),
|
||||
organizeTokensButtonConfig = WalletTokensListState.OrganizeTokensButtonConfig(
|
||||
textRes = R.string.organize_tokens_title,
|
||||
iconRes = R.drawable.ic_filter_24,
|
||||
isEnabled = true,
|
||||
onClick = {},
|
||||
),
|
||||
|
|
@ -119,6 +121,8 @@ internal object WalletScreenPreviewDataLegacy {
|
|||
),
|
||||
),
|
||||
organizeTokensButtonConfig = WalletTokensListState.OrganizeTokensButtonConfig(
|
||||
textRes = R.string.organize_tokens_title,
|
||||
iconRes = R.drawable.ic_filter_24,
|
||||
isEnabled = true,
|
||||
onClick = {},
|
||||
),
|
||||
|
|
@ -149,6 +153,8 @@ internal object WalletScreenPreviewDataLegacy {
|
|||
),
|
||||
),
|
||||
organizeTokensButtonConfig = WalletTokensListState.OrganizeTokensButtonConfig(
|
||||
textRes = R.string.organize_tokens_title,
|
||||
iconRes = R.drawable.ic_filter_24,
|
||||
isEnabled = true,
|
||||
onClick = {},
|
||||
),
|
||||
|
|
@ -211,15 +217,8 @@ internal object WalletScreenPreviewDataLegacy {
|
|||
isFlickering = false,
|
||||
onItemClick = { },
|
||||
),
|
||||
tangemPayState = TangemPayState.Card(
|
||||
lastFourDigits = stringReference("*1234"),
|
||||
balanceText = stringReference("$10"),
|
||||
balanceSymbol = stringReference("USDC"),
|
||||
onClick = {},
|
||||
),
|
||||
type = WalletType.Cold,
|
||||
tangemPayMainUM = TangemPayMainUM.Empty,
|
||||
isTangemPayRefactorEnabled = false,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import com.tangem.core.ui.extensions.stringReference
|
|||
import com.tangem.core.ui.extensions.styledStringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAdditionalInfo
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletBalanceUM
|
||||
|
||||
internal object WalletBalancePreview {
|
||||
|
|
@ -38,6 +39,36 @@ internal object WalletBalancePreview {
|
|||
isZeroBalance = false,
|
||||
)
|
||||
|
||||
val syncProgress = WalletBalanceUM.Content(
|
||||
id = UserWalletId("0"),
|
||||
name = "My Wallet",
|
||||
balanceInAppBar = combinedReference(
|
||||
stringReference("1,234"),
|
||||
styledStringReference(
|
||||
".56",
|
||||
{ SpanStyle(color = TangemTheme.colors2.text.neutral.secondary) },
|
||||
),
|
||||
stringReference(" $"),
|
||||
),
|
||||
balance = combinedReference(
|
||||
stringReference("1,234"),
|
||||
styledStringReference(
|
||||
".56",
|
||||
{
|
||||
TangemTheme.typography2.headingRegular28.toSpanStyle()
|
||||
},
|
||||
),
|
||||
stringReference(" $"),
|
||||
),
|
||||
deviceIcon = DeviceIconUM.Stub(cardsCount = 3),
|
||||
isBalanceFlickering = false,
|
||||
isZeroBalance = false,
|
||||
additionalInfo = WalletAdditionalInfo(
|
||||
hideable = false,
|
||||
content = WalletAdditionalInfo.Content.SyncProgress(37),
|
||||
),
|
||||
)
|
||||
|
||||
val hiddenBalanceContent = content.copy(balance = content.balance.orMaskWithStars(true))
|
||||
|
||||
val loading: WalletBalanceUM.Loading = WalletBalanceUM.Loading(
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import javax.inject.Inject
|
|||
|
||||
/** Default implementation of wallet feature router */
|
||||
@ModelScoped
|
||||
@Suppress("TooManyFunctions")
|
||||
internal class DefaultWalletRouter @Inject constructor(
|
||||
private val router: AppRouter,
|
||||
private val urlOpener: UrlOpener,
|
||||
|
|
@ -66,14 +67,20 @@ internal class DefaultWalletRouter @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
override fun openManageTokensScreen(accountId: AccountId) {
|
||||
override fun openManageTokensScreen(accountId: AccountId, source: AppRoute.ManageTokens.Source) {
|
||||
val route = AppRoute.ManageTokens(
|
||||
source = AppRoute.ManageTokens.Source.ACCOUNT,
|
||||
source = source,
|
||||
accountId = accountId,
|
||||
)
|
||||
router.push(route)
|
||||
}
|
||||
|
||||
override fun openAddAndManageBottomSheet(userWalletId: UserWalletId) {
|
||||
dialogNavigation.activate(
|
||||
configuration = WalletDialogConfig.AddAndManage(userWalletId = userWalletId),
|
||||
)
|
||||
}
|
||||
|
||||
override fun openOnboardingScreen(scanResponse: ScanResponse, continueBackup: Boolean) {
|
||||
router.push(
|
||||
AppRoute.Onboarding(
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import kotlinx.coroutines.flow.SharedFlow
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Stable
|
||||
@Suppress("TooManyFunctions")
|
||||
internal interface InnerWalletRouter {
|
||||
|
||||
val dialogNavigation: SlotNavigation<WalletDialogConfig>
|
||||
|
|
@ -47,7 +48,13 @@ internal interface InnerWalletRouter {
|
|||
fun openDetailsScreen(selectedWalletId: UserWalletId)
|
||||
|
||||
/** Open manage tokens screen */
|
||||
fun openManageTokensScreen(accountId: AccountId)
|
||||
fun openManageTokensScreen(
|
||||
accountId: AccountId,
|
||||
source: AppRoute.ManageTokens.Source = AppRoute.ManageTokens.Source.ACCOUNT,
|
||||
)
|
||||
|
||||
/** Open add and manage tokens bottom sheet */
|
||||
fun openAddAndManageBottomSheet(userWalletId: UserWalletId)
|
||||
|
||||
/** Open onboarding screen */
|
||||
fun openOnboardingScreen(scanResponse: ScanResponse, continueBackup: Boolean = false)
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ internal class TokenListAnalyticsSender @Inject constructor(
|
|||
) {
|
||||
// for now send only for Polkadot ecosystem blockchains
|
||||
// later dependency on Blockchain will be removed and use token name
|
||||
when (val blockchain = Blockchain.fromNetworkId(currencyStatus.currency.network.backendId)) {
|
||||
when (val blockchain = Blockchain.fromNetworkId(currencyStatus.currency.network.rawId)) {
|
||||
Blockchain.Polkadot,
|
||||
Blockchain.AlephZero,
|
||||
Blockchain.Kusama,
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.analytics.utils
|
|||
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.domain.models.kyc.KycStatus
|
||||
import com.tangem.domain.pay.model.MainScreenCustomerInfo
|
||||
import com.tangem.domain.pay.model.OrderStatus
|
||||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||
import com.tangem.domain.tangempay.TangemPayAnalyticsEvents
|
||||
import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider
|
||||
import javax.inject.Inject
|
||||
|
|
@ -15,26 +13,24 @@ internal class WalletTangemPayAnalyticsEventSender @Inject constructor(
|
|||
private val screenLifecycleProvider: ScreenLifecycleProvider,
|
||||
) {
|
||||
|
||||
private val sentEvents = mutableSetOf<TangemPayAnalyticsEvents>()
|
||||
private val sentEvents = mutableSetOf<String>()
|
||||
|
||||
fun send(customerInfo: MainScreenCustomerInfo) {
|
||||
fun send(statusValue: PaymentAccountStatusValue) {
|
||||
if (screenLifecycleProvider.isBackgroundState.value) return
|
||||
|
||||
val cardInfo = customerInfo.info.cardInfo
|
||||
val productInstance = customerInfo.info.productInstance
|
||||
|
||||
// TODO: TangemPay refactor analytics
|
||||
// when statement copied from TangemPayUpdateInfoStateTransformer. Be careful when editing
|
||||
val event = when {
|
||||
// ignore cancelled state on analytics
|
||||
customerInfo.orderStatus == OrderStatus.CANCELED -> return
|
||||
// ignore kyc not approved state on analytics
|
||||
customerInfo.info.kycStatus != KycStatus.APPROVED -> return
|
||||
cardInfo != null && productInstance != null -> return
|
||||
else -> TangemPayAnalyticsEvents.IssuingBannerDisplayed()
|
||||
val event = when (statusValue) {
|
||||
is PaymentAccountStatusValue.IssuingCard -> TangemPayAnalyticsEvents.IssuingBannerDisplayed()
|
||||
PaymentAccountStatusValue.Empty,
|
||||
is PaymentAccountStatusValue.Error,
|
||||
is PaymentAccountStatusValue.Loaded,
|
||||
PaymentAccountStatusValue.Loading,
|
||||
PaymentAccountStatusValue.NotCreated,
|
||||
is PaymentAccountStatusValue.UnderReview,
|
||||
is PaymentAccountStatusValue.Deactivated,
|
||||
-> return
|
||||
}
|
||||
|
||||
if (sentEvents.add(event)) {
|
||||
if (sentEvents.add(event.id)) {
|
||||
analyticsEventHandler.send(event)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ internal class WalletWarningsAnalyticsSender @Inject constructor(
|
|||
is WalletNotification.Warning.TangemPayRefreshNeeded -> null
|
||||
is WalletNotification.Warning.TangemPayUnreachable -> null
|
||||
is WalletNotification.UpgradeHotWalletPromo -> null
|
||||
is WalletNotification.TokenSyncCompleted -> null
|
||||
is WalletNotification.AssetsDiscoveryCompleted -> null
|
||||
is WalletNotification.CreateTangemPayAccount -> null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ import com.tangem.domain.notifications.repository.NotificationsRepository
|
|||
import com.tangem.domain.promo.ShouldShowPromoWalletUseCase
|
||||
import com.tangem.domain.promo.models.PromoId
|
||||
import com.tangem.domain.settings.IsReadyToShowRateAppUseCase
|
||||
import com.tangem.domain.tokensync.model.TokenSyncProgress
|
||||
import com.tangem.domain.tokensync.usecase.ObserveTokenSyncUseCase
|
||||
import com.tangem.domain.assetsdiscovery.model.AssetsDiscoveryProgress
|
||||
import com.tangem.domain.assetsdiscovery.usecase.ObserveAssetsDiscoveryUseCase
|
||||
import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase
|
||||
import com.tangem.feature.wallet.child.wallet.model.WalletActivationBannerType
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
|
|
@ -61,7 +61,7 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
|
|||
private val shouldShowUpgradeHotWalletBannerUseCase: ShouldShowUpgradeHotWalletBannerUseCase,
|
||||
private val getUpgradeBannerClosureTimestampUseCase: GetUpgradeBannerClosureTimestampUseCase,
|
||||
private val checkHotWalletUpgradeBannerUseCase: CheckHotWalletUpgradeBannerUseCase,
|
||||
private val observeTokenSyncUseCase: ObserveTokenSyncUseCase,
|
||||
private val observeAssetsDiscoveryUseCase: ObserveAssetsDiscoveryUseCase,
|
||||
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
||||
) {
|
||||
|
||||
|
|
@ -71,11 +71,12 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
|
|||
val params = SingleAccountStatusListProducer.Params(userWallet.walletId)
|
||||
val accountStatusListFlow = accountDependencies.singleAccountStatusListSupplier(params)
|
||||
|
||||
val tokenSyncProgressFlow = if (hotWalletFeatureToggles.isTokenSyncEnabled && userWallet is UserWallet.Hot) {
|
||||
observeTokenSyncUseCase(userWallet.walletId).distinctUntilChanged()
|
||||
} else {
|
||||
flowOf(TokenSyncProgress.Idle)
|
||||
}
|
||||
val assetsDiscoveryProgressFlow =
|
||||
if (hotWalletFeatureToggles.isAssetsDiscoveryEnabled && userWallet is UserWallet.Hot) {
|
||||
observeAssetsDiscoveryUseCase(userWallet.walletId).distinctUntilChanged()
|
||||
} else {
|
||||
flowOf(AssetsDiscoveryProgress.Idle)
|
||||
}
|
||||
|
||||
return combine(
|
||||
accountStatusListFlow,
|
||||
|
|
@ -92,7 +93,7 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
|
|||
.distinctUntilChanged(),
|
||||
getUpgradeBannerClosureTimestampUseCase(userWallet.walletId)
|
||||
.distinctUntilChanged(),
|
||||
tokenSyncProgressFlow,
|
||||
assetsDiscoveryProgressFlow,
|
||||
) { array -> array }
|
||||
.map { array ->
|
||||
val accountStatusList = array[0] as AccountStatusList
|
||||
|
|
@ -104,7 +105,7 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
|
|||
val shouldShowYieldPromo = array[6] as Boolean
|
||||
val shouldShowUpgradeBanner = array[7] as Boolean
|
||||
val closureTimestamp = array[8] as? Long
|
||||
val tokenSyncProgress = array[9] as TokenSyncProgress
|
||||
val assetsDiscoveryProgress = array[9] as AssetsDiscoveryProgress
|
||||
|
||||
val flattenCurrencies = accountStatusList.flattenCurrencies()
|
||||
val paymentAccountStatus = accountStatusList.accountStatuses
|
||||
|
|
@ -149,9 +150,9 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
|
|||
clickIntents = clickIntents,
|
||||
)
|
||||
|
||||
addTokenSyncCompletedNotification(
|
||||
addAssetsDiscoveryCompletedNotification(
|
||||
userWallet = userWallet,
|
||||
tokenSyncProgress = tokenSyncProgress,
|
||||
assetsDiscoveryProgress = assetsDiscoveryProgress,
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
|
||||
|
|
@ -208,7 +209,6 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
|
|||
is PaymentAccountStatusValue.IssuingCard,
|
||||
is PaymentAccountStatusValue.Loaded,
|
||||
is PaymentAccountStatusValue.Loading,
|
||||
is PaymentAccountStatusValue.Locked,
|
||||
is PaymentAccountStatusValue.UnderReview,
|
||||
is PaymentAccountStatusValue.Empty,
|
||||
is PaymentAccountStatusValue.Deactivated,
|
||||
|
|
@ -402,17 +402,17 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
|
|||
// }
|
||||
// }
|
||||
|
||||
private fun MutableList<WalletNotification>.addTokenSyncCompletedNotification(
|
||||
private fun MutableList<WalletNotification>.addAssetsDiscoveryCompletedNotification(
|
||||
userWallet: UserWallet,
|
||||
tokenSyncProgress: TokenSyncProgress,
|
||||
assetsDiscoveryProgress: AssetsDiscoveryProgress,
|
||||
clickIntents: WalletClickIntents,
|
||||
) {
|
||||
addIf(
|
||||
element = WalletNotification.TokenSyncCompleted(
|
||||
onCloseClick = { clickIntents.onDismissTokenSyncNotification(userWallet.walletId) },
|
||||
onManageTokensClick = { clickIntents.onTokenSyncManageClick(userWallet.walletId) },
|
||||
element = WalletNotification.AssetsDiscoveryCompleted(
|
||||
onCloseClick = { clickIntents.onDismissAssetsDiscoveryNotification(userWallet.walletId) },
|
||||
onManageTokensClick = { clickIntents.onAssetsDiscoveryManageClick(userWallet.walletId) },
|
||||
),
|
||||
condition = tokenSyncProgress is TokenSyncProgress.Completed,
|
||||
condition = assetsDiscoveryProgress is AssetsDiscoveryProgress.Completed,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -237,7 +237,6 @@ internal class GetWalletNotificationsFactory @Inject constructor(
|
|||
is PaymentAccountStatusValue.IssuingCard,
|
||||
is PaymentAccountStatusValue.Loaded,
|
||||
is PaymentAccountStatusValue.Loading,
|
||||
is PaymentAccountStatusValue.Locked,
|
||||
is PaymentAccountStatusValue.UnderReview,
|
||||
is PaymentAccountStatusValue.Empty,
|
||||
is PaymentAccountStatusValue.Deactivated,
|
||||
|
|
|
|||
|
|
@ -354,7 +354,7 @@ internal enum class Wallet2CobrandImage(
|
|||
WinterSakura(
|
||||
cards2ResId = R.drawable.ill_winter_sakura_card2_120_106,
|
||||
cards3ResId = R.drawable.ill_winter_sakura_card3_120_106,
|
||||
batchIds = setOf("AF990053", "AF990054", "AF990055"),
|
||||
batchIds = setOf("AF990053", "AF990054", "AF990055", "AF990074", "AF990075", "AF990076"),
|
||||
),
|
||||
|
||||
LockedMoney(
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import com.tangem.domain.card.common.util.cardTypesResolver
|
|||
import com.tangem.domain.card.common.util.getCardsCount
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TokenSyncProgressUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.AssetsDiscoveryProgressUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAdditionalInfo
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ internal object WalletAdditionalInfoFactory {
|
|||
fun resolve(
|
||||
wallet: UserWallet,
|
||||
currencyAmount: BigDecimal? = null,
|
||||
syncProgress: TokenSyncProgressUM = TokenSyncProgressUM.Idle,
|
||||
syncProgress: AssetsDiscoveryProgressUM = AssetsDiscoveryProgressUM.Idle,
|
||||
): WalletAdditionalInfo {
|
||||
return when (wallet) {
|
||||
is UserWallet.Cold -> {
|
||||
|
|
@ -46,8 +46,8 @@ internal object WalletAdditionalInfoFactory {
|
|||
}
|
||||
}
|
||||
|
||||
private fun UserWallet.Hot.resolveAdditionalInfo(syncProgress: TokenSyncProgressUM): WalletAdditionalInfo {
|
||||
val content = if (syncProgress is TokenSyncProgressUM.InProgress) {
|
||||
private fun UserWallet.Hot.resolveAdditionalInfo(syncProgress: AssetsDiscoveryProgressUM): WalletAdditionalInfo {
|
||||
val content = if (syncProgress is AssetsDiscoveryProgressUM.InProgress) {
|
||||
WalletAdditionalInfo.Content.SyncProgress(syncProgress.progressPercent)
|
||||
} else {
|
||||
WalletAdditionalInfo.Content.Text(
|
||||
|
|
|
|||
|
|
@ -2,16 +2,15 @@ package com.tangem.feature.wallet.presentation.wallet.domain
|
|||
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.tokens.wallet.WalletBalanceFetcher
|
||||
import com.tangem.features.tangempay.TangemPayFeatureToggles
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveInAndJoin
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
|
@ -28,7 +27,6 @@ import javax.inject.Singleton
|
|||
internal class WalletContentFetcher @Inject constructor(
|
||||
private val walletBalanceFetcher: WalletBalanceFetcher,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val tangemPayFeatureToggles: TangemPayFeatureToggles,
|
||||
) {
|
||||
|
||||
private val fetchingJobMap = ConcurrentHashMap<UserWalletId, JobHolder>()
|
||||
|
|
@ -66,12 +64,8 @@ internal class WalletContentFetcher @Inject constructor(
|
|||
TangemLogger.d("Start fetching for $userWalletId")
|
||||
|
||||
val maybeResult = launch {
|
||||
walletBalanceFetcher(
|
||||
params = WalletBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
isPaymentAccountRefactorEnabled = tangemPayFeatureToggles.isTangemPayAccountsRefactorEnabled,
|
||||
),
|
||||
).onLeft { TangemLogger.e("Error", it) }
|
||||
walletBalanceFetcher(params = WalletBalanceFetcher.Params(userWalletId = userWalletId))
|
||||
.onLeft { TangemLogger.e("Error", it) }
|
||||
}
|
||||
.saveInAndJoin(jobHolder)
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ internal class MultiWalletContentLoader @AssistedInject constructor(
|
|||
private val walletNotificationsSubscriberFactory: WalletNotificationsSubscriber.Factory,
|
||||
private val multiWalletActionButtonsSubscriberFactory: MultiWalletActionButtonsSubscriber.Factory,
|
||||
private val tangemPayMainSubscriberFactory: TangemPayMainSubscriber.Factory,
|
||||
private val tokenSyncSubscriberFactory: TokenSyncSubscriber.Factory,
|
||||
private val assetsDiscoverySubscriberFactory: AssetsDiscoverySubscriber.Factory,
|
||||
private val tokenListAnalyticsSubscriberFactory: TokenListAnalyticsSubscriber.Factory,
|
||||
private val designFeatureToggles: DesignFeatureToggles,
|
||||
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
||||
|
|
@ -36,8 +36,8 @@ internal class MultiWalletContentLoader @AssistedInject constructor(
|
|||
multiWalletActionButtonsSubscriberFactory.create(userWallet),
|
||||
tangemPayMainSubscriberFactory.create(userWallet),
|
||||
tokenListAnalyticsSubscriberFactory.create(userWallet),
|
||||
if (hotWalletFeatureToggles.isTokenSyncEnabled && userWallet is UserWallet.Hot) {
|
||||
tokenSyncSubscriberFactory.create(userWallet)
|
||||
if (hotWalletFeatureToggles.isAssetsDiscoveryEnabled && userWallet is UserWallet.Hot) {
|
||||
assetsDiscoverySubscriberFactory.create(userWallet)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.model
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
|
||||
@Immutable
|
||||
internal sealed class AssetsDiscoveryProgressUM {
|
||||
|
||||
data object Idle : AssetsDiscoveryProgressUM()
|
||||
|
||||
data class InProgress(val progressPercent: Int) : AssetsDiscoveryProgressUM()
|
||||
|
||||
data object Completed : AssetsDiscoveryProgressUM()
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.model
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
@Immutable
|
||||
internal sealed class TangemPayState {
|
||||
|
||||
object Empty : TangemPayState()
|
||||
|
||||
data object Loading : TangemPayState()
|
||||
|
||||
data class OnboardingBanner(
|
||||
val onClick: () -> Unit,
|
||||
val closeOnClick: () -> Unit,
|
||||
) : TangemPayState()
|
||||
|
||||
data class Progress(
|
||||
val title: TextReference,
|
||||
val description: TextReference,
|
||||
val buttonText: TextReference,
|
||||
@DrawableRes val iconRes: Int,
|
||||
val onButtonClick: () -> Unit,
|
||||
val showProgress: Boolean = false,
|
||||
) : TangemPayState()
|
||||
|
||||
data class FailedIssue(
|
||||
val title: TextReference,
|
||||
val description: TextReference,
|
||||
@DrawableRes val iconRes: Int,
|
||||
val onButtonClick: () -> Unit,
|
||||
) : TangemPayState()
|
||||
|
||||
data class Card(
|
||||
val lastFourDigits: TextReference,
|
||||
val balanceText: TextReference,
|
||||
val balanceSymbol: TextReference,
|
||||
val onClick: () -> Unit,
|
||||
) : TangemPayState()
|
||||
|
||||
data class RefreshNeeded(
|
||||
val notification: WalletNotification,
|
||||
) : TangemPayState()
|
||||
|
||||
data class TemporaryUnavailable(val notification: WalletNotification) : TangemPayState()
|
||||
|
||||
data object ExposedDevice : TangemPayState()
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.model
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
|
||||
@Immutable
|
||||
internal sealed class TokenSyncProgressUM {
|
||||
|
||||
data object Idle : TokenSyncProgressUM()
|
||||
|
||||
data class InProgress(val progressPercent: Int) : TokenSyncProgressUM()
|
||||
|
||||
data object Completed : TokenSyncProgressUM()
|
||||
}
|
||||
|
|
@ -28,6 +28,9 @@ internal sealed interface WalletBalanceUM {
|
|||
/** Wallet Icon */
|
||||
val deviceIcon: DeviceIconUM
|
||||
|
||||
/** Wallet additional info (e.g. card count, sync progress) */
|
||||
val additionalInfo: WalletAdditionalInfo?
|
||||
|
||||
/**
|
||||
* Wallet card content state
|
||||
*
|
||||
|
|
@ -39,6 +42,7 @@ internal sealed interface WalletBalanceUM {
|
|||
override val id: UserWalletId,
|
||||
override val name: String,
|
||||
override val deviceIcon: DeviceIconUM,
|
||||
override val additionalInfo: WalletAdditionalInfo? = null,
|
||||
val balance: TextReference,
|
||||
val balanceInAppBar: TextReference,
|
||||
val isBalanceFlickering: Boolean,
|
||||
|
|
@ -55,6 +59,7 @@ internal sealed interface WalletBalanceUM {
|
|||
override val id: UserWalletId,
|
||||
override val name: String,
|
||||
override val deviceIcon: DeviceIconUM,
|
||||
override val additionalInfo: WalletAdditionalInfo? = null,
|
||||
) : WalletBalanceUM
|
||||
|
||||
/**
|
||||
|
|
@ -67,6 +72,7 @@ internal sealed interface WalletBalanceUM {
|
|||
override val id: UserWalletId,
|
||||
override val name: String,
|
||||
override val deviceIcon: DeviceIconUM,
|
||||
override val additionalInfo: WalletAdditionalInfo? = null,
|
||||
) : WalletBalanceUM
|
||||
|
||||
/**
|
||||
|
|
@ -79,14 +85,18 @@ internal sealed interface WalletBalanceUM {
|
|||
override val id: UserWalletId,
|
||||
override val name: String,
|
||||
override val deviceIcon: DeviceIconUM,
|
||||
override val additionalInfo: WalletAdditionalInfo? = null,
|
||||
) : WalletBalanceUM
|
||||
|
||||
fun copySealed(name: String): WalletBalanceUM {
|
||||
fun copySealed(
|
||||
name: String = this.name,
|
||||
additionalInfo: WalletAdditionalInfo? = this.additionalInfo,
|
||||
): WalletBalanceUM {
|
||||
return when (this) {
|
||||
is Content -> copy(name = name)
|
||||
is Error -> copy(name = name)
|
||||
is Loading -> copy(name = name)
|
||||
is Empty -> copy(name = name)
|
||||
is Content -> copy(name = name, additionalInfo = additionalInfo)
|
||||
is Error -> copy(name = name, additionalInfo = additionalInfo)
|
||||
is Loading -> copy(name = name, additionalInfo = additionalInfo)
|
||||
is Empty -> copy(name = name, additionalInfo = additionalInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -50,6 +50,9 @@ internal sealed interface WalletDialogConfig {
|
|||
@Serializable
|
||||
data class KycRejected(val walletId: UserWalletId, val customerId: String) : WalletDialogConfig
|
||||
|
||||
@Serializable
|
||||
data class AddAndManage(val userWalletId: UserWalletId) : WalletDialogConfig
|
||||
|
||||
@Serializable
|
||||
data class OrganizeTokens(val userWalletId: UserWalletId) : WalletDialogConfig
|
||||
|
||||
|
|
|
|||
|
|
@ -435,7 +435,7 @@ sealed class WalletNotification(val config: NotificationConfig) {
|
|||
),
|
||||
)
|
||||
|
||||
data class TokenSyncCompleted(
|
||||
data class AssetsDiscoveryCompleted(
|
||||
val onCloseClick: () -> Unit,
|
||||
val onManageTokensClick: () -> Unit,
|
||||
) : WalletNotification(
|
||||
|
|
|
|||
|
|
@ -24,10 +24,8 @@ internal sealed interface WalletState : WalletStateHolder {
|
|||
abstract val tokensListState: WalletTokensListState
|
||||
abstract val nftState: WalletNFTItemUM
|
||||
abstract val type: WalletType
|
||||
abstract val tangemPayState: TangemPayState
|
||||
abstract val tangemPayMainUM: TangemPayMainUM
|
||||
abstract val isTangemPayRefactorEnabled: Boolean // TANGEM_PAY_ACCOUNTS_REFACTOR_ENABLED
|
||||
abstract val tokenSyncProgressUM: TokenSyncProgressUM
|
||||
abstract val assetsDiscoveryProgressUM: AssetsDiscoveryProgressUM
|
||||
|
||||
data class Content(
|
||||
override val pullToRefreshConfig: PullToRefreshConfig,
|
||||
|
|
@ -38,10 +36,8 @@ internal sealed interface WalletState : WalletStateHolder {
|
|||
override val tokensListState: WalletTokensListState,
|
||||
override val nftState: WalletNFTItemUM,
|
||||
override val type: WalletType,
|
||||
override val tangemPayState: TangemPayState,
|
||||
override val tangemPayMainUM: TangemPayMainUM,
|
||||
override val isTangemPayRefactorEnabled: Boolean,
|
||||
override val tokenSyncProgressUM: TokenSyncProgressUM = TokenSyncProgressUM.Idle,
|
||||
override val assetsDiscoveryProgressUM: AssetsDiscoveryProgressUM = AssetsDiscoveryProgressUM.Idle,
|
||||
) : MultiCurrency()
|
||||
|
||||
data class Locked(
|
||||
|
|
@ -60,10 +56,8 @@ internal sealed interface WalletState : WalletStateHolder {
|
|||
|
||||
override val tokensListState = WalletTokensListState.ContentState.Locked
|
||||
override val nftState: WalletNFTItemUM = WalletNFTItemUM.Hidden
|
||||
override val tangemPayState: TangemPayState = TangemPayState.Empty
|
||||
override val tangemPayMainUM: TangemPayMainUM = TangemPayMainUM.Empty
|
||||
override val isTangemPayRefactorEnabled: Boolean = false
|
||||
override val tokenSyncProgressUM: TokenSyncProgressUM = TokenSyncProgressUM.Idle
|
||||
override val assetsDiscoveryProgressUM: AssetsDiscoveryProgressUM = AssetsDiscoveryProgressUM.Idle
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,5 +49,10 @@ internal sealed class WalletTokensListState {
|
|||
}
|
||||
}
|
||||
|
||||
data class OrganizeTokensButtonConfig(val isEnabled: Boolean, val onClick: () -> Unit)
|
||||
data class OrganizeTokensButtonConfig(
|
||||
val textRes: Int,
|
||||
val iconRes: Int,
|
||||
val isEnabled: Boolean,
|
||||
val onClick: () -> Unit,
|
||||
)
|
||||
}
|
||||
|
|
@ -13,7 +13,6 @@ internal class AddWalletTransformer(
|
|||
private val clickIntents: WalletClickIntents,
|
||||
private val walletImageResolver: WalletImageResolver,
|
||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||
private val isTangemPayRefactorEnabled: Boolean,
|
||||
) : WalletScreenStateTransformer {
|
||||
|
||||
private val walletLoadingStateFactory by lazy {
|
||||
|
|
@ -21,7 +20,6 @@ internal class AddWalletTransformer(
|
|||
clickIntents = clickIntents,
|
||||
walletImageResolver = walletImageResolver,
|
||||
getWalletIconUseCase = getWalletIconUseCase,
|
||||
isTangemPayRefactorEnabled = isTangemPayRefactorEnabled,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@ internal class InitializeWalletsTransformer(
|
|||
private val clickIntents: WalletClickIntents,
|
||||
private val walletImageResolver: WalletImageResolver,
|
||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||
private val isMainScreenQrScanningEnabled: Boolean = false,
|
||||
private val isTangemPayRefactorEnabled: Boolean,
|
||||
) : WalletScreenStateTransformer {
|
||||
|
||||
private val walletLoadingStateFactory by lazy {
|
||||
|
|
@ -36,7 +34,6 @@ internal class InitializeWalletsTransformer(
|
|||
clickIntents = clickIntents,
|
||||
walletImageResolver = walletImageResolver,
|
||||
getWalletIconUseCase = getWalletIconUseCase,
|
||||
isTangemPayRefactorEnabled = isTangemPayRefactorEnabled,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -65,15 +62,11 @@ internal class InitializeWalletsTransformer(
|
|||
|
||||
private fun createTopBarConfig(): WalletTopBarConfig {
|
||||
return WalletTopBarConfig(
|
||||
endActions = listOfNotNull(
|
||||
if (isMainScreenQrScanningEnabled) {
|
||||
TangemTopBarActionUM(
|
||||
iconRes = CoreUiR.drawable.ic_qrcode_scaner_24,
|
||||
onClick = clickIntents::onScanQrClick,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
endActions = listOf(
|
||||
TangemTopBarActionUM(
|
||||
iconRes = CoreUiR.drawable.ic_qrcode_scaner_24,
|
||||
onClick = clickIntents::onScanQrClick,
|
||||
),
|
||||
TangemTopBarActionUM(
|
||||
iconRes = CoreUiR.drawable.ic_more_default_24,
|
||||
onClick = clickIntents::onDetailsClick,
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ internal class ReinitializeNewWalletTransformer(
|
|||
private val clickIntents: WalletClickIntents,
|
||||
private val walletImageResolver: WalletImageResolver,
|
||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||
private val isTangemPayRefactorEnabled: Boolean,
|
||||
) : WalletScreenStateTransformer {
|
||||
|
||||
private val walletLoadingStateFactory by lazy {
|
||||
|
|
@ -32,7 +31,6 @@ internal class ReinitializeNewWalletTransformer(
|
|||
clickIntents = clickIntents,
|
||||
walletImageResolver = walletImageResolver,
|
||||
getWalletIconUseCase = getWalletIconUseCase,
|
||||
isTangemPayRefactorEnabled = isTangemPayRefactorEnabled,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ internal class ReinitializeWalletTransformer(
|
|||
private val clickIntents: WalletClickIntents,
|
||||
private val walletImageResolver: WalletImageResolver,
|
||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||
private val isTangemPayRefactorEnabled: Boolean,
|
||||
) : WalletStateTransformer(userWalletId = userWallet.walletId) {
|
||||
|
||||
private val walletLoadingStateFactory by lazy {
|
||||
|
|
@ -28,7 +27,6 @@ internal class ReinitializeWalletTransformer(
|
|||
clickIntents = clickIntents,
|
||||
walletImageResolver = walletImageResolver,
|
||||
getWalletIconUseCase = getWalletIconUseCase,
|
||||
isTangemPayRefactorEnabled = isTangemPayRefactorEnabled,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,27 +2,35 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
|||
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TokenSyncProgressUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.AssetsDiscoveryProgressUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
|
||||
|
||||
internal class SetTokenSyncProgressTransformer(
|
||||
internal class SetAssetsDiscoveryProgressTransformer(
|
||||
private val userWallet: UserWallet,
|
||||
private val progress: TokenSyncProgressUM,
|
||||
private val progress: AssetsDiscoveryProgressUM,
|
||||
) : WalletStateTransformer(userWallet.walletId) {
|
||||
|
||||
override fun transform(prevState: WalletState): WalletState {
|
||||
return when (prevState) {
|
||||
is WalletState.MultiCurrency.Content -> prevState.copy(
|
||||
walletCardState = updateCardState(prevState.walletCardState),
|
||||
tokenSyncProgressUM = progress,
|
||||
assetsDiscoveryProgressUM = progress,
|
||||
)
|
||||
else -> prevState
|
||||
}
|
||||
}
|
||||
|
||||
override fun transform(walletUM: WalletUM): WalletUM = walletUM
|
||||
override fun transform(walletUM: WalletUM): WalletUM {
|
||||
val additionalInfo = WalletAdditionalInfoFactory.resolve(wallet = userWallet, syncProgress = progress)
|
||||
return when (walletUM) {
|
||||
is WalletUM.Content -> walletUM.copy(
|
||||
walletsBalanceUM = walletUM.walletsBalanceUM.copySealed(additionalInfo = additionalInfo),
|
||||
)
|
||||
is WalletUM.Locked -> walletUM
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateCardState(cardState: WalletCardState): WalletCardState {
|
||||
val additionalInfo = WalletAdditionalInfoFactory.resolve(wallet = userWallet, syncProgress = progress)
|
||||
|
|
@ -61,7 +61,7 @@ internal class SetTokenListErrorTransformer(
|
|||
walletsBalanceUM = walletUM.walletsBalanceUM.toLoadedState(),
|
||||
tokensListUM = WalletTokensListUM.Empty(
|
||||
onEmptyClick = {
|
||||
clickIntents.onTokenSyncManageClick(walletUM.walletsBalanceUM.id)
|
||||
clickIntents.onAssetsDiscoveryManageClick(walletUM.walletsBalanceUM.id)
|
||||
},
|
||||
),
|
||||
buttons = walletUM.disableButtons(),
|
||||
|
|
@ -98,6 +98,7 @@ internal class SetTokenListErrorTransformer(
|
|||
id = id,
|
||||
name = name,
|
||||
deviceIcon = deviceIcon,
|
||||
additionalInfo = additionalInfo,
|
||||
balanceInAppBar = BigDecimal.ZERO.formatStyled {
|
||||
fiat(
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ internal class SetTokenListTransformer(
|
|||
private val shouldShowMainPromo: Boolean,
|
||||
private val isAccountsModeEnabled: Boolean,
|
||||
private val isRedesignEnabled: Boolean,
|
||||
private val isAddAndManageTokensEnabled: Boolean,
|
||||
) : WalletStateTransformer(userWallet.walletId) {
|
||||
|
||||
private val tangemPayConverter by lazy {
|
||||
|
|
@ -105,6 +106,7 @@ internal class SetTokenListTransformer(
|
|||
yieldModuleApyMap = yieldSupplyApyMap,
|
||||
stakingAvailabilityMap = stakingAvailabilityMap,
|
||||
shouldShowMainPromo = shouldShowMainPromo,
|
||||
isAddAndManageTokensEnabled = isAddAndManageTokensEnabled,
|
||||
).convert(value = this)
|
||||
}
|
||||
|
||||
|
|
@ -123,7 +125,7 @@ internal class SetTokenListTransformer(
|
|||
if (params !is TokenConverterParams.Account) {
|
||||
return WalletTokensListUM.Empty(
|
||||
onEmptyClick = {
|
||||
clickIntents.onTokenSyncManageClick(userWallet.walletId)
|
||||
clickIntents.onAssetsDiscoveryManageClick(userWallet.walletId)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -137,6 +139,7 @@ internal class SetTokenListTransformer(
|
|||
shouldShowMainPromo = shouldShowMainPromo,
|
||||
isAccountsModeEnabled = isAccountsModeEnabled,
|
||||
expandedAccounts = params.expandedAccounts,
|
||||
isAddAndManageTokensEnabled = isAddAndManageTokensEnabled,
|
||||
).convert(value = params.accountList)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
||||
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
|
||||
|
||||
internal class TangemPayExposedDeviceTransformer(
|
||||
userWalletId: UserWalletId,
|
||||
) : WalletStateTransformer(userWalletId) {
|
||||
override fun transform(prevState: WalletState): WalletState {
|
||||
return if (prevState is WalletState.MultiCurrency.Content) {
|
||||
prevState.copy(tangemPayState = TangemPayState.ExposedDevice)
|
||||
} else {
|
||||
prevState
|
||||
}
|
||||
}
|
||||
|
||||
override fun transform(walletUM: WalletUM): WalletUM {
|
||||
return walletUM // todo redesign main
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
||||
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
|
||||
|
||||
internal class TangemPayHiddenStateTransformer(
|
||||
userWalletId: UserWalletId,
|
||||
) : WalletStateTransformer(userWalletId) {
|
||||
|
||||
override fun transform(prevState: WalletState): WalletState {
|
||||
return if (prevState is WalletState.MultiCurrency.Content) {
|
||||
prevState.copy(tangemPayState = TangemPayState.Empty)
|
||||
} else {
|
||||
prevState
|
||||
}
|
||||
}
|
||||
|
||||
override fun transform(walletUM: WalletUM): WalletUM {
|
||||
return walletUM // todo redesign main
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
||||
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
|
||||
import com.tangem.features.tangempay.entity.TangemPayMainUM
|
||||
|
|
@ -12,7 +11,7 @@ internal class TangemPayHideOnboardingStateTransformer(
|
|||
|
||||
override fun transform(prevState: WalletState): WalletState {
|
||||
return if (prevState is WalletState.MultiCurrency.Content) {
|
||||
prevState.copy(tangemPayState = TangemPayState.Empty, tangemPayMainUM = TangemPayMainUM.Empty)
|
||||
prevState.copy(tangemPayMainUM = TangemPayMainUM.Empty)
|
||||
} else {
|
||||
prevState
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
||||
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
|
||||
|
||||
internal class TangemPayLoadingStateTransformer(userWalletId: UserWalletId) : WalletStateTransformer(userWalletId) {
|
||||
override fun transform(prevState: WalletState): WalletState {
|
||||
return if (prevState is WalletState.MultiCurrency.Content) {
|
||||
prevState.copy(tangemPayState = TangemPayState.Loading)
|
||||
} else {
|
||||
prevState
|
||||
}
|
||||
}
|
||||
|
||||
override fun transform(walletUM: WalletUM): WalletUM {
|
||||
return walletUM // todo redesign main
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
||||
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
|
||||
|
||||
internal class TangemPayOnboardingBannerStateTransformer(
|
||||
userWalletId: UserWalletId,
|
||||
private val onClick: (UserWalletId) -> Unit,
|
||||
private val closeOnClick: (UserWalletId) -> Unit,
|
||||
) : WalletStateTransformer(userWalletId) {
|
||||
|
||||
override fun transform(prevState: WalletState): WalletState {
|
||||
return if (prevState is WalletState.MultiCurrency.Content) {
|
||||
prevState.copy(
|
||||
tangemPayState = TangemPayState.OnboardingBanner(
|
||||
onClick = { onClick(userWalletId) },
|
||||
closeOnClick = { closeOnClick(userWalletId) },
|
||||
),
|
||||
)
|
||||
} else {
|
||||
prevState
|
||||
}
|
||||
}
|
||||
|
||||
override fun transform(walletUM: WalletUM): WalletUM {
|
||||
return walletUM // todo redesign main
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
||||
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification.Warning.TangemPayRefreshNeeded
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
|
||||
|
||||
internal class TangemPayRefreshNeededStateTransformer(
|
||||
userWalletId: UserWalletId,
|
||||
private val userWallet: UserWallet,
|
||||
private val onRefreshClick: () -> Unit,
|
||||
) : WalletStateTransformer(userWalletId = userWalletId) {
|
||||
|
||||
override fun transform(prevState: WalletState): WalletState {
|
||||
val tangemPayState = TangemPayState.RefreshNeeded(
|
||||
notification = TangemPayRefreshNeeded(
|
||||
buttonText = when (userWallet) {
|
||||
is UserWallet.Cold -> resourceReference(id = R.string.home_button_scan)
|
||||
is UserWallet.Hot -> resourceReference(id = R.string.tangempay_sync_needed_restore_access)
|
||||
},
|
||||
onRefreshClick = onRefreshClick,
|
||||
shouldShowProgress = false,
|
||||
),
|
||||
)
|
||||
return if (prevState is WalletState.MultiCurrency.Content) {
|
||||
prevState.copy(tangemPayState = tangemPayState)
|
||||
} else {
|
||||
prevState
|
||||
}
|
||||
}
|
||||
|
||||
override fun transform(walletUM: WalletUM): WalletUM {
|
||||
return walletUM // todo redesign main
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
||||
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
|
||||
|
|
@ -14,9 +13,6 @@ internal class TangemPayRefreshShowProgressTransformer(
|
|||
|
||||
override fun transform(prevState: WalletState): WalletState {
|
||||
val multiContentState = prevState as? WalletState.MultiCurrency.Content ?: return prevState
|
||||
val refreshNeededState = multiContentState.tangemPayState as? TangemPayState.RefreshNeeded ?: return prevState
|
||||
val refreshNotification =
|
||||
refreshNeededState.notification as? WalletNotification.Warning.TangemPayRefreshNeeded ?: return prevState
|
||||
val newWarnings = prevState.warnings.map { warning ->
|
||||
if (warning is WalletNotification.Warning.TangemPayRefreshNeeded) {
|
||||
warning.copy(shouldShowProgress = shouldShowProgress)
|
||||
|
|
@ -25,12 +21,7 @@ internal class TangemPayRefreshShowProgressTransformer(
|
|||
}
|
||||
}
|
||||
|
||||
return multiContentState.copy(
|
||||
tangemPayState = refreshNeededState.copy(
|
||||
notification = refreshNotification.copy(shouldShowProgress = shouldShowProgress),
|
||||
),
|
||||
warnings = newWarnings.toImmutableList(),
|
||||
)
|
||||
return multiContentState.copy(warnings = newWarnings.toImmutableList())
|
||||
}
|
||||
|
||||
override fun transform(walletUM: WalletUM): WalletUM {
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
||||
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
|
||||
|
||||
internal class TangemPayUnavailableStateTransformer(
|
||||
userWalletId: UserWalletId,
|
||||
) : WalletStateTransformer(userWalletId) {
|
||||
|
||||
override fun transform(prevState: WalletState): WalletState {
|
||||
return if (prevState is WalletState.MultiCurrency.Content) {
|
||||
prevState.copy(
|
||||
tangemPayState = TangemPayState.TemporaryUnavailable(
|
||||
notification = WalletNotification.Warning.TangemPayUnreachable,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
prevState
|
||||
}
|
||||
}
|
||||
|
||||
override fun transform(walletUM: WalletUM): WalletUM {
|
||||
return walletUM // todo redesign main
|
||||
}
|
||||
}
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
||||
|
||||
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.domain.models.kyc.KycStatus
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.TangemPayDetailsConfig
|
||||
import com.tangem.domain.pay.model.CustomerInfo.CardInfo
|
||||
import com.tangem.domain.pay.model.CustomerInfo.ProductInstance
|
||||
import com.tangem.domain.pay.model.MainScreenCustomerInfo
|
||||
import com.tangem.domain.pay.model.OrderStatus
|
||||
import com.tangem.domain.visa.model.TangemPayCardFrozenState
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.TangemPayIntents
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState.Progress
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
|
||||
import java.util.Currency
|
||||
|
||||
/**
|
||||
* Hardcode Polygon chain id only for F&F.
|
||||
* Later chain id will be fetched from BFF.
|
||||
*/
|
||||
private const val POLYGON_CHAIN_ID = 137
|
||||
|
||||
internal class TangemPayUpdateInfoStateTransformer(
|
||||
userWalletId: UserWalletId,
|
||||
private val value: MainScreenCustomerInfo,
|
||||
private val cardFrozenState: TangemPayCardFrozenState,
|
||||
private val tangemPayClickIntents: TangemPayIntents,
|
||||
) : WalletStateTransformer(userWalletId = userWalletId) {
|
||||
|
||||
override fun transform(prevState: WalletState): WalletState {
|
||||
val tangemPayState = createInitialState()
|
||||
return if (prevState is WalletState.MultiCurrency.Content) {
|
||||
prevState.copy(tangemPayState = tangemPayState)
|
||||
} else {
|
||||
prevState
|
||||
}
|
||||
}
|
||||
|
||||
override fun transform(walletUM: WalletUM): WalletUM {
|
||||
return walletUM // todo redesign main
|
||||
}
|
||||
|
||||
private fun createInitialState(): TangemPayState {
|
||||
val cardInfo = value.info.cardInfo
|
||||
val productInstance = value.info.productInstance
|
||||
val customerId = value.info.customerId ?: "Unknown"
|
||||
|
||||
// when statement copied to WalletTangemPayAnalyticsEventSender. Be careful when editing.
|
||||
return when {
|
||||
value.info.kycStatus != KycStatus.APPROVED && !value.info.customerId.isNullOrEmpty() ->
|
||||
createKycInProgressState(kycStatus = value.info.kycStatus, customerId = customerId)
|
||||
value.orderStatus == OrderStatus.CANCELED -> createCancelledState(customerId)
|
||||
cardInfo != null && productInstance != null && value.orderStatus == OrderStatus.COMPLETED ->
|
||||
getCardInfoState(customerId, cardInfo, productInstance)
|
||||
else -> createIssueProgressState()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCardInfoState(
|
||||
customerId: String,
|
||||
cardInfo: CardInfo,
|
||||
productInstance: ProductInstance,
|
||||
): TangemPayState = TangemPayState.Card(
|
||||
lastFourDigits = TextReference.Str("*${cardInfo.lastFourDigits}"),
|
||||
balanceText = TextReference.Str(getBalanceText(cardInfo)),
|
||||
balanceSymbol = stringReference("USDC"), // TODO hardcode for now
|
||||
onClick = {
|
||||
tangemPayClickIntents.openDetails(
|
||||
userWalletId,
|
||||
TangemPayDetailsConfig(
|
||||
customerId = customerId,
|
||||
cardId = productInstance.cardId,
|
||||
isPinSet = cardInfo.isPinSet,
|
||||
cardFrozenState = cardFrozenState,
|
||||
cardNumberEnd = cardInfo.lastFourDigits,
|
||||
chainId = POLYGON_CHAIN_ID,
|
||||
isTangemPayDeactivated = false,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
private fun getBalanceText(cardInfo: CardInfo): String {
|
||||
val currency = Currency.getInstance(cardInfo.currencyCode)
|
||||
return cardInfo.balance.format {
|
||||
fiat(fiatCurrencyCode = currency.currencyCode, fiatCurrencySymbol = currency.symbol)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createKycInProgressState(kycStatus: KycStatus, customerId: String): TangemPayState = Progress(
|
||||
title = TextReference.Res(R.string.tangempay_payment_account),
|
||||
description = when (kycStatus) {
|
||||
KycStatus.REJECTED -> TextReference.Res(R.string.tangempay_kyc_has_failed)
|
||||
else -> TextReference.Res(R.string.tangempay_kyc_in_progress)
|
||||
},
|
||||
buttonText = TextReference.Res(R.string.tangempay_kyc_in_progress_notification_button),
|
||||
iconRes = R.drawable.ic_promo_kyc_36,
|
||||
onButtonClick = {
|
||||
when (kycStatus) {
|
||||
KycStatus.REJECTED -> tangemPayClickIntents.onKycRejectedClicked(
|
||||
userWalletId = userWalletId,
|
||||
customerId = customerId,
|
||||
)
|
||||
else -> tangemPayClickIntents.onKycProgressClicked(userWalletId)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
private fun createIssueProgressState(): TangemPayState = Progress(
|
||||
title = TextReference.Res(R.string.tangempay_payment_account),
|
||||
description = TextReference.Res(R.string.tangempay_issuing_your_card),
|
||||
buttonText = TextReference.EMPTY,
|
||||
iconRes = R.drawable.ic_tangem_pay_promo_card_36,
|
||||
onButtonClick = tangemPayClickIntents::onIssuingCardClicked,
|
||||
showProgress = true,
|
||||
)
|
||||
|
||||
private fun createCancelledState(customerId: String): TangemPayState = TangemPayState.FailedIssue(
|
||||
title = TextReference.Res(R.string.tangempay_payment_account),
|
||||
description = TextReference.Res(R.string.tangempay_failed_to_issue_card),
|
||||
iconRes = R.drawable.ic_alert_24,
|
||||
onButtonClick = { tangemPayClickIntents.onIssuingFailedClicked(customerId) },
|
||||
)
|
||||
}
|
||||
|
|
@ -9,16 +9,15 @@ import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenSta
|
|||
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.state.utils.WalletLoadingStateFactory
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
|
||||
internal class UnlockWalletTransformer(
|
||||
private val unlockedWallets: List<UserWallet>,
|
||||
private val clickIntents: WalletClickIntents,
|
||||
private val walletImageResolver: WalletImageResolver,
|
||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||
private val isTangemPayRefactorEnabled: Boolean,
|
||||
) : WalletScreenStateTransformer {
|
||||
|
||||
private val walletLoadingStateFactory by lazy {
|
||||
|
|
@ -26,7 +25,6 @@ internal class UnlockWalletTransformer(
|
|||
clickIntents = clickIntents,
|
||||
walletImageResolver = walletImageResolver,
|
||||
getWalletIconUseCase = getWalletIconUseCase,
|
||||
isTangemPayRefactorEnabled = isTangemPayRefactorEnabled,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import com.tangem.domain.card.common.util.getCardsCount
|
|||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TokenSyncProgressUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.AssetsDiscoveryProgressUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
|
||||
|
|
@ -19,7 +19,7 @@ internal class UpdateWalletCardsCountTransformer(
|
|||
return when (prevState) {
|
||||
is WalletState.MultiCurrency.Content -> {
|
||||
prevState.copy(
|
||||
walletCardState = prevState.walletCardState.toUpdatedState(prevState.tokenSyncProgressUM),
|
||||
walletCardState = prevState.walletCardState.toUpdatedState(prevState.assetsDiscoveryProgressUM),
|
||||
)
|
||||
}
|
||||
is WalletState.SingleCurrency.Content -> {
|
||||
|
|
@ -39,7 +39,7 @@ internal class UpdateWalletCardsCountTransformer(
|
|||
}
|
||||
|
||||
private fun WalletCardState.toUpdatedState(
|
||||
syncProgress: TokenSyncProgressUM = TokenSyncProgressUM.Idle,
|
||||
syncProgress: AssetsDiscoveryProgressUM = AssetsDiscoveryProgressUM.Idle,
|
||||
): WalletCardState {
|
||||
return when (this) {
|
||||
is WalletCardState.Content -> copy(
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ internal class MultiWalletBalanceUMTransformer(
|
|||
id = id,
|
||||
name = name,
|
||||
deviceIcon = deviceIcon,
|
||||
additionalInfo = additionalInfo,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -37,6 +38,7 @@ internal class MultiWalletBalanceUMTransformer(
|
|||
id = id,
|
||||
name = name,
|
||||
deviceIcon = deviceIcon,
|
||||
additionalInfo = additionalInfo,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -45,6 +47,7 @@ internal class MultiWalletBalanceUMTransformer(
|
|||
id = id,
|
||||
name = name,
|
||||
deviceIcon = deviceIcon,
|
||||
additionalInfo = additionalInfo,
|
||||
balanceInAppBar = fiatBalance.amount.formatStyled {
|
||||
fiat(
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
|
|
|
|||
|
|
@ -1,17 +1,20 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers.converter
|
||||
|
||||
import com.tangem.common.ui.expressStatus.state.*
|
||||
import com.tangem.common.ui.expressStatus.toActiveStatusText
|
||||
import com.tangem.common.ui.expressStatus.toIconState
|
||||
import com.tangem.common.ui.notifications.ExpressNotificationsUM
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.common.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
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.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.utils.mapFormattedDate
|
||||
import com.tangem.core.ui.utils.toDateFormatWithTodayYesterday
|
||||
import com.tangem.core.ui.utils.toTimeFormat
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
|
|
@ -36,6 +39,7 @@ internal class SingleWalletOnrampTransactionConverter(
|
|||
private val currency = cryptoCurrencyStatus.currency
|
||||
private val status = cryptoCurrencyStatus.value
|
||||
|
||||
@Suppress("LongMethod")
|
||||
override fun convert(value: OnrampTransaction): ExpressTransactionStateUM.OnrampUM {
|
||||
return ExpressTransactionStateUM.OnrampUM(
|
||||
info = ExpressTransactionStateInfoUM(
|
||||
|
|
@ -56,6 +60,8 @@ internal class SingleWalletOnrampTransactionConverter(
|
|||
value.timestamp.toTimeFormat(),
|
||||
),
|
||||
),
|
||||
timestampAgoFormatted = mapFormattedDate(value.timestamp),
|
||||
activeStatus = value.status.toActiveStatusText(currency.name),
|
||||
toAmount = stringReference(value.toAmount.format { crypto(currency) }),
|
||||
toFiatAmount = stringReference(
|
||||
status.fiatRate?.multiply(value.toAmount).format {
|
||||
|
|
@ -81,7 +87,7 @@ internal class SingleWalletOnrampTransactionConverter(
|
|||
url = value.fromCurrency.image,
|
||||
fallbackResId = R.drawable.ic_currency_24,
|
||||
),
|
||||
iconState = getIconState(value.status),
|
||||
iconState = value.status.toIconState(),
|
||||
onGoToProviderClick = { url ->
|
||||
analyticsEventHandler.send(TokenOnrampAnalyticsEvent.GoToProvider())
|
||||
clickIntents.onGoToProviderClick(url)
|
||||
|
|
@ -134,18 +140,6 @@ internal class SingleWalletOnrampTransactionConverter(
|
|||
null
|
||||
}
|
||||
|
||||
private fun getIconState(status: OnrampStatus.Status): ExpressTransactionStateIconUM {
|
||||
return when (status) {
|
||||
OnrampStatus.Status.Verifying,
|
||||
OnrampStatus.Status.RefundInProgress,
|
||||
-> ExpressTransactionStateIconUM.Warning
|
||||
OnrampStatus.Status.Refunded,
|
||||
OnrampStatus.Status.Failed,
|
||||
-> ExpressTransactionStateIconUM.Error
|
||||
else -> ExpressTransactionStateIconUM.None
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertStatuses(status: OnrampStatus.Status, externalTxUrl: String?): ExpressStatusUM {
|
||||
val statuses = with(status) {
|
||||
persistentListOf(
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers.convert
|
|||
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.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
|
|
@ -76,59 +77,50 @@ internal class TangemPayMainBlockConverter(
|
|||
cardFrozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
cardNumberEnd = "",
|
||||
chainId = POLYGON_CHAIN_ID,
|
||||
displayName = null,
|
||||
isTangemPayDeactivated = true,
|
||||
isReissuing = false,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
is PaymentAccountStatusValue.Locked -> TangemPayMainUM.Content(
|
||||
subtitle = stringReference("*${statusValue.lastFourDigits}"),
|
||||
isBalanceFlickering = statusValue.source == StatusSource.CACHE,
|
||||
balance = getBalanceText(
|
||||
currencyCode = statusValue.currencyCode,
|
||||
balance = statusValue.fiatBalance.availableBalance,
|
||||
),
|
||||
balanceSubtitle = stringReference("USDC"), // TODO hardcode for now
|
||||
shouldShowOnlyCacheWarning = statusValue.source == StatusSource.ONLY_CACHE,
|
||||
onClick = {
|
||||
tangemPayClickIntents.openDetails(
|
||||
value.account.userWalletId,
|
||||
TangemPayDetailsConfig(
|
||||
customerId = statusValue.customerId,
|
||||
cardId = statusValue.cardId,
|
||||
isPinSet = statusValue.isPinSet,
|
||||
cardFrozenState = TangemPayCardFrozenState.Frozen,
|
||||
cardNumberEnd = statusValue.lastFourDigits,
|
||||
chainId = POLYGON_CHAIN_ID,
|
||||
isTangemPayDeactivated = false,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
is PaymentAccountStatusValue.Loaded -> TangemPayMainUM.Content(
|
||||
subtitle = stringReference("*${statusValue.lastFourDigits}"),
|
||||
isBalanceFlickering = statusValue.source == StatusSource.CACHE,
|
||||
balance = getBalanceText(
|
||||
currencyCode = statusValue.currencyCode,
|
||||
balance = statusValue.fiatBalance.availableBalance,
|
||||
),
|
||||
balanceSubtitle = stringReference("USDC"), // TODO hardcode for now
|
||||
shouldShowOnlyCacheWarning = statusValue.source == StatusSource.ONLY_CACHE,
|
||||
onClick = {
|
||||
tangemPayClickIntents.openDetails(
|
||||
value.account.userWalletId,
|
||||
TangemPayDetailsConfig(
|
||||
customerId = statusValue.customerId,
|
||||
cardId = statusValue.cardId,
|
||||
isPinSet = statusValue.isPinSet,
|
||||
cardFrozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
cardNumberEnd = statusValue.lastFourDigits,
|
||||
chainId = POLYGON_CHAIN_ID,
|
||||
isTangemPayDeactivated = false,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
is PaymentAccountStatusValue.Loaded -> {
|
||||
val card = statusValue.cards.firstOrNull() ?: return TangemPayMainUM.TemporaryUnavailable
|
||||
TangemPayMainUM.Content(
|
||||
subtitle = if (card.isReissuing) {
|
||||
resourceReference(R.string.tangempay_status_replacing)
|
||||
} else {
|
||||
stringReference("*${card.lastDigits}")
|
||||
},
|
||||
isBalanceFlickering = statusValue.source == StatusSource.CACHE,
|
||||
balance = getBalanceText(
|
||||
currencyCode = statusValue.currencyCode,
|
||||
balance = statusValue.fiatBalance.availableBalance,
|
||||
),
|
||||
balanceSubtitle = stringReference("USDC"), // TODO hardcode for now
|
||||
shouldShowOnlyCacheWarning = statusValue.source == StatusSource.ONLY_CACHE,
|
||||
onClick = {
|
||||
tangemPayClickIntents.openDetails(
|
||||
value.account.userWalletId,
|
||||
TangemPayDetailsConfig(
|
||||
customerId = statusValue.customerId,
|
||||
cardId = card.id,
|
||||
isPinSet = card.hasPinCode,
|
||||
cardFrozenState = if (card.isFrozen) {
|
||||
TangemPayCardFrozenState.Frozen
|
||||
} else {
|
||||
TangemPayCardFrozenState.Unfrozen
|
||||
},
|
||||
cardNumberEnd = card.lastDigits,
|
||||
chainId = POLYGON_CHAIN_ID,
|
||||
displayName = card.displayName,
|
||||
isTangemPayDeactivated = false,
|
||||
isReissuing = card.isReissuing,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ internal class TokenListStateConverter(
|
|||
private val yieldModuleApyMap: Map<String, BigDecimal>,
|
||||
private val stakingAvailabilityMap: Map<CryptoCurrency, StakingAvailability>,
|
||||
private val shouldShowMainPromo: Boolean,
|
||||
private val isAddAndManageTokensEnabled: Boolean,
|
||||
) : Converter<WalletTokensListState, WalletTokensListState> {
|
||||
|
||||
private val yieldSupplyPromoBannerConverter = YieldSupplyPromoBannerConverter(
|
||||
|
|
@ -157,6 +158,8 @@ internal class TokenListStateConverter(
|
|||
}
|
||||
return if (currenciesSize > 1 && !isSingleCurrencyWalletWithToken()) {
|
||||
WalletOrganizeTokensButtonConfig(
|
||||
textRes = organizeButtonTextRes(),
|
||||
iconRes = organizeButtonIconRes(),
|
||||
isEnabled = tokenList.totalFiatBalance !is TotalFiatBalance.Loading,
|
||||
onClick = clickIntents::onOrganizeTokensClick,
|
||||
)
|
||||
|
|
@ -168,6 +171,8 @@ internal class TokenListStateConverter(
|
|||
private fun getOrganizeTokensButtonStateV2(accountList: AccountStatusList): WalletOrganizeTokensButtonConfig? {
|
||||
return if (accountList.flattenCurrencies().size > 1 && !isSingleCurrencyWalletWithToken()) {
|
||||
WalletOrganizeTokensButtonConfig(
|
||||
textRes = organizeButtonTextRes(),
|
||||
iconRes = organizeButtonIconRes(),
|
||||
isEnabled = accountList.totalFiatBalance !is TotalFiatBalance.Loading,
|
||||
onClick = clickIntents::onOrganizeTokensClick,
|
||||
)
|
||||
|
|
@ -176,6 +181,18 @@ internal class TokenListStateConverter(
|
|||
}
|
||||
}
|
||||
|
||||
private fun organizeButtonTextRes(): Int = if (isAddAndManageTokensEnabled) {
|
||||
R.string.main_add_and_manage_tokens
|
||||
} else {
|
||||
R.string.organize_tokens_title
|
||||
}
|
||||
|
||||
private fun organizeButtonIconRes(): Int = if (isAddAndManageTokensEnabled) {
|
||||
R.drawable.ic_filter_default_24
|
||||
} else {
|
||||
R.drawable.ic_filter_24
|
||||
}
|
||||
|
||||
private fun isSingleCurrencyWalletWithToken(): Boolean {
|
||||
return selectedWallet is UserWallet.Cold &&
|
||||
selectedWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers.convert
|
|||
import androidx.compose.ui.text.SpanStyle
|
||||
import com.tangem.common.getTotalCryptoAmount
|
||||
import com.tangem.common.getTotalFiatAmount
|
||||
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.common.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeState
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
import com.tangem.core.ui.ds.badge.*
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ internal class WalletTokensListUMConverter(
|
|||
private val isAccountsModeEnabled: Boolean,
|
||||
private val expandedAccounts: Set<AccountId>,
|
||||
private val stakingAvailabilityMap: Map<CryptoCurrency, StakingAvailability>,
|
||||
private val isAddAndManageTokensEnabled: Boolean,
|
||||
shouldShowMainPromo: Boolean,
|
||||
) : Converter<AccountStatusList, WalletTokensListUM> {
|
||||
|
||||
|
|
@ -164,15 +165,25 @@ internal class WalletTokensListUMConverter(
|
|||
}
|
||||
|
||||
private fun getOrganizeButtonUM(accountList: AccountStatusList): TangemButtonUM? {
|
||||
val textRes = if (isAddAndManageTokensEnabled) {
|
||||
R.string.main_add_and_manage_tokens
|
||||
} else {
|
||||
R.string.organize_tokens_title
|
||||
}
|
||||
val iconRes = if (isAddAndManageTokensEnabled) {
|
||||
R.drawable.ic_filter_default_24
|
||||
} else {
|
||||
R.drawable.ic_filter_24
|
||||
}
|
||||
return if (accountList.flattenCurrencies().size > 1 && !selectedWallet.isSingleWalletWithToken()) {
|
||||
TangemButtonUM(
|
||||
text = resourceReference(R.string.organize_tokens_title),
|
||||
text = resourceReference(textRes),
|
||||
isEnabled = accountList.totalFiatBalance !is TotalFiatBalance.Loading,
|
||||
size = TangemButtonSize.X9,
|
||||
shape = TangemButtonShape.Rounded,
|
||||
type = TangemButtonType.PrimaryInverse,
|
||||
tangemIconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_filter_default_24,
|
||||
iconRes = iconRes,
|
||||
tintReference = {
|
||||
if (accountList.totalFiatBalance !is TotalFiatBalance.Loading) {
|
||||
TangemTheme.colors2.graphic.neutral.primary
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ internal class WalletLoadingStateFactory(
|
|||
private val clickIntents: WalletClickIntents,
|
||||
private val walletImageResolver: WalletImageResolver,
|
||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||
private val isTangemPayRefactorEnabled: Boolean,
|
||||
) {
|
||||
|
||||
fun create(userWallet: UserWallet): WalletState {
|
||||
|
|
@ -83,9 +82,7 @@ internal class WalletLoadingStateFactory(
|
|||
tokensListState = WalletTokensListState.ContentState.Loading,
|
||||
nftState = WalletNFTItemUM.Hidden,
|
||||
type = WalletType.Hot,
|
||||
tangemPayState = TangemPayState.Empty,
|
||||
tangemPayMainUM = TangemPayMainUM.Empty,
|
||||
isTangemPayRefactorEnabled = isTangemPayRefactorEnabled,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -99,9 +96,7 @@ internal class WalletLoadingStateFactory(
|
|||
tokensListState = WalletTokensListState.ContentState.Loading,
|
||||
nftState = WalletNFTItemUM.Hidden,
|
||||
type = WalletType.Cold,
|
||||
tangemPayState = TangemPayState.Empty,
|
||||
tangemPayMainUM = TangemPayMainUM.Empty,
|
||||
isTangemPayRefactorEnabled = isTangemPayRefactorEnabled,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.tangem.domain.yield.supply.usecase.YieldSupplyGetShouldShowMainPromoU
|
|||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.account.AccountDependencies
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import com.tangem.utils.coroutines.combine7
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import dagger.assisted.Assisted
|
||||
|
|
@ -42,8 +43,12 @@ internal class AccountListSubscriber @AssistedInject constructor(
|
|||
private val stakingAvailabilityListUseCase: StakingAvailabilityListUseCase,
|
||||
private val yieldSupplyGetShouldShowMainPromoUseCase: YieldSupplyGetShouldShowMainPromoUseCase,
|
||||
private val designFeatureToggles: DesignFeatureToggles,
|
||||
private val walletFeatureToggles: WalletFeatureToggles,
|
||||
) : BasicAccountListSubscriber() {
|
||||
|
||||
override val isAddAndManageTokensEnabled: Boolean
|
||||
get() = walletFeatureToggles.isAddAndManageTokensEnabled
|
||||
|
||||
override fun create(coroutineScope: CoroutineScope): Flow<*> {
|
||||
val walletId = userWallet.walletId.stringValue
|
||||
TangemLogger.i("$TAG[$walletId]: create() called, building combine7")
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.subscribers
|
||||
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.tokensync.model.TokenSyncProgress
|
||||
import com.tangem.domain.tokensync.usecase.ObserveTokenSyncUseCase
|
||||
import com.tangem.domain.assetsdiscovery.model.AssetsDiscoveryProgress
|
||||
import com.tangem.domain.assetsdiscovery.usecase.ObserveAssetsDiscoveryUseCase
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TokenSyncProgressUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTokenSyncProgressTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.AssetsDiscoveryProgressUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetAssetsDiscoveryProgressTransformer
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -13,25 +13,25 @@ import kotlinx.coroutines.CoroutineScope
|
|||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
||||
internal class TokenSyncSubscriber @AssistedInject constructor(
|
||||
internal class AssetsDiscoverySubscriber @AssistedInject constructor(
|
||||
@Assisted private val userWallet: UserWallet,
|
||||
private val stateController: WalletStateController,
|
||||
private val observeTokenSyncUseCase: ObserveTokenSyncUseCase,
|
||||
private val observeAssetsDiscoveryUseCase: ObserveAssetsDiscoveryUseCase,
|
||||
) : WalletSubscriber() {
|
||||
|
||||
override fun create(coroutineScope: CoroutineScope): Flow<*> {
|
||||
return observeTokenSyncUseCase(userWallet.walletId)
|
||||
return observeAssetsDiscoveryUseCase(userWallet.walletId)
|
||||
.onEach { current -> handleProgress(userWallet, current) }
|
||||
}
|
||||
|
||||
private fun handleProgress(userWallet: UserWallet, current: TokenSyncProgress) {
|
||||
private fun handleProgress(userWallet: UserWallet, current: AssetsDiscoveryProgress) {
|
||||
val progressUM = when (current) {
|
||||
is TokenSyncProgress.InProgress -> TokenSyncProgressUM.InProgress(current.progressPercent)
|
||||
is TokenSyncProgress.Completed -> TokenSyncProgressUM.Completed
|
||||
is TokenSyncProgress.Idle -> TokenSyncProgressUM.Idle
|
||||
is AssetsDiscoveryProgress.InProgress -> AssetsDiscoveryProgressUM.InProgress(current.progressPercent)
|
||||
is AssetsDiscoveryProgress.Completed -> AssetsDiscoveryProgressUM.Completed
|
||||
is AssetsDiscoveryProgress.Idle -> AssetsDiscoveryProgressUM.Idle
|
||||
}
|
||||
stateController.update(
|
||||
SetTokenSyncProgressTransformer(
|
||||
SetAssetsDiscoveryProgressTransformer(
|
||||
userWallet = userWallet,
|
||||
progress = progressUM,
|
||||
),
|
||||
|
|
@ -40,6 +40,6 @@ internal class TokenSyncSubscriber @AssistedInject constructor(
|
|||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(userWallet: UserWallet): TokenSyncSubscriber
|
||||
fun create(userWallet: UserWallet): AssetsDiscoverySubscriber
|
||||
}
|
||||
}
|
||||
|
|
@ -34,6 +34,7 @@ internal abstract class BasicAccountListSubscriber : BasicWalletSubscriber() {
|
|||
abstract val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase
|
||||
abstract val stateController: WalletStateController
|
||||
abstract val clickIntents: WalletClickIntents
|
||||
abstract val isAddAndManageTokensEnabled: Boolean
|
||||
|
||||
override val singleAccountStatusListSupplier: SingleAccountStatusListSupplier
|
||||
get() = accountDependencies.singleAccountStatusListSupplier
|
||||
|
|
@ -105,6 +106,7 @@ internal abstract class BasicAccountListSubscriber : BasicWalletSubscriber() {
|
|||
shouldShowMainPromo = shouldShowMainPromo,
|
||||
isAccountsModeEnabled = isAccountMode,
|
||||
isRedesignEnabled = true,
|
||||
isAddAndManageTokensEnabled = isAddAndManageTokensEnabled,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -168,6 +170,7 @@ internal abstract class BasicAccountListSubscriber : BasicWalletSubscriber() {
|
|||
shouldShowMainPromo = shouldShowMainPromo,
|
||||
isAccountsModeEnabled = false,
|
||||
isRedesignEnabled = false,
|
||||
isAddAndManageTokensEnabled = isAddAndManageTokensEnabled,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.tangem.domain.models.wallet.UserWallet
|
|||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.account.AccountDependencies
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -18,8 +19,12 @@ internal class SingleWalletSubscriber @AssistedInject constructor(
|
|||
override val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
override val stateController: WalletStateController,
|
||||
override val clickIntents: WalletClickIntents,
|
||||
private val walletFeatureToggles: WalletFeatureToggles,
|
||||
) : BasicAccountListSubscriber() {
|
||||
|
||||
override val isAddAndManageTokensEnabled: Boolean
|
||||
get() = walletFeatureToggles.isAddAndManageTokensEnabled
|
||||
|
||||
override fun create(coroutineScope: CoroutineScope): Flow<Unit> = combine(
|
||||
flow = getAccountStatusListFlow(),
|
||||
flow2 = getAppCurrencyFlow(),
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.tangem.domain.models.wallet.UserWallet
|
|||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.account.AccountDependencies
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -19,8 +20,12 @@ internal class SingleWalletWithTokenSubscriberLegacy @AssistedInject constructor
|
|||
override val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
override val stateController: WalletStateController,
|
||||
override val clickIntents: WalletClickIntents,
|
||||
private val walletFeatureToggles: WalletFeatureToggles,
|
||||
) : BasicAccountListSubscriber() {
|
||||
|
||||
override val isAddAndManageTokensEnabled: Boolean
|
||||
get() = walletFeatureToggles.isAddAndManageTokensEnabled
|
||||
|
||||
override fun create(coroutineScope: CoroutineScope): Flow<Unit> = combine(
|
||||
flow = getAccountStatusListFlow(),
|
||||
flow2 = getAppCurrencyFlow(),
|
||||
|
|
|
|||
|
|
@ -1,117 +1,38 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.subscribers
|
||||
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.model.MainCustomerInfoContentState
|
||||
import com.tangem.domain.pay.model.MainScreenCustomerInfo
|
||||
import com.tangem.domain.pay.model.TangemPayCustomerInfoError
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier
|
||||
import com.tangem.domain.pay.repository.TangemPayWithdrawRepository
|
||||
import com.tangem.domain.pay.usecase.TangemPayMainScreenCustomerInfoUseCase
|
||||
import com.tangem.domain.visa.model.TangemPayCardFrozenState
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletTangemPayAnalyticsEventSender
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.*
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class TangemPayMainSubscriber @AssistedInject constructor(
|
||||
@Assisted private val userWallet: UserWallet,
|
||||
private val stateController: WalletStateController,
|
||||
private val clickIntents: WalletClickIntents,
|
||||
private val cardDetailsRepository: TangemPayCardDetailsRepository,
|
||||
private val tangemPayMainScreenCustomerInfoUseCase: TangemPayMainScreenCustomerInfoUseCase,
|
||||
private val tangemPayWithdrawRepository: TangemPayWithdrawRepository,
|
||||
private val paymentAccountStatusSupplier: PaymentAccountStatusSupplier,
|
||||
private val analytics: WalletTangemPayAnalyticsEventSender,
|
||||
) : WalletSubscriber() {
|
||||
|
||||
override fun create(coroutineScope: CoroutineScope): Flow<*> {
|
||||
coroutineScope.launch {
|
||||
// TODO: Doston move this logic to proper place(e.g. WalletBalanceFetcher)
|
||||
tangemPayWithdrawRepository.pollWithdrawOrdersIfNeeds(userWallet)
|
||||
}
|
||||
return subscribeOnTangemPayInfoUpdates()
|
||||
subscribeToStatus(coroutineScope)
|
||||
return emptyFlow<Any>()
|
||||
}
|
||||
|
||||
private fun subscribeOnTangemPayInfoUpdates(): Flow<*> {
|
||||
return tangemPayMainScreenCustomerInfoUseCase(userWalletId = userWallet.walletId)
|
||||
private fun subscribeToStatus(coroutineScope: CoroutineScope) {
|
||||
paymentAccountStatusSupplier.invoke(userWalletId = userWallet.walletId)
|
||||
.map { it.value }
|
||||
.distinctUntilChanged()
|
||||
.onEach { mainInfoData ->
|
||||
val userWalletId = userWallet.walletId
|
||||
mainInfoData.onLeft { tangemPayError ->
|
||||
when (tangemPayError) {
|
||||
TangemPayCustomerInfoError.RefreshNeededError -> {
|
||||
stateController.update(
|
||||
transformer = TangemPayRefreshNeededStateTransformer(
|
||||
userWalletId = userWalletId,
|
||||
userWallet = userWallet,
|
||||
onRefreshClick = { clickIntents.onRefreshPayToken(userWallet) },
|
||||
),
|
||||
)
|
||||
}
|
||||
TangemPayCustomerInfoError.UnavailableError -> {
|
||||
stateController.update(
|
||||
transformer = TangemPayUnavailableStateTransformer(userWalletId),
|
||||
)
|
||||
}
|
||||
TangemPayCustomerInfoError.ExposedDeviceError -> {
|
||||
stateController.update(TangemPayExposedDeviceTransformer(userWalletId))
|
||||
}
|
||||
TangemPayCustomerInfoError.UnknownError -> {
|
||||
// hide TangemPay block
|
||||
TangemLogger.e("Failed when loading main screen TangemPay info: $tangemPayError")
|
||||
stateController.update(
|
||||
transformer = TangemPayHiddenStateTransformer(userWalletId),
|
||||
)
|
||||
}
|
||||
}
|
||||
}.onRight { contentState -> handleContentState(state = contentState) }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun handleContentState(state: MainCustomerInfoContentState) {
|
||||
val userWalletId = userWallet.walletId
|
||||
when (state) {
|
||||
MainCustomerInfoContentState.Loading -> stateController.update(
|
||||
transformer = TangemPayLoadingStateTransformer(userWalletId),
|
||||
)
|
||||
is MainCustomerInfoContentState.Content -> {
|
||||
updateTangemPay(data = state.info, userWalletId = userWalletId)
|
||||
analytics.send(customerInfo = state.info)
|
||||
}
|
||||
is MainCustomerInfoContentState.OnboardingBanner -> stateController.update(
|
||||
transformer = TangemPayOnboardingBannerStateTransformer(
|
||||
userWalletId = userWalletId,
|
||||
onClick = clickIntents::onOnboardingBannerClick,
|
||||
closeOnClick = clickIntents::onOnboardingBannerCloseClick,
|
||||
),
|
||||
)
|
||||
is MainCustomerInfoContentState.Empty -> stateController.update(
|
||||
transformer = TangemPayHiddenStateTransformer(userWalletId),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateTangemPay(data: MainScreenCustomerInfo, userWalletId: UserWalletId) {
|
||||
val cardFrozenState =
|
||||
data.info.productInstance?.cardId?.let { cardDetailsRepository.cardFrozenStateSync(it) }
|
||||
?: TangemPayCardFrozenState.Unfrozen
|
||||
stateController.update(
|
||||
transformer = TangemPayUpdateInfoStateTransformer(
|
||||
userWalletId = userWalletId,
|
||||
value = data,
|
||||
cardFrozenState = cardFrozenState,
|
||||
tangemPayClickIntents = clickIntents,
|
||||
),
|
||||
)
|
||||
.onEach(analytics::send)
|
||||
.launchIn(coroutineScope)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ import com.tangem.feature.wallet.presentation.wallet.ui.components.common.*
|
|||
import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency.nftCollections
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency.organizeTokensButton
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.singlecurrency.marketPriceBlock
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.TangemPayMainScreenBlock
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.utils.changeWalletAnimator
|
||||
import com.tangem.features.tangempay.component.TangemPayMainBlockComponent
|
||||
import com.tangem.features.tangempay.entity.TangemPayMainUM
|
||||
|
|
@ -96,7 +95,7 @@ internal fun WalletScreen(
|
|||
state: WalletScreenState,
|
||||
tangemPayComponent: TangemPayMainBlockComponent,
|
||||
promoBannersBlockComponent: ComposableContentComponent? = null,
|
||||
bottomSheetContent: @Composable (() -> Unit),
|
||||
bottomSheetContent: @Composable (onExpandSheet: () -> Unit) -> Unit,
|
||||
bottomSheetHeaderHeightProvider: () -> Dp,
|
||||
onBottomSheetStateChange: (BottomSheetState) -> Unit,
|
||||
) {
|
||||
|
|
@ -140,7 +139,7 @@ private fun WalletContent(
|
|||
promoBannersBlockComponent: ComposableContentComponent? = null,
|
||||
bottomSheetHeaderHeightProvider: () -> Dp,
|
||||
onBottomSheetStateChange: (BottomSheetState) -> Unit,
|
||||
bottomSheetContent: @Composable (() -> Unit),
|
||||
bottomSheetContent: @Composable (onExpandSheet: () -> Unit) -> Unit,
|
||||
) {
|
||||
/*
|
||||
* Don't pass key to remember, because it will brake scroll animation.
|
||||
|
|
@ -296,7 +295,7 @@ private inline fun BaseScaffoldWithMarkets(
|
|||
snackbarHostState: SnackbarHostState,
|
||||
bottomSheetHeaderHeightProvider: () -> Dp,
|
||||
noinline onBottomSheetStateChange: (BottomSheetState) -> Unit,
|
||||
crossinline bottomSheetContent: @Composable () -> Unit,
|
||||
crossinline bottomSheetContent: @Composable (onExpandSheet: () -> Unit) -> Unit,
|
||||
crossinline content: @Composable (PaddingValues) -> Unit,
|
||||
) {
|
||||
val isKeyboardVisible by rememberIsKeyboardVisible()
|
||||
|
|
@ -383,7 +382,7 @@ private inline fun BaseScaffoldWithMarkets(
|
|||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
// expand bottom sheet when clicked on the header
|
||||
// expand bottom sheet when clicked on the drag handle
|
||||
.clickable(
|
||||
enabled = bottomSheetState.currentValue == TangemSheetValue.PartiallyExpanded,
|
||||
indication = null,
|
||||
|
|
@ -401,7 +400,9 @@ private inline fun BaseScaffoldWithMarkets(
|
|||
isSearchFieldFocused = it.isFocused
|
||||
},
|
||||
) {
|
||||
bottomSheetContent()
|
||||
bottomSheetContent {
|
||||
coroutineScope.launch { bottomSheetState.expand() }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -726,17 +727,13 @@ private fun WalletSnackbarHost(
|
|||
}
|
||||
|
||||
internal fun LazyListScope.organizeTokens(state: WalletState, itemModifier: Modifier) {
|
||||
(state as? WalletState.MultiCurrency)?.let {
|
||||
(state.tokensListState as? WalletTokensListState.ContentState)?.let {
|
||||
it.organizeTokensButtonConfig?.let { config ->
|
||||
organizeTokensButton(
|
||||
modifier = itemModifier,
|
||||
isEnabled = config.isEnabled,
|
||||
onClick = config.onClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
val multiCurrencyState = state as? WalletState.MultiCurrency ?: return
|
||||
val contentState = multiCurrencyState.tokensListState as? WalletTokensListState.ContentState ?: return
|
||||
val config = contentState.organizeTokensButtonConfig ?: return
|
||||
organizeTokensButton(
|
||||
modifier = itemModifier,
|
||||
config = config,
|
||||
)
|
||||
}
|
||||
|
||||
internal fun LazyListScope.nftCollections(state: WalletState, itemModifier: Modifier) {
|
||||
|
|
@ -756,14 +753,8 @@ internal fun LazyListScope.tangemPayItem(
|
|||
) {
|
||||
if (state !is WalletState.MultiCurrency) return
|
||||
|
||||
if (state.isTangemPayRefactorEnabled) {
|
||||
with(tangemPayComponent) {
|
||||
tangemPayMainContent(modifier = modifier, state = state.tangemPayMainUM, isBalanceHidden = isHidingMode)
|
||||
}
|
||||
} else {
|
||||
item(key = "TangemPayMainScreenBlock", contentType = state.tangemPayState::class.java) {
|
||||
TangemPayMainScreenBlock(modifier = modifier, state = state.tangemPayState, isBalanceHidden = isHidingMode)
|
||||
}
|
||||
with(tangemPayComponent) {
|
||||
tangemPayMainContent(modifier = modifier, state = state.tangemPayMainUM, isBalanceHidden = isHidingMode)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ internal fun WalletScreen2(
|
|||
state: WalletScreenState,
|
||||
tangemPayComponent: TangemPayMainBlockComponent,
|
||||
modifier: Modifier = Modifier,
|
||||
bottomSheetContent: @Composable (() -> Unit),
|
||||
bottomSheetContent: @Composable (onExpandSheet: () -> Unit) -> Unit,
|
||||
bottomSheetHeaderHeightProvider: () -> Dp,
|
||||
onBottomSheetStateChange: (BottomSheetState) -> Unit,
|
||||
) {
|
||||
|
|
@ -162,7 +162,7 @@ private fun WalletContent2(
|
|||
modifier: Modifier = Modifier,
|
||||
bottomSheetHeaderHeightProvider: () -> Dp,
|
||||
onBottomSheetStateChange: (BottomSheetState) -> Unit,
|
||||
bottomSheetContent: @Composable (() -> Unit),
|
||||
bottomSheetContent: @Composable (onExpandSheet: () -> Unit) -> Unit,
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
val bottomBarHeight = with(density) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||
|
|
@ -343,7 +343,7 @@ private inline fun BaseScaffoldWithMarkets(
|
|||
modifier: Modifier = Modifier,
|
||||
noinline onBottomSheetStateChange: (BottomSheetState) -> Unit,
|
||||
crossinline appBarContent: @Composable () -> Unit,
|
||||
crossinline bottomSheetContent: @Composable () -> Unit,
|
||||
crossinline bottomSheetContent: @Composable (onExpandSheet: () -> Unit) -> Unit,
|
||||
crossinline content: @Composable (PaddingValues, TangemSheetState) -> Unit,
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
|
|
@ -384,7 +384,9 @@ private inline fun BaseScaffoldWithMarkets(
|
|||
isSearchFieldFocused = focusState.isFocused
|
||||
},
|
||||
) {
|
||||
bottomSheetContent()
|
||||
bottomSheetContent {
|
||||
coroutineScope.launch { bottomSheetState.expand() }
|
||||
}
|
||||
}
|
||||
},
|
||||
content = { paddingValues ->
|
||||
|
|
@ -456,7 +458,7 @@ private fun BottomSheet(
|
|||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
// expand bottom sheet when clicked on the header
|
||||
// expand bottom sheet when clicked on the drag handle
|
||||
.clickable(
|
||||
enabled = bottomSheetState.currentValue == TangemSheetValue.PartiallyExpanded,
|
||||
indication = null,
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ import androidx.compose.animation.togetherWith
|
|||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.text.TextAutoSize
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
|
|
@ -25,25 +25,26 @@ import androidx.compose.ui.unit.dp
|
|||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.TextShimmer
|
||||
import com.tangem.core.ui.components.text.applyBladeBrush
|
||||
import com.tangem.core.ui.ds.button.SecondaryTangemButton
|
||||
import com.tangem.core.ui.ds.button.TangemButtonShape
|
||||
import com.tangem.core.ui.ds.button.TangemButtonUM
|
||||
import com.tangem.core.ui.ds.button.action.ActionButtons
|
||||
import com.tangem.core.ui.ds.image.TangemDeviceIcon
|
||||
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.orEmpty
|
||||
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.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.core.ui.test.MainScreenTestTags
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
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.WalletAdditionalInfo
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletBalanceUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.fastForEach
|
||||
import com.tangem.utils.StringsSigns
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
|
|
@ -84,17 +85,7 @@ internal fun WalletBalance(
|
|||
isBalanceHidden = isBalanceHidden,
|
||||
)
|
||||
SpacerH(TangemTheme.dimens2.x3)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x1),
|
||||
) {
|
||||
Text(
|
||||
text = walletBalanceUM.name,
|
||||
style = TangemTheme.typography2.bodyRegular14,
|
||||
color = TangemTheme.colors2.text.neutral.tertiary,
|
||||
)
|
||||
TangemDeviceIcon(state = walletBalanceUM.deviceIcon)
|
||||
}
|
||||
SubtitleRow(walletBalanceUM = walletBalanceUM)
|
||||
}
|
||||
SpacerH(TangemTheme.dimens2.x2)
|
||||
ActionButtons(buttons)
|
||||
|
|
@ -102,6 +93,61 @@ internal fun WalletBalance(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SubtitleRow(walletBalanceUM: WalletBalanceUM, modifier: Modifier = Modifier) {
|
||||
AnimatedContent(
|
||||
targetState = walletBalanceUM.additionalInfo?.content,
|
||||
contentKey = { content ->
|
||||
when (content) {
|
||||
is WalletAdditionalInfo.Content.SyncProgress -> WalletAdditionalInfo.Content.SyncProgress::class
|
||||
else -> content
|
||||
}
|
||||
},
|
||||
label = "Update subtitle",
|
||||
modifier = modifier,
|
||||
transitionSpec = {
|
||||
fadeIn(animationSpec = tween(durationMillis = 220, delayMillis = 90)) togetherWith
|
||||
fadeOut(animationSpec = tween(durationMillis = 90))
|
||||
},
|
||||
) { content ->
|
||||
when (content) {
|
||||
is WalletAdditionalInfo.Content.SyncProgress -> {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x1_5),
|
||||
) {
|
||||
Text(
|
||||
text = resourceReference(
|
||||
id = R.string.initial_wallet_sync_restore_progress,
|
||||
formatArgs = wrappedList(content.progressPercent),
|
||||
).resolveReference(),
|
||||
style = TangemTheme.typography2.bodyRegular14,
|
||||
color = TangemTheme.colors2.text.neutral.tertiary,
|
||||
)
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(19.dp),
|
||||
color = TangemTheme.colors2.graphic.neutral.primary,
|
||||
strokeWidth = 2.dp,
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x1),
|
||||
) {
|
||||
Text(
|
||||
text = walletBalanceUM.name,
|
||||
style = TangemTheme.typography2.bodyRegular14,
|
||||
color = TangemTheme.colors2.text.neutral.tertiary,
|
||||
)
|
||||
TangemDeviceIcon(state = walletBalanceUM.deviceIcon)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Balance(walletBalanceUM: WalletBalanceUM, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
|
||||
AnimatedContent(
|
||||
|
|
@ -152,41 +198,6 @@ private fun Balance(walletBalanceUM: WalletBalanceUM, isBalanceHidden: Boolean,
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ActionButtons(buttons: ImmutableList<TangemButtonUM>) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(14.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
buttons.fastForEach { button ->
|
||||
key(button.text) {
|
||||
val textColor = if (button.isEnabled) {
|
||||
TangemTheme.colors2.text.neutral.primary
|
||||
} else {
|
||||
TangemTheme.colors2.text.status.disabled
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier.padding(horizontal = TangemTheme.dimens2.x2_5),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
SecondaryTangemButton(
|
||||
tangemIconUM = button.tangemIconUM,
|
||||
onClick = button.onClick,
|
||||
isEnabled = button.isEnabled,
|
||||
shape = TangemButtonShape.Rounded,
|
||||
)
|
||||
Text(
|
||||
text = button.text.orEmpty().resolveReference(),
|
||||
style = TangemTheme.typography2.bodySemibold15,
|
||||
color = textColor,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
|
|
@ -215,6 +226,7 @@ private class WalletBalancePreviewProvider : PreviewParameterProvider<WalletBala
|
|||
override val values: Sequence<WalletBalancePreviewData>
|
||||
get() = sequenceOf(
|
||||
WalletBalancePreviewData(WalletBalancePreview.content, WalletPreviewData.actionButtons),
|
||||
WalletBalancePreviewData(WalletBalancePreview.syncProgress, WalletPreviewData.actionButtons),
|
||||
WalletBalancePreviewData(WalletBalancePreview.hiddenBalanceContent, WalletPreviewData.actionButtons),
|
||||
WalletBalancePreviewData(WalletBalancePreview.loading, WalletPreviewData.disabledActionButtons),
|
||||
WalletBalancePreviewData(WalletBalancePreview.error, WalletPreviewData.disabledActionButtons),
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import com.tangem.core.ui.components.buttons.actions.RoundedActionButton
|
|||
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.WalletTokensListState
|
||||
|
||||
private const val ORGANIZE_BUTTON_CONTENT_TYPE = "OrganizeTokensButton"
|
||||
|
||||
|
|
@ -20,18 +21,22 @@ private const val ORGANIZE_BUTTON_CONTENT_TYPE = "OrganizeTokensButton"
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal fun LazyListScope.organizeTokensButton(
|
||||
isEnabled: Boolean,
|
||||
onClick: () -> Unit,
|
||||
config: WalletTokensListState.OrganizeTokensButtonConfig,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
item(key = ORGANIZE_BUTTON_CONTENT_TYPE, contentType = ORGANIZE_BUTTON_CONTENT_TYPE) {
|
||||
val testTag = if (config.textRes == R.string.main_add_and_manage_tokens) {
|
||||
MainScreenTestTags.ADD_AND_MANAGE_BUTTON
|
||||
} else {
|
||||
MainScreenTestTags.ORGANIZE_TOKENS_BUTTON
|
||||
}
|
||||
RoundedActionButton(
|
||||
modifier = modifier.testTag(MainScreenTestTags.ORGANIZE_TOKENS_BUTTON),
|
||||
modifier = modifier.testTag(testTag),
|
||||
config = ActionButtonConfig(
|
||||
text = resourceReference(id = R.string.organize_tokens_title),
|
||||
iconResId = R.drawable.ic_filter_24,
|
||||
onClick = onClick,
|
||||
isEnabled = isEnabled,
|
||||
text = resourceReference(id = config.textRes),
|
||||
iconResId = config.iconRes,
|
||||
onClick = config.onClick,
|
||||
isEnabled = config.isEnabled,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,103 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components.singlecurrency
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.orMaskWithStars
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.TangemPayMainScreenBlock
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayCardMainBlock(
|
||||
state: TangemPayState.Card,
|
||||
isBalanceHidden: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Surface(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
shape = TangemTheme.shapes.roundedCornersXMedium,
|
||||
color = TangemTheme.colors.background.primary,
|
||||
onClick = state.onClick,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(IntrinsicSize.Min)
|
||||
.padding(horizontal = 12.dp, vertical = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.img_visa_36),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(36.dp),
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier.weight(1f),
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.tangempay_payment_account),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
Text(
|
||||
text = state.lastFourDigits.resolveReference(),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||
horizontalAlignment = Alignment.End,
|
||||
) {
|
||||
Text(
|
||||
text = state.balanceText.resolveReference().orMaskWithStars(isBalanceHidden),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.End,
|
||||
)
|
||||
Text(
|
||||
text = state.balanceSymbol.resolveReference(),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
textAlign = TextAlign.End,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun TangemPayCardMainBlockPreview() {
|
||||
TangemThemePreview {
|
||||
TangemPayMainScreenBlock(
|
||||
TangemPayState.Card(
|
||||
lastFourDigits = TextReference.Str("*1234"),
|
||||
balanceText = TextReference.Str("$ 0.00"),
|
||||
balanceSymbol = TextReference.Str("USDC"),
|
||||
onClick = {},
|
||||
),
|
||||
isBalanceHidden = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components.visa
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.block.BlockCard
|
||||
import com.tangem.core.ui.components.inputrow.InputRowImageBase
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
private const val DISABLED_ALPHA = 0.6F
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayExposedDeviceState(modifier: Modifier = Modifier) {
|
||||
BlockCard(
|
||||
modifier = modifier
|
||||
.clip(RoundedCornerShape(size = TangemTheme.dimens.radius14))
|
||||
.background(TangemTheme.colors.background.primary)
|
||||
.alpha(DISABLED_ALPHA),
|
||||
enabled = false,
|
||||
onClick = {},
|
||||
) {
|
||||
InputRowImageBase(
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
all = TangemTheme.dimens.spacing12,
|
||||
),
|
||||
subtitle = resourceReference(R.string.tangempay_payment_account),
|
||||
caption = resourceReference(R.string.tangem_pay_rooted_device_subtitle),
|
||||
subtitleColor = TangemTheme.colors.text.primary1,
|
||||
captionColor = TangemTheme.colors.text.tertiary,
|
||||
iconResWebp = R.drawable.img_visa_36,
|
||||
endIconTint = TangemTheme.colors.icon.warning,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components.visa
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import com.tangem.core.ui.components.block.BlockCard
|
||||
import com.tangem.core.ui.components.inputrow.InputRowImageBase
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayFailedIssueState(state: TangemPayState.FailedIssue, modifier: Modifier = Modifier) {
|
||||
BlockCard(
|
||||
modifier = modifier
|
||||
.clip(RoundedCornerShape(size = TangemTheme.dimens.radius14))
|
||||
.background(TangemTheme.colors.background.primary),
|
||||
onClick = state.onButtonClick,
|
||||
) {
|
||||
InputRowImageBase(
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
all = TangemTheme.dimens.spacing12,
|
||||
),
|
||||
subtitle = state.title,
|
||||
caption = state.description,
|
||||
subtitleColor = TangemTheme.colors.text.primary1,
|
||||
captionColor = TangemTheme.colors.text.tertiary,
|
||||
iconResWebp = com.tangem.core.ui.R.drawable.img_visa_36,
|
||||
iconEndRes = state.iconRes,
|
||||
endIconTint = TangemTheme.colors.icon.warning,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components.visa
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.CircleShimmer
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.components.SpacerWMax
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayLoadingScreenBlock(modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.background(color = TangemTheme.colors.background.primary, shape = TangemTheme.shapes.roundedCornersXMedium)
|
||||
.padding(horizontal = 12.dp, vertical = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
CircleShimmer(modifier = Modifier.size(36.dp))
|
||||
Column(
|
||||
modifier = Modifier.padding(start = 12.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||
) {
|
||||
RectangleShimmer(modifier = Modifier.padding(vertical = 4.dp).sizeIn(minWidth = 70.dp, minHeight = 12.dp))
|
||||
RectangleShimmer(modifier = Modifier.padding(vertical = 2.dp).sizeIn(minWidth = 52.dp, minHeight = 12.dp))
|
||||
}
|
||||
SpacerWMax()
|
||||
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
|
||||
RectangleShimmer(modifier = Modifier.padding(vertical = 4.dp).sizeIn(minWidth = 40.dp, minHeight = 12.dp))
|
||||
RectangleShimmer(modifier = Modifier.padding(vertical = 2.dp).sizeIn(minWidth = 40.dp, minHeight = 12.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components.visa
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState.Progress
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification.Warning.TangemPayRefreshNeeded
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.singlecurrency.TangemPayCardMainBlock
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayMainScreenBlock(state: TangemPayState, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
|
||||
when (state) {
|
||||
is Progress -> TangemPayProgressState(state, modifier)
|
||||
is TangemPayState.Card -> TangemPayCardMainBlock(state, isBalanceHidden, modifier)
|
||||
is TangemPayState.Empty -> Unit
|
||||
is TangemPayState.RefreshNeeded -> TangemPayRefreshBlock(state, modifier)
|
||||
is TangemPayState.TemporaryUnavailable -> TangemPayUnavailableBlock(state, modifier)
|
||||
is TangemPayState.FailedIssue -> TangemPayFailedIssueState(state, modifier)
|
||||
is TangemPayState.OnboardingBanner -> TangemPayOnboardingBanner(state, modifier)
|
||||
is TangemPayState.ExposedDevice -> TangemPayExposedDeviceState(modifier)
|
||||
is TangemPayState.Loading -> TangemPayLoadingScreenBlock(modifier)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun TangemPayMainScreenBlockPreview() {
|
||||
TangemThemePreview {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8)) {
|
||||
TangemPayMainScreenBlock(state = TangemPayState.Loading, isBalanceHidden = false)
|
||||
TangemPayMainScreenBlock(
|
||||
state = TangemPayState.RefreshNeeded(
|
||||
TangemPayRefreshNeeded(
|
||||
buttonText = resourceReference(id = R.string.home_button_scan),
|
||||
onRefreshClick = {},
|
||||
shouldShowProgress = false,
|
||||
),
|
||||
),
|
||||
isBalanceHidden = false,
|
||||
)
|
||||
TangemPayMainScreenBlock(
|
||||
state = TangemPayState.TemporaryUnavailable(WalletNotification.Warning.TangemPayUnreachable),
|
||||
isBalanceHidden = false,
|
||||
)
|
||||
TangemPayMainScreenBlock(
|
||||
state = TangemPayState.OnboardingBanner(onClick = {}, closeOnClick = {}),
|
||||
isBalanceHidden = false,
|
||||
)
|
||||
|
||||
TangemPayMainScreenBlock(state = TangemPayState.ExposedDevice, isBalanceHidden = false)
|
||||
TangemPayMainScreenBlock(
|
||||
state = TangemPayState.FailedIssue(
|
||||
title = TextReference.Res(R.string.tangempay_payment_account),
|
||||
description = TextReference.Res(R.string.tangempay_failed_to_issue_card),
|
||||
iconRes = R.drawable.ic_alert_24,
|
||||
onButtonClick = { },
|
||||
),
|
||||
isBalanceHidden = false,
|
||||
)
|
||||
|
||||
TangemPayMainScreenBlock(
|
||||
Progress(
|
||||
title = TextReference.Res(R.string.tangempay_payment_account),
|
||||
description = TextReference.Res(R.string.tangempay_kyc_in_progress),
|
||||
buttonText = TextReference.Res(R.string.tangempay_kyc_in_progress_notification_button),
|
||||
iconRes = R.drawable.ic_promo_kyc_36,
|
||||
onButtonClick = {},
|
||||
),
|
||||
isBalanceHidden = false,
|
||||
)
|
||||
|
||||
TangemPayMainScreenBlock(
|
||||
Progress(
|
||||
title = TextReference.Res(R.string.tangempay_payment_account),
|
||||
description = TextReference.Res(R.string.tangempay_issuing_your_card),
|
||||
buttonText = TextReference.EMPTY,
|
||||
iconRes = R.drawable.ic_tangem_pay_promo_card_36,
|
||||
onButtonClick = {},
|
||||
showProgress = true,
|
||||
),
|
||||
isBalanceHidden = false,
|
||||
)
|
||||
|
||||
TangemPayMainScreenBlock(
|
||||
TangemPayState.Card(
|
||||
lastFourDigits = TextReference.Str("*1234"),
|
||||
balanceText = TextReference.Str("$ 0.00"),
|
||||
balanceSymbol = TextReference.Str("USDC"),
|
||||
onClick = {},
|
||||
),
|
||||
isBalanceHidden = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components.visa
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import androidx.constraintlayout.compose.Dimension
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState
|
||||
|
||||
private const val GRADIENT_START_COLOR = 0xFF252934
|
||||
private const val GRADIENT_END_COLOR = 0xFF12141E
|
||||
private const val GRADIENT_OFFSET_X = 0f
|
||||
private const val GRADIENT_OFFSET_Y = 80F
|
||||
private const val GRADIENT_RADIUS = 200F
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayOnboardingBanner(state: TangemPayState.OnboardingBanner, modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(
|
||||
brush = Brush.radialGradient(
|
||||
colors = listOf(Color(GRADIENT_START_COLOR), Color(GRADIENT_END_COLOR)),
|
||||
center = Offset(GRADIENT_OFFSET_X, GRADIENT_OFFSET_Y),
|
||||
radius = GRADIENT_RADIUS,
|
||||
),
|
||||
)
|
||||
.clickable(onClick = state.onClick),
|
||||
) {
|
||||
ConstraintLayout(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
val (image, text, close) = createRefs()
|
||||
|
||||
Image(
|
||||
painter = painterResource(R.drawable.ic_close_24),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.size(16.dp)
|
||||
.clickable(onClick = state.closeOnClick)
|
||||
.constrainAs(close) {
|
||||
top.linkTo(parent.top, margin = 16.dp)
|
||||
end.linkTo(parent.end, margin = 16.dp)
|
||||
},
|
||||
colorFilter = ColorFilter.tint(TangemTheme.colors.icon.inactive),
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.constrainAs(text) {
|
||||
top.linkTo(parent.top)
|
||||
start.linkTo(image.end, margin = 12.dp)
|
||||
end.linkTo(close.start, margin = 12.dp)
|
||||
width = Dimension.fillToConstraints
|
||||
}
|
||||
.padding(top = 16.dp, bottom = 16.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.tangempay_onboarding_banner_title),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.constantWhite,
|
||||
)
|
||||
|
||||
SpacerH(6.dp)
|
||||
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.tangempay_onboarding_banner_description),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
|
||||
Image(
|
||||
painter = painterResource(R.drawable.img_tangem_pay_onboarding_banner),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.padding(top = 8.dp, start = 24.dp)
|
||||
.constrainAs(image) {
|
||||
start.linkTo(parent.start)
|
||||
top.linkTo(text.top)
|
||||
bottom.linkTo(text.bottom)
|
||||
height = Dimension.fillToConstraints
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun PreviewTangemOnboardingBanner() {
|
||||
TangemThemePreview {
|
||||
TangemPayOnboardingBanner(
|
||||
TangemPayState.OnboardingBanner(
|
||||
onClick = {},
|
||||
closeOnClick = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components.visa
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.block.BlockCard
|
||||
import com.tangem.core.ui.components.inputrow.InputRowImageBase
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayProgressState(state: TangemPayState.Progress, modifier: Modifier = Modifier) {
|
||||
BlockCard(
|
||||
modifier = modifier
|
||||
.clip(RoundedCornerShape(size = TangemTheme.dimens.radius14))
|
||||
.background(TangemTheme.colors.background.primary),
|
||||
onClick = state.onButtonClick,
|
||||
) {
|
||||
InputRowImageBase(
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
all = TangemTheme.dimens.spacing12,
|
||||
),
|
||||
subtitle = state.title,
|
||||
caption = state.description,
|
||||
subtitleColor = TangemTheme.colors.text.primary1,
|
||||
captionColor = TangemTheme.colors.text.tertiary,
|
||||
iconResWebp = R.drawable.img_visa_36,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components.visa
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.SpacerH12
|
||||
import com.tangem.core.ui.components.block.BlockCard
|
||||
import com.tangem.core.ui.components.inputrow.InputRowImageBase
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification.Warning.TangemPayRefreshNeeded
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayRefreshBlock(state: TangemPayState.RefreshNeeded, modifier: Modifier = Modifier) {
|
||||
Column(modifier) {
|
||||
Notification(
|
||||
config = state.notification.config,
|
||||
iconTint = when (state.notification) {
|
||||
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
|
||||
},
|
||||
)
|
||||
SpacerH12()
|
||||
|
||||
BlockCard(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(size = TangemTheme.dimens.radius14))
|
||||
.background(TangemTheme.colors.background.primary),
|
||||
enabled = false,
|
||||
) {
|
||||
InputRowImageBase(
|
||||
modifier = Modifier.padding(
|
||||
all = TangemTheme.dimens.spacing12,
|
||||
),
|
||||
subtitle = resourceReference(R.string.tangempay_payment_account),
|
||||
caption = resourceReference(R.string.tangempay_payment_account_sync_needed),
|
||||
subtitleColor = TangemTheme.colors.text.tertiary,
|
||||
captionColor = TangemTheme.colors.text.tertiary,
|
||||
iconResWebp = R.drawable.img_visa_36,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun TangemPayRefreshBlockPreview() {
|
||||
TangemThemePreview {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8)) {
|
||||
TangemPayRefreshBlock(
|
||||
state = TangemPayState.RefreshNeeded(
|
||||
TangemPayRefreshNeeded(
|
||||
buttonText = resourceReference(id = R.string.tangempay_sync_needed_restore_access),
|
||||
onRefreshClick = {},
|
||||
shouldShowProgress = true,
|
||||
),
|
||||
),
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components.visa
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.SpacerH12
|
||||
import com.tangem.core.ui.components.block.BlockCard
|
||||
import com.tangem.core.ui.components.inputrow.InputRowImageBase
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification
|
||||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayUnavailableBlock(state: TangemPayState.TemporaryUnavailable, modifier: Modifier = Modifier) {
|
||||
Column(modifier) {
|
||||
Notification(
|
||||
config = state.notification.config,
|
||||
iconTint = when (state.notification) {
|
||||
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
|
||||
},
|
||||
)
|
||||
SpacerH12()
|
||||
|
||||
BlockCard(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(size = TangemTheme.dimens.radius14))
|
||||
.background(TangemTheme.colors.background.primary),
|
||||
enabled = false,
|
||||
) {
|
||||
InputRowImageBase(
|
||||
modifier = Modifier.padding(
|
||||
all = TangemTheme.dimens.spacing12,
|
||||
),
|
||||
subtitle = resourceReference(R.string.tangempay_payment_account),
|
||||
caption = TextReference.Str(DASH_SIGN),
|
||||
subtitleColor = TangemTheme.colors.text.tertiary,
|
||||
captionColor = TangemTheme.colors.text.tertiary,
|
||||
iconResWebp = R.drawable.img_visa_36,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun TangemPayUnavailableBlockPreview() {
|
||||
TangemThemePreview {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8)) {
|
||||
TangemPayUnavailableBlock(
|
||||
state = TangemPayState.TemporaryUnavailable(
|
||||
WalletNotification.Warning.TangemPayUnreachable,
|
||||
),
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ class YieldSupplyPromoBannerConverterTest {
|
|||
|
||||
@Test
|
||||
fun `GIVEN promo disabled WHEN convert THEN return null`() {
|
||||
val token = createToken(networkId = "ethereum", backendId = "ethereum", contract = "0xABCDEF")
|
||||
val token = createToken(networkId = "ethereum", rawId = "ethereum", contract = "0xABCDEF")
|
||||
val status = createLoadedStatus(token = token, amount = BigDecimal.ONE, isYieldActive = false)
|
||||
val tokenList = ungroupedTokenList(status)
|
||||
val params = TokenConverterParams.Wallet(
|
||||
|
|
@ -35,7 +35,7 @@ class YieldSupplyPromoBannerConverterTest {
|
|||
tokenList = tokenList,
|
||||
)
|
||||
val converter = YieldSupplyPromoBannerConverter(
|
||||
yieldModuleApyMap = mapOf("${token.network.backendId}_${token.contractAddress}" to BigDecimal("0.10")),
|
||||
yieldModuleApyMap = mapOf("${token.network.rawId}_${token.contractAddress}" to BigDecimal("0.10")),
|
||||
shouldShowMainPromo = false,
|
||||
)
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ class YieldSupplyPromoBannerConverterTest {
|
|||
|
||||
@Test
|
||||
fun `GIVEN empty apy map WHEN convert THEN return null`() {
|
||||
val token = createToken(networkId = "ethereum", backendId = "ethereum", contract = "0xA1")
|
||||
val token = createToken(networkId = "ethereum", rawId = "ethereum", contract = "0xA1")
|
||||
val status = createLoadedStatus(token = token, amount = BigDecimal("2.0"), isYieldActive = false)
|
||||
val params = TokenConverterParams.Wallet(
|
||||
mainAccount = account,
|
||||
|
|
@ -64,14 +64,14 @@ class YieldSupplyPromoBannerConverterTest {
|
|||
|
||||
@Test
|
||||
fun `GIVEN active yield token present WHEN convert THEN return null`() {
|
||||
val token = createToken(networkId = "ethereum", backendId = "ethereum", contract = "0xAA")
|
||||
val token = createToken(networkId = "ethereum", rawId = "ethereum", contract = "0xAA")
|
||||
val statusActive = createLoadedStatus(token = token, amount = BigDecimal("5"), isYieldActive = true)
|
||||
val params = TokenConverterParams.Wallet(
|
||||
mainAccount = account,
|
||||
tokenList = ungroupedTokenList(statusActive),
|
||||
)
|
||||
val converter = YieldSupplyPromoBannerConverter(
|
||||
yieldModuleApyMap = mapOf("${token.network.backendId}_${token.contractAddress}" to BigDecimal("0.12")),
|
||||
yieldModuleApyMap = mapOf("${token.network.rawId}_${token.contractAddress}" to BigDecimal("0.12")),
|
||||
shouldShowMainPromo = true,
|
||||
)
|
||||
|
||||
|
|
@ -82,16 +82,16 @@ class YieldSupplyPromoBannerConverterTest {
|
|||
|
||||
@Test
|
||||
fun `GIVEN multiple candidates EVM case insensitive WHEN convert THEN return status of max amount`() {
|
||||
val evmNetworkId = "ETH"
|
||||
val tokenSmall = createToken(networkId = evmNetworkId, backendId = evmNetworkId, contract = "0xAbCd")
|
||||
val tokenBig = createToken(networkId = evmNetworkId, backendId = evmNetworkId, contract = "0xBEEF")
|
||||
val evmNetworkId = "ethereum"
|
||||
val tokenSmall = createToken(networkId = evmNetworkId, rawId = evmNetworkId, contract = "0xAbCd")
|
||||
val tokenBig = createToken(networkId = evmNetworkId, rawId = evmNetworkId, contract = "0xBEEF")
|
||||
|
||||
val statusSmall = createLoadedStatus(token = tokenSmall, amount = BigDecimal("1.00"), isYieldActive = false)
|
||||
val statusBig = createLoadedStatus(token = tokenBig, amount = BigDecimal("10.00"), isYieldActive = false)
|
||||
|
||||
val apyMap = mapOf(
|
||||
"${tokenSmall.network.backendId}_${tokenSmall.contractAddress.lowercase()}" to BigDecimal("0.05"),
|
||||
"${tokenBig.network.backendId}_${tokenBig.contractAddress.uppercase()}" to BigDecimal("0.15"),
|
||||
"${tokenSmall.network.rawId}_${tokenSmall.contractAddress.lowercase()}" to BigDecimal("0.05"),
|
||||
"${tokenBig.network.rawId}_${tokenBig.contractAddress.uppercase()}" to BigDecimal("0.15"),
|
||||
)
|
||||
|
||||
val params = TokenConverterParams.Wallet(
|
||||
|
|
@ -111,10 +111,10 @@ class YieldSupplyPromoBannerConverterTest {
|
|||
@Test
|
||||
fun `GIVEN non evm case sensitive mismatch WHEN convert THEN return null`() {
|
||||
val nonEvmId = "xrp"
|
||||
val token = createToken(networkId = nonEvmId, backendId = nonEvmId, contract = "rAbC123")
|
||||
val token = createToken(networkId = nonEvmId, rawId = nonEvmId, contract = "rAbC123")
|
||||
val status = createLoadedStatus(token = token, amount = BigDecimal("3"), isYieldActive = false)
|
||||
|
||||
val mismatchedKey = "${token.network.backendId}_${token.contractAddress.lowercase()}"
|
||||
val mismatchedKey = "${token.network.rawId}_${token.contractAddress.lowercase()}"
|
||||
val apyMap = mapOf(mismatchedKey to BigDecimal("0.07"))
|
||||
|
||||
val params = TokenConverterParams.Wallet(
|
||||
|
|
@ -133,14 +133,14 @@ class YieldSupplyPromoBannerConverterTest {
|
|||
|
||||
@Test
|
||||
fun `GIVEN custom status WHEN convert THEN return null`() {
|
||||
val token = createToken(networkId = "ethereum", backendId = "ethereum", contract = "0xCUSTOM")
|
||||
val token = createToken(networkId = "ethereum", rawId = "ethereum", contract = "0xCUSTOM")
|
||||
val status = createCustomStatus(token = token, amount = BigDecimal("5.0"), isYieldActive = false)
|
||||
val params = TokenConverterParams.Wallet(
|
||||
mainAccount = account,
|
||||
tokenList = ungroupedTokenList(status),
|
||||
)
|
||||
val converter = YieldSupplyPromoBannerConverter(
|
||||
yieldModuleApyMap = mapOf("${token.network.backendId}_${token.contractAddress}" to BigDecimal("0.10")),
|
||||
yieldModuleApyMap = mapOf("${token.network.rawId}_${token.contractAddress}" to BigDecimal("0.10")),
|
||||
shouldShowMainPromo = true,
|
||||
)
|
||||
|
||||
|
|
@ -236,15 +236,14 @@ class YieldSupplyPromoBannerConverterTest {
|
|||
)
|
||||
}
|
||||
|
||||
private fun createToken(networkId: String, backendId: String, contract: String): CryptoCurrency.Token {
|
||||
private fun createToken(networkId: String, rawId: String, contract: String): CryptoCurrency.Token {
|
||||
val network = Network(
|
||||
id = Network.ID(value = networkId, derivationPath = Network.DerivationPath.None),
|
||||
backendId = backendId,
|
||||
name = backendId,
|
||||
id = Network.ID(value = rawId, derivationPath = Network.DerivationPath.None),
|
||||
name = rawId,
|
||||
currencySymbol = "SYM",
|
||||
derivationPath = Network.DerivationPath.None,
|
||||
isTestnet = false,
|
||||
standardType = when (backendId) {
|
||||
standardType = when (rawId) {
|
||||
"ethereum" -> Network.StandardType.ERC20
|
||||
else -> Network.StandardType.Unspecified("UNSPEC")
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
package com.tangem.feature.wallet.child.managetokens.model
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.decompose.model.MutableParamsContainer
|
||||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.child.managetokens.AddAndManageBottomSheetComponent
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioFetcher
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorController
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.slot
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
internal class AddAndManageModelTest {
|
||||
|
||||
private val analyticsEventHandler: AnalyticsEventHandler = mockk(relaxed = true)
|
||||
private val portfolioFetcher: PortfolioFetcher = mockk(relaxed = true) {
|
||||
every { data } returns flowOf(
|
||||
PortfolioFetcher.Data(
|
||||
appCurrency = mockk(relaxed = true),
|
||||
isBalanceHidden = false,
|
||||
balances = emptyMap(),
|
||||
),
|
||||
)
|
||||
}
|
||||
private val portfolioFetcherFactory: PortfolioFetcher.Factory = mockk(relaxed = true) {
|
||||
every { create(any(), any()) } returns portfolioFetcher
|
||||
}
|
||||
private val portfolioSelectorController: PortfolioSelectorController = mockk(relaxed = true) {
|
||||
every { selectedAccount } returns flowOf(null)
|
||||
}
|
||||
|
||||
private val onDismiss: () -> Unit = mockk(relaxed = true)
|
||||
private val onOrganizeTokensClick: () -> Unit = mockk(relaxed = true)
|
||||
private val onManageTokensClick: (AccountId) -> Unit = mockk(relaxed = true)
|
||||
|
||||
private val userWalletId = UserWalletId(stringValue = "0123456789ABCDEF")
|
||||
|
||||
private val params = AddAndManageBottomSheetComponent.Params(
|
||||
userWalletId = userWalletId,
|
||||
onDismiss = onDismiss,
|
||||
onOrganizeTokensClick = onOrganizeTokensClick,
|
||||
onManageTokensClick = onManageTokensClick,
|
||||
)
|
||||
|
||||
private fun createModel(): AddAndManageModel = AddAndManageModel(
|
||||
paramsContainer = MutableParamsContainer(params),
|
||||
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||
portfolioFetcherFactory = portfolioFetcherFactory,
|
||||
analyticsEventHandler = analyticsEventHandler,
|
||||
portfolioSelectorController = portfolioSelectorController,
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `GIVEN bottom sheet model WHEN onAddTokensClick THEN sends ButtonAddTokens event with correct payload`() =
|
||||
runTest {
|
||||
val model = createModel()
|
||||
val captured = slot<AnalyticsEvent>()
|
||||
|
||||
model.onAddTokensClick()
|
||||
|
||||
verify(exactly = 1) { analyticsEventHandler.send(capture(captured)) }
|
||||
assertThat(captured.captured.category).isEqualTo("Portfolio")
|
||||
assertThat(captured.captured.event).isEqualTo("Button - Add tokens")
|
||||
assertThat(captured.captured.params).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN bottom sheet model WHEN onOrganizeTokensClick THEN sends ButtonOrganizeTokens event with correct payload`() =
|
||||
runTest {
|
||||
val model = createModel()
|
||||
val captured = slot<AnalyticsEvent>()
|
||||
|
||||
model.onOrganizeTokensClick()
|
||||
|
||||
verify(exactly = 1) { analyticsEventHandler.send(capture(captured)) }
|
||||
assertThat(captured.captured.category).isEqualTo("Portfolio")
|
||||
assertThat(captured.captured.event).isEqualTo("Button - Organize Tokens")
|
||||
assertThat(captured.captured.params).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN bottom sheet model WHEN onOrganizeTokensClick THEN dismisses bottom sheet and forwards to params callback`() =
|
||||
runTest {
|
||||
val model = createModel()
|
||||
|
||||
model.onOrganizeTokensClick()
|
||||
|
||||
verify(exactly = 1) { onDismiss() }
|
||||
verify(exactly = 1) { onOrganizeTokensClick() }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
package com.tangem.feature.wallet.child.wallet.model.intents
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.router.InnerWalletRouter
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.slot
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
internal class WalletContentClickIntentsAnalyticsTest {
|
||||
|
||||
private val stateHolder: WalletStateController = mockk(relaxed = true)
|
||||
private val analyticsEventHandler: AnalyticsEventHandler = mockk(relaxed = true)
|
||||
private val walletFeatureToggles: WalletFeatureToggles = mockk(relaxed = true)
|
||||
private val router: InnerWalletRouter = mockk(relaxed = true)
|
||||
|
||||
private val userWalletId = UserWalletId(stringValue = "0123456789ABCDEF")
|
||||
|
||||
private fun createImplementor(): WalletContentClickIntentsImplementor {
|
||||
every { stateHolder.getSelectedWalletId() } returns userWalletId
|
||||
|
||||
val implementor = WalletContentClickIntentsImplementor(
|
||||
stateHolder = stateHolder,
|
||||
currencyActionsClickIntents = mockk(relaxed = true),
|
||||
onrampStatusFactory = mockk(relaxed = true),
|
||||
getUserWalletUseCase = mockk(relaxed = true),
|
||||
singleAccountStatusListSupplier = mockk(relaxed = true),
|
||||
getCryptoCurrencyActionsUseCase = mockk(relaxed = true),
|
||||
getExplorerTransactionUrlUseCase = mockk(relaxed = true),
|
||||
shouldShowMarketsTooltipUseCase = mockk(relaxed = true),
|
||||
dispatchers = mockk(relaxed = true),
|
||||
walletEventSender = mockk(relaxed = true),
|
||||
analyticsEventHandler = analyticsEventHandler,
|
||||
accountDependencies = mockk(relaxed = true),
|
||||
yieldSupplySetShouldShowMainPromoUseCase = mockk(relaxed = true),
|
||||
tokenListAnalyticsSender = mockk(relaxed = true),
|
||||
uiMessageSender = mockk(relaxed = true),
|
||||
walletFeatureToggles = walletFeatureToggles,
|
||||
)
|
||||
implementor.initialize(router = router, coroutineScope = TestScope())
|
||||
return implementor
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN add and manage toggle enabled WHEN onOrganizeTokensClick THEN sends ButtonAddManage event and opens bottom sheet`() =
|
||||
runTest {
|
||||
every { walletFeatureToggles.isAddAndManageTokensEnabled } returns true
|
||||
val implementor = createImplementor()
|
||||
val captured = slot<AnalyticsEvent>()
|
||||
|
||||
implementor.onOrganizeTokensClick()
|
||||
|
||||
verify(exactly = 1) { analyticsEventHandler.send(capture(captured)) }
|
||||
assertThat(captured.captured.category).isEqualTo("Portfolio")
|
||||
assertThat(captured.captured.event).isEqualTo("Button - Add Manage")
|
||||
assertThat(captured.captured.params).isEmpty()
|
||||
verify(exactly = 1) { router.openAddAndManageBottomSheet(userWalletId = userWalletId) }
|
||||
verify(exactly = 0) { router.openOrganizeTokensScreen(any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN add and manage toggle disabled WHEN onOrganizeTokensClick THEN does not send analytics and opens organize screen`() =
|
||||
runTest {
|
||||
every { walletFeatureToggles.isAddAndManageTokensEnabled } returns false
|
||||
val implementor = createImplementor()
|
||||
|
||||
implementor.onOrganizeTokensClick()
|
||||
|
||||
verify(exactly = 0) { analyticsEventHandler.send(any<AnalyticsEvent>()) }
|
||||
verify(exactly = 1) { router.openOrganizeTokensScreen(userWalletId = userWalletId) }
|
||||
verify(exactly = 0) { router.openAddAndManageBottomSheet(any()) }
|
||||
}
|
||||
}
|
||||
|
|
@ -834,10 +834,9 @@ class DefaultPromoDeeplinkHandlerTest {
|
|||
address: String,
|
||||
derivationPath: Network.DerivationPath = Network.DerivationPath.None,
|
||||
): NetworkStatus {
|
||||
val networkId = Network.ID(Network.RawID(rawNetworkId), derivationPath)
|
||||
val networkId = Network.ID(value = rawNetworkId, derivationPath = derivationPath)
|
||||
val network = Network(
|
||||
id = networkId,
|
||||
backendId = rawNetworkId,
|
||||
name = rawNetworkId,
|
||||
currencySymbol = rawNetworkId.take(3).uppercase(),
|
||||
derivationPath = derivationPath,
|
||||
|
|
@ -866,10 +865,9 @@ class DefaultPromoDeeplinkHandlerTest {
|
|||
}
|
||||
|
||||
private fun buildUnreachableNetworkStatus(rawNetworkId: String): NetworkStatus {
|
||||
val networkId = Network.ID(Network.RawID(rawNetworkId), Network.DerivationPath.None)
|
||||
val networkId = Network.ID(value = rawNetworkId, derivationPath = Network.DerivationPath.None)
|
||||
val network = Network(
|
||||
id = networkId,
|
||||
backendId = rawNetworkId,
|
||||
name = rawNetworkId,
|
||||
currencySymbol = rawNetworkId.take(3).uppercase(),
|
||||
derivationPath = Network.DerivationPath.None,
|
||||
|
|
@ -890,10 +888,9 @@ class DefaultPromoDeeplinkHandlerTest {
|
|||
rawNetworkId: String,
|
||||
derivationPath: Network.DerivationPath = Network.DerivationPath.None,
|
||||
): CryptoCurrency.Coin {
|
||||
val networkId = Network.ID(Network.RawID(rawNetworkId), derivationPath)
|
||||
val networkId = Network.ID(value = rawNetworkId, derivationPath = derivationPath)
|
||||
val network = Network(
|
||||
id = networkId,
|
||||
backendId = rawNetworkId,
|
||||
name = rawNetworkId,
|
||||
currencySymbol = rawNetworkId.take(3).uppercase(),
|
||||
derivationPath = derivationPath,
|
||||
|
|
|
|||
|
|
@ -285,8 +285,7 @@ internal class QrContentClassifierTest {
|
|||
|
||||
private fun buildNetwork(rawNetworkId: String): Network {
|
||||
return Network(
|
||||
id = Network.ID(Network.RawID(rawNetworkId), Network.DerivationPath.None),
|
||||
backendId = rawNetworkId,
|
||||
id = Network.ID(value = rawNetworkId, derivationPath = Network.DerivationPath.None),
|
||||
name = rawNetworkId,
|
||||
currencySymbol = rawNetworkId.take(3).uppercase(),
|
||||
derivationPath = Network.DerivationPath.None,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue