diff --git a/app/src/debug/res/values-ru/strings.xml b/app/src/debug/res/values-ru/strings.xml new file mode 100644 index 0000000000..1abc31ee12 --- /dev/null +++ b/app/src/debug/res/values-ru/strings.xml @@ -0,0 +1,6 @@ + + + + DebugTangem + + \ No newline at end of file diff --git a/app/src/debug_beta/res/values-ru/strings.xml b/app/src/debug_beta/res/values-ru/strings.xml new file mode 100644 index 0000000000..3e2d147b31 --- /dev/null +++ b/app/src/debug_beta/res/values-ru/strings.xml @@ -0,0 +1,6 @@ + + + + BetaTangem + + \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/extensions/StringBuilder.kt b/app/src/main/java/com/tangem/tap/common/extensions/StringBuilder.kt index 132b8cc44c..3f8fa992ff 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/StringBuilder.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/StringBuilder.kt @@ -3,6 +3,20 @@ package com.tangem.tap.common.extensions /** [REDACTED_AUTHOR] */ -fun StringBuilder.appendIf(value: String, predicate: (String) -> Boolean) { +fun StringBuilder.appendIf(value: String, predicate: (String) -> Boolean): StringBuilder { if (predicate(value)) this.append(value) + return this +} + +fun StringBuilder.appendIfNotNull(value: String?, prefix: String? = null, postfix: String? = null): StringBuilder { + if (value == null) return this + + prefix?.let { append(it) } + append(value) + postfix?.let { append(it) } + return this +} + +fun String.appendIfNotNull(value: String?, prefix: String? = null, postfix: String? = null): String { + return StringBuilder(this).apply { appendIfNotNull(value, prefix, postfix) }.toString() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/StateDialog.kt b/app/src/main/java/com/tangem/tap/common/redux/StateDialog.kt index ecec5fb9f4..6419e09ac2 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/StateDialog.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/StateDialog.kt @@ -1,5 +1,6 @@ package com.tangem.tap.common.redux +import com.tangem.common.extensions.VoidCallback import com.tangem.tap.features.wallet.redux.AddressData import com.tangem.tap.features.wallet.redux.Currency @@ -9,8 +10,8 @@ import com.tangem.tap.features.wallet.redux.Currency interface StateDialog sealed class AppDialog : StateDialog { - data class SimpleOkDialog(val header: String, val message: String) : AppDialog() - data class SimpleOkDialogRes(val headerId: Int, val messageId: Int) : AppDialog() + data class SimpleOkDialog(val header: String, val message: String, val onOk: VoidCallback? = null) : AppDialog() + data class SimpleOkDialogRes(val headerId: Int, val messageId: Int, val onOk: VoidCallback? = null) : AppDialog() object ScanFailsDialog : AppDialog() data class AddressInfoDialog( val currency: Currency, diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt index 9e6fcd5de6..2abf3c060f 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -1,9 +1,12 @@ package com.tangem.tap.domain +import com.tangem.blockchain.blockchains.solana.RentProvider import com.tangem.blockchain.common.* import com.tangem.common.services.Result import com.tangem.tap.common.extensions.dispatchDebugErrorNotification +import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.safeUpdate +import com.tangem.tap.common.extensions.stripZeroPlainString import com.tangem.tap.common.redux.global.FiatCurrencyName import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.currenciesRepository @@ -15,12 +18,16 @@ import com.tangem.tap.domain.extensions.makeWalletManagersForApp import com.tangem.tap.domain.tasks.product.ScanResponse import com.tangem.tap.domain.tokens.CardCurrencies import com.tangem.tap.features.demo.isDemoCard +import com.tangem.tap.features.wallet.models.PendingTransactionType +import com.tangem.tap.features.wallet.models.getPendingTransactions import com.tangem.tap.features.wallet.redux.Currency import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.network.NetworkConnectivity import com.tangem.tap.network.coinmarketcap.CoinMarketCapService +import com.tangem.tap.scope import com.tangem.tap.store import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.math.BigDecimal @@ -32,7 +39,7 @@ class TapWalletManager { store.state.globalState.configManager?.config?.blockchainSdkConfig ?: BlockchainSdkConfig() } val walletManagerFactory: WalletManagerFactory - by lazy { WalletManagerFactory(blockchainSdkConfig) } + by lazy { WalletManagerFactory(blockchainSdkConfig) } suspend fun loadWalletData(walletManager: WalletManager) { handleUpdateWalletResult(walletManager.safeUpdate(), walletManager) @@ -53,8 +60,8 @@ class TapWalletManager { suspend fun loadFiatRate(fiatCurrency: FiatCurrencyName, wallet: Wallet) { val currencies = wallet.getTokens() - .map { Currency.Token(it) } - .plus(Currency.Blockchain(wallet.blockchain)) + .map { Currency.Token(it) } + .plus(Currency.Blockchain(wallet.blockchain)) loadFiatRate(fiatCurrency, currencies) } @@ -91,7 +98,7 @@ class TapWalletManager { configManager?.turnOff(ConfigManager.isSendingToPayIdEnabled) configManager?.turnOff(ConfigManager.isTopUpEnabled) } else if (blockchain == Blockchain.Bitcoin - || data.walletData?.blockchain == Blockchain.Bitcoin.id) { + || data.walletData?.blockchain == Blockchain.Bitcoin.id) { configManager?.resetToDefault(ConfigManager.isSendingToPayIdEnabled) configManager?.resetToDefault(ConfigManager.isTopUpEnabled) } else { @@ -158,7 +165,7 @@ class TapWalletManager { CardCurrencies(blockchains = blockchains, tokens = emptyList()) )) val walletManagers = - walletManagerFactory.makeWalletManagersForApp(scanResponse, blockchains.toList()) + walletManagerFactory.makeWalletManagersForApp(scanResponse, blockchains.toList()) store.dispatch(WalletAction.MultiWallet.AddWalletManagers(walletManagers)) store.dispatch(WalletAction.MultiWallet.AddBlockchains(blockchains.toList())) } @@ -167,12 +174,12 @@ class TapWalletManager { } else { val blockchains = savedCurrencies.blockchains.toList() val walletManagers = if ( - primaryTokens.isNotEmpty() && - primaryWalletManager != null && primaryBlockchain != null + primaryTokens.isNotEmpty() && + primaryWalletManager != null && primaryBlockchain != null ) { val blockchainsWithoutPrimary = blockchains.filterNot { it == primaryBlockchain } walletManagerFactory.makeWalletManagersForApp(scanResponse, blockchainsWithoutPrimary) - .plus(primaryWalletManager) + .plus(primaryWalletManager) } else { walletManagerFactory.makeWalletManagersForApp(scanResponse, blockchains) } @@ -222,7 +229,10 @@ class TapWalletManager { private suspend fun handleUpdateWalletResult(result: Result, walletManager: WalletManager) { withContext(Dispatchers.Main) { when (result) { - is Result.Success -> store.dispatch(WalletAction.LoadWallet.Success(result.data)) + is Result.Success -> { + checkForRentWarning(walletManager) + store.dispatch(WalletAction.LoadWallet.Success(result.data)) + } is Result.Failure -> { val error = (result.error as? TapError) ?: TapError.UnknownError when (error) { @@ -231,11 +241,11 @@ class TapWalletManager { } is TapError.WalletManagerUpdate.NoAccountError -> { store.dispatch(WalletAction.LoadWallet - .NoAccount(walletManager.wallet, error.customMessage)) + .NoAccount(walletManager.wallet, error.customMessage)) } is TapError.WalletManagerUpdate.InternalError -> { store.dispatch(WalletAction.LoadWallet - .Failure(walletManager.wallet, error.customMessage)) + .Failure(walletManager.wallet, error.customMessage)) } else -> { store.dispatchDebugErrorNotification(error) @@ -246,6 +256,38 @@ class TapWalletManager { } } + private fun checkForRentWarning(walletManager: WalletManager) { + val rentProvider = walletManager as? RentProvider ?: return + + scope.launch { + when (val result = rentProvider.minimalBalanceForRentExemption()) { + is com.tangem.blockchain.extensions.Result.Success -> { + fun isNeedToShowWarning(balance: BigDecimal, rentExempt: BigDecimal): Boolean = balance < rentExempt + + val balance = walletManager.wallet.fundsAvailable(AmountType.Coin) + val outgoingTxs = walletManager.wallet.getPendingTransactions(PendingTransactionType.Outgoing) + val rentExempt = result.data + val show = if (outgoingTxs.isEmpty()) { + isNeedToShowWarning(balance, rentExempt) + } else { + val outgoingAmount = outgoingTxs.sumOf { it.amount ?: BigDecimal.ZERO } + val rest = balance.minus(outgoingAmount) + isNeedToShowWarning(rest, rentExempt) + } + if (!show) return@launch + + val currency = walletManager.wallet.blockchain.currency + store.dispatchOnMain(WalletAction.SetWalletRent( + blockchain = walletManager.wallet.blockchain, + minRent = ("${rentProvider.rentAmount().stripZeroPlainString()} $currency"), + rentExempt = ("${rentExempt.stripZeroPlainString()} $currency") + )) + } + is com.tangem.blockchain.extensions.Result.Failure -> {} + } + } + } + private suspend fun handleFiatRatesResult(results: List?>>) { withContext(Dispatchers.Main) { results.map { diff --git a/app/src/main/java/com/tangem/tap/features/demo/DemoHelper.kt b/app/src/main/java/com/tangem/tap/features/demo/DemoHelper.kt index 8f51995b2a..260a2d9e34 100644 --- a/app/src/main/java/com/tangem/tap/features/demo/DemoHelper.kt +++ b/app/src/main/java/com/tangem/tap/features/demo/DemoHelper.kt @@ -1,8 +1,10 @@ package com.tangem.tap.features.demo +import com.tangem.blockchain.blockchains.bitcoin.BitcoinWalletManager import com.tangem.blockchain.common.* import com.tangem.blockchain.extensions.Result import com.tangem.blockchain.extensions.SimpleResult +import com.tangem.common.CompletionResult import com.tangem.tap.common.extensions.dispatchNotification import com.tangem.tap.common.redux.AppState import com.tangem.tap.domain.tasks.product.ScanResponse @@ -165,13 +167,26 @@ class DemoTransactionSender( private val sender: TransactionSender = walletManager as TransactionSender ) : TransactionSender { - override suspend fun getFee(amount: Amount, destination: String): Result> = - sender.getFee(amount, destination) + override suspend fun getFee(amount: Amount, destination: String): Result> { + val blockchain = walletManager.wallet.blockchain + return when (walletManager) { + is BitcoinWalletManager -> Result.Success(listOf( + Amount(0.0001.toBigDecimal(), blockchain), + Amount(0.0003.toBigDecimal(), blockchain), + Amount(0.00055.toBigDecimal(), blockchain), + )) + else -> sender.getFee(amount, destination) + } + } + override suspend fun send(transactionData: TransactionData, signer: TransactionSigner): SimpleResult { val dataToSign = randomString(32).toByteArray() val signerResponse = signer.sign(dataToSign, walletManager.wallet.cardId, walletManager.wallet.publicKey) - return SimpleResult.Failure(Exception(ID)) + return when (signerResponse) { + is CompletionResult.Success -> SimpleResult.Failure(Exception(ID)) + is CompletionResult.Failure -> SimpleResult.fromTangemSdkError(signerResponse.error) + } } private fun randomInt(from: Int, to: Int): Int = kotlin.random.Random.nextInt(from, to) diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/RequestFeeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/RequestFeeMiddleware.kt index 04d5b420d5..29165f8bad 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/RequestFeeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/RequestFeeMiddleware.kt @@ -6,6 +6,8 @@ import com.tangem.blockchain.common.TransactionSender import com.tangem.blockchain.extensions.Result import com.tangem.common.extensions.isZero import com.tangem.tap.common.redux.AppState +import com.tangem.tap.features.demo.DemoTransactionSender +import com.tangem.tap.features.demo.isDemoWallet import com.tangem.tap.features.send.redux.AmountActionUi import com.tangem.tap.features.send.redux.FeeAction import com.tangem.tap.features.send.redux.ReceiptAction @@ -38,7 +40,11 @@ class RequestFeeMiddleware { val destinationAddress = sendState.addressPayIdState.destinationWalletAddress!! val destinationAmount = Amount(typedAmount, sendState.amountState.amountToSendCrypto) - val txSender = walletManager as TransactionSender + val txSender = if (walletManager.isDemoWallet()) { + DemoTransactionSender(walletManager) + } else { + walletManager as TransactionSender + } scope.launch { val feeResult = txSender.getFee(destinationAmount, destinationAddress) withContext(Dispatchers.Main) { @@ -84,15 +90,15 @@ class FeeMock { suspend fun feeZero(blockchain: Blockchain): List = listOf(Amount(BigDecimal.ZERO, blockchain)) suspend fun feeStandard(blockchain: Blockchain): List = listOf( - Amount(0.001500.toBigDecimal(), blockchain), - Amount(0.0030.toBigDecimal(), blockchain), - Amount(0.0045001.toBigDecimal(), blockchain) + Amount(0.001500.toBigDecimal(), blockchain), + Amount(0.0030.toBigDecimal(), blockchain), + Amount(0.0045001.toBigDecimal(), blockchain) ) suspend fun feeStandardBig(blockchain: Blockchain): List = listOf( - Amount(1.76.toBigDecimal(), blockchain), - Amount(2.30.toBigDecimal(), blockchain), - Amount(3.45.toBigDecimal(), blockchain) + Amount(1.76.toBigDecimal(), blockchain), + Amount(2.30.toBigDecimal(), blockchain), + Amount(3.45.toBigDecimal(), blockchain) ) suspend fun feeSingle(blockchain: Blockchain): List = listOf(Amount(0.0015.toBigDecimal(), blockchain)) diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt index 34a63dd905..f103fc3817 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt @@ -246,10 +246,11 @@ private fun sendTransaction( dispatch(SendAction.SendError(TapError.XmlError.AssetAccountNotCreated)) } message.contains(DemoTransactionSender.ID) -> { + delay(DELAY_SDK_DIALOG_CLOSE) store.dispatchDialogShow(AppDialog.SimpleOkDialogRes( R.string.common_done, - R.string.alert_demo_tx_send - )) + R.string.alert_demo_feature_disabled + ) { dispatch(NavigationAction.PopBackTo()) }) } else -> { (sendResult.error as? TangemSdkError)?.let { error -> diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt index 1d31def08c..607e12599c 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt @@ -1,12 +1,10 @@ package com.tangem.tap.features.wallet.redux.middlewares -import com.tangem.blockchain.blockchains.solana.RentProvider import com.tangem.blockchain.common.* import com.tangem.blockchain.extensions.Result import com.tangem.common.extensions.isZero import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.safeUpdate -import com.tangem.tap.common.extensions.stripZeroPlainString import com.tangem.tap.common.redux.global.GlobalState import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction @@ -15,8 +13,6 @@ import com.tangem.tap.domain.extensions.makeWalletManagerForApp import com.tangem.tap.domain.extensions.makeWalletManagersForApp import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.demo.isDemoCard -import com.tangem.tap.features.wallet.models.PendingTransactionType -import com.tangem.tap.features.wallet.models.getPendingTransactions import com.tangem.tap.features.wallet.redux.Currency import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletState @@ -38,7 +34,6 @@ class MultiWalletMiddleware { when (action) { is WalletAction.MultiWallet.AddWalletManagers -> { globalState.feedbackManager?.infoHolder?.setWalletsInfo(action.walletManagers) - action.walletManagers.forEach { checkForRentWarning(it) } if (globalState.scanResponse?.isDemoCard() == true) { addDummyBalances(action.walletManagers) } @@ -213,38 +208,6 @@ class MultiWalletMiddleware { } } - private fun checkForRentWarning(walletManager: WalletManager) { - val rentProvider = walletManager as? RentProvider ?: return - - scope.launch { - when (val result = rentProvider.minimalBalanceForRentExemption()) { - is Result.Success -> { - fun isNeedToShowWarning(balance: BigDecimal, rentExempt: BigDecimal): Boolean = balance >= rentExempt - - val balance = walletManager.wallet.fundsAvailable(AmountType.Coin) - val outgoingTxs = walletManager.wallet.getPendingTransactions(PendingTransactionType.Outgoing) - val rentExempt = result.data - val show = if (outgoingTxs.isEmpty()) { - isNeedToShowWarning(balance, rentExempt) - } else { - val outgoingAmount = outgoingTxs.sumOf { it.amount ?: BigDecimal.ZERO } - val rest = balance.minus(outgoingAmount) - isNeedToShowWarning(rest, rentExempt) - } - if (!show) return@launch - - val currency = walletManager.wallet.blockchain.currency - store.dispatchOnMain(WalletAction.SetWalletRent( - blockchain = walletManager.wallet.blockchain, - minRent = ("${rentProvider.rentAmount().stripZeroPlainString()} $currency"), - rentExempt = ("${rentExempt.stripZeroPlainString()} $currency") - )) - } - is Result.Failure -> {} - } - } - } - private fun addTokens( tokens: List, walletState: WalletState?, diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt index 936a4d0321..57d4b733de 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt @@ -3,8 +3,10 @@ package com.tangem.tap.features.wallet.ui import android.app.Dialog import android.os.Bundle import android.view.* +import android.widget.TextView import androidx.activity.OnBackPressedCallback -import androidx.annotation.IdRes +import androidx.annotation.ColorRes +import androidx.annotation.DrawableRes import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager @@ -228,45 +230,38 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), private fun setupBalanceData(data: BalanceWidgetData) = with(binding.lWalletDetails) { when (data.status) { BalanceStatus.Loading -> { - lBalance.root.show() lBalanceError.root.hide() - lBalance.tvFiatAmount.hide() - lBalance.tvAmount.text = "" - showStatus(R.id.tv_status_loading) - showBalanceWithoutToken(data, false) + lBalance.root.show() + lBalance.groupBalance.show() + lBalance.tvError.hide() + lBalance.tvAmount.text = data.amount + lBalance.tvFiatAmount.text = data.fiatAmountFormatted + lBalance.tvStatus.setLoadingStatus(R.string.wallet_balance_loading) } BalanceStatus.VerifiedOnline, BalanceStatus.SameCurrencyTransactionInProgress, BalanceStatus.TransactionInProgress -> { - lBalance.root.show() lBalanceError.root.hide() - val statusView = if (data.status == BalanceStatus.VerifiedOnline || - data.status == BalanceStatus.SameCurrencyTransactionInProgress - ) { - R.id.tv_status_verified - } else { - lBalance.tvStatusError.text = - getText(R.string.wallet_balance_tx_in_progress) - R.id.group_error + lBalance.root.show() + lBalance.groupBalance.show() + lBalance.tvError.hide() + lBalance.tvAmount.text = data.amount + lBalance.tvFiatAmount.text = data.fiatAmountFormatted + when (data.status) { + BalanceStatus.VerifiedOnline, BalanceStatus.SameCurrencyTransactionInProgress -> { + lBalance.tvStatus.setVerifiedBalanceStatus(R.string.wallet_balance_verified) + } + else -> { + lBalance.tvStatus.setWarningStatus(R.string.wallet_balance_tx_in_progress) + } } - showStatus(statusView) - lBalance.tvStatusErrorMessage.hide() - showBalanceWithoutToken(data, true) } BalanceStatus.Unreachable -> { - lBalance.root.show() lBalanceError.root.hide() - lBalance.tvFiatAmount.hide() - - lBalance.tvAmount.text = "" - - lBalance.tvStatusErrorMessage.text = data.errorMessage - lBalance.tvStatusError.text = - getString(R.string.wallet_balance_blockchain_unreachable) - - showStatus(R.id.group_error) - lBalance.tvStatusErrorMessage.show(!data.errorMessage.isNullOrBlank()) + lBalance.root.show() + lBalance.groupBalance.hide() + lBalance.tvError.show() + lBalance.tvError.setWarningStatus(R.string.wallet_balance_blockchain_unreachable, data.errorMessage) } - BalanceStatus.NoAccount -> { lBalance.root.hide() lBalanceError.root.show() @@ -281,24 +276,6 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), binding.cardPendingTransactionWarning.show(data.status == BalanceStatus.SameCurrencyTransactionInProgress) } - private fun showStatus(@IdRes viewRes: Int) { - with(binding.lWalletDetails.lBalance) { - groupError.show(viewRes == R.id.group_error) - tvStatusLoading.show(viewRes == R.id.tv_status_loading) - tvStatusVerified.show(viewRes == R.id.tv_status_verified) - } - } - - private fun showBalanceWithoutToken(data: BalanceWidgetData, showAmount: Boolean) { - with(binding.lWalletDetails.lBalance) { - tvAmount.text = if (showAmount) data.amount else "" - if (showAmount) { - tvFiatAmount.show() - tvFiatAmount.text = data.fiatAmountFormatted - } - } - } - private fun handleDialogs(walletDialog: StateDialog?) { when (walletDialog) { is WalletDialog.SelectAmountToSendDialog -> { @@ -337,4 +314,22 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), menu.getItem(0).isEnabled = walletCanBeRemoved } -} + private fun TextView.setWarningStatus(mainMessage: Int, error: String? = null) { + val text = getString(mainMessage).appendIfNotNull(error, "\nError: ") + setStatus(text, R.color.warning, R.drawable.ic_warning_small) + } + + private fun TextView.setVerifiedBalanceStatus(mainMessage: Int) { + setStatus(getString(mainMessage), R.color.accent, R.drawable.ic_ok) + } + + private fun TextView.setLoadingStatus(mainMessage: Int) { + setStatus(getString(mainMessage), R.color.darkGray4, null) + } + + private fun TextView.setStatus(text: String, @ColorRes color: Int, @DrawableRes drawable: Int?) { + this.text = text + setTextColor(getColor(color)) + setCompoundDrawablesWithIntrinsicBounds(drawable ?: 0, 0, 0, 0) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/SimpleOkDialog.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/SimpleOkDialog.kt index aa15f94e9f..3fc5187741 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/SimpleOkDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/SimpleOkDialog.kt @@ -18,7 +18,10 @@ class SimpleOkDialog { setTitle(dialog.header) setMessage(dialog.message) setPositiveButton(R.string.common_ok) { _, _ -> } - setOnDismissListener { store.dispatchDialogHide() } + setOnDismissListener { + store.dispatchDialogHide() + dialog.onOk?.invoke() + } }.create() } @@ -27,7 +30,10 @@ class SimpleOkDialog { setTitle(context.getString(dialog.headerId)) setMessage(dialog.messageId) setPositiveButton(R.string.common_ok) { _, _ -> } - setOnDismissListener { store.dispatchDialogHide() } + setOnDismissListener { + store.dispatchDialogHide() + dialog.onOk?.invoke() + } }.create() } } diff --git a/app/src/main/res/layout/layout_balance_wallet_details.xml b/app/src/main/res/layout/layout_balance_wallet_details.xml index e094de5fee..29a44311c8 100644 --- a/app/src/main/res/layout/layout_balance_wallet_details.xml +++ b/app/src/main/res/layout/layout_balance_wallet_details.xml @@ -64,70 +64,41 @@ tools:text="J" /> + app:layout_constraintTop_toBottomOf="@id/tv_fiat_amount" + tools:text="@string/wallet_balance_verified" /> - - + app:layout_constraintTop_toBottomOf="@id/tv_fiat_amount" + tools:text="@string/lorem_ipsum" /> + app:constraint_referenced_ids="tv_amount, tv_fiat_amount, tv_status" /> - \ No newline at end of file diff --git a/app/src/main/res/values-de/strings_final.xml b/app/src/main/res/values-de/strings_final.xml index 339691d69b..fa5d2dc4b3 100644 --- a/app/src/main/res/values-de/strings_final.xml +++ b/app/src/main/res/values-de/strings_final.xml @@ -1,6 +1,6 @@ - One Wallet + Tangem Wallet 3 cards 2 cards Shipping @@ -26,12 +26,13 @@ Up to 3 physical cards to one wallet Thousands of Currencies A hardware wallet for your Bitcoin, Ethereum and many more currencies simultaneously – all in one card - Web3 Compatible + DeFi Compatible Exchange, buy NFT’s, make loans and deposits in more than 100 different decentralized services The Wallet for Everyone Use it on the go, anywhere, anytime. No wires or batteries. Just tap the card to your phone when you need your crypto. Order card + Search tokens + Search tokens You are currently running in Demo mode. All funds are not real. - This feature is disabled in Demo mode. - The transaction has been successfully signed, but not sent to the blockchain because of Demo mode. + This feature is disabled in Demo mode \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings_final.xml b/app/src/main/res/values-fr/strings_final.xml index 339691d69b..fa5d2dc4b3 100644 --- a/app/src/main/res/values-fr/strings_final.xml +++ b/app/src/main/res/values-fr/strings_final.xml @@ -1,6 +1,6 @@ - One Wallet + Tangem Wallet 3 cards 2 cards Shipping @@ -26,12 +26,13 @@ Up to 3 physical cards to one wallet Thousands of Currencies A hardware wallet for your Bitcoin, Ethereum and many more currencies simultaneously – all in one card - Web3 Compatible + DeFi Compatible Exchange, buy NFT’s, make loans and deposits in more than 100 different decentralized services The Wallet for Everyone Use it on the go, anywhere, anytime. No wires or batteries. Just tap the card to your phone when you need your crypto. Order card + Search tokens + Search tokens You are currently running in Demo mode. All funds are not real. - This feature is disabled in Demo mode. - The transaction has been successfully signed, but not sent to the blockchain because of Demo mode. + This feature is disabled in Demo mode \ No newline at end of file diff --git a/app/src/main/res/values-it/strings_final.xml b/app/src/main/res/values-it/strings_final.xml index 339691d69b..fa5d2dc4b3 100644 --- a/app/src/main/res/values-it/strings_final.xml +++ b/app/src/main/res/values-it/strings_final.xml @@ -1,6 +1,6 @@ - One Wallet + Tangem Wallet 3 cards 2 cards Shipping @@ -26,12 +26,13 @@ Up to 3 physical cards to one wallet Thousands of Currencies A hardware wallet for your Bitcoin, Ethereum and many more currencies simultaneously – all in one card - Web3 Compatible + DeFi Compatible Exchange, buy NFT’s, make loans and deposits in more than 100 different decentralized services The Wallet for Everyone Use it on the go, anywhere, anytime. No wires or batteries. Just tap the card to your phone when you need your crypto. Order card + Search tokens + Search tokens You are currently running in Demo mode. All funds are not real. - This feature is disabled in Demo mode. - The transaction has been successfully signed, but not sent to the blockchain because of Demo mode. + This feature is disabled in Demo mode \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 94ce1b19d2..c54c69a74d 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -10,15 +10,15 @@ Принять %s Доступ к камере запрещен - Вы не предоставили доступ к своей камере, измените настройки конфиденциальности. + Вы не предоставили доступ к своей камере, измените настройки конфиденциальности Настройки Добро пожаловать в Tangem.\nУ Вас есть одна из наших карт? Добро пожаловать обратно в Тангем. \nОтсканируйте карту, чтобы начать. Магазин - Приготовьтесь приложить свою\nкарту к задней панели\nтелефона. + Приготовьтесь приложить свою\nкарту к задней панели\nтелефона Нажмите на Сканировать карту - Да! Отсканировать + Да! Отсканировать. Сканировать Отправить Создать кошелек @@ -48,7 +48,7 @@ PayString имя $payid.tangem.com Создать - Ваша PayString — это уникальная для вас информация, такая как номер телефона, электронная почта или ABN. + Ваша PayString — это уникальная для вас информация, такая как номер телефона, электронная почта или ABN PayString успешно создан и скопирован в буфер обмена Ошибка при создании PayString Такой PayString уже существует. Попробуйте другой. @@ -73,7 +73,7 @@ ≈ %1$s (включая комиссию: %2$s) %1$s %2$s и %3$s %4$s будут отправлены Баланс: %1$s %2$s - Транзакция успешно подписана и отправлена в блокчейн. Баланс кошелька будет обновлен через некоторое время + Транзакция успешно подписана и отправлена в блокчейн. Баланс кошелька будет обновлен через некоторое время. Подробности ID карты Эмитент @@ -91,17 +91,17 @@ Длительное удержание Этот механизм защищает карту от бесконтактной атаки. Это обеспечит задержку между приемом и выполнением команды. После первой подписанной транзакции этот телефон будет привязан к карте, и транзакции будут подписаны без задержки. Пароль - Перед выполнением любой команды, влекущей за собой изменение состояния карты, вам необходимо будет ввести пароль. + Перед выполнением любой команды, влекущей за собой изменение состояния карты, вам необходимо будет ввести пароль Код доступа - Перед сканированием карты вам нужно будет ввести правильный код доступа. - У Вас могут возникнуть проблемы с NFC на некоторых iPhone 7/7+ во время извлечения. + Перед сканированием карты вам нужно будет ввести правильный код доступа + У Вас могут возникнуть проблемы с NFC на некоторых iPhone 7/7+ во время извлечения Эта карта уже пополнялась и подписывала транзакции в прошлом. Рассмотрите возможность немедленного снятия всех средств, если Вы получили эту карту из ненадежного источника. Предупреждение Эта карта не предназначена для работы с этим приложением Карта, которую Вы отсканировали, является картой для разработчиков. Не принимайте ее в качестве оплаты. Карты Tangem, выпущенные до сентября 2019 года, в настоящее время не могут быть извлечены с помощью iPhone. Мы усердно работаем с Apple, чтобы сделать это возможным в будущих версиях iOS. Нажмите, чтобы подписать - Приложите карту к телефону, как показано выше. + Приложите карту к телефону, как показано выше Приложите, чтобы удалить кошелек Приложите, чтобы создать кошелек Приложите, чтобы изменить код доступа @@ -132,7 +132,7 @@ Чтобы не платить повышенную комиссию при следующем пополнении кошелька, уменьшите сумму на %s XTZ Уменьшить на %s XTZ Нет, отправить все - Ошибка сканирования карты. Попробуй снова + Ошибка сканирования карты. Попробуй снова. Купить Продать Торговать @@ -141,10 +141,10 @@ Устаревший Создать кошелек Создать кошелек - Сгенерируйте ключи кошелька на обеих картах, чтобы начать использовать свои Twin карты. + Сгенерируйте ключи кошелька на обеих картах, чтобы начать использовать свои Twin карты Tangem Twin Один кошелек. Две карты. - Одна, которую Вы держите в руках, и вторая карта с номером #%s. + Одна, которую Вы держите в руках, и вторая карта с номером #%s Карта %1d из %2d Пересоздать Twin кошелек Условия использования карты @@ -165,20 +165,20 @@ Поиск Памятка Тег назначения - Недопустимый тег назначения. Он не будет добавлен в транзакцию - Недопустимый идентификатор памятки. Он не будет добавлен в транзакцию + Недопустимый тег назначения. Он не будет добавлен в транзакцию. + Недопустимый идентификатор памятки. Он не будет добавлен в транзакцию. Приложение Отправить отзыв Успешно отправлено Спасибо за ваш отзыв Ваши предложения отправлены - Спасибо за ваш отзыв. Мы ответим как можно скорее + Спасибо за ваш отзыв. Мы ответим как можно скорее. Не удалось отправить электронное письмо Причина: %s Не могу отправить транзакцию Причина: %s. Хотите отправить отзыв? У Вас возникли трудности со сканированием вашей карты? - Пожалуйста, попробуйте приложить карту точно так, как показано на анимации, или обратитесь в поддержку. + Пожалуйста, попробуйте приложить карту точно так, как показано на анимации, или обратитесь в поддержку Отмена Попробуйте снова Обратиться в поддержку @@ -206,21 +206,20 @@ Символ токена Адрес контракта Десятичные - бывший. USD Coin - бывший. USDC + бывший USD Coin + бывший USDC Добавлен Удалить токен Значок токена Блокчейн Управление токенами Блокчейны - %s токены Копировать Поделиться + Добавить токены Пожалуйста, дождитесь завершения транзакции, чтобы иметь возможность отправить средства Проверка подлинности не удалась - Эта карта может быть производственным образцом или подделкой. + Эта карта может быть производственным образцом или подделкой Важная информация о безопасности \u26A0 Эта карта ранее подписывала транзакции Узнать подробнее @@ -232,7 +231,7 @@ Отклонить Это тестовая карта. Не принимайте ее в качестве оплаты. Она должна использоваться только в целях тестирования и разработки. Вы хотите купить или продать криптовалюту? - К сожалению, текущая версия приложения не готова к работе с этой картой, проверьте наличие обновлений. + К сожалению, текущая версия приложения не готова к работе с этой картой, проверьте наличие обновлений Добро пожаловать в Tangem Самый безопасный способ покупать, использовать и\n хранить криптовалюту Получить новую карту @@ -244,7 +243,7 @@ Создать кошелек Пополните свой кошелек Чтобы начать, просто пополните карту на любую сумму - Чтобы начать, просто пополните кошелек более чем на %s %s. + Чтобы начать, просто пополните кошелек более чем на %s %s Купить криптовалюту Показать адрес кошелька Отсканируйте адрес, чтобы пополнить кошелек @@ -257,7 +256,7 @@ Если процесс повторного создания кошелька каким-либо образом прервется, вам придется начать все сначала. Процесс связывания карт частично завершен. Вы не можете выйти из него сейчас. Внутренняя ошибка: не удается создать менеджер кошельков - Блокчейн недоступен. Попробуй позже + Блокчейн недоступен. Попробуй позже. Хорошо, понял! Успешно! Начнем @@ -275,40 +274,40 @@ Добавлена одна резервная карта Добавлены две резервные карты Резервная карта #%d - Вы можете привязать до трех карт к одному кошельку. + Вы можете привязать до трех карт к одному кошельку Чтобы начать процесс резервного копирования, добавьте еще максимум 2 карты Подготовьте основную карту с номером %s Подготовьте основную карту Вы можете добавить еще одну карту или завершить процесс резервного копирования - Добавлено максимальное количество карт. - Если процесс резервного копирования будет прерван каким-либо образом, вам придется начать все сначала. + Добавлено максимальное количество карт + Если процесс резервного копирования будет прерван каким-либо образом, вам придется начать все сначала Вы добавили одну резервную карту. После того, как процесс будет завершен, Вы больше не сможете добавить карт. Если у Вас есть еще одна карта, добавьте ее в резервную копию. Хотите продолжить? Создать код доступа Введите код доступа повторно Защитить Персонализировать Восстановить - Вам необходимо установить единый код доступа для защиты всех ваших кошельков. - Позже Вы сможете установить индивидуальный код доступа для каждой карты. - Код доступа можно восстановить с помощью привязанной карты, не храните все карты в одном месте. - Выберите любое слово, фразу или номер в качестве кода доступа. - Код доступа должен состоять не менее чем из 4 символов. + Вам необходимо установить единый код доступа для защиты всех ваших кошельков + Позже Вы сможете установить индивидуальный код доступа для каждой карты + Код доступа можно восстановить с помощью привязанной карты, не храните все карты в одном месте + Выберите любое слово, фразу или номер в качестве кода доступа + Код доступа должен состоять не менее чем из 4 символов Введенный код доступа не соответствует исходному коду доступа Создать Подтвердить - Вы создали 2 резервные карты, и теперь эти карты готовы к использованию. + Вы создали 2 резервные карты, и теперь эти карты готовы к использованию Создание резервной копии Процесс резервного копирования частично завершен. Вы не можете выйти из него сейчас. Резервный кошелек Идентичные карты Код доступа Восстановление кода доступа - Вы можете сделать до двух резервных копий карты Tangem Wallet. - Все резервные карты могут использоваться как полнофункциональные с одинаковыми ключами. - Вы сможете установить код доступа для защиты своих кошельков. - Код доступа можно восстановить с помощью одной из резервных карт. - Ваша карта Tangem Wallet настроена и готова к использованию. - Вы создали 1 резервную карту, и теперь эта карта готова к использованию. + Вы можете сделать до двух резервных копий карты Tangem Wallet + Все резервные карты могут использоваться как полнофункциональные с одинаковыми ключами + Вы сможете установить код доступа для защиты своих кошельков + Код доступа можно восстановить с помощью одной из резервных карт + Ваша карта Tangem Wallet настроена и готова к использованию + Вы создали 1 резервную карту, и теперь эта карта готова к использованию Основная карта Я понимаю Статус резервного копирования @@ -332,20 +331,20 @@ Подготовьте основную карту с номером %s Сброс до заводских настроек Это действие необратимо. Если после сброса карты кто-то отправит на нее средства, то Вы не сможете их вывести. - Код доступа доступен только для карт с резервной копией. + Код доступа доступен только для карт с резервной копией Сеть Solana взымает арендную плату в размере %s каждые 2 дня. Аккаунты, которые не могут позволить себе арендную плату, удаляются из сети. Пополните свой счет более чем на %s, чтобы использовать его бесплатно. %1s (%2s) Эта карта не является векселем на предъявителя. В настоящее время мы не можем сопоставить количество подписей на карте с информацией в блокчейне. Это нормально, но в редких случаях может означать, что предыдущий владелец скрывает автономную подпись, что является проблемой безопасности.\n\nНе принимайте эту карту в качестве физического платежа от кого-то, кому Вы не доверяете.\n\nВо всех остальных отношениях - это совершенно безопасно.\n\nTangem — единственный аппаратный кошелек, предлагающий защиту от подсчета подписей. - Wallet Connect + WalletConnect Запрос на создание транзакции для %2s\n%3s\n\nСумма: %4s\nКомиссия: %5s\nВсего: %6s\nБаланс: %7s Запрос на запуск сеанса для карты с идентификатором %1s\nдля %2s\n\nURL: %3s - Сеансы подключения кошелька + Сессии WalletConnect Сеанс WalletConnect открыт с %s Упс. Нет сессий. Нет открытых сессий WalletConnect Открытая сессия Карта: %s - Коснитесь карты, чтобы привязать ее к кошельку. + Коснитесь карты, чтобы привязать ее WalletConnect Не удается отправить транзакцию. Недостаточно средств. Просьба подписать сообщение\nкартой %s\n\n Сообщение для %s:\n%s @@ -356,7 +355,7 @@ Операция не может быть завершена Операция не может быть завершена. \n\nВы уже установили сеанс WalletConnect с этими параметрами. Не удалось установить сеанс WalletConnect: ошибка времени выполнения. Пожалуйста, повторите попытку позже. - Транзакция BNB успешно подписана и отправлена в DApp. + Транзакция BNB успешно подписана и отправлена в DApp DApp %s, запрашивает\nподпись транзакции BNB с\nкартой: %s\n\n%s Сведения о транзакции:\nОт: %s\nКому: %s\nСумма: %s Торговый ордер на %s\nЦена: %s\nСумма к получению: %s\nСумма к оплате: %s @@ -366,10 +365,10 @@ Не могу протолкнуть транзакцию Обращение в поддержку Tangem Обращение в поддержку - Расскажите, каких функций Вам не хватает, и мы постараемся Вам помочь. + Расскажите, каких функций Вам не хватает, и мы постараемся Вам помочь Скажите, пожалуйста, какая у Вас карта? Пожалуйста, расскажите нам больше о Вашей проблеме. Каждая маленькая деталь может помочь. Привет, команда поддержки, - Пожалуйста, расскажите нам больше о Вашей проблеме. Каждая деталь может быть полезной + Пожалуйста, расскажите нам больше о Вашей проблеме. Каждая деталь может быть полезной. Информация ниже не является обязательной. Вы можете стереть её, если хотите. \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings_final.xml b/app/src/main/res/values-ru/strings_final.xml index dac3254b83..6105f6b3d6 100644 --- a/app/src/main/res/values-ru/strings_final.xml +++ b/app/src/main/res/values-ru/strings_final.xml @@ -1,15 +1,15 @@ - Один Кошелек + Tangem Wallet 3 карты 2 карты Доставка Бесплатно - У меня есть промо-код… + У меня есть промо-код... Итого Другие способы оплаты Купить сейчас - Оформление вашего заказа + Оформление заказа Ваш заказ Встречайте\nTangem Покупайте @@ -17,21 +17,22 @@ Отправляйте Расплачивайтесь Обменивайте - Одалживайте + Вкладывайте Занимайте - Вкладывайте + Стейкайте Революционный аппаратный кошелек - Держите свои криптосбережения в безопасности - приватные ключи надежно хранятся на карте - Ультрабезопасная резервная копия + Держите свои криптосбережения в безопасности. Приватные ключи надежно хранятся на карте. + Все ключи в безопасности До трех карт с одним кошельком Тысячи криптовалют Аппаратный кошелек для ваших биткоинов, эфира и многих других валют одновременно — все в одной карте - Поддерживает Web3 - Обменивайте, покупайте NFT, получайте займы и вклады в более чем 100 различных децентрализованных сервисах + Поддержка DeFi + Обменивайте, покупайте NFT, получайте займы и делайте вклады в более чем 100 различных децентрализованных сервисах Кошелек для каждого - Используйте его на ходу, в любом месте, в любое время. Без проводов и аккумуляторов. Как только понадобится крипта, просто приложите карту к телефону. + Используйте его на ходу, в любом месте, в любое время. Без проводов и батареек. Как только понадобится крипта, просто приложите карту к телефону. Заказать карту + Поиск токенов + Поиск токенов Приложение работает в демонстрационном режиме. Средства на всех счетах ненастоящие. Эта функция недоступна в демонстрационном режиме - Транзакция успешно подписана, но не отправлена в блокчейн, потому что активирован демонстрационный режим. \ No newline at end of file diff --git a/app/src/main/res/values/strings_final.xml b/app/src/main/res/values/strings_final.xml index 339691d69b..fa5d2dc4b3 100644 --- a/app/src/main/res/values/strings_final.xml +++ b/app/src/main/res/values/strings_final.xml @@ -1,6 +1,6 @@ - One Wallet + Tangem Wallet 3 cards 2 cards Shipping @@ -26,12 +26,13 @@ Up to 3 physical cards to one wallet Thousands of Currencies A hardware wallet for your Bitcoin, Ethereum and many more currencies simultaneously – all in one card - Web3 Compatible + DeFi Compatible Exchange, buy NFT’s, make loans and deposits in more than 100 different decentralized services The Wallet for Everyone Use it on the go, anywhere, anytime. No wires or batteries. Just tap the card to your phone when you need your crypto. Order card + Search tokens + Search tokens You are currently running in Demo mode. All funds are not real. - This feature is disabled in Demo mode. - The transaction has been successfully signed, but not sent to the blockchain because of Demo mode. + This feature is disabled in Demo mode \ No newline at end of file