Updated on 2026-08-14

This commit is contained in:
Tangem 2026-06-19 20:01:38 +05:00
parent 4d75db3cdd
commit 22dc2eb3e9
57 changed files with 931 additions and 258 deletions

View file

@ -25,7 +25,7 @@ import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.domain.tokens.model.details.TokenAction
import com.tangem.feature.wallet.child.managetokens.AddAndManageBottomSheetComponent
import com.tangem.feature.wallet.child.organizetokens.OrganizeTokensComponent
import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent
import com.tangem.features.commonfeatures.api.managefunds.ManageFundsComponent
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
@ -70,7 +70,7 @@ internal class WalletComponent @AssistedInject constructor(
private val networkSelectionComponentFactory: NetworkSelectionComponent.Factory,
private val tokenActionsComponentFactory: TokenActionsComponent.Factory,
private val portfolioSelectorComponentFactory: PortfolioSelectorComponent.Factory,
private val addFundsComponentFactory: AddFundsComponent.Factory,
private val manageFundsComponentFactory: ManageFundsComponent.Factory,
private val designFeatureToggles: DesignFeatureToggles,
) : ComposableContentComponent, AppComponentContext by appComponentContext {
@ -191,10 +191,20 @@ internal class WalletComponent @AssistedInject constructor(
)
}
is WalletDialogConfig.AddFunds -> {
addFundsComponentFactory.create(
manageFundsComponentFactory.create(
context = childByContext(componentContext),
params = AddFundsComponent.Params(
launchMode = AddFundsComponent.LaunchMode.ChooseToken(dialogConfig.userWalletId),
params = ManageFundsComponent.Params(
launchMode = ManageFundsComponent.LaunchMode.ChooseToken(dialogConfig.userWalletId),
onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
),
)
}
is WalletDialogConfig.Transfer -> {
manageFundsComponentFactory.create(
context = childByContext(componentContext),
params = ManageFundsComponent.Params(
launchMode = ManageFundsComponent.LaunchMode.ChooseToken(dialogConfig.userWalletId),
flowType = ManageFundsComponent.FlowType.Transfer,
onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
),
)

View file

@ -566,6 +566,7 @@ internal class WalletModel @Inject constructor(
walletImageResolver = walletImageResolver,
getWalletIconUseCase = getWalletIconUseCase,
isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled,
isManageFundsEnabled = walletFeatureToggles.isManageFundsEnabled,
),
)
@ -613,6 +614,7 @@ internal class WalletModel @Inject constructor(
walletImageResolver = walletImageResolver,
getWalletIconUseCase = getWalletIconUseCase,
isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled,
isManageFundsEnabled = walletFeatureToggles.isManageFundsEnabled,
),
)
}
@ -635,6 +637,7 @@ internal class WalletModel @Inject constructor(
walletImageResolver = walletImageResolver,
getWalletIconUseCase = getWalletIconUseCase,
isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled,
isManageFundsEnabled = walletFeatureToggles.isManageFundsEnabled,
),
)
}
@ -650,6 +653,7 @@ internal class WalletModel @Inject constructor(
walletImageResolver = walletImageResolver,
getWalletIconUseCase = getWalletIconUseCase,
isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled,
isManageFundsEnabled = walletFeatureToggles.isManageFundsEnabled,
),
)
@ -712,6 +716,7 @@ internal class WalletModel @Inject constructor(
walletImageResolver = walletImageResolver,
getWalletIconUseCase = getWalletIconUseCase,
isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled,
isManageFundsEnabled = walletFeatureToggles.isManageFundsEnabled,
),
)

View file

@ -124,6 +124,10 @@ internal class WalletClickIntents @Inject constructor(
router.openAddFunds(userWalletId)
}
fun onTransferClick(userWalletId: UserWalletId) {
router.openTransfer(userWalletId)
}
fun onAddFundsPromoClick(userWalletId: UserWalletId) {
analyticsEventHandler.send(WalletScreenAnalyticsEvent.MainScreen.ButtonAddFundsPromo())
router.openAddFunds(userWalletId)

View file

@ -14,4 +14,7 @@ internal class DefaultWalletFeatureToggles @Inject constructor(
override val isAddFundsStage1Enabled: Boolean
get() = featureToggles.isFeatureEnabled(FeatureToggles.AND_15310_ADD_FUNDS_STAGE1)
override val isManageFundsEnabled: Boolean
get() = featureToggles.isFeatureEnabled(FeatureToggles.TWI_1377_MANAGE_FUNDS)
}

View file

@ -125,6 +125,12 @@ internal class DefaultWalletRouter @Inject constructor(
)
}
override fun openTransfer(userWalletId: UserWalletId) {
dialogNavigation.activate(
configuration = WalletDialogConfig.Transfer(userWalletId = userWalletId),
)
}
override fun isWalletLastScreen(): Boolean {
return router.stack.lastOrNull() is AppRoute.Wallet
}

View file

@ -120,4 +120,7 @@ internal interface InnerWalletRouter {
/** Open Add Funds screen */
fun openAddFunds(userWalletId: UserWalletId)
/** Open Transfer screen */
fun openTransfer(userWalletId: UserWalletId)
}

View file

@ -56,7 +56,7 @@ internal sealed class WalletActionButtons(
override val isEnabled: Boolean,
) : WalletActionButtons(
text = resourceReference(R.string.common_add_funds),
iconRes = R.drawable.ic_plus_default_24,
iconRes = R.drawable.ic_arrow_down_24,
)
data class Swap(
@ -74,4 +74,12 @@ internal sealed class WalletActionButtons(
text = resourceReference(R.string.common_sell),
iconRes = R.drawable.ic_dollar_default_24,
)
data class Transfer(
override val onClick: () -> Unit,
override val isEnabled: Boolean,
) : WalletActionButtons(
text = resourceReference(R.string.common_transfer),
iconRes = R.drawable.ic_arrow_up_24,
)
}

View file

@ -65,6 +65,9 @@ internal sealed interface WalletDialogConfig {
@Serializable
data class AddFunds(val userWalletId: UserWalletId) : WalletDialogConfig
@Serializable
data class Transfer(val userWalletId: UserWalletId) : WalletDialogConfig
@Serializable
data class OrganizeTokens(val userWalletId: UserWalletId) : WalletDialogConfig

View file

@ -58,7 +58,7 @@ internal sealed class WalletManageButton(val config: ActionButtonConfig) {
) : WalletManageButton(
config = ActionButtonConfig(
text = TextReference.Res(id = R.string.common_add_funds),
iconResId = R.drawable.ic_plus_24,
iconResId = R.drawable.ic_arrow_down_24,
onClick = onClick,
isEnabled = enabled,
shouldDimContent = dimContent,
@ -145,6 +145,29 @@ internal sealed class WalletManageButton(val config: ActionButtonConfig) {
),
)
/**
* Transfer
*
* @property enabled button click availability
* @property dimContent determines whether the button content will be dimmed
* @property onClick lambda be invoked when Transfer button is clicked
*/
data class Transfer(
override val enabled: Boolean,
override val dimContent: Boolean,
override val onClick: () -> Unit,
val isInProgress: Boolean = false,
) : WalletManageButton(
config = ActionButtonConfig(
text = TextReference.Res(id = R.string.common_transfer),
iconResId = R.drawable.ic_arrow_up_24,
onClick = onClick,
isEnabled = enabled,
shouldDimContent = dimContent,
isInProgress = isInProgress,
),
)
/**
* Swap
*

View file

@ -14,6 +14,7 @@ internal class AddWalletTransformer(
private val walletImageResolver: WalletImageResolver,
private val getWalletIconUseCase: GetWalletIconUseCase,
private val isAddFundsStage1Enabled: Boolean,
private val isManageFundsEnabled: Boolean,
) : WalletScreenStateTransformer {
private val walletLoadingStateFactory by lazy {
@ -22,6 +23,7 @@ internal class AddWalletTransformer(
walletImageResolver = walletImageResolver,
getWalletIconUseCase = getWalletIconUseCase,
isAddFundsStage1Enabled = isAddFundsStage1Enabled,
isManageFundsEnabled = isManageFundsEnabled,
)
}

View file

@ -21,6 +21,7 @@ import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toPersistentList
import com.tangem.core.ui.R as CoreUiR
@Suppress("LongParameterList")
internal class InitializeWalletsTransformer(
private val selectedWalletIndex: Int,
private val wallets: List<UserWallet>,
@ -28,6 +29,7 @@ internal class InitializeWalletsTransformer(
private val walletImageResolver: WalletImageResolver,
private val getWalletIconUseCase: GetWalletIconUseCase,
private val isAddFundsStage1Enabled: Boolean,
private val isManageFundsEnabled: Boolean,
) : WalletScreenStateTransformer {
private val walletLoadingStateFactory by lazy {
@ -36,6 +38,7 @@ internal class InitializeWalletsTransformer(
walletImageResolver = walletImageResolver,
getWalletIconUseCase = getWalletIconUseCase,
isAddFundsStage1Enabled = isAddFundsStage1Enabled,
isManageFundsEnabled = isManageFundsEnabled,
)
}
@ -159,10 +162,16 @@ internal class InitializeWalletsTransformer(
WalletManageButton.Buy(enabled = false, dimContent = false, onClick = {})
}
val lastButton = if (isManageFundsEnabled) {
WalletManageButton.Transfer(enabled = false, dimContent = false, onClick = {})
} else {
WalletManageButton.Sell(enabled = false, dimContent = false, onClick = {})
}
return persistentListOf(
firstButton,
WalletManageButton.Swap(enabled = false, dimContent = false, onClick = {}),
WalletManageButton.Sell(enabled = false, dimContent = false, onClick = {}),
lastButton,
)
}
@ -190,12 +199,21 @@ internal class InitializeWalletsTransformer(
onClick = {},
).buttonUM,
)
add(
WalletActionButtons.Sell(
isEnabled = false,
onClick = {},
).buttonUM,
)
if (isManageFundsEnabled) {
add(
WalletActionButtons.Transfer(
isEnabled = false,
onClick = {},
).buttonUM,
)
} else {
add(
WalletActionButtons.Sell(
isEnabled = false,
onClick = {},
).buttonUM,
)
}
}.toPersistentList()
}
}

View file

@ -18,6 +18,7 @@ import kotlinx.collections.immutable.toImmutableList
*
[REDACTED_AUTHOR]
*/
@Suppress("LongParameterList")
internal class ReinitializeNewWalletTransformer(
private val prevWalletId: UserWalletId,
private val newUserWallet: UserWallet,
@ -25,6 +26,7 @@ internal class ReinitializeNewWalletTransformer(
private val walletImageResolver: WalletImageResolver,
private val getWalletIconUseCase: GetWalletIconUseCase,
private val isAddFundsStage1Enabled: Boolean,
private val isManageFundsEnabled: Boolean,
) : WalletScreenStateTransformer {
private val walletLoadingStateFactory by lazy {
@ -33,6 +35,7 @@ internal class ReinitializeNewWalletTransformer(
walletImageResolver = walletImageResolver,
getWalletIconUseCase = getWalletIconUseCase,
isAddFundsStage1Enabled = isAddFundsStage1Enabled,
isManageFundsEnabled = isManageFundsEnabled,
)
}

View file

@ -21,6 +21,7 @@ internal class ReinitializeWalletTransformer(
private val walletImageResolver: WalletImageResolver,
private val getWalletIconUseCase: GetWalletIconUseCase,
private val isAddFundsStage1Enabled: Boolean,
private val isManageFundsEnabled: Boolean,
) : WalletStateTransformer(userWalletId = userWallet.walletId) {
private val walletLoadingStateFactory by lazy {
@ -29,6 +30,7 @@ internal class ReinitializeWalletTransformer(
walletImageResolver = walletImageResolver,
getWalletIconUseCase = getWalletIconUseCase,
isAddFundsStage1Enabled = isAddFundsStage1Enabled,
isManageFundsEnabled = isManageFundsEnabled,
)
}

View file

@ -87,6 +87,7 @@ internal class SetRefreshStateTransformer(
is WalletManageButton.AddFunds -> button.copy(enabled = isButtonsEnabled)
is WalletManageButton.Send -> button.copy(enabled = isButtonsEnabled)
is WalletManageButton.Sell -> button.copy(enabled = isButtonsEnabled)
is WalletManageButton.Transfer -> button.copy(enabled = isButtonsEnabled)
is WalletManageButton.Receive -> button
is WalletManageButton.Stake -> null
is WalletManageButton.Swap -> null

View file

@ -19,6 +19,7 @@ internal class UnlockWalletTransformer(
private val walletImageResolver: WalletImageResolver,
private val getWalletIconUseCase: GetWalletIconUseCase,
private val isAddFundsStage1Enabled: Boolean,
private val isManageFundsEnabled: Boolean,
) : WalletScreenStateTransformer {
private val walletLoadingStateFactory by lazy {
@ -27,6 +28,7 @@ internal class UnlockWalletTransformer(
walletImageResolver = walletImageResolver,
getWalletIconUseCase = getWalletIconUseCase,
isAddFundsStage1Enabled = isAddFundsStage1Enabled,
isManageFundsEnabled = isManageFundsEnabled,
)
}

View file

@ -45,6 +45,7 @@ private fun WalletState.MultiCurrency.Content.changeAvailability(enabled: Boolea
is WalletManageButton.Buy -> action.copy(enabled = enabled)
is WalletManageButton.AddFunds -> action.copy(enabled = enabled)
is WalletManageButton.Sell -> action.copy(enabled = enabled)
is WalletManageButton.Transfer -> action.copy(enabled = enabled)
is WalletManageButton.Swap -> action.copy(enabled = enabled)
else -> action
}

View file

@ -36,6 +36,7 @@ internal class WalletLoadingStateFactory(
private val walletImageResolver: WalletImageResolver,
private val getWalletIconUseCase: GetWalletIconUseCase,
private val isAddFundsStage1Enabled: Boolean,
private val isManageFundsEnabled: Boolean,
) {
fun create(userWallet: UserWallet): WalletState {
@ -171,6 +172,20 @@ internal class WalletLoadingStateFactory(
)
}
val lastButton = if (isManageFundsEnabled) {
WalletManageButton.Transfer(
enabled = true,
dimContent = false,
onClick = { clickIntents.onTransferClick(userWallet.walletId) },
)
} else {
WalletManageButton.Sell(
enabled = true,
dimContent = false,
onClick = { clickIntents.onMultiWalletSellClick(userWalletId = userWallet.walletId) },
)
}
return persistentListOf(
firstButton,
WalletManageButton.Swap(
@ -178,11 +193,7 @@ internal class WalletLoadingStateFactory(
dimContent = false,
onClick = { clickIntents.onMultiWalletSwapClick(userWalletId = userWallet.walletId) },
),
WalletManageButton.Sell(
enabled = true,
dimContent = false,
onClick = { clickIntents.onMultiWalletSellClick(userWalletId = userWallet.walletId) },
),
lastButton,
)
}
@ -205,14 +216,25 @@ internal class WalletLoadingStateFactory(
},
).buttonUM,
)
add(
WalletActionButtons.Sell(
isEnabled = false,
onClick = {
clickIntents.onMultiWalletSellClick(userWalletId = userWallet.walletId)
},
).buttonUM,
)
if (isManageFundsEnabled) {
add(
WalletActionButtons.Transfer(
isEnabled = false,
onClick = {
clickIntents.onTransferClick(userWalletId = userWallet.walletId)
},
).buttonUM,
)
} else {
add(
WalletActionButtons.Sell(
isEnabled = false,
onClick = {
clickIntents.onMultiWalletSellClick(userWalletId = userWallet.walletId)
},
).buttonUM,
)
}
}.toPersistentList()
}