Updated on 2026-08-14
This commit is contained in:
commit
5951e1bc25
40 changed files with 405 additions and 230 deletions
|
|
@ -31,6 +31,7 @@ import com.tangem.domain.onboarding.repository.OnboardingRepository
|
|||
import com.tangem.domain.onramp.FetchHotCryptoUseCase
|
||||
import com.tangem.domain.promo.GetStoryContentUseCase
|
||||
import com.tangem.domain.promo.models.StoryContentIds
|
||||
import com.tangem.domain.quotes.multi.MultiQuoteUpdater
|
||||
import com.tangem.domain.settings.DeleteDeprecatedLogsUseCase
|
||||
import com.tangem.domain.settings.IncrementAppLaunchCounterUseCase
|
||||
import com.tangem.domain.settings.usercountry.FetchUserCountryUseCase
|
||||
|
|
@ -86,6 +87,7 @@ internal class MainViewModel @Inject constructor(
|
|||
private val updateRemoteWalletsInfoUseCase: UpdateRemoteWalletsInfoUseCase,
|
||||
private val sendPushTokenUseCase: SendPushTokenUseCase,
|
||||
private val apiConfigsManager: ApiConfigsManager,
|
||||
private val multiQuoteUpdater: MultiQuoteUpdater,
|
||||
routingFeatureToggle: RoutingFeatureToggle,
|
||||
getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
) : ViewModel() {
|
||||
|
|
@ -116,6 +118,8 @@ internal class MainViewModel @Inject constructor(
|
|||
|
||||
viewModelScope.launch { incrementAppLaunchCounterUseCase() }
|
||||
|
||||
multiQuoteUpdater.subscribe()
|
||||
|
||||
observeFlips()
|
||||
displayBalancesHidingStatusToast()
|
||||
displayHiddenBalancesModalNotification()
|
||||
|
|
@ -131,6 +135,12 @@ internal class MainViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
|
||||
multiQuoteUpdater.unsubscribe()
|
||||
}
|
||||
|
||||
fun checkForUnfinishedBackup() {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
val onboardingScanResponse = onboardingRepository.getUnfinishedFinalizeOnboarding() ?: return@launch
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import com.tangem.domain.tokens.GetNetworkCoinStatusUseCase
|
|||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.onramp.OnrampFeatureToggles
|
||||
import com.tangem.utils.Provider
|
||||
|
|
@ -55,7 +56,7 @@ internal class DefaultRampManager(
|
|||
}
|
||||
|
||||
override suspend fun availableForSell(
|
||||
userWalletId: UserWalletId,
|
||||
userWallet: UserWallet,
|
||||
status: CryptoCurrencyStatus,
|
||||
): Either<ScenarioUnavailabilityReason, Unit> {
|
||||
return either {
|
||||
|
|
@ -68,7 +69,7 @@ internal class DefaultRampManager(
|
|||
catch = { raise(ScenarioUnavailabilityReason.NotSupportedBySellService(status.currency.name)) },
|
||||
)
|
||||
|
||||
val reason = getSendUnavailabilityReason(userWalletId, status)
|
||||
val reason = getSendUnavailabilityReason(userWallet = userWallet, cryptoCurrencyStatus = status)
|
||||
|
||||
ensure(condition = reason is ScenarioUnavailabilityReason.None) {
|
||||
when (reason) {
|
||||
|
|
@ -205,14 +206,13 @@ internal class DefaultRampManager(
|
|||
}
|
||||
|
||||
private suspend fun getSendUnavailabilityReason(
|
||||
userWalletId: UserWalletId,
|
||||
userWallet: UserWallet,
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
): ScenarioUnavailabilityReason {
|
||||
val coinStatus = getNetworkCoinStatusUseCase.invokeSync(
|
||||
userWalletId = userWalletId,
|
||||
userWallet = userWallet,
|
||||
networkId = cryptoCurrencyStatus.currency.network.id,
|
||||
derivationPath = cryptoCurrencyStatus.currency.network.derivationPath,
|
||||
isSingleWalletWithTokens = false,
|
||||
).getOrNull()
|
||||
|
||||
return when {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,9 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.graphics.painter.BitmapPainter
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
|
|
@ -178,32 +180,42 @@ fun CardImage(imageState: UserWalletItemUM.ImageState, modifier: Modifier = Modi
|
|||
)
|
||||
}
|
||||
is UserWalletItemUM.ImageState.Image -> {
|
||||
SubcomposeAsyncImage(
|
||||
modifier = imageModifier,
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.size(
|
||||
width = with(LocalDensity.current) { TangemTheme.dimens.size36.roundToPx() },
|
||||
height = with(LocalDensity.current) { TangemTheme.dimens.size24.roundToPx() },
|
||||
)
|
||||
.data(imageState.artwork.verifiedArtwork?.toByteArray() ?: imageState.artwork.defaultUrl)
|
||||
.crossfade(enable = true)
|
||||
.allowHardware(enable = false)
|
||||
.build(),
|
||||
loading = {
|
||||
RectangleShimmer(
|
||||
modifier = imageModifier,
|
||||
radius = TangemTheme.dimens.size2,
|
||||
)
|
||||
},
|
||||
error = {
|
||||
Image(
|
||||
modifier = imageModifier.then(Modifier.rotate(90F)),
|
||||
imageVector = ImageVector.vectorResource(R.drawable.img_card_wallet_2_gray_22_36),
|
||||
contentDescription = null,
|
||||
)
|
||||
},
|
||||
contentDescription = null,
|
||||
)
|
||||
val verifiedArtwork = imageState.artwork.verifiedArtwork
|
||||
if (verifiedArtwork != null) {
|
||||
Image(
|
||||
modifier = imageModifier,
|
||||
painter = BitmapPainter(verifiedArtwork),
|
||||
contentScale = ContentScale.Fit,
|
||||
contentDescription = null,
|
||||
)
|
||||
} else {
|
||||
SubcomposeAsyncImage(
|
||||
modifier = imageModifier,
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.size(
|
||||
width = with(LocalDensity.current) { TangemTheme.dimens.size36.roundToPx() },
|
||||
height = with(LocalDensity.current) { TangemTheme.dimens.size24.roundToPx() },
|
||||
)
|
||||
.data(imageState.artwork.defaultUrl)
|
||||
.crossfade(enable = true)
|
||||
.allowHardware(enable = false)
|
||||
.build(),
|
||||
loading = {
|
||||
RectangleShimmer(
|
||||
modifier = imageModifier,
|
||||
radius = TangemTheme.dimens.size2,
|
||||
)
|
||||
},
|
||||
error = {
|
||||
Image(
|
||||
modifier = imageModifier.then(Modifier.rotate(90F)),
|
||||
imageVector = ImageVector.vectorResource(R.drawable.img_card_wallet_2_gray_22_36),
|
||||
contentDescription = null,
|
||||
)
|
||||
},
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
package com.tangem.common.ui.userwallet.converter
|
||||
|
||||
import android.graphics.BitmapFactory
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import com.tangem.core.ui.components.artwork.ArtworkUM
|
||||
import com.tangem.domain.models.ArtworkModel
|
||||
import com.tangem.utils.converter.Converter
|
||||
import javax.inject.Inject
|
||||
|
||||
class ArtworkUMConverter @Inject constructor() : Converter<ArtworkModel, ArtworkUM> {
|
||||
|
||||
override fun convert(value: ArtworkModel): ArtworkUM {
|
||||
val bimap = try {
|
||||
value.verifiedArtwork?.let { BitmapFactory.decodeByteArray(it, 0, it.size) }
|
||||
} catch (ignore: Exception) {
|
||||
null
|
||||
}
|
||||
return ArtworkUM(
|
||||
verifiedArtwork = bimap?.asImageBitmap(),
|
||||
defaultUrl = value.defaultUrl,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@ package com.tangem.common.ui.userwallet.converter
|
|||
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.common.ui.userwallet.state.UserWalletItemUM
|
||||
import com.tangem.core.ui.components.artwork.ArtworkUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
|
|
@ -38,6 +37,8 @@ class UserWalletItemUMConverter(
|
|||
private val artwork: ArtworkModel? = null,
|
||||
) : Converter<UserWallet, UserWalletItemUM> {
|
||||
|
||||
private val artworkUMConverter = ArtworkUMConverter()
|
||||
|
||||
override fun convert(value: UserWallet): UserWalletItemUM {
|
||||
return with(value) {
|
||||
UserWalletItemUM(
|
||||
|
|
@ -49,7 +50,7 @@ class UserWalletItemUMConverter(
|
|||
endIcon = endIcon,
|
||||
onClick = { onClick(value.walletId) },
|
||||
imageState = artwork?.let {
|
||||
UserWalletItemUM.ImageState.Image(ArtworkUM(it.verifiedArtwork, it.defaultUrl))
|
||||
UserWalletItemUM.ImageState.Image(artworkUMConverter.convert(it))
|
||||
} ?: UserWalletItemUM.ImageState.Loading,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -220,5 +220,7 @@ sealed class AnalyticsParam {
|
|||
const val COLLECTIONS = "Collections"
|
||||
const val NFT = "Nft"
|
||||
const val NONCE = "Nonce"
|
||||
const val STANDARD = "Standard"
|
||||
const val NO_COLLECTION = "No collection"
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@ object NFTSdkAssetIdentifierConverter : TwoWayConverter<SdkNFTAsset.Identifier,
|
|||
)
|
||||
is SdkNFTAsset.Identifier.Solana -> NFTAsset.Identifier.Solana(
|
||||
tokenAddress = value.tokenAddress,
|
||||
cnft = value.cnft,
|
||||
tokenStandard = value.tokenStandard,
|
||||
)
|
||||
is SdkNFTAsset.Identifier.Unknown -> NFTAsset.Identifier.Unknown
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ object NFTSdkAssetIdentifierConverter : TwoWayConverter<SdkNFTAsset.Identifier,
|
|||
)
|
||||
is NFTAsset.Identifier.Solana -> SdkNFTAsset.Identifier.Solana(
|
||||
tokenAddress = value.tokenAddress,
|
||||
cnft = value.cnft,
|
||||
tokenStandard = value.tokenStandard,
|
||||
)
|
||||
is NFTAsset.Identifier.Unknown -> SdkNFTAsset.Identifier.Unknown
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,10 @@
|
|||
package com.tangem.core.ui.components.artwork
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
|
||||
@Immutable
|
||||
data class ArtworkUM(
|
||||
val verifiedArtwork: ImmutableList<Byte>? = null,
|
||||
val verifiedArtwork: ImageBitmap? = null,
|
||||
val defaultUrl: String,
|
||||
) {
|
||||
|
||||
constructor(bytes: ByteArray?, defaultUrl: String) : this(
|
||||
verifiedArtwork = bytes?.toList()?.toImmutableList(),
|
||||
defaultUrl = defaultUrl,
|
||||
)
|
||||
}
|
||||
)
|
||||
|
|
@ -14,6 +14,7 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
|||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Common implementation of network status fetcher
|
||||
|
|
@ -24,6 +25,7 @@ import javax.inject.Inject
|
|||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Singleton
|
||||
internal class CommonNetworkStatusFetcher @Inject constructor(
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val networksStatusesStore: NetworksStatusesStore,
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ internal class DefaultMultiYieldBalanceFetcher @Inject constructor(
|
|||
val yieldBalances = coroutineScope {
|
||||
requests
|
||||
// TODO: in the future, consider optimizing this part
|
||||
.chunked(size = 16) // StakeKitApi limitation: no more than 16 requests at the same time
|
||||
.chunked(size = 15) // StakeKitApi limitation: no more than 15 requests at the same time
|
||||
.map {
|
||||
async(dispatchers.io) { stakeKitApi.getMultipleYieldBalances(it).bind() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.domain.models.currency.CryptoCurrency
|
|||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
|
|
@ -23,11 +24,11 @@ interface RampStateManager {
|
|||
/**
|
||||
* Check if [CryptoCurrency] is available for sell
|
||||
*
|
||||
* @param userWalletId id of multi-currency wallet
|
||||
* @param status crypto currency status
|
||||
* @param userWallet user wallet
|
||||
* @param status crypto currency status
|
||||
*/
|
||||
suspend fun availableForSell(
|
||||
userWalletId: UserWalletId,
|
||||
userWallet: UserWallet,
|
||||
status: CryptoCurrencyStatus,
|
||||
): Either<ScenarioUnavailabilityReason, Unit>
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ data class NFTAsset(
|
|||
@Serializable
|
||||
data class Solana(
|
||||
val tokenAddress: String,
|
||||
val cnft: Boolean,
|
||||
val tokenStandard: Int?,
|
||||
) : Identifier() {
|
||||
override val stringValue: String = tokenAddress
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,12 @@ package com.tangem.domain.nft.analytics
|
|||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.BLOCKCHAIN
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.STANDARD
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.COLLECTIONS
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.NFT
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.NO_COLLECTION
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.STATE
|
||||
import kotlin.collections.buildMap
|
||||
|
||||
sealed class NFTAnalyticsEvent(
|
||||
event: String,
|
||||
|
|
@ -17,19 +20,21 @@ sealed class NFTAnalyticsEvent(
|
|||
|
||||
data class NFTListScreenOpened(
|
||||
val state: State,
|
||||
val collectionsCount: Int,
|
||||
val allAssetsCount: Int,
|
||||
val noCollectionAssetsCount: Int,
|
||||
) : NFTAnalyticsEvent(
|
||||
event = "NFT List Screen Opened",
|
||||
params = buildMap {
|
||||
put(STATE, state.value)
|
||||
if (state is State.Full) {
|
||||
put(COLLECTIONS, state.collectionsCount.toString())
|
||||
put(NFT, state.assetsCount.toString())
|
||||
}
|
||||
put(COLLECTIONS, collectionsCount.toString())
|
||||
put(NFT, allAssetsCount.toString())
|
||||
put(NO_COLLECTION, noCollectionAssetsCount.toString())
|
||||
},
|
||||
) {
|
||||
sealed class State(val value: String) {
|
||||
data object Empty : State("Empty")
|
||||
data class Full(val assetsCount: Int, val collectionsCount: Int) : State("Full")
|
||||
enum class State(val value: String) {
|
||||
Empty("Empty"),
|
||||
Full("Full"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +57,16 @@ sealed class NFTAnalyticsEvent(
|
|||
object Details {
|
||||
data class ScreenOpened(
|
||||
private val blockchain: String,
|
||||
) : NFTAnalyticsEvent(event = "NFT Details Screen Opened", params = mapOf(BLOCKCHAIN to blockchain))
|
||||
private val standard: String?,
|
||||
) : NFTAnalyticsEvent(
|
||||
event = "NFT Details Screen Opened",
|
||||
params = buildMap {
|
||||
put(BLOCKCHAIN, blockchain)
|
||||
standard?.let {
|
||||
put(STANDARD, it)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
data object ButtonReadMore : NFTAnalyticsEvent(event = "Button - Read More")
|
||||
data object ButtonSeeAll : NFTAnalyticsEvent(event = "Button - See All")
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import arrow.core.Either
|
|||
import arrow.core.raise.Raise
|
||||
import arrow.core.raise.catch
|
||||
import arrow.core.raise.either
|
||||
import arrow.core.right
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
|
||||
|
|
@ -51,17 +52,18 @@ class FetchCurrencyStatusUseCase(
|
|||
return either {
|
||||
val currency = getCurrency(userWalletId, id)
|
||||
|
||||
coroutineScope {
|
||||
return@either coroutineScope {
|
||||
val fetchStatus = async {
|
||||
fetchNetworkStatus(userWalletId, currency.network)
|
||||
}
|
||||
val fetchQuote = async {
|
||||
fetchQuote(currency.id)
|
||||
fetchNetworkStatus(userWalletId = userWalletId, network = currency.network)
|
||||
}
|
||||
|
||||
val fetchQuote = async { fetchQuote(currencyId = currency.id) }
|
||||
|
||||
val fetchStakingBalance = async {
|
||||
fetchStakingBalance(userWalletId, currency, refresh)
|
||||
fetchStakingBalance(userWalletId = userWalletId, cryptoCurrency = currency, refresh = refresh)
|
||||
}
|
||||
awaitAll(fetchStatus, fetchQuote, fetchStakingBalance)
|
||||
|
||||
awaitAll(fetchStatus, fetchQuote, fetchStakingBalance).summarizeResult()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -80,14 +82,14 @@ class FetchCurrencyStatusUseCase(
|
|||
return either {
|
||||
val currency = getPrimaryCurrency(userWalletId, refresh)
|
||||
|
||||
coroutineScope {
|
||||
return@either coroutineScope {
|
||||
val fetchStatus = async {
|
||||
fetchNetworkStatus(userWalletId, currency.network)
|
||||
fetchNetworkStatus(userWalletId = userWalletId, network = currency.network)
|
||||
}
|
||||
val fetchQuote = async {
|
||||
fetchQuote(currency.id)
|
||||
}
|
||||
awaitAll(fetchStatus, fetchQuote)
|
||||
|
||||
val fetchQuote = async { fetchQuote(currencyId = currency.id) }
|
||||
|
||||
awaitAll(fetchStatus, fetchQuote).summarizeResult()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -97,9 +99,7 @@ class FetchCurrencyStatusUseCase(
|
|||
id: CryptoCurrency.ID,
|
||||
): CryptoCurrency {
|
||||
return catch(
|
||||
block = {
|
||||
currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId, id)
|
||||
},
|
||||
block = { currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId = userWalletId, id = id) },
|
||||
) {
|
||||
raise(CurrencyStatusError.DataError(it))
|
||||
}
|
||||
|
|
@ -114,31 +114,27 @@ class FetchCurrencyStatusUseCase(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun Raise<CurrencyStatusError>.fetchNetworkStatus(userWalletId: UserWalletId, network: Network) {
|
||||
singleNetworkStatusFetcher(
|
||||
private suspend fun fetchNetworkStatus(userWalletId: UserWalletId, network: Network): Either<Throwable, Unit> {
|
||||
return singleNetworkStatusFetcher(
|
||||
params = SingleNetworkStatusFetcher.Params(userWalletId = userWalletId, network = network),
|
||||
)
|
||||
.mapLeft { CurrencyStatusError.DataError(it) }
|
||||
.bind()
|
||||
}
|
||||
|
||||
private suspend fun Raise<CurrencyStatusError>.fetchQuote(currencyId: CryptoCurrency.ID) {
|
||||
multiQuoteStatusFetcher(
|
||||
private suspend fun fetchQuote(currencyId: CryptoCurrency.ID): Either<Throwable, Unit> {
|
||||
return multiQuoteStatusFetcher(
|
||||
params = MultiQuoteStatusFetcher.Params(
|
||||
currenciesIds = setOfNotNull(currencyId.rawCurrencyId),
|
||||
appCurrencyId = null,
|
||||
),
|
||||
)
|
||||
.mapLeft { CurrencyStatusError.DataError(it) }
|
||||
.bind()
|
||||
}
|
||||
|
||||
private suspend fun Raise<CurrencyStatusError>.fetchStakingBalance(
|
||||
private suspend fun fetchStakingBalance(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
refresh: Boolean,
|
||||
) {
|
||||
if (tokensFeatureToggles.isStakingLoadingRefactoringEnabled) {
|
||||
): Either<Throwable, Unit> {
|
||||
return if (tokensFeatureToggles.isStakingLoadingRefactoringEnabled) {
|
||||
singleYieldBalanceFetcher(
|
||||
params = SingleYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
|
|
@ -147,11 +143,11 @@ class FetchCurrencyStatusUseCase(
|
|||
),
|
||||
)
|
||||
} else {
|
||||
catch(
|
||||
block = { stakingRepository.fetchSingleYieldBalance(userWalletId, cryptoCurrency, refresh) },
|
||||
) {
|
||||
raise(CurrencyStatusError.DataError(it))
|
||||
}
|
||||
Either.catch { stakingRepository.fetchSingleYieldBalance(userWalletId, cryptoCurrency, refresh) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<Either<Throwable, Unit>>.summarizeResult(): Either<Throwable, Unit> {
|
||||
return firstOrNull { it.isLeft() } ?: Unit.right()
|
||||
}
|
||||
}
|
||||
|
|
@ -194,10 +194,7 @@ class GetCryptoCurrencyActionsUseCase(
|
|||
}
|
||||
|
||||
// region sell
|
||||
rampManager.availableForSell(
|
||||
userWalletId = userWallet.walletId,
|
||||
status = cryptoCurrencyStatus,
|
||||
)
|
||||
rampManager.availableForSell(userWallet = userWallet, status = cryptoCurrencyStatus)
|
||||
.onRight {
|
||||
activeList.add(TokenActionsState.ActionState.Sell(ScenarioUnavailabilityReason.None))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.error.mapper.mapToCurrencyError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.models.requireColdWallet
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
|
|
@ -36,16 +39,21 @@ class GetNetworkCoinStatusUseCase(
|
|||
}
|
||||
|
||||
suspend fun invokeSync(
|
||||
userWalletId: UserWalletId,
|
||||
userWallet: UserWallet,
|
||||
networkId: Network.ID,
|
||||
derivationPath: Network.DerivationPath,
|
||||
isSingleWalletWithTokens: Boolean,
|
||||
): Either<CurrencyStatusError, CryptoCurrencyStatus> {
|
||||
val maybeCurrency = if (isSingleWalletWithTokens) {
|
||||
val userWalletId = userWallet.walletId
|
||||
val cardTypesResolver = userWallet.requireColdWallet().cardTypesResolver // TODO [REDACTED_TASK_KEY]
|
||||
|
||||
val maybeCurrency = if (userWallet.isMultiCurrency) {
|
||||
currencyStatusOperations.getNetworkCoinSync(userWalletId, networkId, derivationPath)
|
||||
} else if (cardTypesResolver.isSingleWalletWithToken()) {
|
||||
currencyStatusOperations.getNetworkCoinForSingleWalletWithTokenSync(userWalletId, networkId)
|
||||
} else {
|
||||
currencyStatusOperations.getNetworkCoinSync(userWalletId, networkId, derivationPath)
|
||||
currencyStatusOperations.getPrimaryCurrencyStatusSync(userWalletId)
|
||||
}
|
||||
|
||||
return maybeCurrency.mapLeft(CurrenciesStatusesOperations.Error::mapToCurrencyError)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,11 +54,6 @@ abstract class BaseCurrencyStatusOperations(
|
|||
|
||||
protected abstract fun getQuotes(id: CryptoCurrency.RawID): Flow<Either<Error, Set<QuoteStatus>>>
|
||||
|
||||
protected abstract fun getNetworksStatuses(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
): EitherFlow<Error, Set<NetworkStatus>>
|
||||
|
||||
protected abstract suspend fun fetchComponents(
|
||||
userWalletId: UserWalletId,
|
||||
networks: Set<Network>,
|
||||
|
|
@ -106,13 +101,7 @@ abstract class BaseCurrencyStatusOperations(
|
|||
flow { emit(Error.EmptyQuotes.left()) }
|
||||
}
|
||||
|
||||
val statusFlow = getNetworksStatuses(userWalletId = userWalletId, network = currency.network)
|
||||
.map { maybeStatuses ->
|
||||
maybeStatuses.flatMap { statuses ->
|
||||
statuses.singleOrNull { it.network == currency.network }?.right()
|
||||
?: Error.EmptyNetworksStatuses.left()
|
||||
}
|
||||
}
|
||||
val statusFlow = getNetworkStatus(userWalletId = userWalletId, network = currency.network)
|
||||
|
||||
val yieldBalanceFlow = getYieldBalance(userWalletId = userWalletId, cryptoCurrency = currency)
|
||||
|
||||
|
|
@ -349,6 +338,15 @@ abstract class BaseCurrencyStatusOperations(
|
|||
.onEmpty { emit(Error.EmptyYieldBalances.left()) }
|
||||
}
|
||||
|
||||
private fun getNetworkStatus(userWalletId: UserWalletId, network: Network): EitherFlow<Error, NetworkStatus> {
|
||||
return singleNetworkStatusSupplier(
|
||||
params = SingleNetworkStatusProducer.Params(userWalletId = userWalletId, network = network),
|
||||
)
|
||||
.map<NetworkStatus, Either<Error, NetworkStatus>>(NetworkStatus::right)
|
||||
.distinctUntilChanged()
|
||||
.onEmpty { emit(Error.EmptyNetworksStatuses.left()) }
|
||||
}
|
||||
|
||||
private suspend fun Raise<Error>.getNetworkCoin(
|
||||
userWalletId: UserWalletId,
|
||||
networkId: Network.ID,
|
||||
|
|
|
|||
|
|
@ -303,18 +303,6 @@ class CachedCurrenciesStatusesOperations(
|
|||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
override fun getNetworksStatuses(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
): EitherFlow<Error, Set<NetworkStatus>> {
|
||||
return singleNetworkStatusSupplier(
|
||||
params = SingleNetworkStatusProducer.Params(userWalletId = userWalletId, network = network),
|
||||
)
|
||||
.map<NetworkStatus, Either<Error, Set<NetworkStatus>>> { setOf(it).right() }
|
||||
.distinctUntilChanged()
|
||||
.onEmpty { emit(Error.EmptyNetworksStatuses.left()) }
|
||||
}
|
||||
|
||||
private fun getYieldBalances(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ data class NFTAssetUM(
|
|||
val value: String,
|
||||
val valueTextEllipsis: TextEllipsis = TextEllipsis.End,
|
||||
val showInfoButton: Boolean,
|
||||
val onClick: () -> Unit = { },
|
||||
val onBlockClick: (() -> Unit)? = null,
|
||||
val onValueClick: (() -> Unit)? = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -27,7 +27,8 @@ internal class NFTDetailsUMFactory(
|
|||
private val onExploreClick: () -> Unit,
|
||||
private val onSendClick: () -> Unit,
|
||||
private val onRefresh: () -> Unit,
|
||||
private val onInfoBlockClick: (title: TextReference, text: TextReference) -> Unit,
|
||||
private val onRegularInfoBlockClick: (title: TextReference, text: TextReference) -> Unit,
|
||||
private val onTokenAddressBlockClick: () -> Unit,
|
||||
) {
|
||||
|
||||
fun getInitialState(nftAsset: NFTAsset, nftCollection: NFTCollection): NFTDetailsUM = NFTDetailsUM(
|
||||
|
|
@ -70,13 +71,13 @@ internal class NFTDetailsUMFactory(
|
|||
label = rarity.label,
|
||||
showDivider = hasSalePrice || hasDescription,
|
||||
onLabelClick = {
|
||||
onInfoBlockClick(
|
||||
onRegularInfoBlockClick(
|
||||
resourceReference(R.string.nft_details_rarity_label),
|
||||
resourceReference(R.string.nft_details_info_rarity_label),
|
||||
)
|
||||
},
|
||||
onRankClick = {
|
||||
onInfoBlockClick(
|
||||
onRegularInfoBlockClick(
|
||||
resourceReference(R.string.nft_details_rarity_rank),
|
||||
resourceReference(R.string.nft_details_info_rarity_rank),
|
||||
)
|
||||
|
|
@ -135,8 +136,8 @@ internal class NFTDetailsUMFactory(
|
|||
title = resourceReference(R.string.nft_details_token_standard),
|
||||
value = contractType,
|
||||
showInfoButton = true,
|
||||
onClick = {
|
||||
onInfoBlockClick(
|
||||
onBlockClick = {
|
||||
onRegularInfoBlockClick(
|
||||
resourceReference(R.string.nft_details_token_standard),
|
||||
resourceReference(R.string.nft_details_info_token_standard),
|
||||
)
|
||||
|
|
@ -147,20 +148,23 @@ internal class NFTDetailsUMFactory(
|
|||
value = id.tokenAddress,
|
||||
valueTextEllipsis = TextEllipsis.Middle,
|
||||
showInfoButton = true,
|
||||
onClick = {
|
||||
onInfoBlockClick(
|
||||
onBlockClick = {
|
||||
onRegularInfoBlockClick(
|
||||
resourceReference(R.string.nft_details_contract_address),
|
||||
resourceReference(R.string.nft_details_info_contract_address),
|
||||
)
|
||||
},
|
||||
onValueClick = {
|
||||
onTokenAddressBlockClick()
|
||||
},
|
||||
),
|
||||
NFTAssetUM.BlockItem(
|
||||
title = resourceReference(R.string.nft_details_token_id),
|
||||
value = id.tokenId.toString(),
|
||||
valueTextEllipsis = TextEllipsis.Middle,
|
||||
showInfoButton = true,
|
||||
onClick = {
|
||||
onInfoBlockClick(
|
||||
onBlockClick = {
|
||||
onRegularInfoBlockClick(
|
||||
resourceReference(R.string.nft_details_token_id),
|
||||
resourceReference(R.string.nft_details_info_token_id),
|
||||
)
|
||||
|
|
@ -170,8 +174,8 @@ internal class NFTDetailsUMFactory(
|
|||
title = resourceReference(R.string.nft_details_chain),
|
||||
value = network.name,
|
||||
showInfoButton = true,
|
||||
onClick = {
|
||||
onInfoBlockClick(
|
||||
onBlockClick = {
|
||||
onRegularInfoBlockClick(
|
||||
resourceReference(R.string.nft_details_chain),
|
||||
resourceReference(R.string.nft_details_info_chain),
|
||||
)
|
||||
|
|
@ -184,19 +188,22 @@ internal class NFTDetailsUMFactory(
|
|||
value = id.tokenAddress,
|
||||
valueTextEllipsis = TextEllipsis.Middle,
|
||||
showInfoButton = true,
|
||||
onClick = {
|
||||
onInfoBlockClick(
|
||||
onBlockClick = {
|
||||
onRegularInfoBlockClick(
|
||||
resourceReference(R.string.nft_details_token_address),
|
||||
resourceReference(R.string.nft_details_info_token_address),
|
||||
)
|
||||
},
|
||||
onValueClick = {
|
||||
onTokenAddressBlockClick()
|
||||
},
|
||||
),
|
||||
NFTAssetUM.BlockItem(
|
||||
title = resourceReference(R.string.nft_details_chain),
|
||||
value = network.name,
|
||||
showInfoButton = true,
|
||||
onClick = {
|
||||
onInfoBlockClick(
|
||||
onBlockClick = {
|
||||
onRegularInfoBlockClick(
|
||||
resourceReference(R.string.nft_details_chain),
|
||||
resourceReference(R.string.nft_details_info_chain),
|
||||
)
|
||||
|
|
@ -209,19 +216,22 @@ internal class NFTDetailsUMFactory(
|
|||
value = id.tokenAddress,
|
||||
valueTextEllipsis = TextEllipsis.Middle,
|
||||
showInfoButton = true,
|
||||
onClick = {
|
||||
onInfoBlockClick(
|
||||
onBlockClick = {
|
||||
onRegularInfoBlockClick(
|
||||
resourceReference(R.string.nft_details_token_address),
|
||||
resourceReference(R.string.nft_details_info_token_address),
|
||||
)
|
||||
},
|
||||
onValueClick = {
|
||||
onTokenAddressBlockClick()
|
||||
},
|
||||
),
|
||||
NFTAssetUM.BlockItem(
|
||||
title = resourceReference(R.string.nft_details_chain),
|
||||
value = network.name,
|
||||
showInfoButton = true,
|
||||
onClick = {
|
||||
onInfoBlockClick(
|
||||
onBlockClick = {
|
||||
onRegularInfoBlockClick(
|
||||
resourceReference(R.string.nft_details_chain),
|
||||
resourceReference(R.string.nft_details_info_chain),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import com.tangem.core.decompose.model.Model
|
|||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
import com.tangem.core.ui.clipboard.ClipboardManager
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
|
|
@ -20,6 +21,7 @@ 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.domain.nft.models.NFTAsset
|
||||
import com.tangem.features.nft.details.NFTDetailsComponent
|
||||
import com.tangem.features.nft.details.entity.NFTAssetUM
|
||||
import com.tangem.features.nft.details.entity.NFTDetailsBottomSheetConfig
|
||||
|
|
@ -49,6 +51,7 @@ internal class NFTDetailsModel @Inject constructor(
|
|||
private val getNFTPriceUseCase: GetNFTPriceUseCase,
|
||||
private val fetchNFTCollectionAssetsUseCase: FetchNFTCollectionAssetsUseCase,
|
||||
private val fetchNFTPriceUseCase: FetchNFTPriceUseCase,
|
||||
private val clipboardManager: ClipboardManager,
|
||||
paramsContainer: ParamsContainer,
|
||||
) : Model() {
|
||||
|
||||
|
|
@ -68,8 +71,9 @@ internal class NFTDetailsModel @Inject constructor(
|
|||
},
|
||||
onExploreClick = ::onExploreClick,
|
||||
onSendClick = ::onSendClick,
|
||||
onInfoBlockClick = ::onInfoBlockClick,
|
||||
onRegularInfoBlockClick = ::onInfoBlockClick,
|
||||
onRefresh = ::onRefresh,
|
||||
onTokenAddressBlockClick = ::onTokenAddressBlockClick,
|
||||
)
|
||||
|
||||
private val _state by lazy {
|
||||
|
|
@ -81,7 +85,17 @@ internal class NFTDetailsModel @Inject constructor(
|
|||
val bottomSheetNavigation: SlotNavigation<NFTDetailsBottomSheetConfig> = SlotNavigation()
|
||||
|
||||
init {
|
||||
analyticsEventHandler.send(NFTAnalyticsEvent.Details.ScreenOpened(params.nftAsset.network.name))
|
||||
analyticsEventHandler.send(
|
||||
NFTAnalyticsEvent.Details.ScreenOpened(
|
||||
blockchain = params.nftAsset.network.name,
|
||||
standard = when (val id = params.nftAsset.id) {
|
||||
is NFTAsset.Identifier.EVM -> id.contractType.name
|
||||
is NFTAsset.Identifier.Solana -> id.tokenStandard?.toString()
|
||||
is NFTAsset.Identifier.TON -> null
|
||||
is NFTAsset.Identifier.Unknown -> null
|
||||
},
|
||||
),
|
||||
)
|
||||
initAppCurrency()
|
||||
subscribeToPriceChanges()
|
||||
}
|
||||
|
|
@ -191,4 +205,15 @@ internal class NFTDetailsModel @Inject constructor(
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun onTokenAddressBlockClick() {
|
||||
val asset = params.nftAsset
|
||||
val addressToCopy = when (val id = asset.id) {
|
||||
is NFTAsset.Identifier.EVM -> id.tokenAddress
|
||||
is NFTAsset.Identifier.Solana -> id.tokenAddress
|
||||
is NFTAsset.Identifier.TON -> id.tokenAddress
|
||||
is NFTAsset.Identifier.Unknown -> return
|
||||
}
|
||||
clipboardManager.setText(text = addressToCopy, isSensitive = false)
|
||||
}
|
||||
}
|
||||
|
|
@ -69,17 +69,14 @@ internal fun NFTDetailsBlocksGroup(
|
|||
NFTDetailsGroupBlock(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(paddingValues)
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null,
|
||||
onClick = item1.onClick,
|
||||
),
|
||||
.padding(paddingValues),
|
||||
title = item1.title,
|
||||
value = stringReference(item1.value),
|
||||
titleEllipsis = item1.titleTextEllipsis,
|
||||
valueEllipsis = item1.valueTextEllipsis,
|
||||
showInfoButton = item1.showInfoButton,
|
||||
onBlockClick = item1.onBlockClick,
|
||||
onValueClick = item1.onValueClick,
|
||||
)
|
||||
if (item2 == null) {
|
||||
Box(
|
||||
|
|
@ -91,17 +88,14 @@ internal fun NFTDetailsBlocksGroup(
|
|||
NFTDetailsGroupBlock(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(paddingValues)
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null,
|
||||
onClick = item2.onClick,
|
||||
),
|
||||
.padding(paddingValues),
|
||||
title = item2.title,
|
||||
value = stringReference(item2.value),
|
||||
titleEllipsis = item2.titleTextEllipsis,
|
||||
valueEllipsis = item2.valueTextEllipsis,
|
||||
showInfoButton = item2.showInfoButton,
|
||||
onBlockClick = item2.onBlockClick,
|
||||
onValueClick = item2.onValueClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -128,6 +122,8 @@ internal fun NFTDetailsGroupBlock(
|
|||
value: TextReference,
|
||||
showInfoButton: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
onBlockClick: (() -> Unit)? = null,
|
||||
onValueClick: (() -> Unit)? = null,
|
||||
titleEllipsis: TextEllipsis = TextEllipsis.End,
|
||||
valueEllipsis: TextEllipsis = TextEllipsis.End,
|
||||
) {
|
||||
|
|
@ -136,7 +132,14 @@ internal fun NFTDetailsGroupBlock(
|
|||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
.fillMaxWidth()
|
||||
.clickable(
|
||||
enabled = onBlockClick != null,
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null,
|
||||
) {
|
||||
onBlockClick?.invoke()
|
||||
},
|
||||
) {
|
||||
EllipsisText(
|
||||
modifier = Modifier
|
||||
|
|
@ -159,6 +162,18 @@ internal fun NFTDetailsGroupBlock(
|
|||
}
|
||||
EllipsisText(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(
|
||||
enabled = onValueClick != null || onBlockClick != null,
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null,
|
||||
) {
|
||||
if (onValueClick != null) {
|
||||
onValueClick.invoke()
|
||||
} else {
|
||||
onBlockClick?.invoke()
|
||||
}
|
||||
}
|
||||
.padding(top = TangemTheme.dimens.spacing4),
|
||||
text = value.resolveReference(),
|
||||
style = TangemTheme.typography.body1,
|
||||
|
|
@ -255,27 +270,27 @@ private class NFTAssetBlocksProvider : CollectionPreviewParameterProvider<Immuta
|
|||
NFTAssetUM.BlockItem(
|
||||
title = stringReference("Tier"),
|
||||
value = "Infinite",
|
||||
showInfoButton = false,
|
||||
showInfoButton = true,
|
||||
),
|
||||
NFTAssetUM.BlockItem(
|
||||
title = stringReference("Phygital Toy"),
|
||||
value = "None",
|
||||
showInfoButton = false,
|
||||
showInfoButton = true,
|
||||
),
|
||||
NFTAssetUM.BlockItem(
|
||||
title = stringReference("Class"),
|
||||
value = "CYBER",
|
||||
showInfoButton = false,
|
||||
showInfoButton = true,
|
||||
),
|
||||
NFTAssetUM.BlockItem(
|
||||
title = stringReference("Accessory"),
|
||||
value = "No accessory",
|
||||
showInfoButton = false,
|
||||
showInfoButton = true,
|
||||
),
|
||||
NFTAssetUM.BlockItem(
|
||||
title = stringReference("Sneakers"),
|
||||
value = "Boots",
|
||||
showInfoButton = false,
|
||||
showInfoButton = true,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package com.tangem.features.onboarding.v2.common.ui
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.painter.BitmapPainter
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
|
|
@ -12,16 +14,26 @@ import com.tangem.features.onboarding.v2.impl.R
|
|||
|
||||
@Composable
|
||||
internal fun WalletCard(artwork: ArtworkUM?, modifier: Modifier = Modifier) {
|
||||
AsyncImage(
|
||||
modifier = modifier,
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(artwork?.verifiedArtwork?.toByteArray() ?: artwork?.defaultUrl)
|
||||
.crossfade(true)
|
||||
.build(),
|
||||
placeholder = painterResource(R.drawable.card_placeholder_black),
|
||||
error = painterResource(R.drawable.card_placeholder_black),
|
||||
fallback = painterResource(R.drawable.card_placeholder_black),
|
||||
contentScale = ContentScale.Fit,
|
||||
contentDescription = null,
|
||||
)
|
||||
val verifiedArtwork = artwork?.verifiedArtwork
|
||||
if (verifiedArtwork != null) {
|
||||
Image(
|
||||
modifier = modifier,
|
||||
painter = BitmapPainter(verifiedArtwork),
|
||||
contentScale = ContentScale.Fit,
|
||||
contentDescription = null,
|
||||
)
|
||||
} else {
|
||||
AsyncImage(
|
||||
modifier = modifier,
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(artwork?.defaultUrl)
|
||||
.crossfade(true)
|
||||
.build(),
|
||||
placeholder = painterResource(R.drawable.card_placeholder_black),
|
||||
error = painterResource(R.drawable.card_placeholder_black),
|
||||
fallback = painterResource(R.drawable.card_placeholder_black),
|
||||
contentScale = ContentScale.Fit,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +1,19 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.model
|
||||
|
||||
import com.tangem.common.ui.userwallet.converter.ArtworkUMConverter
|
||||
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.navigation.Router
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.ui.components.artwork.ArtworkUM
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.onboarding.repository.OnboardingRepository
|
||||
import com.tangem.domain.wallets.usecase.GetCardImageUseCase
|
||||
import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent
|
||||
import com.tangem.features.onboarding.v2.common.analytics.OnboardingEvent
|
||||
import com.tangem.features.onboarding.v2.common.ui.interruptBackupDialog
|
||||
import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletState.FinalizeStage
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.ui.state.OnboardingMultiWalletUM
|
||||
|
|
@ -39,6 +39,7 @@ internal class OnboardingMultiWalletModel @Inject constructor(
|
|||
private val onboardingRepository: OnboardingRepository,
|
||||
private val getCardImageUseCase: GetCardImageUseCase,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
private val artworkUMConverter: ArtworkUMConverter,
|
||||
) : Model() {
|
||||
private val params = paramsContainer.require<OnboardingMultiWalletComponent.Params>()
|
||||
private val _uiState = MutableStateFlow(OnboardingMultiWalletUM())
|
||||
|
|
@ -90,7 +91,7 @@ internal class OnboardingMultiWalletModel @Inject constructor(
|
|||
firmwareVersion = backup.card2.firmwareVersion,
|
||||
)
|
||||
_uiState.update {
|
||||
it.copy(artwork2 = ArtworkUM(artwork.verifiedArtwork, artwork.defaultUrl))
|
||||
it.copy(artwork2 = artworkUMConverter.convert(artwork))
|
||||
}
|
||||
}
|
||||
_uiState.value.artwork3 == null && backup.card3 != null -> {
|
||||
|
|
@ -103,7 +104,7 @@ internal class OnboardingMultiWalletModel @Inject constructor(
|
|||
firmwareVersion = backup.card3.firmwareVersion,
|
||||
)
|
||||
_uiState.update {
|
||||
it.copy(artwork3 = ArtworkUM(artwork.verifiedArtwork, artwork.defaultUrl))
|
||||
it.copy(artwork3 = artworkUMConverter.convert(artwork))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -179,7 +180,7 @@ internal class OnboardingMultiWalletModel @Inject constructor(
|
|||
)
|
||||
|
||||
_uiState.update {
|
||||
it.copy(artwork1 = ArtworkUM(artwork.verifiedArtwork, artwork.defaultUrl))
|
||||
it.copy(artwork1 = artworkUMConverter.convert(artwork))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import com.tangem.features.onboarding.v2.common.ui.RefreshButton
|
|||
import com.tangem.features.onboarding.v2.common.ui.WalletCard
|
||||
import com.tangem.features.onboarding.v2.impl.R
|
||||
import com.valentinilk.shimmer.shimmer
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Composable
|
||||
fun OnboardingNoteTopUpHeader(
|
||||
|
|
@ -95,7 +94,7 @@ private fun OnboardinNoteTopUpHeaderPreview() {
|
|||
TangemThemePreview {
|
||||
OnboardingNoteTopUpHeader(
|
||||
balance = "0.00000001 BTC",
|
||||
cardArtwork = ArtworkUM(null as ImmutableList<Byte>?, ""),
|
||||
cardArtwork = ArtworkUM(null, ""),
|
||||
onRefreshBalanceClick = {},
|
||||
isRefreshing = false,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
package com.tangem.features.onboarding.v2.note.impl.model
|
||||
|
||||
import com.arkivanov.decompose.router.stack.StackNavigation
|
||||
import com.tangem.common.ui.userwallet.converter.ArtworkUMConverter
|
||||
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.navigation.Router
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.ui.components.artwork.ArtworkUM
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.usecase.GetCardImageUseCase
|
||||
import com.tangem.features.onboarding.v2.common.ui.exitOnboardingDialog
|
||||
|
|
@ -29,6 +29,7 @@ internal class OnboardingNoteModel @Inject constructor(
|
|||
private val router: Router,
|
||||
private val messageSender: UiMessageSender,
|
||||
private val getCardImageUseCase: GetCardImageUseCase,
|
||||
private val artworkUMConverter: ArtworkUMConverter,
|
||||
) : Model() {
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
|
|
@ -98,7 +99,7 @@ internal class OnboardingNoteModel @Inject constructor(
|
|||
firmwareVersion = cardInfo.firmwareVersion.toSdkFirmwareVersion(),
|
||||
)
|
||||
_uiState.update {
|
||||
it.copy(cardArtwork = ArtworkUM(artwork.verifiedArtwork, artwork.defaultUrl))
|
||||
it.copy(cardArtwork = artworkUMConverter.convert(artwork))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,9 +59,9 @@ internal class OnrampTokenListModel @Inject constructor(
|
|||
val state: StateFlow<TokenListUM> = tokenListUMController.state
|
||||
|
||||
private val params: OnrampTokenListComponent.Params = paramsContainer.require()
|
||||
private val scanResponse by lazy {
|
||||
private val userWallet by lazy {
|
||||
getWalletsUseCase.invokeSync().first { it.walletId == params.userWalletId }
|
||||
.requireColdWallet().scanResponse // TODO [REDACTED_TASK_KEY]
|
||||
.requireColdWallet() // TODO [REDACTED_TASK_KEY]
|
||||
}
|
||||
|
||||
init {
|
||||
|
|
@ -229,16 +229,13 @@ internal class OnrampTokenListModel @Inject constructor(
|
|||
return when (params.filterOperation) {
|
||||
OnrampOperation.BUY -> {
|
||||
rampStateManager.availableForBuy(
|
||||
scanResponse = scanResponse,
|
||||
scanResponse = userWallet.scanResponse,
|
||||
userWalletId = params.userWalletId,
|
||||
cryptoCurrency = status.currency,
|
||||
).isAvailable()
|
||||
}
|
||||
OnrampOperation.SELL -> {
|
||||
rampStateManager.availableForSell(
|
||||
userWalletId = params.userWalletId,
|
||||
status = status,
|
||||
).isRight()
|
||||
rampStateManager.availableForSell(userWallet = userWallet, status = status).isRight()
|
||||
}
|
||||
OnrampOperation.SWAP -> {
|
||||
val isAvailable = rampStateManager.availableForSwap(
|
||||
|
|
|
|||
|
|
@ -277,14 +277,18 @@ internal class SendModel @Inject constructor(
|
|||
isSingleWalletWithToken: Boolean,
|
||||
isMultiCurrency: Boolean,
|
||||
): Flow<Either<CurrencyStatusError, CryptoCurrencyStatus>> {
|
||||
return if (isMultiCurrency) {
|
||||
getSingleCryptoCurrencyStatusUseCase.invokeMultiWallet(
|
||||
return when {
|
||||
isSingleWalletWithToken -> getSingleCryptoCurrencyStatusUseCase.invokeMultiWallet(
|
||||
userWalletId = userWalletId,
|
||||
currencyId = cryptoCurrency.id,
|
||||
isSingleWalletWithTokens = isSingleWalletWithToken,
|
||||
isSingleWalletWithTokens = true,
|
||||
)
|
||||
} else {
|
||||
getSingleCryptoCurrencyStatusUseCase.invokeSingleWallet(userWalletId = userWalletId)
|
||||
isMultiCurrency -> getSingleCryptoCurrencyStatusUseCase.invokeMultiWallet(
|
||||
userWalletId = userWalletId,
|
||||
currencyId = cryptoCurrency.id,
|
||||
isSingleWalletWithTokens = false,
|
||||
)
|
||||
else -> getSingleCryptoCurrencyStatusUseCase.invokeSingleWallet(userWalletId = userWalletId)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -165,6 +165,7 @@ internal class StakingModel @Inject constructor(
|
|||
}
|
||||
|
||||
private var isInitialInfoAnalyticSent: Boolean = false
|
||||
private var isBalanceUpdatedAfterStart: Boolean = false
|
||||
|
||||
private val balanceUpdater by lazy(LazyThreadSafetyMode.NONE) {
|
||||
stakingBalanceUpdater.create(
|
||||
|
|
@ -421,7 +422,7 @@ internal class StakingModel @Inject constructor(
|
|||
override fun onRefreshSwipe(isRefreshing: Boolean) {
|
||||
stateController.update(SetInitialLoadingStateTransformer(isRefreshing))
|
||||
coroutineScope.launch {
|
||||
balanceUpdater.updatePullToRefresh()
|
||||
balanceUpdater.partialUpdate()
|
||||
}.invokeOnCompletion {
|
||||
stateController.update(SetInitialLoadingStateTransformer(false))
|
||||
}
|
||||
|
|
@ -1011,7 +1012,11 @@ internal class StakingModel @Inject constructor(
|
|||
when {
|
||||
isInitState() -> {
|
||||
updateInitialData(status)
|
||||
balanceUpdater.updateAfterNavigationToInitial()
|
||||
|
||||
if (!isBalanceUpdatedAfterStart) {
|
||||
isBalanceUpdatedAfterStart = true
|
||||
balanceUpdater.partialUpdate()
|
||||
}
|
||||
}
|
||||
isAssentState() -> {
|
||||
getFee()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.helpers
|
||||
|
||||
import com.tangem.domain.staking.FetchActionsUseCase
|
||||
import com.tangem.domain.staking.FetchStakingYieldBalanceUseCase
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionStatus
|
||||
import com.tangem.domain.tokens.FetchCurrencyStatusUseCase
|
||||
|
|
@ -22,6 +23,7 @@ internal class StakingBalanceUpdater @AssistedInject constructor(
|
|||
private val fetchActionsUseCase: FetchActionsUseCase,
|
||||
private val txHistoryContentUpdateEmitter: TxHistoryContentUpdateEmitter,
|
||||
private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase,
|
||||
private val fetchStakingYieldBalanceUseCase: FetchStakingYieldBalanceUseCase,
|
||||
@DelayedWork private val coroutineScope: CoroutineScope,
|
||||
@Assisted private val userWallet: UserWallet,
|
||||
@Assisted private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
|
|
@ -37,6 +39,13 @@ internal class StakingBalanceUpdater @AssistedInject constructor(
|
|||
network = cryptoCurrencyStatus.currency.network,
|
||||
)
|
||||
},
|
||||
async {
|
||||
fetchStakingYieldBalanceUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency,
|
||||
isRefactoringEnabled = true,
|
||||
)
|
||||
},
|
||||
// we should update tx history and network for new balances
|
||||
async {
|
||||
fetchCurrencyStatus(delayMillis = BALANCE_UPDATE_DELAY)
|
||||
|
|
@ -51,7 +60,7 @@ internal class StakingBalanceUpdater @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun updatePullToRefresh() {
|
||||
suspend fun partialUpdate() {
|
||||
coroutineScope {
|
||||
listOf(
|
||||
async {
|
||||
|
|
@ -64,12 +73,6 @@ internal class StakingBalanceUpdater @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun updateAfterNavigationToInitial() {
|
||||
coroutineScope {
|
||||
async { updateStakingActions() }.await()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchCurrencyStatus(delayMillis: Long = 0L) {
|
||||
delay(delayMillis)
|
||||
fetchCurrencyStatusUseCase(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.feature.walletsettings.analytics
|
||||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.STATUS
|
||||
|
||||
internal sealed class WalletSettingsAnalyticEvents(
|
||||
category: String = "Settings / Wallet",
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
) : AnalyticsEvent(category, event, params) {
|
||||
|
||||
data class NftToggleSwitch(val enabled: AnalyticsParam.OnOffState) : WalletSettingsAnalyticEvents(
|
||||
event = "NFT toggle switch",
|
||||
params = mapOf(STATUS to enabled.value),
|
||||
)
|
||||
}
|
||||
|
|
@ -6,6 +6,8 @@ import com.arkivanov.decompose.router.slot.SlotNavigation
|
|||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.OnOffState.Off
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.OnOffState.On
|
||||
import com.tangem.core.analytics.utils.AnalyticsContextProxy
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
|
|
@ -29,6 +31,7 @@ import com.tangem.domain.wallets.models.isMultiCurrency
|
|||
import com.tangem.domain.wallets.models.requireColdWallet
|
||||
import com.tangem.domain.wallets.usecase.*
|
||||
import com.tangem.feature.walletsettings.analytics.Settings
|
||||
import com.tangem.feature.walletsettings.analytics.WalletSettingsAnalyticEvents
|
||||
import com.tangem.feature.walletsettings.component.WalletSettingsComponent
|
||||
import com.tangem.feature.walletsettings.entity.DialogConfig
|
||||
import com.tangem.feature.walletsettings.entity.NetworksAvailableForNotificationBSConfig
|
||||
|
|
@ -214,6 +217,11 @@ internal class WalletSettingsModel @Inject constructor(
|
|||
} else {
|
||||
disableWalletNFTUseCase.invoke(params.userWalletId)
|
||||
}
|
||||
analyticsEventHandler.send(
|
||||
WalletSettingsAnalyticEvents.NftToggleSwitch(
|
||||
enabled = if (isChecked) On else Off,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -238,19 +238,31 @@ internal class WalletContentClickIntentsImplementor @Inject constructor(
|
|||
|
||||
override fun onNFTClick(userWallet: UserWallet) {
|
||||
val selectedWallet = stateHolder.getSelectedWallet() as? WalletState.MultiCurrency.Content ?: return
|
||||
val analyticsState = when (val nftState = selectedWallet.nftState) {
|
||||
is WalletNFTItemUM.Content -> NFTAnalyticsEvent.NFTListScreenOpened.State.Full(
|
||||
assetsCount = nftState.assetsCount,
|
||||
collectionsCount = nftState.collectionsCount,
|
||||
)
|
||||
is WalletNFTItemUM.Empty -> NFTAnalyticsEvent.NFTListScreenOpened.State.Empty
|
||||
when (val state = selectedWallet.nftState) {
|
||||
is WalletNFTItemUM.Content -> {
|
||||
analyticsEventHandler.send(
|
||||
NFTAnalyticsEvent.NFTListScreenOpened(
|
||||
state = NFTAnalyticsEvent.NFTListScreenOpened.State.Full,
|
||||
allAssetsCount = state.allAssetsCount,
|
||||
collectionsCount = state.collectionsCount,
|
||||
noCollectionAssetsCount = state.noCollectionAssetsCount,
|
||||
),
|
||||
)
|
||||
}
|
||||
is WalletNFTItemUM.Empty -> {
|
||||
analyticsEventHandler.send(
|
||||
NFTAnalyticsEvent.NFTListScreenOpened(
|
||||
state = NFTAnalyticsEvent.NFTListScreenOpened.State.Empty,
|
||||
allAssetsCount = 0,
|
||||
collectionsCount = 0,
|
||||
noCollectionAssetsCount = 0,
|
||||
),
|
||||
)
|
||||
}
|
||||
is WalletNFTItemUM.Failed,
|
||||
is WalletNFTItemUM.Hidden,
|
||||
is WalletNFTItemUM.Loading,
|
||||
-> null
|
||||
}
|
||||
analyticsState?.let {
|
||||
analyticsEventHandler.send(NFTAnalyticsEvent.NFTListScreenOpened(analyticsState))
|
||||
-> Unit
|
||||
}
|
||||
|
||||
router.openNFT(userWallet)
|
||||
|
|
|
|||
|
|
@ -123,7 +123,8 @@ internal object WalletScreenPreviewData {
|
|||
nftState = WalletNFTItemUM.Content(
|
||||
previews = persistentListOf(WalletNFTItemUM.Content.CollectionPreview.Image("img1")),
|
||||
collectionsCount = 1,
|
||||
assetsCount = 3,
|
||||
allAssetsCount = 3,
|
||||
noCollectionAssetsCount = 0,
|
||||
isFlickering = false,
|
||||
onItemClick = { },
|
||||
),
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ sealed class WalletNFTItemUM {
|
|||
data class Content(
|
||||
val previews: ImmutableList<CollectionPreview>,
|
||||
val collectionsCount: Int,
|
||||
val assetsCount: Int,
|
||||
val allAssetsCount: Int,
|
||||
val noCollectionAssetsCount: Int,
|
||||
val isFlickering: Boolean,
|
||||
val onItemClick: () -> Unit,
|
||||
) : WalletNFTItemUM() {
|
||||
|
|
|
|||
|
|
@ -52,8 +52,24 @@ internal class SetNFTCollectionsTransformer(
|
|||
.toPersistentList()
|
||||
},
|
||||
collectionsCount = collections.size,
|
||||
assetsCount = collections
|
||||
.sumOf { it.count },
|
||||
allAssetsCount = collections.sumOf { it.count },
|
||||
noCollectionAssetsCount = collections.sumOf { collection ->
|
||||
when (val collectionId = collection.id) {
|
||||
is NFTCollection.Identifier.Solana ->
|
||||
collection
|
||||
.count
|
||||
.takeIf { collectionId.collectionAddress == null }
|
||||
?: 0
|
||||
is NFTCollection.Identifier.TON ->
|
||||
collection
|
||||
.count
|
||||
.takeIf { collectionId.contractAddress == null }
|
||||
?: 0
|
||||
is NFTCollection.Identifier.EVM,
|
||||
is NFTCollection.Identifier.Unknown,
|
||||
-> 0
|
||||
}
|
||||
},
|
||||
isFlickering = false,
|
||||
onItemClick = onItemClick,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ private fun WalletNFTItemContent(state: WalletNFTItemUM.Content, onClick: () ->
|
|||
Text(
|
||||
text = stringResourceSafe(
|
||||
id = R.string.nft_wallet_count,
|
||||
state.assetsCount,
|
||||
state.allAssetsCount,
|
||||
state.collectionsCount,
|
||||
),
|
||||
style = TangemTheme.typography.caption2.applyBladeBrush(
|
||||
|
|
@ -411,8 +411,9 @@ private class WalletNFTItemProvider : CollectionPreviewParameterProvider<WalletN
|
|||
previews = persistentListOf(
|
||||
CollectionPreview.Image("img1"),
|
||||
),
|
||||
assetsCount = 125,
|
||||
allAssetsCount = 125,
|
||||
collectionsCount = 11,
|
||||
noCollectionAssetsCount = 0,
|
||||
isFlickering = true,
|
||||
onItemClick = { },
|
||||
),
|
||||
|
|
@ -421,8 +422,9 @@ private class WalletNFTItemProvider : CollectionPreviewParameterProvider<WalletN
|
|||
CollectionPreview.Image("img1"),
|
||||
CollectionPreview.Image("img2"),
|
||||
),
|
||||
assetsCount = 125,
|
||||
allAssetsCount = 125,
|
||||
collectionsCount = 11,
|
||||
noCollectionAssetsCount = 0,
|
||||
isFlickering = false,
|
||||
onItemClick = { },
|
||||
),
|
||||
|
|
@ -432,8 +434,9 @@ private class WalletNFTItemProvider : CollectionPreviewParameterProvider<WalletN
|
|||
CollectionPreview.Image("img2"),
|
||||
CollectionPreview.Image("img3"),
|
||||
),
|
||||
assetsCount = 125,
|
||||
allAssetsCount = 125,
|
||||
collectionsCount = 11,
|
||||
noCollectionAssetsCount = 0,
|
||||
isFlickering = false,
|
||||
onItemClick = { },
|
||||
),
|
||||
|
|
@ -444,8 +447,9 @@ private class WalletNFTItemProvider : CollectionPreviewParameterProvider<WalletN
|
|||
CollectionPreview.Image("img3"),
|
||||
CollectionPreview.Image("img4"),
|
||||
),
|
||||
assetsCount = 125,
|
||||
allAssetsCount = 125,
|
||||
collectionsCount = 11,
|
||||
noCollectionAssetsCount = 0,
|
||||
isFlickering = false,
|
||||
onItemClick = { },
|
||||
),
|
||||
|
|
@ -456,9 +460,10 @@ private class WalletNFTItemProvider : CollectionPreviewParameterProvider<WalletN
|
|||
CollectionPreview.Image("img3"),
|
||||
CollectionPreview.More,
|
||||
),
|
||||
assetsCount = 125,
|
||||
allAssetsCount = 125,
|
||||
collectionsCount = 11,
|
||||
isFlickering = true,
|
||||
noCollectionAssetsCount = 0,
|
||||
onItemClick = { },
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import com.tangem.core.decompose.model.ParamsContainer
|
|||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.core.ui.clipboard.ClipboardManager
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.core.lce.Lce
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.tokens.GetNetworkCoinStatusUseCase
|
||||
|
|
@ -132,11 +131,9 @@ internal class WcSendTransactionModel @Inject constructor(
|
|||
network: Network,
|
||||
): Either<CurrencyStatusError, CryptoCurrencyStatus> {
|
||||
return getNetworkCoinUseCase.invokeSync(
|
||||
userWalletId = userWallet.walletId,
|
||||
userWallet = userWallet,
|
||||
networkId = network.id,
|
||||
derivationPath = network.derivationPath,
|
||||
isSingleWalletWithTokens = userWallet is UserWallet.Cold &&
|
||||
userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
# https://github.com/tangem/tangem-sdk-android/
|
||||
# https://github.com/tangem/vico
|
||||
|
||||
tangemBlockchainSdk = "develop-1093"
|
||||
tangemBlockchainSdk = "develop-1097"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "develop-484"
|
||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 034ad04fdf0810e338cb8898f50554874cec96d7
|
||||
Subproject commit bc4cd430853ca794614b8d5163c9b28b9ca26112
|
||||
Loading…
Add table
Add a link
Reference in a new issue