Updated on 2026-08-14
This commit is contained in:
parent
a1a82d3ece
commit
b27ff31652
52 changed files with 860 additions and 518 deletions
|
|
@ -9,7 +9,6 @@ import com.tangem.feature.stories.api.StoriesComponent
|
|||
import com.tangem.feature.usedesk.api.UsedeskComponent
|
||||
import com.tangem.feature.walletsettings.component.WalletSettingsComponent
|
||||
import com.tangem.features.account.AccountCreateEditComponent
|
||||
import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent
|
||||
import com.tangem.features.account.AccountDetailsComponent
|
||||
import com.tangem.features.account.ArchivedAccountListComponent
|
||||
import com.tangem.features.createwalletselection.CreateWalletSelectionComponent
|
||||
|
|
@ -116,7 +115,6 @@ internal class ChildFactory @Inject constructor(
|
|||
private val surveyComponentFactory: SurveyComponent.Factory,
|
||||
private val yieldSupplyEntryComponentFactory: YieldSupplyEntryComponent.Factory,
|
||||
private val feedEntryComponentFactory: FeedEntryComponent.Factory,
|
||||
private val addFundsComponentFactory: AddFundsComponent.Factory,
|
||||
) {
|
||||
|
||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||
|
|
@ -237,13 +235,6 @@ internal class ChildFactory @Inject constructor(
|
|||
componentFactory = buyCryptoComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.AddFunds -> {
|
||||
createComponentChild(
|
||||
context = context,
|
||||
params = AddFundsComponent.Params(userWalletId = route.userWalletId),
|
||||
componentFactory = addFundsComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.SellCrypto -> {
|
||||
createComponentChild(
|
||||
context = context,
|
||||
|
|
|
|||
|
|
@ -59,11 +59,6 @@ sealed class AppRoute(val path: String) : Route {
|
|||
@Serializable
|
||||
data object Wallet : AppRoute(path = "/wallet")
|
||||
|
||||
@Serializable
|
||||
data class AddFunds(
|
||||
val userWalletId: UserWalletId,
|
||||
) : AppRoute(path = "/add_funds/${userWalletId.stringValue}")
|
||||
|
||||
@Serializable
|
||||
data class CurrencyDetails(
|
||||
val userWalletId: UserWalletId,
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class TokenActionsHandler @AssistedInject constructor(
|
|||
private val urlOpener: UrlOpener,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
@Assisted private val currentAppCurrency: Provider<AppCurrency>,
|
||||
@Assisted private val onHandleQuickAction: (HandledQuickAction) -> Unit,
|
||||
@Assisted private val onHandleQuickAction: (action: HandledQuickAction, shouldDismiss: Boolean) -> Unit,
|
||||
private val isDemoCardUseCase: IsDemoCardUseCase,
|
||||
private val messageSender: UiMessageSender,
|
||||
) {
|
||||
|
|
@ -49,6 +49,18 @@ class TokenActionsHandler @AssistedInject constructor(
|
|||
action = action,
|
||||
cryptoCurrencyData = cryptoCurrencyData,
|
||||
),
|
||||
when (action) {
|
||||
TokenActionsBSContentUM.Action.Receive,
|
||||
TokenActionsBSContentUM.Action.CopyAddress,
|
||||
TokenActionsBSContentUM.Action.Sell,
|
||||
-> false
|
||||
TokenActionsBSContentUM.Action.Send,
|
||||
TokenActionsBSContentUM.Action.Stake,
|
||||
TokenActionsBSContentUM.Action.YieldMode,
|
||||
TokenActionsBSContentUM.Action.Buy,
|
||||
TokenActionsBSContentUM.Action.Exchange,
|
||||
-> true
|
||||
},
|
||||
)
|
||||
val userWallet = cryptoCurrencyData.userWallet
|
||||
if (userWallet is UserWallet.Cold && handleDemoMode(action, userWallet)) return
|
||||
|
|
@ -164,7 +176,7 @@ class TokenActionsHandler @AssistedInject constructor(
|
|||
interface Factory {
|
||||
fun create(
|
||||
currentAppCurrency: Provider<AppCurrency>,
|
||||
onHandleQuickAction: (HandledQuickAction) -> Unit,
|
||||
onHandleQuickAction: (HandledQuickAction, shouldDismiss: Boolean) -> Unit,
|
||||
): TokenActionsHandler
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,29 @@
|
|||
package com.tangem.features.commonfeatures.api.addfunds
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
||||
interface AddFundsComponent : ComposableContentComponent {
|
||||
interface AddFundsComponent : ComposableBottomSheetComponent {
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
val launchMode: LaunchMode,
|
||||
val onDismiss: () -> Unit,
|
||||
)
|
||||
|
||||
sealed interface LaunchMode {
|
||||
data class ChooseToken(val userWalletId: UserWalletId) : LaunchMode
|
||||
|
||||
data class TokenActionsOnly(
|
||||
val userWalletId: UserWalletId,
|
||||
val currency: CryptoCurrency,
|
||||
) : LaunchMode
|
||||
|
||||
data class FilteredByRawId(
|
||||
val rawCurrencyId: CryptoCurrency.RawID,
|
||||
) : LaunchMode
|
||||
}
|
||||
|
||||
interface Factory : ComponentFactory<Params, AddFundsComponent>
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
|||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioManager.AnalyticsParams
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioFetcher
|
||||
import com.tangem.features.commonfeatures.api.tokenactions.BottomAction
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
|
|
@ -94,7 +95,14 @@ interface AddToPortfolioManager : AddToPortfolioManagerInternal {
|
|||
val wallet: UserWallet,
|
||||
val account: AccountStatus.CryptoPortfolio,
|
||||
val addedCurrency: CryptoCurrencyStatus,
|
||||
val meta: FinishMeta = FinishMeta.None,
|
||||
)
|
||||
|
||||
sealed interface FinishMeta {
|
||||
data object None : FinishMeta
|
||||
data object OnQuickAction : FinishMeta
|
||||
data class OnBottomAction(val action: BottomAction) : FinishMeta
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ interface ChooseTokenBridge : ChooseTokenBridgeInternal {
|
|||
val title: TextReference,
|
||||
val isShowMarketBlock: Boolean,
|
||||
val isShowPaymentAccount: Boolean,
|
||||
val isAppBarShown: Boolean = true,
|
||||
) {
|
||||
companion object {
|
||||
val SwapFrom = Settings(
|
||||
|
|
@ -45,6 +46,7 @@ interface ChooseTokenBridge : ChooseTokenBridgeInternal {
|
|||
title = resourceReference(R.string.swapping_to_title),
|
||||
isShowMarketBlock = true,
|
||||
isShowPaymentAccount = false,
|
||||
isAppBarShown = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -90,6 +92,11 @@ data class ChooseTokenResult(
|
|||
val analyticsPayload: Set<ChooseTokenAnalyticsPayload> = emptySet(),
|
||||
) {
|
||||
val walletId get() = wallet.walletId
|
||||
|
||||
val wasJustAdded: Boolean
|
||||
get() = analyticsPayload
|
||||
.filterIsInstance<ChooseTokenAnalyticsPayload.IsMarketTokenSelected>()
|
||||
.any { it.value }
|
||||
}
|
||||
|
||||
sealed interface ChooseTokenAnalyticsPayload {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
package com.tangem.features.commonfeatures.api.tokenactions
|
||||
|
||||
enum class BottomAction { GoToToken, None }
|
||||
|
|
@ -1,93 +1,232 @@
|
|||
package com.tangem.features.commonfeatures.impl.addfunds
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.child
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.components.bottomsheets.LocalTangemBottomSheetContentBottomInset
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
|
||||
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.extensions.resourceReference
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetType
|
||||
import com.tangem.core.ui.ds.topbar.TangemTopBar
|
||||
import com.tangem.core.ui.ds.topbar.TangemTopBarType
|
||||
import com.tangem.core.ui.extensions.clickableSingle
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemeRedesign
|
||||
import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenComponent
|
||||
import com.tangem.features.commonfeatures.impl.R
|
||||
import com.tangem.features.commonfeatures.impl.addfunds.model.AddFundsModel
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.TokenActionsComponent
|
||||
import com.tangem.features.commonfeatures.impl.addfunds.model.uiSpec
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.TokenActionsComponent
|
||||
import com.tangem.features.commonfeatures.impl.userportfolio.UserPortfolioComponent
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import com.tangem.core.ui.R as CoreR
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class DefaultAddFundsComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted private val params: AddFundsComponent.Params,
|
||||
chooseTokenComponentFactory: ChooseTokenComponent.Factory,
|
||||
tokenActionsComponentFactory: TokenActionsComponent.Factory,
|
||||
userPortfolioComponentFactory: UserPortfolioComponent.Factory,
|
||||
walletFeatureToggles: WalletFeatureToggles,
|
||||
) : AppComponentContext by appComponentContext, AddFundsComponent {
|
||||
|
||||
private val model: AddFundsModel = getOrCreateModel(params)
|
||||
|
||||
private val chooseTokenComponent: ChooseTokenComponent = chooseTokenComponentFactory.create(
|
||||
context = child(key = "addFundsChooseToken"),
|
||||
params = ChooseTokenComponent.Params(bridge = model.chooseTokenBridge),
|
||||
)
|
||||
private val isCompactTokenActions: Boolean = params.launchMode is AddFundsComponent.LaunchMode.TokenActionsOnly
|
||||
|
||||
private val tokenActionsComponent: TokenActionsComponent = tokenActionsComponentFactory.create(
|
||||
context = child(key = "addFundsTokenActions"),
|
||||
params = TokenActionsComponent.Params(
|
||||
data = model.tokenActionsData,
|
||||
callbacks = model,
|
||||
bottomAction = TokenActionsComponent.BottomAction.GoToToken,
|
||||
isRedesignForced = true,
|
||||
),
|
||||
)
|
||||
private val isAddFundsStage1Enabled: Boolean = walletFeatureToggles.isAddFundsStage1Enabled
|
||||
|
||||
private val tokenActionsComponent: TokenActionsComponent by lazy {
|
||||
tokenActionsComponentFactory.create(
|
||||
context = child(key = "addFundsTokenActions"),
|
||||
params = TokenActionsComponent.Params(
|
||||
data = model.tokenActionsData,
|
||||
callbacks = model,
|
||||
bottomAction = model.currentBottomAction,
|
||||
isRedesignForced = true,
|
||||
isCompact = isCompactTokenActions,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private val chooseTokenComponent: ChooseTokenComponent? by lazy {
|
||||
(params.launchMode as? AddFundsComponent.LaunchMode.ChooseToken)?.let {
|
||||
chooseTokenComponentFactory.create(
|
||||
context = child(key = "addFundsChooseToken"),
|
||||
params = ChooseTokenComponent.Params(
|
||||
bridge = model.chooseTokenBridge,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val userPortfolioComponent: UserPortfolioComponent by lazy {
|
||||
userPortfolioComponentFactory.create(
|
||||
context = child(key = "addFundsUserPortfolio"),
|
||||
params = UserPortfolioComponent.Params(
|
||||
uiState = model.userPortfolioStateController.uiState,
|
||||
callbacks = object : UserPortfolioComponent.Callbacks {
|
||||
override fun onContinueFromUserPortfolio() = Unit
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun dismiss() = model.onDismiss()
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
chooseTokenComponent.Content(modifier)
|
||||
val isTokenActionsShown by model.isTokenActionsShown.collectAsStateWithLifecycle()
|
||||
if (isTokenActionsShown) {
|
||||
// force use redesign theme here according to the task requirements, will be reworked in the next release
|
||||
TangemThemeRedesign {
|
||||
TangemModalBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||
config = TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = model::onTokenActionsDismiss,
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
),
|
||||
containerColor = TangemTheme.colors2.surface.level2,
|
||||
scrollableContent = true,
|
||||
title = {
|
||||
TangemModalBottomSheetTitle(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
title = resourceReference(R.string.common_get_token),
|
||||
endIconRes = R.drawable.ic_close_24,
|
||||
onEndClick = model::onTokenActionsDismiss,
|
||||
)
|
||||
},
|
||||
content = { _ ->
|
||||
Column(
|
||||
modifier = Modifier.padding(
|
||||
start = TangemTheme.dimens2.x4,
|
||||
top = TangemTheme.dimens2.x2,
|
||||
end = TangemTheme.dimens2.x4,
|
||||
bottom = TangemTheme.dimens2.x4,
|
||||
),
|
||||
) {
|
||||
tokenActionsComponent.Content(Modifier)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
override fun BottomSheet() {
|
||||
val route by model.uiRoute.collectAsStateWithLifecycle()
|
||||
val canGoBack by model.canGoBack.collectAsStateWithLifecycle()
|
||||
|
||||
LaunchedEffect(route) {
|
||||
if (route != AddFundsModel.UiRoute.UserPortfolio) return@LaunchedEffect
|
||||
val mode = params.launchMode as? AddFundsComponent.LaunchMode.FilteredByRawId ?: return@LaunchedEffect
|
||||
model.userPortfolioStateController.updateAndWaitNotNullState(
|
||||
allAvailableData = model.buildAvailableToAddDataForChooser(),
|
||||
rawCurrencyId = mode.rawCurrencyId,
|
||||
)
|
||||
}
|
||||
|
||||
WithOptionalRedesignTheme(isEnabled = isAddFundsStage1Enabled) {
|
||||
TangemBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||
onBack = if (canGoBack) model::onBack else ::dismiss,
|
||||
config = TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = ::dismiss,
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
),
|
||||
type = when (params.launchMode) {
|
||||
is AddFundsComponent.LaunchMode.TokenActionsOnly -> TangemBottomSheetType.Modal
|
||||
is AddFundsComponent.LaunchMode.ChooseToken -> TangemBottomSheetType.Default
|
||||
is AddFundsComponent.LaunchMode.FilteredByRawId ->
|
||||
if (route is AddFundsModel.UiRoute.TokenActions) {
|
||||
TangemBottomSheetType.Default
|
||||
} else {
|
||||
TangemBottomSheetType.Modal
|
||||
}
|
||||
},
|
||||
containerColor = TangemTheme.colors2.surface.level2,
|
||||
title = {
|
||||
AddFundsBottomSheetTitle(
|
||||
route = route,
|
||||
canGoBack = canGoBack,
|
||||
onBackClick = model::onBack,
|
||||
onCloseClick = ::dismiss,
|
||||
)
|
||||
},
|
||||
content = {
|
||||
val animatedContentModifier =
|
||||
if (params.launchMode is AddFundsComponent.LaunchMode.ChooseToken) {
|
||||
Modifier.fillMaxSize()
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
AnimatedContent(
|
||||
targetState = route,
|
||||
modifier = animatedContentModifier,
|
||||
label = "AddFundsContentAnimation",
|
||||
) { animatedRoute ->
|
||||
AddFundsRouteContent(
|
||||
route = animatedRoute,
|
||||
shouldFillHeight = !isCompactTokenActions && animatedRoute.uiSpec().shouldFillHeight,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AddFundsRouteContent(route: AddFundsModel.UiRoute, shouldFillHeight: Boolean) {
|
||||
val spec = route.uiSpec()
|
||||
val horizontalPadding = if (spec.shouldApplyHorizontalPadding) {
|
||||
Modifier.padding(horizontal = TangemTheme.dimens2.x4)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
val sizeModifier = if (shouldFillHeight) Modifier.fillMaxSize() else Modifier.fillMaxWidth()
|
||||
RenderRoute(route, horizontalPadding.then(sizeModifier))
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RenderRoute(route: AddFundsModel.UiRoute, modifier: Modifier = Modifier) {
|
||||
when (route) {
|
||||
AddFundsModel.UiRoute.Loading -> Unit
|
||||
AddFundsModel.UiRoute.ChooseToken -> chooseTokenComponent?.Content(modifier)
|
||||
AddFundsModel.UiRoute.UserPortfolio -> CompositionLocalProvider(
|
||||
LocalTangemBottomSheetContentBottomInset provides TangemTheme.dimens2.x4,
|
||||
) {
|
||||
userPortfolioComponent.Content(modifier)
|
||||
}
|
||||
AddFundsModel.UiRoute.TokenActions -> tokenActionsComponent.Content(modifier)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AddFundsBottomSheetTitle(
|
||||
route: AddFundsModel.UiRoute,
|
||||
canGoBack: Boolean,
|
||||
onBackClick: () -> Unit,
|
||||
onCloseClick: () -> Unit,
|
||||
) {
|
||||
TangemTopBar(
|
||||
title = route.uiSpec().title,
|
||||
type = TangemTopBarType.BottomSheet,
|
||||
startContent = if (canGoBack) {
|
||||
{ CircleIconButton(iconRes = CoreR.drawable.ic_arrow_back_28, onClick = onBackClick) }
|
||||
} else {
|
||||
null
|
||||
},
|
||||
endContent = {
|
||||
CircleIconButton(iconRes = R.drawable.ic_close_24, onClick = onCloseClick)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WithOptionalRedesignTheme(isEnabled: Boolean, content: @Composable () -> Unit) {
|
||||
if (isEnabled) {
|
||||
TangemThemeRedesign(content = content)
|
||||
} else {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CircleIconButton(iconRes: Int, onClick: () -> Unit) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(id = iconRes),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors2.graphic.neutral.primary,
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens2.x11)
|
||||
.background(
|
||||
color = TangemTheme.colors2.button.backgroundSecondary,
|
||||
shape = CircleShape,
|
||||
)
|
||||
.clickableSingle(onClick = onClick)
|
||||
.padding(TangemTheme.dimens2.x2),
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@ internal sealed class AddFundsAnalyticsEvent(
|
|||
|
||||
class ButtonReceive : AddFundsAnalyticsEvent(event = "Button - Receive")
|
||||
|
||||
class ButtonGoToToken : AddFundsAnalyticsEvent(event = "Button - Go to Token")
|
||||
|
||||
companion object {
|
||||
private const val CATEGORY = "Add Funds"
|
||||
const val SOURCE_MAIN_SCREEN = "Main Screen"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.commonfeatures.impl.addfunds.model
|
||||
|
||||
import com.tangem.blockchainsdk.compatibility.getTokenIdIfL2Network
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.ui.markets.action.CryptoCurrencyData
|
||||
|
|
@ -8,14 +9,25 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
|
|||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.domain.account.status.supplier.MultiAccountStatusListSupplier
|
||||
import com.tangem.domain.account.status.usecase.GetCryptoCurrencyActionsUseCaseV2
|
||||
import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase
|
||||
import com.tangem.domain.models.account.AccountStatus
|
||||
import com.tangem.domain.models.account.filterCryptoPortfolio
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.AvailableToAddData
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.AvailableToAddWallet
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenAnalyticsPayload
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridge
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenResult
|
||||
import com.tangem.features.commonfeatures.api.tokenactions.BottomAction
|
||||
import com.tangem.features.commonfeatures.impl.addfunds.analytics.AddFundsAnalyticsEvent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.TokenActionsComponent
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.TokenActionsComponent
|
||||
import com.tangem.features.commonfeatures.impl.userportfolio.state.UserPortfolioStateController
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
|
@ -23,98 +35,257 @@ import kotlinx.coroutines.launch
|
|||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
@Suppress("LongParameterList")
|
||||
internal class AddFundsModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
chooseTokenBridgeFactory: ChooseTokenBridge.Factory,
|
||||
userPortfolioStateControllerFactory: UserPortfolioStateController.Factory,
|
||||
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCaseV2,
|
||||
private val appRouter: AppRouter,
|
||||
private val multiAccountStatusListSupplier: MultiAccountStatusListSupplier,
|
||||
private val getUserWalletUseCase: GetUserWalletUseCase,
|
||||
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val appRouter: AppRouter,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
) : Model(), TokenActionsComponent.Callbacks {
|
||||
|
||||
private val params = paramsContainer.require<AddFundsComponent.Params>()
|
||||
val launchMode: AddFundsComponent.LaunchMode = params.launchMode
|
||||
|
||||
val chooseTokenBridge: ChooseTokenBridge = chooseTokenBridgeFactory.create(
|
||||
modelScope = modelScope,
|
||||
settings = ChooseTokenBridge.Settings.AddFunds,
|
||||
analyticsPayload = setOf(
|
||||
ChooseTokenAnalyticsPayload.ScreensSources(SCREEN_SOURCE),
|
||||
),
|
||||
)
|
||||
private val routeStack = MutableStateFlow(listOf<UiRoute>(UiRoute.Loading))
|
||||
|
||||
private val selectedToken = MutableStateFlow<ChooseTokenResult?>(null)
|
||||
val uiRoute: StateFlow<UiRoute> = routeStack
|
||||
.map { it.last() }
|
||||
.distinctUntilChanged()
|
||||
.stateIn(modelScope, SharingStarted.Eagerly, initialValue = UiRoute.Loading)
|
||||
|
||||
val isTokenActionsShown: StateFlow<Boolean> = selectedToken
|
||||
.map { it != null }
|
||||
val canGoBack: StateFlow<Boolean> = routeStack
|
||||
.map { it.size > 1 }
|
||||
.distinctUntilChanged()
|
||||
.stateIn(modelScope, SharingStarted.Eagerly, initialValue = false)
|
||||
|
||||
private val tokenActionsTrigger = MutableStateFlow<TokenActionsRequest?>(null)
|
||||
private val filteredEntries = MutableStateFlow<List<FilteredEntry>>(emptyList())
|
||||
|
||||
val currentBottomAction: MutableStateFlow<BottomAction> =
|
||||
MutableStateFlow(BottomAction.None)
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val tokenActionsData: Flow<CryptoCurrencyData> = selectedToken
|
||||
val tokenActionsData: Flow<CryptoCurrencyData> = tokenActionsTrigger
|
||||
.filterNotNull()
|
||||
.flatMapLatest { result ->
|
||||
val cryptoPortfolio = result.account as? AccountStatus.CryptoPortfolio
|
||||
?: return@flatMapLatest emptyFlow()
|
||||
getCryptoCurrencyActionsUseCase(
|
||||
accountId = cryptoPortfolio.account.accountId,
|
||||
currency = result.currency.currency,
|
||||
).map { actionsState ->
|
||||
.flatMapLatest { request ->
|
||||
combine(
|
||||
getCryptoCurrencyActionsUseCase(
|
||||
accountId = request.account.account.accountId,
|
||||
currency = request.status.currency,
|
||||
),
|
||||
isAccountsModeEnabledUseCase(),
|
||||
) { actionsState, isAccountMode ->
|
||||
CryptoCurrencyData(
|
||||
userWallet = result.wallet,
|
||||
status = result.currency,
|
||||
userWallet = request.userWallet,
|
||||
status = request.status,
|
||||
actions = actionsState.states,
|
||||
isAccountMode = false,
|
||||
account = cryptoPortfolio,
|
||||
isAccountMode = isAccountMode,
|
||||
account = request.account,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val chooseTokenBridge: ChooseTokenBridge by lazy {
|
||||
chooseTokenBridgeFactory.create(
|
||||
modelScope = modelScope,
|
||||
settings = ChooseTokenBridge.Settings.AddFunds,
|
||||
analyticsPayload = setOf(ChooseTokenAnalyticsPayload.ScreensSources(SCREEN_SOURCE)),
|
||||
)
|
||||
}
|
||||
|
||||
val userPortfolioStateController: UserPortfolioStateController = userPortfolioStateControllerFactory.create(
|
||||
modelScope = modelScope,
|
||||
onTokenSelected = { result ->
|
||||
openTokenActions(
|
||||
request = TokenActionsRequest(
|
||||
userWallet = result.wallet,
|
||||
account = result.account,
|
||||
status = result.addedCurrency,
|
||||
),
|
||||
bottomAction = BottomAction.None,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
init {
|
||||
chooseTokenBridge.selectWalletTab(params.userWalletId)
|
||||
analyticsEventHandler.send(
|
||||
AddFundsAnalyticsEvent.MethodScreenOpened(source = AddFundsAnalyticsEvent.SOURCE_MAIN_SCREEN),
|
||||
)
|
||||
observeBridge()
|
||||
when (val mode = launchMode) {
|
||||
is AddFundsComponent.LaunchMode.ChooseToken -> initChooseToken(mode)
|
||||
is AddFundsComponent.LaunchMode.TokenActionsOnly -> initTokenActionsOnly(mode)
|
||||
is AddFundsComponent.LaunchMode.FilteredByRawId -> initFilteredByRawId(mode)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBottomActionClick() {
|
||||
val result = selectedToken.value ?: return
|
||||
selectedToken.value = null
|
||||
analyticsEventHandler.send(AddFundsAnalyticsEvent.ButtonGoToToken())
|
||||
appRouter.replaceCurrent(
|
||||
AppRoute.CurrencyDetails(
|
||||
userWalletId = result.wallet.walletId,
|
||||
currency = result.currency.currency,
|
||||
),
|
||||
)
|
||||
fun onBack() {
|
||||
routeStack.update { stack -> if (stack.size > 1) stack.dropLast(1) else stack }
|
||||
}
|
||||
|
||||
override fun onQuickActionClick(action: TokenActionsBSContentUM.Action) {
|
||||
fun onDismiss() = params.onDismiss()
|
||||
|
||||
override fun onBottomActionClick(bottomAction: BottomAction) {
|
||||
val request = tokenActionsTrigger.value
|
||||
if (bottomAction == BottomAction.GoToToken && request != null) {
|
||||
appRouter.push(
|
||||
AppRoute.CurrencyDetails(
|
||||
userWalletId = request.userWallet.walletId,
|
||||
currency = request.status.currency,
|
||||
),
|
||||
)
|
||||
}
|
||||
params.onDismiss()
|
||||
}
|
||||
|
||||
override fun onQuickActionClick(action: TokenActionsBSContentUM.Action, shouldDismiss: Boolean) {
|
||||
val event = when (action) {
|
||||
TokenActionsBSContentUM.Action.Buy -> AddFundsAnalyticsEvent.ButtonBuy()
|
||||
TokenActionsBSContentUM.Action.Exchange -> AddFundsAnalyticsEvent.ButtonSwap()
|
||||
TokenActionsBSContentUM.Action.Receive -> AddFundsAnalyticsEvent.ButtonReceive()
|
||||
else -> return
|
||||
else -> null
|
||||
}
|
||||
event?.let { analyticsEventHandler.send(it) }
|
||||
if (shouldDismiss) {
|
||||
params.onDismiss()
|
||||
}
|
||||
analyticsEventHandler.send(event)
|
||||
}
|
||||
|
||||
fun onTokenActionsDismiss() {
|
||||
selectedToken.value = null
|
||||
fun buildAvailableToAddDataForChooser(): AvailableToAddData {
|
||||
val byWallet = filteredEntries.value.groupBy { it.userWallet.walletId }
|
||||
return AvailableToAddData(
|
||||
availableToAddWallets = byWallet.mapValues { (_, entries) ->
|
||||
AvailableToAddWallet(
|
||||
userWallet = entries.first().userWallet,
|
||||
accounts = entries.map { it.account }.distinct(),
|
||||
availableNetworks = emptySet(),
|
||||
availableToAddAccounts = emptyMap(),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun observeBridge() {
|
||||
private fun initChooseToken(mode: AddFundsComponent.LaunchMode.ChooseToken) {
|
||||
chooseTokenBridge.selectWalletTab(mode.userWalletId)
|
||||
analyticsEventHandler.send(
|
||||
AddFundsAnalyticsEvent.MethodScreenOpened(source = AddFundsAnalyticsEvent.SOURCE_MAIN_SCREEN),
|
||||
)
|
||||
replaceRoot(UiRoute.ChooseToken)
|
||||
modelScope.launch {
|
||||
chooseTokenBridge.onCurrencyChosen.receiveAsFlow().collect { result ->
|
||||
selectedToken.value = result
|
||||
}
|
||||
chooseTokenBridge.onCurrencyChosen.receiveAsFlow().collect(::openTokenActionsFromBridge)
|
||||
}
|
||||
modelScope.launch {
|
||||
chooseTokenBridge.onClose.receiveAsFlow().collect {
|
||||
appRouter.pop()
|
||||
chooseTokenBridge.onClose.receiveAsFlow().collect { params.onDismiss() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun initTokenActionsOnly(mode: AddFundsComponent.LaunchMode.TokenActionsOnly) {
|
||||
modelScope.launch {
|
||||
val wallet = getUserWalletUseCase.invokeFlow(mode.userWalletId)
|
||||
.mapNotNull { it.getOrNull() }
|
||||
.first()
|
||||
val match = multiAccountStatusListSupplier()
|
||||
.first()
|
||||
.firstOrNull { it.userWalletId == mode.userWalletId }
|
||||
?.accountStatuses
|
||||
?.filterCryptoPortfolio()
|
||||
?.firstNotNullOfOrNull { accountStatus ->
|
||||
accountStatus.tokenList.flattenCurrencies()
|
||||
.firstOrNull { it.currency.id == mode.currency.id }
|
||||
?.let { accountStatus to it }
|
||||
}
|
||||
?: run {
|
||||
params.onDismiss()
|
||||
return@launch
|
||||
}
|
||||
tokenActionsTrigger.value = TokenActionsRequest(wallet, match.first, match.second)
|
||||
replaceRoot(UiRoute.TokenActions)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initFilteredByRawId(mode: AddFundsComponent.LaunchMode.FilteredByRawId) {
|
||||
modelScope.launch {
|
||||
val entries = collectFilteredEntries(mode.rawCurrencyId)
|
||||
when (entries.size) {
|
||||
0 -> params.onDismiss()
|
||||
1 -> {
|
||||
val entry = entries.first()
|
||||
tokenActionsTrigger.value = TokenActionsRequest(entry.userWallet, entry.account, entry.status)
|
||||
replaceRoot(UiRoute.TokenActions)
|
||||
}
|
||||
else -> {
|
||||
filteredEntries.value = entries
|
||||
replaceRoot(UiRoute.UserPortfolio)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun collectFilteredEntries(rawCurrencyId: CryptoCurrency.RawID): List<FilteredEntry> {
|
||||
val accountLists = multiAccountStatusListSupplier().first()
|
||||
return accountLists.flatMap { accountStatusList ->
|
||||
val wallet = getUserWalletUseCase.invokeFlow(accountStatusList.userWalletId)
|
||||
.mapNotNull { it.getOrNull() }
|
||||
.firstOrNull()
|
||||
?: return@flatMap emptyList()
|
||||
accountStatusList.accountStatuses.filterCryptoPortfolio().flatMap { accountStatus ->
|
||||
accountStatus.tokenList.flattenCurrencies()
|
||||
.filter { status ->
|
||||
val id = status.currency.id.rawCurrencyId ?: return@filter false
|
||||
getTokenIdIfL2Network(id.value) == rawCurrencyId.value
|
||||
}
|
||||
.map { status -> FilteredEntry(wallet, accountStatus, status) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun openTokenActionsFromBridge(result: ChooseTokenResult) {
|
||||
val account = result.account as? AccountStatus.CryptoPortfolio ?: return
|
||||
openTokenActions(
|
||||
request = TokenActionsRequest(result.wallet, account, result.currency),
|
||||
bottomAction = if (result.wasJustAdded) {
|
||||
BottomAction.GoToToken
|
||||
} else {
|
||||
BottomAction.None
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun openTokenActions(request: TokenActionsRequest, bottomAction: BottomAction) {
|
||||
tokenActionsTrigger.value = request
|
||||
currentBottomAction.value = bottomAction
|
||||
pushRoute(UiRoute.TokenActions)
|
||||
}
|
||||
|
||||
private fun replaceRoot(route: UiRoute) {
|
||||
routeStack.value = listOf(route)
|
||||
}
|
||||
|
||||
private fun pushRoute(route: UiRoute) {
|
||||
routeStack.update { it + route }
|
||||
}
|
||||
|
||||
sealed interface UiRoute {
|
||||
data object Loading : UiRoute
|
||||
data object ChooseToken : UiRoute
|
||||
data object UserPortfolio : UiRoute
|
||||
data object TokenActions : UiRoute
|
||||
}
|
||||
|
||||
private data class TokenActionsRequest(
|
||||
val userWallet: UserWallet,
|
||||
val account: AccountStatus.CryptoPortfolio,
|
||||
val status: CryptoCurrencyStatus,
|
||||
)
|
||||
|
||||
private data class FilteredEntry(
|
||||
val userWallet: UserWallet,
|
||||
val account: AccountStatus.CryptoPortfolio,
|
||||
val status: CryptoCurrencyStatus,
|
||||
)
|
||||
|
||||
private companion object {
|
||||
const val SCREEN_SOURCE = "AddFunds"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
package com.tangem.features.commonfeatures.impl.addfunds.model
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.features.commonfeatures.impl.R
|
||||
import com.tangem.core.ui.R as CoreR
|
||||
|
||||
internal data class AddFundsRouteUiSpec(
|
||||
val title: TextReference,
|
||||
val shouldApplyHorizontalPadding: Boolean,
|
||||
val shouldFillHeight: Boolean,
|
||||
)
|
||||
|
||||
internal fun AddFundsModel.UiRoute.uiSpec(): AddFundsRouteUiSpec = when (this) {
|
||||
AddFundsModel.UiRoute.Loading -> AddFundsRouteUiSpec(
|
||||
title = resourceReference(R.string.common_add_funds),
|
||||
shouldApplyHorizontalPadding = false,
|
||||
shouldFillHeight = false,
|
||||
)
|
||||
AddFundsModel.UiRoute.ChooseToken -> AddFundsRouteUiSpec(
|
||||
title = resourceReference(R.string.common_add_funds),
|
||||
shouldApplyHorizontalPadding = false,
|
||||
shouldFillHeight = true,
|
||||
)
|
||||
AddFundsModel.UiRoute.UserPortfolio -> AddFundsRouteUiSpec(
|
||||
title = resourceReference(R.string.common_add_funds),
|
||||
shouldApplyHorizontalPadding = false,
|
||||
shouldFillHeight = false,
|
||||
)
|
||||
AddFundsModel.UiRoute.TokenActions -> AddFundsRouteUiSpec(
|
||||
title = resourceReference(CoreR.string.common_get_token),
|
||||
shouldApplyHorizontalPadding = true,
|
||||
shouldFillHeight = true,
|
||||
)
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ import com.tangem.features.commonfeatures.impl.R
|
|||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.AddToPortfolioFooterKind
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.AddToPortfolioRoutes
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.uiSpec
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.model.UserPortfolioUM
|
||||
import com.tangem.features.commonfeatures.impl.userportfolio.model.UserPortfolioUM
|
||||
import dev.chrisbanes.haze.rememberHazeState
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import com.arkivanov.decompose.router.stack.ChildStack
|
|||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.AddToPortfolioRoutes
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.model.UserPortfolioUM
|
||||
import com.tangem.features.commonfeatures.impl.userportfolio.model.UserPortfolioUM
|
||||
|
||||
@Composable
|
||||
internal fun AddToPortfolioBottomSheetSwitch(
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
import com.tangem.features.commonfeatures.impl.R
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.AddToPortfolioRoutes
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.uiSpec
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.model.UserPortfolioUM
|
||||
import com.tangem.features.commonfeatures.impl.userportfolio.model.UserPortfolioUM
|
||||
|
||||
@Composable
|
||||
internal fun AddToPortfolioBottomSheetV2(
|
||||
|
|
@ -39,6 +39,11 @@ internal fun AddToPortfolioBottomSheetV2(
|
|||
contentStack.value = stack
|
||||
}
|
||||
|
||||
val type = if (stack.active.configuration is AddToPortfolioRoutes.TokenActions) {
|
||||
TangemBottomSheetType.Default
|
||||
} else {
|
||||
TangemBottomSheetType.Modal
|
||||
}
|
||||
TangemBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||
onBack = onBack,
|
||||
config = TangemBottomSheetConfig(
|
||||
|
|
@ -46,7 +51,7 @@ internal fun AddToPortfolioBottomSheetV2(
|
|||
onDismissRequest = onDismiss,
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
),
|
||||
type = TangemBottomSheetType.Modal,
|
||||
type = type,
|
||||
containerColor = TangemTheme.colors2.surface.level2,
|
||||
title = {
|
||||
AddToPortfolioBottomSheetTitle(
|
||||
|
|
@ -86,7 +91,9 @@ private fun AddToPortfolioRouteContent(animatedStack: ChildStack<AddToPortfolioR
|
|||
Spacer(modifier = Modifier.height(scrollBottomReserve))
|
||||
}
|
||||
} else {
|
||||
animatedStack.active.instance.Content(modifier = baseModifier)
|
||||
val isFullScreenRoute = animatedStack.active.configuration is AddToPortfolioRoutes.TokenActions
|
||||
val sizeModifier = if (isFullScreenRoute) Modifier.fillMaxSize() else Modifier
|
||||
animatedStack.active.instance.Content(modifier = baseModifier.then(sizeModifier))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,11 +15,14 @@ import com.tangem.core.ui.decompose.ComposableContentComponent
|
|||
import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioComponent
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorComponent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.AddToPortfolioModel
|
||||
import com.tangem.features.commonfeatures.api.tokenactions.BottomAction
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.AddToPortfolioRoutes
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.UserPortfolioComponent
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.TokenActionsComponent
|
||||
import com.tangem.features.commonfeatures.impl.userportfolio.UserPortfolioComponent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class DefaultAddToPortfolioComponent @AssistedInject constructor(
|
||||
|
|
@ -60,6 +63,7 @@ internal class DefaultAddToPortfolioComponent @AssistedInject constructor(
|
|||
params = TokenActionsComponent.Params(
|
||||
callbacks = model,
|
||||
data = model.tokenActionsData,
|
||||
bottomAction = flowOf(BottomAction.GoToToken),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,13 +92,5 @@ internal class PortfolioAnalyticsEvent(
|
|||
if (source != null) put("Source", source)
|
||||
},
|
||||
)
|
||||
|
||||
fun getTokenLater() = PortfolioAnalyticsEvent(
|
||||
event = "Popup Get token - Button Later",
|
||||
category = category,
|
||||
params = buildMap {
|
||||
if (source != null) put("Source", source)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,8 +4,8 @@ import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioCompo
|
|||
import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioManager
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.DefaultAddToPortfolioComponent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.DefaultAddToPortfolioManager
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.DefaultUserPortfolioComponent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.UserPortfolioComponent
|
||||
import com.tangem.features.commonfeatures.impl.userportfolio.DefaultUserPortfolioComponent
|
||||
import com.tangem.features.commonfeatures.impl.userportfolio.UserPortfolioComponent
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import com.tangem.core.decompose.model.Model
|
|||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.AddToPortfolioModel
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.AddTokenModel
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.ChooseNetworkModel
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.TokenActionsModel
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.model.UserPortfolioModel
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.model.TokenActionsModel
|
||||
import com.tangem.features.commonfeatures.impl.userportfolio.model.UserPortfolioModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
|
|||
|
|
@ -29,18 +29,20 @@ import com.tangem.domain.models.wallet.isMultiCurrency
|
|||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.*
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorController
|
||||
import com.tangem.features.commonfeatures.api.tokenactions.BottomAction
|
||||
import com.tangem.features.commonfeatures.impl.R
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.AddTokenComponent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ChooseNetworkComponent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.TokenActionsComponent
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.TokenActionsComponent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.analytics.PortfolioAnalyticsEvent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.UserPortfolioComponent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.state.UserPortfolioStateController
|
||||
import com.tangem.features.commonfeatures.impl.userportfolio.UserPortfolioComponent
|
||||
import com.tangem.features.commonfeatures.impl.userportfolio.state.UserPortfolioStateController
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -107,10 +109,6 @@ internal class AddToPortfolioModel @Inject constructor(
|
|||
startRedesignAddToPortfolioFlow()
|
||||
}
|
||||
|
||||
override fun onQuickActionClick(action: TokenActionsBSContentUM.Action) {
|
||||
analyticsEventHandler.send(eventBuilder.getTokenActionClick(actionUM = action))
|
||||
}
|
||||
|
||||
private fun <T> replayMutableSharedFlow() = MutableSharedFlow<T>(
|
||||
replay = 1,
|
||||
onBufferOverflow = BufferOverflow.DROP_OLDEST,
|
||||
|
|
@ -155,7 +153,7 @@ internal class AddToPortfolioModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||
private fun startRedesignAddToPortfolioFlow() {
|
||||
channelFlow<Unit> {
|
||||
fun finishSuccessFlow(result: AddToPortfolioManager.Result) {
|
||||
|
|
@ -312,9 +310,15 @@ internal class AddToPortfolioModel @Inject constructor(
|
|||
.onEmpty { finishSuccessFlow(result) }
|
||||
.launchIn(this)
|
||||
|
||||
callbackDelegate.onChooseTokenBottomActionClick.receiveAsFlow().first()
|
||||
analyticsEventHandler.send(eventBuilder.getTokenLater())
|
||||
finishSuccessFlow(result)
|
||||
when (val meta = terminalTokenActionsFlow().first()) {
|
||||
is AddToPortfolioManager.FinishMeta.OnBottomAction -> {
|
||||
finishSuccessFlow(result.copy(meta = meta))
|
||||
}
|
||||
AddToPortfolioManager.FinishMeta.OnQuickAction -> {
|
||||
finishSuccessFlow(result.copy(meta = meta))
|
||||
}
|
||||
AddToPortfolioManager.FinishMeta.None -> Unit
|
||||
}
|
||||
}
|
||||
.catch { throwable ->
|
||||
TangemLogger.e("Error", throwable)
|
||||
|
|
@ -323,6 +327,21 @@ internal class AddToPortfolioModel @Inject constructor(
|
|||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun terminalTokenActionsFlow() = channelFlow {
|
||||
callbackDelegate.onChooseTokenBottomActionClick.receiveAsFlow()
|
||||
.onEach { bottomAction ->
|
||||
channel.send(AddToPortfolioManager.FinishMeta.OnBottomAction(bottomAction))
|
||||
}
|
||||
.launchIn(this)
|
||||
callbackDelegate.onQuickActionClick.receiveAsFlow()
|
||||
.onEach { (action, shouldDismiss) ->
|
||||
analyticsEventHandler.send(eventBuilder.getTokenActionClick(actionUM = action))
|
||||
if (shouldDismiss) channel.send(AddToPortfolioManager.FinishMeta.OnQuickAction)
|
||||
}
|
||||
.launchIn(this)
|
||||
awaitClose()
|
||||
}
|
||||
|
||||
private suspend fun getInitialSelection(
|
||||
initialData: AvailableToAddData,
|
||||
): AddToPortfolioInitialSelectionResolver.InitialSelection? {
|
||||
|
|
@ -529,7 +548,8 @@ internal class AddToPortfolioCallbackDelegate @Inject constructor() :
|
|||
UserPortfolioComponent.Callbacks {
|
||||
|
||||
val onNetworkSelected = Channel<TokenMarketInfo.Network>()
|
||||
val onChooseTokenBottomActionClick = Channel<Unit>()
|
||||
val onChooseTokenBottomActionClick = Channel<BottomAction>()
|
||||
val onQuickActionClick = Channel<Pair<TokenActionsBSContentUM.Action, Boolean>>()
|
||||
val onChangeNetworkClick = Channel<Unit>()
|
||||
val onChangePortfolioClick = Channel<Unit>()
|
||||
val onTokenAdded = Channel<CryptoCurrencyStatus>()
|
||||
|
|
@ -539,8 +559,12 @@ internal class AddToPortfolioCallbackDelegate @Inject constructor() :
|
|||
onNetworkSelected.trySend(network)
|
||||
}
|
||||
|
||||
override fun onBottomActionClick() {
|
||||
onChooseTokenBottomActionClick.trySend(Unit)
|
||||
override fun onBottomActionClick(bottomAction: BottomAction) {
|
||||
onChooseTokenBottomActionClick.trySend(bottomAction)
|
||||
}
|
||||
|
||||
override fun onQuickActionClick(action: TokenActionsBSContentUM.Action, shouldDismiss: Boolean) {
|
||||
onQuickActionClick.trySend(action to shouldDismiss)
|
||||
}
|
||||
|
||||
override fun onChangeNetworkClick() {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ internal fun AddToPortfolioRoutes.uiSpec(): AddToPortfolioRouteUiSpec = when (th
|
|||
)
|
||||
AddToPortfolioRoutes.TokenActions -> AddToPortfolioRouteUiSpec(
|
||||
title = resourceReference(R.string.common_get_token),
|
||||
isScrollable = true,
|
||||
isScrollable = false,
|
||||
shouldApplyHorizontalPadding = true,
|
||||
footer = AddToPortfolioFooterKind.None,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ internal class DefaultChooseTokenComponent @AssistedInject constructor(
|
|||
override fun Content(modifier: Modifier) {
|
||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
ChooseTokenScreen(state = state)
|
||||
ChooseTokenScreen(state = state, modifier = modifier)
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import com.tangem.core.decompose.model.Model
|
|||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.features.commonfeatures.api.R
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioManager
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenAnalyticsPayload
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridge
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridgeInternal.SearchQuery
|
||||
|
|
@ -14,10 +16,9 @@ import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenComponent
|
|||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenResult
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.converter.SearchBarToggleTransformer
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.converter.SearchBarUpdateQueryTransformer
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.market.state.SwapMarketState
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.ui.ChooseTokenFullUM
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.ui.ChooseTokenInitialUM
|
||||
import com.tangem.features.commonfeatures.api.R
|
||||
import com.tangem.features.commonfeatures.impl.choosetoken.market.state.SwapMarketState
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
import javax.inject.Inject
|
||||
|
|
@ -78,18 +79,10 @@ internal class ChooseTokenModel @Inject constructor(
|
|||
.onEach { marketBlockDelegate.addToPortfolioSlot.dismiss() }
|
||||
.launchIn(modelScope)
|
||||
addToPortfolioManager.onSuccessAdded.receiveAsFlow()
|
||||
.onEach { addedResult ->
|
||||
val isSearched = ChooseTokenAnalyticsPayload.IsSearched(isSearchingState)
|
||||
val isMarketToken = ChooseTokenAnalyticsPayload.IsMarketTokenSelected(true)
|
||||
val chooseTokenResult = ChooseTokenResult(
|
||||
currency = addedResult.addedCurrency,
|
||||
account = addedResult.account,
|
||||
wallet = addedResult.wallet,
|
||||
analyticsPayload = setOf(isSearched, isMarketToken),
|
||||
)
|
||||
bridge.onCurrencyChosen(chooseTokenResult)
|
||||
marketBlockDelegate.addToPortfolioSlot.dismiss()
|
||||
}
|
||||
.onEach { notifyCurrencyChosen(it, isMarketTokenSelected = true) }
|
||||
.launchIn(modelScope)
|
||||
addToPortfolioManager.onAddedTokenClick.receiveAsFlow()
|
||||
.onEach { notifyCurrencyChosen(it, isMarketTokenSelected = false) }
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
|
|
@ -97,6 +90,20 @@ internal class ChooseTokenModel @Inject constructor(
|
|||
bridge.onClose()
|
||||
}
|
||||
|
||||
private fun notifyCurrencyChosen(addedResult: AddToPortfolioManager.Result, isMarketTokenSelected: Boolean) {
|
||||
val chooseTokenResult = ChooseTokenResult(
|
||||
currency = addedResult.addedCurrency,
|
||||
account = addedResult.account,
|
||||
wallet = addedResult.wallet,
|
||||
analyticsPayload = setOf(
|
||||
ChooseTokenAnalyticsPayload.IsSearched(isSearchingState),
|
||||
ChooseTokenAnalyticsPayload.IsMarketTokenSelected(isMarketTokenSelected),
|
||||
),
|
||||
)
|
||||
bridge.onCurrencyChosen(chooseTokenResult)
|
||||
marketBlockDelegate.addToPortfolioSlot.dismiss()
|
||||
}
|
||||
|
||||
private fun getInitialSearchBar(): SearchBarUM = SearchBarUM(
|
||||
placeholderText = resourceReference(R.string.common_search),
|
||||
query = "",
|
||||
|
|
@ -112,6 +119,7 @@ internal class ChooseTokenModel @Inject constructor(
|
|||
|
||||
private fun getInitState() = ChooseTokenInitialUM(
|
||||
screenTitle = bridge.settings.title,
|
||||
isAppBarShown = bridge.settings.isAppBarShown,
|
||||
onCloseClick = ::onBackClicked,
|
||||
searchBar = getInitialSearchBar(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -82,12 +82,14 @@ private val ChooseTokenFullUM.isEmptyState: Boolean
|
|||
internal fun ChooseTokenScreen(state: ChooseTokenFullUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.background(color = TangemTheme.colors.background.secondary)
|
||||
.background(color = TangemTheme.colors2.surface.level2)
|
||||
.fillMaxSize()
|
||||
.imePadding(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
AppBar(title = state.initialUM.screenTitle, onBackClick = state.initialUM.onCloseClick, Modifier)
|
||||
if (state.initialUM.isAppBarShown) {
|
||||
AppBar(title = state.initialUM.screenTitle, onBackClick = state.initialUM.onCloseClick, Modifier)
|
||||
}
|
||||
|
||||
Content(
|
||||
state = state,
|
||||
|
|
@ -465,6 +467,7 @@ private val wallets
|
|||
|
||||
private val initialUM = ChooseTokenInitialUM(
|
||||
screenTitle = stringReference("Choose token"),
|
||||
isAppBarShown = true,
|
||||
onCloseClick = {},
|
||||
searchBar = searchBar,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ internal data class ChooseTokenFullUM(
|
|||
|
||||
internal data class ChooseTokenInitialUM(
|
||||
val screenTitle: TextReference,
|
||||
val isAppBarShown: Boolean,
|
||||
val onCloseClick: () -> Unit,
|
||||
val searchBar: SearchBarUM,
|
||||
)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio
|
||||
package com.tangem.features.commonfeatures.impl.tokenactions
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
|
|
@ -18,14 +18,16 @@ import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
|||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.TokenActionsModel
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.TokenActionsContent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.TokenActionsContentV2
|
||||
import com.tangem.features.commonfeatures.api.tokenactions.BottomAction
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.model.TokenActionsModel
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.ui.TokenActionsContent
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.ui.TokenActionsContentV2
|
||||
import com.tangem.features.tokenreceive.TokenReceiveComponent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
||||
internal class TokenActionsComponent @AssistedInject constructor(
|
||||
@Assisted context: AppComponentContext,
|
||||
|
|
@ -74,15 +76,14 @@ internal class TokenActionsComponent @AssistedInject constructor(
|
|||
data class Params(
|
||||
val data: Flow<CryptoCurrencyData>,
|
||||
val callbacks: Callbacks,
|
||||
val bottomAction: BottomAction = BottomAction.Later,
|
||||
val bottomAction: Flow<BottomAction> = flowOf(BottomAction.None),
|
||||
val isRedesignForced: Boolean = false,
|
||||
val isCompact: Boolean = false,
|
||||
)
|
||||
|
||||
enum class BottomAction { Later, GoToToken }
|
||||
|
||||
interface Callbacks {
|
||||
fun onBottomActionClick()
|
||||
fun onQuickActionClick(action: TokenActionsBSContentUM.Action) {}
|
||||
fun onBottomActionClick(bottomAction: BottomAction)
|
||||
fun onQuickActionClick(action: TokenActionsBSContentUM.Action, shouldDismiss: Boolean) {}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.model
|
||||
package com.tangem.features.commonfeatures.impl.tokenactions.model
|
||||
|
||||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
|
|
@ -12,8 +12,8 @@ import com.tangem.domain.appcurrency.model.AppCurrency
|
|||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.transaction.usecase.ReceiveAddressesFactory
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.TokenActionsComponent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state.TokenActionsUM
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.TokenActionsComponent
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.ui.state.TokenActionsUM
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
|
|
@ -45,7 +45,9 @@ internal class TokenActionsModel @Inject constructor(
|
|||
private val tokenActionsHandler: TokenActionsHandler =
|
||||
tokenActionsIntentsFactory.create(
|
||||
currentAppCurrency = Provider { currentAppCurrency.value },
|
||||
onHandleQuickAction = { handledAction -> handledQuickAction(handledAction) },
|
||||
onHandleQuickAction = { handledAction, shouldDismiss ->
|
||||
handledQuickAction(handledAction, shouldDismiss)
|
||||
},
|
||||
)
|
||||
|
||||
val bottomSheetNavigation: SlotNavigation<TokenReceiveConfig> = SlotNavigation()
|
||||
|
|
@ -55,15 +57,17 @@ internal class TokenActionsModel @Inject constructor(
|
|||
combine(
|
||||
params.data,
|
||||
getBalanceHidingSettingsUseCase.isBalanceHidden(),
|
||||
) { cryptoCurrencyData, isBalanceHidden ->
|
||||
cryptoCurrencyData to isBalanceHidden
|
||||
params.bottomAction,
|
||||
) { cryptoCurrencyData, isBalanceHidden, bottomAction ->
|
||||
Triple(cryptoCurrencyData, isBalanceHidden, bottomAction)
|
||||
}
|
||||
.mapLatest { (cryptoCurrencyData, isBalanceHidden) ->
|
||||
.mapLatest { (cryptoCurrencyData, isBalanceHidden, bottomAction) ->
|
||||
uiBuilder.build(
|
||||
cryptoCurrencyData = cryptoCurrencyData,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
appCurrency = currentAppCurrency.value,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
bottomAction = bottomAction,
|
||||
)
|
||||
}
|
||||
.flowOn(dispatchers.default)
|
||||
|
|
@ -73,16 +77,18 @@ internal class TokenActionsModel @Inject constructor(
|
|||
initialValue = null,
|
||||
)
|
||||
|
||||
private fun handledQuickAction(handledAction: TokenActionsHandler.HandledQuickAction) = modelScope.launch {
|
||||
params.callbacks.onQuickActionClick(handledAction.action)
|
||||
val isReceive = handledAction.action == TokenActionsBSContentUM.Action.Receive
|
||||
if (!isReceive) return@launch
|
||||
val tokenConfig = withContext(dispatchers.default) {
|
||||
receiveAddressesFactory.create(
|
||||
status = handledAction.cryptoCurrencyData.status,
|
||||
userWalletId = handledAction.cryptoCurrencyData.userWallet.walletId,
|
||||
)
|
||||
} ?: return@launch
|
||||
bottomSheetNavigation.activate(tokenConfig)
|
||||
}
|
||||
private fun handledQuickAction(handledAction: TokenActionsHandler.HandledQuickAction, shouldDismiss: Boolean) =
|
||||
modelScope.launch {
|
||||
val isReceive = handledAction.action == TokenActionsBSContentUM.Action.Receive
|
||||
if (isReceive) {
|
||||
val tokenConfig = withContext(dispatchers.default) {
|
||||
receiveAddressesFactory.create(
|
||||
status = handledAction.cryptoCurrencyData.status,
|
||||
userWalletId = handledAction.cryptoCurrencyData.userWallet.walletId,
|
||||
)
|
||||
}
|
||||
if (tokenConfig != null) bottomSheetNavigation.activate(tokenConfig)
|
||||
}
|
||||
params.callbacks.onQuickActionClick(handledAction.action, shouldDismiss)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.model
|
||||
package com.tangem.features.commonfeatures.impl.tokenactions.model
|
||||
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import com.tangem.common.getTotalCryptoAmount
|
||||
|
|
@ -11,6 +11,7 @@ import com.tangem.common.ui.components.currency.icon.converter.CryptoCurrencyToI
|
|||
import com.tangem.common.ui.markets.action.CryptoCurrencyData
|
||||
import com.tangem.common.ui.markets.action.QuickActionsConverter.quickActions
|
||||
import com.tangem.common.ui.markets.action.TokenActionsHandler
|
||||
import com.tangem.features.commonfeatures.api.tokenactions.BottomAction
|
||||
import com.tangem.common.ui.userwallet.converter.WalletIconUMConverter
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
|
|
@ -30,9 +31,9 @@ import com.tangem.features.commonfeatures.impl.R
|
|||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.usecase.GetWalletIconUseCase
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.TokenActionsComponent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state.PortfolioBadgeUM
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state.TokenActionsUM
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.TokenActionsComponent
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.ui.state.PortfolioBadgeUM
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.ui.state.TokenActionsUM
|
||||
import java.math.BigDecimal
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -50,6 +51,7 @@ internal class TokenActionsUiBuilder @Inject constructor(
|
|||
tokenActionsHandler: TokenActionsHandler,
|
||||
appCurrency: AppCurrency,
|
||||
isBalanceHidden: Boolean,
|
||||
bottomAction: BottomAction,
|
||||
): TokenActionsUM {
|
||||
return if (designFeatureToggles.isRedesignEnabled || params.isRedesignForced) {
|
||||
buildV2(
|
||||
|
|
@ -57,11 +59,13 @@ internal class TokenActionsUiBuilder @Inject constructor(
|
|||
tokenActionsHandler = tokenActionsHandler,
|
||||
appCurrency = appCurrency,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
bottomAction = bottomAction,
|
||||
)
|
||||
} else {
|
||||
buildV1(
|
||||
cryptoCurrencyData = cryptoCurrencyData,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
bottomAction = bottomAction,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -69,6 +73,7 @@ internal class TokenActionsUiBuilder @Inject constructor(
|
|||
private fun buildV1(
|
||||
cryptoCurrencyData: CryptoCurrencyData,
|
||||
tokenActionsHandler: TokenActionsHandler,
|
||||
bottomAction: BottomAction,
|
||||
): TokenActionsUM {
|
||||
val status = cryptoCurrencyData.status
|
||||
val tokenUM = TokenItemState.Content(
|
||||
|
|
@ -88,9 +93,9 @@ internal class TokenActionsUiBuilder @Inject constructor(
|
|||
tokenActionsHandler = tokenActionsHandler,
|
||||
isRedesignEnabled = false,
|
||||
),
|
||||
bottomActionText = bottomActionText(params.bottomAction),
|
||||
bottomActionText = bottomActionText(bottomAction),
|
||||
onBottomActionClick = {
|
||||
params.callbacks.onBottomActionClick()
|
||||
params.callbacks.onBottomActionClick(bottomAction)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -100,6 +105,7 @@ internal class TokenActionsUiBuilder @Inject constructor(
|
|||
tokenActionsHandler: TokenActionsHandler,
|
||||
appCurrency: AppCurrency,
|
||||
isBalanceHidden: Boolean,
|
||||
bottomAction: BottomAction,
|
||||
): TokenActionsUM {
|
||||
val status = cryptoCurrencyData.status
|
||||
val tokenUM = TokenItemState.Content(
|
||||
|
|
@ -119,19 +125,20 @@ internal class TokenActionsUiBuilder @Inject constructor(
|
|||
tokenActionsHandler = tokenActionsHandler,
|
||||
isRedesignEnabled = true,
|
||||
),
|
||||
bottomActionText = bottomActionText(params.bottomAction),
|
||||
bottomActionText = bottomActionText(bottomAction),
|
||||
onBottomActionClick = {
|
||||
params.callbacks.onBottomActionClick()
|
||||
params.callbacks.onBottomActionClick(bottomAction)
|
||||
},
|
||||
isBalancesHidden = isBalanceHidden,
|
||||
portfolioBadge = createPortfolioBadge(cryptoCurrencyData = cryptoCurrencyData),
|
||||
isCompact = params.isCompact,
|
||||
)
|
||||
}
|
||||
|
||||
private fun bottomActionText(action: TokenActionsComponent.BottomAction): TextReference {
|
||||
private fun bottomActionText(action: BottomAction): TextReference? {
|
||||
return when (action) {
|
||||
TokenActionsComponent.BottomAction.Later -> resourceReference(R.string.common_later)
|
||||
TokenActionsComponent.BottomAction.GoToToken -> resourceReference(R.string.common_go_to_token)
|
||||
BottomAction.GoToToken -> resourceReference(R.string.common_go_to_token)
|
||||
BottomAction.None -> null
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.ui
|
||||
package com.tangem.features.commonfeatures.impl.tokenactions.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
|
|
@ -39,7 +39,7 @@ import com.tangem.core.ui.res.TangemColorPalette
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.commonfeatures.impl.R
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state.TokenActionsUM
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.ui.state.TokenActionsUM
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import java.util.UUID
|
||||
|
||||
|
|
@ -73,13 +73,15 @@ internal fun TokenActionsContent(state: TokenActionsUM, modifier: Modifier = Mod
|
|||
}
|
||||
}
|
||||
|
||||
SpacerH16()
|
||||
if (state.bottomActionText != null) {
|
||||
SpacerH16()
|
||||
|
||||
SecondaryButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = state.bottomActionText.resolveReference(),
|
||||
onClick = state.onBottomActionClick,
|
||||
)
|
||||
SecondaryButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = state.bottomActionText.resolveReference(),
|
||||
onClick = state.onBottomActionClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.ui
|
||||
package com.tangem.features.commonfeatures.impl.tokenactions.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
|
|
@ -43,8 +43,8 @@ import com.tangem.core.ui.format.bigdecimal.formatStyled
|
|||
import com.tangem.core.ui.format.bigdecimal.price
|
||||
import com.tangem.core.ui.res.*
|
||||
import com.tangem.features.commonfeatures.impl.R
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state.PortfolioBadgeUM
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state.TokenActionsUM
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.ui.state.PortfolioBadgeUM
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.ui.state.TokenActionsUM
|
||||
import dev.chrisbanes.haze.rememberHazeState
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import java.math.BigDecimal
|
||||
|
|
@ -52,53 +52,84 @@ import java.util.UUID
|
|||
|
||||
@Composable
|
||||
internal fun TokenActionsContentV2(state: TokenActionsUM, modifier: Modifier = Modifier) {
|
||||
if (state.isCompact) {
|
||||
CompactLayout(state, modifier)
|
||||
} else {
|
||||
FullLayout(state, modifier)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CompactLayout(state: TokenActionsUM, modifier: Modifier = Modifier) {
|
||||
Column(modifier = modifier.fillMaxWidth()) {
|
||||
QuickActionsList(state)
|
||||
SpacerH(TangemTheme.dimens2.x4)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FullLayout(state: TokenActionsUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.navigationBarsPadding(),
|
||||
) {
|
||||
TokenHeader(
|
||||
addedToken = state.token,
|
||||
portfolioBadge = state.portfolioBadge,
|
||||
isBalanceHidden = state.isBalancesHidden,
|
||||
)
|
||||
|
||||
SpacerH(TangemTheme.dimens2.x2)
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxWidth(),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
state.quickActions.actions.fastForEach { actionUM ->
|
||||
key(actionUM.title) {
|
||||
val transitionState = remember {
|
||||
MutableTransitionState(initialState = false).apply { targetState = true }
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visibleState = transitionState,
|
||||
enter = fadeIn() + expandVertically(),
|
||||
exit = fadeOut() + shrinkVertically(),
|
||||
) {
|
||||
TokenActionRow(
|
||||
iconRes = actionUM.icon,
|
||||
title = actionUM.title,
|
||||
description = actionUM.description,
|
||||
onClick = { state.quickActions.onQuickActionClick(actionUM) },
|
||||
onLongClick = { state.quickActions.onQuickActionLongClick(actionUM) }
|
||||
.takeIf { actionUM.isLongClickAvailable },
|
||||
)
|
||||
}
|
||||
}
|
||||
TokenHeader(
|
||||
addedToken = state.token,
|
||||
portfolioBadge = state.portfolioBadge,
|
||||
isBalanceHidden = state.isBalancesHidden,
|
||||
)
|
||||
}
|
||||
QuickActionsList(state)
|
||||
val bottomText = state.bottomActionText
|
||||
if (bottomText != null) {
|
||||
SpacerH(TangemTheme.dimens2.x6)
|
||||
CompositionLocalProvider(LocalHazeState provides rememberHazeState()) {
|
||||
SecondaryTangemButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = state.onBottomActionClick,
|
||||
text = bottomText,
|
||||
size = TangemButtonSize.X12,
|
||||
shape = TangemButtonShape.Rounded,
|
||||
)
|
||||
}
|
||||
}
|
||||
SpacerH(TangemTheme.dimens2.x4)
|
||||
}
|
||||
}
|
||||
|
||||
SpacerH(TangemTheme.dimens2.x6)
|
||||
|
||||
CompositionLocalProvider(LocalHazeState provides rememberHazeState()) {
|
||||
SecondaryTangemButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = state.onBottomActionClick,
|
||||
text = state.bottomActionText,
|
||||
size = TangemButtonSize.X12,
|
||||
shape = TangemButtonShape.Rounded,
|
||||
)
|
||||
@Composable
|
||||
private fun QuickActionsList(state: TokenActionsUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
|
||||
) {
|
||||
state.quickActions.actions.fastForEach { actionUM ->
|
||||
key(actionUM.title) {
|
||||
val transitionState = remember {
|
||||
MutableTransitionState(initialState = false).apply { targetState = true }
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visibleState = transitionState,
|
||||
enter = fadeIn() + expandVertically(),
|
||||
exit = fadeOut() + shrinkVertically(),
|
||||
) {
|
||||
TokenActionRow(
|
||||
iconRes = actionUM.icon,
|
||||
title = actionUM.title,
|
||||
description = actionUM.description,
|
||||
onClick = { state.quickActions.onQuickActionClick(actionUM) },
|
||||
onLongClick = { state.quickActions.onQuickActionLongClick(actionUM) }
|
||||
.takeIf { actionUM.isLongClickAvailable },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state
|
||||
package com.tangem.features.commonfeatures.impl.tokenactions.ui.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.common.ui.markets.action.QuickActions
|
||||
|
|
@ -10,10 +10,11 @@ import com.tangem.core.ui.extensions.TextReference
|
|||
internal data class TokenActionsUM(
|
||||
val token: TokenItemState,
|
||||
val quickActions: QuickActions,
|
||||
val bottomActionText: TextReference,
|
||||
val bottomActionText: TextReference?,
|
||||
val onBottomActionClick: () -> Unit,
|
||||
val isBalancesHidden: Boolean = false,
|
||||
val portfolioBadge: PortfolioBadgeUM = PortfolioBadgeUM.None,
|
||||
val isCompact: Boolean = false,
|
||||
)
|
||||
|
||||
@Immutable
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio
|
||||
package com.tangem.features.commonfeatures.impl.userportfolio
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -7,7 +7,7 @@ import com.tangem.common.ui.markets.tokenselector.TokenSelectorEmbeddedContent
|
|||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.components.bottomsheets.LocalTangemBottomSheetContentBottomInset
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.model.UserPortfolioModel
|
||||
import com.tangem.features.commonfeatures.impl.userportfolio.model.UserPortfolioModel
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio
|
||||
package com.tangem.features.commonfeatures.impl.userportfolio
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.model.UserPortfolioUM
|
||||
import com.tangem.features.commonfeatures.impl.userportfolio.model.UserPortfolioUM
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
internal interface UserPortfolioComponent : ComposableContentComponent {
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.model
|
||||
package com.tangem.features.commonfeatures.impl.userportfolio.model
|
||||
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.UserPortfolioComponent
|
||||
import com.tangem.features.commonfeatures.impl.userportfolio.UserPortfolioComponent
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import javax.inject.Inject
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.model
|
||||
package com.tangem.features.commonfeatures.impl.userportfolio.model
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.common.ui.markets.tokenselector.TokenSelectorContentUM
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.state
|
||||
package com.tangem.features.commonfeatures.impl.userportfolio.state
|
||||
|
||||
import com.tangem.common.ui.userwallet.converter.WalletIconUMConverter
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
|
|
@ -7,8 +7,8 @@ import com.tangem.domain.models.currency.CryptoCurrency
|
|||
import com.tangem.domain.wallets.usecase.GetWalletIconUseCase
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioManager
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.AvailableToAddData
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.model.UserPortfolioUM
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.transformer.UserPortfolioSectionsTransformer
|
||||
import com.tangem.features.commonfeatures.impl.userportfolio.model.UserPortfolioUM
|
||||
import com.tangem.features.commonfeatures.impl.userportfolio.transformer.UserPortfolioSectionsTransformer
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.transformer
|
||||
package com.tangem.features.commonfeatures.impl.userportfolio.transformer
|
||||
|
||||
import com.tangem.blockchainsdk.compatibility.getTokenIdIfL2Network
|
||||
import com.tangem.common.ui.account.toUM
|
||||
|
|
@ -21,7 +21,7 @@ import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
|||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioManager
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.AvailableToAddData
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.model.UserPortfolioUM
|
||||
import com.tangem.features.commonfeatures.impl.userportfolio.model.UserPortfolioUM
|
||||
import com.tangem.utils.StringsSigns
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
|
@ -22,11 +22,13 @@ import com.tangem.features.promobanners.api.PromoBannersBlockComponent
|
|||
import kotlinx.serialization.Serializable
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class FeedEntryChildFactory @Inject constructor(
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val portfolioComponentFactory: MarketsPortfolioComponent.Factory,
|
||||
private val portfolioBlockComponentFactory: PortfolioBlockComponent.Factory,
|
||||
private val addToPortfolioComponentFactory: AddToPortfolioComponent.Factory,
|
||||
private val addFundsComponentFactory: com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent.Factory,
|
||||
private val promoBannersBlockComponentFactory: PromoBannersBlockComponent.Factory,
|
||||
private val designFeatureToggles: DesignFeatureToggles,
|
||||
) {
|
||||
|
|
@ -81,6 +83,7 @@ internal class FeedEntryChildFactory @Inject constructor(
|
|||
portfolioBlockComponentFactory = portfolioBlockComponentFactory,
|
||||
designFeatureToggles = designFeatureToggles,
|
||||
addToPortfolioComponentFactory = addToPortfolioComponentFactory,
|
||||
addFundsComponentFactory = addFundsComponentFactory,
|
||||
)
|
||||
}
|
||||
is Child.TokenList -> {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.features.feed.components.market.details
|
||||
|
||||
import com.tangem.core.decompose.navigation.Route
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
internal data class AddFundsSlotRoute(
|
||||
val rawCurrencyId: CryptoCurrency.RawID,
|
||||
) : Route
|
||||
|
|
@ -19,6 +19,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.slot.childSlot
|
||||
import com.arkivanov.decompose.router.slot.dismiss
|
||||
import com.tangem.blockchainsdk.compatibility.getTokenIdIfL2Network
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
|
|
@ -41,6 +42,7 @@ import com.tangem.domain.appcurrency.model.AppCurrency
|
|||
import com.tangem.domain.markets.PreselectedTokenDetailsSection
|
||||
import com.tangem.domain.markets.TokenMarketParams
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioComponent
|
||||
import com.tangem.features.feed.components.market.details.portfolio.api.MarketsPortfolioComponent
|
||||
import com.tangem.features.feed.components.market.details.portfolioblock.PortfolioBlockComponent
|
||||
|
|
@ -64,6 +66,7 @@ internal class DefaultMarketsTokenDetailsComponent(
|
|||
portfolioBlockComponentFactory: PortfolioBlockComponent.Factory,
|
||||
val params: Params,
|
||||
private val addToPortfolioComponentFactory: AddToPortfolioComponent.Factory,
|
||||
private val addFundsComponentFactory: AddFundsComponent.Factory,
|
||||
) : ComposableModularBottomSheetContentComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
// applying l2 compatibility
|
||||
|
|
@ -101,6 +104,10 @@ internal class DefaultMarketsTokenDetailsComponent(
|
|||
override fun openAddToPortfolioViaUserPortfolio(rawCurrencyId: CryptoCurrency.RawID) {
|
||||
model.openAddToPortfolioViaUserPortfolio()
|
||||
}
|
||||
|
||||
override fun openAddFunds(rawCurrencyId: CryptoCurrency.RawID) {
|
||||
model.openAddFunds(rawCurrencyId)
|
||||
}
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
|
@ -114,6 +121,14 @@ internal class DefaultMarketsTokenDetailsComponent(
|
|||
childFactory = ::addToPortfolioChild,
|
||||
)
|
||||
|
||||
private val addFundsSlot = childSlot(
|
||||
source = model.addFundsSheetNavigation,
|
||||
serializer = AddFundsSlotRoute.serializer(),
|
||||
key = "addFundsSlot",
|
||||
handleBackButton = false,
|
||||
childFactory = ::addFundsChild,
|
||||
)
|
||||
|
||||
init {
|
||||
componentScope.launch(dispatchers.default) {
|
||||
model.networksState.collectLatest { state ->
|
||||
|
|
@ -155,6 +170,20 @@ internal class DefaultMarketsTokenDetailsComponent(
|
|||
)
|
||||
}
|
||||
|
||||
private fun addFundsChild(
|
||||
config: AddFundsSlotRoute,
|
||||
componentContext: ComponentContext,
|
||||
): ComposableBottomSheetComponent {
|
||||
val launchMode = AddFundsComponent.LaunchMode.FilteredByRawId(rawCurrencyId = config.rawCurrencyId)
|
||||
return addFundsComponentFactory.create(
|
||||
context = childByContext(componentContext),
|
||||
params = AddFundsComponent.Params(
|
||||
launchMode = launchMode,
|
||||
onDismiss = { model.addFundsSheetNavigation.dismiss() },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Title(bottomSheetState: State<BottomSheetState>) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
|
|
@ -226,6 +255,7 @@ internal class DefaultMarketsTokenDetailsComponent(
|
|||
}
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
val bottomSheet by addToPortfolioSlot.subscribeAsState()
|
||||
val addFundsBs by addFundsSlot.subscribeAsState()
|
||||
val bsState by bottomSheetState
|
||||
LaunchedEffect(bsState) {
|
||||
model.isVisibleOnScreen.value = bsState == BottomSheetState.EXPANDED
|
||||
|
|
@ -248,6 +278,7 @@ internal class DefaultMarketsTokenDetailsComponent(
|
|||
},
|
||||
)
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
addFundsBs.child?.instance?.BottomSheet()
|
||||
}
|
||||
|
||||
@Serializable
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import arrow.core.getOrElse
|
|||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.arkivanov.decompose.router.slot.dismiss
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.ui.markets.action.TokenActionsBSContentUM
|
||||
import com.tangem.common.ui.markets.action.TokenActionsHandler
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
|
|
@ -36,6 +38,7 @@ internal class MarketsPortfolioModel @Inject constructor(
|
|||
private val tokenActionsHandlerFactory: TokenActionsHandler.Factory,
|
||||
private val receiveAddressesFactory: ReceiveAddressesFactory,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val appRouter: AppRouter,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
) : Model() {
|
||||
|
||||
|
|
@ -68,6 +71,17 @@ internal class MarketsPortfolioModel @Inject constructor(
|
|||
addToPortfolioManager.onSuccessAdded.receiveAsFlow()
|
||||
.onEach { bottomSheetNavigation.dismiss() }
|
||||
.launchIn(modelScope)
|
||||
addToPortfolioManager.onAddedTokenClick.receiveAsFlow()
|
||||
.onEach { result ->
|
||||
bottomSheetNavigation.dismiss()
|
||||
appRouter.push(
|
||||
AppRoute.CurrencyDetails(
|
||||
userWalletId = result.wallet.walletId,
|
||||
currency = result.addedCurrency.currency,
|
||||
),
|
||||
)
|
||||
}
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
fun setTokenNetworks(networks: List<TokenMarketInfo.Network>) {
|
||||
|
|
@ -127,7 +141,7 @@ internal class MarketsPortfolioModel @Inject constructor(
|
|||
private fun createTokenActionsHandler(): TokenActionsHandler {
|
||||
return tokenActionsHandlerFactory.create(
|
||||
currentAppCurrency = Provider { currentAppCurrency.value },
|
||||
onHandleQuickAction = { handledAction ->
|
||||
onHandleQuickAction = { handledAction, _ ->
|
||||
val currency = handledAction.cryptoCurrencyData.status.currency
|
||||
analyticsEventHandler.send(
|
||||
analyticsEventBuilder.quickActionClick(
|
||||
|
|
|
|||
|
|
@ -5,4 +5,5 @@ import com.tangem.domain.models.currency.CryptoCurrency
|
|||
internal interface PortfolioBlockParentClickIntents {
|
||||
fun openAddToPortfolioDirect()
|
||||
fun openAddToPortfolioViaUserPortfolio(rawCurrencyId: CryptoCurrency.RawID)
|
||||
fun openAddFunds(rawCurrencyId: CryptoCurrency.RawID)
|
||||
}
|
||||
|
|
@ -171,7 +171,7 @@ internal class PortfolioBlockModel @Inject constructor(
|
|||
tokenSymbol = firstCurrency.symbol,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
onRowClick = { parentRouter?.openAddToPortfolioViaUserPortfolio(currencyRawId) },
|
||||
onAddFundsClick = {},
|
||||
onAddFundsClick = { parentRouter?.openAddFunds(currencyRawId) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ import com.tangem.domain.settings.usercountry.models.UserCountry
|
|||
import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioManager
|
||||
import com.tangem.features.commonfeatures.api.tokenactions.BottomAction
|
||||
import com.tangem.features.feed.components.market.details.AddFundsSlotRoute
|
||||
import com.tangem.features.feed.components.market.details.AddToPortfolioSlotRoute
|
||||
import com.tangem.features.feed.components.market.details.DefaultMarketsTokenDetailsComponent
|
||||
import com.tangem.features.feed.components.market.details.analytics.MarketTokenAnalyticsEvent
|
||||
|
|
@ -233,6 +235,7 @@ internal class MarketsTokenDetailsModel @Inject constructor(
|
|||
val networksState = MutableStateFlow<TokenNetworksState>(TokenNetworksState.Loading)
|
||||
|
||||
val addToPortfolioSheetNavigation = SlotNavigation<AddToPortfolioSlotRoute>()
|
||||
val addFundsSheetNavigation = SlotNavigation<AddFundsSlotRoute>()
|
||||
|
||||
private val isAddToPortfolioAvailable: Boolean =
|
||||
params.shouldShowPortfolio && designFeatureToggles.isRedesignEnabled
|
||||
|
|
@ -345,7 +348,15 @@ internal class MarketsTokenDetailsModel @Inject constructor(
|
|||
.onEach { addToPortfolioSheetNavigation.dismiss() }
|
||||
.launchIn(modelScope)
|
||||
addToPortfolioManager.onSuccessAdded.receiveAsFlow()
|
||||
.onEach { addToPortfolioSheetNavigation.dismiss() }
|
||||
.onEach { result ->
|
||||
addToPortfolioSheetNavigation.dismiss()
|
||||
val meta = result.meta
|
||||
if (meta is AddToPortfolioManager.FinishMeta.OnBottomAction &&
|
||||
meta.action == BottomAction.GoToToken
|
||||
) {
|
||||
openTokenDetails(result)
|
||||
}
|
||||
}
|
||||
.launchIn(modelScope)
|
||||
addToPortfolioManager.onAddedTokenClick.receiveAsFlow()
|
||||
.onEach { result ->
|
||||
|
|
@ -367,6 +378,10 @@ internal class MarketsTokenDetailsModel @Inject constructor(
|
|||
addToPortfolioSheetNavigation.activate(AddToPortfolioSlotRoute)
|
||||
}
|
||||
|
||||
fun openAddFunds(rawCurrencyId: com.tangem.domain.models.currency.CryptoCurrency.RawID) {
|
||||
addFundsSheetNavigation.activate(AddFundsSlotRoute(rawCurrencyId = rawCurrencyId))
|
||||
}
|
||||
|
||||
private fun openTokenDetails(result: AddToPortfolioManager.Result) {
|
||||
appRouter.push(
|
||||
AppRoute.CurrencyDetails(
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ dependencies {
|
|||
implementation(projects.features.sendV2.api)
|
||||
implementation(projects.features.tokenRecieve.api)
|
||||
implementation(projects.features.yieldSupply.api)
|
||||
implementation(projects.features.commonFeatures.api)
|
||||
|
||||
implementation(deps.decompose.ext.compose)
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDeta
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.route.TokenDetailsBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreen
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreenLegacy
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.AddFundsBottomSheetComponent
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.ChooseAddressBottomSheetComponent
|
||||
import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.CloreMigrationBottomSheetComponent
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.DynamicAddressesBottomSheetComponent
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.TransferBottomSheetComponent
|
||||
|
|
@ -47,6 +47,7 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
|||
expressTransactionsComponentFactory: ExpressTransactionsComponent.Factory,
|
||||
private val tokenReceiveComponentFactory: TokenReceiveComponent.Factory,
|
||||
private val yieldSupplyWarningComponentFactory: YieldSupplyDepositedWarningComponent.Factory,
|
||||
private val addFundsComponentFactory: AddFundsComponent.Factory,
|
||||
yieldSupplyComponentFactory: YieldSupplyComponent.Factory,
|
||||
private val ratingComponentFactory: RatingComponent.Factory,
|
||||
) : TokenDetailsComponent, AppComponentContext by appComponentContext {
|
||||
|
|
@ -177,9 +178,15 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
|||
dynamicAddressesDelegate = model.dynamicAddressesDelegate,
|
||||
onDismiss = model.bottomSheetNavigation::dismiss,
|
||||
)
|
||||
is TokenDetailsBottomSheetConfig.AddFunds -> AddFundsBottomSheetComponent(
|
||||
stateFlow = model.addFundsUiState,
|
||||
onDismiss = model.bottomSheetNavigation::dismiss,
|
||||
is TokenDetailsBottomSheetConfig.AddFunds -> addFundsComponentFactory.create(
|
||||
context = childByContext(componentContext),
|
||||
params = AddFundsComponent.Params(
|
||||
launchMode = AddFundsComponent.LaunchMode.TokenActionsOnly(
|
||||
userWalletId = route.userWalletId,
|
||||
currency = route.currency,
|
||||
),
|
||||
onDismiss = model.bottomSheetNavigation::dismiss,
|
||||
),
|
||||
)
|
||||
is TokenDetailsBottomSheetConfig.Transfer -> TransferBottomSheetComponent(
|
||||
stateFlow = model.transferUiState,
|
||||
|
|
|
|||
|
|
@ -559,7 +559,12 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onAddFundsClick() {
|
||||
bottomSheetNavigation.activate(TokenDetailsBottomSheetConfig.AddFunds)
|
||||
bottomSheetNavigation.activate(
|
||||
TokenDetailsBottomSheetConfig.AddFunds(
|
||||
userWalletId = userWalletId,
|
||||
currency = cryptoCurrency,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun onTransferClick() {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.tangem.core.decompose.navigation.Route
|
|||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.NetworkAddress
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.tokens.model.details.TokenAction
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
|
|
@ -32,7 +33,10 @@ sealed class TokenDetailsBottomSheetConfig : Route {
|
|||
data object DynamicAddresses : TokenDetailsBottomSheetConfig()
|
||||
|
||||
@Serializable
|
||||
data object AddFunds : TokenDetailsBottomSheetConfig()
|
||||
data class AddFunds(
|
||||
val userWalletId: UserWalletId,
|
||||
val currency: CryptoCurrency,
|
||||
) : TokenDetailsBottomSheetConfig()
|
||||
|
||||
@Serializable
|
||||
data object Transfer : TokenDetailsBottomSheetConfig()
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.AddFundsUM
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import com.tangem.core.ui.R as CoreR
|
||||
|
||||
internal class AddFundsBottomSheetComponent(
|
||||
private val stateFlow: StateFlow<AddFundsUM>,
|
||||
private val onDismiss: () -> Unit,
|
||||
) : ComposableBottomSheetComponent {
|
||||
|
||||
override fun dismiss() {
|
||||
onDismiss()
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun BottomSheet() {
|
||||
val state by stateFlow.collectAsStateWithLifecycle()
|
||||
|
||||
val config = remember(state) {
|
||||
TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = ::dismiss,
|
||||
content = state,
|
||||
)
|
||||
}
|
||||
|
||||
TangemModalBottomSheet<AddFundsUM>(
|
||||
config = config,
|
||||
containerColor = TangemTheme.colors2.surface.level2,
|
||||
title = {
|
||||
TangemModalBottomSheetTitle(
|
||||
title = resourceReference(CoreR.string.common_get_token),
|
||||
endIconRes = CoreR.drawable.ic_close_24,
|
||||
onEndClick = ::dismiss,
|
||||
)
|
||||
},
|
||||
content = { contentState ->
|
||||
AddFundsBottomSheetContent(
|
||||
state = contentState,
|
||||
onCloseClick = ::dismiss,
|
||||
modifier = Modifier.padding(horizontal = TangemTheme.dimens2.x4),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,167 +0,0 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.common.ui.tokenaction.TokenActionRow
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.ds.button.SecondaryTangemButton
|
||||
import com.tangem.core.ui.ds.button.TangemButtonShape
|
||||
import com.tangem.core.ui.ds.button.TangemButtonSize
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.LocalHazeState
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.AddFundsUM
|
||||
import dev.chrisbanes.haze.rememberHazeState
|
||||
import com.tangem.core.ui.R as CoreR
|
||||
|
||||
@Composable
|
||||
internal fun AddFundsBottomSheetContent(state: AddFundsUM, onCloseClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
|
||||
) {
|
||||
BuyActionRow(state = state)
|
||||
SwapActionRow(state = state)
|
||||
ReceiveActionRow(state = state)
|
||||
|
||||
SpacerH(TangemTheme.dimens2.x2)
|
||||
|
||||
CompositionLocalProvider(LocalHazeState provides rememberHazeState()) {
|
||||
SecondaryTangemButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = onCloseClick,
|
||||
text = resourceReference(CoreR.string.common_close),
|
||||
size = TangemButtonSize.X12,
|
||||
shape = TangemButtonShape.Rounded,
|
||||
)
|
||||
}
|
||||
|
||||
SpacerH(TangemTheme.dimens2.x4)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BuyActionRow(state: AddFundsUM) {
|
||||
val row = (state as? AddFundsUM.Content)?.buy
|
||||
if (state is AddFundsUM.Content && row == null) return
|
||||
ActionRow(
|
||||
iconRes = CoreR.drawable.ic_credit_card_20,
|
||||
title = resourceReference(CoreR.string.common_buy),
|
||||
description = resourceReference(CoreR.string.quick_action_buy_description),
|
||||
row = row,
|
||||
isLoading = state is AddFundsUM.Loading,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SwapActionRow(state: AddFundsUM) {
|
||||
val row = (state as? AddFundsUM.Content)?.swap
|
||||
if (state is AddFundsUM.Content && row == null) return
|
||||
ActionRow(
|
||||
iconRes = CoreR.drawable.ic_exchange_mini_24,
|
||||
title = resourceReference(CoreR.string.common_swap),
|
||||
description = resourceReference(CoreR.string.quick_action_swap_description),
|
||||
row = row,
|
||||
isLoading = state is AddFundsUM.Loading,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ReceiveActionRow(state: AddFundsUM) {
|
||||
val row = (state as? AddFundsUM.Content)?.receive
|
||||
if (state is AddFundsUM.Content && row == null) return
|
||||
ActionRow(
|
||||
iconRes = CoreR.drawable.ic_qrcode_new_24,
|
||||
title = resourceReference(CoreR.string.common_receive),
|
||||
description = resourceReference(CoreR.string.quick_action_receive_description),
|
||||
row = row,
|
||||
isLoading = state is AddFundsUM.Loading,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ActionRow(
|
||||
iconRes: Int,
|
||||
title: TextReference,
|
||||
description: TextReference,
|
||||
row: AddFundsUM.Row?,
|
||||
isLoading: Boolean,
|
||||
) {
|
||||
if (isLoading || row?.isLoading == true) {
|
||||
TokenActionRow(
|
||||
iconRes = iconRes,
|
||||
title = title,
|
||||
description = description,
|
||||
tailContent = { TailLoader() },
|
||||
)
|
||||
} else {
|
||||
TokenActionRow(
|
||||
iconRes = iconRes,
|
||||
title = title,
|
||||
description = description,
|
||||
onClick = row?.onClick,
|
||||
onLongClick = row?.onLongClick,
|
||||
isEnabled = row?.isEnabled == true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TailLoader() {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(20.dp),
|
||||
color = TangemTheme.colors2.graphic.neutral.tertiary,
|
||||
strokeWidth = 2.dp,
|
||||
)
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Preview(widthDp = 360, showBackground = true)
|
||||
@Composable
|
||||
private fun Preview(@PreviewParameter(AddFundsPreviewProvider::class) state: AddFundsUM) {
|
||||
TangemThemePreviewRedesign {
|
||||
CompositionLocalProvider(LocalRedesignEnabled provides true) {
|
||||
AddFundsBottomSheetContent(
|
||||
state = state,
|
||||
onCloseClick = {},
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AddFundsPreviewProvider : PreviewParameterProvider<AddFundsUM> {
|
||||
override val values: Sequence<AddFundsUM> = sequenceOf(
|
||||
AddFundsUM.Loading,
|
||||
AddFundsUM.Content(
|
||||
buy = AddFundsUM.Row(isLoading = false, isEnabled = true, onClick = {}),
|
||||
swap = AddFundsUM.Row(isLoading = false, isEnabled = true, onClick = {}),
|
||||
receive = AddFundsUM.Row(isLoading = false, isEnabled = true, onClick = {}, onLongClick = {}),
|
||||
),
|
||||
AddFundsUM.Content(
|
||||
buy = AddFundsUM.Row(isLoading = false, isEnabled = false, onClick = {}),
|
||||
swap = AddFundsUM.Row(isLoading = false, isEnabled = false, onClick = {}),
|
||||
receive = AddFundsUM.Row(isLoading = false, isEnabled = true, onClick = {}, onLongClick = {}),
|
||||
),
|
||||
AddFundsUM.Content(
|
||||
buy = null,
|
||||
swap = null,
|
||||
receive = AddFundsUM.Row(isLoading = false, isEnabled = true, onClick = {}, onLongClick = {}),
|
||||
),
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -25,6 +25,7 @@ import com.tangem.core.ui.utils.parseBigDecimal
|
|||
import com.tangem.domain.tokens.model.details.TokenAction
|
||||
import com.tangem.feature.wallet.child.managetokens.AddAndManageBottomSheetComponent
|
||||
import com.tangem.feature.wallet.child.organizetokens.OrganizeTokensComponent
|
||||
import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorComponent
|
||||
import com.tangem.feature.wallet.child.tokenActions.DefaultTokenActionsComponent
|
||||
import com.tangem.feature.wallet.child.tokenActions.TokenActionsComponent
|
||||
|
|
@ -67,6 +68,7 @@ internal class WalletComponent @AssistedInject constructor(
|
|||
private val networkSelectionComponentFactory: NetworkSelectionComponent.Factory,
|
||||
private val tokenActionsComponentFactory: TokenActionsComponent.Factory,
|
||||
private val portfolioSelectorComponentFactory: PortfolioSelectorComponent.Factory,
|
||||
private val addFundsComponentFactory: AddFundsComponent.Factory,
|
||||
private val designFeatureToggles: DesignFeatureToggles,
|
||||
) : ComposableContentComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
|
|
@ -180,6 +182,15 @@ internal class WalletComponent @AssistedInject constructor(
|
|||
),
|
||||
)
|
||||
}
|
||||
is WalletDialogConfig.AddFunds -> {
|
||||
addFundsComponentFactory.create(
|
||||
context = childByContext(componentContext),
|
||||
params = AddFundsComponent.Params(
|
||||
launchMode = AddFundsComponent.LaunchMode.ChooseToken(dialogConfig.userWalletId),
|
||||
onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
|
||||
),
|
||||
)
|
||||
}
|
||||
is WalletDialogConfig.AddAndManage -> {
|
||||
AddAndManageBottomSheetComponent(
|
||||
appComponentContext = childByContext(componentContext),
|
||||
|
|
|
|||
|
|
@ -120,7 +120,9 @@ internal class DefaultWalletRouter @Inject constructor(
|
|||
}
|
||||
|
||||
override fun openAddFunds(userWalletId: UserWalletId) {
|
||||
router.push(AppRoute.AddFunds(userWalletId = userWalletId))
|
||||
dialogNavigation.activate(
|
||||
configuration = WalletDialogConfig.AddFunds(userWalletId = userWalletId),
|
||||
)
|
||||
}
|
||||
|
||||
override fun isWalletLastScreen(): Boolean {
|
||||
|
|
|
|||
|
|
@ -62,6 +62,9 @@ internal sealed interface WalletDialogConfig {
|
|||
val customerId: String,
|
||||
) : WalletDialogConfig
|
||||
|
||||
@Serializable
|
||||
data class AddFunds(val userWalletId: UserWalletId) : WalletDialogConfig
|
||||
|
||||
@Serializable
|
||||
data class OrganizeTokens(val userWalletId: UserWalletId) : WalletDialogConfig
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue