Updated on 2026-08-14
This commit is contained in:
commit
a22e77ebe8
669 changed files with 27695 additions and 7905 deletions
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.features.commonfeatures.api.addfunds
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
||||
interface AddFundsComponent : ComposableContentComponent {
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Params, AddFundsComponent>
|
||||
}
|
||||
|
|
@ -41,6 +41,11 @@ interface ChooseTokenBridge : ChooseTokenBridgeInternal {
|
|||
isShowMarketBlock = true,
|
||||
isShowPaymentAccount = true,
|
||||
)
|
||||
val AddFunds = Settings(
|
||||
title = resourceReference(R.string.swapping_to_title),
|
||||
isShowMarketBlock = true,
|
||||
isShowPaymentAccount = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
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.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
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.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.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 dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultAddFundsComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted private val params: AddFundsComponent.Params,
|
||||
chooseTokenComponentFactory: ChooseTokenComponent.Factory,
|
||||
tokenActionsComponentFactory: TokenActionsComponent.Factory,
|
||||
) : 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 tokenActionsComponent: TokenActionsComponent = tokenActionsComponentFactory.create(
|
||||
context = child(key = "addFundsTokenActions"),
|
||||
params = TokenActionsComponent.Params(
|
||||
data = model.tokenActionsData,
|
||||
callbacks = model,
|
||||
bottomAction = TokenActionsComponent.BottomAction.GoToToken,
|
||||
isRedesignForced = true,
|
||||
),
|
||||
)
|
||||
|
||||
@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)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : AddFundsComponent.Factory {
|
||||
override fun create(context: AppComponentContext, params: AddFundsComponent.Params): DefaultAddFundsComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.tangem.features.commonfeatures.impl.addfunds.analytics
|
||||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
|
||||
internal sealed class AddFundsAnalyticsEvent(
|
||||
event: String,
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : AnalyticsEvent(category = CATEGORY, event = event, params = params) {
|
||||
|
||||
class MethodScreenOpened(source: String) : AddFundsAnalyticsEvent(
|
||||
event = "Method Screen Opened",
|
||||
params = mapOf(AnalyticsParam.SOURCE to source),
|
||||
)
|
||||
|
||||
class ButtonBuy : AddFundsAnalyticsEvent(event = "Button - Buy")
|
||||
|
||||
class ButtonSwap : AddFundsAnalyticsEvent(event = "Button - Swap")
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.features.commonfeatures.impl.addfunds.di
|
||||
|
||||
import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent
|
||||
import com.tangem.features.commonfeatures.impl.addfunds.DefaultAddFundsComponent
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface AddFundsComponentModule {
|
||||
|
||||
@Binds
|
||||
fun bindAddFundsComponentFactory(factory: DefaultAddFundsComponent.Factory): AddFundsComponent.Factory
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.features.commonfeatures.impl.addfunds.di
|
||||
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.features.commonfeatures.impl.addfunds.model.AddFundsModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(ModelComponent::class)
|
||||
internal interface AddFundsModelModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(AddFundsModel::class)
|
||||
fun addFundsModel(model: AddFundsModel): Model
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
package com.tangem.features.commonfeatures.impl.addfunds.model
|
||||
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.ui.markets.action.CryptoCurrencyData
|
||||
import com.tangem.common.ui.markets.action.TokenActionsBSContentUM
|
||||
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.usecase.GetCryptoCurrencyActionsUseCaseV2
|
||||
import com.tangem.domain.models.account.AccountStatus
|
||||
import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent
|
||||
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.impl.addfunds.analytics.AddFundsAnalyticsEvent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.TokenActionsComponent
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
internal class AddFundsModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
chooseTokenBridgeFactory: ChooseTokenBridge.Factory,
|
||||
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCaseV2,
|
||||
private val appRouter: AppRouter,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
) : Model(), TokenActionsComponent.Callbacks {
|
||||
|
||||
private val params = paramsContainer.require<AddFundsComponent.Params>()
|
||||
|
||||
val chooseTokenBridge: ChooseTokenBridge = chooseTokenBridgeFactory.create(
|
||||
modelScope = modelScope,
|
||||
settings = ChooseTokenBridge.Settings.AddFunds,
|
||||
analyticsPayload = setOf(
|
||||
ChooseTokenAnalyticsPayload.ScreensSources(SCREEN_SOURCE),
|
||||
),
|
||||
)
|
||||
|
||||
private val selectedToken = MutableStateFlow<ChooseTokenResult?>(null)
|
||||
|
||||
val isTokenActionsShown: StateFlow<Boolean> = selectedToken
|
||||
.map { it != null }
|
||||
.stateIn(modelScope, SharingStarted.Eagerly, initialValue = false)
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val tokenActionsData: Flow<CryptoCurrencyData> = selectedToken
|
||||
.filterNotNull()
|
||||
.flatMapLatest { result ->
|
||||
val cryptoPortfolio = result.account as? AccountStatus.CryptoPortfolio
|
||||
?: return@flatMapLatest emptyFlow()
|
||||
getCryptoCurrencyActionsUseCase(
|
||||
accountId = cryptoPortfolio.account.accountId,
|
||||
currency = result.currency.currency,
|
||||
).map { actionsState ->
|
||||
CryptoCurrencyData(
|
||||
userWallet = result.wallet,
|
||||
status = result.currency,
|
||||
actions = actionsState.states,
|
||||
isAccountMode = false,
|
||||
account = cryptoPortfolio,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
chooseTokenBridge.selectWalletTab(params.userWalletId)
|
||||
analyticsEventHandler.send(
|
||||
AddFundsAnalyticsEvent.MethodScreenOpened(source = AddFundsAnalyticsEvent.SOURCE_MAIN_SCREEN),
|
||||
)
|
||||
observeBridge()
|
||||
}
|
||||
|
||||
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,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun onQuickActionClick(action: TokenActionsBSContentUM.Action) {
|
||||
val event = when (action) {
|
||||
TokenActionsBSContentUM.Action.Buy -> AddFundsAnalyticsEvent.ButtonBuy()
|
||||
TokenActionsBSContentUM.Action.Exchange -> AddFundsAnalyticsEvent.ButtonSwap()
|
||||
TokenActionsBSContentUM.Action.Receive -> AddFundsAnalyticsEvent.ButtonReceive()
|
||||
else -> return
|
||||
}
|
||||
analyticsEventHandler.send(event)
|
||||
}
|
||||
|
||||
fun onTokenActionsDismiss() {
|
||||
selectedToken.value = null
|
||||
}
|
||||
|
||||
private fun observeBridge() {
|
||||
modelScope.launch {
|
||||
chooseTokenBridge.onCurrencyChosen.receiveAsFlow().collect { result ->
|
||||
selectedToken.value = result
|
||||
}
|
||||
}
|
||||
modelScope.launch {
|
||||
chooseTokenBridge.onClose.receiveAsFlow().collect {
|
||||
appRouter.pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val SCREEN_SOURCE = "AddFunds"
|
||||
}
|
||||
}
|
||||
|
|
@ -58,7 +58,6 @@ internal class DefaultAddToPortfolioComponent @AssistedInject constructor(
|
|||
tokenActionsComponentFactory.create(
|
||||
context = child("tokenActionsComponent"),
|
||||
params = TokenActionsComponent.Params(
|
||||
eventBuilder = model.eventBuilder,
|
||||
callbacks = model,
|
||||
data = model.tokenActionsData,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
|||
import com.arkivanov.decompose.router.slot.childSlot
|
||||
import com.arkivanov.decompose.router.slot.dismiss
|
||||
import com.tangem.common.ui.markets.action.CryptoCurrencyData
|
||||
import com.tangem.common.ui.markets.action.TokenActionsBSContentUM
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
|
|
@ -17,7 +18,6 @@ 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.analytics.PortfolioAnalyticsEvent
|
||||
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
|
||||
|
|
@ -46,7 +46,7 @@ internal class TokenActionsComponent @AssistedInject constructor(
|
|||
val state = model.uiState.collectAsStateWithLifecycle()
|
||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||
val tokenActionsUM = state.value ?: return
|
||||
if (LocalRedesignEnabled.current) {
|
||||
if (LocalRedesignEnabled.current || params.isRedesignForced) {
|
||||
TokenActionsContentV2(
|
||||
modifier = modifier,
|
||||
state = tokenActionsUM,
|
||||
|
|
@ -72,13 +72,17 @@ internal class TokenActionsComponent @AssistedInject constructor(
|
|||
)
|
||||
|
||||
data class Params(
|
||||
val eventBuilder: PortfolioAnalyticsEvent.EventBuilder,
|
||||
val data: Flow<CryptoCurrencyData>,
|
||||
val callbacks: Callbacks,
|
||||
val bottomAction: BottomAction = BottomAction.Later,
|
||||
val isRedesignForced: Boolean = false,
|
||||
)
|
||||
|
||||
enum class BottomAction { Later, GoToToken }
|
||||
|
||||
interface Callbacks {
|
||||
fun onLaterClick()
|
||||
fun onBottomActionClick()
|
||||
fun onQuickActionClick(action: TokenActionsBSContentUM.Action) {}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.arkivanov.decompose.router.stack.replaceAll
|
|||
import com.tangem.blockchainsdk.compatibility.getTokenIdIfL2Network
|
||||
import com.tangem.common.ui.markets.action.CryptoCurrencyData
|
||||
import com.tangem.common.ui.markets.action.QuickActionsConverter.toQuickActions
|
||||
import com.tangem.common.ui.markets.action.TokenActionsBSContentUM
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
|
|
@ -106,6 +107,10 @@ 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,
|
||||
|
|
@ -157,6 +162,7 @@ internal class AddToPortfolioModel @Inject constructor(
|
|||
addToPortfolioManager.onSuccessAdded(result)
|
||||
channel.close()
|
||||
}
|
||||
|
||||
fun finishOnAddedTokenClick(result: AddToPortfolioManager.Result) {
|
||||
addToPortfolioManager.onAddedTokenClick(result)
|
||||
channel.close()
|
||||
|
|
@ -306,7 +312,7 @@ internal class AddToPortfolioModel @Inject constructor(
|
|||
.onEmpty { finishSuccessFlow(result) }
|
||||
.launchIn(this)
|
||||
|
||||
callbackDelegate.onLaterClick.receiveAsFlow().first()
|
||||
callbackDelegate.onChooseTokenBottomActionClick.receiveAsFlow().first()
|
||||
analyticsEventHandler.send(eventBuilder.getTokenLater())
|
||||
finishSuccessFlow(result)
|
||||
}
|
||||
|
|
@ -523,7 +529,7 @@ internal class AddToPortfolioCallbackDelegate @Inject constructor() :
|
|||
UserPortfolioComponent.Callbacks {
|
||||
|
||||
val onNetworkSelected = Channel<TokenMarketInfo.Network>()
|
||||
val onLaterClick = Channel<Unit>()
|
||||
val onChooseTokenBottomActionClick = Channel<Unit>()
|
||||
val onChangeNetworkClick = Channel<Unit>()
|
||||
val onChangePortfolioClick = Channel<Unit>()
|
||||
val onTokenAdded = Channel<CryptoCurrencyStatus>()
|
||||
|
|
@ -533,8 +539,8 @@ internal class AddToPortfolioCallbackDelegate @Inject constructor() :
|
|||
onNetworkSelected.trySend(network)
|
||||
}
|
||||
|
||||
override fun onLaterClick() {
|
||||
onLaterClick.trySend(Unit)
|
||||
override fun onBottomActionClick() {
|
||||
onChooseTokenBottomActionClick.trySend(Unit)
|
||||
}
|
||||
|
||||
override fun onChangeNetworkClick() {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import com.arkivanov.decompose.router.slot.SlotNavigation
|
|||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.tangem.common.ui.markets.action.TokenActionsBSContentUM
|
||||
import com.tangem.common.ui.markets.action.TokenActionsHandler
|
||||
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
|
||||
|
|
@ -31,12 +30,10 @@ internal class TokenActionsModel @Inject constructor(
|
|||
tokenActionsIntentsFactory: TokenActionsHandler.Factory,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val uiBuilder: TokenActionsUiBuilder,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val receiveAddressesFactory: ReceiveAddressesFactory,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<TokenActionsComponent.Params>()
|
||||
private val analyticsEventBuilder get() = params.eventBuilder
|
||||
private val currentAppCurrency = getSelectedAppCurrencyUseCase.invokeOrDefault()
|
||||
.stateIn(
|
||||
scope = modelScope,
|
||||
|
|
@ -68,6 +65,7 @@ internal class TokenActionsModel @Inject constructor(
|
|||
isBalanceHidden = isBalanceHidden,
|
||||
)
|
||||
}
|
||||
.flowOn(dispatchers.default)
|
||||
.stateIn(
|
||||
scope = modelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
|
|
@ -75,11 +73,10 @@ internal class TokenActionsModel @Inject constructor(
|
|||
)
|
||||
|
||||
private fun handledQuickAction(handledAction: TokenActionsHandler.HandledQuickAction) = modelScope.launch {
|
||||
val event = analyticsEventBuilder.getTokenActionClick(actionUM = handledAction.action)
|
||||
analyticsEventHandler.send(event)
|
||||
params.callbacks.onQuickActionClick(handledAction.action)
|
||||
val isReceive = handledAction.action == TokenActionsBSContentUM.Action.Receive
|
||||
if (!isReceive) return@launch
|
||||
modelScope.launch {
|
||||
modelScope.launch(dispatchers.default) {
|
||||
val tokenConfig = receiveAddressesFactory.create(
|
||||
status = handledAction.cryptoCurrencyData.status,
|
||||
userWalletId = handledAction.cryptoCurrencyData.userWallet.walletId,
|
||||
|
|
|
|||
|
|
@ -3,27 +3,35 @@ package com.tangem.features.commonfeatures.impl.addtoportfolio.model
|
|||
import androidx.compose.ui.text.SpanStyle
|
||||
import com.tangem.common.getTotalCryptoAmount
|
||||
import com.tangem.common.getTotalFiatAmount
|
||||
import com.tangem.common.ui.account.*
|
||||
import com.tangem.common.ui.account.CryptoPortfolioIconConverter
|
||||
import com.tangem.common.ui.account.getResId
|
||||
import com.tangem.common.ui.account.getUiColor
|
||||
import com.tangem.common.ui.account.toUM
|
||||
import com.tangem.common.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
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.common.ui.userwallet.converter.WalletIconUMConverter
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.ui.DesignFeatureToggles
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeIconPosition
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeShape
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeSize
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeUM
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.format.bigdecimal.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
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 java.math.BigDecimal
|
||||
import javax.inject.Inject
|
||||
|
|
@ -32,6 +40,8 @@ import javax.inject.Inject
|
|||
internal class TokenActionsUiBuilder @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
private val designFeatureToggles: DesignFeatureToggles,
|
||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||
private val walletIconUMConverter: WalletIconUMConverter,
|
||||
) {
|
||||
private val params = paramsContainer.require<TokenActionsComponent.Params>()
|
||||
|
||||
|
|
@ -41,7 +51,7 @@ internal class TokenActionsUiBuilder @Inject constructor(
|
|||
appCurrency: AppCurrency,
|
||||
isBalanceHidden: Boolean,
|
||||
): TokenActionsUM {
|
||||
return if (designFeatureToggles.isRedesignEnabled) {
|
||||
return if (designFeatureToggles.isRedesignEnabled || params.isRedesignForced) {
|
||||
buildV2(
|
||||
cryptoCurrencyData = cryptoCurrencyData,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
|
|
@ -78,8 +88,9 @@ internal class TokenActionsUiBuilder @Inject constructor(
|
|||
tokenActionsHandler = tokenActionsHandler,
|
||||
isRedesignEnabled = false,
|
||||
),
|
||||
onLaterClick = {
|
||||
params.callbacks.onLaterClick()
|
||||
bottomActionText = bottomActionText(params.bottomAction),
|
||||
onBottomActionClick = {
|
||||
params.callbacks.onBottomActionClick()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -108,50 +119,53 @@ internal class TokenActionsUiBuilder @Inject constructor(
|
|||
tokenActionsHandler = tokenActionsHandler,
|
||||
isRedesignEnabled = true,
|
||||
),
|
||||
onLaterClick = {
|
||||
params.callbacks.onLaterClick()
|
||||
bottomActionText = bottomActionText(params.bottomAction),
|
||||
onBottomActionClick = {
|
||||
params.callbacks.onBottomActionClick()
|
||||
},
|
||||
isBalancesHidden = isBalanceHidden,
|
||||
portfolioBadge = createPortfolioBadge(cryptoCurrencyData),
|
||||
portfolioBadge = createPortfolioBadge(cryptoCurrencyData = cryptoCurrencyData),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createPortfolioBadge(cryptoCurrencyData: CryptoCurrencyData): TangemBadgeUM {
|
||||
val icon: AccountIconUM?
|
||||
val name = if (cryptoCurrencyData.isAccountMode) {
|
||||
icon = CryptoPortfolioIconConverter.convert(cryptoCurrencyData.account.account.icon)
|
||||
cryptoCurrencyData
|
||||
private fun bottomActionText(action: TokenActionsComponent.BottomAction): TextReference {
|
||||
return when (action) {
|
||||
TokenActionsComponent.BottomAction.Later -> resourceReference(R.string.common_later)
|
||||
TokenActionsComponent.BottomAction.GoToToken -> resourceReference(R.string.common_go_to_token)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createPortfolioBadge(cryptoCurrencyData: CryptoCurrencyData): PortfolioBadgeUM {
|
||||
return if (cryptoCurrencyData.isAccountMode) {
|
||||
val icon = CryptoPortfolioIconConverter.convert(cryptoCurrencyData.account.account.icon)
|
||||
val name = cryptoCurrencyData
|
||||
.account
|
||||
.account
|
||||
.accountName
|
||||
.toUM()
|
||||
.value
|
||||
PortfolioBadgeUM.Account(
|
||||
badge = TangemBadgeUM(
|
||||
text = name,
|
||||
tangemIconUM = TangemIconUM.Icon(
|
||||
iconRes = icon.value.getResId(),
|
||||
tintReference = { icon.color.getUiColor() },
|
||||
),
|
||||
size = TangemBadgeSize.X6,
|
||||
shape = TangemBadgeShape.Rounded,
|
||||
iconPosition = TangemBadgeIconPosition.Start,
|
||||
shouldRespectIconTint = true,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
icon = null
|
||||
stringReference(cryptoCurrencyData.userWallet.name)
|
||||
val userWallet = cryptoCurrencyData.userWallet
|
||||
PortfolioBadgeUM.Wallet(
|
||||
name = stringReference(userWallet.name),
|
||||
deviceIcon = walletIconUMConverter.convert(
|
||||
getWalletIconUseCase(cryptoCurrencyData.userWallet),
|
||||
),
|
||||
)
|
||||
}
|
||||
return TangemBadgeUM(
|
||||
text = name,
|
||||
tangemIconUM = if (icon == null) {
|
||||
TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_key_card_20,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.tertiary },
|
||||
)
|
||||
} else {
|
||||
TangemIconUM.Icon(
|
||||
iconRes = icon.value.getResId(),
|
||||
tintReference = { icon.color.getUiColor() },
|
||||
)
|
||||
},
|
||||
size = TangemBadgeSize.X6,
|
||||
shape = TangemBadgeShape.Rounded,
|
||||
iconPosition = if (cryptoCurrencyData.isAccountMode) {
|
||||
TangemBadgeIconPosition.Start
|
||||
} else {
|
||||
TangemBadgeIconPosition.End
|
||||
},
|
||||
shouldRespectIconTint = cryptoCurrencyData.isAccountMode,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createSubtitle2State(status: CryptoCurrencyStatus): TokenItemState.Subtitle2State? {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ import com.tangem.core.ui.components.token.TokenItem
|
|||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.haptic.TangemHapticEffect
|
||||
import com.tangem.core.ui.res.LocalHapticManager
|
||||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
|
|
@ -78,8 +77,8 @@ internal fun TokenActionsContent(state: TokenActionsUM, modifier: Modifier = Mod
|
|||
|
||||
SecondaryButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResourceSafe(R.string.common_later),
|
||||
onClick = state.onLaterClick,
|
||||
text = state.bottomActionText.resolveReference(),
|
||||
onClick = state.onBottomActionClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -198,7 +197,8 @@ private class TokenActionsContentPreviewProvider : PreviewParameterProvider<Toke
|
|||
onQuickActionLongClick = {},
|
||||
),
|
||||
token = tokenState,
|
||||
onLaterClick = {},
|
||||
bottomActionText = stringReference("Later"),
|
||||
onBottomActionClick = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -1,22 +1,16 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.layoutId
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
|
|
@ -25,32 +19,30 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.compose.ui.util.fastForEach
|
||||
import com.tangem.common.ui.markets.action.QuickActionUM
|
||||
import com.tangem.common.ui.markets.action.QuickActions
|
||||
import com.tangem.common.ui.tokenaction.TokenActionRow
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.ds.badge.*
|
||||
import com.tangem.core.ui.ds.badge.TangemBadge
|
||||
import com.tangem.core.ui.ds.button.SecondaryTangemButton
|
||||
import com.tangem.core.ui.ds.button.TangemButtonShape
|
||||
import com.tangem.core.ui.ds.button.TangemButtonSize
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.ds.row.TangemRowContainer
|
||||
import com.tangem.core.ui.ds.row.TangemRowLayoutId
|
||||
import com.tangem.core.ui.ds.image.DeviceIconUM
|
||||
import com.tangem.core.ui.ds.image.TangemDeviceIcon
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.formatStyled
|
||||
import com.tangem.core.ui.format.bigdecimal.price
|
||||
import com.tangem.core.ui.haptic.TangemHapticEffect
|
||||
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 dev.chrisbanes.haze.rememberHazeState
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import java.math.BigDecimal
|
||||
import java.util.UUID
|
||||
|
||||
private const val ACTION_BACKGROUND_ALPHA = .1f
|
||||
|
||||
@Composable
|
||||
internal fun TokenActionsContentV2(state: TokenActionsUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
|
|
@ -69,10 +61,13 @@ internal fun TokenActionsContentV2(state: TokenActionsUM, modifier: Modifier = M
|
|||
) {
|
||||
state.quickActions.actions.fastForEach { actionUM ->
|
||||
key(actionUM.title) {
|
||||
ActionRow(
|
||||
state = actionUM,
|
||||
TokenActionRow(
|
||||
iconRes = actionUM.icon,
|
||||
title = actionUM.title,
|
||||
description = actionUM.description,
|
||||
onClick = { state.quickActions.onQuickActionClick(actionUM) },
|
||||
onLongClick = { state.quickActions.onQuickActionLongClick(actionUM) },
|
||||
onLongClick = { state.quickActions.onQuickActionLongClick(actionUM) }
|
||||
.takeIf { actionUM.isLongClickAvailable },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -83,8 +78,8 @@ internal fun TokenActionsContentV2(state: TokenActionsUM, modifier: Modifier = M
|
|||
CompositionLocalProvider(LocalHazeState provides rememberHazeState()) {
|
||||
SecondaryTangemButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = state.onLaterClick,
|
||||
text = resourceReference(R.string.common_later),
|
||||
onClick = state.onBottomActionClick,
|
||||
text = state.bottomActionText,
|
||||
size = TangemButtonSize.X12,
|
||||
shape = TangemButtonShape.Rounded,
|
||||
)
|
||||
|
|
@ -92,81 +87,11 @@ internal fun TokenActionsContentV2(state: TokenActionsUM, modifier: Modifier = M
|
|||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun ActionRow(
|
||||
state: QuickActionUM,
|
||||
onClick: () -> Unit,
|
||||
onLongClick: (() -> Unit),
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val hapticManager = LocalHapticManager.current
|
||||
val onLongClickInternal = {
|
||||
hapticManager.perform(TangemHapticEffect.View.LongPress)
|
||||
onLongClick()
|
||||
}
|
||||
|
||||
TangemRowContainer(
|
||||
modifier = modifier
|
||||
.combinedClickable(
|
||||
onLongClick = onLongClickInternal.takeIf { state.isLongClickAvailable },
|
||||
onClick = {
|
||||
hapticManager.perform(TangemHapticEffect.View.SegmentTick)
|
||||
onClick()
|
||||
},
|
||||
)
|
||||
.background(
|
||||
color = TangemTheme.colors2.surface.level3,
|
||||
shape = RoundedCornerShape(TangemTheme.dimens2.x5),
|
||||
),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.layoutId(TangemRowLayoutId.HEAD)
|
||||
.padding(end = TangemTheme.dimens2.x3)
|
||||
.size(40.dp)
|
||||
.background(
|
||||
color = TangemTheme.colors2.graphic.status.accent.copy(alpha = ACTION_BACKGROUND_ALPHA),
|
||||
shape = CircleShape,
|
||||
),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(20.dp),
|
||||
imageVector = ImageVector.vectorResource(id = state.icon),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors2.graphic.status.accent,
|
||||
)
|
||||
}
|
||||
Text(
|
||||
modifier = Modifier.layoutId(TangemRowLayoutId.START_TOP),
|
||||
text = state.title.resolveReference(),
|
||||
style = TangemTheme.typography2.bodyMedium16,
|
||||
color = TangemTheme.colors2.text.neutral.primary,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.layoutId(TangemRowLayoutId.START_BOTTOM),
|
||||
text = state.description.resolveReference(),
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
color = TangemTheme.colors2.text.neutral.secondary,
|
||||
)
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.layoutId(TangemRowLayoutId.TAIL)
|
||||
.padding(start = TangemTheme.dimens2.x2)
|
||||
.size(24.dp),
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_chevron_small_right_24),
|
||||
tint = TangemTheme.colors2.graphic.neutral.tertiary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TokenHeader(
|
||||
addedToken: TokenItemState,
|
||||
isBalanceHidden: Boolean,
|
||||
portfolioBadge: TangemBadgeUM?,
|
||||
portfolioBadge: PortfolioBadgeUM,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
|
|
@ -209,8 +134,38 @@ private fun TokenHeader(
|
|||
|
||||
SpacerH(TangemTheme.dimens2.x7)
|
||||
|
||||
if (portfolioBadge == null) return
|
||||
TangemBadge(portfolioBadge)
|
||||
when (portfolioBadge) {
|
||||
is PortfolioBadgeUM.None -> Unit
|
||||
is PortfolioBadgeUM.Account -> TangemBadge(portfolioBadge.badge)
|
||||
is PortfolioBadgeUM.Wallet -> WalletPortfolioRow(
|
||||
name = portfolioBadge.name,
|
||||
deviceIcon = portfolioBadge.deviceIcon,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WalletPortfolioRow(name: TextReference, deviceIcon: DeviceIconUM, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.heightIn(TangemTheme.dimens2.x6)
|
||||
.clip(RoundedCornerShape(TangemTheme.dimens2.x4))
|
||||
.background(TangemTheme.colors2.markers.backgroundSolidGray)
|
||||
.padding(start = TangemTheme.dimens2.x3, end = TangemTheme.dimens2.x2),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x1),
|
||||
) {
|
||||
Text(
|
||||
text = name.resolveReference(),
|
||||
style = TangemTheme.typography2.captionSemibold12,
|
||||
color = TangemTheme.colors2.markers.textGray,
|
||||
maxLines = 1,
|
||||
)
|
||||
TangemDeviceIcon(
|
||||
state = deviceIcon,
|
||||
modifier = Modifier.size(TangemTheme.dimens2.x4),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -279,16 +234,11 @@ private class TokenActionsContentPreviewProviderV2 : PreviewParameterProvider<To
|
|||
onQuickActionLongClick = {},
|
||||
),
|
||||
token = tokenState,
|
||||
onLaterClick = {},
|
||||
portfolioBadge = TangemBadgeUM(
|
||||
text = stringReference("Wallet 2"),
|
||||
tangemIconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_key_card_20,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.tertiary },
|
||||
),
|
||||
size = TangemBadgeSize.X6,
|
||||
shape = TangemBadgeShape.Rounded,
|
||||
iconPosition = TangemBadgeIconPosition.End,
|
||||
bottomActionText = resourceReference(R.string.common_later),
|
||||
onBottomActionClick = {},
|
||||
portfolioBadge = PortfolioBadgeUM.Wallet(
|
||||
name = stringReference("Wallet 2"),
|
||||
deviceIcon = DeviceIconUM.Stub(cardsCount = 2),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,13 +1,24 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.common.ui.markets.action.QuickActions
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeUM
|
||||
import com.tangem.core.ui.ds.image.DeviceIconUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
internal data class TokenActionsUM(
|
||||
val token: TokenItemState,
|
||||
val quickActions: QuickActions,
|
||||
val onLaterClick: () -> Unit,
|
||||
val bottomActionText: TextReference,
|
||||
val onBottomActionClick: () -> Unit,
|
||||
val isBalancesHidden: Boolean = false,
|
||||
val portfolioBadge: TangemBadgeUM? = null,
|
||||
)
|
||||
val portfolioBadge: PortfolioBadgeUM = PortfolioBadgeUM.None,
|
||||
)
|
||||
|
||||
@Immutable
|
||||
internal sealed interface PortfolioBadgeUM {
|
||||
data class Account(val badge: TangemBadgeUM) : PortfolioBadgeUM
|
||||
data class Wallet(val name: TextReference, val deviceIcon: DeviceIconUM) : PortfolioBadgeUM
|
||||
data object None : PortfolioBadgeUM
|
||||
}
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.userportfolio.state
|
||||
|
||||
import com.tangem.common.ui.userwallet.converter.WalletIconUMConverter
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
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
|
||||
|
|
@ -17,6 +19,8 @@ import kotlinx.coroutines.flow.*
|
|||
internal class UserPortfolioStateController @AssistedInject constructor(
|
||||
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||
private val walletIconUMConverter: WalletIconUMConverter,
|
||||
@Assisted private val modelScope: CoroutineScope,
|
||||
@Assisted private val onTokenSelected: (AddToPortfolioManager.Result) -> Unit,
|
||||
) {
|
||||
|
|
@ -36,6 +40,9 @@ internal class UserPortfolioStateController @AssistedInject constructor(
|
|||
rawCurrencyId = rawCurrencyId,
|
||||
appCurrency = appCurrency,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
resolveWalletDeviceIcon = {
|
||||
walletIconUMConverter.convert(getWalletIconUseCase(it))
|
||||
},
|
||||
onTokenSelected = onTokenSelected,
|
||||
).transform()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.common.ui.components.currency.icon.converter.CryptoCurrencyToI
|
|||
import com.tangem.common.ui.markets.tokenselector.*
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeState
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
import com.tangem.core.ui.ds.image.DeviceIconUM
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
|
|
@ -31,6 +32,7 @@ internal class UserPortfolioSectionsTransformer(
|
|||
private val rawCurrencyId: CryptoCurrency.RawID,
|
||||
private val appCurrency: AppCurrency,
|
||||
private val isBalanceHidden: Boolean,
|
||||
private val resolveWalletDeviceIcon: (UserWallet) -> DeviceIconUM,
|
||||
private val onTokenSelected: (AddToPortfolioManager.Result) -> Unit,
|
||||
) {
|
||||
|
||||
|
|
@ -68,8 +70,12 @@ internal class UserPortfolioSectionsTransformer(
|
|||
|
||||
for ((_, walletEntries) in byWallet) {
|
||||
if (shouldShowWalletHeaders) {
|
||||
val wallet = walletEntries.first().wallet
|
||||
sections.add(
|
||||
TokenSelectorSectionUM.WalletHeader(walletName = walletEntries.first().wallet.name),
|
||||
TokenSelectorSectionUM.WalletHeader(
|
||||
walletName = wallet.name,
|
||||
deviceIcon = resolveWalletDeviceIcon(wallet),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -187,8 +187,8 @@ internal class ChooseTokenListItemConverter(
|
|||
is PaymentAccountStatusValue.UnderReview,
|
||||
PaymentAccountStatusValue.Loading,
|
||||
PaymentAccountStatusValue.Empty,
|
||||
is PaymentAccountStatusValue.Deactivated,
|
||||
-> return null
|
||||
is PaymentAccountStatusValue.Deactivated -> status.cryptoCurrencyStatus
|
||||
is PaymentAccountStatusValue.Loaded -> status.cryptoCurrencyStatus
|
||||
}
|
||||
val account = this.account
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ package com.tangem.features.commonfeatures.impl.portfolioselector
|
|||
|
||||
import com.tangem.common.ui.account.AccountPortfolioItemUMConverter
|
||||
import com.tangem.common.ui.userwallet.converter.UserWalletItemUMConverter
|
||||
import com.tangem.common.ui.userwallet.converter.WalletIconUMConverter
|
||||
import com.tangem.common.ui.userwallet.state.UserWalletItemUM
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.ui.ds.image.DeviceIconUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
|
|
@ -15,6 +17,7 @@ import com.tangem.domain.models.account.AccountStatus
|
|||
import com.tangem.domain.models.account.filterCryptoPortfolio
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.GetWalletIconUseCase
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioFetcher
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorComponent
|
||||
import com.tangem.features.commonfeatures.impl.R
|
||||
|
|
@ -33,6 +36,8 @@ internal class PortfolioSelectorModel @Inject constructor(
|
|||
paramsContainer: ParamsContainer,
|
||||
walletImageFetcher: UserWalletImageFetcher,
|
||||
isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||
private val walletIconUMConverter: WalletIconUMConverter,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
) : Model() {
|
||||
|
||||
|
|
@ -173,6 +178,7 @@ internal class PortfolioSelectorModel @Inject constructor(
|
|||
val walletTitle = PortfolioSelectorItemUM.GroupTitle(
|
||||
id = "GroupTitle ${wallet.walletId.stringValue}",
|
||||
name = stringReference(wallet.name),
|
||||
deviceIcon = walletIconUMConverter.convert(getWalletIconUseCase(wallet)),
|
||||
)
|
||||
|
||||
add(walletTitle)
|
||||
|
|
@ -204,6 +210,7 @@ internal class PortfolioSelectorModel @Inject constructor(
|
|||
val lockedWalletsTitle = PortfolioSelectorItemUM.GroupTitle(
|
||||
id = "lockedWalletsTitleId",
|
||||
name = resourceReference(R.string.common_locked_wallets),
|
||||
deviceIcon = DeviceIconUM.Stub(cardsCount = 1),
|
||||
)
|
||||
|
||||
return listOf(lockedWalletsTitle) + wallets
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.features.commonfeatures.impl.portfolioselector.entity
|
|||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.common.ui.userwallet.state.UserWalletItemUM
|
||||
import com.tangem.core.ui.ds.image.DeviceIconUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
|
|
@ -17,6 +18,7 @@ sealed interface PortfolioSelectorItemUM {
|
|||
data class GroupTitle(
|
||||
override val id: String,
|
||||
val name: TextReference,
|
||||
val deviceIcon: DeviceIconUM,
|
||||
) : PortfolioSelectorItemUM
|
||||
|
||||
data class Portfolio(
|
||||
|
|
|
|||
|
|
@ -11,9 +11,11 @@ import androidx.compose.foundation.layout.heightIn
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
|
|
@ -26,10 +28,12 @@ import com.tangem.common.ui.account.AccountIconPreviewData
|
|||
import com.tangem.common.ui.userwallet.UserWalletItemRow
|
||||
import com.tangem.common.ui.userwallet.state.UserWalletItemUM
|
||||
import com.tangem.common.ui.userwallet.state.UserWalletItemUM.ImageState
|
||||
import com.tangem.core.ui.ds.image.DeviceIconUM
|
||||
import com.tangem.core.ui.extensions.conditional
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.LocalCanScrollBackward
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.commonfeatures.impl.R
|
||||
|
|
@ -46,51 +50,59 @@ internal fun PortfolioSelectorContent(
|
|||
modifier: Modifier = Modifier,
|
||||
contentPadding: PaddingValues = PaddingValues(),
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = modifier,
|
||||
contentPadding = contentPadding,
|
||||
val lazyListState = rememberLazyListState()
|
||||
|
||||
CompositionLocalProvider(
|
||||
LocalCanScrollBackward provides
|
||||
lazyListState.canScrollBackward,
|
||||
) {
|
||||
val items = state.items
|
||||
itemsIndexed(
|
||||
items = items,
|
||||
key = { _, item -> item.id },
|
||||
) { index, item ->
|
||||
val previewItem = items.getOrNull(index.dec())
|
||||
val offsetModifier = when {
|
||||
previewItem == null -> Modifier
|
||||
item is PortfolioSelectorItemUM.GroupTitle -> Modifier.padding(
|
||||
top = TangemTheme.dimens.spacing16,
|
||||
)
|
||||
else -> Modifier.padding(
|
||||
top = TangemTheme.dimens.spacing8,
|
||||
)
|
||||
}
|
||||
LazyColumn(
|
||||
state = lazyListState,
|
||||
modifier = modifier,
|
||||
contentPadding = contentPadding,
|
||||
) {
|
||||
val items = state.items
|
||||
itemsIndexed(
|
||||
items = items,
|
||||
key = { _, item -> item.id },
|
||||
) { index, item ->
|
||||
val previewItem = items.getOrNull(index.dec())
|
||||
val offsetModifier = when {
|
||||
previewItem == null -> Modifier
|
||||
item is PortfolioSelectorItemUM.GroupTitle -> Modifier.padding(
|
||||
top = TangemTheme.dimens.spacing16,
|
||||
)
|
||||
else -> Modifier.padding(
|
||||
top = TangemTheme.dimens.spacing8,
|
||||
)
|
||||
}
|
||||
|
||||
val portfolioShape = RoundedCornerShape(TangemTheme.dimens.radius14)
|
||||
val border = BorderStroke(
|
||||
width = 1.dp,
|
||||
color = TangemTheme.colors.text.accent,
|
||||
)
|
||||
val portfolioShape = RoundedCornerShape(TangemTheme.dimens.radius14)
|
||||
val border = BorderStroke(
|
||||
width = 1.dp,
|
||||
color = TangemTheme.colors.text.accent,
|
||||
)
|
||||
|
||||
when (item) {
|
||||
is PortfolioSelectorItemUM.Portfolio -> UserWalletItemRow(
|
||||
state = item.item,
|
||||
modifier = offsetModifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = TangemTheme.dimens.size68)
|
||||
.clip(portfolioShape)
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.conditional(item.isSelected) { border(border, portfolioShape) }
|
||||
.clickable(enabled = item.item.isEnabled, onClick = item.item.onClick)
|
||||
.padding(all = TangemTheme.dimens.spacing12)
|
||||
.conditional(!item.item.isEnabled) { alpha(DISABLED_WALLET_ALPHA) },
|
||||
)
|
||||
is PortfolioSelectorItemUM.GroupTitle -> WalletNameRow(
|
||||
model = item,
|
||||
modifier = offsetModifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
)
|
||||
when (item) {
|
||||
is PortfolioSelectorItemUM.Portfolio -> UserWalletItemRow(
|
||||
state = item.item,
|
||||
modifier = offsetModifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = TangemTheme.dimens.size68)
|
||||
.clip(portfolioShape)
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.conditional(item.isSelected) { border(border, portfolioShape) }
|
||||
.clickable(enabled = item.item.isEnabled, onClick = item.item.onClick)
|
||||
.padding(all = TangemTheme.dimens.spacing12)
|
||||
.conditional(!item.item.isEnabled) { alpha(DISABLED_WALLET_ALPHA) },
|
||||
)
|
||||
is PortfolioSelectorItemUM.GroupTitle -> WalletNameRow(
|
||||
model = item,
|
||||
modifier = offsetModifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -161,12 +173,14 @@ internal object PortfolioSelectorPreviewData {
|
|||
PortfolioSelectorItemUM.GroupTitle(
|
||||
id = UUID.randomUUID().toString(),
|
||||
name = stringReference("Tangem 2.0"),
|
||||
deviceIcon = DeviceIconUM.Stub(cardsCount = 2),
|
||||
),
|
||||
PortfolioSelectorItemUM.Portfolio(accountItem, false),
|
||||
PortfolioSelectorItemUM.Portfolio(lockedAccountItem, false),
|
||||
PortfolioSelectorItemUM.GroupTitle(
|
||||
id = UUID.randomUUID().toString(),
|
||||
name = stringReference("Tangem White"),
|
||||
deviceIcon = DeviceIconUM.Stub(cardsCount = 1),
|
||||
),
|
||||
PortfolioSelectorItemUM.Portfolio(accountItem, true),
|
||||
)
|
||||
|
|
@ -176,6 +190,7 @@ internal object PortfolioSelectorPreviewData {
|
|||
PortfolioSelectorItemUM.GroupTitle(
|
||||
id = UUID.randomUUID().toString(),
|
||||
name = resourceReference(R.string.common_locked_wallets),
|
||||
deviceIcon = DeviceIconUM.Stub(cardsCount = 1),
|
||||
),
|
||||
PortfolioSelectorItemUM.Portfolio(lockedWalletItem, false),
|
||||
PortfolioSelectorItemUM.Portfolio(lockedWalletItem, false),
|
||||
|
|
@ -193,6 +208,7 @@ internal object PortfolioSelectorPreviewData {
|
|||
PortfolioSelectorItemUM.GroupTitle(
|
||||
id = UUID.randomUUID().toString(),
|
||||
name = resourceReference(R.string.common_locked_wallets),
|
||||
deviceIcon = DeviceIconUM.Stub(cardsCount = 1),
|
||||
),
|
||||
PortfolioSelectorItemUM.Portfolio(lockedWalletItem, false),
|
||||
PortfolioSelectorItemUM.Portfolio(lockedWalletItem, false),
|
||||
|
|
|
|||
|
|
@ -7,16 +7,14 @@ import androidx.compose.foundation.clickable
|
|||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.layoutId
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
|
|
@ -25,14 +23,15 @@ import com.tangem.common.ui.userwallet.CardImage
|
|||
import com.tangem.common.ui.userwallet.getBalanceValueAndFlickerState
|
||||
import com.tangem.common.ui.userwallet.getInformationValue
|
||||
import com.tangem.common.ui.userwallet.state.UserWalletItemUM
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.TextShimmer
|
||||
import com.tangem.core.ui.components.text.applyBladeBrush
|
||||
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
|
||||
import com.tangem.core.ui.ds.image.TangemDeviceIcon
|
||||
import com.tangem.core.ui.ds.row.TangemRowContainer
|
||||
import com.tangem.core.ui.ds.row.TangemRowLayoutId
|
||||
import com.tangem.core.ui.extensions.conditional
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.LocalCanScrollBackward
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
|
@ -48,20 +47,41 @@ internal fun PortfolioSelectorContentV2(
|
|||
modifier: Modifier = Modifier,
|
||||
contentPadding: PaddingValues = PaddingValues(),
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = modifier,
|
||||
contentPadding = contentPadding,
|
||||
val lazyListState = rememberLazyListState()
|
||||
|
||||
CompositionLocalProvider(
|
||||
LocalCanScrollBackward provides
|
||||
lazyListState.canScrollBackward,
|
||||
) {
|
||||
val items = state.items
|
||||
itemsIndexed(
|
||||
items = items,
|
||||
key = { _, item -> item.id },
|
||||
) { index, item ->
|
||||
when (item) {
|
||||
is PortfolioSelectorItemUM.Portfolio ->
|
||||
PortfolioSelectorItem(
|
||||
state = item.item,
|
||||
LazyColumn(
|
||||
state = lazyListState,
|
||||
modifier = modifier,
|
||||
contentPadding = contentPadding,
|
||||
) {
|
||||
val items = state.items
|
||||
itemsIndexed(
|
||||
items = items,
|
||||
key = { _, item -> item.id },
|
||||
) { index, item ->
|
||||
when (item) {
|
||||
is PortfolioSelectorItemUM.Portfolio ->
|
||||
PortfolioSelectorItem(
|
||||
state = item.item,
|
||||
modifier = Modifier
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = index,
|
||||
lastIndex = state.items.lastIndex,
|
||||
backgroundColor = TangemTheme.colors2.surface.level3,
|
||||
radius = TangemTheme.dimens2.x5,
|
||||
addDefaultPadding = false,
|
||||
)
|
||||
.clickable(enabled = item.item.isEnabled, onClick = item.item.onClick)
|
||||
.conditional(!item.item.isEnabled) { alpha(DISABLED_WALLET_ALPHA) },
|
||||
)
|
||||
is PortfolioSelectorItemUM.GroupTitle -> WalletNameRow(
|
||||
model = item,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = index,
|
||||
lastIndex = state.items.lastIndex,
|
||||
|
|
@ -69,22 +89,9 @@ internal fun PortfolioSelectorContentV2(
|
|||
radius = TangemTheme.dimens2.x5,
|
||||
addDefaultPadding = false,
|
||||
)
|
||||
.clickable(enabled = item.item.isEnabled, onClick = item.item.onClick)
|
||||
.conditional(!item.item.isEnabled) { alpha(DISABLED_WALLET_ALPHA) },
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
)
|
||||
is PortfolioSelectorItemUM.GroupTitle -> WalletNameRow(
|
||||
model = item,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = index,
|
||||
lastIndex = state.items.lastIndex,
|
||||
backgroundColor = TangemTheme.colors2.surface.level3,
|
||||
radius = TangemTheme.dimens2.x5,
|
||||
addDefaultPadding = false,
|
||||
)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -197,13 +204,11 @@ private fun WalletNameRow(model: PortfolioSelectorItemUM.GroupTitle, modifier: M
|
|||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_key_card_20),
|
||||
TangemDeviceIcon(
|
||||
state = model.deviceIcon,
|
||||
modifier = Modifier
|
||||
.align(Alignment.Bottom)
|
||||
.size(TangemTheme.dimens2.x5),
|
||||
tint = TangemTheme.colors2.graphic.neutral.tertiary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue