diff --git a/common/ui/src/main/java/com/tangem/common/ui/userwallet/UserWalletItem.kt b/common/ui/src/main/java/com/tangem/common/ui/userwallet/UserWalletItem.kt index 0d924cd00b..0e9f64511c 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/userwallet/UserWalletItem.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/userwallet/UserWalletItem.kt @@ -7,7 +7,7 @@ import androidx.compose.foundation.layout.* import androidx.compose.material3.CardColors import androidx.compose.material3.Icon import androidx.compose.material3.Text -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -93,7 +93,7 @@ fun UserWalletItem( @Composable private fun NameAndInfo( name: TextReference, - information: TextReference, + information: UserWalletItemUM.Information, balance: UserWalletItemUM.Balance, modifier: Modifier = Modifier, ) { @@ -113,8 +113,28 @@ private fun NameAndInfo( Row( verticalAlignment = Alignment.CenterVertically, ) { + AnimatedContent( + targetState = information, + label = "Information content", + ) { information -> + val informationValue = getInformationValue(information) + + if (informationValue == null) { + TextShimmer( + style = TangemTheme.typography.caption2, + text = "aaaaa", + ) + } else { + Text( + text = informationValue, + style = TangemTheme.typography.caption2, + color = TangemTheme.colors.text.tertiary, + maxLines = 1, + ) + } + } Text( - text = information.resolveReference() + " $DOT ", + text = " $DOT ", style = TangemTheme.typography.caption2, color = TangemTheme.colors.text.tertiary, maxLines = 1, @@ -203,6 +223,15 @@ fun getBalanceValueAndFlickerState(balance: UserWalletItemUM.Balance): Pair DASH_SIGN + UserWalletItemUM.Information.Loading -> null + is UserWalletItemUM.Information.Loaded -> information.value.resolveReference() + } +} + // region Preview @Composable @Preview(showBackground = true, widthDp = 360) @@ -255,6 +284,15 @@ private class UserWalletItemUMPreviewProvider : PreviewParameterProviderNFT senden Eigenschaften Unbetitelte Sammlung + + + %1$d NFTs in der %2$d Sammlung + Tippe hier, um das erste NFT zu erhalten NFT-Sammlungen Die Daten konnten nicht geladen werden diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml index 9bb0a97146..10fafd2e79 100644 --- a/core/res/src/main/res/values-es/strings.xml +++ b/core/res/src/main/res/values-es/strings.xml @@ -443,6 +443,8 @@ Top Ganadores Top Perdedores Tendencias + Staking es la forma más fácil de recibir recompensas por tus criptomonedas. %s + Gana hasta %s APY Acerca de %s %d intercambio @@ -864,6 +866,11 @@ La opción de volver a staking le permite mover sus fondos de un validador a otro sin necesidad de retirarlos. Está a punto de hacer staking con todo su saldo. Recomendamos dejar una cantidad para cubrir las tarifas de la red por unstaking o reclamo de recompensas. Para empezar a hacer staking en TON, realice primero una transacción de salida de cualquier importe - esto activará su billetera. + Es posible que se requieran hasta 0.2 TON además de la tarifa de red para completar la transacción. Cualquier cantidad no utilizada será reembolsada. + Se requieren 0.2 TON para realizar esta operación, además de la tarifa de red. Por favor, recargue su saldo. + 0.2 Ton Reservado + Esta acción cerrará otras posiciones o las cambiará al estado de retiro, de acuerdo con las reglas de la red. + Estado de las posiciones Desbloquee su dinero para retirarlo del proceso de staking. El desbloqueo demora %s minuto. Sus fondos estarán disponibles para su uso después del período de desvinculación de 21 días. La recompensa se retirará junto con los fondos de desvinculación. Sus fondos estarán disponibles para su uso después del período de desvinculación de %s. diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index 5ed0dd7e5d..e26fb2f165 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -443,6 +443,8 @@ Meilleurs Gagnants Top Perdants Tendances + Le staking est le moyen le plus simple de recevoir des récompenses sur votre crypto. %s + Gagnez jusqu\'à %s APY À propos de %s %d échange @@ -516,6 +518,10 @@ Collections NFT Certaines données peuvent ne pas se charger Problèmes de chargement temporaires + + + %1$d NFT dans la collection %2$d + Appuyez ici pour recevoir le premier NFT Collections NFT Impossible de charger les données @@ -873,6 +879,11 @@ L\'option de restaker vous permet de déplacer vos fonds d\'un validateur à un autre sans avoir besoin de les déstaker. Vous êtes sur le point de staker l\'intégralité de votre solde. Nous vous recommandons de laisser un petit montant pour couvrir les frais de réseau pour unstaking ou la réclamation des récompenses. Pour commencer à staker TON, effectuez d\'abord une transaction sortante de n\'importe quel montant — cela activera votre portefeuille. + Jusqu\'à 0,2 TON peuvent être requis en plus des frais de réseau pour terminer la transaction. Tout montant non utilisé sera remboursé. + 0,2 TON requis pour effectuer cette opération, en plus des frais de réseau. Veuillez recharger votre solde. + 0,2 Ton réservés + Cette action fermera d\'autres positions ou les fera passer au statut de retrait, conformément aux règles du réseau. + Statut des positions Débloquez votre argent pour le retirer du processus de staking. Le déverrouillage prend %s. Vos fonds seront disponibles à l\'utilisation après la période de déblocage de 21 jours. La récompense sera retirée en même temps que vos fonds de déblocage. Vos fonds seront disponibles pour utilisation après la période de désengagement %s. diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index 29f843c61b..5abe91349d 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -554,6 +554,9 @@ NFTを送信する 特徴 無題のコレクション + + %1$dコレクションの%2$dNFT + ここをタップして最初のNFTを受け取ります NFTコレクション データを読み込めません @@ -687,6 +690,7 @@ 残高順 トークンを整理する グループ解除 + 詳細はこちら Tangemの通知は設定で有効にできます。 後で有効にする 設定 @@ -912,7 +916,7 @@ 再ステーキングを使うと、ステーキングを解除することなく、あるバリデータから別のバリデータに資金を移動できます。 残高のすべてをステーキングしようとしています。ステーキング解除や報酬請求にかかるネットワーク手数料をカバーするために、少額を残しておくことをお勧めします。 TONでステーキングを開始するには、まず任意の金額の送金を行ってください。これにより、ウォレットがアクティブになります。 - ネットワーク手数料に加え、取引の全ステップを完了するには最大0.2 TONが必要です。未使用分は取引完了後に返金されます。 + 取引を完了するには、ネットワーク手数料に加えて最大0.2TONが必要になる場合があります。未使用分は返金されます。 この操作を続行するには、ネットワーク手数料に加えて0.2 TONが必要です。残高を補充してください。 0.2 TON保留済み このアクションは、ネットワークのルールに従って、他のポジションをクローズするか、引き出しステータスに切り替えます。 diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index d3e55d4136..4c2a4c1617 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -713,6 +713,8 @@ По балансу Упорядочить токены Список + Подробнее + Подключить нотификации Выбрать из галереи Настройки Вы не предоставили доступ к вашей камере @@ -937,9 +939,11 @@ Рестейк позволяет вам переместить средства из одного валидатора в другого без необходимости выхода из стейкинга. Вы собираетесь застейкать весь баланс, рекомендуем оставить небольшую сумму для оплаты комиссии сети при выходе из стейкинга или получении награды. Чтобы начать стейкинг в TON, сначала осуществите исходящую транзакцию на любую сумму — это активирует ваш кошелек. - В дополнение к сетевой комиссии может потребоваться до 0.2 TON для завершения всех этапов транзакции. Неиспользованная часть будет возвращена после выполнения. + До 0.2 TON может потребоваться сверх сетевой комиссии для завершения транзакции. Неиспользованная часть будет возвращена. Для выполнения операции требуется дополнительно 0.2 TON, помимо сетевой комиссии. Пожалуйста, пополните баланс. Зарезервировано 0.2 TON + Это действие закроет другие позиции или переведёт их в статус вывода средств в соответствии с правилами сети. + Статус позиций Разблокируйте свои средства, чтобы вывести их из стейкинга. Разблокировка займёт %s. Ваши средства будут доступны для использования после 21-дневного периода отзыва. Награда будет выведена вместе с вашими выводими средствами. Ваши средства будут доступны после %s периода отзыва. @@ -1153,6 +1157,7 @@ Получить с 10% скидкой Получите доступ к более чем 13 000 криптовалют. Покупайте, продавайте, обменивайте и стейкайте в один клик. Свяжите до трех карт для резервного копирования. Откройте Tangem Wallet + Уведомления о транзакциях Настройки кошелька Tangem Используйте %s или отсканируйте карту/кольцо, чтобы разблокировать доступ к вашему кошельку diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index eeaac91b42..4e052d6444 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -65,6 +65,10 @@ %d device %d devices + + %d token + %d tokens + Disable this option if you don\'t want this card to be used to reset access codes on other cards or rings in this wallet. Please note that this will also prevent you from resetting the access code on this card. Allows you to use this card to reset access code on other cards in this wallet Access code recovery @@ -929,7 +933,7 @@ Restake lets you move your funds from one validator to another without the need to unstake You’re about to stake your entire balance. We recommend leaving a small amount to cover network fees for unstaking or claiming rewards. To start staking in TON, first make an outgoing transaction of any amount — this will activate your wallet. - In addition to the network fee, up to 0.2 TON is needed to complete all steps of the transaction. Unused amount will be returned after it\'s finished. + Up to 0.2 TON may be required in addition to the network fee to complete the transaction. Any unused amount will be refunded. 0.2 TON is required to proceed with this operation, in addition to the network fee. Please top up your balance. 0.2 Ton Reserved This action will close other positions or switch them to withdrawal status, according to network rules. @@ -1215,7 +1219,7 @@ Access 13,000+ cryptocurrencies. Buy, sell, swap, and stake with a single tap.\nLink up to three cards for a backup. Discover Tangem Wallet Stay notified on wallet incoming transactions and Tangem updates. - Push Notifications + Transaction Notifications Wallet settings Tangem Use %s or scan a card/ring to unlock access to your wallet diff --git a/features/details/impl/build.gradle.kts b/features/details/impl/build.gradle.kts index 552f96b756..6522c52450 100644 --- a/features/details/impl/build.gradle.kts +++ b/features/details/impl/build.gradle.kts @@ -15,6 +15,7 @@ dependencies { /* Project - API */ implementation(projects.features.details.api) + implementation(projects.features.wallet.api) implementation(projects.features.disclaimer.api) implementation(projects.features.tester.api) diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewUserWalletListComponent.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewUserWalletListComponent.kt index 7d8f07f26d..fb5a7beb55 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewUserWalletListComponent.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewUserWalletListComponent.kt @@ -77,11 +77,12 @@ internal class PreviewUserWalletListComponent : UserWalletListComponent { } } - private fun getInformation(cardCount: Int): TextReference { - return TextReference.PluralRes( + private fun getInformation(cardCount: Int): UserWalletItemUM.Information.Loaded { + val text = TextReference.PluralRes( id = R.plurals.card_label_card_count, count = cardCount, formatArgs = wrappedList(cardCount), ) + return UserWalletItemUM.Information.Loaded(text) } } \ No newline at end of file diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt index 4b10237030..9f4e9c74ab 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt @@ -1,15 +1,18 @@ package com.tangem.features.details.model +import com.tangem.common.routing.AppRoute import com.tangem.common.ui.userwallet.state.UserWalletItemUM import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model +import com.tangem.core.decompose.navigation.Router +import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase import com.tangem.features.details.entity.UserWalletListUM import com.tangem.features.details.impl.R import com.tangem.features.details.utils.UserWalletSaver -import com.tangem.features.details.utils.UserWalletsFetcher +import com.tangem.features.wallet.utils.UserWalletsFetcher import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -21,13 +24,17 @@ import javax.inject.Inject @ModelScoped internal class UserWalletListModel @Inject constructor( - userWalletsFetcher: UserWalletsFetcher, + userWalletsFetcherFactory: UserWalletsFetcher.Factory, shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase, + private val router: Router, + private val messageSender: UiMessageSender, private val userWalletSaver: UserWalletSaver, override val dispatchers: CoroutineDispatcherProvider, ) : Model() { private val isWalletSavingInProgress: MutableStateFlow = MutableStateFlow(value = false) + private val userWalletsFetcher = userWalletsFetcherFactory + .create(messageSender) { userWalletId -> router.push(AppRoute.WalletSettings(userWalletId)) } val state: MutableStateFlow = MutableStateFlow( value = UserWalletListUM( diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/preview/PreviewAddToPortfolioBSContentProvider.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/preview/PreviewAddToPortfolioBSContentProvider.kt index 4dd21ecb8a..4710cdc8f5 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/preview/PreviewAddToPortfolioBSContentProvider.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/preview/PreviewAddToPortfolioBSContentProvider.kt @@ -4,6 +4,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider import com.tangem.common.ui.userwallet.state.UserWalletItemUM import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.core.ui.components.rows.model.BlockchainRowUM +import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.stringReference import com.tangem.domain.wallets.models.UserWalletId import com.tangem.features.markets.impl.R @@ -25,7 +26,7 @@ internal class PreviewAddToPortfolioBSContentProvider : PreviewParameterProvider val userWallet = UserWalletItemUM( id = UserWalletId("1"), name = stringReference("Wallet 1"), - information = stringReference("3 cards"), + information = UserWalletItemUM.Information.Loaded(TextReference.Str("3 cards")), balance = UserWalletItemUM.Balance.Loading, isEnabled = true, endIcon = UserWalletItemUM.EndIcon.Arrow, diff --git a/features/wallet/api/build.gradle.kts b/features/wallet/api/build.gradle.kts index 8e523e4ddd..eb6e2d71ed 100644 --- a/features/wallet/api/build.gradle.kts +++ b/features/wallet/api/build.gradle.kts @@ -12,7 +12,14 @@ dependencies { /** AndroidX */ implementation(deps.androidx.fragment.ktx) + /** Project - Domain */ + implementation(projects.domain.wallets.models) + /** Core */ implementation(projects.core.ui) implementation(projects.core.decompose) + implementation(projects.common.ui) + + /** Other */ + implementation(deps.kotlin.immutable.collections) } \ No newline at end of file diff --git a/features/wallet/api/src/main/kotlin/com/tangem/features/wallet/utils/UserWalletsFetcher.kt b/features/wallet/api/src/main/kotlin/com/tangem/features/wallet/utils/UserWalletsFetcher.kt new file mode 100644 index 0000000000..6753ea5dec --- /dev/null +++ b/features/wallet/api/src/main/kotlin/com/tangem/features/wallet/utils/UserWalletsFetcher.kt @@ -0,0 +1,16 @@ +package com.tangem.features.wallet.utils + +import com.tangem.common.ui.userwallet.state.UserWalletItemUM +import com.tangem.core.decompose.ui.UiMessageSender +import com.tangem.domain.wallets.models.UserWalletId +import kotlinx.collections.immutable.ImmutableList +import kotlinx.coroutines.flow.Flow + +interface UserWalletsFetcher { + + val userWallets: Flow> + + interface Factory { + fun create(messageSender: UiMessageSender, onWalletClick: (UserWalletId) -> Unit): UserWalletsFetcher + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/di/WalletFeatureModule.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/di/WalletFeatureModule.kt index 22cf0f0df5..74a02c34b7 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/di/WalletFeatureModule.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/di/WalletFeatureModule.kt @@ -4,7 +4,9 @@ import com.tangem.core.decompose.model.Model import com.tangem.feature.wallet.DefaultWalletEntryComponent import com.tangem.feature.wallet.child.organizetokens.model.OrganizeTokensModel import com.tangem.feature.wallet.child.wallet.model.WalletModel +import com.tangem.feature.wallet.utils.DefaultUserWalletsFetcher import com.tangem.features.wallet.WalletEntryComponent +import com.tangem.features.wallet.utils.UserWalletsFetcher import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -19,6 +21,9 @@ internal interface WalletFeatureModule { @Binds fun bindComponentFactory(impl: DefaultWalletEntryComponent.Factory): WalletEntryComponent.Factory + @Binds + fun bindUserWalletsFetcher(impl: DefaultUserWalletsFetcher.Factory): UserWalletsFetcher.Factory + @Binds @IntoMap @ClassKey(WalletModel::class) diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletsFetcher.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/utils/DefaultUserWalletsFetcher.kt similarity index 83% rename from features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletsFetcher.kt rename to features/wallet/impl/src/main/java/com/tangem/feature/wallet/utils/DefaultUserWalletsFetcher.kt index 344068b99b..09cfabc38b 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletsFetcher.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/utils/DefaultUserWalletsFetcher.kt @@ -1,11 +1,8 @@ -package com.tangem.features.details.utils +package com.tangem.feature.wallet.utils import arrow.core.Either -import com.tangem.common.routing.AppRoute import com.tangem.common.ui.userwallet.converter.UserWalletItemUMConverter import com.tangem.common.ui.userwallet.state.UserWalletItemUM -import com.tangem.core.decompose.di.ModelScoped -import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.message.SnackbarMessage @@ -15,6 +12,7 @@ import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.BalanceHidingSettings import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase import com.tangem.domain.core.lce.Lce +import com.tangem.feature.wallet.impl.R import com.tangem.domain.core.lce.lce import com.tangem.domain.core.utils.getOrElse import com.tangem.domain.core.utils.toLce @@ -26,31 +24,32 @@ import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.usecase.GetCardImageUseCase import com.tangem.domain.wallets.usecase.GetWalletsUseCase -import com.tangem.features.details.impl.R +import com.tangem.features.wallet.utils.UserWalletsFetcher import com.tangem.operations.attestation.ArtworkSize +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList -import kotlinx.coroutines.* +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.* -import javax.inject.Inject @Suppress("LongParameterList") -@ModelScoped -internal class UserWalletsFetcher @Inject constructor( +internal class DefaultUserWalletsFetcher @AssistedInject constructor( getWalletsUseCase: GetWalletsUseCase, private val getWalletTotalBalanceUseCase: GetWalletTotalBalanceUseCase, private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, - private val router: Router, - private val messageSender: UiMessageSender, + @Assisted private val onWalletClick: (UserWalletId) -> Unit, + @Assisted private val messageSender: UiMessageSender, private val getCardImageUseCase: GetCardImageUseCase, -) { +) : UserWalletsFetcher { private var loadedArtworks: HashMap = hashMapOf() @OptIn(ExperimentalCoroutinesApi::class) - val userWallets: Flow> = getWalletsUseCase().transformLatest { wallets -> - val uiModels = UserWalletItemUMConverter(onClick = ::navigateToWalletSettings).convertList(wallets) + override val userWallets: Flow> = getWalletsUseCase().transformLatest { wallets -> + val uiModels = UserWalletItemUMConverter(onClick = { onWalletClick(it) }).convertList(wallets) .toImmutableList() emit(uiModels) @@ -122,7 +121,7 @@ internal class UserWalletsFetcher @Inject constructor( balances .map { (userWallet, balance) -> UserWalletItemUMConverter( - onClick = ::navigateToWalletSettings, + onClick = { onWalletClick(it) }, appCurrency = appCurrency, balance = balance, isBalanceHidden = balanceHidingSettings.isBalanceHidden, @@ -133,14 +132,18 @@ internal class UserWalletsFetcher @Inject constructor( .toImmutableList() } - private fun navigateToWalletSettings(userWalletId: UserWalletId) { - router.push(AppRoute.WalletSettings(userWalletId)) - } - sealed class Error { data object UnableToGetAppCurrency : Error() data object UnableToGetBalances : Error() } + + @AssistedFactory + interface Factory : UserWalletsFetcher.Factory { + override fun create( + messageSender: UiMessageSender, + onWalletClick: (UserWalletId) -> Unit, + ): DefaultUserWalletsFetcher + } } \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/WcSelectWalletComponent.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/WcSelectWalletComponent.kt index 152effbda2..febecc22a5 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/WcSelectWalletComponent.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/WcSelectWalletComponent.kt @@ -27,7 +27,9 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle import com.tangem.core.ui.decompose.ComposableBottomSheetComponent +import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.domain.wallets.models.UserWalletId @@ -138,6 +140,7 @@ private fun WcSelectWalletContent( } } +@Suppress("LongMethod") @Composable @Preview(showBackground = true, device = Devices.PIXEL_7_PRO) @Preview(showBackground = true, device = Devices.PIXEL_7_PRO, uiMode = Configuration.UI_MODE_NIGHT_YES) @@ -165,7 +168,7 @@ private fun WcSelectWalletContent_Preview() { UserWalletItemUM( id = UserWalletId("user_wallet_1".encodeToByteArray()), name = stringReference("Tangem 2.0"), - information = stringReference("42 tokens"), + information = getInformation(42), balance = UserWalletItemUM.Balance.Loaded("1 496,34 \$", isFlickering = false), isEnabled = true, onClick = {}, @@ -173,7 +176,7 @@ private fun WcSelectWalletContent_Preview() { UserWalletItemUM( id = UserWalletId("user_wallet_2".encodeToByteArray()), name = stringReference("Tangem White"), - information = stringReference("24 tokens"), + information = getInformation(24), balance = UserWalletItemUM.Balance.Loaded("1 496,34 \$", isFlickering = false), isEnabled = true, onClick = {}, @@ -181,7 +184,7 @@ private fun WcSelectWalletContent_Preview() { UserWalletItemUM( id = UserWalletId("user_wallet_3".encodeToByteArray()), name = stringReference("Bitcoin"), - information = stringReference("1 token"), + information = getInformation(1), balance = UserWalletItemUM.Balance.Loaded("1 496,34 \$", isFlickering = false), isEnabled = true, onClick = {}, @@ -189,7 +192,23 @@ private fun WcSelectWalletContent_Preview() { UserWalletItemUM( id = UserWalletId("user_wallet_4".encodeToByteArray()), name = stringReference("Tangem 1.0"), - information = stringReference("21 tokens"), + information = getInformation(21), + balance = UserWalletItemUM.Balance.Loaded("1 496,34 \$", isFlickering = false), + isEnabled = true, + onClick = {}, + ), + UserWalletItemUM( + id = UserWalletId("user_wallet_4".encodeToByteArray()), + name = stringReference("Tangem 1.0"), + information = UserWalletItemUM.Information.Loading, + balance = UserWalletItemUM.Balance.Loaded("1 496,34 \$", isFlickering = false), + isEnabled = true, + onClick = {}, + ), + UserWalletItemUM( + id = UserWalletId("user_wallet_4".encodeToByteArray()), + name = stringReference("Tangem 1.0"), + information = UserWalletItemUM.Information.Failed, balance = UserWalletItemUM.Balance.Loaded("1 496,34 \$", isFlickering = false), isEnabled = true, onClick = {}, @@ -199,4 +218,13 @@ private fun WcSelectWalletContent_Preview() { }, ) } +} + +private fun getInformation(tokenCount: Int): UserWalletItemUM.Information.Loaded { + val text = TextReference.PluralRes( + id = R.plurals.card_label_token_count, + count = tokenCount, + formatArgs = wrappedList(tokenCount), + ) + return UserWalletItemUM.Information.Loaded(text) } \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcSelectWalletModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcSelectWalletModel.kt index 758d1a0054..d3766e761c 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcSelectWalletModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcSelectWalletModel.kt @@ -6,12 +6,9 @@ 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.domain.appcurrency.GetSelectedAppCurrencyUseCase -import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase -import com.tangem.domain.tokens.GetWalletTotalBalanceUseCase +import com.tangem.domain.tokens.GetTokenListUseCase import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.domain.wallets.usecase.GetCardImageUseCase -import com.tangem.domain.wallets.usecase.GetWalletsUseCase +import com.tangem.features.wallet.utils.UserWalletsFetcher import com.tangem.features.walletconnect.connections.components.WcSelectWalletComponent.WcSelectWalletParams import com.tangem.features.walletconnect.connections.entity.WcAppInfoWalletUM import com.tangem.features.walletconnect.connections.utils.WcUserWalletsFetcher @@ -25,12 +22,9 @@ import javax.inject.Inject @ModelScoped internal class WcSelectWalletModel @Inject constructor( paramsContainer: ParamsContainer, - getWalletsUseCase: GetWalletsUseCase, - getWalletTotalBalanceUseCase: GetWalletTotalBalanceUseCase, - getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, - getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, messageSender: UiMessageSender, - getCardImageUseCase: GetCardImageUseCase, + userWalletsFetcherFactory: UserWalletsFetcher.Factory, + getTokenListUseCase: GetTokenListUseCase, private val router: Router, override val dispatchers: CoroutineDispatcherProvider, ) : Model() { @@ -46,12 +40,9 @@ internal class WcSelectWalletModel @Inject constructor( ) private val userWalletsFetcher = WcUserWalletsFetcher( - getWalletsUseCase = getWalletsUseCase, - getWalletTotalBalanceUseCase = getWalletTotalBalanceUseCase, - getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase, - getBalanceHidingSettingsUseCase = getBalanceHidingSettingsUseCase, + userWalletsFetcherFactory = userWalletsFetcherFactory, + getTokenListUseCase = getTokenListUseCase, messageSender = messageSender, - getCardImageUseCase = getCardImageUseCase, onWalletSelected = ::onWalletSelected, ) diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/utils/WcUserWalletsFetcher.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/utils/WcUserWalletsFetcher.kt index b27f364699..93bded7a85 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/utils/WcUserWalletsFetcher.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/utils/WcUserWalletsFetcher.kt @@ -1,140 +1,57 @@ package com.tangem.features.walletconnect.connections.utils -import arrow.core.Either -import com.tangem.common.ui.userwallet.converter.UserWalletItemUMConverter +import com.tangem.common.ui.R import com.tangem.common.ui.userwallet.state.UserWalletItemUM import com.tangem.core.decompose.di.ModelScoped 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.appcurrency.GetSelectedAppCurrencyUseCase -import com.tangem.domain.appcurrency.error.SelectedAppCurrencyError -import com.tangem.domain.appcurrency.model.AppCurrency -import com.tangem.domain.balancehiding.BalanceHidingSettings -import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase -import com.tangem.domain.core.lce.Lce -import com.tangem.domain.core.lce.lce -import com.tangem.domain.core.utils.getOrElse -import com.tangem.domain.core.utils.toLce -import com.tangem.domain.models.ArtworkModel -import com.tangem.domain.tokens.GetWalletTotalBalanceUseCase -import com.tangem.domain.tokens.error.TokenListError -import com.tangem.domain.tokens.model.TotalFiatBalance -import com.tangem.domain.wallets.models.UserWallet +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.wrappedList +import com.tangem.domain.tokens.GetTokenListUseCase import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.domain.wallets.usecase.GetCardImageUseCase -import com.tangem.domain.wallets.usecase.GetWalletsUseCase -import com.tangem.features.walletconnect.impl.R -import com.tangem.operations.attestation.ArtworkSize +import com.tangem.features.wallet.utils.UserWalletsFetcher import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.map @Suppress("LongParameterList") @ModelScoped internal class WcUserWalletsFetcher( - getWalletsUseCase: GetWalletsUseCase, - private val getWalletTotalBalanceUseCase: GetWalletTotalBalanceUseCase, - private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, - private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, - private val messageSender: UiMessageSender, - private val getCardImageUseCase: GetCardImageUseCase, + userWalletsFetcherFactory: UserWalletsFetcher.Factory, + messageSender: UiMessageSender, + private val getTokenListUseCase: GetTokenListUseCase, private val onWalletSelected: (UserWalletId) -> Unit, ) { - private var loadedArtworks: HashMap = hashMapOf() + private val userWalletsFetcher = userWalletsFetcherFactory.create(messageSender) { onWalletSelected(it) } @OptIn(ExperimentalCoroutinesApi::class) - val userWallets: Flow> = getWalletsUseCase().transformLatest { wallets -> - val uiModels = UserWalletItemUMConverter(onClick = onWalletSelected) - .convertList(wallets) - .toImmutableList() + val userWallets: Flow> = userWalletsFetcher.userWallets + .flatMapLatest { listOfWalletItem -> + val flows = listOfWalletItem.map(::getTokenListFlow) + combine(flows) { it.toList().toImmutableList() } + } - emit(uiModels) - combine( - flow = getSelectedAppCurrencyUseCase().distinctUntilChanged(), - flow2 = getBalanceHidingSettingsUseCase().distinctUntilChanged(), - flow3 = getWalletTotalBalanceUseCase(wallets.map(UserWallet::walletId)).distinctUntilChanged(), - flow4 = loadArtworks(wallets), - ) { maybeAppCurrency, balanceHidingSettings, maybeBalances, artworks -> - val models = createUiModels( - wallets = wallets, - maybeAppCurrency = maybeAppCurrency, - maybeBalances = maybeBalances, - balanceHidingSettings = balanceHidingSettings, - artworks = artworks, - ).getOrElse( - ifLoading = { return@combine }, - ifError = { - val message = resourceReference(R.string.common_unknown_error) - messageSender.send(SnackbarMessage(message)) - - return@combine - }, + private fun getTokenListFlow(walletItem: UserWalletItemUM): Flow { + return getTokenListUseCase.launch(walletItem.id).map { lce -> + val information = lce.fold( + ifLoading = { UserWalletItemUM.Information.Loading }, + ifError = { UserWalletItemUM.Information.Failed }, + ifContent = { tokenList -> tokenCountInfo(tokenList.flattenCurrencies().size) }, ) - - emit(models) - }.collect() - } - - private fun loadArtworks(wallets: List): Flow> { - return flow { - emit(hashMapOf()) // emits right away so the transform doesn't wait for the images' loading to finish - wallets.forEach { wallet -> - val card = wallet.scanResponse.card - val artwork = getCardImageUseCase( - cardId = wallet.cardId, - cardPublicKey = card.cardPublicKey, - size = ArtworkSize.SMALL, - manufacturerName = card.manufacturer.name, - firmwareVersion = card.firmwareVersion.toSdkFirmwareVersion(), - ) - loadedArtworks[wallet.walletId] = artwork - emit(loadedArtworks) - } + walletItem.copy(information = information) } } - private fun createUiModels( - wallets: List, - maybeAppCurrency: Either, - maybeBalances: Lce>, - balanceHidingSettings: BalanceHidingSettings, - artworks: HashMap, - ): Lce> = lce { - val balances = withError( - transform = { Error.UnableToGetBalances }, - block = { - maybeBalances.bindOrNull().orEmpty() - .filterKeys { userWalletId -> wallets.any { it.walletId == userWalletId } } - .mapKeys { entry -> wallets.first { it.walletId == entry.key } } - }, + private fun tokenCountInfo(count: Int): UserWalletItemUM.Information.Loaded { + val text = TextReference.PluralRes( + id = R.plurals.card_label_token_count, + count = count, + formatArgs = wrappedList(count), ) - - val appCurrency = withError( - transform = { Error.UnableToGetAppCurrency }, - block = { maybeAppCurrency.toLce().bind() }, - ) - - balances - .map { (userWallet, balance) -> - UserWalletItemUMConverter( - onClick = onWalletSelected, - appCurrency = appCurrency, - balance = balance, - isBalanceHidden = balanceHidingSettings.isBalanceHidden, - artwork = artworks[userWallet.walletId], - ) - .convert(userWallet) - } - .toImmutableList() - } - - sealed class Error { - - data object UnableToGetAppCurrency : Error() - - data object UnableToGetBalances : Error() + return UserWalletItemUM.Information.Loaded(text) } } \ No newline at end of file