Updated on 2026-08-14
This commit is contained in:
commit
ca49abf2b1
892 changed files with 17979 additions and 6555 deletions
|
|
@ -5,6 +5,7 @@ import androidx.compose.ui.Modifier
|
|||
import com.tangem.core.decompose.navigation.DummyRouter
|
||||
import com.tangem.core.navigation.url.DummyUrlOpener
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.details.component.DetailsComponent
|
||||
import com.tangem.features.details.entity.DetailsFooterUM
|
||||
import com.tangem.features.details.entity.DetailsUM
|
||||
|
|
@ -18,7 +19,12 @@ internal class PreviewDetailsComponent : DetailsComponent {
|
|||
private val previewBlocks = runBlocking {
|
||||
ItemsBuilder(
|
||||
router = DummyRouter(),
|
||||
).buildAll(isWalletConnectAvailable = true, onSupportClick = {}, onBuyClick = {})
|
||||
).buildAll(
|
||||
isWalletConnectAvailable = true,
|
||||
userWalletId = UserWalletId(""),
|
||||
onSupportClick = {},
|
||||
onBuyClick = {},
|
||||
)
|
||||
}
|
||||
|
||||
private val previewFooter = DetailsFooterUM(
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ internal class DetailsModel @Inject constructor(
|
|||
items = MutableStateFlow(
|
||||
itemsBuilder.buildAll(
|
||||
isWalletConnectAvailable = isWalletConnectAvailable,
|
||||
userWalletId = params.userWalletId,
|
||||
onSupportClick = ::sendFeedback,
|
||||
onBuyClick = ::onBuyClick,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.core.decompose.navigation.Router
|
|||
import com.tangem.core.ui.components.block.model.BlockUM
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.details.entity.DetailsItemUM
|
||||
import com.tangem.features.details.impl.BuildConfig
|
||||
import com.tangem.features.details.impl.R
|
||||
|
|
@ -19,20 +20,21 @@ internal class ItemsBuilder @Inject constructor(private val router: Router) {
|
|||
|
||||
fun buildAll(
|
||||
isWalletConnectAvailable: Boolean,
|
||||
userWalletId: UserWalletId,
|
||||
onSupportClick: () -> Unit,
|
||||
onBuyClick: () -> Unit,
|
||||
): ImmutableList<DetailsItemUM> = buildList {
|
||||
buildWalletConnectBlock(isWalletConnectAvailable)?.let(::add)
|
||||
buildWalletConnectBlock(isWalletConnectAvailable, userWalletId)?.let(::add)
|
||||
buildUserWalletListBlock().let(::add)
|
||||
buildShopBlock(onBuyClick).let(::add)
|
||||
buildSettingsBlock().let(::add)
|
||||
buildSupportBlock(onSupportClick).let(::add)
|
||||
}.toImmutableList()
|
||||
|
||||
private fun buildWalletConnectBlock(isWalletConnectAvailable: Boolean): DetailsItemUM? {
|
||||
private fun buildWalletConnectBlock(isWalletConnectAvailable: Boolean, userWalletId: UserWalletId): DetailsItemUM? {
|
||||
return if (isWalletConnectAvailable) {
|
||||
DetailsItemUM.WalletConnect(
|
||||
onClick = { router.push(AppRoute.WalletConnectSessions) },
|
||||
onClick = { router.push(AppRoute.WalletConnectSessions(userWalletId)) },
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import com.tangem.core.decompose.context.AppComponentContext
|
|||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.features.managetokens.analytics.CustomTokenAnalyticsEvent
|
||||
import com.tangem.features.managetokens.component.AddCustomTokenComponent
|
||||
import com.tangem.features.managetokens.component.CustomTokenFormComponent
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import com.tangem.core.decompose.context.AppComponentContext
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.managetokens.ValidateDerivationPathUseCase
|
||||
import com.tangem.domain.managetokens.model.exceptoin.DerivationPathValidationException
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.features.managetokens.component.CustomTokenDerivationInputComponent
|
||||
import com.tangem.features.managetokens.entity.customtoken.CustomDerivationInputUM
|
||||
import com.tangem.features.managetokens.entity.customtoken.SelectedDerivationPath
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.features.managetokens.component.preview
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.managetokens.component.CustomTokenSelectorComponent
|
||||
import com.tangem.features.managetokens.component.CustomTokenSelectorComponent.Params
|
||||
|
|
@ -26,17 +26,19 @@ internal class PreviewCustomTokenSelectorComponent(
|
|||
) : CustomTokenSelectorComponent {
|
||||
|
||||
private val previewItems = List(size = itemsSize) { index ->
|
||||
val derivationPath = Network.DerivationPath.Card("m/44'/0'/0'/0/$index")
|
||||
|
||||
when (params) {
|
||||
is Params.DerivationPathSelector -> {
|
||||
val d = SelectedDerivationPath(
|
||||
id = Network.ID(index.toString()),
|
||||
value = Network.DerivationPath.Card("m/44'/0'/0'/0/$index"),
|
||||
id = Network.ID(value = index.toString(), derivationPath = derivationPath),
|
||||
value = derivationPath,
|
||||
name = "Network $index",
|
||||
isDefault = false,
|
||||
)
|
||||
|
||||
DerivationPathUM(
|
||||
id = d.id?.value ?: "",
|
||||
id = d.id?.rawId?.value ?: "",
|
||||
value = d.value.value.orEmpty(),
|
||||
networkName = stringReference(d.name),
|
||||
isSelected = d.value == params.selectedDerivationPath?.value,
|
||||
|
|
@ -45,16 +47,16 @@ internal class PreviewCustomTokenSelectorComponent(
|
|||
}
|
||||
is Params.NetworkSelector -> {
|
||||
val n = SelectedNetwork(
|
||||
id = Network.ID(index.toString()),
|
||||
id = Network.ID(value = index.toString(), derivationPath = derivationPath),
|
||||
name = "Network $index",
|
||||
derivationPath = Network.DerivationPath.Card("m/44'/0'/0'/0/$index"),
|
||||
derivationPath = derivationPath,
|
||||
canHandleTokens = false,
|
||||
)
|
||||
|
||||
CurrencyNetworkUM(
|
||||
network = Network(
|
||||
id = n.id,
|
||||
backendId = n.id.value,
|
||||
backendId = n.id.rawId.value,
|
||||
name = "Network $index",
|
||||
currencySymbol = "N$index",
|
||||
derivationPath = Network.DerivationPath.Card(""),
|
||||
|
|
@ -76,7 +78,7 @@ internal class PreviewCustomTokenSelectorComponent(
|
|||
}
|
||||
}.toImmutableList()
|
||||
|
||||
val previewState = CustomTokenSelectorUM(
|
||||
private val previewState = CustomTokenSelectorUM(
|
||||
header = when (params) {
|
||||
is Params.DerivationPathSelector -> CustomTokenSelectorUM.HeaderUM.CustomDerivationButton(
|
||||
value = null,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
|||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.features.managetokens.component.ManageTokensComponent
|
||||
import com.tangem.features.managetokens.entity.item.CurrencyItemUM
|
||||
import com.tangem.features.managetokens.entity.item.CurrencyNetworkUM
|
||||
|
|
@ -27,7 +27,7 @@ import kotlinx.coroutines.flow.update
|
|||
|
||||
internal class PreviewManageTokensComponent(
|
||||
private val isLoading: Boolean,
|
||||
private val showTangemIcon: Boolean,
|
||||
showTangemIcon: Boolean,
|
||||
params: ManageTokensComponent.Params,
|
||||
) : ManageTokensComponent {
|
||||
|
||||
|
|
@ -150,13 +150,14 @@ internal class PreviewManageTokensComponent(
|
|||
)
|
||||
|
||||
private fun getCurrencyNetworks(currencyIndex: Int) = List(size = 3) { networkIndex ->
|
||||
val derivationPath = Network.DerivationPath.Card("")
|
||||
CurrencyNetworkUM(
|
||||
network = Network(
|
||||
id = Network.ID(networkIndex.toString()),
|
||||
id = Network.ID(value = networkIndex.toString(), derivationPath = derivationPath),
|
||||
backendId = networkIndex.toString(),
|
||||
name = "Network $networkIndex",
|
||||
currencySymbol = "N$networkIndex",
|
||||
derivationPath = Network.DerivationPath.Card(""),
|
||||
derivationPath = derivationPath,
|
||||
isTestnet = false,
|
||||
standardType = Network.StandardType.ERC20,
|
||||
hasFiatFeeRate = false,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
|||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.features.managetokens.component.OnboardingManageTokensComponent
|
||||
import com.tangem.features.managetokens.entity.item.CurrencyItemUM
|
||||
import com.tangem.features.managetokens.entity.item.CurrencyNetworkUM
|
||||
|
|
@ -90,13 +90,15 @@ internal class PreviewOnboardingManageTokensComponent(
|
|||
)
|
||||
|
||||
private fun getCurrencyNetworks() = List(size = 3) { networkIndex ->
|
||||
val derivationPath = Network.DerivationPath.Card("")
|
||||
|
||||
CurrencyNetworkUM(
|
||||
network = Network(
|
||||
id = Network.ID(networkIndex.toString()),
|
||||
id = Network.ID(value = networkIndex.toString(), derivationPath = derivationPath),
|
||||
backendId = networkIndex.toString(),
|
||||
name = "Network $networkIndex",
|
||||
currencySymbol = "N$networkIndex",
|
||||
derivationPath = Network.DerivationPath.Card(""),
|
||||
derivationPath = derivationPath,
|
||||
isTestnet = false,
|
||||
standardType = Network.StandardType.ERC20,
|
||||
hasFiatFeeRate = false,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.features.managetokens.entity.customtoken
|
||||
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.features.managetokens.entity.item
|
||||
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.models.network.Network
|
||||
|
||||
internal data class CurrencyNetworkUM(
|
||||
val network: Network,
|
||||
|
|
@ -13,5 +13,5 @@ internal data class CurrencyNetworkUM(
|
|||
override val onSelectedStateChange: (Boolean) -> Unit,
|
||||
) : SelectableItemUM {
|
||||
|
||||
override val id: String = network.id.value
|
||||
override val id: String = network.rawId
|
||||
}
|
||||
|
|
@ -12,9 +12,9 @@ import com.tangem.core.ui.message.DialogMessage
|
|||
import com.tangem.domain.card.DerivePublicKeysUseCase
|
||||
import com.tangem.domain.card.HasMissedDerivationsUseCase
|
||||
import com.tangem.domain.managetokens.model.exceptoin.CustomTokenFormValidationException
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.features.managetokens.analytics.CustomTokenAnalyticsEvent
|
||||
import com.tangem.features.managetokens.component.CustomTokenFormComponent
|
||||
import com.tangem.features.managetokens.entity.customtoken.ClickableFieldUM
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import com.tangem.core.decompose.ui.UiMessageSender
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.domain.managetokens.GetSupportedNetworksUseCase
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.managetokens.component.CustomTokenSelectorComponent
|
||||
import com.tangem.features.managetokens.component.CustomTokenSelectorComponent.Params.DerivationPathSelector
|
||||
|
|
|
|||
|
|
@ -12,11 +12,11 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
|||
import com.tangem.core.ui.components.appbar.TangemTopAppBar
|
||||
import com.tangem.core.ui.components.appbar.TangemTopAppBarHeight
|
||||
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
|
||||
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.managetokens.component.AddCustomTokenComponent
|
||||
import com.tangem.features.managetokens.component.preview.PreviewAddCustomTokenComponent
|
||||
|
|
@ -76,7 +76,7 @@ private class AddCustomTokenComponentPreviewProvider : PreviewParameterProvider<
|
|||
userWalletId = UserWalletId(stringValue = "321"),
|
||||
step = AddCustomTokenConfig.Step.FORM,
|
||||
selectedNetwork = SelectedNetwork(
|
||||
id = Network.ID(value = "1"),
|
||||
id = Network.ID(value = "1", derivationPath = Network.DerivationPath.None),
|
||||
name = "Ethereum",
|
||||
derivationPath = Network.DerivationPath.None,
|
||||
canHandleTokens = false,
|
||||
|
|
@ -88,7 +88,7 @@ private class AddCustomTokenComponentPreviewProvider : PreviewParameterProvider<
|
|||
userWalletId = UserWalletId(stringValue = "321"),
|
||||
step = AddCustomTokenConfig.Step.NETWORK_SELECTOR,
|
||||
selectedNetwork = SelectedNetwork(
|
||||
id = Network.ID(value = "0"),
|
||||
id = Network.ID(value = "0", derivationPath = Network.DerivationPath.None),
|
||||
name = "Ethereum",
|
||||
derivationPath = Network.DerivationPath.None,
|
||||
canHandleTokens = false,
|
||||
|
|
@ -100,7 +100,7 @@ private class AddCustomTokenComponentPreviewProvider : PreviewParameterProvider<
|
|||
userWalletId = UserWalletId(stringValue = "321"),
|
||||
step = AddCustomTokenConfig.Step.DERIVATION_PATH_SELECTOR,
|
||||
selectedDerivationPath = SelectedDerivationPath(
|
||||
id = Network.ID(value = "0"),
|
||||
id = Network.ID(value = "0", derivationPath = Network.DerivationPath.None),
|
||||
value = Network.DerivationPath.None,
|
||||
name = "Ethereum",
|
||||
isDefault = false,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import com.tangem.core.ui.extensions.resolveReference
|
|||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.managetokens.component.CustomTokenSelectorComponent
|
||||
import com.tangem.features.managetokens.component.preview.PreviewCustomTokenSelectorComponent
|
||||
|
|
@ -266,20 +266,23 @@ private fun Preview_CustomTokenNetworkSelectorContent(
|
|||
|
||||
private class CustomTokenNetworkSelectorComponentPreviewProvider :
|
||||
PreviewParameterProvider<CustomTokenSelectorComponent> {
|
||||
|
||||
private val derivationPath = Network.DerivationPath.Card("m/44'/0'/0'/0/0")
|
||||
|
||||
override val values: Sequence<CustomTokenSelectorComponent>
|
||||
get() = sequenceOf(
|
||||
PreviewCustomTokenSelectorComponent(
|
||||
params = CustomTokenSelectorComponent.Params.DerivationPathSelector(
|
||||
userWalletId = UserWalletId(stringValue = "321"),
|
||||
selectedNetwork = SelectedNetwork(
|
||||
id = Network.ID(value = "0"),
|
||||
id = Network.ID(value = "0", derivationPath = derivationPath),
|
||||
name = "Ethereum",
|
||||
derivationPath = Network.DerivationPath.Card("m/44'/0'/0'/0/0"),
|
||||
derivationPath = derivationPath,
|
||||
canHandleTokens = true,
|
||||
),
|
||||
selectedDerivationPath = SelectedDerivationPath(
|
||||
id = Network.ID(value = "0"),
|
||||
value = Network.DerivationPath.Card("m/44'/0'/0'/0/0"),
|
||||
id = Network.ID(value = "0", derivationPath = derivationPath),
|
||||
value = derivationPath,
|
||||
name = "",
|
||||
isDefault = false,
|
||||
),
|
||||
|
|
@ -290,9 +293,9 @@ private class CustomTokenNetworkSelectorComponentPreviewProvider :
|
|||
params = CustomTokenSelectorComponent.Params.NetworkSelector(
|
||||
userWalletId = UserWalletId(stringValue = "321"),
|
||||
selectedNetwork = SelectedNetwork(
|
||||
id = Network.ID(value = "0"),
|
||||
id = Network.ID(value = "0", derivationPath = derivationPath),
|
||||
name = "Ethereum",
|
||||
derivationPath = Network.DerivationPath.Card("m/44'/0'/0'/0/0"),
|
||||
derivationPath = derivationPath,
|
||||
canHandleTokens = true,
|
||||
),
|
||||
onNetworkSelected = {},
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import com.tangem.domain.managetokens.ValidateTokenFormUseCase
|
|||
import com.tangem.domain.managetokens.model.AddCustomTokenForm
|
||||
import com.tangem.domain.managetokens.model.exceptoin.CustomTokenFormValidationException
|
||||
import com.tangem.domain.managetokens.model.exceptoin.FindTokenException
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveInAndJoin
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.features.managetokens.utils.list
|
||||
|
||||
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.models.network.Network
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import com.tangem.core.ui.extensions.stringReference
|
|||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.domain.managetokens.*
|
||||
import com.tangem.domain.managetokens.model.*
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.managetokens.analytics.ManageTokensAnalyticEvent
|
||||
import com.tangem.features.managetokens.component.ManageTokensSource
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package com.tangem.features.managetokens.utils.list
|
|||
|
||||
import com.tangem.domain.managetokens.model.CurrencyUnsupportedState
|
||||
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
internal interface ManageTokensUiActions {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import com.tangem.core.ui.message.EventMessageAction
|
|||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.domain.managetokens.model.CurrencyUnsupportedState
|
||||
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.features.managetokens.component.ManageTokensSource
|
||||
import com.tangem.features.managetokens.entity.item.CurrencyItemUM
|
||||
import com.tangem.features.managetokens.impl.R
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package com.tangem.features.managetokens.utils.mapper
|
|||
|
||||
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
|
||||
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency.SourceNetwork
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.features.managetokens.entity.item.CurrencyItemUM.Basic.NetworksUM
|
||||
import com.tangem.features.managetokens.entity.item.CurrencyNetworkUM
|
||||
import com.tangem.features.managetokens.utils.ui.getIconRes
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package com.tangem.features.managetokens.utils.mapper
|
|||
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.features.managetokens.entity.customtoken.SelectedNetwork
|
||||
import com.tangem.features.managetokens.entity.item.DerivationPathUM
|
||||
import com.tangem.features.managetokens.impl.R
|
||||
|
|
@ -12,7 +12,7 @@ internal fun Network.toDerivationPathModel(
|
|||
onSelectedStateChange: (Boolean) -> Unit,
|
||||
): DerivationPathUM? {
|
||||
return DerivationPathUM(
|
||||
id = id.value,
|
||||
id = rawId,
|
||||
value = derivationPath.value ?: return null,
|
||||
networkName = stringReference(name),
|
||||
isSelected = isSelected,
|
||||
|
|
@ -25,7 +25,7 @@ internal fun SelectedNetwork.toDerivationPathModel(
|
|||
onSelectedStateChange: (Boolean) -> Unit,
|
||||
): DerivationPathUM? {
|
||||
return DerivationPathUM(
|
||||
id = id.value,
|
||||
id = id.rawId.value,
|
||||
value = derivationPath.value ?: return null,
|
||||
networkName = resourceReference(R.string.custom_token_derivation_path_default),
|
||||
isSelected = isSelected,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.features.managetokens.utils.ui
|
|||
import androidx.annotation.DrawableRes
|
||||
import com.tangem.core.ui.extensions.getActiveIconRes
|
||||
import com.tangem.core.ui.extensions.getGreyedOutIconRes
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.features.managetokens.entity.item.CurrencyNetworkUM
|
||||
|
||||
internal fun CurrencyNetworkUM.select(isSelected: Boolean): CurrencyNetworkUM {
|
||||
|
|
@ -15,7 +15,7 @@ internal fun CurrencyNetworkUM.select(isSelected: Boolean): CurrencyNetworkUM {
|
|||
|
||||
@DrawableRes
|
||||
internal fun Network.ID.getIconRes(isColored: Boolean): Int = if (isColored) {
|
||||
getActiveIconRes(value)
|
||||
getActiveIconRes(rawId.value)
|
||||
} else {
|
||||
getGreyedOutIconRes(value)
|
||||
getGreyedOutIconRes(rawId.value)
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ import com.tangem.core.ui.extensions.resourceReference
|
|||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.domain.managetokens.ValidateTokenFormUseCase
|
||||
import com.tangem.domain.managetokens.model.exceptoin.CustomTokenFormValidationException
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.managetokens.entity.customtoken.CustomTokenFormUM
|
||||
import com.tangem.features.managetokens.entity.customtoken.CustomTokenFormUM.TokenFormUM.Field
|
||||
import com.tangem.features.managetokens.impl.R
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.features.markets.token.block
|
|||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Stable
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import com.tangem.core.decompose.context.child
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.res.LocalMainBottomSheetColor
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.markets.details.MarketsTokenDetailsComponent
|
||||
import com.tangem.features.markets.details.MarketsTokenDetailsComponent.Params
|
||||
import com.tangem.features.markets.details.impl.analytics.MarketDetailsAnalyticsEvent
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
|||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.core.lce.Lce
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.tokens.GetAllWalletsCryptoCurrencyStatusesUseCase
|
||||
import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase
|
||||
import com.tangem.domain.tokens.GetWalletTotalBalanceUseCase
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.TotalFiatBalance
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ import com.tangem.core.ui.message.DialogMessage
|
|||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.onramp.model.OnrampSource
|
||||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.domain.tokens.legacy.TradeCryptoAction
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.tokens.model.TokenActionsState
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.features.markets.impl.R
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ import com.tangem.domain.appcurrency.model.AppCurrency
|
|||
import com.tangem.domain.markets.GetMarketsTokenListFlowUseCase
|
||||
import com.tangem.domain.markets.GetStakingNotificationMaxApyUseCase
|
||||
import com.tangem.domain.markets.TokenMarket
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.promo.PromoRepository
|
||||
import com.tangem.domain.settings.usercountry.GetUserCountryUseCase
|
||||
import com.tangem.domain.settings.usercountry.models.UserCountry
|
||||
import com.tangem.domain.settings.usercountry.models.UserCountryError
|
||||
import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.features.markets.entry.BottomSheetState
|
||||
import com.tangem.features.markets.tokenlist.impl.analytics.MarketsListAnalyticsEvent
|
||||
import com.tangem.features.markets.tokenlist.impl.model.statemanager.MarketsListBatchFlowManager
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package com.tangem.features.markets.tokenlist.impl.model.statemanager
|
|||
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.markets.*
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.markets.tokenlist.impl.model.converters.MarketsTokenItemConverter
|
||||
import com.tangem.features.markets.tokenlist.impl.model.utils.logAction
|
||||
import com.tangem.features.markets.tokenlist.impl.model.utils.logStatus
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
|||
import com.tangem.core.ui.event.consumedEvent
|
||||
import com.tangem.core.ui.event.triggeredEvent
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.markets.impl.R
|
||||
import com.tangem.features.markets.tokenlist.impl.ui.state.*
|
||||
import com.tangem.utils.Provider
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ import com.tangem.core.ui.format.bigdecimal.percent
|
|||
import com.tangem.core.ui.res.LocalMainBottomSheetColor
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.markets.entry.BottomSheetState
|
||||
import com.tangem.features.markets.impl.R
|
||||
import com.tangem.features.markets.tokenlist.impl.ui.components.MarketsListLazyColumn
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import com.tangem.core.ui.event.EventEffect
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.markets.impl.R
|
||||
import com.tangem.features.markets.tokenlist.impl.ui.state.ListUM
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
@file:Suppress("MagicNumber")
|
||||
|
||||
package com.tangem.features.markets.tokenlist.impl.ui.preview
|
||||
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.common.ui.charts.state.MarketChartRawData
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.markets.tokenlist.impl.ui.state.MarketsListItemUM
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import com.tangem.common.ui.charts.state.MarketChartLook
|
|||
import com.tangem.common.ui.charts.state.MarketChartRawData
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
|
||||
@Immutable
|
||||
data class MarketsListItemUM(
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
|||
import com.tangem.core.ui.event.StateEvent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.markets.impl.R
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import java.math.BigDecimal
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.features.nft.entity
|
||||
|
||||
/**
|
||||
* Trigger on success nft send
|
||||
*/
|
||||
interface NFTSendSuccessTrigger {
|
||||
suspend fun triggerSuccessNFTSend()
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@ dependencies {
|
|||
|
||||
/** Domain modules */
|
||||
implementation(projects.domain.appCurrency.models)
|
||||
implementation(projects.domain.appCurrency)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.nft)
|
||||
implementation(projects.domain.nft.models)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import com.tangem.core.ui.extensions.TextReference
|
|||
|
||||
internal data class NFTCollectionUM(
|
||||
val id: String,
|
||||
val name: String?,
|
||||
val name: String,
|
||||
@DrawableRes val networkIconId: Int,
|
||||
val logoUrl: String?,
|
||||
val description: TextReference,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
package com.tangem.features.nft.collections.entity
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
@Immutable
|
||||
internal sealed class NFTSalePriceUM {
|
||||
data object Loading : NFTSalePriceUM()
|
||||
data object Failed : NFTSalePriceUM()
|
||||
data class Content(val price: String) : NFTSalePriceUM()
|
||||
data class Content(val price: TextReference) : NFTSalePriceUM()
|
||||
}
|
||||
|
|
@ -2,13 +2,13 @@ package com.tangem.features.nft.collections.entity.transformer
|
|||
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.getActiveIconRes
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.nft.models.*
|
||||
import com.tangem.features.nft.collections.entity.*
|
||||
import com.tangem.features.nft.impl.R
|
||||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
|
@ -16,7 +16,6 @@ import kotlinx.collections.immutable.toPersistentList
|
|||
@Suppress("LongParameterList")
|
||||
internal class UpdateDataStateTransformer(
|
||||
private val nftCollections: List<NFTCollections>,
|
||||
private val searchQuery: String,
|
||||
private val onReceiveClick: () -> Unit,
|
||||
private val onRetryClick: () -> Unit,
|
||||
private val onExpandCollectionClick: (NFTCollection) -> Unit,
|
||||
|
|
@ -56,7 +55,7 @@ internal class UpdateDataStateTransformer(
|
|||
.map { it.content }
|
||||
.asSequence()
|
||||
.filterIsInstance<NFTCollections.Content.Collections>()
|
||||
.map { it.collections.orEmpty().transform(prevState, searchQuery) }
|
||||
.map { it.collections.orEmpty().transform(prevState) }
|
||||
.flatten()
|
||||
.toPersistentList(),
|
||||
warnings = transformNotifications(),
|
||||
|
|
@ -75,48 +74,23 @@ internal class UpdateDataStateTransformer(
|
|||
)
|
||||
}
|
||||
|
||||
private fun List<NFTCollection>.transform(
|
||||
state: NFTCollectionsStateUM,
|
||||
query: String,
|
||||
): ImmutableList<NFTCollectionUM> = mapNotNull {
|
||||
val assetsFulfillQuery = if (query.isEmpty()) {
|
||||
true
|
||||
} else {
|
||||
when (val assets = it.assets) {
|
||||
is NFTCollection.Assets.Empty,
|
||||
is NFTCollection.Assets.Failed,
|
||||
is NFTCollection.Assets.Loading,
|
||||
-> false
|
||||
is NFTCollection.Assets.Value -> {
|
||||
assets.items.any { asset ->
|
||||
asset.name?.lowercase()?.contains(query.lowercase()) == true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val collectionFulfillQuery = query.isEmpty() || it.name?.lowercase()?.contains(query.lowercase()) == true
|
||||
|
||||
if (collectionFulfillQuery || assetsFulfillQuery) {
|
||||
NFTCollectionUM(
|
||||
id = it.collectionIdProvider(),
|
||||
networkIconId = getActiveIconRes(it.network.id.value),
|
||||
name = it.name,
|
||||
description = TextReference.PluralRes(
|
||||
R.plurals.nft_collections_count,
|
||||
it.count,
|
||||
wrappedList(it.count),
|
||||
),
|
||||
logoUrl = it.logoUrl,
|
||||
assets = it.transformAssets(),
|
||||
onExpandClick = {
|
||||
onExpandCollectionClick(it)
|
||||
},
|
||||
isExpanded = it.isExpanded(state),
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
private fun List<NFTCollection>.transform(state: NFTCollectionsStateUM): ImmutableList<NFTCollectionUM> = map {
|
||||
NFTCollectionUM(
|
||||
id = it.collectionIdProvider(),
|
||||
networkIconId = getActiveIconRes(it.network.rawId),
|
||||
name = it.name.orEmpty(),
|
||||
description = TextReference.PluralRes(
|
||||
R.plurals.nft_collections_count,
|
||||
it.count,
|
||||
wrappedList(it.count),
|
||||
),
|
||||
logoUrl = it.logoUrl,
|
||||
assets = it.transformAssets(),
|
||||
onExpandClick = {
|
||||
onExpandCollectionClick(it)
|
||||
},
|
||||
isExpanded = it.isExpanded(state),
|
||||
)
|
||||
}.toPersistentList()
|
||||
|
||||
private fun transformNotifications(): ImmutableList<NFTCollectionsWarningUM> = buildList {
|
||||
|
|
@ -146,20 +120,31 @@ internal class UpdateDataStateTransformer(
|
|||
)
|
||||
}
|
||||
|
||||
private fun NFTAsset.transform(collectionName: String): NFTCollectionAssetUM = NFTCollectionAssetUM(
|
||||
id = id.toString(),
|
||||
name = name.orEmpty(),
|
||||
imageUrl = media?.url,
|
||||
price = when (val salePrice = salePrice) {
|
||||
is NFTSalePrice.Empty -> NFTSalePriceUM.Failed
|
||||
is NFTSalePrice.Loading -> NFTSalePriceUM.Loading
|
||||
is NFTSalePrice.Error -> NFTSalePriceUM.Failed
|
||||
is NFTSalePrice.Value -> NFTSalePriceUM.Content(salePrice.value.toString())
|
||||
},
|
||||
onItemClick = {
|
||||
onAssetClick(this, collectionName)
|
||||
},
|
||||
)
|
||||
private fun NFTAsset.transform(collectionName: String): NFTCollectionAssetUM {
|
||||
return NFTCollectionAssetUM(
|
||||
id = id.toString(),
|
||||
name = name ?: DASH_SIGN,
|
||||
imageUrl = media?.url,
|
||||
price = when (val salePrice = salePrice) {
|
||||
is NFTSalePrice.Empty -> NFTSalePriceUM.Failed
|
||||
is NFTSalePrice.Loading -> NFTSalePriceUM.Loading
|
||||
is NFTSalePrice.Error -> NFTSalePriceUM.Failed
|
||||
is NFTSalePrice.Value -> NFTSalePriceUM.Content(
|
||||
price = stringReference(
|
||||
salePrice.value.format {
|
||||
crypto(
|
||||
symbol = salePrice.symbol,
|
||||
decimals = salePrice.decimals,
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
},
|
||||
onItemClick = {
|
||||
onAssetClick(this, collectionName)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun NFTCollection.isExpanded(state: NFTCollectionsStateUM): Boolean =
|
||||
(state.content as? NFTCollectionsUM.Content)
|
||||
|
|
|
|||
|
|
@ -11,14 +11,11 @@ import com.tangem.domain.nft.FetchNFTCollectionAssetsUseCase
|
|||
import com.tangem.domain.nft.GetNFTCollectionsUseCase
|
||||
import com.tangem.domain.nft.RefreshAllNFTUseCase
|
||||
import com.tangem.domain.nft.models.NFTCollection
|
||||
import com.tangem.domain.nft.models.NFTCollections
|
||||
import com.tangem.features.nft.collections.NFTCollectionsComponent
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionsStateUM
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionsUM
|
||||
import com.tangem.features.nft.collections.entity.transformer.*
|
||||
import com.tangem.features.nft.collections.entity.transformer.ChangeCollectionExpandedStateTransformer
|
||||
import com.tangem.features.nft.collections.entity.transformer.ToggleSearchBarTransformer
|
||||
import com.tangem.features.nft.collections.entity.transformer.UpdateDataStateTransformer
|
||||
import com.tangem.features.nft.collections.entity.transformer.UpdateSearchQueryTransformer
|
||||
import com.tangem.features.nft.impl.R
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
|
@ -75,8 +72,7 @@ internal class NFTCollectionsModel @Inject constructor(
|
|||
) { nftCollections, query ->
|
||||
_state.update {
|
||||
UpdateDataStateTransformer(
|
||||
nftCollections = nftCollections,
|
||||
searchQuery = query,
|
||||
nftCollections = nftCollections.filter(query),
|
||||
onReceiveClick = {
|
||||
params.onReceiveClick()
|
||||
},
|
||||
|
|
@ -95,6 +91,38 @@ internal class NFTCollectionsModel @Inject constructor(
|
|||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun List<NFTCollections>.filter(query: String): List<NFTCollections> = map {
|
||||
it.copy(
|
||||
content = when (val content = it.content) {
|
||||
is NFTCollections.Content.Collections -> content.copy(
|
||||
collections = content.collections.orEmpty().filter {
|
||||
val assetsFulfillQuery = if (query.isEmpty()) {
|
||||
true
|
||||
} else {
|
||||
when (val assets = it.assets) {
|
||||
is NFTCollection.Assets.Empty,
|
||||
is NFTCollection.Assets.Failed,
|
||||
is NFTCollection.Assets.Loading,
|
||||
-> false
|
||||
is NFTCollection.Assets.Value -> {
|
||||
assets.items.any { asset ->
|
||||
asset.name?.lowercase()?.contains(query.lowercase()) == true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val collectionFulfillQuery =
|
||||
query.isEmpty() || it.name?.lowercase()?.contains(query.lowercase()) == true
|
||||
|
||||
collectionFulfillQuery || assetsFulfillQuery
|
||||
},
|
||||
)
|
||||
is NFTCollections.Content.Error -> it.content
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun onRefresh() {
|
||||
modelScope.launch {
|
||||
_state.update { ChangeRefreshingStateTransformer(true).transform(it) }
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
|||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionAssetsListUM
|
||||
|
|
@ -90,7 +89,7 @@ private fun RowScope.Text(state: NFTCollectionUM) {
|
|||
) {
|
||||
Text(
|
||||
modifier = Modifier,
|
||||
text = state.name.takeUnless { it.isNullOrEmpty() } ?: stringResourceSafe(R.string.nft_no_collection),
|
||||
text = state.name,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
maxLines = 1,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import coil.request.ImageRequest
|
|||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.components.SpacerH12
|
||||
import com.tangem.core.ui.components.SpacerH2
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionAssetUM
|
||||
|
|
@ -116,7 +117,9 @@ private class NFTCollectionAssetProvider : CollectionPreviewParameterProvider<NF
|
|||
id = "item3",
|
||||
name = "Nethers #0855",
|
||||
imageUrl = "img",
|
||||
price = NFTSalePriceUM.Content("0.05 ETH"),
|
||||
price = NFTSalePriceUM.Content(
|
||||
price = stringReference("0.05 ETH"),
|
||||
),
|
||||
onItemClick = { },
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
|||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
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.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
|
@ -338,7 +339,9 @@ private fun Preview_NFTCollectionsContent() {
|
|||
id = "item1",
|
||||
name = "Nethers #0854",
|
||||
imageUrl = "img",
|
||||
price = NFTSalePriceUM.Content("0.05 ETH"),
|
||||
price = NFTSalePriceUM.Content(
|
||||
price = stringReference("0.05 ETH"),
|
||||
),
|
||||
onItemClick = { },
|
||||
),
|
||||
NFTCollectionAssetUM(
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ internal fun NFTCollectionsEmpty(state: NFTCollectionsUM.Empty, modifier: Modifi
|
|||
PrimaryButton(
|
||||
modifier = Modifier
|
||||
.padding(top = TangemTheme.dimens.spacing48)
|
||||
.wrapContentWidth(),
|
||||
.widthIn(min = TangemTheme.dimens.size158),
|
||||
text = stringResourceSafe(R.string.nft_collections_receive),
|
||||
onClick = state.onReceiveClick,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import com.tangem.core.ui.components.TextShimmer
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.nft.collections.entity.NFTSalePriceUM
|
||||
|
||||
|
|
@ -15,7 +16,7 @@ internal fun NFTSalePrice(state: NFTSalePriceUM, modifier: Modifier = Modifier)
|
|||
is NFTSalePriceUM.Content -> {
|
||||
Text(
|
||||
modifier = modifier,
|
||||
text = state.price,
|
||||
text = state.price.resolveReference(),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
maxLines = 1,
|
||||
|
|
|
|||
|
|
@ -19,18 +19,22 @@ import com.tangem.features.nft.common.ui.NFTContent
|
|||
import com.tangem.features.nft.component.NFTComponent
|
||||
import com.tangem.features.nft.details.NFTDetailsComponent
|
||||
import com.tangem.features.nft.details.info.NFTDetailsInfoComponent
|
||||
import com.tangem.features.nft.entity.NFTSendSuccessListener
|
||||
import com.tangem.features.nft.receive.NFTReceiveComponent
|
||||
import com.tangem.features.nft.traits.NFTAssetTraitsComponent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
internal class DefaultNFTComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted private val params: NFTComponent.Params,
|
||||
private val nftDetailsInfoComponentFactory: NFTDetailsInfoComponent.Factory,
|
||||
nftSendSuccessListener: NFTSendSuccessListener,
|
||||
) : NFTComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val stackNavigation = StackNavigation<NFTRoute>()
|
||||
|
|
@ -69,6 +73,11 @@ internal class DefaultNFTComponent @AssistedInject constructor(
|
|||
currentRoute.emit(stack.active.configuration)
|
||||
}
|
||||
}
|
||||
nftSendSuccessListener.nftSendSuccessFlow
|
||||
.onEach {
|
||||
innerRouter.popTo(NFTRoute.Collections(userWalletId = params.userWalletId))
|
||||
}
|
||||
.launchIn(componentScope)
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class DefaultNFTDetailsBlockComponent @AssistedInject constructor(
|
|||
assetName = stringReference(params.nftAsset.name.orEmpty()),
|
||||
collectionName = stringReference(params.nftCollectionName),
|
||||
assetImage = params.nftAsset.media?.url,
|
||||
networkIconRes = getActiveIconRes(params.nftAsset.network.id.value),
|
||||
networkIconRes = getActiveIconRes(params.nftAsset.network.rawId),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@ package com.tangem.features.nft.details.entity
|
|||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.components.atoms.text.TextEllipsis
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import java.math.BigDecimal
|
||||
|
||||
data class NFTAssetUM(
|
||||
val name: String,
|
||||
|
|
@ -41,11 +39,9 @@ data class NFTAssetUM(
|
|||
data object Loading : SalePrice()
|
||||
data object Empty : SalePrice()
|
||||
data class Content(
|
||||
val value: BigDecimal,
|
||||
val symbol: String,
|
||||
val decimals: Int,
|
||||
val rate: BigDecimal?,
|
||||
val appCurrency: AppCurrency,
|
||||
val isFlickering: Boolean,
|
||||
val cryptoPrice: TextReference,
|
||||
val fiatPrice: TextReference,
|
||||
) : SalePrice()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
package com.tangem.features.nft.details.entity
|
||||
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
|
||||
internal data class NFTDetailsUM(
|
||||
val nftAsset: NFTAssetUM,
|
||||
val pullToRefreshConfig: PullToRefreshConfig,
|
||||
val onBackClick: () -> Unit,
|
||||
val onReadMoreClick: () -> Unit,
|
||||
val onSeeAllTraitsClick: () -> Unit,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
package com.tangem.features.nft.details.entity.factory
|
||||
|
||||
import com.tangem.core.ui.components.atoms.text.TextEllipsis
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
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.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.nft.models.NFTAsset
|
||||
import com.tangem.domain.nft.models.NFTSalePrice
|
||||
import com.tangem.features.nft.details.entity.NFTAssetUM
|
||||
|
|
@ -12,17 +17,24 @@ import com.tangem.features.nft.impl.R
|
|||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class NFTDetailsUMFactory(
|
||||
private val appCurrency: AppCurrency,
|
||||
private val onBackClick: () -> Unit,
|
||||
private val onReadMoreClick: () -> Unit,
|
||||
private val onSeeAllTraitsClick: () -> Unit,
|
||||
private val onExploreClick: () -> Unit,
|
||||
private val onSendClick: () -> Unit,
|
||||
private val onRefresh: () -> Unit,
|
||||
private val onInfoBlockClick: (title: TextReference, text: TextReference) -> Unit,
|
||||
) {
|
||||
|
||||
fun getInitialState(nftAsset: NFTAsset): NFTDetailsUM = NFTDetailsUM(
|
||||
nftAsset = nftAsset.transform(),
|
||||
pullToRefreshConfig = PullToRefreshConfig(
|
||||
isRefreshing = false,
|
||||
onRefresh = { onRefresh() },
|
||||
),
|
||||
onBackClick = onBackClick,
|
||||
onReadMoreClick = onReadMoreClick,
|
||||
onSeeAllTraitsClick = onSeeAllTraitsClick,
|
||||
|
|
@ -52,7 +64,7 @@ internal class NFTDetailsUMFactory(
|
|||
} else {
|
||||
null
|
||||
},
|
||||
salePrice = NFTAssetUM.SalePrice.Empty,
|
||||
salePrice = toSalePrice(),
|
||||
description = description,
|
||||
rarity = if (rarity != null) {
|
||||
NFTAssetUM.Rarity.Content(
|
||||
|
|
@ -91,6 +103,32 @@ internal class NFTDetailsUMFactory(
|
|||
|
||||
private fun NFTAsset.hasSalePrice() = salePrice !is NFTSalePrice.Empty && salePrice !is NFTSalePrice.Error
|
||||
|
||||
private fun NFTAsset.toSalePrice() = when (val price = salePrice) {
|
||||
is NFTSalePrice.Empty,
|
||||
is NFTSalePrice.Error,
|
||||
-> NFTAssetUM.SalePrice.Empty
|
||||
is NFTSalePrice.Loading -> NFTAssetUM.SalePrice.Loading
|
||||
is NFTSalePrice.Value -> NFTAssetUM.SalePrice.Content(
|
||||
isFlickering = false,
|
||||
cryptoPrice = stringReference(
|
||||
price.value.format {
|
||||
crypto(
|
||||
symbol = price.symbol,
|
||||
decimals = price.decimals,
|
||||
)
|
||||
},
|
||||
),
|
||||
fiatPrice = stringReference(
|
||||
price.fiatValue.format {
|
||||
fiat(
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
private fun NFTAsset.buildBaseInfoItems() = when (val id = id) {
|
||||
is NFTAsset.Identifier.EVM -> persistentListOf(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
package com.tangem.features.nft.details.entity.transformer
|
||||
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.nft.models.NFTSalePrice
|
||||
import com.tangem.features.nft.details.entity.NFTAssetUM
|
||||
import com.tangem.features.nft.details.entity.NFTDetailsUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class NFTPriceChangeTransformer(
|
||||
private val appCurrency: AppCurrency,
|
||||
private val nftSalePrice: NFTSalePrice,
|
||||
) : Transformer<NFTDetailsUM> {
|
||||
|
||||
override fun transform(prevState: NFTDetailsUM): NFTDetailsUM {
|
||||
val topInfo = prevState.nftAsset.topInfo as? NFTAssetUM.TopInfo.Content ?: return prevState
|
||||
|
||||
return prevState.copy(
|
||||
nftAsset = prevState.nftAsset.copy(
|
||||
topInfo = topInfo.copy(
|
||||
salePrice = when (nftSalePrice) {
|
||||
is NFTSalePrice.Empty,
|
||||
is NFTSalePrice.Error,
|
||||
-> NFTAssetUM.SalePrice.Empty
|
||||
is NFTSalePrice.Loading -> NFTAssetUM.SalePrice.Loading
|
||||
is NFTSalePrice.Value -> NFTAssetUM.SalePrice.Content(
|
||||
isFlickering = false,
|
||||
cryptoPrice = stringReference(
|
||||
nftSalePrice.value.format {
|
||||
crypto(
|
||||
symbol = nftSalePrice.symbol,
|
||||
decimals = nftSalePrice.decimals,
|
||||
)
|
||||
},
|
||||
),
|
||||
fiatPrice = stringReference(
|
||||
nftSalePrice.fiatValue.format {
|
||||
fiat(
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.features.nft.details.entity.transformer
|
||||
|
||||
import com.tangem.features.nft.details.entity.NFTAssetUM
|
||||
import com.tangem.features.nft.details.entity.NFTDetailsUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal object NFTPriceUpdatingTransformer : Transformer<NFTDetailsUM> {
|
||||
|
||||
override fun transform(prevState: NFTDetailsUM): NFTDetailsUM {
|
||||
val topInfo = prevState.nftAsset.topInfo as? NFTAssetUM.TopInfo.Content ?: return prevState
|
||||
val salePrice = topInfo.salePrice as? NFTAssetUM.SalePrice.Content
|
||||
return prevState.copy(
|
||||
nftAsset = prevState.nftAsset.copy(
|
||||
topInfo = topInfo.copy(
|
||||
salePrice = salePrice?.copy(
|
||||
isFlickering = true,
|
||||
) ?: topInfo.salePrice,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.nft.details.model
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.tangem.common.routing.AppRoute
|
||||
|
|
@ -12,20 +13,31 @@ import com.tangem.core.navigation.url.UrlOpener
|
|||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.nft.FetchNFTCollectionAssetsUseCase
|
||||
import com.tangem.domain.nft.FetchNFTPriceUseCase
|
||||
import com.tangem.domain.nft.GetNFTExploreUrlUseCase
|
||||
import com.tangem.domain.nft.GetNFTPriceUseCase
|
||||
import com.tangem.domain.nft.analytics.NFTAnalyticsEvent
|
||||
import com.tangem.features.nft.details.NFTDetailsComponent
|
||||
import com.tangem.features.nft.details.entity.NFTAssetUM
|
||||
import com.tangem.features.nft.details.entity.NFTDetailsBottomSheetConfig
|
||||
import com.tangem.features.nft.details.entity.NFTDetailsUM
|
||||
import com.tangem.features.nft.details.entity.factory.NFTDetailsUMFactory
|
||||
import com.tangem.features.nft.details.entity.transformer.NFTPriceChangeTransformer
|
||||
import com.tangem.features.nft.details.entity.transformer.NFTPriceUpdatingTransformer
|
||||
import com.tangem.features.nft.impl.R
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import com.tangem.utils.transformer.update
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@ModelScoped
|
||||
internal class NFTDetailsModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
|
|
@ -33,6 +45,10 @@ internal class NFTDetailsModel @Inject constructor(
|
|||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val urlOpener: UrlOpener,
|
||||
private val getNFTExploreUrlUseCase: GetNFTExploreUrlUseCase,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getNFTPriceUseCase: GetNFTPriceUseCase,
|
||||
private val fetchNFTCollectionAssetsUseCase: FetchNFTCollectionAssetsUseCase,
|
||||
private val fetchNFTPriceUseCase: FetchNFTPriceUseCase,
|
||||
paramsContainer: ParamsContainer,
|
||||
) : Model() {
|
||||
|
||||
|
|
@ -40,23 +56,88 @@ internal class NFTDetailsModel @Inject constructor(
|
|||
|
||||
val state: StateFlow<NFTDetailsUM> get() = _state
|
||||
|
||||
private var appCurrency: AppCurrency = AppCurrency.Default
|
||||
|
||||
private val stateFactory: NFTDetailsUMFactory = NFTDetailsUMFactory(
|
||||
appCurrency = appCurrency,
|
||||
onBackClick = { params.onBackClick() },
|
||||
onReadMoreClick = ::onReadMoreClick,
|
||||
onSeeAllTraitsClick = { params.onAllTraitsClick() },
|
||||
onExploreClick = ::onExploreClick,
|
||||
onSendClick = ::onSendClick,
|
||||
onInfoBlockClick = ::onInfoBlockClick,
|
||||
onRefresh = ::onRefresh,
|
||||
)
|
||||
|
||||
private val _state = MutableStateFlow(
|
||||
value = stateFactory.getInitialState(params.nftAsset),
|
||||
)
|
||||
private val _state by lazy {
|
||||
MutableStateFlow(
|
||||
value = stateFactory.getInitialState(params.nftAsset),
|
||||
)
|
||||
}
|
||||
|
||||
val bottomSheetNavigation: SlotNavigation<NFTDetailsBottomSheetConfig> = SlotNavigation()
|
||||
|
||||
init {
|
||||
analyticsEventHandler.send(NFTAnalyticsEvent.Details.ScreenOpened(params.nftAsset.network.name))
|
||||
initAppCurrency()
|
||||
subscribeToPriceChanges()
|
||||
}
|
||||
|
||||
private fun initAppCurrency() {
|
||||
modelScope.launch {
|
||||
appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default }
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeToPriceChanges() {
|
||||
_state.update(NFTPriceUpdatingTransformer)
|
||||
modelScope.launch {
|
||||
getNFTPriceUseCase(params.userWalletId, params.nftAsset)
|
||||
.fold(
|
||||
ifLeft = {
|
||||
Timber.w(it)
|
||||
},
|
||||
ifRight = { quoteFlow ->
|
||||
quoteFlow
|
||||
.distinctUntilChanged()
|
||||
.onEach { salePrice ->
|
||||
_state.update(
|
||||
NFTPriceChangeTransformer(
|
||||
appCurrency = appCurrency,
|
||||
nftSalePrice = salePrice,
|
||||
),
|
||||
)
|
||||
}.launchIn(modelScope)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onRefresh() {
|
||||
_state.update {
|
||||
it.copy(pullToRefreshConfig = it.pullToRefreshConfig.copy(isRefreshing = true))
|
||||
}
|
||||
_state.update(NFTPriceUpdatingTransformer)
|
||||
modelScope.launch {
|
||||
awaitAll(
|
||||
async {
|
||||
fetchNFTCollectionAssetsUseCase(
|
||||
userWalletId = params.userWalletId,
|
||||
network = params.nftAsset.network,
|
||||
collectionId = params.nftAsset.collectionId,
|
||||
)
|
||||
},
|
||||
async {
|
||||
fetchNFTPriceUseCase(
|
||||
network = params.nftAsset.network,
|
||||
appCurrencyId = null,
|
||||
)
|
||||
},
|
||||
)
|
||||
_state.update {
|
||||
it.copy(pullToRefreshConfig = it.pullToRefreshConfig.copy(isRefreshing = false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onInfoBlockClick(title: TextReference, text: TextReference) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.nft.details.ui
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
|
|
@ -11,6 +12,7 @@ import androidx.compose.ui.Modifier
|
|||
import com.tangem.core.ui.components.PrimaryButton
|
||||
import com.tangem.core.ui.components.appbar.TangemTopAppBar
|
||||
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.TangemPullToRefreshContainer
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.nft.details.entity.NFTDetailsUM
|
||||
|
|
@ -34,14 +36,19 @@ internal fun NFTDetails(state: NFTDetailsUM, modifier: Modifier = Modifier) {
|
|||
)
|
||||
},
|
||||
content = { innerPadding ->
|
||||
NFTDetailsAsset(
|
||||
state = state.nftAsset,
|
||||
onReadMoreClick = state.onReadMoreClick,
|
||||
onSeeAllTraitsClick = state.onSeeAllTraitsClick,
|
||||
onExploreClick = state.onExploreClick,
|
||||
TangemPullToRefreshContainer(
|
||||
config = state.pullToRefreshConfig,
|
||||
modifier = Modifier
|
||||
.padding(innerPadding),
|
||||
)
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
NFTDetailsAsset(
|
||||
state = state.nftAsset,
|
||||
onReadMoreClick = state.onReadMoreClick,
|
||||
onSeeAllTraitsClick = state.onSeeAllTraitsClick,
|
||||
onExploreClick = state.onExploreClick,
|
||||
)
|
||||
}
|
||||
},
|
||||
floatingActionButtonPosition = FabPosition.Center,
|
||||
floatingActionButton = {
|
||||
|
|
|
|||
|
|
@ -16,11 +16,9 @@ import com.tangem.core.ui.extensions.resourceReference
|
|||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.features.nft.details.entity.NFTAssetUM
|
||||
import com.tangem.features.nft.impl.R
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Composable
|
||||
internal fun NFTDetailsAsset(
|
||||
|
|
@ -127,11 +125,9 @@ private class NFTAssetProvider : CollectionPreviewParameterProvider<NFTAssetUM>(
|
|||
topInfo = NFTAssetUM.TopInfo.Content(
|
||||
title = resourceReference(R.string.nft_details_last_sale_price),
|
||||
salePrice = NFTAssetUM.SalePrice.Content(
|
||||
value = BigDecimal("18.75"),
|
||||
symbol = "ETH",
|
||||
decimals = 18,
|
||||
rate = BigDecimal("1"),
|
||||
appCurrency = AppCurrency.Default,
|
||||
cryptoPrice = stringReference("ETH 18.75"),
|
||||
fiatPrice = stringReference("$ 1"),
|
||||
isFlickering = true,
|
||||
),
|
||||
description = "Base edition by Piux. An illustration of Crypto Robot #7804".repeat(3),
|
||||
rarity = NFTAssetUM.Rarity.Content(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
package com.tangem.features.nft.details.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
|
|
@ -14,21 +17,17 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.common.ui.amountScreen.utils.getFiatString
|
||||
import com.tangem.core.ui.components.TextShimmer
|
||||
import com.tangem.core.ui.components.atoms.text.ReadMoreText
|
||||
import com.tangem.core.ui.components.block.information.InformationBlock
|
||||
import com.tangem.core.ui.components.flicker
|
||||
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.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.features.nft.details.entity.NFTAssetUM
|
||||
import com.tangem.features.nft.impl.R
|
||||
import java.math.BigDecimal
|
||||
|
||||
private const val READ_MORE_MAX_LINES = 3
|
||||
|
||||
|
|
@ -68,7 +67,9 @@ internal fun NFTDetailsInfoGroup(
|
|||
@Composable
|
||||
private fun SalePrice(state: NFTAssetUM.SalePrice, modifier: Modifier = Modifier) {
|
||||
AnimatedVisibility(
|
||||
modifier = Modifier.fillMaxWidth().animateContentSize(),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.animateContentSize(),
|
||||
visible = state !is NFTAssetUM.SalePrice.Empty,
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut(),
|
||||
|
|
@ -108,19 +109,15 @@ private fun SalePrice(state: NFTAssetUM.SalePrice, modifier: Modifier = Modifier
|
|||
verticalArrangement = Arrangement.SpaceAround,
|
||||
) {
|
||||
Text(
|
||||
text = state.value.format {
|
||||
crypto(
|
||||
symbol = state.symbol,
|
||||
decimals = state.decimals,
|
||||
)
|
||||
},
|
||||
text = state.cryptoPrice.resolveReference(),
|
||||
style = TangemTheme.typography.head,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(top = TangemTheme.dimens.spacing4),
|
||||
text = getFiatString(state.value, state.rate, state.appCurrency),
|
||||
.padding(top = TangemTheme.dimens.spacing4)
|
||||
.flicker(state.isFlickering),
|
||||
text = state.fiatPrice.resolveReference(),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
|
|
@ -237,11 +234,9 @@ private class NFTAssetInfoProvider : CollectionPreviewParameterProvider<NFTAsset
|
|||
NFTAssetUM.TopInfo.Content(
|
||||
title = resourceReference(R.string.nft_details_last_sale_price),
|
||||
salePrice = NFTAssetUM.SalePrice.Content(
|
||||
value = BigDecimal("18.75"),
|
||||
symbol = "ETH",
|
||||
decimals = 18,
|
||||
rate = BigDecimal("1"),
|
||||
appCurrency = AppCurrency.Default,
|
||||
cryptoPrice = stringReference("ETH 18.75"),
|
||||
fiatPrice = stringReference("$ 1"),
|
||||
isFlickering = false,
|
||||
),
|
||||
description = "Base edition by Piux. An illustration of Crypto Robot #7804".repeat(3),
|
||||
rarity = NFTAssetUM.Rarity.Content(
|
||||
|
|
@ -267,11 +262,9 @@ private class NFTAssetInfoProvider : CollectionPreviewParameterProvider<NFTAsset
|
|||
NFTAssetUM.TopInfo.Content(
|
||||
title = resourceReference(R.string.nft_details_last_sale_price),
|
||||
salePrice = NFTAssetUM.SalePrice.Content(
|
||||
value = BigDecimal("18.75"),
|
||||
symbol = "ETH",
|
||||
decimals = 18,
|
||||
rate = BigDecimal("1"),
|
||||
appCurrency = AppCurrency.Default,
|
||||
cryptoPrice = stringReference("ETH 18.75"),
|
||||
fiatPrice = stringReference("$ 1"),
|
||||
isFlickering = true,
|
||||
),
|
||||
description = null,
|
||||
rarity = NFTAssetUM.Rarity.Content(
|
||||
|
|
@ -285,11 +278,9 @@ private class NFTAssetInfoProvider : CollectionPreviewParameterProvider<NFTAsset
|
|||
NFTAssetUM.TopInfo.Content(
|
||||
title = resourceReference(R.string.nft_details_last_sale_price),
|
||||
salePrice = NFTAssetUM.SalePrice.Content(
|
||||
value = BigDecimal("18.75"),
|
||||
symbol = "ETH",
|
||||
decimals = 18,
|
||||
rate = BigDecimal("1"),
|
||||
appCurrency = AppCurrency.Default,
|
||||
cryptoPrice = stringReference("ETH 18.75"),
|
||||
fiatPrice = stringReference("$ 1"),
|
||||
isFlickering = true,
|
||||
),
|
||||
description = "Base edition by Piux. An illustration of Crypto Robot #7804".repeat(3),
|
||||
rarity = NFTAssetUM.Rarity.Empty,
|
||||
|
|
@ -297,11 +288,9 @@ private class NFTAssetInfoProvider : CollectionPreviewParameterProvider<NFTAsset
|
|||
NFTAssetUM.TopInfo.Content(
|
||||
title = resourceReference(R.string.nft_details_last_sale_price),
|
||||
salePrice = NFTAssetUM.SalePrice.Content(
|
||||
value = BigDecimal("18.75"),
|
||||
symbol = "ETH",
|
||||
decimals = 18,
|
||||
rate = BigDecimal("1"),
|
||||
appCurrency = AppCurrency.Default,
|
||||
cryptoPrice = stringReference("ETH 18.75"),
|
||||
fiatPrice = stringReference("$ 1"),
|
||||
isFlickering = true,
|
||||
),
|
||||
description = null,
|
||||
rarity = NFTAssetUM.Rarity.Empty,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ import com.tangem.features.nft.details.block.DefaultNFTDetailsBlockComponent
|
|||
import com.tangem.features.nft.details.info.DefaultNFTDetailsInfoComponent
|
||||
import com.tangem.features.nft.details.info.NFTDetailsInfoComponent
|
||||
import com.tangem.features.nft.details.model.NFTDetailsModel
|
||||
import com.tangem.features.nft.entity.DefaultNFTSendSuccessTrigger
|
||||
import com.tangem.features.nft.entity.NFTSendSuccessListener
|
||||
import com.tangem.features.nft.entity.NFTSendSuccessTrigger
|
||||
import com.tangem.features.nft.receive.model.NFTReceiveModel
|
||||
import com.tangem.features.nft.traits.model.NFTAssetTraitsModel
|
||||
import dagger.Binds
|
||||
|
|
@ -71,4 +74,12 @@ internal interface NFTFeatureModuleBinds {
|
|||
@IntoMap
|
||||
@ClassKey(NFTAssetTraitsModel::class)
|
||||
fun bindNFTTraitsModel(model: NFTAssetTraitsModel): Model
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindNFTSendSuccessTrigger(impl: DefaultNFTSendSuccessTrigger): NFTSendSuccessTrigger
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindNFTSendSuccessListener(impl: DefaultNFTSendSuccessTrigger): NFTSendSuccessListener
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.features.nft.entity
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Listens to success nft send trigger
|
||||
*/
|
||||
interface NFTSendSuccessListener {
|
||||
val nftSendSuccessFlow: Flow<Unit>
|
||||
}
|
||||
|
||||
@Singleton
|
||||
internal class DefaultNFTSendSuccessTrigger @Inject constructor() : NFTSendSuccessTrigger, NFTSendSuccessListener {
|
||||
|
||||
override val nftSendSuccessFlow: SharedFlow<Unit>
|
||||
field = MutableSharedFlow<Unit>()
|
||||
|
||||
override suspend fun triggerSuccessNFTSend() {
|
||||
nftSendSuccessFlow.emit(Unit)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,8 @@ package com.tangem.features.nft.receive.entity.transformer
|
|||
|
||||
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.tokens.model.NetworkAddress
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.network.NetworkAddress
|
||||
import com.tangem.features.nft.receive.entity.NFTReceiveUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ package com.tangem.features.nft.receive.entity.transformer
|
|||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.rows.model.ChainRowUM
|
||||
import com.tangem.core.ui.extensions.getActiveIconRes
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.nft.models.NFTNetworks
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.features.nft.receive.entity.NFTNetworkUM
|
||||
import com.tangem.features.nft.receive.entity.NFTReceiveUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
|
@ -33,13 +33,13 @@ internal class UpdateDataStateTransformer(
|
|||
private fun Network.transform(enabled: Boolean): NFTNetworkUM {
|
||||
val custom = derivationPath is Network.DerivationPath.Custom
|
||||
return NFTNetworkUM(
|
||||
id = id.value + derivationPath.value,
|
||||
id = rawId + derivationPath.value,
|
||||
chainRowUM = ChainRowUM(
|
||||
name = name,
|
||||
type = "",
|
||||
icon = CurrencyIconState.CoinIcon(
|
||||
url = null,
|
||||
fallbackResId = getActiveIconRes(id.value),
|
||||
fallbackResId = getActiveIconRes(rawId),
|
||||
isGrayscale = !enabled,
|
||||
showCustomBadge = custom,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@ import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.message.DialogMessage
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.network.NetworkStatus
|
||||
import com.tangem.domain.nft.FilterNFTAvailableNetworksUseCase
|
||||
import com.tangem.domain.nft.GetNFTNetworksUseCase
|
||||
import com.tangem.domain.nft.GetNFTNetworkStatusUseCase
|
||||
import com.tangem.domain.nft.GetNFTNetworksUseCase
|
||||
import com.tangem.domain.nft.analytics.NFTAnalyticsEvent
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.tokens.model.NetworkStatus
|
||||
import com.tangem.features.nft.impl.R
|
||||
import com.tangem.features.nft.receive.NFTReceiveComponent
|
||||
import com.tangem.features.nft.receive.entity.NFTReceiveUM
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package com.tangem.features.onboarding.v2.common.analytics
|
|||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
|
||||
sealed class OnboardingEvent(
|
||||
category: String,
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ import com.tangem.core.ui.format.bigdecimal.crypto
|
|||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.exchange.RampStateManager
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.network.NetworkAddress
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.onramp.GetLegacyTopUpUrlUseCase
|
||||
import com.tangem.domain.tokens.FetchCurrencyStatusUseCase
|
||||
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
|
||||
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.tokens.model.NetworkAddress
|
||||
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
|
||||
import com.tangem.domain.tokens.model.analytics.TokenReceiveAnalyticsEvent
|
||||
import com.tangem.domain.wallets.builder.UserWalletBuilder
|
||||
|
|
@ -39,7 +39,7 @@ import javax.inject.Inject
|
|||
internal class OnboardingNoteTopUpModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
|
||||
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
|
||||
private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase,
|
||||
private val userWalletBuilderFactory: UserWalletBuilder.Factory,
|
||||
private val getLegacyTopUpUrlUseCase: GetLegacyTopUpUrlUseCase,
|
||||
|
|
@ -137,8 +137,11 @@ internal class OnboardingNoteTopUpModel @Inject constructor(
|
|||
|
||||
private fun observeCryptoCurrencyStatus() {
|
||||
val userWalletId = userWallet?.walletId ?: return
|
||||
getPrimaryCurrencyStatusUpdatesUseCase(userWalletId = userWalletId).map { it.getOrNull() }.filterNotNull()
|
||||
.onEach(::applyCryptoCurrencyStatusToState).launchIn(modelScope)
|
||||
getSingleCryptoCurrencyStatusUseCase.invokeSingleWallet(userWalletId = userWalletId)
|
||||
.map { it.getOrNull() }
|
||||
.filterNotNull()
|
||||
.onEach(::applyCryptoCurrencyStatusToState)
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun applyCryptoCurrencyStatusToState(status: CryptoCurrencyStatus) {
|
||||
|
|
|
|||
|
|
@ -7,18 +7,18 @@ import com.tangem.common.core.TangemError
|
|||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
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.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.share.ShareManager
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
import com.tangem.core.ui.clipboard.ClipboardManager
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.toWrappedList
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
|
|
@ -30,13 +30,13 @@ import com.tangem.domain.common.getTwinCardNumber
|
|||
import com.tangem.domain.common.util.twinsIsTwinned
|
||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.onboarding.SaveTwinsOnboardingShownUseCase
|
||||
import com.tangem.domain.onramp.GetLegacyTopUpUrlUseCase
|
||||
import com.tangem.domain.tokens.FetchCurrencyStatusUseCase
|
||||
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
|
||||
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.tokens.model.analytics.TokenReceiveAnalyticsEvent
|
||||
import com.tangem.domain.wallets.builder.UserWalletBuilder
|
||||
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
||||
|
|
@ -77,7 +77,7 @@ internal class OnboardingTwinModel @Inject constructor(
|
|||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val issuersConfigStorage: IssuersConfigStorage,
|
||||
private val cardRepository: CardRepository,
|
||||
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
|
||||
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
|
||||
private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase,
|
||||
private val getLegacyTopUpUrlUseCase: GetLegacyTopUpUrlUseCase,
|
||||
private val urlOpener: UrlOpener,
|
||||
|
|
@ -337,16 +337,16 @@ internal class OnboardingTwinModel @Inject constructor(
|
|||
setLoading(false)
|
||||
}
|
||||
|
||||
val cryptoCurrencyStatus =
|
||||
getPrimaryCurrencyStatusUpdatesUseCase.invoke(userWallet.walletId).firstOrNull()?.getOrNull()
|
||||
?: run {
|
||||
setLoading(false)
|
||||
Timber.e("Unable to get currency status")
|
||||
return@coroutineScope
|
||||
}
|
||||
val cryptoCurrencyStatus = getSingleCryptoCurrencyStatusUseCase.invokeSingleWallet(userWallet.walletId)
|
||||
.firstOrNull()?.getOrNull()
|
||||
?: run {
|
||||
setLoading(false)
|
||||
Timber.e("Unable to get currency status")
|
||||
return@coroutineScope
|
||||
}
|
||||
|
||||
launch {
|
||||
getPrimaryCurrencyStatusUpdatesUseCase.invoke(userWallet.walletId)
|
||||
getSingleCryptoCurrencyStatusUseCase.invokeSingleWallet(userWallet.walletId)
|
||||
.collect {
|
||||
it.onRight { status ->
|
||||
applyCryptoCurrencyStatusToState(status)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.features.onboarding.v2.visa.impl.child.accesscode.model
|
|||
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
|
|
@ -9,10 +10,9 @@ 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.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.error.UniversalError
|
||||
import com.tangem.core.error.ext.universalError
|
||||
import com.tangem.core.ui.utils.showErrorDialog
|
||||
import com.tangem.domain.visa.error.VisaAPIError
|
||||
import com.tangem.domain.visa.error.VisaAuthorizationAPIError
|
||||
import com.tangem.domain.visa.model.VisaCardActivationStatus
|
||||
import com.tangem.domain.visa.model.VisaCardId
|
||||
import com.tangem.domain.visa.model.VisaCustomerWalletDataToSignRequest
|
||||
|
|
@ -153,14 +153,11 @@ internal class OnboardingVisaAccessCodeModel @Inject constructor(
|
|||
loading(true)
|
||||
|
||||
modelScope.launch {
|
||||
val challengeToSign = runCatching {
|
||||
visaAuthRepository.getCardAuthChallenge(
|
||||
cardId = activationInput.cardId,
|
||||
cardPublicKey = activationInput.cardPublicKey,
|
||||
)
|
||||
}.getOrElse {
|
||||
loading(false)
|
||||
uiMessageSender.showErrorDialog(VisaAuthorizationAPIError)
|
||||
val challengeToSign = visaAuthRepository.getCardAuthChallenge(
|
||||
cardId = activationInput.cardId,
|
||||
cardPublicKey = activationInput.cardPublicKey,
|
||||
).getOrElse {
|
||||
onError(it)
|
||||
return@launch
|
||||
}
|
||||
|
||||
|
|
@ -174,23 +171,17 @@ internal class OnboardingVisaAccessCodeModel @Inject constructor(
|
|||
|
||||
val resultData = when (result) {
|
||||
is CompletionResult.Failure -> {
|
||||
loading(false)
|
||||
uiMessageSender.showErrorDialog(result.error.universalError)
|
||||
analyticsEventsHandler.send(
|
||||
VisaAnalyticsEvent.ErrorOnboarding(result.error.universalError),
|
||||
)
|
||||
onError(result.error.universalError)
|
||||
return@launch
|
||||
}
|
||||
is CompletionResult.Success -> result.data
|
||||
}
|
||||
|
||||
runCatching {
|
||||
visaActivationRepository.activateCard(resultData.signedActivationData)
|
||||
}.onFailure {
|
||||
loading(false)
|
||||
uiMessageSender.showErrorDialog(VisaAPIError)
|
||||
return@launch
|
||||
}
|
||||
visaActivationRepository.activateCard(resultData.signedActivationData)
|
||||
.onLeft {
|
||||
onError(it)
|
||||
return@launch
|
||||
}
|
||||
|
||||
val targetAddress =
|
||||
result.data.signedActivationData.dataToSign.request.activationOrderInfo.customerWalletAddress
|
||||
|
|
@ -213,6 +204,12 @@ internal class OnboardingVisaAccessCodeModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun onError(error: UniversalError) {
|
||||
loading(false)
|
||||
uiMessageSender.showErrorDialog(error)
|
||||
analyticsEventsHandler.send(VisaAnalyticsEvent.ErrorOnboarding(error))
|
||||
}
|
||||
|
||||
private fun loading(state: Boolean) {
|
||||
_uiState.update { it.copy(buttonLoading = state) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.onboarding.v2.visa.impl.child.approve.model
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
|
|
@ -8,9 +9,9 @@ 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.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.error.UniversalError
|
||||
import com.tangem.core.error.ext.universalError
|
||||
import com.tangem.core.ui.utils.showErrorDialog
|
||||
import com.tangem.domain.visa.error.VisaAPIError
|
||||
import com.tangem.domain.visa.model.VisaCardId
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.domain.visa.repository.VisaActivationRepository
|
||||
|
|
@ -67,13 +68,12 @@ internal class OnboardingVisaApproveModel @Inject constructor(
|
|||
analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.ButtonApprove)
|
||||
|
||||
modelScope.launch {
|
||||
val dataToSign = runCatching {
|
||||
val dataToSign =
|
||||
visaActivationRepository.getCustomerWalletAcceptanceData(params.preparationDataForApprove.request)
|
||||
}.getOrElse {
|
||||
loading(false)
|
||||
uiMessageSender.showErrorDialog(VisaAPIError)
|
||||
return@launch
|
||||
}
|
||||
.getOrElse {
|
||||
onError(it)
|
||||
return@launch
|
||||
}
|
||||
|
||||
val result = tangemSdkManager.visaCustomerWalletApprove(
|
||||
visaDataForApprove = VisaDataForApprove(
|
||||
|
|
@ -85,26 +85,28 @@ internal class OnboardingVisaApproveModel @Inject constructor(
|
|||
|
||||
val resultData = when (result) {
|
||||
is CompletionResult.Failure -> {
|
||||
loading(false)
|
||||
uiMessageSender.showErrorDialog(result.error.universalError)
|
||||
analyticsEventHandler.send(VisaAnalyticsEvent.ErrorOnboarding(result.error.universalError))
|
||||
onError(result.error.universalError)
|
||||
return@launch
|
||||
}
|
||||
is CompletionResult.Success -> result.data
|
||||
}
|
||||
|
||||
runCatching {
|
||||
visaActivationRepository.approveByCustomerWallet(resultData)
|
||||
}.onFailure {
|
||||
loading(false)
|
||||
uiMessageSender.showErrorDialog(VisaAPIError)
|
||||
return@launch
|
||||
}
|
||||
visaActivationRepository.approveByCustomerWallet(resultData)
|
||||
.onLeft {
|
||||
onError(it)
|
||||
return@launch
|
||||
}
|
||||
|
||||
onDone.emit(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onError(error: UniversalError) {
|
||||
loading(false)
|
||||
uiMessageSender.showErrorDialog(error)
|
||||
analyticsEventHandler.send(VisaAnalyticsEvent.ErrorOnboarding(error))
|
||||
}
|
||||
|
||||
private fun loading(state: Boolean) {
|
||||
_uiState.update { it.copy(approveButtonLoading = state) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.onboarding.v2.visa.impl.child.inprogress.model
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
|
|
@ -12,8 +13,10 @@ import com.tangem.datasource.local.visa.VisaAuthTokenStorage
|
|||
import com.tangem.datasource.local.visa.VisaOTPStorage
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.visa.error.VisaActivationError
|
||||
import com.tangem.domain.visa.error.VisaAuthorizationAPIError
|
||||
import com.tangem.domain.visa.model.*
|
||||
import com.tangem.domain.visa.model.VisaActivationRemoteState
|
||||
import com.tangem.domain.visa.model.VisaAuthTokens
|
||||
import com.tangem.domain.visa.model.VisaCardActivationStatus
|
||||
import com.tangem.domain.visa.model.VisaCardId
|
||||
import com.tangem.domain.visa.repository.VisaActivationRepository
|
||||
import com.tangem.domain.visa.repository.VisaAuthRepository
|
||||
import com.tangem.domain.wallets.builder.UserWalletBuilder
|
||||
|
|
@ -64,9 +67,13 @@ internal class OnboardingVisaInProgressModel @Inject constructor(
|
|||
private fun runShortPolling() {
|
||||
modelScope.launch {
|
||||
while (true) {
|
||||
val result = runCatching {
|
||||
visaActivationRepository.getActivationRemoteState()
|
||||
}.getOrNull() ?: continue
|
||||
val result = visaActivationRepository.getActivationRemoteState()
|
||||
.getOrElse {
|
||||
uiMessageSender.showErrorDialog(it)
|
||||
delay(timeMillis = 2000)
|
||||
runShortPolling()
|
||||
return@launch
|
||||
}
|
||||
|
||||
when (result) {
|
||||
is VisaActivationRemoteState.CardWalletSignatureRequired,
|
||||
|
|
@ -156,12 +163,11 @@ internal class OnboardingVisaInProgressModel @Inject constructor(
|
|||
val authTokens = visaAuthTokenStorage.get(params.scanResponse.card.cardId)
|
||||
?: error("Auth tokens are not found. This should not happen.")
|
||||
|
||||
val newTokens = runCatching {
|
||||
visaAuthRepository.refreshAccessTokens(authTokens.refreshToken)
|
||||
}.getOrElse {
|
||||
uiMessageSender.showErrorDialog(VisaAuthorizationAPIError)
|
||||
return
|
||||
}
|
||||
val newTokens = visaAuthRepository.refreshAccessTokens(authTokens.refreshToken)
|
||||
.getOrElse {
|
||||
uiMessageSender.showErrorDialog(it)
|
||||
return
|
||||
}
|
||||
|
||||
val userWallet = createUserWallet(params.scanResponse, newTokens)
|
||||
userWalletsListManager.save(userWallet)
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ 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.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.navigation.share.ShareManager
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
import com.tangem.core.ui.utils.showErrorDialog
|
||||
import com.tangem.domain.visa.model.VisaActivationOrderInfo
|
||||
import com.tangem.domain.visa.model.VisaActivationRemoteState
|
||||
import com.tangem.domain.visa.model.VisaCardId
|
||||
|
|
@ -15,6 +17,7 @@ import com.tangem.domain.visa.repository.VisaActivationRepository
|
|||
import com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.OnboardingVisaOtherWalletComponent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.ui.state.OnboardingVisaOtherWalletUM
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.model.analytics.OnboardingVisaAnalyticsEvent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.model.analytics.VisaAnalyticsEvent
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
|
@ -25,6 +28,7 @@ import javax.inject.Inject
|
|||
|
||||
@Stable
|
||||
@ModelScoped
|
||||
@Suppress("LongParameterList")
|
||||
internal class OnboardingVisaOtherWalletModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
visaActivationRepositoryFactory: VisaActivationRepository.Factory,
|
||||
|
|
@ -32,6 +36,7 @@ internal class OnboardingVisaOtherWalletModel @Inject constructor(
|
|||
private val urlOpener: UrlOpener,
|
||||
private val shareManager: ShareManager,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
) : Model() {
|
||||
|
||||
private val config = paramsContainer.require<OnboardingVisaOtherWalletComponent.Config>()
|
||||
|
|
@ -50,14 +55,18 @@ internal class OnboardingVisaOtherWalletModel @Inject constructor(
|
|||
analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.GoToWebsiteOpened)
|
||||
modelScope.launch {
|
||||
while (true) {
|
||||
val result = runCatching {
|
||||
visaActivationRepository.getActivationRemoteState()
|
||||
}.getOrNull()
|
||||
|
||||
if (result is VisaActivationRemoteState.AwaitingPinCode) {
|
||||
onDone.emit(result.activationOrderInfo)
|
||||
break
|
||||
}
|
||||
visaActivationRepository.getActivationRemoteState()
|
||||
.onLeft {
|
||||
uiMessageSender.showErrorDialog(it)
|
||||
analyticsEventHandler.send(VisaAnalyticsEvent.ErrorOnboarding(it))
|
||||
delay(timeMillis = 60_000)
|
||||
}
|
||||
.onRight {
|
||||
if (it is VisaActivationRemoteState.AwaitingPinCode) {
|
||||
onDone.emit(it.activationOrderInfo)
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
|
||||
delay(timeMillis = 2000)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import com.tangem.core.decompose.ui.UiMessageSender
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.utils.showErrorDialog
|
||||
import com.tangem.domain.visa.SetVisaPinCodeUseCase
|
||||
import com.tangem.domain.visa.error.VisaAuthorizationAPIError
|
||||
import com.tangem.domain.visa.model.VisaCardId
|
||||
import com.tangem.features.onboarding.v2.impl.R
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.pincode.OnboardingVisaPinCodeComponent
|
||||
|
|
@ -95,7 +94,7 @@ internal class OnboardingVisaPinCodeModel @Inject constructor(
|
|||
activationOrderId = params.activationOrderInfo.orderId,
|
||||
).onLeft {
|
||||
loading(false)
|
||||
uiMessageSender.showErrorDialog(VisaAuthorizationAPIError)
|
||||
uiMessageSender.showErrorDialog(it)
|
||||
return@launch
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.onboarding.v2.visa.impl.child.welcome.model
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
|
|
@ -7,9 +8,9 @@ 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.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.error.UniversalError
|
||||
import com.tangem.core.error.ext.universalError
|
||||
import com.tangem.core.ui.utils.showErrorDialog
|
||||
import com.tangem.domain.visa.error.VisaAPIError
|
||||
import com.tangem.domain.visa.model.VisaCardId
|
||||
import com.tangem.domain.visa.model.VisaCustomerWalletDataToSignRequest
|
||||
import com.tangem.domain.visa.repository.VisaActivationRepository
|
||||
|
|
@ -78,13 +79,11 @@ internal class OnboardingVisaWelcomeModel @Inject constructor(
|
|||
loading(true)
|
||||
|
||||
modelScope.launch {
|
||||
val dataToSignByCardWallet = runCatching {
|
||||
visaActivationRepository.getCardWalletAcceptanceData(params.dataToSignRequest)
|
||||
}.getOrElse {
|
||||
loading(false)
|
||||
uiMessageSender.showErrorDialog(VisaAPIError)
|
||||
return@launch
|
||||
}
|
||||
val dataToSignByCardWallet = visaActivationRepository.getCardWalletAcceptanceData(params.dataToSignRequest)
|
||||
.getOrElse {
|
||||
onError(it)
|
||||
return@launch
|
||||
}
|
||||
|
||||
val result = tangemSdkManager.activateVisaCard(
|
||||
mode = VisaCardActivationTaskMode.SignOnly(dataToSignByCardWallet = dataToSignByCardWallet),
|
||||
|
|
@ -93,21 +92,17 @@ internal class OnboardingVisaWelcomeModel @Inject constructor(
|
|||
|
||||
val resultData = when (result) {
|
||||
is CompletionResult.Failure -> {
|
||||
loading(false)
|
||||
uiMessageSender.showErrorDialog(result.error.universalError)
|
||||
analyticsEventsHandler.send(VisaAnalyticsEvent.ErrorOnboarding(result.error.universalError))
|
||||
onError(result.error.universalError)
|
||||
return@launch
|
||||
}
|
||||
is CompletionResult.Success -> result.data
|
||||
}
|
||||
|
||||
runCatching {
|
||||
visaActivationRepository.activateCard(resultData.signedActivationData)
|
||||
}.onFailure {
|
||||
loading(false)
|
||||
uiMessageSender.showErrorDialog(VisaAPIError)
|
||||
return@launch
|
||||
}
|
||||
visaActivationRepository.activateCard(resultData.signedActivationData)
|
||||
.onLeft {
|
||||
onError(it)
|
||||
return@launch
|
||||
}
|
||||
|
||||
val request = result.data.signedActivationData.dataToSign.request
|
||||
val targetAddress = request.activationOrderInfo.customerWalletAddress
|
||||
|
|
@ -132,6 +127,12 @@ internal class OnboardingVisaWelcomeModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun onError(error: UniversalError) {
|
||||
loading(false)
|
||||
uiMessageSender.showErrorDialog(error)
|
||||
analyticsEventsHandler.send(VisaAnalyticsEvent.ErrorOnboarding(error))
|
||||
}
|
||||
|
||||
private fun loading(state: Boolean) {
|
||||
_uiState.update { it.copy(continueButtonLoading = state) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ package com.tangem.features.onramp.component
|
|||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.onramp.model.OnrampSource
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
interface OnrampComponent : ComposableContentComponent {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.features.onramp.deeplink
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
interface BuyDeepLinkHandler {
|
||||
|
||||
interface Factory {
|
||||
fun create(coroutineScope: CoroutineScope): BuyDeepLinkHandler
|
||||
}
|
||||
}
|
||||
|
|
@ -3,10 +3,18 @@ package com.tangem.features.onramp.deeplink
|
|||
import com.tangem.core.deeplink.DeepLink
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
@Deprecated("Use OnrampDeepLinkHandler")
|
||||
abstract class OnrampDeepLink : DeepLink() {
|
||||
override val uri = "tangem://onramp"
|
||||
|
||||
interface Factory {
|
||||
fun create(coroutineScope: CoroutineScope): OnrampDeepLink
|
||||
}
|
||||
}
|
||||
|
||||
interface OnrampDeepLinkHandler {
|
||||
|
||||
interface Factory {
|
||||
fun create(coroutineScope: CoroutineScope, queryParams: Map<String, String>): OnrampDeepLinkHandler
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,8 @@ package com.tangem.features.onramp.confirmresidency
|
|||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.onramp.model.OnrampCountry
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
internal interface ConfirmResidencyComponent : ComposableBottomSheetComponent {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
package com.tangem.features.onramp.deeplink
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.domain.tokens.GetCryptoCurrencyUseCase
|
||||
import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.features.onramp.OnrampFeatureToggles
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
internal class DefaultBuyDeepLinkHandler @AssistedInject constructor(
|
||||
@Assisted scope: CoroutineScope,
|
||||
onrampFeatureToggles: OnrampFeatureToggles,
|
||||
getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
|
||||
getCryptoCurrencyUseCase: GetCryptoCurrencyUseCase,
|
||||
analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : BuyDeepLinkHandler {
|
||||
|
||||
init {
|
||||
// It is okay here, we are navigating from outside, and there is no other way to getting UserWallet
|
||||
getSelectedWalletSyncUseCase().fold(
|
||||
ifLeft = {
|
||||
Timber.e("Error on getting user wallet: $it")
|
||||
},
|
||||
ifRight = { userWallet ->
|
||||
if (!onrampFeatureToggles.isFeatureEnabled && !userWallet.isMultiCurrency) {
|
||||
scope.launch {
|
||||
val cryptoCurrency = getCryptoCurrencyUseCase(userWallet.walletId).getOrElse {
|
||||
Timber.e("Error on getting cryptoCurrency: $it")
|
||||
return@launch
|
||||
}
|
||||
analyticsEventHandler.send(TokenScreenAnalyticsEvent.Bought(cryptoCurrency.symbol))
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : BuyDeepLinkHandler.Factory {
|
||||
override fun create(coroutineScope: CoroutineScope): DefaultBuyDeepLinkHandler
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package com.tangem.features.onramp.deeplink
|
||||
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.features.onramp.success.OnrampSuccessScreenTrigger
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
internal class DefaultOnrampDeepLinkHandler @AssistedInject constructor(
|
||||
@Assisted scope: CoroutineScope,
|
||||
@Assisted queryParams: Map<String, String>,
|
||||
appRouter: AppRouter,
|
||||
onrampSuccessScreenTrigger: OnrampSuccessScreenTrigger,
|
||||
) : OnrampDeepLinkHandler {
|
||||
|
||||
init {
|
||||
val txId = queryParams[TX_ID_KEY]
|
||||
val result = OnrampRedirectResult.getResult(queryParams[RESULT_KEY])
|
||||
|
||||
when {
|
||||
!txId.isNullOrEmpty() -> {
|
||||
// finish current onramp flow and show onramp success screen
|
||||
val replaceOnrampScreens = appRouter.stack
|
||||
.filterNot { it is AppRoute.Onramp || it is AppRoute.OnrampSuccess }
|
||||
.toMutableList() + AppRoute.OnrampSuccess(txId)
|
||||
|
||||
appRouter.replaceAll(*replaceOnrampScreens.toTypedArray())
|
||||
}
|
||||
result != OnrampRedirectResult.Unknown -> {
|
||||
scope.launch {
|
||||
onrampSuccessScreenTrigger.triggerOnrampSuccess(result == OnrampRedirectResult.Success)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
Timber.e(
|
||||
"""
|
||||
Invalid parameters for ONRAMP deeplink
|
||||
|- Params: $queryParams
|
||||
""".trimIndent(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : OnrampDeepLinkHandler.Factory {
|
||||
override fun create(
|
||||
coroutineScope: CoroutineScope,
|
||||
queryParams: Map<String, String>,
|
||||
): DefaultOnrampDeepLinkHandler
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val TX_ID_KEY = "tx_id"
|
||||
const val RESULT_KEY = "result"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.features.onramp.deeplink.di
|
||||
|
||||
import com.tangem.features.onramp.deeplink.DefaultOnrampDeepLink
|
||||
import com.tangem.features.onramp.deeplink.OnrampDeepLink
|
||||
import com.tangem.features.onramp.deeplink.*
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -15,4 +14,12 @@ internal interface OnrampDeeplinkModule {
|
|||
@Binds
|
||||
@Singleton
|
||||
fun bindFactory(impl: DefaultOnrampDeepLink.Factory): OnrampDeepLink.Factory
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindOnrampDeepLinkHandlerFactory(impl: DefaultOnrampDeepLinkHandler.Factory): OnrampDeepLinkHandler.Factory
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindBuyDeepLinkHandler(impl: DefaultBuyDeepLinkHandler.Factory): BuyDeepLinkHandler.Factory
|
||||
}
|
||||
|
|
@ -12,10 +12,10 @@ import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.onramp.GetHotCryptoUseCase
|
||||
import com.tangem.domain.onramp.model.HotCryptoCurrency
|
||||
import com.tangem.domain.tokens.GetCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
|
||||
import com.tangem.features.onramp.hottokens.HotCryptoComponent
|
||||
import com.tangem.features.onramp.hottokens.converter.HotTokenItemStateConverter
|
||||
import com.tangem.features.onramp.hottokens.entity.HotCryptoUM
|
||||
|
|
@ -45,7 +45,7 @@ internal class HotCryptoModel @Inject constructor(
|
|||
paramsContainer: ParamsContainer,
|
||||
getHotCryptoUseCase: GetHotCryptoUseCase,
|
||||
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getCryptoCurrencyStatusSyncUseCase: GetCryptoCurrencyStatusSyncUseCase,
|
||||
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
) : Model() {
|
||||
|
||||
|
|
@ -103,7 +103,10 @@ internal class HotCryptoModel @Inject constructor(
|
|||
|
||||
private fun onSuccessAdding(id: CryptoCurrency.ID) {
|
||||
modelScope.launch {
|
||||
getCryptoCurrencyStatusSyncUseCase(userWalletId = params.userWalletId, cryptoCurrencyId = id)
|
||||
getSingleCryptoCurrencyStatusUseCase.invokeMultiWalletSync(
|
||||
userWalletId = params.userWalletId,
|
||||
cryptoCurrencyId = id,
|
||||
)
|
||||
.onRight {
|
||||
bottomSheetNavigation.dismiss()
|
||||
params.onTokenClick(it)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.features.onramp.hottokens.portfolio
|
|||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.features.onramp.hottokens.portfolio.entity
|
||||
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
|
||||
internal sealed class OnrampAddToPortfolioBSConfig {
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ package com.tangem.features.onramp.main
|
|||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.onramp.model.OnrampProviderWithQuote
|
||||
import com.tangem.domain.onramp.model.OnrampSource
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
internal interface OnrampMainComponent : ComposableContentComponent {
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ import com.tangem.common.ui.amountScreen.models.AmountFieldModel
|
|||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.onramp.model.OnrampCurrency
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.tokens.model.Amount
|
||||
import com.tangem.domain.tokens.model.AmountType
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.convertToAmount
|
||||
import com.tangem.features.onramp.impl.R
|
||||
import com.tangem.features.onramp.main.entity.*
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@ import com.tangem.core.ui.extensions.wrappedList
|
|||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.onramp.analytics.OnrampAnalyticsEvent
|
||||
import com.tangem.domain.onramp.model.OnrampCurrency
|
||||
import com.tangem.domain.onramp.model.OnrampProviderWithQuote
|
||||
import com.tangem.domain.onramp.model.OnrampQuote
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.tokens.model.AmountType
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.features.onramp.impl.R
|
||||
import com.tangem.features.onramp.main.entity.*
|
||||
import com.tangem.features.onramp.providers.entity.SelectProviderResult
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ package com.tangem.features.onramp.providers
|
|||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.onramp.model.OnrampPaymentMethod
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.features.onramp.providers.entity.SelectProviderResult
|
||||
|
||||
internal interface SelectProviderComponent : ComposableBottomSheetComponent {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ package com.tangem.features.onramp.redirect
|
|||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.onramp.model.OnrampProviderWithQuote
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
internal interface OnrampRedirectComponent : ComposableContentComponent {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.features.onramp.root.entity
|
||||
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.onramp.model.OnrampProviderWithQuote
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package com.tangem.features.onramp.selectcountry
|
|||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
internal interface SelectCountryComponent : ComposableBottomSheetComponent {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package com.tangem.features.onramp.selectcurrency
|
|||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
|
||||
internal interface SelectCurrencyComponent : ComposableBottomSheetComponent {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package com.tangem.features.onramp.settings
|
|||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
internal interface OnrampSettingsComponent : ComposableContentComponent {
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ import com.tangem.core.ui.extensions.wrappedList
|
|||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.onramp.model.OnrampStatus
|
||||
import com.tangem.domain.onramp.model.cache.OnrampTransaction
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.features.onramp.impl.R
|
||||
import com.tangem.features.onramp.success.entity.OnrampSuccessComponentUM
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.tangem.core.ui.clipboard.ClipboardManager
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.message.DialogMessage
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.onramp.GetOnrampStatusUseCase
|
||||
import com.tangem.domain.onramp.GetOnrampTransactionUseCase
|
||||
import com.tangem.domain.onramp.OnrampRemoveTransactionUseCase
|
||||
|
|
@ -19,7 +20,6 @@ import com.tangem.domain.onramp.model.OnrampStatus
|
|||
import com.tangem.domain.onramp.model.cache.OnrampTransaction
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.tokens.GetCryptoCurrencyUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.analytics.TokenOnrampAnalyticsEvent
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
|
|
@ -181,7 +181,9 @@ internal class OnrampSuccessComponentModel @Inject constructor(
|
|||
} else {
|
||||
resourceReference(R.string.express_error_code, wrappedList(errorCode))
|
||||
},
|
||||
onDismissRequest = router::pop,
|
||||
firstActionBuilder = {
|
||||
okAction(router::pop)
|
||||
},
|
||||
)
|
||||
|
||||
messageSender.send(message)
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ import com.tangem.domain.core.utils.getOrElse
|
|||
import com.tangem.domain.core.utils.lceContent
|
||||
import com.tangem.domain.core.utils.lceError
|
||||
import com.tangem.domain.core.utils.lceLoading
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.tokens.GetTokenListUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
|
|
|
|||
|
|
@ -17,4 +17,7 @@ dependencies {
|
|||
|
||||
/* Project - Domain */
|
||||
implementation(projects.domain.wallets.models)
|
||||
|
||||
/* Compose */
|
||||
implementation(deps.compose.runtime)
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.feature.referral.api.deeplink
|
||||
|
||||
interface ReferralDeepLinkHandler {
|
||||
|
||||
interface Factory {
|
||||
fun create(): ReferralDeepLinkHandler
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ import com.tangem.datasource.api.common.response.getOrThrow
|
|||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.api.tangemTech.models.StartReferralBody
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.referral.converters.ReferralConverter
|
||||
import com.tangem.feature.referral.domain.ReferralRepository
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ dependencies {
|
|||
|
||||
/** Domain modules */
|
||||
implementation(projects.domain.card)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.tokens)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.wallets)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.feature.referral.domain
|
||||
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.referral.domain.models.ReferralData
|
||||
import com.tangem.feature.referral.domain.models.TokenData
|
||||
|
|
|
|||
|
|
@ -39,12 +39,14 @@ dependencies {
|
|||
/** Domain */
|
||||
implementation(projects.domain.demo)
|
||||
implementation(projects.domain.wallets)
|
||||
implementation(projects.domain.legacy)
|
||||
implementation(projects.domain.wallets.models)
|
||||
implementation(projects.features.referral.domain)
|
||||
|
||||
/** Other libraries */
|
||||
implementation(deps.compose.shimmer)
|
||||
implementation(deps.compose.accompanist.systemUiController)
|
||||
implementation(deps.timber)
|
||||
|
||||
/** DI */
|
||||
implementation(deps.hilt.android)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
package com.tangem.feature.referral.deeplink
|
||||
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.feature.referral.api.deeplink.ReferralDeepLinkHandler
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import timber.log.Timber
|
||||
|
||||
internal class DefaultReferralDeepLinkHandler @AssistedInject constructor(
|
||||
appRouter: AppRouter,
|
||||
getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
|
||||
) : ReferralDeepLinkHandler {
|
||||
|
||||
init {
|
||||
// It is okay here, we are navigating from outside, and there is no other way to getting UserWallet
|
||||
getSelectedWalletSyncUseCase().fold(
|
||||
ifLeft = {
|
||||
Timber.e("Error on getting user wallet: $it")
|
||||
},
|
||||
ifRight = { userWallet ->
|
||||
if (userWallet.cardTypesResolver.isTangemWallet()) {
|
||||
appRouter.push(
|
||||
AppRoute.ReferralProgram(userWalletId = userWallet.walletId),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : ReferralDeepLinkHandler.Factory {
|
||||
override fun create(): DefaultReferralDeepLinkHandler
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue