diff --git a/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt b/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt index 3da94dc568..f5281cc796 100644 --- a/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt +++ b/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt @@ -5,6 +5,7 @@ import android.content.Intent import com.google.android.gms.wallet.PaymentData import com.shopify.buy3.Storefront import com.tangem.tap.common.analytics.AnalyticsHandler +import com.tangem.tap.common.extensions.filterNotNull import com.tangem.tap.common.shop.data.ProductType import com.tangem.tap.common.shop.data.TangemProduct import com.tangem.tap.common.shop.data.TotalSum @@ -21,7 +22,6 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) { private val shopifyService = ShopifyService(application, shopifyShop) - private lateinit var product: Storefront.Product private val checkouts = mutableMapOf() private val variants = mutableMapOf() @@ -31,22 +31,19 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) { suspend fun getProducts(): Result> { val result = shopifyService.getProducts() - result.onSuccess { - product = it.first { - val variantsSku = it.variants.edges.map { it.node.sku } - variantsSku.contains(ProductType.WALLET_2_CARDS.sku) && variantsSku.contains( - ProductType.WALLET_3_CARDS.sku - ) - } - product.variants.edges.map { it.node } - .forEach { variant -> - if (variant.sku == ProductType.WALLET_2_CARDS.sku) { - variants[ProductType.WALLET_2_CARDS] = variant - } else if (variant.sku == ProductType.WALLET_3_CARDS.sku) { - variants[ProductType.WALLET_3_CARDS] = variant - } - } + return result.mapCatching { product -> + val availableVariants = product + .flatMap { it.variants.edges.map { it.node } } + .filter { SKUS_TO_DISPLAY.contains(it.sku) } + .associateBy { ProductType.fromSku(it.sku) } + .filterNotNull() + variants.putAll(availableVariants) + if (variants.size < SKUS_TO_DISPLAY.size) { + return Result.failure(Exception( + "Shopify: products are missing, " + + "\nproducts available: ${variants.keys.map { it.sku }}")) + } val twoCardsProduct = TangemProduct( type = ProductType.WALLET_2_CARDS, @@ -65,7 +62,6 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) { createCheckouts() return Result.success(listOf(twoCardsProduct, threeCardsProduct)) } - return Result.failure(result.exceptionOrNull()!!) } private suspend fun createCheckouts() { @@ -214,6 +210,7 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) { companion object { const val TANGEM_WALLET_2_CARDS_SKU = "TG115x2" const val TANGEM_WALLET_3_CARDS_SKU = "TG115x3" + val SKUS_TO_DISPLAY = listOf(TANGEM_WALLET_2_CARDS_SKU, TANGEM_WALLET_3_CARDS_SKU) } } diff --git a/app/src/main/java/com/tangem/tap/common/shop/data/ProductType.kt b/app/src/main/java/com/tangem/tap/common/shop/data/ProductType.kt index 89116f8096..d8db451147 100644 --- a/app/src/main/java/com/tangem/tap/common/shop/data/ProductType.kt +++ b/app/src/main/java/com/tangem/tap/common/shop/data/ProductType.kt @@ -4,5 +4,15 @@ import com.tangem.tap.common.shop.TangemShopService enum class ProductType(val sku: String) { WALLET_2_CARDS(TangemShopService.TANGEM_WALLET_2_CARDS_SKU), - WALLET_3_CARDS(TangemShopService.TANGEM_WALLET_3_CARDS_SKU) + WALLET_3_CARDS(TangemShopService.TANGEM_WALLET_3_CARDS_SKU); + + companion object { + fun fromSku(sku: String): ProductType? { + return when (sku) { + WALLET_2_CARDS.sku -> WALLET_2_CARDS + WALLET_3_CARDS.sku -> WALLET_3_CARDS + else -> null + } + } + } } \ No newline at end of file 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 cce3a27c15..123c26f691 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -26,7 +26,7 @@ import kotlinx.coroutines.withContext class TapWalletManager { val walletManagerFactory: WalletManagerFactory - by lazy { WalletManagerFactory(blockchainSdkConfig) } + by lazy { WalletManagerFactory(blockchainSdkConfig) } val rates: RatesRepository = RatesRepository() @@ -34,10 +34,10 @@ class TapWalletManager { store.state.globalState.configManager?.config?.blockchainSdkConfig ?: BlockchainSdkConfig() } - private val walletManagersThrottler = ThrottlerWithValues>(10000) + private val walletManagersThrottler = + ThrottlerWithValues>(10000) suspend fun loadWalletData(walletManager: WalletManager) { - val blockchain = walletManager.wallet.blockchain val blockchainNetwork = BlockchainNetwork.fromWalletManager(walletManager) val result = if (walletManagersThrottler.isStillThrottled(blockchainNetwork)) { walletManagersThrottler.geValue(blockchainNetwork)!! @@ -54,17 +54,21 @@ class TapWalletManager { is Result.Failure -> { when (result.error) { is TapError.WalletManager.NoAccountError -> { - dispatchOnMain(WalletAction.LoadWallet.NoAccount( - walletManager.wallet, - blockchainNetwork, - (result.error as TapError.WalletManager.NoAccountError).customMessage - )) + dispatchOnMain( + WalletAction.LoadWallet.NoAccount( + walletManager.wallet, + blockchainNetwork, + (result.error as TapError.WalletManager.NoAccountError).customMessage + ) + ) } else -> { - dispatchOnMain(WalletAction.LoadWallet.Failure( - walletManager.wallet, - result.error.localizedMessage - )) + dispatchOnMain( + WalletAction.LoadWallet.Failure( + walletManager.wallet, + result.error.localizedMessage + ) + ) } } } @@ -109,6 +113,37 @@ class TapWalletManager { return } + if (data.card.isMultiwalletAllowed) { + loadMultiWalletData(data) + } else { + loadSingleWalletData(data) + } + + dispatchOnMain(WalletAction.LoadWallet()) + dispatchOnMain(WalletAction.LoadFiatRate()) + } + + private suspend fun loadMultiWalletData( + scanResponse: ScanResponse + ) { + val savedCurrencies = currenciesRepository.loadSavedCurrencies( + scanResponse.card.cardId, scanResponse.card.settings.isHDWalletAllowed + ) + if (savedCurrencies.isEmpty()) return + + val walletManagers = + walletManagerFactory.makeWalletManagersForApp(scanResponse, savedCurrencies) + dispatchOnMain( + WalletAction.MultiWallet.AddBlockchains(savedCurrencies, walletManagers), + ) + savedCurrencies.map { + if (it.tokens.isNotEmpty()) { + dispatchOnMain(WalletAction.MultiWallet.AddTokens(it.tokens, it)) + } + } + } + + private suspend fun loadSingleWalletData(data: ScanResponse) { val blockchain = data.getBlockchain() val primaryWalletManager = walletManagerFactory.makePrimaryWalletManager(data) @@ -120,87 +155,12 @@ class TapWalletManager { primaryWalletManager.addToken(primaryToken) dispatchOnMain(WalletAction.MultiWallet.SetPrimaryToken(primaryToken)) } - if (data.card.isMultiwalletAllowed) { - loadMultiWalletData(data, blockchain, primaryWalletManager) - } else { - dispatchOnMain(WalletAction.MultiWallet.AddBlockchains( + dispatchOnMain( + WalletAction.MultiWallet.AddBlockchains( listOf(BlockchainNetwork.fromWalletManager(primaryWalletManager)), listOf(primaryWalletManager) - )) - } - } else { - if (data.card.isMultiwalletAllowed) { - loadMultiWalletData(data, blockchain, null) - } - } - dispatchOnMain(WalletAction.LoadWallet()) - dispatchOnMain(WalletAction.LoadFiatRate()) - } - - private suspend fun loadMultiWalletData( - scanResponse: ScanResponse, - primaryBlockchain: Blockchain?, - primaryWalletManager: WalletManager? - ) { - val primaryTokens = primaryWalletManager?.cardTokens?.toList() ?: emptyList() - val savedCurrencies = currenciesRepository.loadSavedCurrencies( - scanResponse.card.cardId, scanResponse.card.settings.isHDWalletAllowed - ) - - if (savedCurrencies.isEmpty()) { - if (primaryBlockchain != null && primaryWalletManager != null) { - val blockchainNetwork = BlockchainNetwork.fromWalletManager(primaryWalletManager) - dispatchOnMain( - WalletAction.MultiWallet.SaveCurrencies(listOf(blockchainNetwork)), - WalletAction.MultiWallet.AddBlockchains( - listOf(blockchainNetwork), - listOf(primaryWalletManager) - ), - WalletAction.MultiWallet.AddTokens(primaryTokens.toList(), blockchainNetwork) ) - - } else { - val blockchainNetworks = listOf( - BlockchainNetwork(Blockchain.Bitcoin, scanResponse.card), - BlockchainNetwork(Blockchain.Ethereum, scanResponse.card) - ) - - val walletManagers = walletManagerFactory.makeWalletManagersForApp( - scanResponse, - blockchainNetworks - ) - - dispatchOnMain( - WalletAction.MultiWallet.SaveCurrencies(blockchainNetworks), - WalletAction.MultiWallet.AddBlockchains(blockchainNetworks, walletManagers), - ) - } -// dispatchOnMain( -// WalletAction.MultiWallet.FindBlockchainsInUse, -// WalletAction.MultiWallet.FindTokensInUse, -// ) - } else { - val walletManagers = if ( - primaryTokens.isNotEmpty() && - primaryWalletManager != null && - primaryBlockchain != null && primaryBlockchain != Blockchain.Unknown - ) { - val blockchainsWithoutPrimary = savedCurrencies.filterNot { it.blockchain == primaryBlockchain } - walletManagerFactory.makeWalletManagersForApp( - scanResponse, - blockchainsWithoutPrimary - ).plus(primaryWalletManager) - } else { - walletManagerFactory.makeWalletManagersForApp(scanResponse, savedCurrencies) - } - dispatchOnMain( - WalletAction.MultiWallet.AddBlockchains(savedCurrencies, walletManagers), ) - savedCurrencies.map { - if (it.tokens.isNotEmpty()) { - dispatchOnMain(WalletAction.MultiWallet.AddTokens(it.tokens, it)) - } - } } } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt index 0f854da103..e470680dbc 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt @@ -1,5 +1,6 @@ package com.tangem.tap.features.onboarding.products.otherCards.redux +import com.tangem.blockchain.common.Blockchain import com.tangem.common.CompletionResult import com.tangem.domain.common.extensions.withMainContext import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE @@ -10,6 +11,8 @@ 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.hasWallets +import com.tangem.tap.domain.tokens.models.BlockchainNetwork +import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.tangemSdkManager @@ -73,6 +76,21 @@ private fun handleOtherCardsAction(action: Action, dispatch: DispatchFunction) { onboardingManager.scanResponse = updatedResponse onboardingManager.activationStarted(updatedResponse.card.cardId) + val primaryBlockchain = updatedResponse.getBlockchain() + val blockchainNetworks = if (primaryBlockchain != Blockchain.Unknown) { + val primaryToken = updatedResponse.getPrimaryToken() + val blockchainNetwork = BlockchainNetwork(primaryBlockchain, updatedResponse.card).updateTokens( + listOfNotNull(primaryToken)) + listOf(blockchainNetwork) + } else { + listOf( + BlockchainNetwork(Blockchain.Bitcoin, updatedResponse.card), + BlockchainNetwork(Blockchain.Ethereum, updatedResponse.card) + ) + } + + store.dispatch(WalletAction.MultiWallet.SaveCurrencies(blockchainNetworks)) + delay(DELAY_SDK_DIALOG_CLOSE) store.dispatch(OnboardingOtherCardsAction.SetStepOfScreen(OnboardingOtherCardsStep.Done)) } 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 c880488141..88121813ad 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 @@ -1,5 +1,6 @@ package com.tangem.tap.features.onboarding.products.wallet.redux +import com.tangem.blockchain.common.Blockchain import com.tangem.common.CompletionResult import com.tangem.common.card.Card import com.tangem.domain.common.ScanResponse @@ -12,9 +13,11 @@ 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.hasWallets +import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.home.redux.HomeAction import com.tangem.tap.features.wallet.redux.Artwork +import com.tangem.tap.features.wallet.redux.WalletAction import kotlinx.coroutines.launch import org.rekotlin.Action import org.rekotlin.Middleware @@ -84,6 +87,11 @@ private fun handleWalletAction(action: Action) { primaryCard = result.data.primaryCard ) onboardingManager.scanResponse = updatedResponse + val blockchainNetworks = listOf( + BlockchainNetwork(Blockchain.Bitcoin, result.data.card), + BlockchainNetwork(Blockchain.Ethereum, result.data.card) + ) + store.dispatchOnMain(WalletAction.MultiWallet.SaveCurrencies(blockchainNetworks)) onboardingManager.activationStarted(updatedResponse.card.cardId) store.dispatch(OnboardingWalletAction.ProceedBackup) } @@ -260,6 +268,11 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) backupService.proceedBackup { result -> when (result) { is CompletionResult.Success -> { + val blockchainNetworks = listOf( + BlockchainNetwork(Blockchain.Bitcoin, result.data), + BlockchainNetwork(Blockchain.Ethereum, result.data) + ) + store.dispatchOnMain(WalletAction.MultiWallet.SaveCurrencies(blockchainNetworks)) if (backupService.currentState == BackupService.State.Finished) { store.dispatchOnMain(BackupAction.FinishBackup) } else { diff --git a/app/src/main/java/com/tangem/tap/features/shop/redux/ShopAction.kt b/app/src/main/java/com/tangem/tap/features/shop/redux/ShopAction.kt index 500cc39285..27a4a5b9e5 100644 --- a/app/src/main/java/com/tangem/tap/features/shop/redux/ShopAction.kt +++ b/app/src/main/java/com/tangem/tap/features/shop/redux/ShopAction.kt @@ -1,15 +1,20 @@ package com.tangem.tap.features.shop.redux import android.content.Intent +import com.tangem.tap.common.redux.NotificationAction import com.tangem.tap.common.shop.GooglePayService import com.tangem.tap.common.shop.data.ProductType import com.tangem.tap.common.shop.data.TangemProduct +import com.tangem.wallet.R import org.rekotlin.Action sealed class ShopAction : Action { object LoadProducts : ShopAction() { data class Success(val products: List) : ShopAction() + object Failure : ShopAction(), NotificationAction { + override val messageResource = R.string.common_server_unavailable + } } data class ApplyPromoCode(val promoCode: String) : ShopAction() { diff --git a/app/src/main/java/com/tangem/tap/features/shop/redux/ShopMiddleware.kt b/app/src/main/java/com/tangem/tap/features/shop/redux/ShopMiddleware.kt index 464a99de96..f3734950da 100644 --- a/app/src/main/java/com/tangem/tap/features/shop/redux/ShopMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/shop/redux/ShopMiddleware.kt @@ -11,6 +11,7 @@ import com.tangem.tap.store import kotlinx.coroutines.launch import org.rekotlin.Action import org.rekotlin.Middleware +import timber.log.Timber class ShopMiddleware { @@ -88,10 +89,13 @@ private fun handle(action: Action) { } ShopAction.LoadProducts -> { scope.launch { - val result = shopService.getProducts() - result.onSuccess { - store.dispatchOnMain(ShopAction.LoadProducts.Success(it)) - } + shopService.getProducts().fold( + onSuccess = { store.dispatchOnMain(ShopAction.LoadProducts.Success(it)) }, + onFailure = { + Timber.e(it) + store.dispatchOnMain(ShopAction.LoadProducts.Failure) + } + ) } } is ShopAction.CheckIfGooglePayAvailable -> { diff --git a/app/src/main/java/com/tangem/tap/features/shop/redux/ShopReducer.kt b/app/src/main/java/com/tangem/tap/features/shop/redux/ShopReducer.kt index ee12f53109..001c48a46f 100644 --- a/app/src/main/java/com/tangem/tap/features/shop/redux/ShopReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/shop/redux/ShopReducer.kt @@ -65,5 +65,6 @@ private fun internalReduce(action: Action, state: ShopState): ShopState { } ShopAction.FinishSuccessfulOrder -> state ShopAction.ResetState -> ShopState() + ShopAction.LoadProducts.Failure -> state } } \ 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 d2c6336c24..3db72281cf 100644 --- a/app/src/main/res/values-de/strings_final.xml +++ b/app/src/main/res/values-de/strings_final.xml @@ -47,6 +47,7 @@ Custom Notice Attention + The server is not available, please try again later Hide %s Hide diff --git a/app/src/main/res/values-fr/strings_final.xml b/app/src/main/res/values-fr/strings_final.xml index d2c6336c24..d6072291e5 100644 --- a/app/src/main/res/values-fr/strings_final.xml +++ b/app/src/main/res/values-fr/strings_final.xml @@ -45,6 +45,7 @@ If you chose the wrong network during your crypto transfer from the exchange, this guide will help you recover your funds Custom + The server is not available, please try again later Notice Attention diff --git a/app/src/main/res/values-it/strings_final.xml b/app/src/main/res/values-it/strings_final.xml index d2c6336c24..d6072291e5 100644 --- a/app/src/main/res/values-it/strings_final.xml +++ b/app/src/main/res/values-it/strings_final.xml @@ -45,6 +45,7 @@ If you chose the wrong network during your crypto transfer from the exchange, this guide will help you recover your funds Custom + The server is not available, please try again later Notice Attention diff --git a/app/src/main/res/values-ru/strings_final.xml b/app/src/main/res/values-ru/strings_final.xml index d3299007a1..dae52fe357 100644 --- a/app/src/main/res/values-ru/strings_final.xml +++ b/app/src/main/res/values-ru/strings_final.xml @@ -47,6 +47,7 @@ Пользовательский Уведомление Внимание + Сервер недоступен, повторите попытку позднее Баланс В сумме учтены не все монеты diff --git a/app/src/main/res/values/strings_final.xml b/app/src/main/res/values/strings_final.xml index 99845e1fb7..15688ccc8d 100644 --- a/app/src/main/res/values/strings_final.xml +++ b/app/src/main/res/values/strings_final.xml @@ -47,6 +47,7 @@ Custom Notice Attention + The server is not available, please try again later Total balance The amount does not include some of your funds