diff --git a/app/src/main/java/com/tangem/tap/common/DialogManager.kt b/app/src/main/java/com/tangem/tap/common/DialogManager.kt index 7f3bf094a7..56ce4dd062 100644 --- a/app/src/main/java/com/tangem/tap/common/DialogManager.kt +++ b/app/src/main/java/com/tangem/tap/common/DialogManager.kt @@ -15,6 +15,7 @@ import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.BackupInPro import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.ConfirmDiscardingBackupDialog import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.UnfinishedBackupFoundDialog import com.tangem.tap.features.wallet.ui.dialogs.ScanFailsDialog +import com.tangem.tap.features.wallet.ui.dialogs.SimpleOkDialog import com.tangem.tap.store import com.tangem.wallet.R import org.rekotlin.StoreSubscriber @@ -48,6 +49,8 @@ class DialogManager : StoreSubscriber { if (dialog != null) return dialog = when (state.dialog) { + is AppDialog.SimpleOkDialog -> SimpleOkDialog.create(state.dialog, context) + is AppDialog.SimpleOkDialogRes -> SimpleOkDialog.create(state.dialog, context) is AppDialog.ScanFailsDialog -> ScanFailsDialog.create(context) is AppDialog.AddressInfoDialog -> AddressInfoBottomSheetDialog(state.dialog, context) is TwinCardsAction.Wallet.ShowInterruptDialog -> CreateWalletInterruptDialog.create(state.dialog, context) diff --git a/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt b/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt index 3d33ceeaa8..f552e835f6 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt @@ -8,18 +8,26 @@ import com.tangem.tap.domain.TapError import com.tangem.tap.domain.extensions.amountToCreateAccount import com.tangem.tap.domain.getFirstToken import com.tangem.tap.domain.topup.TradeCryptoHelper +import com.tangem.tap.features.demo.isDemoWallet import com.tangem.tap.features.wallet.redux.AddressData import com.tangem.tap.features.wallet.redux.reducers.createAddressesData import com.tangem.tap.network.NetworkConnectivity import com.tangem.tap.store +import timber.log.Timber /** [REDACTED_AUTHOR] */ suspend fun WalletManager.safeUpdate(): Result = try { - update() - Result.Success(wallet) + if (isDemoWallet()) { + Result.Success(wallet) + } else { + update() + Result.Success(wallet) + } } catch (exception: Exception) { + Timber.e(exception) + if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) { Result.Failure(TapError.NoInternetConnection) } else { 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 bcde7dae3b..ecec5fb9f4 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 @@ -9,6 +9,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() 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 cfd628a093..9e6fcd5de6 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -10,9 +10,11 @@ import com.tangem.tap.currenciesRepository import com.tangem.tap.domain.TapWorkarounds.isStart2Coin import com.tangem.tap.domain.TapWorkarounds.isTestCard import com.tangem.tap.domain.configurable.config.ConfigManager -import com.tangem.tap.domain.extensions.* +import com.tangem.tap.domain.extensions.makePrimaryWalletManager +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.redux.Currency import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.network.NetworkConnectivity @@ -207,6 +209,9 @@ class TapWalletManager { data.getBlockchain() == Blockchain.Unknown && !data.card.isMultiwalletAllowed -> { WalletAction.LoadData.Failure(TapError.UnknownBlockchain) } + data.isDemoCard() -> { + return null + } data.card.wallets.isEmpty() -> { WalletAction.EmptyWallet } diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt index 3cdf14dfea..663bbcbd6c 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt @@ -10,7 +10,7 @@ import com.tangem.wallet.R [REDACTED_AUTHOR] */ class WarningMessagesManager( - private val warningLoader: RemoteWarningLoader, + private val warningLoader: RemoteWarningLoader, ) { private val warningsList: MutableList = mutableListOf() @@ -33,15 +33,15 @@ class WarningMessagesManager( fun getWarnings(location: WarningMessage.Location, forBlockchains: List = emptyList()): List { return warningsList - .filter { !it.isHidden && it.location.contains(location) } - .filter { - val list = it.blockchainList - when { - list == null -> true - list.containsAny(forBlockchains) -> true - else -> false - } + .filter { !it.isHidden && it.location.contains(location) } + .filter { + val list = it.blockchainList + when { + list == null -> true + list.containsAny(forBlockchains) -> true + else -> false } + } } fun hideWarning(warning: WarningMessage): Boolean { @@ -49,7 +49,7 @@ class WarningMessagesManager( return when { foundWarning == null -> false foundWarning.type == WarningMessage.Type.Temporary - || foundWarning.type == WarningMessage.Type.AppRating -> { + || foundWarning.type == WarningMessage.Type.AppRating -> { if (foundWarning.isHidden) { false } else { @@ -80,32 +80,32 @@ class WarningMessagesManager( companion object { fun devCardWarning(): WarningMessage = WarningMessage( - "", - "", - type = WarningMessage.Type.Permanent, - priority = WarningMessage.Priority.Critical, - listOf(WarningMessage.Location.MainScreen), - null, - R.string.alert_title, - R.string.alert_developer_card, - WarningMessage.Origin.Local + "", + "", + type = WarningMessage.Type.Permanent, + priority = WarningMessage.Priority.Critical, + listOf(WarningMessage.Location.MainScreen), + null, + R.string.alert_title, + R.string.alert_developer_card, + WarningMessage.Origin.Local ) fun alreadySignedHashesWarning(): WarningMessage = WarningMessage( - "", - "", - type = WarningMessage.Type.Temporary, - priority = WarningMessage.Priority.Info, - listOf(WarningMessage.Location.MainScreen), - null, - R.string.alert_title, - R.string.alert_card_signed_transactions, - WarningMessage.Origin.Local + "", + "", + type = WarningMessage.Type.Temporary, + priority = WarningMessage.Priority.Info, + listOf(WarningMessage.Location.MainScreen), + null, + R.string.alert_title, + R.string.alert_card_signed_transactions, + WarningMessage.Origin.Local ) fun signedHashesMultiWalletWarning(): WarningMessage = WarningMessage( title = "", - message = "", + message = "", type = WarningMessage.Type.Temporary, priority = WarningMessage.Priority.Info, location = listOf(WarningMessage.Location.MainScreen), @@ -117,15 +117,15 @@ class WarningMessagesManager( ) fun appRatingWarning(): WarningMessage = WarningMessage( - "", - "", - WarningMessage.Type.AppRating, - WarningMessage.Priority.Info, - listOf(WarningMessage.Location.MainScreen), - null, - R.string.warning_rate_app_title, - R.string.warning_rate_app_message, - WarningMessage.Origin.Local + "", + "", + WarningMessage.Type.AppRating, + WarningMessage.Priority.Info, + listOf(WarningMessage.Location.MainScreen), + null, + R.string.warning_rate_app_title, + R.string.warning_rate_app_message, + WarningMessage.Origin.Local ) fun isAlreadySignedHashesWarning(warning: WarningMessage): Boolean { @@ -133,15 +133,15 @@ class WarningMessagesManager( } fun onlineVerificationFailed(): WarningMessage = WarningMessage( - "", - "", - type = WarningMessage.Type.Permanent, - priority = WarningMessage.Priority.Critical, - listOf(WarningMessage.Location.MainScreen), - null, - R.string.warning_failed_to_verify_card_title, - R.string.warning_failed_to_verify_card_message, - WarningMessage.Origin.Local + "", + "", + type = WarningMessage.Type.Permanent, + priority = WarningMessage.Priority.Critical, + listOf(WarningMessage.Location.MainScreen), + null, + R.string.warning_failed_to_verify_card_title, + R.string.warning_failed_to_verify_card_message, + WarningMessage.Origin.Local ) fun remainingSignaturesNotEnough(remainingSignatures: Int): WarningMessage = WarningMessage( @@ -169,6 +169,18 @@ class WarningMessagesManager( WarningMessage.Origin.Local ) + fun demoCardWarning(): WarningMessage = WarningMessage( + "", + "", + type = WarningMessage.Type.Permanent, + priority = WarningMessage.Priority.Critical, + listOf(WarningMessage.Location.MainScreen), + null, + R.string.alert_title, + R.string.alert_demo_message, + WarningMessage.Origin.Local + ) + const val REMAINING_SIGNATURES_WARNING = 10 } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt index e75da7ca72..29ae9d45bc 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt @@ -5,8 +5,10 @@ import com.tangem.common.card.EllipticCurve import com.tangem.common.core.CardSession import com.tangem.common.core.CardSessionRunnable import com.tangem.common.core.TangemSdkError +import com.tangem.common.extensions.ByteArrayKey import com.tangem.common.extensions.guard import com.tangem.common.extensions.toMapKey +import com.tangem.common.hdWallet.DerivationPath import com.tangem.operations.CommandResponse import com.tangem.operations.backup.PrimaryCard import com.tangem.operations.backup.StartPrimaryCardLinkingTask @@ -16,10 +18,12 @@ import com.tangem.operations.wallet.CreateWalletResponse import com.tangem.operations.wallet.CreateWalletTask import com.tangem.tap.domain.ProductType import com.tangem.tap.domain.TapWorkarounds.getTangemNoteBlockchain +import com.tangem.tap.domain.TapWorkarounds.isTestCard import com.tangem.tap.domain.tasks.product.CreateWalletsTask import com.tangem.tap.domain.tasks.product.KeyWalletPublicKey import com.tangem.tap.domain.tasks.product.ProductCommandProcessor import com.tangem.tap.domain.tasks.product.getCurvesForNonCreatedWallets +import com.tangem.tap.features.demo.DemoHelper data class CreateProductWalletTaskResponse( @@ -96,25 +100,27 @@ private class CreateWalletTangemNote : ProductCommandProcessor { + private lateinit var card: Card private var primaryCard: PrimaryCard? = null - private var createWalletResponse: CreateWalletResponse? = null override fun proceed( card: Card, session: CardSession, callback: (result: CompletionResult) -> Unit, ) { + this.card = card val curves = card.getCurvesForNonCreatedWallets() + CreateWalletsTask(curves).run(session) { result -> when (result) { is CompletionResult.Success -> { - createWalletResponse = result.data.createWalletResponses[0] + val createWalletResponses = result.data.createWalletResponses when { card.settings.isBackupAllowed -> { - linkPrimaryCard(session, callback) + linkPrimaryCard(createWalletResponses, session, callback) } card.settings.isHDWalletAllowed -> { - deriveKeys(session, callback) + deriveKeys(createWalletResponses, session, callback) } else -> { callback( @@ -124,7 +130,6 @@ private class CreateWalletTangemWallet : ProductCommandProcessor callback(CompletionResult.Failure(result.error)) } @@ -132,6 +137,7 @@ private class CreateWalletTangemWallet : ProductCommandProcessor, session: CardSession, callback: (result: CompletionResult) -> Unit, ) { @@ -139,7 +145,7 @@ private class CreateWalletTangemWallet : ProductCommandProcessor { primaryCard = result.data - deriveKeys(session, callback) + deriveKeys(createWalletResponse, session, callback) } is CompletionResult.Failure -> { callback(CompletionResult.Failure(result.error)) @@ -149,28 +155,26 @@ private class CreateWalletTangemWallet : ProductCommandProcessor, session: CardSession, callback: (result: CompletionResult) -> Unit, ) { - val derivationPaths = listOf(Blockchain.Bitcoin, Blockchain.Ethereum) - .mapNotNull { it.derivationPath() } - val response = createWalletResponse.guard { + val map = mutableMapOf>() + createWalletResponse.forEach { response -> + val blockchainsForCurve = getBlockchains(response.cardId).filter { + it.getSupportedCurves().contains(response.wallet.curve) + } + val derivationPaths = blockchainsForCurve.mapNotNull { it.derivationPath() } + if (derivationPaths.isNotEmpty()) { + map[response.wallet.publicKey.toMapKey()] = derivationPaths + } + } + if (map.isEmpty()) { callback(CompletionResult.Failure(TangemSdkError.UnknownError())) return } - if (derivationPaths.isNullOrEmpty()) { - callback( - CompletionResult.Success( - CreateProductWalletTaskResponse( - card = session.environment.card!!, primaryCard = primaryCard - ) - ) - ) - return - } - - DeriveMultipleWalletPublicKeysTask(mapOf(response.wallet.publicKey.toMapKey() to derivationPaths)) + DeriveMultipleWalletPublicKeysTask(map) .run(session) { result -> when (result) { is CompletionResult.Success -> { @@ -188,4 +192,12 @@ private class CreateWalletTangemWallet : ProductCommandProcessor { + return when { + DemoHelper.isDemoCardId(cardId) -> DemoHelper.config.demoBlockchains + card.isTestCard -> listOf(Blockchain.BitcoinTestnet, Blockchain.EthereumTestnet) + else -> listOf(Blockchain.Bitcoin, Blockchain.Ethereum) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt b/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt index f56e6f7bc8..114746a06f 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt @@ -13,9 +13,11 @@ import com.tangem.tap.common.extensions.appendIf import com.tangem.tap.common.extensions.readJsonFileToString import com.tangem.tap.domain.extensions.getCustomIconUrl import com.tangem.tap.domain.extensions.setCustomIconUrl +import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.network.createMoshi class CurrenciesRepository(val context: Application) { + private val moshi = createMoshi() private val blockchainsAdapter: JsonAdapter> = moshi.adapter( Types.newParameterizedType(List::class.java, Blockchain::class.java) @@ -28,10 +30,13 @@ class CurrenciesRepository(val context: Application) { ) fun loadCardCurrencies(cardId: String): CardCurrencies? { - val blockchains = loadSavedBlockchains(cardId) + val blockchains = loadSavedBlockchains(cardId).toMutableSet() + if (DemoHelper.isDemoCardId(cardId)) { + blockchains.addAll(DemoHelper.config.demoBlockchains) + } if (blockchains.isEmpty()) return null - return CardCurrencies(loadSavedTokens(cardId), blockchains) + return CardCurrencies(loadSavedTokens(cardId), blockchains.toList()) } fun saveCardCurrencies(cardId: String, currencies: CardCurrencies) { @@ -164,11 +169,10 @@ class CurrenciesRepository(val context: Application) { return excludeUnsupportedBlockchains(blockchains) } - //TODO: move to the App settings private fun excludeUnsupportedBlockchains(blockchains: List): List { return blockchains.toMutableList().apply { removeAll(listOf( - Blockchain.Fantom, Blockchain.FantomTestnet +// Blockchain.Fantom, Blockchain.FantomTestnet )) } } diff --git a/app/src/main/java/com/tangem/tap/domain/topup/TopUpManager.kt b/app/src/main/java/com/tangem/tap/domain/topup/TopUpManager.kt index 9dd6e91960..c5e74334a4 100644 --- a/app/src/main/java/com/tangem/tap/domain/topup/TopUpManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/topup/TopUpManager.kt @@ -6,6 +6,7 @@ import com.tangem.blockchain.common.Amount import com.tangem.blockchain.common.AmountType import com.tangem.blockchain.common.Token import com.tangem.blockchain.extensions.Result +import com.tangem.tap.common.extensions.safeUpdate import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.TangemSigner import com.tangem.tap.store @@ -14,7 +15,7 @@ import java.math.BigDecimal class TopUpManager { suspend fun topUpTestErc20Tokens(walletManager: EthereumWalletManager, token: Token) { - walletManager.update() + walletManager.safeUpdate() val amountToSend = Amount(walletManager.wallet.blockchain) val destinationAddress = token.contractAddress diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt index e56b4d9ce6..1d0dc4a9e0 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt @@ -15,6 +15,7 @@ import com.tangem.common.extensions.toHexString import com.tangem.crypto.CryptoUtils import com.tangem.operations.sign.SignHashCommand import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.extensions.safeUpdate import com.tangem.tap.common.extensions.toFormattedString import com.tangem.tap.features.details.redux.walletconnect.* import com.tangem.tap.features.details.ui.walletconnect.dialogs.PersonalSignDialogData @@ -35,18 +36,11 @@ class WalletConnectSdkHelper { id: Long, type: WcTransactionType, ): WcTransactionData? { - val walletManager = getWalletManager(session) ?: return null - try { - walletManager.update() - } catch (exception: Exception) { - Timber.e(exception) - return null - } + walletManager.safeUpdate() val wallet = walletManager.wallet - val balance = - wallet.amounts[AmountType.Coin]?.value ?: return null + val balance = wallet.amounts[AmountType.Coin]?.value ?: return null val gas = transaction.gas?.hexToBigDecimal() ?: transaction.gasLimit?.hexToBigDecimal() 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 new file mode 100644 index 0000000000..f80e04df6b --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/demo/DemoHelper.kt @@ -0,0 +1,153 @@ +package com.tangem.tap.features.demo + +import com.tangem.blockchain.common.* +import com.tangem.blockchain.extensions.Result +import com.tangem.blockchain.extensions.SimpleResult +import com.tangem.tap.common.extensions.dispatchNotification +import com.tangem.tap.common.redux.AppState +import com.tangem.tap.domain.tasks.product.ScanResponse +import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction +import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction +import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.store +import com.tangem.wallet.BuildConfig +import com.tangem.wallet.R +import org.rekotlin.Action +import java.math.BigDecimal + +/** +[REDACTED_AUTHOR] + */ +interface DemoMiddleware { + fun tryHandle(config: DemoConfig, scanResponse: ScanResponse, action: Action): Boolean +} + +object DemoHelper { + val config = DemoConfig() + + private val demoMiddlewares = listOf( + DemoOnboardingNoteMiddleware(), + ) + + private val disabledActionFeatures = listOf( + WalletConnectAction.StartWalletConnect::class.java, + WalletAction.TradeCryptoAction.Buy::class.java, + WalletAction.TradeCryptoAction.Sell::class.java, + BackupAction.StartBackup::class.java, + WalletAction.ExploreAddress::class.java + ) + + fun isDemoCard(scanResponse: ScanResponse): Boolean = isDemoCardId(scanResponse.card.cardId) + + fun isDemoCardId(cardId: String): Boolean = config.isDemoCardId(cardId) + + fun tryHandle(appState: () -> AppState?, action: Action): Boolean { + val scanResponse = getScanResponse(appState) ?: return false + if (!scanResponse.isDemoCard()) return false + + demoMiddlewares.forEach { + if (it.tryHandle(config, scanResponse, action)) return true + } + + disabledActionFeatures.firstOrNull { it == action::class.java }?.let { + store.dispatchNotification(R.string.alert_demo_feature_disabled) + return true + } + + return false + } + + fun injectDemoBalance(walletManager: WalletManager?) { + val manager = walletManager ?: return + + val blockchain = walletManager.wallet.blockchain + val amount = config.getBalance(blockchain) + manager.wallet.setAmount(amount) + } + + private fun getScanResponse(appState: () -> AppState?): ScanResponse? { + val state = appState() ?: return null + + return state.globalState.onboardingState.onboardingManager?.scanResponse + ?: state.globalState.scanResponse + } +} + +class DemoConfig { + + val demoBlockchains = listOf( + Blockchain.Bitcoin, + Blockchain.Ethereum, + Blockchain.Dogecoin, + Blockchain.Solana, + ) + + val demoCardIds: List by lazy { + val demoIds = (releaseDemoCardIds + testDemoCardIds).toMutableList() + if (BuildConfig.DEBUG) demoIds.addAll(debugTestDemoCardIds) + + return@lazy demoIds.distinct() + } + + private val walletBalances: Map = mapOf( + Blockchain.Bitcoin to Amount(0.028.toBigDecimal(), Blockchain.Bitcoin), + Blockchain.Ethereum to Amount(0.2311.toBigDecimal(), Blockchain.Ethereum), + Blockchain.Dogecoin to Amount(1450.025.toBigDecimal(), Blockchain.Dogecoin), + Blockchain.Solana to Amount(13.246.toBigDecimal(), Blockchain.Solana), + ) + + fun isDemoCardId(cardId: String): Boolean = demoCardIds.contains(cardId) + + fun getBalance(blockchain: Blockchain): Amount = walletBalances[blockchain]?.copy() + ?: Amount(BigDecimal.ZERO, blockchain).copy() + + private val releaseDemoCardIds = mutableListOf( + + ) + + private val testDemoCardIds = listOf( + "FB20000000000186", // Note ETH + "FB10000000000196", // Note BTC + "FB30000000000176", // Wallet + //TODO: delete bellow ids before 3.28 release + "AB01000000045060", // Note BTC + "AB02000000045028", // Note ETH + "AC79000000000004", // Wallet 4.46 + ) + + private val debugTestDemoCardIds = listOf( + "AB01000000045060", // Note BTC + "AB02000000045028", // Note ETH + "AC79000000000004", // Wallet 4.46 + ) +} + +class DemoTransactionSender( + private val walletManager: WalletManager, + private val sender: TransactionSender = walletManager as TransactionSender +) : TransactionSender { + + override suspend fun getFee(amount: Amount, destination: String): Result> = + 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)) + } + + private fun randomInt(from: Int, to: Int): Int = kotlin.random.Random.nextInt(from, to) + + private fun randomString(length: Int): String { + val charPool: List = ('a'..'z') + ('A'..'Z') + ('0'..'9') + return (1..length) + .map { randomInt(0, charPool.size) } + .map(charPool::get) + .joinToString("") + } + + companion object { + val ID = DemoTransactionSender::class.java.simpleName + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/demo/DemoMiddlewares.kt b/app/src/main/java/com/tangem/tap/features/demo/DemoMiddlewares.kt new file mode 100644 index 0000000000..7537d54bdd --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/demo/DemoMiddlewares.kt @@ -0,0 +1,58 @@ +package com.tangem.tap.features.demo + +import com.tangem.common.extensions.guard +import com.tangem.tap.common.extensions.withMainContext +import com.tangem.tap.domain.extensions.makePrimaryWalletManager +import com.tangem.tap.domain.tasks.product.ScanResponse +import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteAction +import com.tangem.tap.features.wallet.redux.Currency +import com.tangem.tap.features.wallet.redux.ProgressState +import com.tangem.tap.scope +import com.tangem.tap.store +import kotlinx.coroutines.launch +import org.rekotlin.Action + +/** +[REDACTED_AUTHOR] + */ +internal class DemoOnboardingNoteMiddleware : DemoMiddleware { + + override fun tryHandle(config: DemoConfig, scanResponse: ScanResponse, action: Action): Boolean { + val globalState = store.state.globalState + val noteState = store.state.onboardingNoteState + + when (action) { + is OnboardingNoteAction.Balance.Update -> { + val walletManager = if (noteState.walletManager != null) { + noteState.walletManager + } else { + val wmFactory = globalState.tapWalletManager.walletManagerFactory + val walletManager = wmFactory.makePrimaryWalletManager(scanResponse).guard { + return false + } + store.dispatch(OnboardingNoteAction.SetWalletManager(walletManager)) + walletManager + } + val balanceAmount = config.getBalance(walletManager.wallet.blockchain) + val loadedBalance = noteState.walletBalance.copy( + value = balanceAmount.value!!, + currency = Currency.Blockchain(walletManager.wallet.blockchain), + state = ProgressState.Done, + error = null, + criticalError = null + ) + walletManager.wallet.setAmount(balanceAmount) + + scope.launch { + withMainContext { + store.dispatch(OnboardingNoteAction.Balance.Set(loadedBalance)) + store.dispatch(OnboardingNoteAction.Balance.SetCriticalError(loadedBalance.criticalError)) + store.dispatch(OnboardingNoteAction.Balance.SetNonCriticalError(loadedBalance.error)) + } + } + return true + } + } + return false + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/demo/Extentions.kt b/app/src/main/java/com/tangem/tap/features/demo/Extentions.kt new file mode 100644 index 0000000000..f32c079efc --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/demo/Extentions.kt @@ -0,0 +1,12 @@ +package com.tangem.tap.features.demo + +import com.tangem.blockchain.common.Wallet +import com.tangem.blockchain.common.WalletManager +import com.tangem.tap.domain.tasks.product.ScanResponse + +/** +[REDACTED_AUTHOR] + */ +fun ScanResponse.isDemoCard(): Boolean = DemoHelper.isDemoCardId(card.cardId) +fun WalletManager.isDemoWallet(): Boolean = DemoHelper.isDemoCardId(wallet.cardId) +fun Wallet.isDemoWallet(): Boolean = DemoHelper.isDemoCardId(cardId) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt index a8517bd1bc..6db0bf1a97 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt @@ -17,9 +17,11 @@ import com.tangem.tap.domain.tasks.product.ScanResponse import com.tangem.tap.domain.walletconnect.BnbHelper import com.tangem.tap.domain.walletconnect.WalletConnectManager import com.tangem.tap.domain.walletconnect.WalletConnectNetworkUtils +import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.store import com.tangem.wallet.R +import org.rekotlin.Action import org.rekotlin.Middleware class WalletConnectMiddleware { @@ -28,138 +30,131 @@ class WalletConnectMiddleware { val walletConnectMiddleware: Middleware = { dispatch, state -> { next -> { action -> - when (action) { + handle(state, action) + next(action) + } + } + } - is WalletConnectAction.RestoreSessions -> { - walletConnectManager.restoreSessions() - } + private fun handle(state: () -> AppState?, action: Action) { + if (DemoHelper.tryHandle(state, action)) return - is WalletConnectAction.HandleDeepLink -> { - if (!action.wcUri.isNullOrBlank()) { - if (WalletConnectManager.isCorrectWcUri(action.wcUri)) { - store.dispatchOnMain(WalletConnectAction.OpenSession(action.wcUri)) - } - } - } - - is WalletConnectAction.StartWalletConnect -> { - val uri = action.activity.getFromClipboard()?.toString() - if (uri != null && WalletConnectManager.isCorrectWcUri(uri)) { - store.dispatchOnMain(WalletConnectAction.ShowClipboardOrScanQrDialog(uri)) - } else { - store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.QrScan)) - } - } - - is WalletConnectAction.ShowClipboardOrScanQrDialog -> { - store.dispatchOnMain( - GlobalAction.ShowDialog( - WalletConnectDialog.ClipboardOrScanQr( - action.wcUri - ) - ) - ) - } - - is WalletConnectAction.OpeningSessionTimeout -> { - store.dispatchOnMain(GlobalAction.ShowDialog(WalletConnectDialog.SessionTimeout)) - } - - is WalletConnectAction.FailureEstablishingSession -> { - if (action.session != null) { - walletConnectManager.disconnect(action.session) - } - } - - is WalletConnectAction.UnsupportedCard -> { - store.dispatchOnMain(GlobalAction.ShowDialog(WalletConnectDialog.UnsupportedCard)) - } - - is WalletConnectAction.OpenSession -> { - walletConnectManager.connect( - wcUri = action.wcUri, - ) - } - - is WalletConnectAction.RefuseOpeningSession -> { - store.dispatch( - GlobalAction.ShowDialog( - WalletConnectDialog.OpeningSessionRejected - ) - ) - } - - is WalletConnectAction.ScanCard -> { - scanCard(action.session, action.chainId) - } - - is WalletConnectAction.ApproveSession -> { - walletConnectManager.approve(action.session) - } - - is WalletConnectAction.DisconnectSession -> { - walletConnectManager.disconnect(action.session) - } - - is WalletConnectAction.HandleTransactionRequest -> { - walletConnectManager.handleTransactionRequest( - transaction = action.transaction, - session = action.session, - id = action.id, - type = action.type - ) - } - is WalletConnectAction.HandlePersonalSignRequest -> { - walletConnectManager.handlePersonalSignRequest( - message = action.message, - session = action.session, - id = action.id - ) - } - is WalletConnectAction.RejectRequest -> { - walletConnectManager.rejectRequest(action.session, action.id) - } - is WalletConnectAction.SendTransaction -> { - walletConnectManager.completeTransaction(action.session) - } - is WalletConnectAction.SignMessage -> { - walletConnectManager.sendSignedMessage(action.session) - } - is WalletConnectAction.BinanceTransaction.Trade -> { - val messageData = BnbHelper.createMessageData(action.order) - store.dispatchOnMain( - GlobalAction.ShowDialog( - WalletConnectDialog.BnbTransactionDialog( - data = messageData, - session = action.sessionData.session, - sessionId = action.id, - cardId = action.sessionData.wallet.cardId, - dAppName = action.sessionData.peerMeta.name - ) - ) - ) - } - is WalletConnectAction.BinanceTransaction.Transfer -> { - val messageData = BnbHelper.createMessageData(action.order) - store.dispatchOnMain( - GlobalAction.ShowDialog( - WalletConnectDialog.BnbTransactionDialog( - data = messageData, - session = action.sessionData.session, - sessionId = action.id, - cardId = action.sessionData.wallet.cardId, - dAppName = action.sessionData.peerMeta.name - ) - ) - ) - } - is WalletConnectAction.BinanceTransaction.Sign -> { - walletConnectManager.signBnb( - action.id, action.data, action.sessionData - ) + when (action) { + is WalletConnectAction.RestoreSessions -> { + walletConnectManager.restoreSessions() + } + is WalletConnectAction.HandleDeepLink -> { + if (!action.wcUri.isNullOrBlank()) { + if (WalletConnectManager.isCorrectWcUri(action.wcUri)) { + store.dispatchOnMain(WalletConnectAction.OpenSession(action.wcUri)) } } - next(action) + } + is WalletConnectAction.StartWalletConnect -> { + val uri = action.activity.getFromClipboard()?.toString() + if (uri != null && WalletConnectManager.isCorrectWcUri(uri)) { + store.dispatchOnMain(WalletConnectAction.ShowClipboardOrScanQrDialog(uri)) + } else { + store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.QrScan)) + } + } + is WalletConnectAction.ShowClipboardOrScanQrDialog -> { + store.dispatchOnMain( + GlobalAction.ShowDialog( + WalletConnectDialog.ClipboardOrScanQr( + action.wcUri + ) + ) + ) + } + is WalletConnectAction.OpeningSessionTimeout -> { + store.dispatchOnMain(GlobalAction.ShowDialog(WalletConnectDialog.SessionTimeout)) + } + is WalletConnectAction.FailureEstablishingSession -> { + if (action.session != null) { + walletConnectManager.disconnect(action.session) + } + } + is WalletConnectAction.UnsupportedCard -> { + store.dispatchOnMain(GlobalAction.ShowDialog(WalletConnectDialog.UnsupportedCard)) + } + is WalletConnectAction.OpenSession -> { + walletConnectManager.connect( + wcUri = action.wcUri, + ) + } + is WalletConnectAction.RefuseOpeningSession -> { + store.dispatch( + GlobalAction.ShowDialog( + WalletConnectDialog.OpeningSessionRejected + ) + ) + } + is WalletConnectAction.ScanCard -> { + scanCard(action.session, action.chainId) + } + is WalletConnectAction.ApproveSession -> { + walletConnectManager.approve(action.session) + } + is WalletConnectAction.DisconnectSession -> { + walletConnectManager.disconnect(action.session) + } + is WalletConnectAction.HandleTransactionRequest -> { + walletConnectManager.handleTransactionRequest( + transaction = action.transaction, + session = action.session, + id = action.id, + type = action.type + ) + } + is WalletConnectAction.HandlePersonalSignRequest -> { + walletConnectManager.handlePersonalSignRequest( + message = action.message, + session = action.session, + id = action.id + ) + } + is WalletConnectAction.RejectRequest -> { + walletConnectManager.rejectRequest(action.session, action.id) + } + is WalletConnectAction.SendTransaction -> { + walletConnectManager.completeTransaction(action.session) + } + is WalletConnectAction.SignMessage -> { + walletConnectManager.sendSignedMessage(action.session) + } + is WalletConnectAction.BinanceTransaction.Trade -> { + val messageData = BnbHelper.createMessageData(action.order) + store.dispatchOnMain( + GlobalAction.ShowDialog( + WalletConnectDialog.BnbTransactionDialog( + data = messageData, + session = action.sessionData.session, + sessionId = action.id, + cardId = action.sessionData.wallet.cardId, + dAppName = action.sessionData.peerMeta.name + ) + ) + ) + } + is WalletConnectAction.BinanceTransaction.Transfer -> { + val messageData = BnbHelper.createMessageData(action.order) + store.dispatchOnMain( + GlobalAction.ShowDialog( + WalletConnectDialog.BnbTransactionDialog( + data = messageData, + session = action.sessionData.session, + sessionId = action.id, + cardId = action.sessionData.wallet.cardId, + dAppName = action.sessionData.peerMeta.name + ) + ) + ) + } + is WalletConnectAction.BinanceTransaction.Sign -> { + walletConnectManager.signBnb( + action.id, action.data, action.sessionData + ) } } } @@ -190,9 +185,9 @@ class WalletConnectMiddleware { } val walletManager = getWalletManager(scanResponse, blockchain).guard { - store.dispatchOnMain(WalletConnectAction.FailureEstablishingSession(null)) - return - } + store.dispatchOnMain(WalletConnectAction.FailureEstablishingSession(null)) + return + } val wallet = walletManager.wallet val derivedKey = @@ -227,7 +222,7 @@ class WalletConnectMiddleware { ): WalletManager? { val card = scanResponse.card val factory = store.state.globalState.tapWalletManager.walletManagerFactory - val blockchainToMake = if (blockchain == Blockchain.Ethereum && card.isTestCard) { + val blockchainToMake = if (blockchain == Blockchain.Ethereum && card.isTestCard) { Blockchain.EthereumTestnet } else { blockchain diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt index 6a8cc146b7..a611b435d6 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt @@ -13,6 +13,7 @@ import com.tangem.tap.domain.DELAY_SDK_DIALOG_CLOSE import com.tangem.tap.domain.TapError import com.tangem.tap.domain.extensions.hasWallets import com.tangem.tap.domain.extensions.makePrimaryWalletManager +import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.wallet.redux.Currency import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.scope @@ -33,14 +34,16 @@ class OnboardingNoteMiddleware { private val onboardingNoteMiddleware: Middleware = { dispatch, state -> { next -> { action -> - handleNoteAction(action, dispatch) + handleNoteAction(state, action, dispatch) next(action) } } } -private fun handleNoteAction(action: Action, dispatch: DispatchFunction) { +private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch: DispatchFunction) { if (action !is OnboardingNoteAction) return + if (DemoHelper.tryHandle(appState, action)) return + val globalState = store.state.globalState val onboardingManager = globalState.onboardingState.onboardingManager ?: return diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt index 29cdd561b2..9c61e0c402 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt @@ -16,6 +16,7 @@ import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.extensions.hasWallets import com.tangem.tap.domain.tasks.product.ScanResponse +import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.home.redux.HomeAction import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletMiddleware.Companion.BUY_WALLET_URL import com.tangem.tap.features.wallet.redux.Artwork @@ -164,14 +165,16 @@ class BackupMiddleware { val backupMiddleware: Middleware = { dispatch, state -> { next -> { action -> - if (action is BackupAction) handleBackupAction(action) + if (action is BackupAction) handleBackupAction(state, action) next(action) } } } } -private fun handleBackupAction(action: BackupAction) { +private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) { + if (DemoHelper.tryHandle(appState, action)) return + val backupState = store.state.onboardingWalletState.backupState val globalState = store.state.globalState 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 572658b793..34a63dd905 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 @@ -13,6 +13,7 @@ import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsEvent import com.tangem.tap.common.analytics.AnalyticsParam import com.tangem.tap.common.extensions.* +import com.tangem.tap.common.redux.AppDialog import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.navigation.NavigationAction @@ -22,6 +23,8 @@ import com.tangem.tap.domain.TapError import com.tangem.tap.domain.TapWorkarounds.isStart2Coin import com.tangem.tap.domain.configurable.warningMessage.WarningMessage import com.tangem.tap.domain.extensions.minimalAmount +import com.tangem.tap.features.demo.DemoTransactionSender +import com.tangem.tap.features.demo.isDemoWallet import com.tangem.tap.features.send.redux.* import com.tangem.tap.features.send.redux.FeeAction.RequestFee import com.tangem.tap.features.send.redux.states.ButtonState @@ -32,6 +35,7 @@ import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.tangemSdk +import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -164,9 +168,12 @@ private fun sendTransaction( ) ) } - val sendResult = try { - (walletManager as TransactionSender).send(txData, signer) + if (walletManager.isDemoWallet()) { + DemoTransactionSender(walletManager).send(txData, signer) + } else { + (walletManager as TransactionSender).send(txData, signer) + } } catch (ex: Exception) { FirebaseCrashlytics.getInstance().recordException(ex) delay(DELAY_SDK_DIALOG_CLOSE) @@ -238,6 +245,12 @@ private fun sendTransaction( message.contains("Target account is not created. To create account send 1+ XLM.") -> { dispatch(SendAction.SendError(TapError.XmlError.AssetAccountNotCreated)) } + message.contains(DemoTransactionSender.ID) -> { + store.dispatchDialogShow(AppDialog.SimpleOkDialogRes( + R.string.common_done, + R.string.alert_demo_tx_send + )) + } else -> { (sendResult.error as? TangemSdkError)?.let { error -> store.state.globalState.analyticsHandlers?.logCardSdkError( 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 25da5ead8b..1d31def08c 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 @@ -13,6 +13,8 @@ import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.currenciesRepository 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 @@ -37,6 +39,9 @@ class MultiWalletMiddleware { is WalletAction.MultiWallet.AddWalletManagers -> { globalState.feedbackManager?.infoHolder?.setWalletsInfo(action.walletManagers) action.walletManagers.forEach { checkForRentWarning(it) } + if (globalState.scanResponse?.isDemoCard() == true) { + addDummyBalances(action.walletManagers) + } } is WalletAction.MultiWallet.SelectWallet -> { if (action.walletData != null) { @@ -102,28 +107,25 @@ class MultiWalletMiddleware { scope.launch { walletManagers.map { walletManager -> async(Dispatchers.IO) { - try { - walletManager.update() - val wallet = walletManager.wallet - val coinAmount = wallet.amounts[AmountType.Coin]?.value - if (coinAmount != null && !coinAmount.isZero()) { - scope.launch(Dispatchers.Main) { - if (walletState?.getWalletData(wallet.blockchain) == null) { - store.dispatch( - WalletAction.MultiWallet.AddWalletManagers( - listOfNotNull(walletManager) - ) + walletManager.safeUpdate() + val wallet = walletManager.wallet + val coinAmount = wallet.amounts[AmountType.Coin]?.value + if (coinAmount != null && !coinAmount.isZero()) { + scope.launch(Dispatchers.Main) { + if (walletState?.getWalletData(wallet.blockchain) == null) { + store.dispatch( + WalletAction.MultiWallet.AddWalletManagers( + listOfNotNull(walletManager) ) - store.dispatch( - WalletAction.MultiWallet.AddBlockchain( - wallet.blockchain - ) + ) + store.dispatch( + WalletAction.MultiWallet.AddBlockchain( + wallet.blockchain ) - store.dispatch(WalletAction.LoadWallet.Success(wallet)) - } + ) + store.dispatch(WalletAction.LoadWallet.Success(wallet)) } } - } catch (exception: Exception) { } } } @@ -170,6 +172,14 @@ class MultiWalletMiddleware { } } + private fun addDummyBalances(walletManagers: List) { + walletManagers.forEach { + if (it.wallet.fundsAvailable(AmountType.Coin) == BigDecimal.ZERO) { + DemoHelper.injectDemoBalance(it) + } + } + } + private fun addToken(token: Token, walletState: WalletState?, globalState: GlobalState?) { val scanResponse = globalState?.scanResponse ?: return diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt index 2cd5627545..fdf3312ab0 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt @@ -3,10 +3,12 @@ package com.tangem.tap.features.wallet.redux.middlewares import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager import com.tangem.blockchain.common.AmountType import com.tangem.tap.common.extensions.dispatchOnMain +import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.topup.TopUpManager import com.tangem.tap.domain.topup.TradeCryptoHelper +import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.send.redux.PrepareSendScreen import com.tangem.tap.features.send.redux.SendAction import com.tangem.tap.features.wallet.redux.Currency @@ -18,7 +20,9 @@ import timber.log.Timber class TradeCryptoMiddleware { - fun handle(action: WalletAction.TradeCryptoAction) { + fun handle(state: () -> AppState?, action: WalletAction.TradeCryptoAction) { + if (DemoHelper.tryHandle(state, action)) return + when (action) { is WalletAction.TradeCryptoAction.Buy -> startExchange(action) is WalletAction.TradeCryptoAction.Sell -> startExchange(action) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index 37b71f1c2a..088fe72d40 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -3,13 +3,15 @@ package com.tangem.tap.features.wallet.redux.middlewares import android.content.Intent import android.net.Uri import androidx.core.content.ContextCompat -import com.tangem.blockchain.common.* +import com.tangem.blockchain.common.Amount +import com.tangem.blockchain.common.AmountType +import com.tangem.blockchain.common.Wallet +import com.tangem.blockchain.common.WalletManager import com.tangem.common.CompletionResult import com.tangem.common.core.TangemSdkError import com.tangem.common.extensions.isZero import com.tangem.common.services.Result import com.tangem.operations.attestation.OnlineCardVerifier -import com.tangem.tap.* import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.extensions.* import com.tangem.tap.common.redux.AppDialog @@ -18,10 +20,14 @@ import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.extensions.toSendableAmounts +import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.home.redux.HomeAction import com.tangem.tap.features.send.redux.PrepareSendScreen import com.tangem.tap.features.wallet.redux.* import com.tangem.tap.network.NetworkStateChanged +import com.tangem.tap.scope +import com.tangem.tap.store +import com.tangem.tap.tangemSdkManager import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.launch @@ -37,18 +43,20 @@ class WalletMiddleware { val walletMiddleware: Middleware = { dispatch, state -> { next -> { action -> - handleAction(action, dispatch) + handleAction(state, action, dispatch) next(action) } } } - private fun handleAction(action: Action, dispatch: DispatchFunction) { + private fun handleAction(state: () -> AppState?, action: Action, dispatch: DispatchFunction) { + if (DemoHelper.tryHandle(state, action)) return + val globalState = store.state.globalState val walletState = store.state.walletState when (action) { - is WalletAction.TradeCryptoAction -> tradeCryptoMiddleware.handle(action) + is WalletAction.TradeCryptoAction -> tradeCryptoMiddleware.handle(state, action) is WalletAction.Warnings -> warningsMiddleware.handle(action, globalState) is WalletAction.MultiWallet -> multiWalletMiddleware.handle(action, walletState, globalState) is WalletAction.LoadWallet -> { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt index 408f0ef8a3..b7c104861d 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt @@ -17,6 +17,7 @@ import com.tangem.tap.domain.extensions.hasSignedHashes import com.tangem.tap.domain.extensions.remainingSignatures import com.tangem.tap.domain.isMultiwalletAllowed import com.tangem.tap.domain.tasks.product.ScanResponse +import com.tangem.tap.features.demo.isDemoCard import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.network.NetworkConnectivity import com.tangem.tap.preferencesStorage @@ -99,6 +100,9 @@ class WarningsMiddleware { addWarningMessage(WarningMessagesManager.onlineVerificationFailed()) } } + if (scanResponse.isDemoCard()){ + addWarningMessage(WarningMessagesManager.demoCardWarning()) + } setWarningMessages() } } 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 new file mode 100644 index 0000000000..aa15f94e9f --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/SimpleOkDialog.kt @@ -0,0 +1,35 @@ +package com.tangem.tap.features.wallet.ui.dialogs + +import android.content.Context +import androidx.appcompat.app.AlertDialog +import com.tangem.tap.common.extensions.dispatchDialogHide +import com.tangem.tap.common.redux.AppDialog +import com.tangem.tap.store +import com.tangem.wallet.R + +/** +[REDACTED_AUTHOR] + */ +class SimpleOkDialog { + + companion object { + fun create(dialog: AppDialog.SimpleOkDialog, context: Context): AlertDialog { + return AlertDialog.Builder(context).apply { + setTitle(dialog.header) + setMessage(dialog.message) + setPositiveButton(R.string.common_ok) { _, _ -> } + setOnDismissListener { store.dispatchDialogHide() } + }.create() + } + + fun create(dialog: AppDialog.SimpleOkDialogRes, context: Context): AlertDialog { + return AlertDialog.Builder(context).apply { + setTitle(context.getString(dialog.headerId)) + setMessage(dialog.messageId) + setPositiveButton(R.string.common_ok) { _, _ -> } + setOnDismissListener { store.dispatchDialogHide() } + }.create() + } + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_shop.xml b/app/src/main/res/layout/fragment_shop.xml index ef4297ba3d..9ad04edbdd 100644 --- a/app/src/main/res/layout/fragment_shop.xml +++ b/app/src/main/res/layout/fragment_shop.xml @@ -26,7 +26,7 @@ android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:navigationIcon="@drawable/ic_clear_24" - app:title="@string/shop_title" + app:title="@string/home_button_order" app:titleCentered="true" /> diff --git a/app/src/main/res/values-de/strings_final.xml b/app/src/main/res/values-de/strings_final.xml new file mode 100644 index 0000000000..339691d69b --- /dev/null +++ b/app/src/main/res/values-de/strings_final.xml @@ -0,0 +1,37 @@ + + + One Wallet + 3 cards + 2 cards + Shipping + Free + I have a promo code… + Total + Other payment methods + Buy now + Placing your order + Your order + Meet\nTangem + Buy + Store + Send + Pay + Exchange + Lend + Borrow + Stake + Revolutionary Hardware Wallet + Store your crypto assets secure while keeping private keys contained in your card + Ultra Secure Backup + 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 + 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 + 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. + \ 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 new file mode 100644 index 0000000000..339691d69b --- /dev/null +++ b/app/src/main/res/values-fr/strings_final.xml @@ -0,0 +1,37 @@ + + + One Wallet + 3 cards + 2 cards + Shipping + Free + I have a promo code… + Total + Other payment methods + Buy now + Placing your order + Your order + Meet\nTangem + Buy + Store + Send + Pay + Exchange + Lend + Borrow + Stake + Revolutionary Hardware Wallet + Store your crypto assets secure while keeping private keys contained in your card + Ultra Secure Backup + 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 + 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 + 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. + \ 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 new file mode 100644 index 0000000000..339691d69b --- /dev/null +++ b/app/src/main/res/values-it/strings_final.xml @@ -0,0 +1,37 @@ + + + One Wallet + 3 cards + 2 cards + Shipping + Free + I have a promo code… + Total + Other payment methods + Buy now + Placing your order + Your order + Meet\nTangem + Buy + Store + Send + Pay + Exchange + Lend + Borrow + Stake + Revolutionary Hardware Wallet + Store your crypto assets secure while keeping private keys contained in your card + Ultra Secure Backup + 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 + 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 + 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. + \ 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 new file mode 100644 index 0000000000..dac3254b83 --- /dev/null +++ b/app/src/main/res/values-ru/strings_final.xml @@ -0,0 +1,37 @@ + + + Один Кошелек + 3 карты + 2 карты + Доставка + Бесплатно + У меня есть промо-код… + Итого + Другие способы оплаты + Купить сейчас + Оформление вашего заказа + Ваш заказ + Встречайте\nTangem + Покупайте + Храните + Отправляйте + Расплачивайтесь + Обменивайте + Одалживайте + Занимайте + Вкладывайте + Революционный аппаратный кошелек + Держите свои криптосбережения в безопасности - приватные ключи надежно хранятся на карте + Ультрабезопасная резервная копия + До трех карт с одним кошельком + Тысячи криптовалют + Аппаратный кошелек для ваших биткоинов, эфира и многих других валют одновременно — все в одной карте + Поддерживает Web3 + Обменивайте, покупайте 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 new file mode 100644 index 0000000000..339691d69b --- /dev/null +++ b/app/src/main/res/values/strings_final.xml @@ -0,0 +1,37 @@ + + + One Wallet + 3 cards + 2 cards + Shipping + Free + I have a promo code… + Total + Other payment methods + Buy now + Placing your order + Your order + Meet\nTangem + Buy + Store + Send + Pay + Exchange + Lend + Borrow + Stake + Revolutionary Hardware Wallet + Store your crypto assets secure while keeping private keys contained in your card + Ultra Secure Backup + 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 + 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 + 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. + \ No newline at end of file diff --git a/app/src/main/res/values/strings_untranslated.xml b/app/src/main/res/values/strings_untranslated.xml index d52e9f1f7b..f746827108 100644 --- a/app/src/main/res/values/strings_untranslated.xml +++ b/app/src/main/res/values/strings_untranslated.xml @@ -331,16 +331,4 @@ Amount to pay: %s Please tell us more about your issue. Every small detail can help. Following information is optional. You can erase it if you don’t want to share it. - One Wallet - 3 cards - 2 cards - Shipping - Free - I have a promo code... - Total - Other payment methods - Buy now - Order card - Delivery (Free shipping) -