diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 77fd07304f..194da3dfb2 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -66,6 +66,7 @@ Одобрение Внимание Баланс: %s + Баланс биометрическую аутентификацию биометрией Купить @@ -85,9 +86,11 @@ Включено Ошибка Обменять - Посмотреть историю транзакций Обозреватель + Посмотреть историю + Посмотреть историю транзакций Обозреватель + Комиссия Сетевые комиссии за транзакции используются для поддержки безопасности сети, поощрения валидаторов, выделения ресурсов и определения приоритета транзакции. Свое Быстро @@ -126,7 +129,6 @@ Отправить Успешно Обмен - Комиссия условия участия Ошибка транзакции Транзакции @@ -192,14 +194,18 @@ Мои токены У вас нет добавленных токенов. Добавьте токены для обмена Недоступен для обмена с %s + Статус Провайдеры проводят транзакции, обеспечивая плавный и эффективный обмен токенами Выберите провайдера Чтобы узнать причину, посетите сайт провайдера Операция не выполнена провайдером Посетите сайт провайдера для проверки Провайдер: требуется верификация + Получение наилучших курсов... Провайдер Лучший курс + Доступно с %s + Недоступно для этой пары Требуется разрешение Информация ниже не является обязательной. Вы можете стереть её, если хотите. Расскажите, каких функций вам не хватает, и мы постараемся вам помочь. @@ -273,7 +279,6 @@ Введенные коды доступа не совпадают Вы добавили одну резервную карту. После того, как процесс будет завершен, Вы больше не сможете добавить карт. Если у Вас есть еще одна карта, добавьте ее в резервную копию. Хотите продолжить? Процесс резервного копирования почти завершен. Вы не можете выйти из него сейчас. - Баланс Добавить резервную карту Сканировать карту #%d Создать резервную копию @@ -634,12 +639,18 @@ Нравится Понятно! Очень круто! + Обновить Вы находитесь в режиме демо Демо режим включен Отсканированная вами карта является картой разработчика. Не используйте ее для создания своего кошелька. Не для пользователя! Cеть %1$s использует концепцию экзистенциального депозита. Если баланс вашего счета будет ниже %2$s, то он будет деактивирован, а средства на счете уничтожены. Для работы с сетью необходим депозит + У вас в списке нет монет доступных для обмена с %s + Нет доступных токенов для обмена + Cервис временно недоступен + Пожалуйста, измените сумму для обмена + Сумма для обмена должна быть не менее %s Возможно, данная карта - образец или подделка Ошибка проверки подлинности На этой карте осталось всего %s подписей. Вам следует вывести все ваши средства. diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index ffc1858e33..8d4ff0b882 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -64,6 +64,7 @@ Approval Attention Balance: %s + Balance biometric authentication biometrics Buy @@ -84,8 +85,10 @@ Error Exchange Explore + Explore history Explore transaction history Explorer + Fee Network transaction fees are used to support network security, incentivize validators, allocate resources, and determine transaction priority. Custom Fast @@ -125,7 +128,6 @@ Submit Success Swap - Fee terms and conditions Transaction failed Transactions @@ -186,14 +188,16 @@ Terms of Service Oops, the current version of the application is not ready to work with this card, please check for updates. You have used a card from another wallet. Tap the card associated with this wallet - You Receive - You Send + You receive + You send My tokens - You don\'t have any added tokens yet. Add tokens via Market to swap - Unavailable for swap from %s - Providers facilitate transactions, ensuring smooth and efficient token exchanges - Choose Provider + You haven\'t added any tokens yet. Add tokens via Market to swap + Cannot be swapped for %s + Status + Providers facilitate transactions, ensuring smooth and efficient token swaps + Choose provider Estimated amount + Exchange by %s Visit provider’s website to see why Operation failed by provider Visit provider’s website for verification @@ -216,7 +220,8 @@ Go to provider Provider Best rate - Exchange by %s + Available from %s + Unavailable for this pair Permission Needed The following information is optional. You can erase it if you don\'t want to share it. Tell us what functions you are missing, and we will try to help you. @@ -291,7 +296,6 @@ Entered access code didn\'t match the initial access code You\'ve added one backup card. When backup process is finished you can\'t add more backup cards. If you have one more card, add it to backup. Do you like to continue the backup process? The backup process is partly complete. You can\'t exit it now. - Balance Add a backup card Scan the card #%d Backup now @@ -437,7 +441,6 @@ Invalid Memo. It won\'t be added to the transaction. Tag Memo - Insufficient funds for transfer Include fee Low Normal @@ -513,7 +516,7 @@ Meet Tangem Exchange, buy NFT\'s, make loans and deposits in more than 100 different decentralized services Web 3.0 Compatible - Approvals are considered an industry standard across all decentralized exchanges and protect your wallet from being accessed by a smart contract without your permission. By design, smart contracts can\'t access your tokens unless you approve access from your end. By \"unlocking\" your tokens, you are give permission to the 1inch smart contract to spend your assets. The miners of the network are compensated with a gas fee (paid by you) to record this action on the blockchain. Once permission has been granted you will be able to swap your token. + All decentralized exchanges require approvals to prevent smart contracts from accessing your wallet without your permission. By design, smart contracts can\'t access your tokens unless you approve. By \"unlocking\" your tokens, you authorize the 1-inch smart contract to spend them. The network\'s miners receive a gas fee (paid by you) to record this action on the blockchain. You can swap your token after giving approval. Approve Error: %s There was an error. Please try again. @@ -521,25 +524,25 @@ High price impact! Swapping this amount of selected tokens will cause a significant price impact and reduce your outcome. Insufficient funds - Not enough funds for fee in your %1$s wallet to create a transaction. Top up your %2$s wallet first. + Insufficient funds in your %1$s wallet to cover fees. Top up your %2$s wallet first. Transaction in progress... Waiting Approve Current transaction - The token approval network fee will be charged to confirm that you are the one allowing your token to be used for the exchange. + The network will charge a token approval fee to verify that you are authorizing the use of your token for the swap. Give Permission Specify the approve limit for the selected token Amount %s Spender - Your Wallet - To continue you need to allow 1inch smart contracts to use your %s + Your wallet + To continue, grant 1inch smart contracts permission to use your %s Unlimited - View in Explorer - In progress You swap You receive + View in Explorer + In progress Swap - Swap of %s to + Swap %s for Quotes include an additional Tangem commission of %s. This helps us deliver a top-of-the-line product. Other tokens Choose token @@ -661,12 +664,20 @@ Like it Ok, Got it! Really cool! + Refresh You are currently in the Demo mode Demo mode active The card you scanned is a developer card. Do not use it to create your wallet. Not for users! %1$s network requires an Existential Deposit. If your account drops below %2$s, it will be deactivated, and any remaining funds will be destroyed. Network requires Existential Deposit + You do not have any %s exchangeable coins in your list + No available tokens to swap + To make a transaction you need to deposit some %1$s %2$s + Unable to cover %s fee + Service temporary unavailable + Please change the amount to swap + The amount to swap must be at least %s This card might be a production sample or counterfeit Authenticity check failed Only %s signatures are left on this card. You must withdraw all of your funds. diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/NetworkOperations.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/NetworkOperations.kt index f5a1bf13df..ae8d8d9373 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/NetworkOperations.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/NetworkOperations.kt @@ -26,6 +26,7 @@ internal fun getNetwork( name = blockchain.fullName, isTestnet = blockchain.isTestnet(), derivationPath = getNetworkDerivationPath(blockchain, extraDerivationPath, derivationStyleProvider), + currencySymbol = blockchain.currency, standardType = getNetworkStandardType(blockchain), ) } diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/Network.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/Network.kt index c57d5beee8..17274cfbe9 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/Network.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/Network.kt @@ -22,6 +22,7 @@ data class Network( val id: ID, val backendId: String, val name: String, + val currencySymbol: String, val derivationPath: DerivationPath, val isTestnet: Boolean, val standardType: StandardType, diff --git a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockNetworks.kt b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockNetworks.kt index 979479e010..7b61592137 100644 --- a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockNetworks.kt +++ b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockNetworks.kt @@ -18,6 +18,8 @@ internal object MockNetworks { name = "Network One", isTestnet = false, standardType = Network.StandardType.ERC20, + backendId = "network1", + currencySymbol = "ETH", derivationPath = Network.DerivationPath.None, ) @@ -26,6 +28,8 @@ internal object MockNetworks { name = "Network Two", isTestnet = false, standardType = Network.StandardType.ERC20, + backendId = "network1", + currencySymbol = "ETH", derivationPath = Network.DerivationPath.None, ) @@ -34,6 +38,8 @@ internal object MockNetworks { name = "Network Three", isTestnet = false, standardType = Network.StandardType.ERC20, + backendId = "network1", + currencySymbol = "ETH", derivationPath = Network.DerivationPath.None, ) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldConverter.kt index 4b027a624d..9ab26bd83d 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldConverter.kt @@ -24,7 +24,7 @@ internal class SendAmountFieldConverter( ), placeholder = TextReference.Str(DEFAULT_VALUE), isError = false, - error = TextReference.Res(R.string.send_insufficient_funds), + error = TextReference.Res(R.string.swapping_insufficient_funds), ) } diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ChooseFeeBottomSheet.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ChooseFeeBottomSheet.kt index 4556f2d785..d0f47a62a2 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ChooseFeeBottomSheet.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ChooseFeeBottomSheet.kt @@ -7,6 +7,7 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import com.tangem.core.ui.components.SpacerH24 @@ -35,7 +36,7 @@ private fun ChooseFeeBottomSheetContent(content: ChooseFeeBottomSheetConfig) { modifier = Modifier.background(TangemTheme.colors.background.primary), ) { Text( - text = "Choose fee", // todo replace with strings + text = stringResource(R.string.common_fee_selector_title), style = TangemTheme.typography.subtitle1, color = TangemTheme.colors.text.primary1, modifier = Modifier @@ -53,9 +54,7 @@ private fun ChooseFeeBottomSheetContent(content: ChooseFeeBottomSheetConfig) { FeeItemsBlock(content) } Text( - text = "Network transaction fees are small charges paid to support network security, incentivize " + - "validators," + - " allocate resources, and determine transaction priority.", // todo replace with strings + text = stringResource(R.string.common_fee_selector_footer), style = TangemTheme.typography.caption2, color = TangemTheme.colors.text.secondary, modifier = Modifier diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ChooseProviderBottomSheet.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ChooseProviderBottomSheet.kt index c0743867bd..f11e395923 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ChooseProviderBottomSheet.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ChooseProviderBottomSheet.kt @@ -10,6 +10,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet @@ -18,6 +19,7 @@ import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.swap.models.states.ChooseProviderBottomSheetConfig import com.tangem.feature.swap.models.states.ProviderState +import com.tangem.feature.swap.presentation.R import kotlinx.collections.immutable.toImmutableList @Composable @@ -33,7 +35,7 @@ private fun ChooseProviderBottomSheetContent(content: ChooseProviderBottomSheetC modifier = Modifier.background(TangemTheme.colors.background.primary), ) { Text( - text = "Choose provider", + text = stringResource(R.string.express_choose_providers_title), style = TangemTheme.typography.subtitle1, color = TangemTheme.colors.text.primary1, modifier = Modifier @@ -41,7 +43,7 @@ private fun ChooseProviderBottomSheetContent(content: ChooseProviderBottomSheetC .align(Alignment.CenterHorizontally), ) Text( - text = "Providers facilitate transactions, ensuring smooth and efficient token exchanges", + text = stringResource(R.string.express_choose_providers_subtitle), style = TangemTheme.typography.caption2, color = TangemTheme.colors.text.secondary, modifier = Modifier diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt index 8e51119147..99595d6398 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt @@ -76,6 +76,7 @@ fun ProviderItem(state: ProviderState, modifier: Modifier = Modifier, isSelected } } +@Suppress("LongMethod") @Composable private fun ProviderContentState( state: ProviderState.Content, diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index dd313d462a..43cb364d2c 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -120,8 +120,11 @@ internal class StateBuilder( warnings = listOf( SwapWarning.NoAvailableTokensToSwap( notificationConfig = NotificationConfig( - title = stringReference("No tokens"), - subtitle = stringReference("Swap tokens not available"), + title = resourceReference(R.string.warning_express_no_exchangeable_coins_title), + subtitle = resourceReference( + id = R.string.warning_express_no_exchangeable_coins_description, + formatArgs = wrappedList(fromToken.currency.name), + ), iconResId = R.drawable.img_attention_20, ), ), @@ -210,8 +213,9 @@ internal class StateBuilder( ), ) } - if (quoteModel.permissionState !is PermissionDataState.PermissionReadyForRequest && - !quoteModel.preparedSwapConfigState.isFeeEnough + if (quoteModel.preparedSwapConfigState.isAllowedToSpend && + !quoteModel.preparedSwapConfigState.isFeeEnough && + quoteModel.preparedSwapConfigState.isBalanceEnough ) { warnings.add( SwapWarning.UnableToCoverFeeWarning( @@ -439,7 +443,7 @@ internal class StateBuilder( return FeeItemState.Content( feeType = feeType, - title = stringReference("Fee"), // todo replace with string + title = resourceReference(R.string.common_fee_label), amountCrypto = fee.feeCryptoFormatted, symbolCrypto = fee.cryptoSymbol, amountFiatFormatted = fee.feeFiatFormatted, @@ -611,6 +615,7 @@ internal class StateBuilder( ) } + @Suppress("LongParameterList") fun showSelectProviderBottomSheet( uiState: SwapStateHolder, selectedProviderId: String, @@ -624,7 +629,7 @@ internal class StateBuilder( } val unavailableProviderStates = unavailableProviders.map { it.convertToUnavailableProviderState( - alertText = stringReference("Unavailable for pair"), + alertText = resourceReference(R.string.express_provider_not_available), selectionType = ProviderState.SelectionType.NONE, ) } @@ -701,7 +706,7 @@ internal class StateBuilder( return listOf( FeeItemState.Content( feeType = this.normalFee.feeType, - title = stringReference("Fee"), // todo replace with string + title = resourceReference(R.string.common_fee_label), amountCrypto = this.normalFee.feeCryptoFormatted, symbolCrypto = this.normalFee.cryptoSymbol, amountFiatFormatted = this.normalFee.feeFiatFormatted, @@ -710,7 +715,7 @@ internal class StateBuilder( ), FeeItemState.Content( feeType = this.priorityFee.feeType, - title = stringReference("Fee"), // todo replace with string + title = resourceReference(R.string.common_fee_label), amountCrypto = this.priorityFee.feeCryptoFormatted, symbolCrypto = this.priorityFee.cryptoSymbol, amountFiatFormatted = this.priorityFee.feeFiatFormatted, @@ -733,8 +738,9 @@ internal class StateBuilder( onProviderClick = onProviderSelect, selectionType = ProviderState.SelectionType.SELECT, ) + // todo handle error is SwapState.SwapError -> provider.convertToUnavailableProviderState( - alertText = stringReference("Available from"), + alertText = resourceReference(R.string.express_provider_min_amount, wrappedList("10")), selectionType = ProviderState.SelectionType.NONE, onProviderClick = onProviderSelect, ) @@ -765,15 +771,18 @@ internal class StateBuilder( fromToken: CryptoCurrency, onBuyClick: () -> Unit, ): NotificationConfig { - // todo add strings return NotificationConfig( - title = stringReference("Unable to cover ${fromToken.name} fee"), - subtitle = stringReference( - "To make transaction you need to deposit some ${fromToken.name} ${fromToken.symbol}", + title = resourceReference( + R.string.warning_express_not_enough_fee_for_token_tx_title, + wrappedList(fromToken.network.name), + ), + subtitle = resourceReference( + R.string.warning_express_not_enough_fee_for_token_tx_description, + wrappedList(fromToken.network.name, fromToken.network.currencySymbol), ), iconResId = fromToken.networkIconResId, buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig( - text = stringReference("Buy ${fromToken.name}"), + text = resourceReference(R.string.common_buy_currency, wrappedList(fromToken.name)), onClick = onBuyClick, ), )