From 5ec60f0cce8ebf4ff7114ab945d4861aa97a3b70 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 21 Oct 2021 19:19:59 +0300 Subject: [PATCH 01/18] Updated on 2026-08-14 --- .../java/com/tangem/tap/domain/ProductType.kt | 2 +- .../tangem/tap/domain/tasks/ScanNoteTask.kt | 4 +-- .../CreateProductWalletAndRescanTask.kt | 2 +- .../domain/tasks/product/ScanProductTask.kt | 26 +++++++++++-------- .../tap/domain/twins/TwinCardsManager.kt | 12 ++------- .../tangem/tap/domain/twins/TwinsHelper.kt | 9 +++++++ .../features/onboarding/OnboardingHelper.kt | 20 +++++++++++--- 7 files changed, 47 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/ProductType.kt b/app/src/main/java/com/tangem/tap/domain/ProductType.kt index 02f0246c82..07cbea8905 100644 --- a/app/src/main/java/com/tangem/tap/domain/ProductType.kt +++ b/app/src/main/java/com/tangem/tap/domain/ProductType.kt @@ -4,5 +4,5 @@ package com.tangem.tap.domain [REDACTED_AUTHOR] */ enum class ProductType { - Note, Wallet, Twin, Other + Note, Wallet, Twins, Other } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt index b2b415dc15..3b01ae1c98 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt @@ -16,7 +16,7 @@ import com.tangem.tap.domain.TapWorkarounds.isExcluded import com.tangem.tap.domain.TapWorkarounds.isTangemNote import com.tangem.tap.domain.extensions.getSingleWallet import com.tangem.tap.domain.tasks.product.ScanResponse -import com.tangem.tap.domain.twins.TwinCardsManager +import com.tangem.tap.domain.twins.TwinsHelper import com.tangem.tap.domain.twins.isTangemTwin class ScanNoteTask(val card: Card? = null) : CardSessionRunnable { @@ -92,7 +92,7 @@ class ScanNoteTask(val card: Card? = null) : CardSessionRunnable { callback(CompletionResult.Success(ScanResponse(card, ProductType.Other, null))) return@run } - val verified = TwinCardsManager.verifyTwinPublicKey( + val verified = TwinsHelper.verifyTwinPublicKey( readDataResult.data.issuerData, publicKey ) if (verified) { diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletAndRescanTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletAndRescanTask.kt index 3b3c6ea2ae..92beb01238 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletAndRescanTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletAndRescanTask.kt @@ -45,7 +45,7 @@ private class CreateProductWalletTask( override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) { val commandProcessor = when (type) { ProductType.Note -> CreateWalletTangemNote() - ProductType.Twin -> throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet") + ProductType.Twins -> throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet") ProductType.Wallet -> CreateWalletTangemWallet() else -> CreateWalletOtherCards() } diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt index cdb63d456b..34f8f201f7 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt @@ -24,7 +24,7 @@ import com.tangem.tap.domain.TapWorkarounds.isExcluded import com.tangem.tap.domain.TapWorkarounds.isTangemNote import com.tangem.tap.domain.TapWorkarounds.isTangemWallet import com.tangem.tap.domain.extensions.getSingleWallet -import com.tangem.tap.domain.twins.TwinCardsManager +import com.tangem.tap.domain.twins.TwinsHelper import com.tangem.tap.domain.twins.isTangemTwin data class ScanResponse( @@ -43,13 +43,17 @@ data class ScanResponse( fun getPrimaryToken(): Token? { val cardToken = walletData?.token ?: return null return Token( - cardToken.name, - cardToken.symbol, - cardToken.contractAddress, - cardToken.decimals, - Blockchain.fromId(walletData.blockchain) + cardToken.name, + cardToken.symbol, + cardToken.contractAddress, + cardToken.decimals, + Blockchain.fromId(walletData.blockchain) ) } + + fun twinsIsTwinned(): Boolean { + return walletData != null && secondTwinPublicKey != null + } } class ScanProductTask(val card: Card? = null) : CardSessionRunnable { @@ -120,21 +124,21 @@ private class ScanTwinProcessor : ProductCommandProcessor { is CompletionResult.Success -> { val publicKey = card.getSingleWallet()?.publicKey if (publicKey == null) { - callback(CompletionResult.Success(ScanResponse(card, ProductType.Twin, null))) + callback(CompletionResult.Success(ScanResponse(card, ProductType.Twins, null))) return@run } - val verified = TwinCardsManager.verifyTwinPublicKey(readDataResult.data.issuerData, publicKey) + val verified = TwinsHelper.verifyTwinPublicKey(readDataResult.data.issuerData, publicKey) if (verified) { val twinPublicKey = readDataResult.data.issuerData.sliceArray(0 until 65) val walletData = session.environment.walletData - val response = ScanResponse(card, ProductType.Twin, walletData, twinPublicKey.toHexString()) + val response = ScanResponse(card, ProductType.Twins, walletData, twinPublicKey.toHexString()) callback(CompletionResult.Success(response)) } else { - callback(CompletionResult.Success(ScanResponse(card, ProductType.Twin, null))) + callback(CompletionResult.Success(ScanResponse(card, ProductType.Twins, null))) } } is CompletionResult.Failure -> - callback(CompletionResult.Success(ScanResponse(card, ProductType.Twin, null))) + callback(CompletionResult.Success(ScanResponse(card, ProductType.Twins, null))) } } } diff --git a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt index d2d8aa143c..df48e76971 100644 --- a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt @@ -11,7 +11,6 @@ import com.tangem.common.KeyPair import com.tangem.common.core.TangemSdkError import com.tangem.common.extensions.hexToBytes import com.tangem.common.extensions.toHexString -import com.tangem.crypto.CryptoUtils import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler import com.tangem.tap.common.extensions.readAssetAsString import com.tangem.tap.domain.tasks.product.ScanResponse @@ -21,7 +20,8 @@ import com.tangem.tap.tangemSdkManager class TwinCardsManager(private val scanResponse: ScanResponse, context: Context) { private val currentCardId: String = scanResponse.card.cardId -// private val secondCardId: String? = TwinsHelper.getTwinsCardId(currentCardId) + + // private val secondCardId: String? = TwinsHelper.getTwinsCardId(currentCardId) private val secondCardId: String? = null private var currentCardPublicKey: String? = null @@ -108,14 +108,6 @@ class TwinCardsManager(private val scanResponse: ScanResponse, context: Context) } companion object { - fun verifyTwinPublicKey(issuerData: ByteArray, cardWalletPublicKey: ByteArray?): Boolean { - if (issuerData.size < 65 || cardWalletPublicKey == null) return false - - val publicKey = issuerData.sliceArray(0 until 65) - val signedKey = issuerData.sliceArray(65 until issuerData.size) - return CryptoUtils.verify(cardWalletPublicKey, publicKey, signedKey) - } - private fun getIssuerKeys(context: Context, publicKey: String): KeyPair { val issuer = getIssuers(context).first { it.publicKey == publicKey } return KeyPair( diff --git a/app/src/main/java/com/tangem/tap/domain/twins/TwinsHelper.kt b/app/src/main/java/com/tangem/tap/domain/twins/TwinsHelper.kt index 65c4d7cb53..89affa15d1 100644 --- a/app/src/main/java/com/tangem/tap/domain/twins/TwinsHelper.kt +++ b/app/src/main/java/com/tangem/tap/domain/twins/TwinsHelper.kt @@ -1,11 +1,20 @@ package com.tangem.tap.domain.twins import com.tangem.common.card.Card +import com.tangem.crypto.CryptoUtils class TwinsHelper { companion object { const val TWIN_FILE_NAME = "TwinPublicKey" + fun verifyTwinPublicKey(issuerData: ByteArray, cardWalletPublicKey: ByteArray?): Boolean { + if (issuerData.size < 65 || cardWalletPublicKey == null) return false + + val publicKey = issuerData.sliceArray(0 until 65) + val signedKey = issuerData.sliceArray(65 until issuerData.size) + return CryptoUtils.verify(cardWalletPublicKey, publicKey, signedKey) + } + fun getTwinCardNumber(cardId: String): TwinCardNumber? { return when { firstCardSeries.map { cardId.startsWith(it) }.contains(true) -> { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt index 38b2517ad1..6a097f6511 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt @@ -12,14 +12,28 @@ import com.tangem.tap.preferencesStorage class OnboardingHelper { companion object { - fun isOnboardingCase(response: ScanResponse): Boolean = if (response.card.hasWallets()) - preferencesStorage.usedCardsPrefStorage.activationIsStarted(response.card.cardId) else true + fun isOnboardingCase(response: ScanResponse): Boolean { + val cardInfoStorage = preferencesStorage.usedCardsPrefStorage + return when { + response.productType == ProductType.Twins -> { + if (!response.twinsIsTwinned()) { + true + } else { + cardInfoStorage.activationIsStarted(response.card.cardId) + } + } + response.card.hasWallets() -> { + cardInfoStorage.activationIsStarted(response.card.cardId) + } + else -> true + } + } fun whereToNavigate(scanResponse: ScanResponse): AppScreen { return when (scanResponse.productType) { ProductType.Note -> AppScreen.OnboardingNote ProductType.Wallet -> AppScreen.OnboardingWallet - ProductType.Twin -> AppScreen.OnboardingTwins + ProductType.Twins -> AppScreen.OnboardingTwins ProductType.Other -> AppScreen.OnboardingOther } } From 7379f3555a965c7f5d4898b1689af1ab6dd58bab Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 21 Oct 2021 20:42:12 +0300 Subject: [PATCH 02/18] Updated on 2026-08-14 --- .../tap/common/extensions/Navigation.kt | 16 +- .../com/tangem/tap/common/redux/AppState.kt | 26 ++-- .../com/tangem/tap/domain/TapWalletManager.kt | 26 ++-- .../features/details/redux/DetailsAction.kt | 42 ------ .../details/redux/DetailsMiddleware.kt | 5 +- .../features/details/redux/DetailsReducer.kt | 61 ++++---- .../features/details/redux/DetailsState.kt | 40 ++--- .../redux/twins/CreateTwinWalletMiddleware.kt | 119 --------------- .../redux/twins/CreateTwinWalletReducer.kt | 68 --------- .../features/details/ui/DetailsFragment.kt | 13 +- .../twins}/OnboardingTwinsFragment.kt | 21 ++- .../features/tokens/ui/AddTokensFragment.kt | 1 - .../twins/redux/CreateTwinWalletAction.kt | 52 +++++++ .../twins/redux/CreateTwinWalletMiddleware.kt | 138 ++++++++++++++++++ .../twins/redux/CreateTwinWalletReducer.kt | 67 +++++++++ .../redux}/CreateTwinWalletState.kt | 2 +- .../ui}/CreateTwinWalletFragment.kt | 40 ++--- .../ui}/TwinWalletWarningFragment.kt | 15 +- .../redux/middlewares/WalletMiddleware.kt | 35 ++--- .../wallet/ui/WalletDetailsFragment.kt | 30 ++-- ...rds.xml => fragment_twin_cards_create.xml} | 0 ...ng.xml => fragment_twin_cards_warning.xml} | 6 +- ...ds.xml => fragment_twin_cards_welcome.xml} | 8 +- 23 files changed, 429 insertions(+), 402 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/features/details/redux/twins/CreateTwinWalletMiddleware.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/details/redux/twins/CreateTwinWalletReducer.kt rename app/src/main/java/com/tangem/tap/features/{wallet/ui => onboarding/products/twins}/OnboardingTwinsFragment.kt (74%) create mode 100644 app/src/main/java/com/tangem/tap/features/twins/redux/CreateTwinWalletAction.kt create mode 100644 app/src/main/java/com/tangem/tap/features/twins/redux/CreateTwinWalletMiddleware.kt create mode 100644 app/src/main/java/com/tangem/tap/features/twins/redux/CreateTwinWalletReducer.kt rename app/src/main/java/com/tangem/tap/features/{details/redux/twins => twins/redux}/CreateTwinWalletState.kt (91%) rename app/src/main/java/com/tangem/tap/features/{details/ui/twins => twins/ui}/CreateTwinWalletFragment.kt (79%) rename app/src/main/java/com/tangem/tap/features/{details/ui/twins => twins/ui}/TwinWalletWarningFragment.kt (81%) rename app/src/main/res/layout/{fragment_details_twin_cards.xml => fragment_twin_cards_create.xml} (100%) rename app/src/main/res/layout/{fragment_details_twin_cards_warning.xml => fragment_twin_cards_warning.xml} (97%) rename app/src/main/res/layout/{fragment_twin_cards.xml => fragment_twin_cards_welcome.xml} (95%) diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt index 02c794329c..135e0cbd9c 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt @@ -10,26 +10,26 @@ import com.tangem.tap.common.redux.navigation.FragmentShareTransition import com.tangem.tap.features.details.ui.DetailsConfirmFragment import com.tangem.tap.features.details.ui.DetailsFragment import com.tangem.tap.features.details.ui.DetailsSecurityFragment -import com.tangem.tap.features.details.ui.twins.CreateTwinWalletFragment -import com.tangem.tap.features.details.ui.twins.TwinWalletWarningFragment import com.tangem.tap.features.details.ui.walletconnect.QrScanFragment import com.tangem.tap.features.details.ui.walletconnect.WalletConnectSessionsFragment import com.tangem.tap.features.disclaimer.ui.DisclaimerFragment import com.tangem.tap.features.home.HomeFragment import com.tangem.tap.features.onboarding.products.note.OnboardingNoteFragment import com.tangem.tap.features.onboarding.products.otherCards.OnboardingOtherCardsFragment +import com.tangem.tap.features.onboarding.products.twins.OnboardingTwinsFragment import com.tangem.tap.features.onboarding.products.wallet.OnboardingWalletFragment import com.tangem.tap.features.send.ui.SendFragment import com.tangem.tap.features.tokens.ui.AddTokensFragment -import com.tangem.tap.features.wallet.ui.OnboardingTwinsFragment +import com.tangem.tap.features.twins.ui.CreateTwinWalletFragment +import com.tangem.tap.features.twins.ui.TwinWalletWarningFragment import com.tangem.tap.features.wallet.ui.WalletDetailsFragment import com.tangem.tap.features.wallet.ui.WalletFragment import com.tangem.wallet.R fun FragmentActivity.openFragment( - screen: AppScreen, - addToBackstack: Boolean, - fgShareTransition: FragmentShareTransition? = null + screen: AppScreen, + addToBackstack: Boolean, + fgShareTransition: FragmentShareTransition? = null ) { val transaction = this.supportFragmentManager.beginTransaction() val fragment = fragmentFactory(screen) @@ -60,8 +60,8 @@ fun FragmentActivity.getPreviousScreen(): AppScreen? { } fun FragmentActivity.addOnBackPressedDispatcher( - isEnabled: Boolean = true, - onBackPressed: VoidCallback + isEnabled: Boolean = true, + onBackPressed: VoidCallback ): OnBackPressedCallback = (object : OnBackPressedCallback(isEnabled) { override fun handleOnBackPressed() { onBackPressed() diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt index 40e0c80077..f883d78840 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt @@ -22,6 +22,7 @@ import com.tangem.tap.features.send.redux.middlewares.SendMiddleware import com.tangem.tap.features.send.redux.states.SendState import com.tangem.tap.features.tokens.redux.TokensMiddleware import com.tangem.tap.features.tokens.redux.TokensState +import com.tangem.tap.features.twins.redux.CreateTwinWalletMiddleware import com.tangem.tap.features.wallet.redux.WalletState import com.tangem.tap.features.wallet.redux.middlewares.WalletMiddleware import org.rekotlin.Middleware @@ -45,18 +46,19 @@ data class AppState( companion object { fun getMiddleware(): List> { return listOf( - logMiddleware, navigationMiddleware, notificationsMiddleware, - GlobalMiddleware.handler, - HomeMiddleware.handler, - OnboardingNoteMiddleware.handler, - OnboardingWalletMiddleware.handler, - OnboardingOtherCardsMiddleware.handler, - WalletMiddleware().walletMiddleware, - SendMiddleware().sendMiddleware, - DetailsMiddleware().detailsMiddleware, - DisclaimerMiddleware().disclaimerMiddleware, - TokensMiddleware().tokensMiddleware, - WalletConnectMiddleware().walletConnectMiddleware + logMiddleware, navigationMiddleware, notificationsMiddleware, + GlobalMiddleware.handler, + HomeMiddleware.handler, + OnboardingNoteMiddleware.handler, + OnboardingWalletMiddleware.handler, + OnboardingOtherCardsMiddleware.handler, + WalletMiddleware().walletMiddleware, + CreateTwinWalletMiddleware.handler, + SendMiddleware().sendMiddleware, + DetailsMiddleware().detailsMiddleware, + DisclaimerMiddleware().disclaimerMiddleware, + TokensMiddleware().tokensMiddleware, + WalletConnectMiddleware().walletConnectMiddleware ) } } 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 32403ae363..163359460d 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -59,8 +59,8 @@ class TapWalletManager { suspend fun loadFiatRate(fiatCurrency: FiatCurrencyName, wallet: Wallet) { Timber.d(wallet.getTokens().toString()) 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) } @@ -126,11 +126,13 @@ class TapWalletManager { store.dispatch(WalletAction.LoadCardInfo(data.card)) when { + data.card.isTangemTwin() && data.secondTwinPublicKey == null -> { + store.dispatch(WalletAction.EmptyWallet) + } data.getBlockchain() == Blockchain.Unknown && !data.card.isMultiwalletAllowed -> { store.dispatch(WalletAction.LoadData.Failure(TapError.UnknownBlockchain)) } - data.card.wallets.isEmpty() || - (data.card.isTangemTwin() && data.secondTwinPublicKey == null) -> { + data.card.wallets.isEmpty() -> { store.dispatch(WalletAction.EmptyWallet) } else -> { @@ -171,7 +173,7 @@ class TapWalletManager { } private fun loadMultiWalletData( - card: Card, primaryBlockchain: Blockchain?, primaryWalletManager: WalletManager? + card: Card, primaryBlockchain: Blockchain?, primaryWalletManager: WalletManager? ) { val primaryTokens = primaryWalletManager?.cardTokens ?: emptySet() val savedCurrencies = currenciesRepository.loadCardCurrencies(card.cardId) @@ -179,9 +181,9 @@ class TapWalletManager { if (savedCurrencies == null) { if (primaryBlockchain != null && primaryWalletManager != null) { store.dispatch(WalletAction.MultiWallet.SaveCurrencies( - CardCurrencies( - blockchains = setOf(primaryBlockchain), tokens = primaryTokens - ))) + CardCurrencies( + blockchains = setOf(primaryBlockchain), tokens = primaryTokens + ))) store.dispatch(WalletAction.MultiWallet.AddWalletManagers(primaryWalletManager)) store.dispatch(WalletAction.MultiWallet.AddBlockchains(listOf(primaryBlockchain))) store.dispatch(WalletAction.MultiWallet.AddTokens(primaryTokens.toList())) @@ -191,7 +193,7 @@ class TapWalletManager { CardCurrencies(blockchains = blockchains, tokens = emptySet()) )) val walletManagers = - walletManagerFactory.makeWalletManagersForApp(card, blockchains.toList()) + walletManagerFactory.makeWalletManagersForApp(card, blockchains.toList()) store.dispatch(WalletAction.MultiWallet.AddWalletManagers(walletManagers)) store.dispatch(WalletAction.MultiWallet.AddBlockchains(blockchains.toList())) } @@ -200,12 +202,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(card, blockchainsWithoutPrimary) - .plus(primaryWalletManager) + .plus(primaryWalletManager) } else { walletManagerFactory.makeWalletManagersForApp(card, blockchains) } diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt index 74b37f90f4..0e7a1f5e21 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt @@ -1,7 +1,5 @@ package com.tangem.tap.features.details.redux -import android.content.Context -import com.tangem.Message import com.tangem.blockchain.common.Wallet import com.tangem.common.card.Card import com.tangem.operations.pins.CheckUserCodesResponse @@ -9,8 +7,6 @@ import com.tangem.tap.common.redux.NotificationAction import com.tangem.tap.common.redux.global.FiatCurrencyName import com.tangem.tap.domain.tasks.product.ScanResponse import com.tangem.tap.domain.termsOfUse.CardTou -import com.tangem.tap.domain.twins.TwinCardNumber -import com.tangem.tap.features.details.redux.twins.CreateTwinWallet import com.tangem.tap.network.coinmarketcap.FiatCurrency import com.tangem.wallet.R import org.rekotlin.Action @@ -48,44 +44,6 @@ sealed class DetailsAction : Action { object Success : EraseWallet() } - sealed class CreateTwinWalletAction : DetailsAction() { - data class ShowWarning( - val twinCardNumber: TwinCardNumber?, - val createTwinWallet: CreateTwinWallet = CreateTwinWallet.RecreateWallet - ) : CreateTwinWalletAction() - object NotEmpty : CreateTwinWalletAction(), NotificationAction { - override val messageResource = R.string.details_notification_erase_wallet_not_possible - } - object ShowAlert : CreateTwinWalletAction() - object HideAlert : CreateTwinWalletAction() - object Proceed: CreateTwinWalletAction() - - object Cancel : CreateTwinWalletAction() { - object Confirm : CreateTwinWalletAction() - } - - data class LaunchFirstStep( - val message: Message, val context: Context - ) : CreateTwinWalletAction() { - object Success : CreateTwinWalletAction() - object Failure : CreateTwinWalletAction() - } - - data class LaunchSecondStep( - val initialMessage: Message, - val preparingMessage: Message, - val creatingWalletMessage: Message, - ) : CreateTwinWalletAction() { - object Success : CreateTwinWalletAction() - object Failure : CreateTwinWalletAction() - } - - data class LaunchThirdStep(val message: Message) : CreateTwinWalletAction() { - data class Success(val scanResponse: ScanResponse) : CreateTwinWalletAction() - object Failure : CreateTwinWalletAction() - } - } - sealed class AppCurrencyAction : DetailsAction() { data class SetCurrencies(val currencies: List) : AppCurrencyAction() object ChooseAppCurrency : AppCurrencyAction() diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index 15eca00858..b539946faa 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -9,7 +9,6 @@ import com.tangem.tap.common.redux.AppState 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.features.details.redux.twins.CreateTwinWalletMiddleware import com.tangem.tap.features.disclaimer.redux.DisclaimerAction import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.network.coinmarketcap.CoinMarketCapService @@ -26,7 +25,6 @@ class DetailsMiddleware { private val eraseWalletMiddleware = EraseWalletMiddleware() private val appCurrencyMiddleware = AppCurrencyMiddleware() private val manageSecurityMiddleware = ManageSecurityMiddleware() - private val twinWalletMiddleware = CreateTwinWalletMiddleware() val detailsMiddleware: Middleware = { dispatch, state -> { next -> { action -> @@ -35,7 +33,6 @@ class DetailsMiddleware { is DetailsAction.EraseWallet -> eraseWalletMiddleware.handle(action) is DetailsAction.AppCurrencyAction -> appCurrencyMiddleware.handle(action) is DetailsAction.ManageSecurity -> manageSecurityMiddleware.handle(action) - is DetailsAction.CreateTwinWalletAction -> twinWalletMiddleware.handle(action) is DetailsAction.ShowDisclaimer -> { store.dispatch(DisclaimerAction.ShowAcceptedDisclaimer) store.dispatch(NavigationAction.NavigateTo(AppScreen.Disclaimer)) @@ -84,7 +81,7 @@ class DetailsMiddleware { store.dispatch(NavigationAction.PopBackTo()) } is DetailsAction.EraseWallet.Confirm -> { - val card = store.state.detailsState.card ?: return + val card = store.state.detailsState.card ?: return scope.launch { val result = tangemSdkManager.eraseWallet(card) withContext(Dispatchers.Main) { diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt index 4e45d765d7..5989a084e2 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt @@ -9,8 +9,7 @@ import com.tangem.tap.domain.extensions.signedHashesCount import com.tangem.tap.domain.extensions.toSendableAmounts import com.tangem.tap.domain.twins.getTwinCardNumber import com.tangem.tap.domain.twins.isTangemTwin -import com.tangem.tap.features.details.redux.twins.CreateTwinWalletReducer -import com.tangem.tap.features.details.redux.twins.CreateTwinWalletState +import com.tangem.tap.features.twins.redux.CreateTwinWalletState import com.tangem.tap.features.wallet.models.hasPendingTransactions import org.rekotlin.Action import java.util.* @@ -38,9 +37,6 @@ private fun internalReduce(action: Action, state: AppState): DetailsState { is DetailsAction.ManageSecurity -> { handleSecurityAction(action, detailsState) } - is DetailsAction.CreateTwinWalletAction -> { - CreateTwinWalletReducer.handle(action, detailsState) - } else -> detailsState } } @@ -48,24 +44,24 @@ private fun internalReduce(action: Action, state: AppState): DetailsState { private fun handlePrepareScreen(action: DetailsAction.PrepareScreen, state: DetailsState): DetailsState { val twinsState = if (action.card.isTangemTwin()) { CreateTwinWalletState( - scanResponse = action.scanResponse, - twinCardNumber = action.card.getTwinCardNumber(), - createTwinWallet = null, - showAlert = false, - allowRecreatingWallet = action.isCreatingTwinWalletAllowed + scanResponse = action.scanResponse, + twinCardNumber = action.card.getTwinCardNumber(), + createTwinWallet = null, + showAlert = false, + allowRecreatingWallet = action.isCreatingTwinWalletAllowed ) } else { null } return DetailsState( - card = action.card, wallets = action.wallets, - cardInfo = action.card.toCardInfo(), - appCurrencyState = AppCurrencyState( - action.fiatCurrencyName - ), - createTwinWalletState = twinsState, - cardTermsOfUseUrl = action.cardTou.getUrl(action.card) + card = action.card, wallets = action.wallets, + cardInfo = action.card.toCardInfo(), + appCurrencyState = AppCurrencyState( + action.fiatCurrencyName + ), + createTwinWalletState = twinsState, + cardTermsOfUseUrl = action.cardTou.getUrl(action.card) ) } @@ -99,7 +95,7 @@ private fun handleEraseWallet(action: DetailsAction.EraseWallet, state: DetailsS } private fun handleAppCurrencyAction( - action: DetailsAction.AppCurrencyAction, state: DetailsState + action: DetailsAction.AppCurrencyAction, state: DetailsState ): DetailsState { return when (action) { is DetailsAction.AppCurrencyAction.SetCurrencies -> { @@ -113,9 +109,9 @@ private fun handleAppCurrencyAction( } is DetailsAction.AppCurrencyAction.SelectAppCurrency -> { state.copy( - appCurrencyState = state.appCurrencyState.copy( - fiatCurrencyName = action.fiatCurrencyName, showAppCurrencyDialog = false - ) + appCurrencyState = state.appCurrencyState.copy( + fiatCurrencyName = action.fiatCurrencyName, showAppCurrencyDialog = false + ) ) } else -> state @@ -123,7 +119,7 @@ private fun handleAppCurrencyAction( } private fun handleSecurityAction( - action: DetailsAction.ManageSecurity, state: DetailsState + action: DetailsAction.ManageSecurity, state: DetailsState ): DetailsState { return when (action) { is DetailsAction.ManageSecurity.SetCurrentOption -> { @@ -143,8 +139,8 @@ private fun handleSecurityAction( is DetailsAction.ManageSecurity.OpenSecurity -> { if (state.card?.isStart2Coin == true) { return state.copy(securityScreenState = state.securityScreenState?.copy( - allowedOptions = EnumSet.of(SecurityOption.LongTap), - selectedOption = state.securityScreenState.currentOption + allowedOptions = EnumSet.of(SecurityOption.LongTap), + selectedOption = state.securityScreenState.currentOption )) } @@ -152,13 +148,13 @@ private fun handleSecurityAction( state.card, state.securityScreenState?.currentOption ) state.copy(securityScreenState = state.securityScreenState?.copy( - allowedOptions = allowedSecurityOptions, - selectedOption = state.securityScreenState.currentOption + allowedOptions = allowedSecurityOptions, + selectedOption = state.securityScreenState.currentOption )) } is DetailsAction.ManageSecurity.SelectOption -> { state.copy(securityScreenState = state.securityScreenState?.copy( - selectedOption = action.option + selectedOption = action.option )) } is DetailsAction.ManageSecurity.ConfirmSelection -> { @@ -172,10 +168,10 @@ private fun handleSecurityAction( is DetailsAction.ManageSecurity.SaveChanges.Success -> { // Setting options to show only LongTap from now on state.copy( - securityScreenState = state.securityScreenState?.copy( - currentOption = state.securityScreenState.selectedOption, - allowedOptions = EnumSet.of(SecurityOption.LongTap) - )) + securityScreenState = state.securityScreenState?.copy( + currentOption = state.securityScreenState.selectedOption, + allowedOptions = EnumSet.of(SecurityOption.LongTap) + )) } else -> state @@ -205,4 +201,5 @@ private fun Card.toCardInfo(): CardInfo? { val cardId = this.cardId.chunked(4).joinToString(separator = " ") val issuer = this.issuer.name val signedHashes = this.signedHashesCount() - return CardInfo(cardId, issuer, signedHashes)} \ No newline at end of file + return CardInfo(cardId, issuer, signedHashes) +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt index bf16dd3674..bd55c9aa95 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt @@ -6,41 +6,41 @@ import com.tangem.common.card.Card import com.tangem.tap.common.entities.Button import com.tangem.tap.common.entities.TapCurrency.Companion.DEFAULT_FIAT_CURRENCY import com.tangem.tap.common.redux.global.FiatCurrencyName -import com.tangem.tap.features.details.redux.twins.CreateTwinWalletState +import com.tangem.tap.features.twins.redux.CreateTwinWalletState import com.tangem.tap.network.coinmarketcap.FiatCurrency import org.rekotlin.StateType import java.util.* data class DetailsState( - val card: Card? = null, - val wallets: List = emptyList(), - val cardInfo: CardInfo? = null, - val appCurrencyState: AppCurrencyState = AppCurrencyState(), - val eraseWalletState: EraseWalletState? = null, - val confirmScreenState: ConfirmScreenState? = null, - val securityScreenState: SecurityScreenState? = null, - val createTwinWalletState: CreateTwinWalletState? = null, - val cardTermsOfUseUrl: Uri? = null, + val card: Card? = null, + val wallets: List = emptyList(), + val cardInfo: CardInfo? = null, + val appCurrencyState: AppCurrencyState = AppCurrencyState(), + val eraseWalletState: EraseWalletState? = null, + val confirmScreenState: ConfirmScreenState? = null, + val securityScreenState: SecurityScreenState? = null, + val createTwinWalletState: CreateTwinWalletState? = null, + val cardTermsOfUseUrl: Uri? = null, ) : StateType data class CardInfo( - val cardId: String, - val issuer: String, - val signedHashes: Int, + val cardId: String, + val issuer: String, + val signedHashes: Int, ) enum class EraseWalletState { Allowed, NotAllowedByCard, NotEmpty } enum class ConfirmScreenState { EraseWallet, LongTap, AccessCode, PassCode } data class SecurityScreenState( - val currentOption: SecurityOption = SecurityOption.LongTap, - val selectedOption: SecurityOption = currentOption, - val allowedOptions: EnumSet = EnumSet.allOf(SecurityOption::class.java), - val buttonProceed: Button = Button(true), + val currentOption: SecurityOption = SecurityOption.LongTap, + val selectedOption: SecurityOption = currentOption, + val allowedOptions: EnumSet = EnumSet.allOf(SecurityOption::class.java), + val buttonProceed: Button = Button(true), ) enum class SecurityOption { LongTap, PassCode, AccessCode } data class AppCurrencyState( - val fiatCurrencyName: FiatCurrencyName = DEFAULT_FIAT_CURRENCY, - val showAppCurrencyDialog: Boolean = false, - val fiatCurrencies: List? = null, + val fiatCurrencyName: FiatCurrencyName = DEFAULT_FIAT_CURRENCY, + val showAppCurrencyDialog: Boolean = false, + val fiatCurrencies: List? = null, ) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/twins/CreateTwinWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/twins/CreateTwinWalletMiddleware.kt deleted file mode 100644 index 1a6c05c2b1..0000000000 --- a/app/src/main/java/com/tangem/tap/features/details/redux/twins/CreateTwinWalletMiddleware.kt +++ /dev/null @@ -1,119 +0,0 @@ -package com.tangem.tap.features.details.redux.twins - -import com.tangem.blockchain.extensions.Result -import com.tangem.blockchain.extensions.SimpleResult -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.domain.twins.TwinCardsManager -import com.tangem.tap.features.details.redux.DetailsAction -import com.tangem.tap.scope -import com.tangem.tap.store -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext - -class CreateTwinWalletMiddleware { - var twinsManager: TwinCardsManager? = null - fun handle(action: DetailsAction.CreateTwinWalletAction) { - when (action) { - is DetailsAction.CreateTwinWalletAction.ShowWarning -> { - val wallet = store.state.detailsState.wallets.firstOrNull() - if (wallet == null) { - store.dispatch(NavigationAction.NavigateTo(AppScreen.CreateTwinWalletWarning)) - return - } - val notEmpty = wallet.recentTransactions.isNotEmpty() || wallet.amounts.toSendableAmounts().isNotEmpty() - if (notEmpty) { - store.dispatch(DetailsAction.CreateTwinWalletAction.NotEmpty) - } else { - store.dispatch(NavigationAction.NavigateTo(AppScreen.CreateTwinWalletWarning)) - } - } - is DetailsAction.CreateTwinWalletAction.Proceed -> - store.dispatch(NavigationAction.NavigateTo(AppScreen.CreateTwinWallet)) - is DetailsAction.CreateTwinWalletAction.Cancel -> { - - val step = store.state.detailsState.createTwinWalletState?.step - if (step != null && step != CreateTwinWalletStep.FirstStep - ) { - store.dispatch(DetailsAction.CreateTwinWalletAction.ShowAlert) - } else { - twinsManager = null - store.dispatch(NavigationAction.PopBackTo()) - } - } - is DetailsAction.CreateTwinWalletAction.Cancel.Confirm -> { - twinsManager = null - store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) - } - is DetailsAction.CreateTwinWalletAction.LaunchFirstStep -> { - store.state.globalState.scanResponse?.let { - twinsManager = TwinCardsManager(it, action.context) - } - scope.launch { - val result = twinsManager?.createFirstWallet(action.message) - withContext(Dispatchers.Main) { - when (result) { - SimpleResult.Success -> - store.dispatch(DetailsAction.CreateTwinWalletAction.LaunchFirstStep.Success) - is SimpleResult.Failure -> - store.dispatch(DetailsAction.CreateTwinWalletAction.LaunchFirstStep.Failure) - } - } - } - } - DetailsAction.CreateTwinWalletAction.LaunchFirstStep.Success -> { - - } - DetailsAction.CreateTwinWalletAction.LaunchFirstStep.Failure -> { - - } - is DetailsAction.CreateTwinWalletAction.LaunchSecondStep -> - scope.launch { - val result = twinsManager?.createSecondWallet(action.initialMessage, - action.preparingMessage, action.creatingWalletMessage) - withContext(Dispatchers.Main) { - when (result) { - SimpleResult.Success -> - store.dispatch(DetailsAction.CreateTwinWalletAction.LaunchSecondStep.Success) - is SimpleResult.Failure -> - store.dispatch(DetailsAction.CreateTwinWalletAction.LaunchSecondStep.Failure) - } - } - } - DetailsAction.CreateTwinWalletAction.LaunchSecondStep.Success -> { - - } - DetailsAction.CreateTwinWalletAction.LaunchSecondStep.Failure -> { - - } - is DetailsAction.CreateTwinWalletAction.LaunchThirdStep -> { - scope.launch { - val result = twinsManager?.complete(action.message) - withContext(Dispatchers.Main) { - when (result) { - is Result.Success -> - store.dispatch( - DetailsAction.CreateTwinWalletAction - .LaunchThirdStep.Success(result.data) - ) - is Result.Failure -> - store.dispatch(DetailsAction.CreateTwinWalletAction.LaunchThirdStep.Failure) - } - } - } - } - is DetailsAction.CreateTwinWalletAction.LaunchThirdStep.Success -> { - scope.launch { - store.state.globalState.tapWalletManager.onCardScanned(action.scanResponse) - } - store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) - store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet)) - } - DetailsAction.CreateTwinWalletAction.LaunchThirdStep.Failure -> { - - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/twins/CreateTwinWalletReducer.kt b/app/src/main/java/com/tangem/tap/features/details/redux/twins/CreateTwinWalletReducer.kt deleted file mode 100644 index 7de266d076..0000000000 --- a/app/src/main/java/com/tangem/tap/features/details/redux/twins/CreateTwinWalletReducer.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.tangem.tap.features.details.redux.twins - -import com.tangem.tap.features.details.redux.DetailsAction -import com.tangem.tap.features.details.redux.DetailsState - -class CreateTwinWalletReducer { - companion object { - fun handle( - action: DetailsAction.CreateTwinWalletAction, state: DetailsState - ): DetailsState { - return when (action) { - is DetailsAction.CreateTwinWalletAction.ShowWarning -> { - state.copy(createTwinWalletState = CreateTwinWalletState( - scanResponse = null, - twinCardNumber = action.twinCardNumber - ?: state.createTwinWalletState?.twinCardNumber, - createTwinWallet = action.createTwinWallet, - showAlert = false, - allowRecreatingWallet = state.createTwinWalletState?.allowRecreatingWallet - )) - } - DetailsAction.CreateTwinWalletAction.NotEmpty -> state - DetailsAction.CreateTwinWalletAction.ShowAlert -> { - state.copy(createTwinWalletState = state.createTwinWalletState?.copy( - showAlert = true - )) - } - DetailsAction.CreateTwinWalletAction.HideAlert -> { - state.copy(createTwinWalletState = state.createTwinWalletState?.copy( - showAlert = false - )) - } - is DetailsAction.CreateTwinWalletAction.Proceed -> { - state - } - DetailsAction.CreateTwinWalletAction.Cancel -> state - DetailsAction.CreateTwinWalletAction.Cancel.Confirm -> state - is DetailsAction.CreateTwinWalletAction.LaunchFirstStep -> state - - DetailsAction.CreateTwinWalletAction.LaunchFirstStep.Success -> { - state.copy(createTwinWalletState = state.createTwinWalletState?.copy( - step = CreateTwinWalletStep.SecondStep - )) - } - DetailsAction.CreateTwinWalletAction.LaunchFirstStep.Failure -> state - - is DetailsAction.CreateTwinWalletAction.LaunchSecondStep -> state - DetailsAction.CreateTwinWalletAction.LaunchSecondStep.Success -> - state.copy(createTwinWalletState = state.createTwinWalletState?.copy( - step = CreateTwinWalletStep.ThirdStep - )) - DetailsAction.CreateTwinWalletAction.LaunchSecondStep.Failure -> { - state - } - is DetailsAction.CreateTwinWalletAction.LaunchThirdStep -> { - state - } - is DetailsAction.CreateTwinWalletAction.LaunchThirdStep.Success -> { - state - } - DetailsAction.CreateTwinWalletAction.LaunchThirdStep.Failure -> { - state - } - } - } - - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt index 640cc47cf0..7d845228f7 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt @@ -16,8 +16,9 @@ import com.tangem.tap.domain.twins.isTangemTwin import com.tangem.tap.features.details.redux.DetailsAction import com.tangem.tap.features.details.redux.DetailsState import com.tangem.tap.features.details.redux.SecurityOption -import com.tangem.tap.features.details.redux.twins.CreateTwinWallet import com.tangem.tap.features.feedback.FeedbackEmail +import com.tangem.tap.features.twins.redux.CreateTwinWallet +import com.tangem.tap.features.twins.redux.CreateTwinWalletAction import com.tangem.tap.store import com.tangem.wallet.R import kotlinx.android.synthetic.main.fragment_details.* @@ -95,9 +96,7 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber = { dispatch, state -> + { next -> + { action -> + handle(action, dispatch) + next(action) + } + } +} + +private var twinsManager: TwinCardsManager? = null + +private fun handle(action: Action, dispatch: DispatchFunction) { + val action = action as? CreateTwinWalletAction ?: return + + when (action) { + is CreateTwinWalletAction.ShowWarning -> { + val wallet = store.state.detailsState.wallets.firstOrNull() + if (wallet == null) { + store.dispatch(NavigationAction.NavigateTo(AppScreen.CreateTwinWalletWarning)) + return + } + val notEmpty = wallet.recentTransactions.isNotEmpty() || wallet.amounts.toSendableAmounts().isNotEmpty() + if (notEmpty) { + store.dispatch(CreateTwinWalletAction.NotEmpty) + } else { + store.dispatch(NavigationAction.NavigateTo(AppScreen.CreateTwinWalletWarning)) + } + } + is CreateTwinWalletAction.Proceed -> + store.dispatch(NavigationAction.NavigateTo(AppScreen.CreateTwinWallet)) + is CreateTwinWalletAction.Cancel -> { + + val step = store.state.detailsState.createTwinWalletState?.step + if (step != null && step != CreateTwinWalletStep.FirstStep + ) { + store.dispatch(CreateTwinWalletAction.ShowAlert) + } else { + twinsManager = null + store.dispatch(NavigationAction.PopBackTo()) + } + } + is CreateTwinWalletAction.Cancel.Confirm -> { + twinsManager = null + store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) + } + is CreateTwinWalletAction.LaunchFirstStep -> { + store.state.globalState.scanResponse?.let { + twinsManager = TwinCardsManager(it, action.context) + } + scope.launch { + val result = twinsManager?.createFirstWallet(action.message) + withContext(Dispatchers.Main) { + when (result) { + SimpleResult.Success -> + store.dispatch(CreateTwinWalletAction.LaunchFirstStep.Success) + is SimpleResult.Failure -> + store.dispatch(CreateTwinWalletAction.LaunchFirstStep.Failure) + } + } + } + } + CreateTwinWalletAction.LaunchFirstStep.Success -> { + + } + CreateTwinWalletAction.LaunchFirstStep.Failure -> { + + } + is CreateTwinWalletAction.LaunchSecondStep -> + scope.launch { + val result = twinsManager?.createSecondWallet(action.initialMessage, + action.preparingMessage, action.creatingWalletMessage) + withContext(Dispatchers.Main) { + when (result) { + SimpleResult.Success -> + store.dispatch(CreateTwinWalletAction.LaunchSecondStep.Success) + is SimpleResult.Failure -> + store.dispatch(CreateTwinWalletAction.LaunchSecondStep.Failure) + } + } + } + CreateTwinWalletAction.LaunchSecondStep.Success -> { + + } + CreateTwinWalletAction.LaunchSecondStep.Failure -> { + + } + is CreateTwinWalletAction.LaunchThirdStep -> { + scope.launch { + val result = twinsManager?.complete(action.message) + withContext(Dispatchers.Main) { + when (result) { + is Result.Success -> + store.dispatch( + CreateTwinWalletAction + .LaunchThirdStep.Success(result.data) + ) + is Result.Failure -> + store.dispatch(CreateTwinWalletAction.LaunchThirdStep.Failure) + } + } + } + } + is CreateTwinWalletAction.LaunchThirdStep.Success -> { + scope.launch { + store.state.globalState.tapWalletManager.onCardScanned(action.scanResponse) + } + store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) + store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet)) + } + CreateTwinWalletAction.LaunchThirdStep.Failure -> { + + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/twins/redux/CreateTwinWalletReducer.kt b/app/src/main/java/com/tangem/tap/features/twins/redux/CreateTwinWalletReducer.kt new file mode 100644 index 0000000000..6eeb6e18f5 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/twins/redux/CreateTwinWalletReducer.kt @@ -0,0 +1,67 @@ +package com.tangem.tap.features.twins.redux + +import com.tangem.tap.features.details.redux.DetailsState + +class CreateTwinWalletReducer { + companion object { + fun handle( + action: CreateTwinWalletAction, state: DetailsState + ): DetailsState { + return when (action) { + is CreateTwinWalletAction.ShowWarning -> { + state.copy(createTwinWalletState = CreateTwinWalletState( + scanResponse = null, + twinCardNumber = action.twinCardNumber + ?: state.createTwinWalletState?.twinCardNumber, + createTwinWallet = action.createTwinWallet, + showAlert = false, + allowRecreatingWallet = state.createTwinWalletState?.allowRecreatingWallet + )) + } + CreateTwinWalletAction.NotEmpty -> state + CreateTwinWalletAction.ShowAlert -> { + state.copy(createTwinWalletState = state.createTwinWalletState?.copy( + showAlert = true + )) + } + CreateTwinWalletAction.HideAlert -> { + state.copy(createTwinWalletState = state.createTwinWalletState?.copy( + showAlert = false + )) + } + is CreateTwinWalletAction.Proceed -> { + state + } + CreateTwinWalletAction.Cancel -> state + CreateTwinWalletAction.Cancel.Confirm -> state + is CreateTwinWalletAction.LaunchFirstStep -> state + + CreateTwinWalletAction.LaunchFirstStep.Success -> { + state.copy(createTwinWalletState = state.createTwinWalletState?.copy( + step = CreateTwinWalletStep.SecondStep + )) + } + CreateTwinWalletAction.LaunchFirstStep.Failure -> state + + is CreateTwinWalletAction.LaunchSecondStep -> state + CreateTwinWalletAction.LaunchSecondStep.Success -> + state.copy(createTwinWalletState = state.createTwinWalletState?.copy( + step = CreateTwinWalletStep.ThirdStep + )) + CreateTwinWalletAction.LaunchSecondStep.Failure -> { + state + } + is CreateTwinWalletAction.LaunchThirdStep -> { + state + } + is CreateTwinWalletAction.LaunchThirdStep.Success -> { + state + } + CreateTwinWalletAction.LaunchThirdStep.Failure -> { + state + } + } + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/twins/CreateTwinWalletState.kt b/app/src/main/java/com/tangem/tap/features/twins/redux/CreateTwinWalletState.kt similarity index 91% rename from app/src/main/java/com/tangem/tap/features/details/redux/twins/CreateTwinWalletState.kt rename to app/src/main/java/com/tangem/tap/features/twins/redux/CreateTwinWalletState.kt index 22c96dd0bf..0a7c6e04ee 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/twins/CreateTwinWalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/twins/redux/CreateTwinWalletState.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.details.redux.twins +package com.tangem.tap.features.twins.redux import com.tangem.tap.domain.tasks.product.ScanResponse import com.tangem.tap.domain.twins.TwinCardNumber diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/twins/CreateTwinWalletFragment.kt b/app/src/main/java/com/tangem/tap/features/twins/ui/CreateTwinWalletFragment.kt similarity index 79% rename from app/src/main/java/com/tangem/tap/features/details/ui/twins/CreateTwinWalletFragment.kt rename to app/src/main/java/com/tangem/tap/features/twins/ui/CreateTwinWalletFragment.kt index f8a09c7131..8c4b950a0d 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/twins/CreateTwinWalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/twins/ui/CreateTwinWalletFragment.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.details.ui.twins +package com.tangem.tap.features.twins.ui import android.app.Dialog import android.os.Bundle @@ -11,17 +11,17 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.squareup.picasso.Picasso import com.tangem.Message import com.tangem.tap.domain.twins.TwinCardNumber -import com.tangem.tap.features.details.redux.DetailsAction import com.tangem.tap.features.details.redux.DetailsState -import com.tangem.tap.features.details.redux.twins.CreateTwinWallet -import com.tangem.tap.features.details.redux.twins.CreateTwinWalletStep +import com.tangem.tap.features.twins.redux.CreateTwinWallet +import com.tangem.tap.features.twins.redux.CreateTwinWalletAction +import com.tangem.tap.features.twins.redux.CreateTwinWalletStep import com.tangem.tap.features.wallet.redux.Artwork import com.tangem.tap.store import com.tangem.wallet.R -import kotlinx.android.synthetic.main.fragment_details_twin_cards.* +import kotlinx.android.synthetic.main.fragment_twin_cards_create.* import org.rekotlin.StoreSubscriber -class CreateTwinWalletFragment : Fragment(R.layout.fragment_details_twin_cards), +class CreateTwinWalletFragment : Fragment(R.layout.fragment_twin_cards_create), StoreSubscriber { private var dialog: Dialog? = null @@ -30,7 +30,7 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_details_twin_cards), super.onCreate(savedInstanceState) activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { - store.dispatch(DetailsAction.CreateTwinWalletAction.Cancel) + store.dispatch(CreateTwinWalletAction.Cancel) } }) val inflater = TransitionInflater.from(requireContext()) @@ -56,7 +56,7 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_details_twin_cards), super.onViewCreated(view, savedInstanceState) toolbar.setNavigationOnClickListener { - store.dispatch(DetailsAction.CreateTwinWalletAction.Cancel) + store.dispatch(CreateTwinWalletAction.Cancel) } Picasso.get() @@ -96,7 +96,7 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_details_twin_cards), v_step_2.setBackgroundColor(defaultColor) v_step_3.setBackgroundColor(defaultColor) btn_tap.setOnClickListener { - store.dispatch(DetailsAction.CreateTwinWalletAction.LaunchFirstStep( + store.dispatch(CreateTwinWalletAction.LaunchFirstStep( Message(getString( R.string.details_twins_recreate_title_format, twinCardNumberString @@ -105,7 +105,7 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_details_twin_cards), )) } btn_tap.text = getString(R.string.details_twins_recreate_button_format, - twinCardNumber.number.toString()) + twinCardNumber.number.toString()) twinCardNumberString } CreateTwinWalletStep.SecondStep -> { @@ -117,10 +117,10 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_details_twin_cards), v_step_2.setBackgroundColor(selectedColor) v_step_3.setBackgroundColor(defaultColor) btn_tap.setOnClickListener { - store.dispatch(DetailsAction.CreateTwinWalletAction.LaunchSecondStep( - Message(getString(R.string.details_twins_recreate_title_format, twinCardNumberString)), - Message(getString(R.string.details_twins_recreate_title_preparing)), - Message(getString(R.string.details_twins_recreate_title_creating_wallet)), + store.dispatch(CreateTwinWalletAction.LaunchSecondStep( + Message(getString(R.string.details_twins_recreate_title_format, twinCardNumberString)), + Message(getString(R.string.details_twins_recreate_title_preparing)), + Message(getString(R.string.details_twins_recreate_title_creating_wallet)), )) } btn_tap.text = getString(R.string.details_twins_recreate_button_format, "2") @@ -135,10 +135,10 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_details_twin_cards), v_step_2.setBackgroundColor(selectedColor) v_step_3.setBackgroundColor(selectedColor) btn_tap.setOnClickListener { - store.dispatch(DetailsAction.CreateTwinWalletAction.LaunchThirdStep( - Message(getString( - R.string.details_twins_recreate_title_format, twinCardNumberString) - ) + store.dispatch(CreateTwinWalletAction.LaunchThirdStep( + Message(getString( + R.string.details_twins_recreate_title_format, twinCardNumberString) + ) )) } btn_tap.text = getString(R.string.details_twins_recreate_button_format, twinCardNumberString) @@ -154,13 +154,13 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_details_twin_cards), dialog = MaterialAlertDialogBuilder(requireContext()) .setMessage(R.string.details_twins_recreate_alert) .setPositiveButton(R.string.common_ok) { _, _ -> - store.dispatch(DetailsAction.CreateTwinWalletAction.Cancel.Confirm) + store.dispatch(CreateTwinWalletAction.Cancel.Confirm) } .setNegativeButton(R.string.common_cancel) { _, _ -> dialog?.cancel() } .setOnCancelListener { - store.dispatch(DetailsAction.CreateTwinWalletAction.HideAlert) + store.dispatch(CreateTwinWalletAction.HideAlert) } .create() dialog?.show() diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/twins/TwinWalletWarningFragment.kt b/app/src/main/java/com/tangem/tap/features/twins/ui/TwinWalletWarningFragment.kt similarity index 81% rename from app/src/main/java/com/tangem/tap/features/details/ui/twins/TwinWalletWarningFragment.kt rename to app/src/main/java/com/tangem/tap/features/twins/ui/TwinWalletWarningFragment.kt index 678dddf2bb..a1103c5bc7 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/twins/TwinWalletWarningFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/twins/ui/TwinWalletWarningFragment.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.details.ui.twins +package com.tangem.tap.features.twins.ui import android.os.Bundle import android.view.View @@ -7,15 +7,15 @@ import androidx.fragment.app.Fragment import androidx.transition.TransitionInflater import com.squareup.picasso.Picasso import com.tangem.tap.common.redux.navigation.NavigationAction -import com.tangem.tap.features.details.redux.DetailsAction -import com.tangem.tap.features.details.redux.twins.CreateTwinWallet +import com.tangem.tap.features.twins.redux.CreateTwinWallet +import com.tangem.tap.features.twins.redux.CreateTwinWalletAction import com.tangem.tap.features.wallet.redux.Artwork import com.tangem.tap.store import com.tangem.wallet.R -import kotlinx.android.synthetic.main.fragment_details_twin_cards_warning.* +import kotlinx.android.synthetic.main.fragment_twin_cards_warning.* import kotlinx.android.synthetic.main.layout_twin_cards_orange.* -class TwinWalletWarningFragment : Fragment(R.layout.fragment_details_twin_cards_warning) { +class TwinWalletWarningFragment : Fragment(R.layout.fragment_twin_cards_warning) { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -39,10 +39,7 @@ class TwinWalletWarningFragment : Fragment(R.layout.fragment_details_twin_cards_ } btn_cancel.setOnClickListener { store.dispatch(NavigationAction.PopBackTo()) } - btn_start.setOnClickListener { - store.dispatch( - DetailsAction.CreateTwinWalletAction.Proceed) - } + btn_start.setOnClickListener { store.dispatch(CreateTwinWalletAction.Proceed) } Picasso.get() .load(Artwork.TWIN_CARD_1) .placeholder(R.drawable.card_placeholder) 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 3b3a4f31c1..45ebaee21f 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 @@ -11,19 +11,17 @@ import com.tangem.common.services.Result import com.tangem.operations.attestation.OnlineCardVerifier import com.tangem.tap.* import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler -import com.tangem.tap.common.extensions.copyToClipboard -import com.tangem.tap.common.extensions.dispatchOnMain -import com.tangem.tap.common.extensions.shareText +import com.tangem.tap.common.extensions.* import com.tangem.tap.common.redux.AppState 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.domain.twins.TwinsHelper -import com.tangem.tap.features.details.redux.DetailsAction -import com.tangem.tap.features.details.redux.twins.CreateTwinWallet import com.tangem.tap.features.home.redux.HomeAction import com.tangem.tap.features.send.redux.PrepareSendScreen +import com.tangem.tap.features.twins.redux.CreateTwinWallet +import com.tangem.tap.features.twins.redux.CreateTwinWalletAction import com.tangem.tap.features.wallet.redux.* import com.tangem.tap.network.NetworkStateChanged import kotlinx.coroutines.launch @@ -87,7 +85,7 @@ class WalletMiddleware { globalState?.tapWalletManager?.loadFiatRate( fiatCurrency = globalState.appCurrency, currencies = walletState?.wallets?.mapNotNull { it.currency } - ?: emptyList() + ?: emptyList() ) } } @@ -95,16 +93,15 @@ class WalletMiddleware { } is WalletAction.CreateWallet -> { if (walletState?.twinCardsState != null) { - store.dispatch(DetailsAction.CreateTwinWalletAction.ShowWarning( - globalState?.scanResponse?.card?.cardId?.let { - TwinsHelper.getTwinCardNumber(it) - }, - CreateTwinWallet.CreateWallet - )) + val cardId = globalState?.scanResponse?.card?.cardId + val twinCardNumber = cardId?.let { TwinsHelper.getTwinCardNumber(it) } + store.dispatch( + CreateTwinWalletAction.ShowWarning(twinCardNumber, CreateTwinWallet.CreateWallet) + ) } else { scope.launch { val result = tangemSdkManager.createWallet( - globalState?.scanResponse?.card?.cardId + globalState?.scanResponse?.card?.cardId ) when (result) { is CompletionResult.Success -> { @@ -236,12 +233,12 @@ class WalletMiddleware { when (currency) { is Currency.Blockchain -> { val amountToSend = amounts?.find { it.currencySymbol == currency.blockchain.currency } - ?: return WalletAction.Send.ChooseCurrency(amounts) + ?: return WalletAction.Send.ChooseCurrency(amounts) PrepareSendScreen(amountToSend, selectedWalletData.fiatRate, walletManager) } is Currency.Token -> { val amountToSend = amounts?.find { it.currencySymbol == currency.token.symbol } - ?: return WalletAction.Send.ChooseCurrency(amounts) + ?: return WalletAction.Send.ChooseCurrency(amounts) prepareSendActionForToken(amountToSend, state, selectedWalletData, wallet, walletManager) } } @@ -257,8 +254,8 @@ class WalletMiddleware { } private fun prepareSendActionForToken( - amount: Amount, state: WalletState?, selectedWalletData: WalletData?, wallet: Wallet?, - walletManager: WalletManager? + amount: Amount, state: WalletState?, selectedWalletData: WalletData?, wallet: Wallet?, + walletManager: WalletManager? ): PrepareSendScreen { val coinRate = state?.getWalletData(wallet?.blockchain)?.fiatRate val tokenRate = if (state?.isMultiwalletAllowed == true) { @@ -267,7 +264,7 @@ class WalletMiddleware { selectedWalletData?.currencyData?.token?.fiatRate } return PrepareSendScreen( - wallet?.amounts?.get(AmountType.Coin), coinRate, walletManager, - amount, tokenRate) + wallet?.amounts?.get(AmountType.Coin), coinRate, walletManager, + amount, tokenRate) } } 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 1592ae4eb2..f2072f7cf3 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 @@ -20,9 +20,7 @@ import com.tangem.tap.features.wallet.ui.adapters.PendingTransactionsAdapter import com.tangem.tap.features.wallet.ui.dialogs.AmountToSendDialog import com.tangem.tap.store import com.tangem.wallet.R -import kotlinx.android.synthetic.main.fragment_details_twin_cards.* import kotlinx.android.synthetic.main.fragment_wallet_details.* -import kotlinx.android.synthetic.main.fragment_wallet_details.toolbar import kotlinx.android.synthetic.main.item_currency_wallet.view.* import kotlinx.android.synthetic.main.item_popular_token.view.* import kotlinx.android.synthetic.main.layout_balance_error.* @@ -98,12 +96,12 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS tv_currency_title.text = selectedWallet.currencyData.currency val currency = selectedWallet.currency - if (currency is Currency.Token) { - tv_currency_subtitle.text = currency.blockchain.tokenDisplayName() - tv_currency_subtitle.show() + if (currency is Currency.Token) { + tv_currency_subtitle.text = currency.blockchain.tokenDisplayName() + tv_currency_subtitle.show() } else { - tv_currency_subtitle.hide() - } + tv_currency_subtitle.hide() + } showPendingTransactionsIfPresent(selectedWallet.pendingTransactions) @@ -129,9 +127,9 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS srl_wallet_details.setOnRefreshListener { if (selectedWallet.currencyData.status != BalanceStatus.Loading) { store.dispatch(WalletAction.LoadWallet( - allowToBuy = selectedWallet.tradeCryptoState.buyingAllowed, - allowToSell = selectedWallet.tradeCryptoState.sellingAllowed, - blockchain = selectedWallet.currency?.blockchain + allowToBuy = selectedWallet.tradeCryptoState.buyingAllowed, + allowToSell = selectedWallet.tradeCryptoState.sellingAllowed, + blockchain = selectedWallet.currency?.blockchain )) } } @@ -180,8 +178,8 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS tv_address.text = state.walletAddresses.selectedAddress.address tv_explore?.setOnClickListener { store.dispatch(WalletAction.ExploreAddress( - state.walletAddresses.selectedAddress.exploreUrl, - requireContext())) + state.walletAddresses.selectedAddress.exploreUrl, + requireContext())) } iv_qr_code.setImageBitmap(state.walletAddresses.selectedAddress.shareUrl.toQrCode()) } @@ -192,8 +190,8 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS if (state.error == ErrorType.NoInternetConnection) { srl_wallet_details?.isRefreshing = false (activity as? SnackbarHandler)?.showSnackbar( - text = R.string.wallet_notification_no_internet, - buttonTitle = R.string.common_retry + text = R.string.wallet_notification_no_internet, + buttonTitle = R.string.common_retry ) { store.dispatch(WalletAction.LoadData) } } } else { @@ -249,8 +247,8 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS tv_error_title.text = getText(R.string.wallet_error_no_account) tv_error_descriptions.text = getString( - R.string.wallet_error_no_account_subtitle_format, - data.amountToCreateAccount, data.currencySymbol + R.string.wallet_error_no_account_subtitle_format, + data.amountToCreateAccount, data.currencySymbol ) } } diff --git a/app/src/main/res/layout/fragment_details_twin_cards.xml b/app/src/main/res/layout/fragment_twin_cards_create.xml similarity index 100% rename from app/src/main/res/layout/fragment_details_twin_cards.xml rename to app/src/main/res/layout/fragment_twin_cards_create.xml diff --git a/app/src/main/res/layout/fragment_details_twin_cards_warning.xml b/app/src/main/res/layout/fragment_twin_cards_warning.xml similarity index 97% rename from app/src/main/res/layout/fragment_details_twin_cards_warning.xml rename to app/src/main/res/layout/fragment_twin_cards_warning.xml index 1343fbe116..6ca8d8f68c 100644 --- a/app/src/main/res/layout/fragment_details_twin_cards_warning.xml +++ b/app/src/main/res/layout/fragment_twin_cards_warning.xml @@ -16,10 +16,10 @@ + android:background="@color/warning" + app:layout_constraintBottom_toTopOf="@id/l_twin_cards" + app:layout_constraintTop_toTopOf="parent" /> + android:background="@color/darkGray6" + app:layout_constraintBottom_toTopOf="@id/l_twin_cards" + app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintStart_toStartOf="parent" /> Date: Fri, 22 Oct 2021 00:15:34 +0300 Subject: [PATCH 03/18] Updated on 2026-08-14 --- .../redux/middlewares/WalletMiddleware.kt | 324 +++++++++--------- 1 file changed, 159 insertions(+), 165 deletions(-) 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 45ebaee21f..5f0ee586c7 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 @@ -26,6 +26,7 @@ import com.tangem.tap.features.wallet.redux.* import com.tangem.tap.network.NetworkStateChanged import kotlinx.coroutines.launch import org.rekotlin.Action +import org.rekotlin.DispatchFunction import org.rekotlin.Middleware class WalletMiddleware { @@ -37,180 +38,173 @@ class WalletMiddleware { val walletMiddleware: Middleware = { dispatch, state -> { next -> { action -> - val globalState = state()?.globalState - val walletState = state()?.walletState - when (action) { - is WalletAction.TradeCryptoAction -> tradeCryptoMiddleware.handle(action) - is WalletAction.TwinsAction -> twinsMiddleware.handle(action) - is WalletAction.Warnings -> warningsMiddleware.handle(action, globalState) - is WalletAction.MultiWallet -> - multiWalletMiddleware.handle(action, walletState, globalState) - is WalletAction.LoadWallet -> { - scope.launch { - if (action.blockchain == null) { - walletState?.walletManagers?.map { walletManager -> - globalState?.tapWalletManager?.loadWalletData(walletManager) - } - } else { - val walletManager = walletState?.getWalletManager(action.blockchain) - walletManager?.let { globalState?.tapWalletManager?.loadWalletData(it) } - } - } - } - is WalletAction.LoadWallet.Success -> { - val coinAmount = action.wallet.amounts[AmountType.Coin]?.value - if (coinAmount != null && !coinAmount.isZero()) { - if (walletState?.getWalletData(action.wallet.blockchain) == null) { - store.dispatch(WalletAction.MultiWallet.AddBlockchain(action.wallet.blockchain)) - store.dispatch(WalletAction.LoadWallet.Success(action.wallet)) - } - } - store.dispatch(WalletAction.Warnings.CheckHashesCount.CheckHashesCountOnline) - warningsMiddleware.tryToShowAppRatingWarning(action.wallet) - } - is WalletAction.LoadFiatRate -> { - scope.launch { - when { - action.wallet != null -> { - globalState?.tapWalletManager?.loadFiatRate( - globalState.appCurrency, action.wallet - ) - } - action.currency != null -> { - globalState?.tapWalletManager?.loadFiatRate( - globalState.appCurrency, action.currency - ) - } - else -> { - globalState?.tapWalletManager?.loadFiatRate( - fiatCurrency = globalState.appCurrency, - currencies = walletState?.wallets?.mapNotNull { it.currency } - ?: emptyList() - ) - } - } - } - } - is WalletAction.CreateWallet -> { - if (walletState?.twinCardsState != null) { - val cardId = globalState?.scanResponse?.card?.cardId - val twinCardNumber = cardId?.let { TwinsHelper.getTwinCardNumber(it) } - store.dispatch( - CreateTwinWalletAction.ShowWarning(twinCardNumber, CreateTwinWallet.CreateWallet) - ) - } else { - scope.launch { - val result = tangemSdkManager.createWallet( - globalState?.scanResponse?.card?.cardId - ) - when (result) { - is CompletionResult.Success -> { - val scanNoteResponse = - globalState?.scanResponse?.copy(card = result.data) - scanNoteResponse?.let { - globalState.tapWalletManager.onCardScanned(scanNoteResponse) - } - } - is CompletionResult.Failure -> { - (result.error as? TangemSdkError)?.let { error -> - FirebaseAnalyticsHandler.logCardSdkError( - error, - FirebaseAnalyticsHandler.ActionToLog.CreateWallet, - card = store.state.detailsState.card - ) - } - } - } - } - } - } - is WalletAction.UpdateWallet -> { - if (action.blockchain != null) { - scope.launch { - val walletManager = walletState?.getWalletManager(action.blockchain) - walletManager?.let { globalState?.tapWalletManager?.updateWallet(it) } - } - } else { - scope.launch { - if (walletState?.state == ProgressState.Done) { - walletState.walletManagers.map { walletManager -> - globalState?.tapWalletManager?.updateWallet(walletManager) - } - } - } - } + handleAction(action, dispatch) + next(action) + } + } + } + private fun handleAction(action: Action, dispatch: DispatchFunction) { + val globalState = store.state.globalState + val walletState = store.state.walletState + + when (action) { + is WalletAction.TradeCryptoAction -> tradeCryptoMiddleware.handle(action) + is WalletAction.TwinsAction -> twinsMiddleware.handle(action) + is WalletAction.Warnings -> warningsMiddleware.handle(action, globalState) + is WalletAction.MultiWallet -> multiWalletMiddleware.handle(action, walletState, globalState) + is WalletAction.LoadWallet -> { + scope.launch { + if (action.blockchain == null) { + walletState.walletManagers.map { walletManager -> + globalState.tapWalletManager.loadWalletData(walletManager) + } + } else { + val walletManager = walletState.getWalletManager(action.blockchain) + walletManager?.let { globalState.tapWalletManager.loadWalletData(it) } } - is WalletAction.Scan -> { - store.dispatch(HomeAction.ShouldScanCardOnResume(true)) - store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) + } + } + is WalletAction.LoadWallet.Success -> { + val coinAmount = action.wallet.amounts[AmountType.Coin]?.value + if (coinAmount != null && !coinAmount.isZero()) { + if (walletState.getWalletData(action.wallet.blockchain) == null) { + store.dispatch(WalletAction.MultiWallet.AddBlockchain(action.wallet.blockchain)) + store.dispatch(WalletAction.LoadWallet.Success(action.wallet)) } - is WalletAction.LoadCardInfo -> { - scope.launch { - val response = OnlineCardVerifier().getCardInfo( - action.card.cardId, action.card.cardPublicKey + } + store.dispatch(WalletAction.Warnings.CheckHashesCount.CheckHashesCountOnline) + warningsMiddleware.tryToShowAppRatingWarning(action.wallet) + } + is WalletAction.LoadFiatRate -> { + scope.launch { + when { + action.wallet != null -> { + globalState.tapWalletManager.loadFiatRate( + globalState.appCurrency, action.wallet ) - when (response) { - is Result.Success -> { - store.dispatchOnMain( - WalletAction.SetArtworkId(response.data.artwork?.id) - ) - store.dispatchOnMain( - WalletAction.LoadArtwork(action.card, response.data.artwork?.id) - ) - store.dispatchOnMain( - GlobalAction.SetIfCardVerifiedOnline(response.data.passed) - ) - } - is Result.Failure -> { - store.dispatchOnMain( - GlobalAction.SetIfCardVerifiedOnline(false) - ) - } - } - store.dispatchOnMain(WalletAction.Warnings.CheckIfNeeded) } - } - is WalletAction.LoadData -> { - scope.launch { - val scanNoteResponse = globalState?.scanResponse - ?: return@launch - if (!walletState?.wallets.isNullOrEmpty()) { - globalState.tapWalletManager.reloadData(scanNoteResponse) - } else { - globalState.tapWalletManager.loadData(scanNoteResponse) - } + action.currency != null -> { + globalState.tapWalletManager.loadFiatRate( + globalState.appCurrency, action.currency + ) } - } - is NetworkStateChanged -> { - globalState?.scanResponse?.let { scanNoteResponse -> - store.dispatch(WalletAction.Warnings.CheckHashesCount.CheckHashesCountOnline) - scope.launch { - globalState.tapWalletManager.loadData(scanNoteResponse) - } - } - } - is WalletAction.CopyAddress -> { - action.context.copyToClipboard(action.address) - store.dispatch(WalletAction.CopyAddress.Success) - } - is WalletAction.ShareAddress -> { - action.context.shareText(action.address) - } - is WalletAction.ExploreAddress -> { - val uri = Uri.parse(action.exploreUrl) - val intent = Intent(Intent.ACTION_VIEW, uri) - ContextCompat.startActivity(action.context, intent, null) - } - is WalletAction.Send -> { - val newAction = prepareSendAction(action.amount, state()?.walletState) - store.dispatch(newAction) - if (newAction is PrepareSendScreen) { - store.dispatch(NavigationAction.NavigateTo(AppScreen.Send)) + else -> { + globalState.tapWalletManager.loadFiatRate( + fiatCurrency = globalState.appCurrency, + currencies = walletState.wallets.mapNotNull { it.currency } + ) } } } - next(action) + } + is WalletAction.CreateWallet -> { + if (walletState.twinCardsState != null) { + val cardId = globalState.scanResponse?.card?.cardId + val twinCardNumber = cardId?.let { TwinsHelper.getTwinCardNumber(it) } + store.dispatch( + CreateTwinWalletAction.ShowWarning(twinCardNumber, CreateTwinWallet.CreateWallet) + ) + } else { + scope.launch { + val result = tangemSdkManager.createWallet( + globalState.scanResponse?.card?.cardId + ) + when (result) { + is CompletionResult.Success -> { + val scanNoteResponse = globalState.scanResponse?.copy(card = result.data) + scanNoteResponse?.let { + globalState.tapWalletManager.onCardScanned(scanNoteResponse) + } + } + is CompletionResult.Failure -> { + (result.error as? TangemSdkError)?.let { error -> + FirebaseAnalyticsHandler.logCardSdkError( + error, + FirebaseAnalyticsHandler.ActionToLog.CreateWallet, + card = store.state.detailsState.card + ) + } + } + } + } + } + } + is WalletAction.UpdateWallet -> { + if (action.blockchain != null) { + scope.launch { + val walletManager = walletState.getWalletManager(action.blockchain) + walletManager?.let { globalState.tapWalletManager.updateWallet(it) } + } + } else { + scope.launch { + if (walletState.state == ProgressState.Done) { + walletState.walletManagers.map { walletManager -> + globalState.tapWalletManager.updateWallet(walletManager) + } + } + } + } + } + is WalletAction.Scan -> { + store.dispatch(HomeAction.ShouldScanCardOnResume(true)) + store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) + } + is WalletAction.LoadCardInfo -> { + scope.launch { + val response = OnlineCardVerifier().getCardInfo( + action.card.cardId, action.card.cardPublicKey + ) + when (response) { + is Result.Success -> { + val actionList = listOf( + WalletAction.SetArtworkId(response.data.artwork?.id), + WalletAction.LoadArtwork(action.card, response.data.artwork?.id), + GlobalAction.SetIfCardVerifiedOnline(response.data.passed) + ) + actionList.forEach { store.dispatch(it) } + } + is Result.Failure -> { + store.dispatchOnMain(GlobalAction.SetIfCardVerifiedOnline(false)) + } + } + store.dispatchOnMain(WalletAction.Warnings.CheckIfNeeded) + } + } + is WalletAction.LoadData -> { + scope.launch { + val scanNoteResponse = globalState.scanResponse ?: return@launch + if (!walletState.wallets.isEmpty()) { + globalState.tapWalletManager.reloadData(scanNoteResponse) + } else { + globalState.tapWalletManager.loadData(scanNoteResponse) + } + } + } + is NetworkStateChanged -> { + globalState.scanResponse?.let { scanNoteResponse -> + store.dispatch(WalletAction.Warnings.CheckHashesCount.CheckHashesCountOnline) + scope.launch { globalState.tapWalletManager.loadData(scanNoteResponse) } + } + } + is WalletAction.CopyAddress -> { + action.context.copyToClipboard(action.address) + store.dispatch(WalletAction.CopyAddress.Success) + } + is WalletAction.ShareAddress -> { + action.context.shareText(action.address) + } + is WalletAction.ExploreAddress -> { + val uri = Uri.parse(action.exploreUrl) + val intent = Intent(Intent.ACTION_VIEW, uri) + ContextCompat.startActivity(action.context, intent, null) + } + is WalletAction.Send -> { + val newAction = prepareSendAction(action.amount, store.state.walletState) + store.dispatch(newAction) + if (newAction is PrepareSendScreen) { + store.dispatch(NavigationAction.NavigateTo(AppScreen.Send)) + } } } } From 66f7ab98e9b998951cf56e00be23257f167ee41e Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 22 Oct 2021 02:59:15 +0300 Subject: [PATCH 04/18] Updated on 2026-08-14 --- .../com/tangem/tap/common/redux/AppReducer.kt | 2 + .../com/tangem/tap/common/redux/AppState.kt | 6 +- .../com/tangem/tap/domain/TapWalletManager.kt | 131 +++++++++--------- .../com/tangem/tap/domain/TapWorkarounds.kt | 11 +- .../tangem/tap/domain/tasks/ScanNoteTask.kt | 2 +- .../CreateProductWalletAndRescanTask.kt | 2 +- .../domain/tasks/product/ScanProductTask.kt | 22 ++- .../tangem/tap/domain/twins/TwinsHelper.kt | 1 + .../features/details/redux/DetailsAction.kt | 3 - .../features/details/redux/DetailsReducer.kt | 27 +--- .../features/details/redux/DetailsState.kt | 17 ++- .../features/details/ui/DetailsFragment.kt | 13 +- .../products/twins/OnboardingTwinsFragment.kt | 6 +- .../twins/redux/CreateTwinWalletAction.kt | 52 ------- .../twins/redux/CreateTwinWalletReducer.kt | 67 --------- .../twins/redux/CreateTwinWalletState.kt | 17 --- .../features/twins/redux/TwinCardsAction.kt | 62 +++++++++ ...etMiddleware.kt => TwinCardsMiddleware.kt} | 67 ++++----- .../features/twins/redux/TwinCardsReducer.kt | 63 +++++++++ .../features/twins/redux/TwinCardsState.kt | 34 +++++ .../twins/ui/CreateTwinWalletFragment.kt | 40 +++--- .../twins/ui/TwinWalletWarningFragment.kt | 12 +- .../tap/features/wallet/redux/WalletAction.kt | 9 -- .../tap/features/wallet/redux/WalletState.kt | 89 ++++++------ .../redux/middlewares/TwinsMiddleware.kt | 19 --- .../redux/middlewares/WalletMiddleware.kt | 18 +-- .../wallet/redux/reducers/TwinsReducer.kt | 36 ----- .../wallet/redux/reducers/WalletReducer.kt | 8 +- .../tap/features/wallet/ui/WalletFragment.kt | 13 +- .../wallet/ui/wallet/SingleWalletView.kt | 5 +- 30 files changed, 412 insertions(+), 442 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/features/twins/redux/CreateTwinWalletAction.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/twins/redux/CreateTwinWalletReducer.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/twins/redux/CreateTwinWalletState.kt create mode 100644 app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsAction.kt rename app/src/main/java/com/tangem/tap/features/twins/redux/{CreateTwinWalletMiddleware.kt => TwinCardsMiddleware.kt} (61%) create mode 100644 app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsReducer.kt create mode 100644 app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsState.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TwinsMiddleware.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/TwinsReducer.kt diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt index 38c76819b3..ed4dbe69aa 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt @@ -11,6 +11,7 @@ import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOt import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletReducer import com.tangem.tap.features.send.redux.reducers.SendScreenReducer import com.tangem.tap.features.tokens.redux.TokensReducer +import com.tangem.tap.features.twins.redux.TwinCardsReducer import com.tangem.tap.features.wallet.redux.reducers.WalletReducer import org.rekotlin.Action @@ -26,6 +27,7 @@ fun appReducer(action: Action, state: AppState?): AppState { onboardingWalletState = OnboardingWalletReducer.reduce(action, state), onboardingOtherCardsState = OnboardingOtherCardsReducer.reduce(action, state), walletState = WalletReducer.reduce(action, state), + twinCardsState = TwinCardsReducer.reduce(action, state), sendState = SendScreenReducer.reduce(action, state.sendState), detailsState = DetailsReducer.reduce(action, state), disclaimerState = DisclaimerReducer.reduce(action, state), diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt index f883d78840..98827674a0 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt @@ -22,7 +22,8 @@ import com.tangem.tap.features.send.redux.middlewares.SendMiddleware import com.tangem.tap.features.send.redux.states.SendState import com.tangem.tap.features.tokens.redux.TokensMiddleware import com.tangem.tap.features.tokens.redux.TokensState -import com.tangem.tap.features.twins.redux.CreateTwinWalletMiddleware +import com.tangem.tap.features.twins.redux.TwinCardsMiddleware +import com.tangem.tap.features.twins.redux.TwinCardsState import com.tangem.tap.features.wallet.redux.WalletState import com.tangem.tap.features.wallet.redux.middlewares.WalletMiddleware import org.rekotlin.Middleware @@ -36,6 +37,7 @@ data class AppState( val onboardingWalletState: OnboardingWalletState = OnboardingWalletState(), val onboardingOtherCardsState: OnboardingOtherCardsState = OnboardingOtherCardsState(), val walletState: WalletState = WalletState(), + val twinCardsState: TwinCardsState = TwinCardsState(), val sendState: SendState = SendState(), val detailsState: DetailsState = DetailsState(), val disclaimerState: DisclaimerState = DisclaimerState(), @@ -53,7 +55,7 @@ data class AppState( OnboardingWalletMiddleware.handler, OnboardingOtherCardsMiddleware.handler, WalletMiddleware().walletMiddleware, - CreateTwinWalletMiddleware.handler, + TwinCardsMiddleware.handler, SendMiddleware().sendMiddleware, DetailsMiddleware().detailsMiddleware, DisclaimerMiddleware().disclaimerMiddleware, 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 163359460d..edc4601d8c 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -19,6 +19,7 @@ import com.tangem.tap.domain.tokens.CardCurrencies import com.tangem.tap.domain.twins.getTwinCardNumber import com.tangem.tap.domain.twins.isTangemTwin import com.tangem.tap.features.tokens.redux.TokensAction +import com.tangem.tap.features.twins.redux.TwinCardsAction import com.tangem.tap.features.wallet.redux.Currency import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.network.NetworkConnectivity @@ -82,7 +83,8 @@ class TapWalletManager { FirebaseAnalyticsHandler.triggerEvent(AnalyticsEvent.CARD_IS_SCANNED, data.card, data.walletData?.blockchain) } store.state.globalState.feedbackManager?.infoHolder?.setCardInfo(data.card) - updateConfigManager(data) + val configManager = store.state.globalState.configManager + updateConfigManager(configManager, data) withContext(Dispatchers.Main) { store.dispatch(WalletAction.ResetState) @@ -91,7 +93,8 @@ class TapWalletManager { store.dispatch(WalletAction.MultiWallet.SetIsMultiwalletAllowed(data.card.isMultiwalletAllowed)) if (data.card.isTangemTwin()) { data.card.getTwinCardNumber()?.let { - store.dispatch(WalletAction.TwinsAction.SetTwinCard(null, it, true)) + val isCreatingTwinsAllowed = configManager?.config?.isCreatingTwinCardsAllowed ?: false + store.dispatch(TwinCardsAction.SetTwinCard(it, null, isCreatingTwinsAllowed)) } } @@ -104,8 +107,7 @@ class TapWalletManager { } } - private fun updateConfigManager(data: ScanResponse) { - val configManager = store.state.globalState.configManager + private fun updateConfigManager(configManager: ConfigManager?, data: ScanResponse) { val blockchain = data.getBlockchain() if (data.card.isStart2Coin) { configManager?.turnOff(ConfigManager.isSendingToPayIdEnabled) @@ -122,53 +124,42 @@ class TapWalletManager { suspend fun loadData(data: ScanResponse) { withContext(Dispatchers.Main) { - store.dispatch(WalletAction.LoadCardInfo(data.card)) + getActionIfUnknownBlockchainOrEmptyWallet(data)?.let { + store.dispatch(it) + return@withContext + } - when { - data.card.isTangemTwin() && data.secondTwinPublicKey == null -> { - store.dispatch(WalletAction.EmptyWallet) + val config = store.state.globalState.configManager?.config ?: return@withContext + val blockchain = data.getBlockchain() + val primaryWalletManager = walletManagerFactory.makePrimaryWalletManager(data) + + if (blockchain != Blockchain.Unknown && primaryWalletManager != null) { + val primaryToken = data.getPrimaryToken() + + store.dispatch(WalletAction.MultiWallet.SetPrimaryBlockchain(blockchain)) + if (primaryToken != null) { + primaryWalletManager.addToken(primaryToken) + store.dispatch(WalletAction.MultiWallet.SetPrimaryToken(primaryToken)) } - data.getBlockchain() == Blockchain.Unknown && !data.card.isMultiwalletAllowed -> { - store.dispatch(WalletAction.LoadData.Failure(TapError.UnknownBlockchain)) + if (data.card.isMultiwalletAllowed) { + loadMultiWalletData(data.card, blockchain, primaryWalletManager) + } else { + store.dispatch(WalletAction.MultiWallet.AddWalletManagers(primaryWalletManager)) + store.dispatch(WalletAction.MultiWallet.AddBlockchains(listOf(blockchain))) } - data.card.wallets.isEmpty() -> { - store.dispatch(WalletAction.EmptyWallet) - } - else -> { - val config = store.state.globalState.configManager?.config ?: return@withContext - val blockchain = data.getBlockchain() - val primaryWalletManager = walletManagerFactory.makePrimaryWalletManager(data) - - if (blockchain != Blockchain.Unknown && primaryWalletManager != null) { - val primaryToken = data.getPrimaryToken() - - store.dispatch(WalletAction.MultiWallet.SetPrimaryBlockchain(blockchain)) - if (primaryToken != null) { - primaryWalletManager.addToken(primaryToken) - store.dispatch(WalletAction.MultiWallet.SetPrimaryToken(primaryToken)) - } - if (data.card.isMultiwalletAllowed) { - loadMultiWalletData(data.card, blockchain, primaryWalletManager) - } else { - store.dispatch(WalletAction.MultiWallet.AddWalletManagers(primaryWalletManager)) - store.dispatch(WalletAction.MultiWallet.AddBlockchains(listOf(blockchain))) - } - - } else { - if (data.card.isMultiwalletAllowed) { - loadMultiWalletData(data.card, blockchain, null) - } - } - val moonPayUserStatus = store.state.globalState.moonPayUserStatus - store.dispatch(WalletAction.LoadWallet( - allowToBuy = config.isTopUpEnabled && moonPayUserStatus?.isBuyAllowed == true, - allowToSell = config.isTopUpEnabled && moonPayUserStatus?.isSellAllowed == true, - )) - store.dispatch(WalletAction.LoadFiatRate()) + } else { + if (data.card.isMultiwalletAllowed) { + loadMultiWalletData(data.card, blockchain, null) } } + val moonPayUserStatus = store.state.globalState.moonPayUserStatus + store.dispatch(WalletAction.LoadWallet( + allowToBuy = config.isTopUpEnabled && moonPayUserStatus?.isBuyAllowed == true, + allowToSell = config.isTopUpEnabled && moonPayUserStatus?.isSellAllowed == true, + )) + store.dispatch(WalletAction.LoadFiatRate()) } } @@ -220,28 +211,38 @@ class TapWalletManager { suspend fun reloadData(data: ScanResponse) { withContext(Dispatchers.Main) { - when { - data.getBlockchain() == Blockchain.Unknown && !data.card.isMultiwalletAllowed -> { - store.dispatch(WalletAction.LoadData.Failure(TapError.UnknownBlockchain)) - } - data.card.wallets.isEmpty() || - (data.card.isTangemTwin() && data.secondTwinPublicKey == null) -> { - store.dispatch(WalletAction.EmptyWallet) - } - else -> { - if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) { - store.dispatch(WalletAction.LoadData.Failure(TapError.NoInternetConnection)) - return@withContext - } - val config = store.state.globalState.configManager?.config ?: return@withContext - val moonpayUserStatus = store.state.globalState.moonPayUserStatus - store.dispatch(WalletAction.LoadWallet( - allowToBuy = config.isTopUpEnabled && moonpayUserStatus?.isBuyAllowed == true, - allowToSell = config.isTopUpEnabled && moonpayUserStatus?.isSellAllowed == true, - )) - store.dispatch(WalletAction.LoadFiatRate()) - } + getActionIfUnknownBlockchainOrEmptyWallet(data)?.let { + store.dispatch(it) + return@withContext } + if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) { + store.dispatch(WalletAction.LoadData.Failure(TapError.NoInternetConnection)) + return@withContext + } + + val config = store.state.globalState.configManager?.config ?: return@withContext + val moonpayUserStatus = store.state.globalState.moonPayUserStatus + store.dispatch(WalletAction.LoadWallet( + allowToBuy = config.isTopUpEnabled && moonpayUserStatus?.isBuyAllowed == true, + allowToSell = config.isTopUpEnabled && moonpayUserStatus?.isSellAllowed == true, + )) + store.dispatch(WalletAction.LoadFiatRate()) + } + } + + private fun getActionIfUnknownBlockchainOrEmptyWallet(data: ScanResponse): WalletAction? { + return when { + // check order is important + data.card.isTangemTwin() && !data.twinsIsTwinned() -> { + WalletAction.EmptyWallet + } + data.getBlockchain() == Blockchain.Unknown && !data.card.isMultiwalletAllowed -> { + WalletAction.LoadData.Failure(TapError.UnknownBlockchain) + } + data.card.wallets.isEmpty() -> { + WalletAction.EmptyWallet + } + else -> null } } diff --git a/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt b/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt index 9003c9f4fc..01ef833c3d 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt @@ -28,10 +28,13 @@ object TapWorkarounds { return excludedBatch || excludedIssuerName } - fun Card.isTangemNote(): Boolean = tangemNoteBatches.contains(batchId) - fun Card.isTangemWallet(): Boolean = tangemWalletBatches.contains(batchId) + @Deprecated("Use ScanResponse.isTangemNote") + fun isTangemNote(card: Card): Boolean = tangemNoteBatches.contains(card.batchId) - fun Card.getTangemNoteBlockchain(): Blockchain? = tangemNoteBatches[batchId] + @Deprecated("Use ScanResponse.isTangemWallet") + fun isTangemWallet(card: Card): Boolean = tangemWalletBatches.contains(card.batchId) + + fun getTangemNoteBlockchain(card: Card): Blockchain? = tangemNoteBatches[card.batchId] private const val START_2_COIN_ISSUER = "start2coin" private const val TEST_CARD_BATCH = "99FF" @@ -64,7 +67,7 @@ val DELAY_SDK_DIALOG_CLOSE = 1400L val Card.isMultiwalletAllowed: Boolean get() { - return !isTangemTwin() && !isStart2Coin && !isTangemNote() + return !isTangemTwin() && !isStart2Coin && !isTangemNote(this) && (firmwareVersion >= FirmwareVersion.MultiWalletAvailable || getSingleWallet()?.curve == EllipticCurve.Secp256k1) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt index 3b01ae1c98..8b3c26a91e 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt @@ -40,7 +40,7 @@ class ScanNoteTask(val card: Card? = null) : CardSessionRunnable { if (card.isTangemTwin()) { dealWithTwinCard(card, session, callback) - } else if (!card.isTangemNote() && card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable) { + } else if (!isTangemNote(card) && card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable) { createMissingWalletsIfNeeded(card, session, callback) } else { callback(CompletionResult.Success( diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletAndRescanTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletAndRescanTask.kt index 92beb01238..f1024cdf11 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletAndRescanTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletAndRescanTask.kt @@ -64,7 +64,7 @@ private class CreateWalletTangemNote : ProductCommandProcessor { override fun run( @@ -74,9 +82,9 @@ class ScanProductTask(val card: Card? = null) : CardSessionRunnable ScanNoteProcessor() - card.isTangemTwin() -> ScanTwinProcessor() - card.isTangemWallet() -> ScanWalletProcessor() + TapWorkarounds.isTangemNote(card) -> ScanNoteProcessor() + TwinsHelper.getTwinCardNumber(card.cardId) != null -> ScanTwinProcessor() + TapWorkarounds.isTangemWallet(card) -> ScanWalletProcessor() else -> ScanOtherCardsProcessor() } commandProcessor.proceed(card, session, callback) diff --git a/app/src/main/java/com/tangem/tap/domain/twins/TwinsHelper.kt b/app/src/main/java/com/tangem/tap/domain/twins/TwinsHelper.kt index 89affa15d1..d74d5ccf0d 100644 --- a/app/src/main/java/com/tangem/tap/domain/twins/TwinsHelper.kt +++ b/app/src/main/java/com/tangem/tap/domain/twins/TwinsHelper.kt @@ -51,6 +51,7 @@ enum class TwinCardNumber(val number: Int) { } } +@Deprecated("Use ScanResponse.isTangemTwin") fun Card.isTangemTwin(): Boolean { return TwinsHelper.getTwinCardNumber(cardId) != null } diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt index 0e7a1f5e21..3f8fbfccea 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt @@ -1,7 +1,6 @@ package com.tangem.tap.features.details.redux import com.tangem.blockchain.common.Wallet -import com.tangem.common.card.Card import com.tangem.operations.pins.CheckUserCodesResponse import com.tangem.tap.common.redux.NotificationAction import com.tangem.tap.common.redux.global.FiatCurrencyName @@ -14,10 +13,8 @@ import org.rekotlin.Action sealed class DetailsAction : Action { data class PrepareScreen( - val card: Card, val scanResponse: ScanResponse, val wallets: List, - val isCreatingTwinWalletAllowed: Boolean?, val cardTou: CardTou, val fiatCurrencyName: FiatCurrencyName, val fiatCurrencies: List? = null, diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt index 5989a084e2..52c9652e68 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt @@ -7,9 +7,6 @@ import com.tangem.tap.domain.TapWorkarounds.isStart2Coin import com.tangem.tap.domain.extensions.isWalletDataSupported import com.tangem.tap.domain.extensions.signedHashesCount import com.tangem.tap.domain.extensions.toSendableAmounts -import com.tangem.tap.domain.twins.getTwinCardNumber -import com.tangem.tap.domain.twins.isTangemTwin -import com.tangem.tap.features.twins.redux.CreateTwinWalletState import com.tangem.tap.features.wallet.models.hasPendingTransactions import org.rekotlin.Action import java.util.* @@ -42,26 +39,12 @@ private fun internalReduce(action: Action, state: AppState): DetailsState { } private fun handlePrepareScreen(action: DetailsAction.PrepareScreen, state: DetailsState): DetailsState { - val twinsState = if (action.card.isTangemTwin()) { - CreateTwinWalletState( - scanResponse = action.scanResponse, - twinCardNumber = action.card.getTwinCardNumber(), - createTwinWallet = null, - showAlert = false, - allowRecreatingWallet = action.isCreatingTwinWalletAllowed - ) - } else { - null - } - return DetailsState( - card = action.card, wallets = action.wallets, - cardInfo = action.card.toCardInfo(), - appCurrencyState = AppCurrencyState( - action.fiatCurrencyName - ), - createTwinWalletState = twinsState, - cardTermsOfUseUrl = action.cardTou.getUrl(action.card) + card = action.scanResponse.card, + wallets = action.wallets, + cardInfo = action.scanResponse.card.toCardInfo(), + appCurrencyState = AppCurrencyState(action.fiatCurrencyName), + cardTermsOfUseUrl = action.cardTou.getUrl(action.scanResponse.card) ) } diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt index bd55c9aa95..40a6a6df31 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt @@ -6,10 +6,12 @@ import com.tangem.common.card.Card import com.tangem.tap.common.entities.Button import com.tangem.tap.common.entities.TapCurrency.Companion.DEFAULT_FIAT_CURRENCY import com.tangem.tap.common.redux.global.FiatCurrencyName -import com.tangem.tap.features.twins.redux.CreateTwinWalletState +import com.tangem.tap.features.twins.redux.TwinCardsState import com.tangem.tap.network.coinmarketcap.FiatCurrency +import com.tangem.tap.store import org.rekotlin.StateType import java.util.* +import kotlin.properties.ReadOnlyProperty data class DetailsState( val card: Card? = null, @@ -19,9 +21,18 @@ data class DetailsState( val eraseWalletState: EraseWalletState? = null, val confirmScreenState: ConfirmScreenState? = null, val securityScreenState: SecurityScreenState? = null, - val createTwinWalletState: CreateTwinWalletState? = null, val cardTermsOfUseUrl: Uri? = null, -) : StateType +) : StateType { + + // if you do not delegate - the application crashes on startup, + // because twinCardsState has not been created yet + val twinCardsState: TwinCardsState by ReadOnlyProperty { thisRef, property -> + store.state.twinCardsState + } + + val isTangemTwins: Boolean + get() = store.state.globalState.scanResponse?.isTangemTwins() == true +} data class CardInfo( val cardId: String, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt index 7d845228f7..81b6e91032 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt @@ -17,8 +17,8 @@ import com.tangem.tap.features.details.redux.DetailsAction import com.tangem.tap.features.details.redux.DetailsState import com.tangem.tap.features.details.redux.SecurityOption import com.tangem.tap.features.feedback.FeedbackEmail -import com.tangem.tap.features.twins.redux.CreateTwinWallet -import com.tangem.tap.features.twins.redux.CreateTwinWalletAction +import com.tangem.tap.features.twins.redux.CreateTwinWalletMode +import com.tangem.tap.features.twins.redux.TwinCardsAction import com.tangem.tap.store import com.tangem.wallet.R import kotlinx.android.synthetic.main.fragment_details.* @@ -91,12 +91,15 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber { - state.copy(createTwinWalletState = CreateTwinWalletState( - scanResponse = null, - twinCardNumber = action.twinCardNumber - ?: state.createTwinWalletState?.twinCardNumber, - createTwinWallet = action.createTwinWallet, - showAlert = false, - allowRecreatingWallet = state.createTwinWalletState?.allowRecreatingWallet - )) - } - CreateTwinWalletAction.NotEmpty -> state - CreateTwinWalletAction.ShowAlert -> { - state.copy(createTwinWalletState = state.createTwinWalletState?.copy( - showAlert = true - )) - } - CreateTwinWalletAction.HideAlert -> { - state.copy(createTwinWalletState = state.createTwinWalletState?.copy( - showAlert = false - )) - } - is CreateTwinWalletAction.Proceed -> { - state - } - CreateTwinWalletAction.Cancel -> state - CreateTwinWalletAction.Cancel.Confirm -> state - is CreateTwinWalletAction.LaunchFirstStep -> state - - CreateTwinWalletAction.LaunchFirstStep.Success -> { - state.copy(createTwinWalletState = state.createTwinWalletState?.copy( - step = CreateTwinWalletStep.SecondStep - )) - } - CreateTwinWalletAction.LaunchFirstStep.Failure -> state - - is CreateTwinWalletAction.LaunchSecondStep -> state - CreateTwinWalletAction.LaunchSecondStep.Success -> - state.copy(createTwinWalletState = state.createTwinWalletState?.copy( - step = CreateTwinWalletStep.ThirdStep - )) - CreateTwinWalletAction.LaunchSecondStep.Failure -> { - state - } - is CreateTwinWalletAction.LaunchThirdStep -> { - state - } - is CreateTwinWalletAction.LaunchThirdStep.Success -> { - state - } - CreateTwinWalletAction.LaunchThirdStep.Failure -> { - state - } - } - } - - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/twins/redux/CreateTwinWalletState.kt b/app/src/main/java/com/tangem/tap/features/twins/redux/CreateTwinWalletState.kt deleted file mode 100644 index 0a7c6e04ee..0000000000 --- a/app/src/main/java/com/tangem/tap/features/twins/redux/CreateTwinWalletState.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.tangem.tap.features.twins.redux - -import com.tangem.tap.domain.tasks.product.ScanResponse -import com.tangem.tap.domain.twins.TwinCardNumber - -data class CreateTwinWalletState( - val scanResponse: ScanResponse?, - val step: CreateTwinWalletStep = CreateTwinWalletStep.FirstStep, - val twinCardNumber: TwinCardNumber?, - val createTwinWallet: CreateTwinWallet?, - val showAlert: Boolean, - val allowRecreatingWallet: Boolean? = null -) - -enum class CreateTwinWalletStep { FirstStep, SecondStep, ThirdStep } - -enum class CreateTwinWallet { CreateWallet, RecreateWallet } diff --git a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsAction.kt b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsAction.kt new file mode 100644 index 0000000000..cf7d2433dd --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsAction.kt @@ -0,0 +1,62 @@ +package com.tangem.tap.features.twins.redux + +import android.content.Context +import com.tangem.Message +import com.tangem.tap.common.redux.NotificationAction +import com.tangem.tap.domain.tasks.product.ScanResponse +import com.tangem.tap.domain.twins.TwinCardNumber +import com.tangem.wallet.R +import org.rekotlin.Action + +/** +[REDACTED_AUTHOR] + */ +sealed class TwinCardsAction : Action { + object ShowOnboarding : TwinCardsAction() + object SetOnboardingShown : TwinCardsAction() + data class SetTwinCard( + val number: TwinCardNumber, + val secondCardId: String?, + val isCreatingTwinCardsAllowed: Boolean, + ) : TwinCardsAction() + + sealed class CreateWallet : TwinCardsAction() { + data class Create( + val number: TwinCardNumber, + val createTwinWalletMode: CreateTwinWalletMode + ) : CreateWallet() + + object NotEmpty : CreateWallet(), NotificationAction { + override val messageResource = R.string.details_notification_erase_wallet_not_possible + } + + object ShowAlert : CreateWallet() + object HideAlert : CreateWallet() + object Proceed : CreateWallet() + + object Cancel : CreateWallet() { + object Confirm : CreateWallet() + } + + data class LaunchFirstStep( + val message: Message, val context: Context + ) : CreateWallet() { + object Success : CreateWallet() + object Failure : CreateWallet() + } + + data class LaunchSecondStep( + val initialMessage: Message, + val preparingMessage: Message, + val creatingWalletMessage: Message, + ) : CreateWallet() { + object Success : CreateWallet() + object Failure : CreateWallet() + } + + data class LaunchThirdStep(val message: Message) : CreateWallet() { + data class Success(val scanResponse: ScanResponse) : CreateWallet() + object Failure : CreateWallet() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/twins/redux/CreateTwinWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsMiddleware.kt similarity index 61% rename from app/src/main/java/com/tangem/tap/features/twins/redux/CreateTwinWalletMiddleware.kt rename to app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsMiddleware.kt index 69f72f798d..673e0616d5 100644 --- a/app/src/main/java/com/tangem/tap/features/twins/redux/CreateTwinWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsMiddleware.kt @@ -7,6 +7,7 @@ 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.domain.twins.TwinCardsManager +import com.tangem.tap.preferencesStorage import com.tangem.tap.scope import com.tangem.tap.store import kotlinx.coroutines.Dispatchers @@ -16,7 +17,7 @@ import org.rekotlin.Action import org.rekotlin.DispatchFunction import org.rekotlin.Middleware -class CreateTwinWalletMiddleware { +class TwinCardsMiddleware { companion object { val handler = twinsWalletMiddleware } @@ -34,40 +35,47 @@ private val twinsWalletMiddleware: Middleware = { dispatch, state -> private var twinsManager: TwinCardsManager? = null private fun handle(action: Action, dispatch: DispatchFunction) { - val action = action as? CreateTwinWalletAction ?: return + val action = action as? TwinCardsAction ?: return + val twinCardsState = store.state.twinCardsState when (action) { - is CreateTwinWalletAction.ShowWarning -> { - val wallet = store.state.detailsState.wallets.firstOrNull() + is TwinCardsAction.SetTwinCard -> { + val showOnboarding = !preferencesStorage.wasTwinsOnboardingShown() + if (showOnboarding) store.dispatch(TwinCardsAction.ShowOnboarding) + } + TwinCardsAction.SetOnboardingShown -> { + preferencesStorage.saveTwinsOnboardingShown() + } + is TwinCardsAction.CreateWallet.Create -> { + val wallet = store.state.walletState.walletManagers.map { it.wallet }.firstOrNull() if (wallet == null) { store.dispatch(NavigationAction.NavigateTo(AppScreen.CreateTwinWalletWarning)) return } val notEmpty = wallet.recentTransactions.isNotEmpty() || wallet.amounts.toSendableAmounts().isNotEmpty() if (notEmpty) { - store.dispatch(CreateTwinWalletAction.NotEmpty) + store.dispatch(TwinCardsAction.CreateWallet.NotEmpty) } else { store.dispatch(NavigationAction.NavigateTo(AppScreen.CreateTwinWalletWarning)) } } - is CreateTwinWalletAction.Proceed -> + is TwinCardsAction.CreateWallet.Proceed -> { store.dispatch(NavigationAction.NavigateTo(AppScreen.CreateTwinWallet)) - is CreateTwinWalletAction.Cancel -> { - - val step = store.state.detailsState.createTwinWalletState?.step - if (step != null && step != CreateTwinWalletStep.FirstStep - ) { - store.dispatch(CreateTwinWalletAction.ShowAlert) + } + is TwinCardsAction.CreateWallet.Cancel -> { + val step = twinCardsState.createWalletState?.step + if (step != null && step != CreateTwinWalletStep.FirstStep) { + store.dispatch(TwinCardsAction.CreateWallet.ShowAlert) } else { twinsManager = null store.dispatch(NavigationAction.PopBackTo()) } } - is CreateTwinWalletAction.Cancel.Confirm -> { + is TwinCardsAction.CreateWallet.Cancel.Confirm -> { twinsManager = null store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) } - is CreateTwinWalletAction.LaunchFirstStep -> { + is TwinCardsAction.CreateWallet.LaunchFirstStep -> { store.state.globalState.scanResponse?.let { twinsManager = TwinCardsManager(it, action.context) } @@ -76,62 +84,59 @@ private fun handle(action: Action, dispatch: DispatchFunction) { withContext(Dispatchers.Main) { when (result) { SimpleResult.Success -> - store.dispatch(CreateTwinWalletAction.LaunchFirstStep.Success) + store.dispatch(TwinCardsAction.CreateWallet.LaunchFirstStep.Success) is SimpleResult.Failure -> - store.dispatch(CreateTwinWalletAction.LaunchFirstStep.Failure) + store.dispatch(TwinCardsAction.CreateWallet.LaunchFirstStep.Failure) } } } } - CreateTwinWalletAction.LaunchFirstStep.Success -> { + TwinCardsAction.CreateWallet.LaunchFirstStep.Success -> { } - CreateTwinWalletAction.LaunchFirstStep.Failure -> { + TwinCardsAction.CreateWallet.LaunchFirstStep.Failure -> { } - is CreateTwinWalletAction.LaunchSecondStep -> + is TwinCardsAction.CreateWallet.LaunchSecondStep -> scope.launch { val result = twinsManager?.createSecondWallet(action.initialMessage, action.preparingMessage, action.creatingWalletMessage) withContext(Dispatchers.Main) { when (result) { SimpleResult.Success -> - store.dispatch(CreateTwinWalletAction.LaunchSecondStep.Success) + store.dispatch(TwinCardsAction.CreateWallet.LaunchSecondStep.Success) is SimpleResult.Failure -> - store.dispatch(CreateTwinWalletAction.LaunchSecondStep.Failure) + store.dispatch(TwinCardsAction.CreateWallet.LaunchSecondStep.Failure) } } } - CreateTwinWalletAction.LaunchSecondStep.Success -> { + TwinCardsAction.CreateWallet.LaunchSecondStep.Success -> { } - CreateTwinWalletAction.LaunchSecondStep.Failure -> { + TwinCardsAction.CreateWallet.LaunchSecondStep.Failure -> { } - is CreateTwinWalletAction.LaunchThirdStep -> { + is TwinCardsAction.CreateWallet.LaunchThirdStep -> { scope.launch { val result = twinsManager?.complete(action.message) withContext(Dispatchers.Main) { when (result) { is Result.Success -> - store.dispatch( - CreateTwinWalletAction - .LaunchThirdStep.Success(result.data) - ) + store.dispatch(TwinCardsAction.CreateWallet.LaunchThirdStep.Success(result.data)) is Result.Failure -> - store.dispatch(CreateTwinWalletAction.LaunchThirdStep.Failure) + store.dispatch(TwinCardsAction.CreateWallet.LaunchThirdStep.Failure) } } } } - is CreateTwinWalletAction.LaunchThirdStep.Success -> { + is TwinCardsAction.CreateWallet.LaunchThirdStep.Success -> { scope.launch { store.state.globalState.tapWalletManager.onCardScanned(action.scanResponse) } store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet)) } - CreateTwinWalletAction.LaunchThirdStep.Failure -> { + TwinCardsAction.CreateWallet.LaunchThirdStep.Failure -> { } } diff --git a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsReducer.kt b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsReducer.kt new file mode 100644 index 0000000000..6f9e3a6f57 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsReducer.kt @@ -0,0 +1,63 @@ +package com.tangem.tap.features.twins.redux + +import com.tangem.tap.common.redux.AppState +import org.rekotlin.Action + +class TwinCardsReducer { + companion object { + fun reduce(action: Action, state: AppState): TwinCardsState = internalReduce(action, state) + } +} + +private fun internalReduce(action: Action, state: AppState): TwinCardsState { + if (action !is TwinCardsAction) return state.twinCardsState + + val twinCardsState = state.twinCardsState + return when (action) { + is TwinCardsAction.SetTwinCard -> { + twinCardsState.copy( + cardNumber = action.number, + secondCardId = action.secondCardId, + showTwinOnboarding = state.twinCardsState.showTwinOnboarding, + isCreatingTwinCardsAllowed = action.isCreatingTwinCardsAllowed, + ) + } + is TwinCardsAction.ShowOnboarding -> { + state.twinCardsState.copy(showTwinOnboarding = true) + } + is TwinCardsAction.SetOnboardingShown -> { + twinCardsState.copy(showTwinOnboarding = false) + } + is TwinCardsAction.CreateWallet.Create -> { + val prevState = twinCardsState.createWalletState + twinCardsState.copy(createWalletState = CreateTwinWalletState( + prevState?.scanResponse, + prevState?.number ?: action.number, + prevState?.mode ?: action.createTwinWalletMode, + )) + } + TwinCardsAction.CreateWallet.LaunchFirstStep.Success -> { + twinCardsState.copy(createWalletState = twinCardsState.createWalletState?.copy( + step = CreateTwinWalletStep.SecondStep + )) + } + TwinCardsAction.CreateWallet.LaunchSecondStep.Success -> + twinCardsState.copy(createWalletState = twinCardsState.createWalletState?.copy( + step = CreateTwinWalletStep.ThirdStep + )) + TwinCardsAction.CreateWallet.ShowAlert -> twinCardsState + TwinCardsAction.CreateWallet.HideAlert -> twinCardsState + is TwinCardsAction.CreateWallet.Proceed -> twinCardsState + TwinCardsAction.CreateWallet.NotEmpty -> twinCardsState + TwinCardsAction.CreateWallet.Cancel -> twinCardsState + TwinCardsAction.CreateWallet.Cancel.Confirm -> twinCardsState + is TwinCardsAction.CreateWallet.LaunchFirstStep -> twinCardsState + TwinCardsAction.CreateWallet.LaunchFirstStep.Failure -> twinCardsState + is TwinCardsAction.CreateWallet.LaunchSecondStep -> twinCardsState + TwinCardsAction.CreateWallet.LaunchSecondStep.Failure -> twinCardsState + is TwinCardsAction.CreateWallet.LaunchThirdStep -> twinCardsState + is TwinCardsAction.CreateWallet.LaunchThirdStep.Success -> twinCardsState + TwinCardsAction.CreateWallet.LaunchThirdStep.Failure -> twinCardsState + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsState.kt b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsState.kt new file mode 100644 index 0000000000..49a43b9d93 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsState.kt @@ -0,0 +1,34 @@ +package com.tangem.tap.features.twins.redux + +import com.tangem.tap.domain.tasks.product.ScanResponse +import com.tangem.tap.domain.twins.TwinCardNumber +import org.rekotlin.StateType + +/** +[REDACTED_AUTHOR] + */ +data class TwinCardsState( + // if cardNumber is not set -> the scanned card is not Twin + val cardNumber: TwinCardNumber? = null, + val secondCardId: String? = null, + val showTwinOnboarding: Boolean = false, + val isCreatingTwinCardsAllowed: Boolean = false, + val createWalletState: CreateTwinWalletState? = null +) : StateType { + val isReadyToUse: Boolean + get() = cardNumber != null +} + +data class CreateTwinWalletState( + val scanResponse: ScanResponse?, + val number: TwinCardNumber = TwinCardNumber.First, + val mode: CreateTwinWalletMode = CreateTwinWalletMode.CreateWallet, + val step: CreateTwinWalletStep = CreateTwinWalletStep.FirstStep, +) { + val showAlert: Boolean + get() = mode != CreateTwinWalletMode.RecreateWallet +} + +enum class CreateTwinWalletStep { FirstStep, SecondStep, ThirdStep } + +enum class CreateTwinWalletMode { CreateWallet, RecreateWallet } diff --git a/app/src/main/java/com/tangem/tap/features/twins/ui/CreateTwinWalletFragment.kt b/app/src/main/java/com/tangem/tap/features/twins/ui/CreateTwinWalletFragment.kt index 8c4b950a0d..0c23906aaf 100644 --- a/app/src/main/java/com/tangem/tap/features/twins/ui/CreateTwinWalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/twins/ui/CreateTwinWalletFragment.kt @@ -11,10 +11,10 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.squareup.picasso.Picasso import com.tangem.Message import com.tangem.tap.domain.twins.TwinCardNumber -import com.tangem.tap.features.details.redux.DetailsState -import com.tangem.tap.features.twins.redux.CreateTwinWallet -import com.tangem.tap.features.twins.redux.CreateTwinWalletAction +import com.tangem.tap.features.twins.redux.CreateTwinWalletMode import com.tangem.tap.features.twins.redux.CreateTwinWalletStep +import com.tangem.tap.features.twins.redux.TwinCardsAction +import com.tangem.tap.features.twins.redux.TwinCardsState import com.tangem.tap.features.wallet.redux.Artwork import com.tangem.tap.store import com.tangem.wallet.R @@ -22,7 +22,7 @@ import kotlinx.android.synthetic.main.fragment_twin_cards_create.* import org.rekotlin.StoreSubscriber class CreateTwinWalletFragment : Fragment(R.layout.fragment_twin_cards_create), - StoreSubscriber { + StoreSubscriber { private var dialog: Dialog? = null @@ -30,7 +30,7 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_twin_cards_create), super.onCreate(savedInstanceState) activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { - store.dispatch(CreateTwinWalletAction.Cancel) + store.dispatch(TwinCardsAction.CreateWallet.Cancel) } }) val inflater = TransitionInflater.from(requireContext()) @@ -42,8 +42,8 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_twin_cards_create), super.onStart() store.subscribe(this) { state -> state.skipRepeats { oldState, newState -> - oldState.detailsState == newState.detailsState - }.select { it.detailsState } + oldState.twinCardsState == newState.twinCardsState + }.select { it.twinCardsState } } } @@ -56,7 +56,7 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_twin_cards_create), super.onViewCreated(view, savedInstanceState) toolbar.setNavigationOnClickListener { - store.dispatch(CreateTwinWalletAction.Cancel) + store.dispatch(TwinCardsAction.CreateWallet.Cancel) } Picasso.get() @@ -73,21 +73,21 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_twin_cards_create), } - override fun newState(state: DetailsState) { + override fun newState(state: TwinCardsState) { if (activity == null) return - toolbar.title = when (state.createTwinWalletState?.createTwinWallet) { - CreateTwinWallet.CreateWallet -> getText(R.string.wallet_button_create_wallet) - CreateTwinWallet.RecreateWallet, null -> getText(R.string.details_twins_recreate_toolbar) + toolbar.title = when (state.createWalletState?.mode) { + CreateTwinWalletMode.CreateWallet -> getText(R.string.wallet_button_create_wallet) + CreateTwinWalletMode.RecreateWallet, null -> getText(R.string.details_twins_recreate_toolbar) } val selectedColor = getColor(requireContext(), R.color.colorSecondary) val defaultColor = getColor(requireContext(), R.color.blue_pale) - val twinCardNumber = state.createTwinWalletState?.twinCardNumber ?: TwinCardNumber.First + val twinCardNumber = state.createWalletState?.number ?: TwinCardNumber.First - val cardNumber = when (state.createTwinWalletState?.step) { + val cardNumber = when (state.createWalletState?.step) { CreateTwinWalletStep.FirstStep -> { val twinCardNumberString = twinCardNumber.number.toString() tv_step_number.text = @@ -96,7 +96,7 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_twin_cards_create), v_step_2.setBackgroundColor(defaultColor) v_step_3.setBackgroundColor(defaultColor) btn_tap.setOnClickListener { - store.dispatch(CreateTwinWalletAction.LaunchFirstStep( + store.dispatch(TwinCardsAction.CreateWallet.LaunchFirstStep( Message(getString( R.string.details_twins_recreate_title_format, twinCardNumberString @@ -117,7 +117,7 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_twin_cards_create), v_step_2.setBackgroundColor(selectedColor) v_step_3.setBackgroundColor(defaultColor) btn_tap.setOnClickListener { - store.dispatch(CreateTwinWalletAction.LaunchSecondStep( + store.dispatch(TwinCardsAction.CreateWallet.LaunchSecondStep( Message(getString(R.string.details_twins_recreate_title_format, twinCardNumberString)), Message(getString(R.string.details_twins_recreate_title_preparing)), Message(getString(R.string.details_twins_recreate_title_creating_wallet)), @@ -135,7 +135,7 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_twin_cards_create), v_step_2.setBackgroundColor(selectedColor) v_step_3.setBackgroundColor(selectedColor) btn_tap.setOnClickListener { - store.dispatch(CreateTwinWalletAction.LaunchThirdStep( + store.dispatch(TwinCardsAction.CreateWallet.LaunchThirdStep( Message(getString( R.string.details_twins_recreate_title_format, twinCardNumberString) ) @@ -149,18 +149,18 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_twin_cards_create), btn_tap.text = getString(R.string.details_twins_recreate_button_format, cardNumber) tv_twin_title.text = getString(R.string.details_twins_recreate_title_format, cardNumber) - if (state.createTwinWalletState?.showAlert == true) { + if (state.createWalletState?.showAlert == true) { if (dialog == null) { dialog = MaterialAlertDialogBuilder(requireContext()) .setMessage(R.string.details_twins_recreate_alert) .setPositiveButton(R.string.common_ok) { _, _ -> - store.dispatch(CreateTwinWalletAction.Cancel.Confirm) + store.dispatch(TwinCardsAction.CreateWallet.Cancel.Confirm) } .setNegativeButton(R.string.common_cancel) { _, _ -> dialog?.cancel() } .setOnCancelListener { - store.dispatch(CreateTwinWalletAction.HideAlert) + store.dispatch(TwinCardsAction.CreateWallet.HideAlert) } .create() dialog?.show() diff --git a/app/src/main/java/com/tangem/tap/features/twins/ui/TwinWalletWarningFragment.kt b/app/src/main/java/com/tangem/tap/features/twins/ui/TwinWalletWarningFragment.kt index a1103c5bc7..fefff8729c 100644 --- a/app/src/main/java/com/tangem/tap/features/twins/ui/TwinWalletWarningFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/twins/ui/TwinWalletWarningFragment.kt @@ -7,8 +7,8 @@ import androidx.fragment.app.Fragment import androidx.transition.TransitionInflater import com.squareup.picasso.Picasso import com.tangem.tap.common.redux.navigation.NavigationAction -import com.tangem.tap.features.twins.redux.CreateTwinWallet -import com.tangem.tap.features.twins.redux.CreateTwinWalletAction +import com.tangem.tap.features.twins.redux.CreateTwinWalletMode +import com.tangem.tap.features.twins.redux.TwinCardsAction import com.tangem.tap.features.wallet.redux.Artwork import com.tangem.tap.store import com.tangem.wallet.R @@ -31,15 +31,15 @@ class TwinWalletWarningFragment : Fragment(R.layout.fragment_twin_cards_warning) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - val createTwinWallet = store.state.detailsState.createTwinWalletState?.createTwinWallet - if (createTwinWallet == CreateTwinWallet.CreateWallet) { + val createTwinWallet = store.state.twinCardsState.createWalletState?.mode + if (createTwinWallet == CreateTwinWalletMode.CreateWallet) { tv_twin_cards_description.text = getText(R.string.details_twins_recreate_subtitle) - } else if (createTwinWallet == CreateTwinWallet.RecreateWallet) { + } else if (createTwinWallet == CreateTwinWalletMode.RecreateWallet) { tv_twin_cards_description.text = getText(R.string.details_twins_recreate_warning) } btn_cancel.setOnClickListener { store.dispatch(NavigationAction.PopBackTo()) } - btn_start.setOnClickListener { store.dispatch(CreateTwinWalletAction.Proceed) } + btn_start.setOnClickListener { store.dispatch(TwinCardsAction.CreateWallet.Proceed) } Picasso.get() .load(Artwork.TWIN_CARD_1) .placeholder(R.drawable.card_placeholder) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt index 55e7fb4f66..ae0a273c14 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt @@ -9,7 +9,6 @@ import com.tangem.tap.common.redux.NotificationAction import com.tangem.tap.domain.TapError import com.tangem.tap.domain.configurable.warningMessage.WarningMessage import com.tangem.tap.domain.tokens.CardCurrencies -import com.tangem.tap.domain.twins.TwinCardNumber import com.tangem.wallet.R import org.rekotlin.Action import java.math.BigDecimal @@ -147,12 +146,4 @@ sealed class WalletAction : Action { data class ChangeSelectedAddress(val type: AddressType) : WalletAction() - sealed class TwinsAction : WalletAction() { - object ShowOnboarding : TwinsAction() - object SetOnboardingShown : TwinsAction() - data class SetTwinCard( - val secondCardId: String?, val number: TwinCardNumber, - val isCreatingTwinCardsAllowed: Boolean, - ) : TwinsAction() - } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt index 6c3db01f3c..aa6094f26c 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt @@ -12,39 +12,49 @@ import com.tangem.tap.common.toggleWidget.WidgetState import com.tangem.tap.domain.configurable.warningMessage.WarningMessage import com.tangem.tap.domain.extensions.toSendableAmounts import com.tangem.tap.domain.topup.TradeCryptoHelper -import com.tangem.tap.domain.twins.TwinCardNumber +import com.tangem.tap.features.twins.redux.TwinCardsState import com.tangem.tap.features.wallet.models.PendingTransaction import com.tangem.tap.features.wallet.models.toPendingTransactions import com.tangem.tap.features.wallet.models.toPendingTransactionsForToken +import com.tangem.tap.features.wallet.ui.BalanceStatus import com.tangem.tap.features.wallet.ui.BalanceWidgetData import com.tangem.tap.store import org.rekotlin.StateType import java.math.BigDecimal +import kotlin.properties.ReadOnlyProperty data class WalletState( - val state: ProgressState = ProgressState.Done, - val error: ErrorType? = null, - val cardImage: Artwork? = null, - val hashesCountVerified: Boolean? = null, - val walletDialog: StateDialog? = null, - val twinCardsState: TwinCardsState? = null, - val mainWarningsList: List = mutableListOf(), - val wallets: List = emptyList(), - val walletManagers: List = emptyList(), - val isMultiwalletAllowed: Boolean = false, - val cardCurrency: CryptoCurrencyName? = null, - val selectedWallet: Currency? = null, - val primaryBlockchain: Blockchain? = null, - val primaryToken: Token? = null, - val isTestnet: Boolean = false, - val tradeCryptoAllowed: TradeCryptoAvailability = TradeCryptoAvailability() + val state: ProgressState = ProgressState.Done, + val error: ErrorType? = null, + val cardImage: Artwork? = null, + val hashesCountVerified: Boolean? = null, + val walletDialog: StateDialog? = null, + val mainWarningsList: List = mutableListOf(), + val wallets: List = emptyList(), + val walletManagers: List = emptyList(), + val isMultiwalletAllowed: Boolean = false, + val cardCurrency: CryptoCurrencyName? = null, + val selectedWallet: Currency? = null, + val primaryBlockchain: Blockchain? = null, + val primaryToken: Token? = null, + val isTestnet: Boolean = false, + val tradeCryptoAllowed: TradeCryptoAvailability = TradeCryptoAvailability() ) : StateType { + // if you do not delegate - the application crashes on startup, + // because twinCardsState has not been created yet + val twinCardsState: TwinCardsState by ReadOnlyProperty { thisRef, property -> + store.state.twinCardsState + } + + val isTangemTwins: Boolean + get() = store.state.globalState.scanResponse?.isTangemTwins() == true + val primaryWallet = if (wallets.isNotEmpty()) wallets[0] else null val shouldShowDetails: Boolean = - primaryWallet?.currencyData?.status != com.tangem.tap.features.wallet.ui.BalanceStatus.EmptyCard && - primaryWallet?.currencyData?.status != com.tangem.tap.features.wallet.ui.BalanceStatus.UnknownBlockchain + primaryWallet?.currencyData?.status != BalanceStatus.EmptyCard && + primaryWallet?.currencyData?.status != BalanceStatus.UnknownBlockchain val blockchains: List get() = walletManagers.map { it.wallet.blockchain } @@ -57,16 +67,16 @@ data class WalletState( return walletManagers.find { it.wallet.blockchain == token.blockchain } } - fun getWalletManager(currency: Currency?) : WalletManager? { + fun getWalletManager(currency: Currency?): WalletManager? { if (currency?.blockchain == null) return null return walletManagers.find { it.wallet.blockchain == currency.blockchain } } - fun getWalletManager(blockchain: Blockchain) : WalletManager? { + fun getWalletManager(blockchain: Blockchain): WalletManager? { return walletManagers.find { it.wallet.blockchain == blockchain } } - fun getWalletData(currency: Currency?) : WalletData? { + fun getWalletData(currency: Currency?): WalletData? { if (currency == null) return null return wallets.find { it.currency == currency } } @@ -93,7 +103,7 @@ data class WalletState( ?: return true if (walletData.currency is Currency.Blockchain && - walletManager.cardTokens.isNotEmpty() + walletManager.cardTokens.isNotEmpty() ) { return false } @@ -105,9 +115,9 @@ data class WalletState( wallet.amounts.toSendableAmounts().isEmpty() } else if (walletData.currency is Currency.Token) ( return wallet.recentTransactions.toPendingTransactionsForToken( - walletData.currency.token, wallet.address).isEmpty() + walletData.currency.token, wallet.address).isEmpty() && wallet.amounts[AmountType.Token(token = walletData.currency.token)] - ?.isAboveZero() != true + ?.isAboveZero() != true ) } return false @@ -137,9 +147,9 @@ data class WalletState( } } -sealed class WalletDialog: StateDialog { +sealed class WalletDialog : StateDialog { data class QrDialog( - val qrCode: Bitmap?, val shareUrl: String?, val currencyName: CryptoCurrencyName? + val qrCode: Bitmap?, val shareUrl: String?, val currencyName: CryptoCurrencyName? ) : WalletDialog() data class SelectAmountToSendDialog(val amounts: List?) : WalletDialog() @@ -147,7 +157,7 @@ sealed class WalletDialog: StateDialog { object ChooseTradeActionDialog : WalletDialog() } -enum class ProgressState: WidgetState { Loading, Done, Error } +enum class ProgressState : WidgetState { Loading, Done, Error } enum class ErrorType { NoInternetConnection } @@ -157,22 +167,22 @@ sealed class WalletMainButton(enabled: Boolean) : Button(enabled) { } data class WalletAddresses( - val selectedAddress: AddressData, - val list: List + val selectedAddress: AddressData, + val list: List ) data class AddressData( - val address: String, - val type: AddressType, - val shareUrl: String, - val exploreUrl: String, + val address: String, + val type: AddressType, + val shareUrl: String, + val exploreUrl: String, ) { val qrCode: Bitmap by lazy { shareUrl.toQrCode() } } data class Artwork( - val artworkId: String, - val artwork: Bitmap? = null + val artworkId: String, + val artwork: Bitmap? = null ) { companion object { const val DEFAULT_IMG_URL = "https://app.tangem.com/cards/card_default.png" @@ -198,13 +208,6 @@ data class TradeCryptoAvailability( val availableToSell: Set = TradeCryptoHelper.AVAILABLE_TO_SELL, ) -data class TwinCardsState( - val secondCardId: String?, - val cardNumber: TwinCardNumber?, - val showTwinOnboarding: Boolean, - val isCreatingTwinCardsAllowed: Boolean -) - data class WalletData( val pendingTransactions: List = emptyList(), val hashesCountVerified: Boolean? = null, diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TwinsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TwinsMiddleware.kt deleted file mode 100644 index 88ba60d1d1..0000000000 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TwinsMiddleware.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.tangem.tap.features.wallet.redux.middlewares - -import com.tangem.tap.features.wallet.redux.WalletAction -import com.tangem.tap.preferencesStorage -import com.tangem.tap.store - -class TwinsMiddleware { - fun handle(action: WalletAction.TwinsAction) { - when (action) { - is WalletAction.TwinsAction.SetTwinCard -> { - val showOnboarding = !preferencesStorage.wasTwinsOnboardingShown() - if (showOnboarding) store.dispatch(WalletAction.TwinsAction.ShowOnboarding) - } - WalletAction.TwinsAction.SetOnboardingShown -> { - preferencesStorage.saveTwinsOnboardingShown() - } - } - } -} \ No newline at end of file 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 5f0ee586c7..61b4423e33 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 @@ -17,11 +17,10 @@ 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.domain.twins.TwinsHelper import com.tangem.tap.features.home.redux.HomeAction import com.tangem.tap.features.send.redux.PrepareSendScreen -import com.tangem.tap.features.twins.redux.CreateTwinWallet -import com.tangem.tap.features.twins.redux.CreateTwinWalletAction +import com.tangem.tap.features.twins.redux.CreateTwinWalletMode +import com.tangem.tap.features.twins.redux.TwinCardsAction import com.tangem.tap.features.wallet.redux.* import com.tangem.tap.network.NetworkStateChanged import kotlinx.coroutines.launch @@ -31,7 +30,6 @@ import org.rekotlin.Middleware class WalletMiddleware { private val tradeCryptoMiddleware = TradeCryptoMiddleware() - private val twinsMiddleware = TwinsMiddleware() private val warningsMiddleware = WarningsMiddleware() private val multiWalletMiddleware = MultiWalletMiddleware() @@ -50,7 +48,6 @@ class WalletMiddleware { when (action) { is WalletAction.TradeCryptoAction -> tradeCryptoMiddleware.handle(action) - is WalletAction.TwinsAction -> twinsMiddleware.handle(action) is WalletAction.Warnings -> warningsMiddleware.handle(action, globalState) is WalletAction.MultiWallet -> multiWalletMiddleware.handle(action, walletState, globalState) is WalletAction.LoadWallet -> { @@ -99,12 +96,11 @@ class WalletMiddleware { } } is WalletAction.CreateWallet -> { - if (walletState.twinCardsState != null) { - val cardId = globalState.scanResponse?.card?.cardId - val twinCardNumber = cardId?.let { TwinsHelper.getTwinCardNumber(it) } - store.dispatch( - CreateTwinWalletAction.ShowWarning(twinCardNumber, CreateTwinWallet.CreateWallet) - ) + if (walletState.isTangemTwins) { + store.dispatch(TwinCardsAction.CreateWallet.Create( + walletState.twinCardsState.cardNumber!!, + CreateTwinWalletMode.CreateWallet + )) } else { scope.launch { val result = tangemSdkManager.createWallet( diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/TwinsReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/TwinsReducer.kt deleted file mode 100644 index 79025ca6cc..0000000000 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/TwinsReducer.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.tangem.tap.features.wallet.redux.reducers - -import com.tangem.tap.features.wallet.redux.TwinCardsState -import com.tangem.tap.features.wallet.redux.WalletAction -import com.tangem.tap.features.wallet.redux.WalletState - -class TwinsReducer { - fun reduce(action: WalletAction.TwinsAction, state: WalletState): WalletState { - return when (action) { - is WalletAction.TwinsAction.SetTwinCard -> { - state.copy( - twinCardsState = TwinCardsState( - secondCardId = action.secondCardId, - cardNumber = action.number, - showTwinOnboarding = state.twinCardsState?.showTwinOnboarding - ?: false, - isCreatingTwinCardsAllowed = action.isCreatingTwinCardsAllowed - ) - ) - } - is WalletAction.TwinsAction.ShowOnboarding -> { - state.copy( - twinCardsState = state.twinCardsState?.copy(showTwinOnboarding = true) - ?: TwinCardsState(null, null, - showTwinOnboarding = true, - isCreatingTwinCardsAllowed = false) - ) - } - is WalletAction.TwinsAction.SetOnboardingShown -> { - state.copy( - twinCardsState = state.twinCardsState?.copy(showTwinOnboarding = false) - ) - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt index d999216bba..8e0e9df126 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt @@ -25,7 +25,6 @@ class WalletReducer { private fun internalReduce(action: Action, state: AppState): WalletState { val multiWalletReducer = MultiWalletReducer() - val twinsReducer = TwinsReducer() val onWalletLoadedReducer = OnWalletLoadedReducer() if (action !is WalletAction) return state.walletState @@ -34,15 +33,12 @@ private fun internalReduce(action: Action, state: AppState): WalletState { when (action) { is WalletAction.Warnings -> newState = handleCheckSignedHashesActions(action, newState) - is WalletAction.TwinsAction -> newState = twinsReducer.reduce(action, newState) is WalletAction.MultiWallet -> newState = multiWalletReducer.reduce(action, newState) is WalletAction.ResetState -> newState = WalletState() is WalletAction.SetIfTestnetCard -> newState = newState.copy(isTestnet = action.isTestnet) is WalletAction.EmptyWallet -> { - val creatingWalletAllowed = !(newState.twinCardsState != null && - newState.twinCardsState?.isCreatingTwinCardsAllowed != true) - + val creatingWalletAllowed = state.twinCardsState.isCreatingTwinCardsAllowed newState = newState.copy( state = ProgressState.Done, wallets = listOf( @@ -215,7 +211,7 @@ private fun internalReduce(action: Action, state: AppState): WalletState { newState = setNewFiatRate(action.fiatRate, state.globalState.appCurrency, newState) is WalletAction.LoadArtwork -> { val artworkUrl = action.card.getArtworkUrl(action.artworkId) - ?: when (newState.twinCardsState?.cardNumber) { + ?: when (state.twinCardsState.cardNumber) { TwinCardNumber.First -> Artwork.TWIN_CARD_1 TwinCardNumber.Second -> Artwork.TWIN_CARD_2 else -> Artwork.DEFAULT_IMG_URL diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index e8f2a250fd..fd65f1b619 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -135,8 +135,8 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber store.dispatch(DetailsAction.PrepareScreen( - scanNoteResponse.card, scanNoteResponse, - store.state.walletState.walletManagers.map { it.wallet }, - store.state.globalState.configManager?.config?.isCreatingTwinCardsAllowed, - CardTou(), - store.state.globalState.appCurrency + scanNoteResponse, + store.state.walletState.walletManagers.map { it.wallet }, + CardTou(), + store.state.globalState.appCurrency )) store.dispatch(NavigationAction.NavigateTo(AppScreen.Details)) true diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt index d2e4e77cc5..3c760f3e6e 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt @@ -10,6 +10,7 @@ import com.tangem.tap.common.redux.StateDialog import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.twins.TwinCardNumber +import com.tangem.tap.features.twins.redux.TwinCardsState import com.tangem.tap.features.wallet.models.PendingTransaction import com.tangem.tap.features.wallet.redux.* import com.tangem.tap.features.wallet.ui.BalanceWidget @@ -71,7 +72,7 @@ class SingleWalletView : WalletView { state.primaryWallet ?: return setupTwinCards(state.twinCardsState, fragment) - setupButtons(state.primaryWallet, state.twinCardsState != null, fragment) + setupButtons(state.primaryWallet, state.isTangemTwins, fragment) setupAddressCard(state.primaryWallet, fragment) showPendingTransactionsIfPresent(state.primaryWallet.pendingTransactions) setupBalance(state, state.primaryWallet) @@ -87,7 +88,7 @@ class SingleWalletView : WalletView { private fun setupBalance(state: WalletState, primaryWallet: WalletData) { fragment?.apply { this.l_balance.show() - BalanceWidget(this, primaryWallet.currencyData, state.twinCardsState != null).setup() + BalanceWidget(this, primaryWallet.currencyData, state.isTangemTwins).setup() } } From 913402bb7e219d80ea9b89ef14ded09727eca137 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 22 Oct 2021 03:14:09 +0300 Subject: [PATCH 05/18] Updated on 2026-08-14 --- .../common/redux/global/GlobalMidlleware.kt | 6 ++-- .../com/tangem/tap/domain/TangemSdkManager.kt | 21 ++++++------ .../com/tangem/tap/domain/TapWalletManager.kt | 5 ++- .../domain/extensions/WalletManagerFactory.kt | 3 +- .../tangem/tap/domain/tasks/ScanNoteTask.kt | 18 +++++------ .../domain/tasks/product/ScanProductTask.kt | 13 +++----- .../features/details/ui/DetailsFragment.kt | 9 +++--- .../redux/middlewares/WarningsMiddleware.kt | 32 ++++++++++--------- 8 files changed, 50 insertions(+), 57 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt index ea80ab463c..10aa0f1533 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt @@ -47,7 +47,7 @@ private val globalMiddlewareHandler: Middleware = { dispatch, appState } is GlobalAction.RestoreAppCurrency -> { store.dispatch(GlobalAction.RestoreAppCurrency.Success( - preferencesStorage.getAppCurrency() + preferencesStorage.getAppCurrency() )) } is GlobalAction.HideWarningMessage -> { @@ -81,7 +81,7 @@ private val globalMiddlewareHandler: Middleware = { dispatch, appState val userStatusResponse = MoonpayService().getUserStatus(apiKey) if (userStatusResponse is Result.Success) { store.dispatchOnMain( - GlobalAction.GetMoonPayUserStatus.Success(userStatusResponse.data) + GlobalAction.GetMoonPayUserStatus.Success(userStatusResponse.data) ) } } @@ -94,7 +94,7 @@ private val globalMiddlewareHandler: Middleware = { dispatch, appState withMainContext { when (result) { is CompletionResult.Success -> { - tangemSdkManager.changeDisplayedCardIdNumbersCount(result.data.card) + tangemSdkManager.changeDisplayedCardIdNumbersCount(result.data) action.onSuccess?.invoke(result.data) } is CompletionResult.Failure -> action.onFailure?.invoke(result.error) diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt index 5253a9f91c..3a3acc1a87 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -23,7 +23,6 @@ import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler import com.tangem.tap.domain.tasks.CreateWalletAndRescanTask import com.tangem.tap.domain.tasks.product.ScanProductTask import com.tangem.tap.domain.tasks.product.ScanResponse -import com.tangem.tap.domain.twins.isTangemTwin import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -45,9 +44,9 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co suspend fun createProductWallet(scanResponse: ScanResponse): CompletionResult { return runTaskAsync( - CreateProductWalletAndRescanTask(scanResponse.productType), - scanResponse.card.cardId, - Message(context.getString(R.string.initial_message_create_wallet_body)) + CreateProductWalletAndRescanTask(scanResponse.productType), + scanResponse.card.cardId, + Message(context.getString(R.string.initial_message_create_wallet_body)) ) } @@ -105,13 +104,13 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co suspend fun runTaskAsync( runnable: CardSessionRunnable, cardId: String? = null, initialMessage: Message? = null, ): CompletionResult = - withContext(Dispatchers.Main) { - suspendCoroutine { continuation -> - tangemSdk.startSessionWithRunnable(runnable, cardId, initialMessage) { result -> - continuation.resume(result) + withContext(Dispatchers.Main) { + suspendCoroutine { continuation -> + tangemSdk.startSessionWithRunnable(runnable, cardId, initialMessage) { result -> + continuation.resume(result) + } } } - } private suspend fun runTaskAsyncReturnOnMain( runnable: CardSessionRunnable, cardId: String? = null, initialMessage: Message? = null, @@ -120,8 +119,8 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co return withContext(Dispatchers.Main) { result } } - fun changeDisplayedCardIdNumbersCount(card: Card) { - tangemSdk.config.cardIdDisplayedNumbersCount = if (card.isTangemTwin()) 4 else null + fun changeDisplayedCardIdNumbersCount(scanResponse: ScanResponse) { + tangemSdk.config.cardIdDisplayedNumbersCount = if (scanResponse.isTangemTwins()) 4 else null } companion object { 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 edc4601d8c..75e8333a1c 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -17,7 +17,6 @@ import com.tangem.tap.domain.extensions.* import com.tangem.tap.domain.tasks.product.ScanResponse import com.tangem.tap.domain.tokens.CardCurrencies import com.tangem.tap.domain.twins.getTwinCardNumber -import com.tangem.tap.domain.twins.isTangemTwin import com.tangem.tap.features.tokens.redux.TokensAction import com.tangem.tap.features.twins.redux.TwinCardsAction import com.tangem.tap.features.wallet.redux.Currency @@ -91,7 +90,7 @@ class TapWalletManager { store.dispatch(GlobalAction.SaveScanNoteResponse(data)) store.dispatch(WalletAction.SetIfTestnetCard(data.card.isTestCard)) store.dispatch(WalletAction.MultiWallet.SetIsMultiwalletAllowed(data.card.isMultiwalletAllowed)) - if (data.card.isTangemTwin()) { + if (data.isTangemTwins()) { data.card.getTwinCardNumber()?.let { val isCreatingTwinsAllowed = configManager?.config?.isCreatingTwinCardsAllowed ?: false store.dispatch(TwinCardsAction.SetTwinCard(it, null, isCreatingTwinsAllowed)) @@ -233,7 +232,7 @@ class TapWalletManager { private fun getActionIfUnknownBlockchainOrEmptyWallet(data: ScanResponse): WalletAction? { return when { // check order is important - data.card.isTangemTwin() && !data.twinsIsTwinned() -> { + data.isTangemTwins() && !data.twinsIsTwinned() -> { WalletAction.EmptyWallet } data.getBlockchain() == Blockchain.Unknown && !data.card.isMultiwalletAllowed -> { diff --git a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt index 99ed8231c4..aa85331ab2 100644 --- a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt +++ b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt @@ -9,7 +9,6 @@ import com.tangem.common.card.EllipticCurve import com.tangem.common.extensions.hexToBytes import com.tangem.tap.domain.TapWorkarounds.isTestCard import com.tangem.tap.domain.tasks.product.ScanResponse -import com.tangem.tap.domain.twins.isTangemTwin fun WalletManagerFactory.makeWalletManagerForApp( card: Card, @@ -65,7 +64,7 @@ fun WalletManagerFactory.makePrimaryWalletManager( val publicKey = wallet?.publicKey ?: return null val curveToUse = wallet.curve - return if (card.isTangemTwin() && data.secondTwinPublicKey != null) { + return if (data.isTangemTwins() && data.secondTwinPublicKey != null) { makeMultisigWalletManager( cardId = card.cardId, walletPublicKey = publicKey, pairPublicKey = data.secondTwinPublicKey.hexToBytes(), diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt index 8b3c26a91e..22a7e5ca87 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt @@ -17,8 +17,8 @@ import com.tangem.tap.domain.TapWorkarounds.isTangemNote import com.tangem.tap.domain.extensions.getSingleWallet import com.tangem.tap.domain.tasks.product.ScanResponse import com.tangem.tap.domain.twins.TwinsHelper -import com.tangem.tap.domain.twins.isTangemTwin +@Deprecated("Use ScanProductTask instead") class ScanNoteTask(val card: Card? = null) : CardSessionRunnable { override fun run( @@ -38,13 +38,13 @@ class ScanNoteTask(val card: Card? = null) : CardSessionRunnable { return@run } - if (card.isTangemTwin()) { + if (TwinsHelper.getTwinCardNumber(card.cardId) != null) { dealWithTwinCard(card, session, callback) } else if (!isTangemNote(card) && card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable) { createMissingWalletsIfNeeded(card, session, callback) } else { callback(CompletionResult.Success( - ScanResponse(card, ProductType.Other, session.environment.walletData))) + ScanResponse(card, ProductType.Other, session.environment.walletData))) } } } @@ -93,16 +93,16 @@ class ScanNoteTask(val card: Card? = null) : CardSessionRunnable { return@run } val verified = TwinsHelper.verifyTwinPublicKey( - readDataResult.data.issuerData, publicKey + readDataResult.data.issuerData, publicKey ) if (verified) { val twinPublicKey = readDataResult.data.issuerData.sliceArray(0 until 65) callback(CompletionResult.Success( - ScanResponse( - card = card, - ProductType.Other, - walletData = session.environment.walletData, - secondTwinPublicKey = twinPublicKey.toHexString()) + ScanResponse( + card = card, + ProductType.Other, + walletData = session.environment.walletData, + secondTwinPublicKey = twinPublicKey.toHexString()) )) return@run } else { diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt index 3818c4b211..fa6a74564b 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt @@ -24,7 +24,6 @@ import com.tangem.tap.domain.TapWorkarounds.getTangemNoteBlockchain import com.tangem.tap.domain.TapWorkarounds.isExcluded import com.tangem.tap.domain.extensions.getSingleWallet import com.tangem.tap.domain.twins.TwinsHelper -import com.tangem.tap.domain.twins.isTangemTwin data class ScanResponse( val card: Card, @@ -55,13 +54,7 @@ data class ScanResponse( fun isTangemTwins(): Boolean = productType == ProductType.Twins fun isTangemOtherCards(): Boolean = productType == ProductType.Other - fun twinsIsTwinned(): Boolean { - return card.isTangemTwin() && walletData != null && secondTwinPublicKey != null - } -} - -private fun Card.isTangemTwin(): Boolean { - return TwinsHelper.getTwinCardNumber(cardId) != null + fun twinsIsTwinned(): Boolean = card.isTangemTwins() && walletData != null && secondTwinPublicKey != null } class ScanProductTask(val card: Card? = null) : CardSessionRunnable { @@ -83,7 +76,7 @@ class ScanProductTask(val card: Card? = null) : CardSessionRunnable ScanNoteProcessor() - TwinsHelper.getTwinCardNumber(card.cardId) != null -> ScanTwinProcessor() + card.isTangemTwins() -> ScanTwinProcessor() TapWorkarounds.isTangemWallet(card) -> ScanWalletProcessor() else -> ScanOtherCardsProcessor() } @@ -101,6 +94,8 @@ class ScanProductTask(val card: Card? = null) : CardSessionRunnable { override fun proceed( card: Card, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt index 81b6e91032..efa81149b7 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt @@ -12,7 +12,6 @@ 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.twins.getTwinCardIdForUser -import com.tangem.tap.domain.twins.isTangemTwin import com.tangem.tap.features.details.redux.DetailsAction import com.tangem.tap.features.details.redux.DetailsState import com.tangem.tap.features.details.redux.SecurityOption @@ -69,8 +68,8 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber { if (action.remainingSignatures != null && - action.remainingSignatures <= WarningMessagesManager.REMAINING_SIGNATURES_WARNING + action.remainingSignatures <= WarningMessagesManager.REMAINING_SIGNATURES_WARNING ) { store.state.globalState.warningManager - ?.removeWarnings( - messageRes = R.string.warning_low_signatures_format - ) + ?.removeWarnings( + messageRes = R.string.warning_low_signatures_format + ) addWarningMessage( warning = WarningMessagesManager.remainingSignaturesNotEnough(action.remainingSignatures), @@ -81,7 +81,8 @@ class WarningsMiddleware { } private fun showCardWarningsIfNeeded(globalState: GlobalState?) { - globalState?.scanResponse?.card?.let { card -> + globalState?.scanResponse?.let { scanResponse -> + val card = scanResponse.card globalState.warningManager?.removeWarnings(WarningMessage.Origin.Local) if (card.isTestCard) { addWarningMessage(WarningMessagesManager.testCardWarning(), autoUpdate = true) @@ -92,7 +93,7 @@ class WarningsMiddleware { if (card.firmwareVersion.type != FirmwareVersion.FirmwareType.Release) { addWarningMessage(WarningMessagesManager.devCardWarning()) } else if (!preferencesStorage.usedCardsPrefStorage.wasScanned(card.cardId)) { - checkIfWarningNeeded(card)?.let { warning -> addWarningMessage(warning) } + checkIfWarningNeeded(scanResponse)?.let { warning -> addWarningMessage(warning) } } if (card.firmwareVersion.type == FirmwareVersion.FirmwareType.Release) { if (!globalState.cardVerifiedOnline) { @@ -106,7 +107,7 @@ class WarningsMiddleware { private fun showWarningLowRemainingSignaturesIfNeeded(card: Card) { val remainingSignatures = card.remainingSignatures if (remainingSignatures != null && - remainingSignatures <= WarningMessagesManager.REMAINING_SIGNATURES_WARNING + remainingSignatures <= WarningMessagesManager.REMAINING_SIGNATURES_WARNING ) { addWarningMessage( WarningMessagesManager.remainingSignaturesNotEnough( @@ -117,12 +118,12 @@ class WarningsMiddleware { } private fun checkIfWarningNeeded( - card: Card, + scanResponse: ScanResponse, ): WarningMessage? { - if (card.isTangemTwin()) return null + if (scanResponse.isTangemTwins()) return null - if (card.isMultiwalletAllowed) { - return if (card.hasSignedHashes()) { + if (scanResponse.card.isMultiwalletAllowed) { + return if (scanResponse.card.hasSignedHashes()) { WarningMessagesManager.signedHashesMultiWalletWarning() } else { store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId) @@ -133,7 +134,7 @@ class WarningsMiddleware { val validator = store.state.walletState.walletManagers.firstOrNull() as? SignatureCountValidator return if (validator == null) { - if (card.hasSignedHashes()) { + if (scanResponse.card.hasSignedHashes()) { WarningMessagesManager.alreadySignedHashesWarning() } else { store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId) @@ -149,10 +150,11 @@ class WarningsMiddleware { if (store.state.walletState.hashesCountVerified != false) return if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) return - val card = store.state.globalState.scanResponse?.card + val scanResponse = store.state.globalState.scanResponse + val card = scanResponse?.card if (card == null || preferencesStorage.usedCardsPrefStorage.wasScanned(card.cardId)) return - if (card.isTangemTwin() || card.isMultiwalletAllowed) return + if (scanResponse.isTangemTwins() || card.isMultiwalletAllowed) return val validator = store.state.walletState.walletManagers.firstOrNull() as? SignatureCountValidator From f34aeba4ed019903270ee9be586de4e9fcf6c0f2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 22 Oct 2021 05:54:34 +0300 Subject: [PATCH 06/18] Updated on 2026-08-14 --- .../com/tangem/tap/common/DialogManager.kt | 21 ++-- .../com/tangem/tap/domain/TapWalletManager.kt | 14 +-- .../tap/domain/twins/TwinCardsManager.kt | 22 ++-- ...{TwinsCardWidget.kt => TwinCardsWidget.kt} | 0 .../features/details/ui/DetailsFragment.kt | 2 +- .../tap/features/home/redux/HomeMiddleware.kt | 10 ++ .../products/note/OnboardingNoteFragment.kt | 13 ++- .../note/redux/OnboardingNoteAction.kt | 2 +- .../note/redux/OnboardingNoteState.kt | 16 +-- .../features/twins/redux/TwinCardsAction.kt | 56 +++++----- .../twins/redux/TwinCardsMiddleware.kt | 104 +++++++++--------- .../features/twins/redux/TwinCardsReducer.kt | 47 ++++---- .../features/twins/redux/TwinCardsState.kt | 21 +++- .../twins/ui/CreateTwinWalletFragment.kt | 62 +++++------ .../twins/ui/TwinWalletWarningFragment.kt | 2 +- .../ui/dialog/CreateWalletInterruptDialog.kt | 25 +++++ .../wallet/models/PendingTransaction.kt | 2 +- .../redux/middlewares/WalletMiddleware.kt | 2 +- 18 files changed, 222 insertions(+), 199 deletions(-) rename app/src/main/java/com/tangem/tap/domain/twins/{TwinsCardWidget.kt => TwinCardsWidget.kt} (100%) create mode 100644 app/src/main/java/com/tangem/tap/features/twins/ui/dialog/CreateWalletInterruptDialog.kt 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 114c17c7cd..a604cbd643 100644 --- a/app/src/main/java/com/tangem/tap/common/DialogManager.kt +++ b/app/src/main/java/com/tangem/tap/common/DialogManager.kt @@ -7,6 +7,8 @@ import com.tangem.tap.common.redux.global.GlobalState import com.tangem.tap.features.details.redux.walletconnect.WalletConnectDialog import com.tangem.tap.features.details.ui.walletconnect.dialogs.* import com.tangem.tap.features.onboarding.AddressInfoBottomSheetDialog +import com.tangem.tap.features.twins.redux.TwinCardsAction +import com.tangem.tap.features.twins.ui.dialog.CreateWalletInterruptDialog import com.tangem.tap.features.wallet.ui.dialogs.ScanFailsDialog import com.tangem.tap.store import com.tangem.wallet.R @@ -43,24 +45,25 @@ class DialogManager : StoreSubscriber { dialog = when (state.dialog) { is AppDialog.ScanFailsDialog -> ScanFailsDialog.create(context) is AppDialog.AddressInfoDialog -> AddressInfoBottomSheetDialog(state.dialog, context) + is TwinCardsAction.Wallet.InterruptDialog -> CreateWalletInterruptDialog.create(state.dialog, context) is WalletConnectDialog.UnsupportedCard -> SimpleAlertDialog.create( - titleRes = R.string.wallet_connect, - messageRes = R.string.wallet_connect_scanner_error_no_ethereum_wallet, - context = context + titleRes = R.string.wallet_connect, + messageRes = R.string.wallet_connect_scanner_error_no_ethereum_wallet, + context = context ) is WalletConnectDialog.OpeningSessionRejected -> { SimpleAlertDialog.create( - titleRes = R.string.wallet_connect, - messageRes = R.string.wallet_connect_same_wcuri, - context = context + titleRes = R.string.wallet_connect, + messageRes = R.string.wallet_connect_same_wcuri, + context = context ) } is WalletConnectDialog.SessionTimeout -> { SimpleAlertDialog.create( - titleRes = R.string.wallet_connect, - messageRes = R.string.wallet_connect_error_timeout, - context = context + titleRes = R.string.wallet_connect, + messageRes = R.string.wallet_connect_error_timeout, + context = context ) } is WalletConnectDialog.ApproveWcSession -> 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 75e8333a1c..14f7b50b6b 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -16,9 +16,7 @@ import com.tangem.tap.domain.configurable.config.ConfigManager import com.tangem.tap.domain.extensions.* import com.tangem.tap.domain.tasks.product.ScanResponse import com.tangem.tap.domain.tokens.CardCurrencies -import com.tangem.tap.domain.twins.getTwinCardNumber import com.tangem.tap.features.tokens.redux.TokensAction -import com.tangem.tap.features.twins.redux.TwinCardsAction import com.tangem.tap.features.wallet.redux.Currency import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.network.NetworkConnectivity @@ -82,20 +80,13 @@ class TapWalletManager { FirebaseAnalyticsHandler.triggerEvent(AnalyticsEvent.CARD_IS_SCANNED, data.card, data.walletData?.blockchain) } store.state.globalState.feedbackManager?.infoHolder?.setCardInfo(data.card) - val configManager = store.state.globalState.configManager - updateConfigManager(configManager, data) + updateConfigManager(data) withContext(Dispatchers.Main) { store.dispatch(WalletAction.ResetState) store.dispatch(GlobalAction.SaveScanNoteResponse(data)) store.dispatch(WalletAction.SetIfTestnetCard(data.card.isTestCard)) store.dispatch(WalletAction.MultiWallet.SetIsMultiwalletAllowed(data.card.isMultiwalletAllowed)) - if (data.isTangemTwins()) { - data.card.getTwinCardNumber()?.let { - val isCreatingTwinsAllowed = configManager?.config?.isCreatingTwinCardsAllowed ?: false - store.dispatch(TwinCardsAction.SetTwinCard(it, null, isCreatingTwinsAllowed)) - } - } val blockchain = data.getBlockchain() if (blockchain == Blockchain.Ethereum || @@ -106,7 +97,8 @@ class TapWalletManager { } } - private fun updateConfigManager(configManager: ConfigManager?, data: ScanResponse) { + private fun updateConfigManager(data: ScanResponse) { + val configManager = store.state.globalState.configManager val blockchain = data.getBlockchain() if (data.card.isStart2Coin) { configManager?.turnOff(ConfigManager.isSendingToPayIdEnabled) diff --git a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt index df48e76971..39c203e744 100644 --- a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt @@ -1,6 +1,5 @@ package com.tangem.tap.domain.twins -import android.content.Context import com.squareup.moshi.JsonAdapter import com.squareup.moshi.Types import com.tangem.Message @@ -12,24 +11,21 @@ import com.tangem.common.core.TangemSdkError import com.tangem.common.extensions.hexToBytes import com.tangem.common.extensions.toHexString import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler -import com.tangem.tap.common.extensions.readAssetAsString import com.tangem.tap.domain.tasks.product.ScanResponse import com.tangem.tap.network.createMoshi import com.tangem.tap.tangemSdkManager -class TwinCardsManager(private val scanResponse: ScanResponse, context: Context) { +class TwinCardsManager(private val scanResponse: ScanResponse, assetReader: AssetReader) { private val currentCardId: String = scanResponse.card.cardId - // private val secondCardId: String? = TwinsHelper.getTwinsCardId(currentCardId) + // private val secondCardId: Strings? = TwinsHelper.getTwinsCardId(currentCardId) private val secondCardId: String? = null private var currentCardPublicKey: String? = null private var secondCardPublicKey: String? = null - private val issuerKeyPair: KeyPair = getIssuerKeys( - context, scanResponse.card.issuer.publicKey.toHexString() - ) + private val issuerKeyPair: KeyPair = getIssuerKeys(assetReader, scanResponse.card.issuer.publicKey.toHexString()) suspend fun createFirstWallet(message: Message): SimpleResult { val response = tangemSdkManager.runTaskAsync( @@ -108,8 +104,8 @@ class TwinCardsManager(private val scanResponse: ScanResponse, context: Context) } companion object { - private fun getIssuerKeys(context: Context, publicKey: String): KeyPair { - val issuer = getIssuers(context).first { it.publicKey == publicKey } + private fun getIssuerKeys(reader: AssetReader, publicKey: String): KeyPair { + val issuer = getIssuers(reader).first { it.publicKey == publicKey } return KeyPair( publicKey = issuer.publicKey.hexToBytes(), privateKey = issuer.privateKey.hexToBytes() @@ -122,13 +118,17 @@ class TwinCardsManager(private val scanResponse: ScanResponse, context: Context) ) } - private fun getIssuers(context: Context): List { - val file = context.readAssetAsString("tangem-app-config/issuers") + private fun getIssuers(reader: AssetReader): List { + val file = reader.readAssetAsString("tangem-app-config/issuers") return getAdapter().fromJson(file)!! } } } +interface AssetReader { + fun readAssetAsString(name: String): String +} + private class Issuer( val id: String, val privateKey: String, diff --git a/app/src/main/java/com/tangem/tap/domain/twins/TwinsCardWidget.kt b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsWidget.kt similarity index 100% rename from app/src/main/java/com/tangem/tap/domain/twins/TwinsCardWidget.kt rename to app/src/main/java/com/tangem/tap/domain/twins/TwinCardsWidget.kt diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt index efa81149b7..31d11dbc31 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt @@ -95,7 +95,7 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber + if (scanResponse.isTangemTwins()) { + scanResponse.card.getTwinCardNumber()?.let { + val configManager = store.state.globalState.configManager + val isCreatingTwinsAllowed = configManager?.config?.isCreatingTwinCardsAllowed ?: false + store.dispatch(TwinCardsAction.SetTwinCard(it, null, isCreatingTwinsAllowed)) + } + } + if (OnboardingHelper.isOnboardingCase(scanResponse)) { val navigateTo = OnboardingHelper.whereToNavigate(scanResponse) store.dispatch(GlobalAction.Onboarding.Start(scanResponse)) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt index 6bf7ca96bf..173662c65e 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt @@ -19,7 +19,10 @@ import com.tangem.tap.common.postUi import com.tangem.tap.common.toggleWidget.RefreshBalanceWidget import com.tangem.tap.common.transitions.InternalNoteLayoutTransition import com.tangem.tap.features.onboarding.products.BaseOnboardingFragment -import com.tangem.tap.features.onboarding.products.note.redux.* +import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteAction +import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteResources +import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteState +import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteStep import com.tangem.tap.store import com.tangem.wallet.R import kotlinx.android.synthetic.main.fragment_onboarding_main.* @@ -43,14 +46,14 @@ class OnboardingNoteFragment : BaseOnboardingFragment() { toolbar.setTitle(R.string.onboarding_title) btnRefreshBalanceWidget = RefreshBalanceWidget(onboarding_main_container) - val resources = AndroidResources( - OnboardingStringResources( + + val resources = OnboardingNoteResources( + OnboardingNoteResources.Strings( R.string.copy_toast_msg ) ) - - store.dispatch(OnboardingNoteAction.LoadCardArtwork) store.dispatch(OnboardingNoteAction.SetResources(resources)) + store.dispatch(OnboardingNoteAction.LoadCardArtwork) store.dispatch(OnboardingNoteAction.DetermineStepOfScreen) } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt index 798f8f4136..1948bfe98c 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt @@ -10,7 +10,7 @@ import org.rekotlin.Action */ sealed class OnboardingNoteAction : Action { // from user, ui - data class SetResources(val resources: AndroidResources) : OnboardingNoteAction() + data class SetResources(val resources: OnboardingNoteResources) : OnboardingNoteAction() object LoadCardArtwork : OnboardingNoteAction() object CreateWallet : OnboardingNoteAction() object TopUp : OnboardingNoteAction() diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteState.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteState.kt index d4f1c2bcb7..33c5cbdd7d 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteState.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteState.kt @@ -10,7 +10,7 @@ import org.rekotlin.StateType */ data class OnboardingNoteState( val walletManager: WalletManager? = null, - val resources: AndroidResources = AndroidResources(), + val resources: OnboardingNoteResources = OnboardingNoteResources(), // UI val cardArtwork: Artwork? = null, val walletBalance: OnboardingWalletBalance = OnboardingWalletBalance.loading(), @@ -27,10 +27,10 @@ enum class OnboardingNoteStep { None, CreateWallet, TopUpWallet, Done } -data class AndroidResources( - val strings: OnboardingStringResources = OnboardingStringResources() -) - -data class OnboardingStringResources( - val addressWasCopied: Int = -1 -) \ No newline at end of file +data class OnboardingNoteResources( + val strings: Strings = Strings() +) { + data class Strings( + val addressWasCopied: Int = -1 + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsAction.kt b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsAction.kt index cf7d2433dd..383481a905 100644 --- a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsAction.kt +++ b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsAction.kt @@ -1,62 +1,62 @@ package com.tangem.tap.features.twins.redux -import android.content.Context import com.tangem.Message -import com.tangem.tap.common.redux.NotificationAction +import com.tangem.tap.common.redux.StateDialog import com.tangem.tap.domain.tasks.product.ScanResponse +import com.tangem.tap.domain.twins.AssetReader import com.tangem.tap.domain.twins.TwinCardNumber -import com.tangem.wallet.R +import com.tangem.tap.domain.twins.TwinCardsManager import org.rekotlin.Action /** [REDACTED_AUTHOR] */ sealed class TwinCardsAction : Action { - object ShowOnboarding : TwinCardsAction() - object SetOnboardingShown : TwinCardsAction() + + data class SetResources(val resources: TwinCardsResources) : TwinCardsAction() + data class SetTwinCard( val number: TwinCardNumber, val secondCardId: String?, val isCreatingTwinCardsAllowed: Boolean, ) : TwinCardsAction() - sealed class CreateWallet : TwinCardsAction() { + sealed class CardsManager { + data class Set(val manager: TwinCardsManager) : TwinCardsAction() + object Release : TwinCardsAction() + } + + object ShowOnboarding : TwinCardsAction() + object SetOnboardingShown : TwinCardsAction() + object ProceedToCreateWallet : TwinCardsAction() + + sealed class Wallet : TwinCardsAction() { + object HandleOnBackPressed : TwinCardsAction() + data class Create( val number: TwinCardNumber, val createTwinWalletMode: CreateTwinWalletMode - ) : CreateWallet() + ) : TwinCardsAction() - object NotEmpty : CreateWallet(), NotificationAction { - override val messageResource = R.string.details_notification_erase_wallet_not_possible - } - - object ShowAlert : CreateWallet() - object HideAlert : CreateWallet() - object Proceed : CreateWallet() - - object Cancel : CreateWallet() { - object Confirm : CreateWallet() - } + data class InterruptDialog(val interrupt: () -> Unit) : TwinCardsAction(), StateDialog data class LaunchFirstStep( - val message: Message, val context: Context - ) : CreateWallet() { - object Success : CreateWallet() - object Failure : CreateWallet() + val initialMessage: Message, + val reader: AssetReader + ) : TwinCardsAction() { + object Success : TwinCardsAction() } data class LaunchSecondStep( val initialMessage: Message, val preparingMessage: Message, val creatingWalletMessage: Message, - ) : CreateWallet() { - object Success : CreateWallet() - object Failure : CreateWallet() + ) : TwinCardsAction() { + object Success : TwinCardsAction() } - data class LaunchThirdStep(val message: Message) : CreateWallet() { - data class Success(val scanResponse: ScanResponse) : CreateWallet() - object Failure : CreateWallet() + data class LaunchThirdStep(val message: Message) : TwinCardsAction() { + data class Success(val scanResponse: ScanResponse) : TwinCardsAction() } } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsMiddleware.kt index 673e0616d5..84c837d778 100644 --- a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsMiddleware.kt @@ -2,6 +2,8 @@ package com.tangem.tap.features.twins.redux import com.tangem.blockchain.extensions.Result import com.tangem.blockchain.extensions.SimpleResult +import com.tangem.tap.common.extensions.dispatchDialogShow +import com.tangem.tap.common.extensions.dispatchNotification import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction @@ -32,12 +34,11 @@ private val twinsWalletMiddleware: Middleware = { dispatch, state -> } } -private var twinsManager: TwinCardsManager? = null - private fun handle(action: Action, dispatch: DispatchFunction) { val action = action as? TwinCardsAction ?: return val twinCardsState = store.state.twinCardsState + when (action) { is TwinCardsAction.SetTwinCard -> { val showOnboarding = !preferencesStorage.wasTwinsOnboardingShown() @@ -46,7 +47,22 @@ private fun handle(action: Action, dispatch: DispatchFunction) { TwinCardsAction.SetOnboardingShown -> { preferencesStorage.saveTwinsOnboardingShown() } - is TwinCardsAction.CreateWallet.Create -> { + is TwinCardsAction.ProceedToCreateWallet -> { + store.dispatch(NavigationAction.NavigateTo(AppScreen.CreateTwinWallet)) + } + is TwinCardsAction.Wallet.HandleOnBackPressed -> { + if (twinCardsState.createWalletState?.showAlert == true) { + val stateDialog = TwinCardsAction.Wallet.InterruptDialog { + store.dispatch(TwinCardsAction.CardsManager.Release) + store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) + } + store.dispatchDialogShow(stateDialog) + } else { + store.dispatch(TwinCardsAction.CardsManager.Release) + store.dispatch(NavigationAction.PopBackTo()) + } + } + is TwinCardsAction.Wallet.Create -> { val wallet = store.state.walletState.walletManagers.map { it.wallet }.firstOrNull() if (wallet == null) { store.dispatch(NavigationAction.NavigateTo(AppScreen.CreateTwinWalletWarning)) @@ -54,90 +70,70 @@ private fun handle(action: Action, dispatch: DispatchFunction) { } val notEmpty = wallet.recentTransactions.isNotEmpty() || wallet.amounts.toSendableAmounts().isNotEmpty() if (notEmpty) { - store.dispatch(TwinCardsAction.CreateWallet.NotEmpty) + store.dispatchNotification(twinCardsState.resources.strings.walletIsNotEmpty) } else { store.dispatch(NavigationAction.NavigateTo(AppScreen.CreateTwinWalletWarning)) } } - is TwinCardsAction.CreateWallet.Proceed -> { - store.dispatch(NavigationAction.NavigateTo(AppScreen.CreateTwinWallet)) - } - is TwinCardsAction.CreateWallet.Cancel -> { - val step = twinCardsState.createWalletState?.step - if (step != null && step != CreateTwinWalletStep.FirstStep) { - store.dispatch(TwinCardsAction.CreateWallet.ShowAlert) - } else { - twinsManager = null - store.dispatch(NavigationAction.PopBackTo()) - } - } - is TwinCardsAction.CreateWallet.Cancel.Confirm -> { - twinsManager = null - store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) - } - is TwinCardsAction.CreateWallet.LaunchFirstStep -> { - store.state.globalState.scanResponse?.let { - twinsManager = TwinCardsManager(it, action.context) - } + is TwinCardsAction.Wallet.LaunchFirstStep -> { + val scanResponse = store.state.globalState.scanResponse ?: return + + val manager = TwinCardsManager(scanResponse, action.reader) + store.dispatch(TwinCardsAction.CardsManager.Set(manager)) + scope.launch { - val result = twinsManager?.createFirstWallet(action.message) + val result = manager.createFirstWallet(action.initialMessage) withContext(Dispatchers.Main) { when (result) { - SimpleResult.Success -> - store.dispatch(TwinCardsAction.CreateWallet.LaunchFirstStep.Success) - is SimpleResult.Failure -> - store.dispatch(TwinCardsAction.CreateWallet.LaunchFirstStep.Failure) + SimpleResult.Success -> { + store.dispatch(TwinCardsAction.Wallet.LaunchFirstStep.Success) + } + is SimpleResult.Failure -> { + } } } } } - TwinCardsAction.CreateWallet.LaunchFirstStep.Success -> { + is TwinCardsAction.Wallet.LaunchSecondStep -> { + val manager = twinCardsState.twinCardsManager ?: return - } - TwinCardsAction.CreateWallet.LaunchFirstStep.Failure -> { - - } - is TwinCardsAction.CreateWallet.LaunchSecondStep -> scope.launch { - val result = twinsManager?.createSecondWallet(action.initialMessage, + val result = manager.createSecondWallet(action.initialMessage, action.preparingMessage, action.creatingWalletMessage) withContext(Dispatchers.Main) { when (result) { - SimpleResult.Success -> - store.dispatch(TwinCardsAction.CreateWallet.LaunchSecondStep.Success) - is SimpleResult.Failure -> - store.dispatch(TwinCardsAction.CreateWallet.LaunchSecondStep.Failure) + SimpleResult.Success -> { + store.dispatch(TwinCardsAction.Wallet.LaunchSecondStep.Success) + } + is SimpleResult.Failure -> { + } } } } - TwinCardsAction.CreateWallet.LaunchSecondStep.Success -> { - } - TwinCardsAction.CreateWallet.LaunchSecondStep.Failure -> { + is TwinCardsAction.Wallet.LaunchThirdStep -> { + val manager = twinCardsState.twinCardsManager ?: return - } - is TwinCardsAction.CreateWallet.LaunchThirdStep -> { scope.launch { - val result = twinsManager?.complete(action.message) + val result = manager.complete(action.message) withContext(Dispatchers.Main) { when (result) { - is Result.Success -> - store.dispatch(TwinCardsAction.CreateWallet.LaunchThirdStep.Success(result.data)) - is Result.Failure -> - store.dispatch(TwinCardsAction.CreateWallet.LaunchThirdStep.Failure) + is Result.Success -> { + store.dispatch(TwinCardsAction.Wallet.LaunchThirdStep.Success(result.data)) + } + is Result.Failure -> { + + } } } } } - is TwinCardsAction.CreateWallet.LaunchThirdStep.Success -> { + is TwinCardsAction.Wallet.LaunchThirdStep.Success -> { scope.launch { store.state.globalState.tapWalletManager.onCardScanned(action.scanResponse) } store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet)) } - TwinCardsAction.CreateWallet.LaunchThirdStep.Failure -> { - - } } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsReducer.kt b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsReducer.kt index 6f9e3a6f57..89978790a1 100644 --- a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsReducer.kt @@ -12,52 +12,49 @@ class TwinCardsReducer { private fun internalReduce(action: Action, state: AppState): TwinCardsState { if (action !is TwinCardsAction) return state.twinCardsState - val twinCardsState = state.twinCardsState + val state = state.twinCardsState return when (action) { + is TwinCardsAction.SetResources -> { + state.copy(resources = action.resources) + } is TwinCardsAction.SetTwinCard -> { - twinCardsState.copy( + state.copy( cardNumber = action.number, secondCardId = action.secondCardId, - showTwinOnboarding = state.twinCardsState.showTwinOnboarding, + showTwinOnboarding = state.showTwinOnboarding, isCreatingTwinCardsAllowed = action.isCreatingTwinCardsAllowed, ) } + is TwinCardsAction.CardsManager.Set -> { + state.copy(twinCardsManager = action.manager) + } + TwinCardsAction.CardsManager.Release -> { + state.copy(twinCardsManager = null) + } is TwinCardsAction.ShowOnboarding -> { - state.twinCardsState.copy(showTwinOnboarding = true) + state.copy(showTwinOnboarding = true) } is TwinCardsAction.SetOnboardingShown -> { - twinCardsState.copy(showTwinOnboarding = false) + state.copy(showTwinOnboarding = false) } - is TwinCardsAction.CreateWallet.Create -> { - val prevState = twinCardsState.createWalletState - twinCardsState.copy(createWalletState = CreateTwinWalletState( + is TwinCardsAction.Wallet.Create -> { + val prevState = state.createWalletState + state.copy(createWalletState = CreateTwinWalletState( prevState?.scanResponse, prevState?.number ?: action.number, prevState?.mode ?: action.createTwinWalletMode, )) } - TwinCardsAction.CreateWallet.LaunchFirstStep.Success -> { - twinCardsState.copy(createWalletState = twinCardsState.createWalletState?.copy( + TwinCardsAction.Wallet.LaunchFirstStep.Success -> { + state.copy(createWalletState = state.createWalletState?.copy( step = CreateTwinWalletStep.SecondStep )) } - TwinCardsAction.CreateWallet.LaunchSecondStep.Success -> - twinCardsState.copy(createWalletState = twinCardsState.createWalletState?.copy( + TwinCardsAction.Wallet.LaunchSecondStep.Success -> + state.copy(createWalletState = state.createWalletState?.copy( step = CreateTwinWalletStep.ThirdStep )) - TwinCardsAction.CreateWallet.ShowAlert -> twinCardsState - TwinCardsAction.CreateWallet.HideAlert -> twinCardsState - is TwinCardsAction.CreateWallet.Proceed -> twinCardsState - TwinCardsAction.CreateWallet.NotEmpty -> twinCardsState - TwinCardsAction.CreateWallet.Cancel -> twinCardsState - TwinCardsAction.CreateWallet.Cancel.Confirm -> twinCardsState - is TwinCardsAction.CreateWallet.LaunchFirstStep -> twinCardsState - TwinCardsAction.CreateWallet.LaunchFirstStep.Failure -> twinCardsState - is TwinCardsAction.CreateWallet.LaunchSecondStep -> twinCardsState - TwinCardsAction.CreateWallet.LaunchSecondStep.Failure -> twinCardsState - is TwinCardsAction.CreateWallet.LaunchThirdStep -> twinCardsState - is TwinCardsAction.CreateWallet.LaunchThirdStep.Success -> twinCardsState - TwinCardsAction.CreateWallet.LaunchThirdStep.Failure -> twinCardsState + else -> state } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsState.kt b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsState.kt index 49a43b9d93..f23ac31930 100644 --- a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsState.kt +++ b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsState.kt @@ -2,22 +2,22 @@ package com.tangem.tap.features.twins.redux import com.tangem.tap.domain.tasks.product.ScanResponse import com.tangem.tap.domain.twins.TwinCardNumber +import com.tangem.tap.domain.twins.TwinCardsManager import org.rekotlin.StateType /** [REDACTED_AUTHOR] */ data class TwinCardsState( + val twinCardsManager: TwinCardsManager? = null, // if cardNumber is not set -> the scanned card is not Twin val cardNumber: TwinCardNumber? = null, val secondCardId: String? = null, val showTwinOnboarding: Boolean = false, val isCreatingTwinCardsAllowed: Boolean = false, - val createWalletState: CreateTwinWalletState? = null -) : StateType { - val isReadyToUse: Boolean - get() = cardNumber != null -} + val createWalletState: CreateTwinWalletState? = null, + val resources: TwinCardsResources = TwinCardsResources(), +) : StateType data class CreateTwinWalletState( val scanResponse: ScanResponse?, @@ -26,9 +26,18 @@ data class CreateTwinWalletState( val step: CreateTwinWalletStep = CreateTwinWalletStep.FirstStep, ) { val showAlert: Boolean - get() = mode != CreateTwinWalletMode.RecreateWallet + get() = step != CreateTwinWalletStep.FirstStep } enum class CreateTwinWalletStep { FirstStep, SecondStep, ThirdStep } enum class CreateTwinWalletMode { CreateWallet, RecreateWallet } + +data class TwinCardsResources( + val strings: Strings = Strings() +) { + //TODO: create global structure for StringRes. Set it from the MainActivity. + data class Strings( + val walletIsNotEmpty: Int = -1 + ) +} diff --git a/app/src/main/java/com/tangem/tap/features/twins/ui/CreateTwinWalletFragment.kt b/app/src/main/java/com/tangem/tap/features/twins/ui/CreateTwinWalletFragment.kt index 0c23906aaf..94c5a099bc 100644 --- a/app/src/main/java/com/tangem/tap/features/twins/ui/CreateTwinWalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/twins/ui/CreateTwinWalletFragment.kt @@ -1,20 +1,17 @@ package com.tangem.tap.features.twins.ui -import android.app.Dialog import android.os.Bundle import android.view.View import androidx.activity.OnBackPressedCallback import androidx.core.content.ContextCompat.getColor import androidx.fragment.app.Fragment import androidx.transition.TransitionInflater -import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.squareup.picasso.Picasso import com.tangem.Message +import com.tangem.tap.common.extensions.readAssetAsString +import com.tangem.tap.domain.twins.AssetReader import com.tangem.tap.domain.twins.TwinCardNumber -import com.tangem.tap.features.twins.redux.CreateTwinWalletMode -import com.tangem.tap.features.twins.redux.CreateTwinWalletStep -import com.tangem.tap.features.twins.redux.TwinCardsAction -import com.tangem.tap.features.twins.redux.TwinCardsState +import com.tangem.tap.features.twins.redux.* import com.tangem.tap.features.wallet.redux.Artwork import com.tangem.tap.store import com.tangem.wallet.R @@ -24,20 +21,35 @@ import org.rekotlin.StoreSubscriber class CreateTwinWalletFragment : Fragment(R.layout.fragment_twin_cards_create), StoreSubscriber { - private var dialog: Dialog? = null + private val assetReader: AssetReader by lazy { + object : AssetReader { + override fun readAssetAsString(name: String): String = requireContext().readAssetAsString(name) + } + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { - store.dispatch(TwinCardsAction.CreateWallet.Cancel) + store.dispatch(TwinCardsAction.Wallet.HandleOnBackPressed) } }) + + initResources() val inflater = TransitionInflater.from(requireContext()) enterTransition = inflater.inflateTransition(R.transition.slide_right) exitTransition = inflater.inflateTransition(R.transition.fade) } + private fun initResources() { + val resources = TwinCardsResources( + TwinCardsResources.Strings( + R.string.details_notification_erase_wallet_not_possible + ) + ) + store.dispatch(TwinCardsAction.SetResources(resources)) + } + override fun onStart() { super.onStart() store.subscribe(this) { state -> @@ -55,9 +67,7 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_twin_cards_create), override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - toolbar.setNavigationOnClickListener { - store.dispatch(TwinCardsAction.CreateWallet.Cancel) - } + toolbar.setNavigationOnClickListener { store.dispatch(TwinCardsAction.Wallet.HandleOnBackPressed) } Picasso.get() .load(Artwork.TWIN_CARD_1) @@ -96,12 +106,12 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_twin_cards_create), v_step_2.setBackgroundColor(defaultColor) v_step_3.setBackgroundColor(defaultColor) btn_tap.setOnClickListener { - store.dispatch(TwinCardsAction.CreateWallet.LaunchFirstStep( + store.dispatch(TwinCardsAction.Wallet.LaunchFirstStep( Message(getString( R.string.details_twins_recreate_title_format, twinCardNumberString )), - requireContext() + assetReader )) } btn_tap.text = getString(R.string.details_twins_recreate_button_format, @@ -117,7 +127,7 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_twin_cards_create), v_step_2.setBackgroundColor(selectedColor) v_step_3.setBackgroundColor(defaultColor) btn_tap.setOnClickListener { - store.dispatch(TwinCardsAction.CreateWallet.LaunchSecondStep( + store.dispatch(TwinCardsAction.Wallet.LaunchSecondStep( Message(getString(R.string.details_twins_recreate_title_format, twinCardNumberString)), Message(getString(R.string.details_twins_recreate_title_preparing)), Message(getString(R.string.details_twins_recreate_title_creating_wallet)), @@ -135,7 +145,7 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_twin_cards_create), v_step_2.setBackgroundColor(selectedColor) v_step_3.setBackgroundColor(selectedColor) btn_tap.setOnClickListener { - store.dispatch(TwinCardsAction.CreateWallet.LaunchThirdStep( + store.dispatch(TwinCardsAction.Wallet.LaunchThirdStep( Message(getString( R.string.details_twins_recreate_title_format, twinCardNumberString) ) @@ -148,27 +158,5 @@ class CreateTwinWalletFragment : Fragment(R.layout.fragment_twin_cards_create), } btn_tap.text = getString(R.string.details_twins_recreate_button_format, cardNumber) tv_twin_title.text = getString(R.string.details_twins_recreate_title_format, cardNumber) - - if (state.createWalletState?.showAlert == true) { - if (dialog == null) { - dialog = MaterialAlertDialogBuilder(requireContext()) - .setMessage(R.string.details_twins_recreate_alert) - .setPositiveButton(R.string.common_ok) { _, _ -> - store.dispatch(TwinCardsAction.CreateWallet.Cancel.Confirm) - } - .setNegativeButton(R.string.common_cancel) { _, _ -> - dialog?.cancel() - } - .setOnCancelListener { - store.dispatch(TwinCardsAction.CreateWallet.HideAlert) - } - .create() - dialog?.show() - } - } else { - dialog?.cancel() - dialog = null - } } - } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/twins/ui/TwinWalletWarningFragment.kt b/app/src/main/java/com/tangem/tap/features/twins/ui/TwinWalletWarningFragment.kt index fefff8729c..18f779a400 100644 --- a/app/src/main/java/com/tangem/tap/features/twins/ui/TwinWalletWarningFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/twins/ui/TwinWalletWarningFragment.kt @@ -39,7 +39,7 @@ class TwinWalletWarningFragment : Fragment(R.layout.fragment_twin_cards_warning) } btn_cancel.setOnClickListener { store.dispatch(NavigationAction.PopBackTo()) } - btn_start.setOnClickListener { store.dispatch(TwinCardsAction.CreateWallet.Proceed) } + btn_start.setOnClickListener { store.dispatch(TwinCardsAction.ProceedToCreateWallet) } Picasso.get() .load(Artwork.TWIN_CARD_1) .placeholder(R.drawable.card_placeholder) diff --git a/app/src/main/java/com/tangem/tap/features/twins/ui/dialog/CreateWalletInterruptDialog.kt b/app/src/main/java/com/tangem/tap/features/twins/ui/dialog/CreateWalletInterruptDialog.kt new file mode 100644 index 0000000000..ab34b78039 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/twins/ui/dialog/CreateWalletInterruptDialog.kt @@ -0,0 +1,25 @@ +package com.tangem.tap.features.twins.ui.dialog + +import android.content.Context +import androidx.appcompat.app.AlertDialog +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.tangem.tap.common.extensions.dispatchDialogHide +import com.tangem.tap.features.twins.redux.TwinCardsAction +import com.tangem.tap.store +import com.tangem.wallet.R + +/** +[REDACTED_AUTHOR] + */ +class CreateWalletInterruptDialog { + companion object { + fun create(state: TwinCardsAction.Wallet.InterruptDialog, context: Context): AlertDialog { + return MaterialAlertDialogBuilder(context) + .setMessage(R.string.details_twins_recreate_alert) + .setPositiveButton(R.string.common_ok) { _, _ -> state.interrupt() } + .setNegativeButton(R.string.common_cancel) { _, _ -> } + .setOnDismissListener { store.dispatchDialogHide() } + .create() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/models/PendingTransaction.kt b/app/src/main/java/com/tangem/tap/features/wallet/models/PendingTransaction.kt index 492513e02c..29fe72df99 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/models/PendingTransaction.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/models/PendingTransaction.kt @@ -65,5 +65,5 @@ fun Wallet.getPendingTransactions(): List { } fun Wallet.hasPendingTransactions(): Boolean { - return recentTransactions.toPendingTransactions(address).isNotEmpty() + return getPendingTransactions().isNotEmpty() } \ No newline at end of file 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 61b4423e33..bdf79de67a 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 @@ -97,7 +97,7 @@ class WalletMiddleware { } is WalletAction.CreateWallet -> { if (walletState.isTangemTwins) { - store.dispatch(TwinCardsAction.CreateWallet.Create( + store.dispatch(TwinCardsAction.Wallet.Create( walletState.twinCardsState.cardNumber!!, CreateTwinWalletMode.CreateWallet )) From 73fe2a87afb707ee7a6b556e253663e0da1d5697 Mon Sep 17 00:00:00 2001 From: Tangem Date: Sun, 24 Oct 2021 18:35:16 +0300 Subject: [PATCH 07/18] Updated on 2026-08-14 --- .../java/com/tangem/tap/domain/tasks/ScanNoteTask.kt | 9 --------- .../tangem/tap/features/details/redux/DetailsReducer.kt | 1 + .../onboarding/products/twins/OnboardingTwinsFragment.kt | 6 ++---- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt index 820b159123..22a7e5ca87 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt @@ -1,8 +1,6 @@ package com.tangem.tap.domain.tasks import com.tangem.* -import com.tangem.blockchain.common.BlockchainSdkConfig -import com.tangem.blockchain.common.WalletManagerFactory import com.tangem.common.CompletionResult import com.tangem.common.card.Card import com.tangem.common.card.FirmwareVersion @@ -123,11 +121,4 @@ class ScanNoteTask(val card: Card? = null) : CardSessionRunnable { // if (card.isMultiCurrencyWallet()) return UpdateAppToUseThisCard() return null } - - private fun getWalletManagerFactory(): WalletManagerFactory { - val blockchainSdkConfig = store.state.globalState.configManager?.config - ?.blockchainSdkConfig ?: BlockchainSdkConfig() - return WalletManagerFactory(blockchainSdkConfig) - } - } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt index 14884b13f6..d2622417f7 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt @@ -7,6 +7,7 @@ import com.tangem.tap.domain.TapWorkarounds.isStart2Coin import com.tangem.tap.domain.extensions.isWalletDataSupported import com.tangem.tap.domain.extensions.signedHashesCount import com.tangem.tap.domain.extensions.toSendableAmounts +import com.tangem.tap.domain.twins.isTangemTwin import com.tangem.tap.features.wallet.models.hasPendingTransactions import org.rekotlin.Action import java.util.* diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/OnboardingTwinsFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/OnboardingTwinsFragment.kt index 791c31589c..684d05324e 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/OnboardingTwinsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/OnboardingTwinsFragment.kt @@ -10,7 +10,6 @@ import com.tangem.tap.common.extensions.dispatchDebugErrorNotification import com.tangem.tap.common.extensions.withMainContext import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction -import com.tangem.tap.domain.twins.TwinsHelper import com.tangem.tap.features.twins.redux.TwinCardsAction import com.tangem.tap.features.wallet.redux.Artwork import com.tangem.tap.scope @@ -37,9 +36,8 @@ class OnboardingTwinsFragment : Fragment(R.layout.fragment_twin_cards_welcome) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - store.dispatch(TwinCardsAction.SetOnboardingShown)) - val secondTwinNumber = - store.state.twinCardsState?.cardNumber?.pairNumber()?.number ?: "" + store.dispatch(TwinCardsAction.SetOnboardingShown) + val secondTwinNumber = store.state.twinCardsState.cardNumber?.pairNumber()?.number ?: "" val text = getString(R.string.twins_onboarding_description_format, secondTwinNumber) tv_twin_cards_description_1.text = text From cf97a1778d5ed953a8483b76bda0eb3c7443a9ba Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 25 Oct 2021 01:35:57 +0300 Subject: [PATCH 08/18] Updated on 2026-08-14 --- .../onboarding/products/note/redux/OnboardingNoteAction.kt | 2 +- .../onboarding/products/note/redux/OnboardingNoteMiddleware.kt | 2 +- .../onboarding/products/note/redux/OnboardingNoteReducer.kt | 2 +- .../products/otherCards/OnboardingOtherCardsFragment.kt | 1 - .../products/otherCards/redux/OnboardingOtherCardsAction.kt | 2 +- .../products/otherCards/redux/OnboardingOtherCardsMiddleware.kt | 2 +- .../products/otherCards/redux/OnboardingOtherCardsReducer.kt | 2 +- 7 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt index 1948bfe98c..859e1104fa 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt @@ -17,7 +17,7 @@ sealed class OnboardingNoteAction : Action { object ShowAddressInfoDialog : OnboardingNoteAction() // from redux - class SetArtworkUrl(val artwork: Artwork) : OnboardingNoteAction() + class SetArtwork(val artwork: Artwork) : OnboardingNoteAction() data class SetWalletManager(val walletManager: WalletManager) : OnboardingNoteAction() object DetermineStepOfScreen : OnboardingNoteAction() object Done : OnboardingNoteAction() 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 0a925dc7ee..8267514eb0 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 @@ -50,7 +50,7 @@ private fun handleNoteAction(action: Action, dispatch: DispatchFunction) { is OnboardingNoteAction.LoadCardArtwork -> { scope.launch { val artwork = onboardingManager.loadArtwork() - withMainContext { store.dispatch(OnboardingNoteAction.SetArtworkUrl(artwork)) } + withMainContext { store.dispatch(OnboardingNoteAction.SetArtwork(artwork)) } } } is OnboardingNoteAction.DetermineStepOfScreen -> { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteReducer.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteReducer.kt index 03415eec84..c88906cb20 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteReducer.kt @@ -17,7 +17,7 @@ private fun internalReduce(action: Action, appState: AppState): OnboardingNoteSt is GlobalAction.Onboarding.Start -> { state = OnboardingNoteState() } - is OnboardingNoteAction.SetArtworkUrl -> { + is OnboardingNoteAction.SetArtwork -> { state = state.copy(cardArtwork = action.artwork) } is OnboardingNoteAction.SetWalletManager -> { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt index ebdbe7d4c1..abfb32f6d5 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt @@ -10,7 +10,6 @@ import androidx.transition.TransitionManager import com.tangem.tap.common.extensions.getDrawableCompat import com.tangem.tap.common.transitions.InternalNoteLayoutTransition import com.tangem.tap.features.onboarding.products.BaseOnboardingFragment -import com.tangem.tap.features.onboarding.products.note.swapToBitmapDrawable import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsAction import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsState import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsStep diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsAction.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsAction.kt index 44bdec53c8..b48570b6c9 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsAction.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsAction.kt @@ -12,7 +12,7 @@ sealed class OnboardingOtherCardsAction : Action { object CreateWallet : OnboardingOtherCardsAction() // from redux - class SetArtworkUrl(val artwork: Artwork) : OnboardingOtherCardsAction() + class SetArtwork(val artwork: Artwork) : OnboardingOtherCardsAction() object DetermineStepOfScreen : OnboardingOtherCardsAction() object Done : OnboardingOtherCardsAction() 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 e775176f10..6fea776c74 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 @@ -44,7 +44,7 @@ private fun handleOtherCardsAction(action: Action, dispatch: DispatchFunction) { is OnboardingOtherCardsAction.LoadCardArtwork -> { scope.launch { val artwork = onboardingManager.loadArtwork() - withMainContext { store.dispatch(OnboardingOtherCardsAction.SetArtworkUrl(artwork)) } + withMainContext { store.dispatch(OnboardingOtherCardsAction.SetArtwork(artwork)) } } } is OnboardingOtherCardsAction.DetermineStepOfScreen -> { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsReducer.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsReducer.kt index a6313b9199..129b7ea280 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsReducer.kt @@ -17,7 +17,7 @@ private fun internalReduce(action: Action, appState: AppState): OnboardingOtherC is GlobalAction.Onboarding.Start -> { state = OnboardingOtherCardsState() } - is OnboardingOtherCardsAction.SetArtworkUrl -> { + is OnboardingOtherCardsAction.SetArtwork -> { state = state.copy(cardArtwork = action.artwork) } is OnboardingOtherCardsAction.SetStepOfScreen -> { From df6fe358986ce3be1f594a4fe585429cc02ee61f Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 26 Oct 2021 18:04:55 +0300 Subject: [PATCH 09/18] Updated on 2026-08-14 --- Gemfile.lock | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 Gemfile.lock diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000000..9dd60618bd --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,184 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.4) + rexml + addressable (2.8.0) + public_suffix (>= 2.0.2, < 5.0) + atomos (0.1.3) + aws-eventstream (1.2.0) + aws-partitions (1.519.0) + aws-sdk-core (3.121.3) + aws-eventstream (~> 1, >= 1.0.2) + aws-partitions (~> 1, >= 1.239.0) + aws-sigv4 (~> 1.1) + jmespath (~> 1.0) + aws-sdk-kms (1.50.0) + aws-sdk-core (~> 3, >= 3.121.2) + aws-sigv4 (~> 1.1) + aws-sdk-s3 (1.104.0) + aws-sdk-core (~> 3, >= 3.121.2) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.4) + aws-sigv4 (1.4.0) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.4) + claide (1.0.3) + colored (1.2) + colored2 (3.1.2) + commander-fastlane (4.4.6) + highline (~> 1.7.2) + declarative (0.0.20) + declarative-option (0.1.0) + digest-crc (0.6.4) + rake (>= 12.0.0, < 14.0.0) + domain_name (0.5.20190701) + unf (>= 0.0.5, < 1.0.0) + dotenv (2.7.6) + emoji_regex (1.0.1) + excon (0.87.0) + faraday (0.17.4) + multipart-post (>= 1.2, < 3) + faraday-cookie_jar (0.0.7) + faraday (>= 0.8.0) + http-cookie (~> 1.0.0) + faraday_middleware (0.13.1) + faraday (>= 0.7.4, < 1.0) + fastimage (2.2.5) + fastlane (2.146.1) + CFPropertyList (>= 2.3, < 4.0.0) + addressable (>= 2.3, < 3.0.0) + aws-sdk-s3 (~> 1.0) + babosa (>= 1.0.2, < 2.0.0) + bundler (>= 1.12.0, < 3.0.0) + colored + commander-fastlane (>= 4.4.6, < 5.0.0) + dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (>= 0.1, < 2.0) + excon (>= 0.71.0, < 1.0.0) + faraday (~> 0.17) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (~> 0.13.1) + fastimage (>= 2.1.0, < 3.0.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-api-client (>= 0.29.2, < 0.37.0) + google-cloud-storage (>= 1.15.0, < 2.0.0) + highline (>= 1.7.2, < 2.0.0) + json (< 3.0.0) + jwt (~> 2.1.0) + mini_magick (>= 4.9.4, < 5.0.0) + multi_xml (~> 0.5) + multipart-post (~> 2.0.0) + plist (>= 3.1.0, < 4.0.0) + public_suffix (~> 2.0.0) + rubyzip (>= 1.3.0, < 2.0.0) + security (= 0.1.3) + simctl (~> 1.6.3) + slack-notifier (>= 2.0.0, < 3.0.0) + terminal-notifier (>= 2.0.0, < 3.0.0) + terminal-table (>= 1.4.5, < 2.0.0) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) + word_wrap (~> 1.0.0) + xcodeproj (>= 1.13.0, < 2.0.0) + xcpretty (~> 0.3.0) + xcpretty-travis-formatter (>= 0.0.3) + fastlane-plugin-firebase_app_distribution (0.3.1) + gh_inspector (1.1.3) + google-api-client (0.32.1) + addressable (~> 2.5, >= 2.5.1) + googleauth (>= 0.5, < 0.10.0) + httpclient (>= 2.8.1, < 3.0) + mini_mime (~> 1.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.0) + signet (~> 0.10) + google-cloud-core (1.3.2) + google-cloud-env (~> 1.0) + google-cloud-env (1.2.1) + faraday (~> 0.11) + google-cloud-storage (1.21.1) + addressable (~> 2.5) + digest-crc (~> 0.4) + google-api-client (~> 0.26) + google-cloud-core (~> 1.2) + googleauth (>= 0.6.2, < 0.10.0) + mini_mime (~> 1.0) + googleauth (0.9.0) + faraday (~> 0.12) + jwt (>= 1.4, < 3.0) + memoist (~> 0.16) + multi_json (~> 1.11) + os (>= 0.9, < 2.0) + signet (~> 0.7) + highline (1.7.10) + http-cookie (1.0.4) + domain_name (~> 0.5) + httpclient (2.8.3) + jmespath (1.4.0) + json (2.6.1) + jwt (2.1.0) + memoist (0.16.2) + mini_magick (4.11.0) + mini_mime (1.1.2) + multi_json (1.15.0) + multi_xml (0.6.0) + multipart-post (2.0.0) + nanaimo (0.3.0) + naturally (2.2.1) + os (1.1.1) + plist (3.6.0) + public_suffix (2.0.5) + rake (13.0.6) + representable (3.0.4) + declarative (< 0.1.0) + declarative-option (< 0.2.0) + uber (< 0.2.0) + retriable (3.1.2) + rexml (3.2.5) + rouge (2.0.7) + rubyzip (1.3.0) + security (0.1.3) + signet (0.11.0) + addressable (~> 2.3) + faraday (~> 0.9) + jwt (>= 1.5, < 3.0) + multi_json (~> 1.10) + simctl (1.6.8) + CFPropertyList + naturally + slack-notifier (2.4.0) + terminal-notifier (2.0.0) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + tty-cursor (0.7.1) + tty-screen (0.8.1) + tty-spinner (0.9.3) + tty-cursor (~> 0.7) + uber (0.1.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.8) + unicode-display_width (1.8.0) + word_wrap (1.0.0) + xcodeproj (1.21.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.3.0) + rexml (~> 3.2.4) + xcpretty (0.3.0) + rouge (~> 2.0.7) + xcpretty-travis-formatter (1.0.1) + xcpretty (~> 0.2, >= 0.0.7) + +PLATFORMS + universal-darwin-18 + +DEPENDENCIES + fastlane + fastlane-plugin-firebase_app_distribution + +BUNDLED WITH + 2.2.16 From e6569a72585a039f6674d4bde759eb5e804608c6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 27 Oct 2021 23:05:29 +0300 Subject: [PATCH 10/18] Updated on 2026-08-14 --- .../java/com/tangem/tap/common/extensions/Store.kt | 5 +++++ .../com/tangem/tap/common/redux/global/GlobalAction.kt | 3 +++ .../tangem/tap/common/redux/global/GlobalReducer.kt | 3 +++ .../com/tangem/tap/common/redux/global/GlobalState.kt | 10 ++++++++++ 4 files changed, 21 insertions(+) diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Store.kt b/app/src/main/java/com/tangem/tap/common/extensions/Store.kt index f5fd832f2b..17db11e102 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Store.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Store.kt @@ -4,6 +4,7 @@ import com.tangem.tap.common.redux.StateDialog import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.TapError +import com.tangem.tap.domain.tasks.product.ScanResponse import com.tangem.tap.scope import com.tangem.tap.store import kotlinx.coroutines.Dispatchers @@ -17,6 +18,10 @@ fun Store<*>.dispatchOnMain(action: Action) { } } +suspend fun Store<*>.onCardScanned(scanResponse: ScanResponse) { + store.state.globalState.tapWalletManager.onCardScanned(scanResponse) +} + fun Store<*>.dispatchOpenUrl(url: String) { store.dispatch(NavigationAction.OpenUrl(url)) } diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt index 297ba9fd40..278672bff1 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt @@ -23,6 +23,9 @@ sealed class GlobalAction : Action { data class ShowErrorNotification(override val error: TapError) : GlobalAction(), ErrorAction data class DebugShowErrorNotification(override val error: TapError) : GlobalAction(), DebugErrorAction + // android resources + data class SetResources(val resources: AndroidResources) : GlobalAction() + // dialogs data class ShowDialog(val stateDialog: StateDialog) : GlobalAction() object HideDialog : GlobalAction() diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt index 29ec84876e..f5ce207390 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt @@ -12,6 +12,9 @@ fun globalReducer(action: Action, state: AppState): GlobalState { val globalState = state.globalState return when (action) { + is GlobalAction.SetResources -> { + globalState.copy(resources = action.resources) + } is GlobalAction.Onboarding.Start -> { val usedCardsPrefStorage = preferencesStorage.usedCardsPrefStorage val onboardingState = OnboardingManager(action.scanResponse, usedCardsPrefStorage) diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt index e27641b854..e0166e90e8 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt @@ -27,7 +27,17 @@ data class GlobalState( val scanCardFailsCounter: Int = 0, val dialog: StateDialog? = null, val moonPayUserStatus: MoonPayUserStatus? = null, + val resources: AndroidResources = AndroidResources(), ) : StateType + +data class AndroidResources( + val strings: RString = RString() +) { + data class RString( + val addressWasCopied: Int = -1, + val walletIsNotEmpty: Int = -1 + ) +} typealias CryptoCurrencyName = String typealias FiatCurrencyName = String \ No newline at end of file From c02e5b93f69135c851b254e132ad1050f0c9dd0a Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 27 Oct 2021 23:11:06 +0300 Subject: [PATCH 11/18] Updated on 2026-08-14 --- .../features/details/redux/DetailsAction.kt | 3 ++- .../details/redux/DetailsMiddleware.kt | 19 +++++++++++++++++++ .../features/details/redux/DetailsState.kt | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt index 3f8fbfccea..29143f79b9 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt @@ -6,6 +6,7 @@ import com.tangem.tap.common.redux.NotificationAction import com.tangem.tap.common.redux.global.FiatCurrencyName import com.tangem.tap.domain.tasks.product.ScanResponse import com.tangem.tap.domain.termsOfUse.CardTou +import com.tangem.tap.domain.twins.TwinCardNumber import com.tangem.tap.network.coinmarketcap.FiatCurrency import com.tangem.wallet.R import org.rekotlin.Action @@ -21,7 +22,7 @@ sealed class DetailsAction : Action { ) : DetailsAction() object ShowDisclaimer : DetailsAction() - + data class ReCreateTwinsWallet(val number: TwinCardNumber) : DetailsAction() sealed class EraseWallet : DetailsAction() { object Check : EraseWallet() diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index b539946faa..9192ef3043 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -4,12 +4,16 @@ import com.tangem.common.CompletionResult import com.tangem.common.core.TangemSdkError import com.tangem.common.services.Result import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler +import com.tangem.tap.common.extensions.dispatchNotification import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.redux.AppState 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.features.disclaimer.redux.DisclaimerAction +import com.tangem.tap.features.onboarding.twins.redux.CreateTwinWalletMode +import com.tangem.tap.features.onboarding.twins.redux.TwinCardsAction +import com.tangem.tap.features.wallet.models.hasSendableAmountsOrPendingTransactions import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.network.coinmarketcap.CoinMarketCapService import com.tangem.tap.preferencesStorage @@ -37,6 +41,21 @@ class DetailsMiddleware { store.dispatch(DisclaimerAction.ShowAcceptedDisclaimer) store.dispatch(NavigationAction.NavigateTo(AppScreen.Disclaimer)) } + is DetailsAction.ReCreateTwinsWallet -> { + val wallet = store.state.walletState.walletManagers.map { it.wallet }.firstOrNull() + if (wallet == null) { + store.dispatch(TwinCardsAction.SetMode(CreateTwinWalletMode.RecreateWallet)) + store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingTwins)) + } else { + if (wallet.hasSendableAmountsOrPendingTransactions()) { + val walletIsNotEmpty = store.state.globalState.resources.strings.walletIsNotEmpty + store.dispatchNotification(walletIsNotEmpty) + } else { + store.dispatch(TwinCardsAction.SetMode(CreateTwinWalletMode.RecreateWallet)) + store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingTwins)) + } + } + } } next(action) } diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt index 40a6a6df31..271f51cc97 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt @@ -6,7 +6,7 @@ import com.tangem.common.card.Card import com.tangem.tap.common.entities.Button import com.tangem.tap.common.entities.TapCurrency.Companion.DEFAULT_FIAT_CURRENCY import com.tangem.tap.common.redux.global.FiatCurrencyName -import com.tangem.tap.features.twins.redux.TwinCardsState +import com.tangem.tap.features.onboarding.twins.redux.TwinCardsState import com.tangem.tap.network.coinmarketcap.FiatCurrency import com.tangem.tap.store import org.rekotlin.StateType From 6dcce60fb4f69531021fe03f5807c40379c4b884 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 27 Oct 2021 23:21:34 +0300 Subject: [PATCH 12/18] Updated on 2026-08-14 --- .../main/java/com/tangem/tap/MainActivity.kt | 12 + .../com/tangem/tap/common/DialogManager.kt | 6 +- .../tap/common/extensions/Navigation.kt | 11 +- .../common/leapfrogWidget/LeapfrogWidget.kt | 65 ++-- .../com/tangem/tap/common/redux/AppReducer.kt | 28 +- .../com/tangem/tap/common/redux/AppState.kt | 4 +- .../tangem/tap/common/redux/StateDialog.kt | 5 +- .../navigation/FragmentShareTransition.kt | 35 ++ .../redux/navigation/NavigationAction.kt | 12 +- .../redux/navigation/NavigationState.kt | 5 +- .../configurable/config/ConfigManager.kt | 5 +- .../tangem/tap/domain/tasks/ScanNoteTask.kt | 124 ------ .../tap/domain/twins/TwinCardsManager.kt | 27 +- .../tap/domain/twins/TwinCardsWidget.kt | 64 +-- .../BaseStoreFragment.kt => BaseFragment.kt} | 44 ++- .../tangem/tap/features/BaseStoreFragment.kt | 24 ++ .../details/redux/DetailsMiddleware.kt | 4 +- .../features/details/redux/DetailsState.kt | 2 +- .../features/details/ui/DetailsFragment.kt | 18 +- .../tangem/tap/features/home/HomeFragment.kt | 13 +- .../tap/features/home/redux/HomeMiddleware.kt | 27 +- .../products/BaseOnboardingFragment.kt | 7 +- .../products/note/OnboardingNoteFragment.kt | 31 +- .../note/redux/OnboardingNoteAction.kt | 1 - .../note/redux/OnboardingNoteMiddleware.kt | 6 +- .../note/redux/OnboardingNoteReducer.kt | 3 - .../note/redux/OnboardingNoteState.kt | 9 - .../OnboardingOtherCardsFragment.kt | 16 +- .../redux/OnboardingOtherCardsMiddleware.kt | 3 +- .../products/twins/OnboardingTwinsFragment.kt | 72 ---- .../products/twins/redux/TwinCardsAction.kt | 64 +++ .../twins/redux/TwinCardsMiddleware.kt | 275 +++++++++++++ .../products/twins/redux/TwinCardsReducer.kt | 64 +++ .../products/twins/redux/TwinCardsState.kt | 61 +++ .../products/twins/ui/TwinsCardsFragment.kt | 366 ++++++++++++++++++ .../ui/dialog/CreateWalletInterruptDialog.kt | 10 +- .../wallet/OnboardingWalletFragment.kt | 2 +- .../tap/features/send/ui/SendFragment.kt | 37 +- .../FragmentStateSubscriber.kt | 2 +- .../stateSubscribers/SendStateSubscriber.kt | 16 +- .../features/twins/redux/TwinCardsAction.kt | 62 --- .../twins/redux/TwinCardsMiddleware.kt | 139 ------- .../features/twins/redux/TwinCardsReducer.kt | 60 --- .../features/twins/redux/TwinCardsState.kt | 43 -- .../twins/ui/CreateTwinWalletFragment.kt | 162 -------- .../twins/ui/TwinWalletWarningFragment.kt | 57 --- .../wallet/models/PendingTransaction.kt | 21 +- .../tap/features/wallet/redux/WalletState.kt | 2 +- .../redux/middlewares/WalletMiddleware.kt | 43 +- .../wallet/redux/reducers/WalletReducer.kt | 3 +- .../tap/features/wallet/ui/WalletFragment.kt | 4 +- .../wallet/ui/wallet/SingleWalletView.kt | 11 +- .../main/res/drawable/card_placeholder.xml | 22 -- .../res/drawable/card_placeholder_black.xml | 126 ++++++ .../res/drawable/card_placeholder_white.xml | 108 ++++++ .../main/res/drawable/ic_home_back_card.xml | 102 ----- .../main/res/drawable/ic_home_front_card.xml | 118 ------ ...=> layout_onboarding_container_bottom.xml} | 16 + .../res/layout/fragment_onboarding_main.xml | 2 +- .../res/layout/fragment_twin_cards_create.xml | 160 -------- .../layout/fragment_twin_cards_warning.xml | 103 ----- .../layout/fragment_twin_cards_welcome.xml | 97 ----- app/src/main/res/layout/fragment_wallet.xml | 2 +- ...=> layout_onboarding_container_bottom.xml} | 18 +- ...ml => layout_onboarding_container_top.xml} | 43 +- ...ome.xml => layout_onboarding_home_top.xml} | 5 +- app/src/main/res/layout/layout_twin_cards.xml | 38 -- .../res/layout/layout_twin_cards_orange.xml | 38 -- .../layout/lp_onboarding_create_wallet.xml | 40 +- .../main/res/layout/lp_onboarding_done.xml | 40 +- .../layout/lp_onboarding_done_activation.xml | 40 +- .../lp_onboarding_done_activation_twins.xml | 116 ++++++ .../res/layout/lp_onboarding_topup_wallet.xml | 42 +- .../lp_onboarding_topup_wallet_twins.xml | 116 ++++++ .../main/res/layout/test_leapfrog_widget.xml | 7 +- .../main/res/layout/view_bg_twins_welcome.xml | 46 +++ .../res/layout/view_onboarding_progress.xml | 21 +- .../res/layout/view_onboarding_tv_balance.xml | 1 + .../main/res/values/strings_untranslated.xml | 27 +- app/src/main/res/values/styles.xml | 3 +- 80 files changed, 1946 insertions(+), 1738 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/common/redux/navigation/FragmentShareTransition.kt delete mode 100644 app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt rename app/src/main/java/com/tangem/tap/features/{send/BaseStoreFragment.kt => BaseFragment.kt} (56%) create mode 100644 app/src/main/java/com/tangem/tap/features/BaseStoreFragment.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/twins/OnboardingTwinsFragment.kt create mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsAction.kt create mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt create mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt create mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsState.kt create mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt rename app/src/main/java/com/tangem/tap/features/{ => onboarding/products}/twins/ui/dialog/CreateWalletInterruptDialog.kt (66%) delete mode 100644 app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsAction.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsMiddleware.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsReducer.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsState.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/twins/ui/CreateTwinWalletFragment.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/twins/ui/TwinWalletWarningFragment.kt delete mode 100644 app/src/main/res/drawable/card_placeholder.xml create mode 100644 app/src/main/res/drawable/card_placeholder_black.xml create mode 100644 app/src/main/res/drawable/card_placeholder_white.xml delete mode 100644 app/src/main/res/drawable/ic_home_back_card.xml delete mode 100644 app/src/main/res/drawable/ic_home_front_card.xml rename app/src/main/res/layout-h680dp/{layout_onboarding_bottom_action_views.xml => layout_onboarding_container_bottom.xml} (83%) delete mode 100644 app/src/main/res/layout/fragment_twin_cards_create.xml delete mode 100644 app/src/main/res/layout/fragment_twin_cards_warning.xml delete mode 100644 app/src/main/res/layout/fragment_twin_cards_welcome.xml rename app/src/main/res/layout/{layout_onboarding_bottom_action_views.xml => layout_onboarding_container_bottom.xml} (82%) rename app/src/main/res/layout/{layout_onboarding_note.xml => layout_onboarding_container_top.xml} (69%) rename app/src/main/res/layout/{layout_onboarding_home.xml => layout_onboarding_home_top.xml} (90%) delete mode 100644 app/src/main/res/layout/layout_twin_cards.xml delete mode 100644 app/src/main/res/layout/layout_twin_cards_orange.xml create mode 100644 app/src/main/res/layout/lp_onboarding_done_activation_twins.xml create mode 100644 app/src/main/res/layout/lp_onboarding_topup_wallet_twins.xml create mode 100644 app/src/main/res/layout/view_bg_twins_welcome.xml diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index 6f99403572..a7307e4e74 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -13,6 +13,8 @@ import com.tangem.tap.common.DialogManager import com.tangem.tap.common.IntentHandler import com.tangem.tap.common.SnackbarHandler import com.tangem.tap.common.redux.NotificationsHandler +import com.tangem.tap.common.redux.global.AndroidResources +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.TangemSdkManager @@ -66,9 +68,19 @@ class MainActivity : AppCompatActivity(), SnackbarHandler { tangemSdk = TangemSdk.init(this, TangemSdkManager.config) tangemSdkManager = TangemSdkManager(tangemSdk, this) + store.dispatch(GlobalAction.SetResources(getAndroidResources())) store.dispatch(WalletConnectAction.RestoreSessions) } + private fun getAndroidResources(): AndroidResources { + return AndroidResources( + AndroidResources.RString( + R.string.copy_toast_msg, + R.string.details_notification_erase_wallet_not_possible + ) + ) + } + private fun systemActions() { // makes the status bar text dark window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR 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 a604cbd643..b3a0c345e2 100644 --- a/app/src/main/java/com/tangem/tap/common/DialogManager.kt +++ b/app/src/main/java/com/tangem/tap/common/DialogManager.kt @@ -7,8 +7,8 @@ import com.tangem.tap.common.redux.global.GlobalState import com.tangem.tap.features.details.redux.walletconnect.WalletConnectDialog import com.tangem.tap.features.details.ui.walletconnect.dialogs.* import com.tangem.tap.features.onboarding.AddressInfoBottomSheetDialog -import com.tangem.tap.features.twins.redux.TwinCardsAction -import com.tangem.tap.features.twins.ui.dialog.CreateWalletInterruptDialog +import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction +import com.tangem.tap.features.onboarding.products.twins.ui.dialog.CreateWalletInterruptDialog import com.tangem.tap.features.wallet.ui.dialogs.ScanFailsDialog import com.tangem.tap.store import com.tangem.wallet.R @@ -45,7 +45,7 @@ class DialogManager : StoreSubscriber { dialog = when (state.dialog) { is AppDialog.ScanFailsDialog -> ScanFailsDialog.create(context) is AppDialog.AddressInfoDialog -> AddressInfoBottomSheetDialog(state.dialog, context) - is TwinCardsAction.Wallet.InterruptDialog -> CreateWalletInterruptDialog.create(state.dialog, context) + is TwinCardsAction.Wallet.ShowInterruptDialog -> CreateWalletInterruptDialog.create(state.dialog, context) is WalletConnectDialog.UnsupportedCard -> SimpleAlertDialog.create( titleRes = R.string.wallet_connect, diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt index 135e0cbd9c..f96f16f5ee 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt @@ -16,12 +16,10 @@ import com.tangem.tap.features.disclaimer.ui.DisclaimerFragment import com.tangem.tap.features.home.HomeFragment import com.tangem.tap.features.onboarding.products.note.OnboardingNoteFragment import com.tangem.tap.features.onboarding.products.otherCards.OnboardingOtherCardsFragment -import com.tangem.tap.features.onboarding.products.twins.OnboardingTwinsFragment +import com.tangem.tap.features.onboarding.products.twins.ui.TwinsCardsFragment import com.tangem.tap.features.onboarding.products.wallet.OnboardingWalletFragment import com.tangem.tap.features.send.ui.SendFragment import com.tangem.tap.features.tokens.ui.AddTokensFragment -import com.tangem.tap.features.twins.ui.CreateTwinWalletFragment -import com.tangem.tap.features.twins.ui.TwinWalletWarningFragment import com.tangem.tap.features.wallet.ui.WalletDetailsFragment import com.tangem.tap.features.wallet.ui.WalletFragment import com.tangem.wallet.R @@ -39,7 +37,7 @@ fun FragmentActivity.openFragment( transaction.setReorderingAllowed(true) shareElements.forEach { shareElement -> shareElement.wView.get()?.let { view -> - transaction.addSharedElement(view, shareElement.name) + transaction.addSharedElement(view, shareElement.elementName) } } } @@ -70,10 +68,11 @@ fun FragmentActivity.addOnBackPressedDispatcher( private fun fragmentFactory(screen: AppScreen): Fragment { return when (screen) { +// AppScreen.Home -> TestLeapfrogFragment() AppScreen.Home -> HomeFragment() AppScreen.OnboardingNote -> OnboardingNoteFragment() AppScreen.OnboardingWallet -> OnboardingWalletFragment() - AppScreen.OnboardingTwins -> OnboardingTwinsFragment() + AppScreen.OnboardingTwins -> TwinsCardsFragment() AppScreen.OnboardingOther -> OnboardingOtherCardsFragment() AppScreen.Wallet -> WalletFragment() AppScreen.Send -> SendFragment() @@ -81,8 +80,6 @@ private fun fragmentFactory(screen: AppScreen): Fragment { AppScreen.DetailsConfirm -> DetailsConfirmFragment() AppScreen.DetailsSecurity -> DetailsSecurityFragment() AppScreen.Disclaimer -> DisclaimerFragment() - AppScreen.CreateTwinWalletWarning -> TwinWalletWarningFragment() - AppScreen.CreateTwinWallet -> CreateTwinWalletFragment() AppScreen.AddTokens -> AddTokensFragment() AppScreen.WalletDetails -> WalletDetailsFragment() AppScreen.WalletConnectSessions -> WalletConnectSessionsFragment() diff --git a/app/src/main/java/com/tangem/tap/common/leapfrogWidget/LeapfrogWidget.kt b/app/src/main/java/com/tangem/tap/common/leapfrogWidget/LeapfrogWidget.kt index 884cef3f94..e83f7b8b92 100644 --- a/app/src/main/java/com/tangem/tap/common/leapfrogWidget/LeapfrogWidget.kt +++ b/app/src/main/java/com/tangem/tap/common/leapfrogWidget/LeapfrogWidget.kt @@ -6,6 +6,7 @@ import android.view.animation.AccelerateDecelerateInterpolator import android.widget.FrameLayout import androidx.core.animation.doOnEnd import androidx.core.view.children +import com.tangem.common.extensions.VoidCallback import com.tangem.tangem_sdk_new.extensions.dpToPx /** @@ -15,9 +16,9 @@ class LeapfrogWidget( private val parentContainer: FrameLayout, private val calculator: PropertyCalculator = PropertyCalculator(), ) { - private val foldAnimationDuration = 500L - private val leapAnimationDuration = 800L - private val leapBackAnimationDuration = 800L + private val foldAnimationDuration = 300L + private val leapAnimationDuration = 500L + private val leapBackAnimationDuration = 500L private val leapViews = mutableListOf() @@ -25,9 +26,6 @@ class LeapfrogWidget( private var leapProgress: Int = 100 private var leapBackProgress: Int = 100 - var isFolded: Boolean = true - private set - init { calculator.setTranslationConverter { parentContainer.dpToPx(it) } if (viewIsFullFledged()) { @@ -43,12 +41,11 @@ class LeapfrogWidget( * Apply initial properties to the views */ fun initViews() { - isFolded = true leapViews.forEach { it.initView() } } - fun fold(onEnd: () -> Unit = {}) { - val animator = foldAnimator() + fun fold(animate: Boolean = true, onEnd: VoidCallback = {}) { + val animator = foldAnimator(animate) if (animator == null) { onEnd() } else { @@ -57,8 +54,8 @@ class LeapfrogWidget( } } - fun unfold(onEnd: () -> Unit = {}) { - val animator = unfoldAnimator() + fun unfold(animate: Boolean = true, onEnd: VoidCallback = {}) { + val animator = unfoldAnimator(animate) if (animator == null) { onEnd() } else { @@ -67,33 +64,31 @@ class LeapfrogWidget( } } - fun foldAnimator(): Animator? { - if (!canFoldUnfold() || isFolded) return null + fun foldAnimator(animate: Boolean = true): Animator? { + if (!canFoldUnfold()) return null - return createFoldUnfoldAnimator(true, foldAnimationDuration) + return createFoldUnfoldAnimator(true, animate, foldAnimationDuration) } - fun unfoldAnimator(): Animator? { - if (!canFoldUnfold() || !isFolded) return null + fun unfoldAnimator(animate: Boolean = true): Animator? { + if (!canFoldUnfold()) return null - return createFoldUnfoldAnimator(false, foldAnimationDuration) + return createFoldUnfoldAnimator(false, animate, foldAnimationDuration) } - private fun createFoldUnfoldAnimator(isFoldAnimation: Boolean, duration: Long): Animator { + private fun createFoldUnfoldAnimator(isFoldAnimation: Boolean, animate: Boolean, duration: Long): Animator { val animatorsList = mutableListOf() + val animateDuration = if (animate) duration else 0 leapViews.forEach { if (isFoldAnimation) { it.fold() - animatorsList.add(it.view.foldAnimation(duration, it.state.properties)) + animatorsList.add(it.view.foldAnimation(animateDuration, it.state.properties)) } else { it.unfold() - animatorsList.add(it.view.unfoldAnimation(duration, it.state.properties)) + animatorsList.add(it.view.unfoldAnimation(animateDuration, it.state.properties)) } } - animatorsList.add(createProgressListener(duration) { - foldUnfoldProgress = it - if (it == 100) isFolded = isFoldAnimation - }) + animatorsList.add(createProgressListener(animateDuration) { foldUnfoldProgress = it }) val animator = AnimatorSet() animator.interpolator = AccelerateDecelerateInterpolator() @@ -101,13 +96,13 @@ class LeapfrogWidget( return animator } - fun leap(onEnd: () -> Unit = {}) { + fun leap(animate: Boolean = true, onEnd: VoidCallback = {}) { if (!canLeap()) { onEnd() return } - val duration = leapAnimationDuration + val duration = if (animate) leapAnimationDuration else 0 val animatorsList = mutableListOf() leapViews.forEach { when (it.leap()) { @@ -128,13 +123,13 @@ class LeapfrogWidget( animator.start() } - fun leapBack(onEnd: () -> Unit = {}) { + fun leapBack(animate: Boolean = true, onEnd: VoidCallback = {}) { if (!canLeapBack()) { onEnd() return } - val duration = leapBackAnimationDuration + val duration = if (animate) leapBackAnimationDuration else 0 val animatorsList = mutableListOf() leapViews.forEach { when (it.leapBack()) { @@ -160,12 +155,11 @@ class LeapfrogWidget( fun getViewByPosition(position: Int): LeapView = leapViews.first { it.state.currentPosition == position } - fun getState(): LeapfrogWidgetState = LeapfrogWidgetState(isFolded, leapViews.map { it.state }) + fun getState(): LeapfrogWidgetState = LeapfrogWidgetState(leapViews.map { it.state }) fun applyState(state: LeapfrogWidgetState) { - isFolded = state.isFolded - state.leapViewStates.forEach { state -> - leapViews.firstOrNull { it.index == state.index }?.applyState(state) + state.leapViewStates.forEach { viewState -> + leapViews.firstOrNull { it.index == viewState.index }?.applyState(viewState) } } @@ -183,7 +177,6 @@ class LeapfrogWidget( private fun canLeap(): Boolean { return when { !viewIsFullFledged() -> false - isFolded -> false leapBackInProgress() -> false leapProgress < 70 -> false else -> true @@ -193,7 +186,6 @@ class LeapfrogWidget( private fun canLeapBack(): Boolean { return when { !viewIsFullFledged() -> false - isFolded -> false leapInProgress() -> false leapBackProgress < 70 -> false else -> true @@ -206,14 +198,13 @@ class LeapfrogWidget( } data class LeapfrogWidgetState( - val isFolded: Boolean, val leapViewStates: List ) class PropertyCalculator( val elevationFactor: Float = 1f, - val decreaseScaleFactor: Float = 0.1f, - val yTranslationFactor: Float = 20f, + val decreaseScaleFactor: Float = 0.15f, + val yTranslationFactor: Float = 35f, val decreaseOverLiftingFactor: Float = 0.85f, ) { // 0 view it is view on the top of stack, but it is last in parent.children diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt index ed4dbe69aa..d797ff9010 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt @@ -8,10 +8,10 @@ import com.tangem.tap.features.disclaimer.redux.DisclaimerReducer import com.tangem.tap.features.home.redux.HomeReducer import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteReducer import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsReducer +import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsReducer import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletReducer import com.tangem.tap.features.send.redux.reducers.SendScreenReducer import com.tangem.tap.features.tokens.redux.TokensReducer -import com.tangem.tap.features.twins.redux.TwinCardsReducer import com.tangem.tap.features.wallet.redux.reducers.WalletReducer import org.rekotlin.Action @@ -20,19 +20,19 @@ fun appReducer(action: Action, state: AppState?): AppState { if (action is AppAction.RestoreState) return action.state return AppState( - navigationState = NavigationReducer.reduce(action, state), - globalState = globalReducer(action, state), - homeState = HomeReducer.reduce(action, state), - onboardingNoteState = OnboardingNoteReducer.reduce(action, state), - onboardingWalletState = OnboardingWalletReducer.reduce(action, state), - onboardingOtherCardsState = OnboardingOtherCardsReducer.reduce(action, state), - walletState = WalletReducer.reduce(action, state), - twinCardsState = TwinCardsReducer.reduce(action, state), - sendState = SendScreenReducer.reduce(action, state.sendState), - detailsState = DetailsReducer.reduce(action, state), - disclaimerState = DisclaimerReducer.reduce(action, state), - tokensState = TokensReducer.reduce(action, state), - walletConnectState = WalletConnectReducer.reduce(action, state.walletConnectState) + navigationState = NavigationReducer.reduce(action, state), + globalState = globalReducer(action, state), + homeState = HomeReducer.reduce(action, state), + onboardingNoteState = OnboardingNoteReducer.reduce(action, state), + onboardingWalletState = OnboardingWalletReducer.reduce(action, state), + onboardingOtherCardsState = OnboardingOtherCardsReducer.reduce(action, state), + walletState = WalletReducer.reduce(action, state), + twinCardsState = TwinCardsReducer.reduce(action, state), + sendState = SendScreenReducer.reduce(action, state.sendState), + detailsState = DetailsReducer.reduce(action, state), + disclaimerState = DisclaimerReducer.reduce(action, state), + tokensState = TokensReducer.reduce(action, state), + walletConnectState = WalletConnectReducer.reduce(action, state.walletConnectState) ) } diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt index 98827674a0..39b221f517 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt @@ -16,14 +16,14 @@ import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteMidd import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteState import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsMiddleware import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsState +import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsMiddleware +import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletMiddleware import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletState import com.tangem.tap.features.send.redux.middlewares.SendMiddleware import com.tangem.tap.features.send.redux.states.SendState import com.tangem.tap.features.tokens.redux.TokensMiddleware import com.tangem.tap.features.tokens.redux.TokensState -import com.tangem.tap.features.twins.redux.TwinCardsMiddleware -import com.tangem.tap.features.twins.redux.TwinCardsState import com.tangem.tap.features.wallet.redux.WalletState import com.tangem.tap.features.wallet.redux.middlewares.WalletMiddleware import org.rekotlin.Middleware 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 36e1a749a5..4334d55f59 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 /** @@ -11,7 +12,7 @@ sealed class AppDialog : StateDialog { object ScanFailsDialog : AppDialog() data class AddressInfoDialog( val addressData: AddressData, - val onCopyAddress: () -> Unit, - val onExploreAddress: () -> Unit + val onCopyAddress: VoidCallback, + val onExploreAddress: VoidCallback ) : AppDialog() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/FragmentShareTransition.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/FragmentShareTransition.kt new file mode 100644 index 0000000000..69547d020f --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/FragmentShareTransition.kt @@ -0,0 +1,35 @@ +package com.tangem.tap.common.redux.navigation + +import android.view.View +import androidx.transition.TransitionSet +import java.lang.ref.WeakReference + +/** +[REDACTED_AUTHOR] + */ +data class FragmentShareTransition( + val shareElements: List, + val enterTransitionSet: TransitionSet, + val exitTransitionSet: TransitionSet +) + +/** + * For ease of use, the name is used as transitionName\name into the FragmentTransaction.addSharedElement + */ +class ShareElement(view: View, name: String? = null) { + + val wView: WeakReference + val elementName: String + + init { + name?.let { view.transitionName = it } + elementName = view.transitionName + ?: throw UnsupportedOperationException("ShareElement require the name") + wView = WeakReference(view) + } + + companion object { + val imvFrontCard = "imv_front_card" + val imvBackCard = "imv_back_card" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationAction.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationAction.kt index 331dc07e1a..d2147ad3c6 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationAction.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationAction.kt @@ -1,8 +1,6 @@ package com.tangem.tap.common.redux.navigation -import android.view.View import androidx.fragment.app.FragmentActivity -import androidx.transition.TransitionSet import org.rekotlin.Action import java.lang.ref.WeakReference @@ -19,12 +17,4 @@ sealed class NavigationAction : Action { data class ActivityCreated(val activity: WeakReference) : NavigationAction() object ActivityDestroyed : NavigationAction() -} - -data class FragmentShareTransition( - val shareElements: List, - val enterTransitionSet: TransitionSet, - val exitTransitionSet: TransitionSet -) - -data class ShareElement(val wView: WeakReference, val name: String) \ No newline at end of file +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt index 4fa02150f0..61e3d263da 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt @@ -5,8 +5,8 @@ import org.rekotlin.StateType import java.lang.ref.WeakReference data class NavigationState( - val backStack: List = listOf(AppScreen.Home), - val activity: WeakReference? = null + val backStack: List = listOf(AppScreen.Home), + val activity: WeakReference? = null ) : StateType enum class AppScreen { @@ -16,7 +16,6 @@ enum class AppScreen { Wallet, WalletDetails, Send, Details, DetailsConfirm, DetailsSecurity, - CreateTwinWalletWarning, CreateTwinWallet, AddTokens, WalletConnectSessions, QrScan diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt b/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt index e08ba924b5..33aa1e1b4d 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt @@ -14,6 +14,7 @@ data class Config( val blockchainSdkConfig: BlockchainSdkConfig = BlockchainSdkConfig(), val isSendingToPayIdEnabled: Boolean = true, val isTopUpEnabled: Boolean = false, + @Deprecated("Not relevant since version 3.23") val isCreatingTwinCardsAllowed: Boolean = false ) @@ -50,10 +51,10 @@ class ConfigManager( fun resetToDefault(name: String) { when (name) { isSendingToPayIdEnabled -> config = - config.copy(isSendingToPayIdEnabled = defaultConfig.isSendingToPayIdEnabled) + config.copy(isSendingToPayIdEnabled = defaultConfig.isSendingToPayIdEnabled) isTopUpEnabled -> config = config.copy(isTopUpEnabled = defaultConfig.isTopUpEnabled) isCreatingTwinCardsAllowed -> config = - config.copy(isCreatingTwinCardsAllowed = defaultConfig.isCreatingTwinCardsAllowed) + config.copy(isCreatingTwinCardsAllowed = defaultConfig.isCreatingTwinCardsAllowed) } } diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt deleted file mode 100644 index 22a7e5ca87..0000000000 --- a/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt +++ /dev/null @@ -1,124 +0,0 @@ -package com.tangem.tap.domain.tasks - -import com.tangem.* -import com.tangem.common.CompletionResult -import com.tangem.common.card.Card -import com.tangem.common.card.FirmwareVersion -import com.tangem.common.core.CardSession -import com.tangem.common.core.CardSessionRunnable -import com.tangem.common.core.TangemError -import com.tangem.common.extensions.toHexString -import com.tangem.operations.ScanTask -import com.tangem.operations.issuerAndUserData.ReadIssuerDataCommand -import com.tangem.tap.domain.ProductType -import com.tangem.tap.domain.TapSdkError -import com.tangem.tap.domain.TapWorkarounds.isExcluded -import com.tangem.tap.domain.TapWorkarounds.isTangemNote -import com.tangem.tap.domain.extensions.getSingleWallet -import com.tangem.tap.domain.tasks.product.ScanResponse -import com.tangem.tap.domain.twins.TwinsHelper - -@Deprecated("Use ScanProductTask instead") -class ScanNoteTask(val card: Card? = null) : CardSessionRunnable { - - override fun run( - session: CardSession, - callback: (result: CompletionResult) -> Unit, - ) { - ScanTask().run(session) { result -> - when (result) { - is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error)) - - is CompletionResult.Success -> { - val card = this.card ?: result.data - - val error = getErrorIfExcludedCard(card) - if (error != null) { - callback(CompletionResult.Failure(error)) - return@run - } - - if (TwinsHelper.getTwinCardNumber(card.cardId) != null) { - dealWithTwinCard(card, session, callback) - } else if (!isTangemNote(card) && card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable) { - createMissingWalletsIfNeeded(card, session, callback) - } else { - callback(CompletionResult.Success( - ScanResponse(card, ProductType.Other, session.environment.walletData))) - } - } - } - } - } - - private fun createMissingWalletsIfNeeded( - card: Card, session: CardSession, - callback: (result: CompletionResult) -> Unit, - ) { - val walletData = session.environment.walletData - if (card.wallets.isEmpty()) { - callback(CompletionResult.Success(ScanResponse(card, ProductType.Other, walletData))) - return - } - - val curvesPresent = card.wallets.map { it.curve } -// val curvesToCreate = EllipticCurve.values().subtract(curvesPresent) - val curvesToCreate = card.supportedCurves.subtract(curvesPresent) - - if (curvesToCreate.isEmpty()) { - callback(CompletionResult.Success(ScanResponse(card, ProductType.Other, walletData))) - return - } - - CreateWalletsTask(curvesToCreate.toList()).run(session) { result -> - when (result) { - is CompletionResult.Success -> - callback(CompletionResult.Success(ScanResponse(result.data, ProductType.Other, walletData))) - is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error)) - } - } - - } - - private fun dealWithTwinCard( - card: Card, session: CardSession, - callback: (result: CompletionResult) -> Unit, - ) { - ReadIssuerDataCommand().run(session) { readDataResult -> - when (readDataResult) { - is CompletionResult.Success -> { - val publicKey = card.getSingleWallet()?.publicKey - if (publicKey == null) { - callback(CompletionResult.Success(ScanResponse(card, ProductType.Other, null))) - return@run - } - val verified = TwinsHelper.verifyTwinPublicKey( - readDataResult.data.issuerData, publicKey - ) - if (verified) { - val twinPublicKey = readDataResult.data.issuerData.sliceArray(0 until 65) - callback(CompletionResult.Success( - ScanResponse( - card = card, - ProductType.Other, - walletData = session.environment.walletData, - secondTwinPublicKey = twinPublicKey.toHexString()) - )) - return@run - } else { - callback(CompletionResult.Success(ScanResponse(card, ProductType.Other, null))) - } - } - is CompletionResult.Failure -> - callback(CompletionResult.Success(ScanResponse(card, ProductType.Other, null))) - } - } - } - - private fun getErrorIfExcludedCard(card: Card): TangemError? { - if (card.isExcluded()) return TapSdkError.CardForDifferentApp - // Disable new multi-currency HD wallet cards on the old version of the app -// if (card.isMultiCurrencyWallet()) return UpdateAppToUseThisCard() - return null - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt index 0024a37cd8..e16ccd79cb 100644 --- a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt @@ -4,44 +4,45 @@ import com.squareup.moshi.JsonAdapter import com.squareup.moshi.Types import com.tangem.Message import com.tangem.blockchain.extensions.Result -import com.tangem.blockchain.extensions.SimpleResult import com.tangem.common.CompletionResult import com.tangem.common.KeyPair +import com.tangem.common.card.Card import com.tangem.common.core.TangemSdkError import com.tangem.common.extensions.hexToBytes import com.tangem.common.extensions.toHexString +import com.tangem.operations.wallet.CreateWalletResponse import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler import com.tangem.tap.domain.tasks.product.ScanResponse import com.tangem.tap.network.createMoshi import com.tangem.tap.tangemSdkManager -class TwinCardsManager(private val scanResponse: ScanResponse, assetReader: AssetReader) { +class TwinCardsManager(private val card: Card, assetReader: AssetReader) { - private val currentCardId: String = scanResponse.card.cardId + private val currentCardId: String = card.cardId private var currentCardPublicKey: String? = null private var secondCardPublicKey: String? = null - private val issuerKeyPair: KeyPair = getIssuerKeys(assetReader, scanResponse.card.issuer.publicKey.toHexString()) + private val issuerKeyPair: KeyPair = getIssuerKeys(assetReader, card.issuer.publicKey.toHexString()) - suspend fun createFirstWallet(message: Message): SimpleResult { + suspend fun createFirstWallet(message: Message): CompletionResult { val response = tangemSdkManager.runTaskAsync( CreateFirstTwinWalletTask(), currentCardId, message ) when (response) { is CompletionResult.Success -> { currentCardPublicKey = response.data.wallet.publicKey.toHexString() - return SimpleResult.Success + return response } is CompletionResult.Failure -> { (response.error as? TangemSdkError)?.let { error -> FirebaseAnalyticsHandler.logCardSdkError( error, FirebaseAnalyticsHandler.ActionToLog.CreateWallet, - card = scanResponse.card + card = card ) } - return SimpleResult.failure(response.error) + return response } } @@ -52,7 +53,7 @@ class TwinCardsManager(private val scanResponse: ScanResponse, assetReader: Asse initialMessage: Message, preparingMessage: Message, creatingWalletMessage: Message, - ): SimpleResult { + ): CompletionResult { val task = CreateSecondTwinWalletTask( firstPublicKey = currentCardPublicKey!!, firstCardId = currentCardId, @@ -64,20 +65,18 @@ class TwinCardsManager(private val scanResponse: ScanResponse, assetReader: Asse when (response) { is CompletionResult.Success -> { secondCardPublicKey = response.data.wallet.publicKey.toHexString() - return SimpleResult.Success } is CompletionResult.Failure -> { (response.error as? TangemSdkError)?.let { error -> FirebaseAnalyticsHandler.logCardSdkError( error, FirebaseAnalyticsHandler.ActionToLog.CreateWallet, - card = scanResponse.card + card = card ) } - return SimpleResult.failure(response.error) } } - + return response } suspend fun complete(message: Message): Result { @@ -92,7 +91,7 @@ class TwinCardsManager(private val scanResponse: ScanResponse, assetReader: Asse FirebaseAnalyticsHandler.logCardSdkError( error, FirebaseAnalyticsHandler.ActionToLog.WriteIssuerData, - card = scanResponse.card + card = card ) } Result.failure(response.error) diff --git a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsWidget.kt b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsWidget.kt index 63f891eb4d..c8f3c02952 100644 --- a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsWidget.kt +++ b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsWidget.kt @@ -5,6 +5,7 @@ import android.animation.ObjectAnimator import android.animation.PropertyValuesHolder import android.view.View import androidx.core.animation.doOnEnd +import com.tangem.common.extensions.VoidCallback import com.tangem.tap.common.leapfrogWidget.LeapView import com.tangem.tap.common.leapfrogWidget.LeapViewState import com.tangem.tap.common.leapfrogWidget.LeapfrogWidget @@ -17,47 +18,60 @@ class TwinsCardWidget( val getTopOfAnchorViewForActivateState: () -> Float ) { + var state: TwinCardsWidgetState? = null + private set + + private val animationDuration = 300L + init { if (leapfrogWidget.getViewsCount() != 2) throw UnsupportedOperationException() } - fun toWelcome(animate: Boolean = true, onEnd: () -> Unit = {}) { - val animator = createAnimator(animate, onEnd) + fun toWelcome(animate: Boolean = true, onEnd: VoidCallback = {}) { + if (state == TwinCardsWidgetState.Welcome) return + + state = TwinCardsWidgetState.Welcome + val animator = createAnimator(animate) animator.playTogether( createAnimator(TwinCardNumber.First, createWelcomeProperties(TwinCardNumber.First)), createAnimator(TwinCardNumber.Second, createWelcomeProperties(TwinCardNumber.Second)) ) - leapfrogWidget.fold { animator.start() } + animator.doOnEnd { onEnd() } + leapfrogWidget.fold(animate) { animator.start() } } - fun toLeapfrog(animate: Boolean = true, onEnd: () -> Unit = {}) { - val animator = createAnimator(animate, onEnd) + fun toLeapfrog(animate: Boolean = true, onEnd: VoidCallback = {}) { + if (state == TwinCardsWidgetState.Leapfrog) return + + state = TwinCardsWidgetState.Leapfrog + val animator = createAnimator(animate) animator.playTogether( createAnimator(TwinCardNumber.First, createLeapfrogProperties(TwinCardNumber.First)), createAnimator(TwinCardNumber.Second, createLeapfrogProperties(TwinCardNumber.Second)) ) - leapfrogWidget.fold { - animator.doOnEnd { - leapfrogWidget.initViews() - leapfrogWidget.unfold() - } - animator.start() + animator.doOnEnd { + leapfrogWidget.initViews() + leapfrogWidget.unfold(animate, onEnd) } + animator.start() } - fun toActivate(animate: Boolean = true, onEnd: () -> Unit = {}) { - val animator = createAnimator(animate, onEnd) + fun toActivate(animate: Boolean = true, onEnd: VoidCallback = {}) { + if (state == TwinCardsWidgetState.Activate) return + + state = TwinCardsWidgetState.Activate + val animator = createAnimator(animate) animator.playTogether( createAnimator(TwinCardNumber.First, createActivateProperties(TwinCardNumber.First)), createAnimator(TwinCardNumber.Second, createActivateProperties(TwinCardNumber.Second)) ) + animator.doOnEnd { onEnd() } animator.start() } - private fun createAnimator(animate: Boolean, onEnd: () -> Unit): AnimatorSet { + private fun createAnimator(animate: Boolean): AnimatorSet { return AnimatorSet().apply { - duration = if (animate) 400 else 0 - doOnEnd { onEnd() } + duration = if (animate) animationDuration else 0 } } @@ -72,20 +86,20 @@ class TwinsCardWidget( return when (cardNumber) { TwinCardNumber.First -> { TwinsCardProperties( - xTranslation = -180f, - yTranslation = -350f, + xTranslation = -120f, + yTranslation = -220f, rotation = -3f, elevation = 1f, - scale = 1.1f, + scale = 1f, ) } TwinCardNumber.Second -> { TwinsCardProperties( - xTranslation = 180f, - yTranslation = 10f, + xTranslation = 170f, + yTranslation = 170f, rotation = -3f, elevation = 0f, - scale = 1.1f, + scale = 1f, ) } } @@ -108,7 +122,7 @@ class TwinsCardWidget( xTranslation = twinProperties.xTranslation, yTranslation = twinProperties.yTranslation - topOfAnchorView, rotation = 0f, - scale = twinProperties.scale - 0.4f, + scale = twinProperties.scale - 0.5f, ) } @@ -120,6 +134,10 @@ class TwinsCardWidget( } } +enum class TwinCardsWidgetState { + Welcome, Leapfrog, Activate +} + private data class TwinsCardProperties( val xTranslation: Float = 0f, val yTranslation: Float = 0f, diff --git a/app/src/main/java/com/tangem/tap/features/send/BaseStoreFragment.kt b/app/src/main/java/com/tangem/tap/features/BaseFragment.kt similarity index 56% rename from app/src/main/java/com/tangem/tap/features/send/BaseStoreFragment.kt rename to app/src/main/java/com/tangem/tap/features/BaseFragment.kt index bb3046db5e..8e1c2e098a 100644 --- a/app/src/main/java/com/tangem/tap/features/send/BaseStoreFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/BaseFragment.kt @@ -1,26 +1,26 @@ -package com.tangem.tap.features.send +package com.tangem.tap.features +import android.annotation.SuppressLint import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.activity.OnBackPressedCallback +import androidx.appcompat.widget.Toolbar import androidx.fragment.app.Fragment import androidx.transition.TransitionInflater import com.google.android.material.snackbar.Snackbar +import com.tangem.common.extensions.VoidCallback +import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.store import com.tangem.wallet.R -import kotlinx.android.synthetic.main.fragment_wallet.* -import org.rekotlin.StoreSubscriber /** [REDACTED_AUTHOR] */ -abstract class BaseStoreFragment(layoutId: Int) : Fragment(layoutId) { - - abstract fun subscribeToStore() +abstract class BaseFragment(layoutId: Int) : Fragment(layoutId), FragmentOnBackPressedHandler { protected lateinit var mainView: View - protected val storeSubscribersList = mutableListOf>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -40,26 +40,32 @@ abstract class BaseStoreFragment(layoutId: Int) : Fragment(layoutId) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - toolbar?.setNavigationOnClickListener { activity?.onBackPressed() } + addBackPressHandler(this) } - override fun onStart() { - super.onStart() - subscribeToStore() + override fun handleOnBackPressed() { + store.dispatch(NavigationAction.PopBackTo()) } - - override fun onStop() { - storeSubscribersList.forEach { store.unsubscribe(it) } - storeSubscribersList.clear() - super.onStop() - } - - fun showRetrySnackbar(message: String, action: () -> Unit) { + fun showRetrySnackbar(message: String, action: VoidCallback) { val snackbar = Snackbar.make(mainView, message, Snackbar.LENGTH_INDEFINITE) snackbar.setAction(getString(R.string.common_retry)) { snackbar.dismiss() action() }.show() } +} + +interface FragmentOnBackPressedHandler { + fun handleOnBackPressed() +} + +@SuppressLint("FragmentBackPressedCallback") +fun Fragment.addBackPressHandler(handler: FragmentOnBackPressedHandler) { + activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + handler.handleOnBackPressed() + } + }) + view?.findViewById(R.id.toolbar)?.setNavigationOnClickListener { activity?.onBackPressed() } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/BaseStoreFragment.kt b/app/src/main/java/com/tangem/tap/features/BaseStoreFragment.kt new file mode 100644 index 0000000000..b4f486a1a2 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/BaseStoreFragment.kt @@ -0,0 +1,24 @@ +package com.tangem.tap.features + +import com.tangem.tap.store +import org.rekotlin.StoreSubscriber + +/** +[REDACTED_AUTHOR] + */ +abstract class BaseStoreFragment(layoutId: Int) : BaseFragment(layoutId) { + + abstract fun subscribeToStore() + protected val storeSubscribersList = mutableListOf>() + + override fun onStart() { + super.onStart() + subscribeToStore() + } + + override fun onStop() { + storeSubscribersList.forEach { store.unsubscribe(it) } + storeSubscribersList.clear() + super.onStop() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index 9192ef3043..22bbd11511 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -11,8 +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.features.disclaimer.redux.DisclaimerAction -import com.tangem.tap.features.onboarding.twins.redux.CreateTwinWalletMode -import com.tangem.tap.features.onboarding.twins.redux.TwinCardsAction +import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode +import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.wallet.models.hasSendableAmountsOrPendingTransactions import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.network.coinmarketcap.CoinMarketCapService diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt index 271f51cc97..40f409c680 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt @@ -6,7 +6,7 @@ import com.tangem.common.card.Card import com.tangem.tap.common.entities.Button import com.tangem.tap.common.entities.TapCurrency.Companion.DEFAULT_FIAT_CURRENCY import com.tangem.tap.common.redux.global.FiatCurrencyName -import com.tangem.tap.features.onboarding.twins.redux.TwinCardsState +import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState import com.tangem.tap.network.coinmarketcap.FiatCurrency import com.tangem.tap.store import org.rekotlin.StateType diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt index 31d11dbc31..cb51e326dd 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/DetailsFragment.kt @@ -6,7 +6,6 @@ import android.view.View import androidx.activity.OnBackPressedCallback import androidx.fragment.app.Fragment import androidx.transition.TransitionInflater -import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.show import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.navigation.AppScreen @@ -16,8 +15,6 @@ import com.tangem.tap.features.details.redux.DetailsAction import com.tangem.tap.features.details.redux.DetailsState import com.tangem.tap.features.details.redux.SecurityOption import com.tangem.tap.features.feedback.FeedbackEmail -import com.tangem.tap.features.twins.redux.CreateTwinWalletMode -import com.tangem.tap.features.twins.redux.TwinCardsAction import com.tangem.tap.store import com.tangem.wallet.R import kotlinx.android.synthetic.main.fragment_details.* @@ -91,17 +88,10 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber() { private lateinit var btnScanCard: ViewStateWidget - override fun getOnboardingTopContainerId(): Int = R.layout.layout_onboarding_home + override fun getOnboardingTopContainerId(): Int = R.layout.layout_onboarding_home_top override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -38,7 +37,10 @@ class HomeFragment : BaseOnboardingFragment() { toolbar.hide() val shareTransition = FragmentShareTransition( - listOf(ShareElement(WeakReference(imv_front_card), imv_front_card.transitionName)), + listOf( + ShareElement(imv_front_card, ShareElement.imvFrontCard), + ShareElement(imv_back_card, ShareElement.imvBackCard) + ), FrontCardEnterTransition(), FrontCardExitTransition() ) @@ -62,6 +64,7 @@ class HomeFragment : BaseOnboardingFragment() { oldState.homeState == newState.homeState }.select { it.homeState } } + storeSubscribersList.add(this) } override fun newState(state: HomeState) { diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt index 4de7177c34..bd5cdcffff 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt @@ -2,6 +2,8 @@ package com.tangem.tap.features.home.redux import com.tangem.tap.common.entities.IndeterminateProgressButton import com.tangem.tap.common.extensions.dispatchOpenUrl +import com.tangem.tap.common.extensions.onCardScanned +import com.tangem.tap.common.extensions.withMainContext import com.tangem.tap.common.post import com.tangem.tap.common.postUi import com.tangem.tap.common.redux.AppState @@ -10,10 +12,10 @@ import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.FragmentShareTransition import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.DELAY_SDK_DIALOG_CLOSE -import com.tangem.tap.domain.twins.getTwinCardNumber import com.tangem.tap.features.onboarding.OnboardingHelper +import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction +import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep import com.tangem.tap.features.send.redux.states.ButtonState -import com.tangem.tap.features.twins.redux.TwinCardsAction import com.tangem.tap.preferencesStorage import com.tangem.tap.scope import com.tangem.tap.store @@ -58,21 +60,24 @@ private fun handleReadCard() { } else { changeButtonState(ButtonState.PROGRESS) store.dispatch(GlobalAction.ScanCard({ scanResponse -> - if (scanResponse.isTangemTwins()) { - scanResponse.card.getTwinCardNumber()?.let { - val configManager = store.state.globalState.configManager - val isCreatingTwinsAllowed = configManager?.config?.isCreatingTwinCardsAllowed ?: false - store.dispatch(TwinCardsAction.SetTwinCard(it, null, isCreatingTwinsAllowed)) - } - } + store.dispatch(TwinCardsAction.IfTwinsPrepareState(scanResponse)) if (OnboardingHelper.isOnboardingCase(scanResponse)) { val navigateTo = OnboardingHelper.whereToNavigate(scanResponse) store.dispatch(GlobalAction.Onboarding.Start(scanResponse)) navigateTo(navigateTo, store.state.homeState.shareTransition) } else { - scope.launch { store.state.globalState.tapWalletManager.onCardScanned(scanResponse) } - navigateTo(AppScreen.Wallet, null) + scope.launch { + store.onCardScanned(scanResponse) + withMainContext { + if (scanResponse.twinsIsTwinned() && !preferencesStorage.wasTwinsOnboardingShown()) { + store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.WelcomeOnly)) + navigateTo(AppScreen.OnboardingTwins, store.state.homeState.shareTransition) + } else { + navigateTo(AppScreen.Wallet, null) + } + } + } } }, { changeButtonState(ButtonState.ENABLED) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/BaseOnboardingFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/BaseOnboardingFragment.kt index 7cdbff7733..b33b3118f5 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/BaseOnboardingFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/BaseOnboardingFragment.kt @@ -5,7 +5,7 @@ import android.view.View import com.tangem.tap.common.extensions.inflate import com.tangem.tap.common.extensions.show import com.tangem.tap.common.transitions.HomeToOnboardingTransition -import com.tangem.tap.features.send.BaseStoreFragment +import com.tangem.tap.features.BaseStoreFragment import com.tangem.wallet.R import kotlinx.android.synthetic.main.fragment_onboarding_main.* import kotlinx.android.synthetic.main.view_confetti.* @@ -16,11 +16,6 @@ import org.rekotlin.StoreSubscriber */ abstract class BaseOnboardingFragment : BaseStoreFragment(R.layout.fragment_onboarding_main), StoreSubscriber { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - configureTransitions() - } - override fun configureTransitions() { enterTransition = HomeToOnboardingTransition() exitTransition = HomeToOnboardingTransition() diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt index 173662c65e..80b671393f 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt @@ -16,18 +16,18 @@ import com.tangem.tangem_sdk_new.extensions.fadeOut import com.tangem.tap.common.extensions.getDrawableCompat import com.tangem.tap.common.extensions.stripZeroPlainString import com.tangem.tap.common.postUi +import com.tangem.tap.common.redux.navigation.ShareElement import com.tangem.tap.common.toggleWidget.RefreshBalanceWidget import com.tangem.tap.common.transitions.InternalNoteLayoutTransition import com.tangem.tap.features.onboarding.products.BaseOnboardingFragment import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteAction -import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteResources import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteState import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteStep import com.tangem.tap.store import com.tangem.wallet.R import kotlinx.android.synthetic.main.fragment_onboarding_main.* -import kotlinx.android.synthetic.main.layout_onboarding_bottom_action_views.* -import kotlinx.android.synthetic.main.layout_onboarding_note.* +import kotlinx.android.synthetic.main.layout_onboarding_container_bottom.* +import kotlinx.android.synthetic.main.layout_onboarding_container_top.* import kotlinx.android.synthetic.main.view_onboarding_progress.* import kotlinx.android.synthetic.main.view_onboarding_tv_balance.* @@ -36,23 +36,26 @@ import kotlinx.android.synthetic.main.view_onboarding_tv_balance.* */ class OnboardingNoteFragment : BaseOnboardingFragment() { - private lateinit var btnRefreshBalanceWidget: RefreshBalanceWidget - private var currentStep: OnboardingNoteStep = OnboardingNoteStep.None + private var previousStep: OnboardingNoteStep = OnboardingNoteStep.None - override fun getOnboardingTopContainerId(): Int = R.layout.layout_onboarding_note + private lateinit var btnRefreshBalanceWidget: RefreshBalanceWidget + + override fun getOnboardingTopContainerId(): Int = R.layout.layout_onboarding_container_top + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + postponeEnterTransition() + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + imv_front_card.transitionName = ShareElement.imvFrontCard + startPostponedEnterTransition() + toolbar.setTitle(R.string.onboarding_title) btnRefreshBalanceWidget = RefreshBalanceWidget(onboarding_main_container) - val resources = OnboardingNoteResources( - OnboardingNoteResources.Strings( - R.string.copy_toast_msg - ) - ) - store.dispatch(OnboardingNoteAction.SetResources(resources)) store.dispatch(OnboardingNoteAction.LoadCardArtwork) store.dispatch(OnboardingNoteAction.DetermineStepOfScreen) } @@ -81,7 +84,7 @@ class OnboardingNoteFragment : BaseOnboardingFragment() { } setBalance(state) showConfetti(state.showConfetti) - currentStep = state.currentStep + previousStep = state.currentStep } private fun setBalance(state: OnboardingNoteState) { @@ -166,7 +169,7 @@ class OnboardingNoteFragment : BaseOnboardingFragment() { } private fun updateConstraints(currentStep: OnboardingNoteStep, @LayoutRes layoutId: Int) { - if (this.currentStep == currentStep) return + if (this.previousStep == currentStep) return val constraintSet = ConstraintSet() constraintSet.clone(requireContext(), layoutId) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt index 859e1104fa..73b588ee69 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt @@ -10,7 +10,6 @@ import org.rekotlin.Action */ sealed class OnboardingNoteAction : Action { // from user, ui - data class SetResources(val resources: OnboardingNoteResources) : OnboardingNoteAction() object LoadCardArtwork : OnboardingNoteAction() object CreateWallet : OnboardingNoteAction() object TopUp : OnboardingNoteAction() 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 8267514eb0..0ef12f9c8f 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 @@ -12,6 +12,7 @@ import com.tangem.tap.common.redux.navigation.NavigationAction 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.wallet.redux.Currency import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.scope import com.tangem.tap.store @@ -107,6 +108,7 @@ private fun handleNoteAction(action: Action, dispatch: DispatchFunction) { val isLoadedBefore = noteState.walletBalance.state != ProgressState.Loading val balanceIsLoading = noteState.walletBalance.copy( + currency = Currency.Blockchain(walletManager.wallet.blockchain), state = ProgressState.Loading, error = null, criticalError = null @@ -128,7 +130,7 @@ private fun handleNoteAction(action: Action, dispatch: DispatchFunction) { } is OnboardingNoteAction.ShowAddressInfoDialog -> { val addressData = noteState.walletManager?.getAddressData() ?: return - val addressWasCopied = noteState.resources.strings.addressWasCopied + val addressWasCopied = globalState.resources.strings.addressWasCopied val appDialog = AppDialog.AddressInfoDialog( addressData, onCopyAddress = { store.dispatchToastNotification(addressWasCopied) }, @@ -143,7 +145,7 @@ private fun handleNoteAction(action: Action, dispatch: DispatchFunction) { OnboardingNoteAction.Done -> { store.dispatch(GlobalAction.Onboarding.Stop) scope.launch { - globalState.tapWalletManager.onCardScanned(scanResponse) + store.onCardScanned(scanResponse) store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet)) } } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteReducer.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteReducer.kt index c88906cb20..206a4893ab 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteReducer.kt @@ -23,9 +23,6 @@ private fun internalReduce(action: Action, appState: AppState): OnboardingNoteSt is OnboardingNoteAction.SetWalletManager -> { state = state.copy(walletManager = action.walletManager) } - is OnboardingNoteAction.SetResources -> { - state = state.copy(resources = action.resources) - } is OnboardingNoteAction.Balance.Set -> { state = state.copy(walletBalance = action.balance) } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteState.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteState.kt index 33c5cbdd7d..23def7368f 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteState.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteState.kt @@ -10,7 +10,6 @@ import org.rekotlin.StateType */ data class OnboardingNoteState( val walletManager: WalletManager? = null, - val resources: OnboardingNoteResources = OnboardingNoteResources(), // UI val cardArtwork: Artwork? = null, val walletBalance: OnboardingWalletBalance = OnboardingWalletBalance.loading(), @@ -25,12 +24,4 @@ data class OnboardingNoteState( enum class OnboardingNoteStep { None, CreateWallet, TopUpWallet, Done -} - -data class OnboardingNoteResources( - val strings: Strings = Strings() -) { - data class Strings( - val addressWasCopied: Int = -1 - ) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt index abfb32f6d5..f57e92fe03 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt @@ -8,16 +8,18 @@ import androidx.constraintlayout.widget.ConstraintSet import androidx.core.view.isVisible import androidx.transition.TransitionManager import com.tangem.tap.common.extensions.getDrawableCompat +import com.tangem.tap.common.redux.navigation.ShareElement import com.tangem.tap.common.transitions.InternalNoteLayoutTransition import com.tangem.tap.features.onboarding.products.BaseOnboardingFragment +import com.tangem.tap.features.onboarding.products.note.swapToBitmapDrawable import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsAction import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsState import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsStep import com.tangem.tap.store import com.tangem.wallet.R import kotlinx.android.synthetic.main.fragment_onboarding_main.* -import kotlinx.android.synthetic.main.layout_onboarding_bottom_action_views.* -import kotlinx.android.synthetic.main.layout_onboarding_note.* +import kotlinx.android.synthetic.main.layout_onboarding_container_bottom.* +import kotlinx.android.synthetic.main.layout_onboarding_container_top.* import kotlinx.android.synthetic.main.view_onboarding_progress.* /** @@ -25,11 +27,19 @@ import kotlinx.android.synthetic.main.view_onboarding_progress.* */ class OnboardingOtherCardsFragment : BaseOnboardingFragment() { - override fun getOnboardingTopContainerId(): Int = R.layout.layout_onboarding_note + override fun getOnboardingTopContainerId(): Int = R.layout.layout_onboarding_container_top + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + postponeEnterTransition() + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + imv_front_card.transitionName = ShareElement.imvFrontCard + startPostponedEnterTransition() + toolbar.setTitle(R.string.onboarding_title) store.dispatch(OnboardingOtherCardsAction.LoadCardArtwork) store.dispatch(OnboardingOtherCardsAction.DetermineStepOfScreen) 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 6fea776c74..fd2dbee87d 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,6 +1,7 @@ package com.tangem.tap.features.onboarding.products.otherCards.redux import com.tangem.common.CompletionResult +import com.tangem.tap.common.extensions.onCardScanned import com.tangem.tap.common.extensions.withMainContext import com.tangem.tap.common.postUi import com.tangem.tap.common.redux.AppState @@ -83,7 +84,7 @@ private fun handleOtherCardsAction(action: Action, dispatch: DispatchFunction) { OnboardingOtherCardsAction.Done -> { store.dispatch(GlobalAction.Onboarding.Stop) scope.launch { - globalState.tapWalletManager.onCardScanned(onboardingManager.scanResponse) + store.onCardScanned(onboardingManager.scanResponse) store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet)) } } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/OnboardingTwinsFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/OnboardingTwinsFragment.kt deleted file mode 100644 index 684d05324e..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/OnboardingTwinsFragment.kt +++ /dev/null @@ -1,72 +0,0 @@ -package com.tangem.tap.features.onboarding.products.twins - -import android.os.Bundle -import android.view.View -import androidx.activity.OnBackPressedCallback -import androidx.fragment.app.Fragment -import androidx.transition.TransitionInflater -import com.squareup.picasso.Picasso -import com.tangem.tap.common.extensions.dispatchDebugErrorNotification -import com.tangem.tap.common.extensions.withMainContext -import com.tangem.tap.common.redux.navigation.AppScreen -import com.tangem.tap.common.redux.navigation.NavigationAction -import com.tangem.tap.features.twins.redux.TwinCardsAction -import com.tangem.tap.features.wallet.redux.Artwork -import com.tangem.tap.scope -import com.tangem.tap.store -import com.tangem.wallet.R -import kotlinx.android.synthetic.main.fragment_twin_cards_welcome.* -import kotlinx.android.synthetic.main.layout_twin_cards.* -import kotlinx.coroutines.launch - -class OnboardingTwinsFragment : Fragment(R.layout.fragment_twin_cards_welcome) { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) - } - }) - val inflater = TransitionInflater.from(requireContext()) - enterTransition = inflater.inflateTransition(R.transition.slide_right) - exitTransition = inflater.inflateTransition(R.transition.fade) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - store.dispatch(TwinCardsAction.SetOnboardingShown) - val secondTwinNumber = store.state.twinCardsState.cardNumber?.pairNumber()?.number ?: "" - val text = getString(R.string.twins_onboarding_description_format, secondTwinNumber) - tv_twin_cards_description_1.text = text - - setOnClickListeners() - - Picasso.get() - .load(Artwork.TWIN_CARD_1) - .placeholder(R.drawable.card_placeholder) - ?.error(R.drawable.card_placeholder) - ?.into(iv_twin_card_1) - - Picasso.get() - .load(Artwork.TWIN_CARD_2) - .placeholder(R.drawable.card_placeholder) - ?.error(R.drawable.card_placeholder) - ?.into(iv_twin_card_2) - } - - private fun setOnClickListeners() { - btn_continue.setOnClickListener { - scope.launch { - val global = store.state.globalState - val scanResponse = global.onboardingManager?.scanResponse ?: return@launch - global.tapWalletManager.onCardScanned(scanResponse) - withMainContext { - store.dispatchDebugErrorNotification("Делаем онбоардинг") - store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet)) - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsAction.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsAction.kt new file mode 100644 index 0000000000..7d48937c17 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsAction.kt @@ -0,0 +1,64 @@ +package com.tangem.tap.features.onboarding.products.twins.redux + +import com.tangem.Message +import com.tangem.blockchain.common.WalletManager +import com.tangem.common.extensions.VoidCallback +import com.tangem.tap.common.redux.StateDialog +import com.tangem.tap.domain.tasks.product.ScanResponse +import com.tangem.tap.domain.twins.AssetReader +import com.tangem.tap.domain.twins.TwinCardsManager +import com.tangem.tap.features.onboarding.OnboardingWalletBalance +import org.rekotlin.Action + +/** +[REDACTED_AUTHOR] + */ +sealed class TwinCardsAction : Action { + data class IfTwinsPrepareState(val scanResponse: ScanResponse) : TwinCardsAction() + + object Init : TwinCardsAction() + data class SetMode(val mode: CreateTwinWalletMode) : TwinCardsAction() + data class SetStepOfScreen(val step: TwinCardsStep) : TwinCardsAction() + data class SetUserUnderstand(val isUnderstand: Boolean) : TwinCardsAction() + + sealed class CardsManager { + data class Set(val manager: TwinCardsManager) : TwinCardsAction() + object Release : TwinCardsAction() + } + + sealed class Wallet : TwinCardsAction() { + data class HandleOnBackPressed( + // this is necessary for the correct animation of the return of cards to the Home screen + val shouldResetTwinCardsWidget: (should: Boolean, popAction: VoidCallback) -> Unit + ) : TwinCardsAction() + + data class ShowInterruptDialog(val onOk: VoidCallback) : TwinCardsAction(), StateDialog + + data class LaunchFirstStep(val initialMessage: Message, val reader: AssetReader) : TwinCardsAction() + data class LaunchSecondStep( + val initialMessage: Message, + val preparingMessage: Message, + val creatingWalletMessage: Message, + ) : TwinCardsAction() + + data class LaunchThirdStep(val message: Message) : TwinCardsAction() + } + + + // for the onboarding + data class SetPairCardId(val cardId: String) : TwinCardsAction() + object TopUp : TwinCardsAction() + object ShowAddressInfoDialog : TwinCardsAction() + data class SetWalletManager(val walletManager: WalletManager) : TwinCardsAction() + object Done : TwinCardsAction() + + sealed class Balance { + object Update : TwinCardsAction() + data class Set(val balance: OnboardingWalletBalance) : TwinCardsAction() + } + + sealed class Confetti { + object Show : TwinCardsAction() + object Hide : TwinCardsAction() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt new file mode 100644 index 0000000000..f56502e209 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt @@ -0,0 +1,275 @@ +package com.tangem.tap.features.onboarding.products.twins.redux + +import com.tangem.blockchain.extensions.Result +import com.tangem.common.CompletionResult +import com.tangem.common.extensions.guard +import com.tangem.tap.common.extensions.* +import com.tangem.tap.common.postUi +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.AppScreen +import com.tangem.tap.common.redux.navigation.NavigationAction +import com.tangem.tap.domain.DELAY_SDK_DIALOG_CLOSE +import com.tangem.tap.domain.TapError +import com.tangem.tap.domain.extensions.makePrimaryWalletManager +import com.tangem.tap.domain.tasks.product.ScanResponse +import com.tangem.tap.domain.twins.TwinCardsManager +import com.tangem.tap.features.wallet.redux.Currency +import com.tangem.tap.features.wallet.redux.ProgressState +import com.tangem.tap.preferencesStorage +import com.tangem.tap.scope +import com.tangem.tap.store +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import org.rekotlin.Action +import org.rekotlin.DispatchFunction +import org.rekotlin.Middleware + +class TwinCardsMiddleware { + companion object { + val handler = twinsWalletMiddleware + } +} + +private val twinsWalletMiddleware: Middleware = { dispatch, state -> + { next -> + { action -> + handle(action, dispatch) + next(action) + } + } +} + +private fun handle(action: Action, dispatch: DispatchFunction) { + val action = action as? TwinCardsAction ?: return + + val globalState = store.state.globalState + val onboardingManager = globalState.onboardingManager + val twinCardsState = store.state.twinCardsState + + fun getScanResponse(): ScanResponse { + return when (twinCardsState.mode) { + CreateTwinWalletMode.CreateWallet -> onboardingManager?.scanResponse + CreateTwinWalletMode.RecreateWallet -> globalState.scanResponse + } ?: throw NullPointerException("ScanResponse can't be NULL") + } + + fun updateScanResponse(response: ScanResponse) { + when (twinCardsState.mode) { + CreateTwinWalletMode.CreateWallet -> onboardingManager?.scanResponse = response + CreateTwinWalletMode.RecreateWallet -> store.dispatch(GlobalAction.SaveScanNoteResponse(response)) + } + } + + fun startCardActivation(cardId: String) { + if (twinCardsState.mode == CreateTwinWalletMode.CreateWallet) { + onboardingManager?.activationStarted(cardId) + } + } + + fun finishCardActivation() { + if (twinCardsState.mode == CreateTwinWalletMode.CreateWallet) { + onboardingManager?.activationFinished(getScanResponse().card.cardId) + twinCardsState.pairCardId?.let { onboardingManager?.activationFinished(it) } + + } + } + + when (action) { + is TwinCardsAction.Init -> { + if (twinCardsState.currentStep == TwinCardsStep.WelcomeOnly) return + + when (twinCardsState.mode) { + CreateTwinWalletMode.CreateWallet -> { + if (preferencesStorage.wasTwinsOnboardingShown()) { + val step = when { + !getScanResponse().twinsIsTwinned() -> TwinCardsStep.CreateFirstWallet + twinCardsState.walletBalance.balanceIsToppedUp() -> TwinCardsStep.Done + else -> TwinCardsStep.TopUpWallet + } + store.dispatch((TwinCardsAction.SetStepOfScreen(step))) + } else { + store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.Welcome)) + } + } + CreateTwinWalletMode.RecreateWallet -> { + store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.Warning)) + } + } + } + is TwinCardsAction.Wallet.HandleOnBackPressed -> { + val shouldReturnCardBack = twinCardsState.mode == CreateTwinWalletMode.CreateWallet + && twinCardsState.currentStep != TwinCardsStep.TopUpWallet + && twinCardsState.currentStep != TwinCardsStep.Done + + if (twinCardsState.showAlert) { + val onInterruptPrompt = { + store.dispatch(TwinCardsAction.CardsManager.Release) + action.shouldResetTwinCardsWidget(shouldReturnCardBack) { + store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) + } + } + val stateDialog = TwinCardsAction.Wallet.ShowInterruptDialog(onInterruptPrompt) + store.dispatchDialogShow(stateDialog) + } else { + store.dispatch(TwinCardsAction.CardsManager.Release) + action.shouldResetTwinCardsWidget(shouldReturnCardBack) { + store.dispatch(NavigationAction.PopBackTo()) + } + } + } + is TwinCardsAction.SetStepOfScreen -> { + when (action.step) { + TwinCardsStep.WelcomeOnly -> { + preferencesStorage.saveTwinsOnboardingShown() + } + TwinCardsStep.Welcome -> { + preferencesStorage.saveTwinsOnboardingShown() + } + TwinCardsStep.Warning -> { + } + TwinCardsStep.CreateFirstWallet -> { + } + TwinCardsStep.CreateSecondWallet -> { + } + TwinCardsStep.CreateThirdWallet -> { + } + TwinCardsStep.TopUpWallet -> { + store.dispatch(TwinCardsAction.Balance.Update) + } + TwinCardsStep.Done -> { + finishCardActivation() + postUi(500) { store.dispatch(TwinCardsAction.Confetti.Show) } + } + } + } + is TwinCardsAction.Wallet.LaunchFirstStep -> { + val manager = TwinCardsManager(getScanResponse().card, action.reader) + store.dispatch(TwinCardsAction.CardsManager.Set(manager)) + + scope.launch { + when (val result = manager.createFirstWallet(action.initialMessage)) { + is CompletionResult.Success -> { + startCardActivation(result.data.cardId) + delay(DELAY_SDK_DIALOG_CLOSE) + withMainContext { + store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.CreateSecondWallet)) + } + } + is CompletionResult.Failure -> { + } + } + } + } + is TwinCardsAction.Wallet.LaunchSecondStep -> { + val manager = twinCardsState.twinCardsManager ?: return + + scope.launch { + val result = manager.createSecondWallet( + action.initialMessage, + action.preparingMessage, + action.creatingWalletMessage + ) + when (result) { + is CompletionResult.Success -> { + startCardActivation(result.data.cardId) + delay(DELAY_SDK_DIALOG_CLOSE) + withMainContext { + store.dispatch(TwinCardsAction.SetPairCardId(result.data.cardId)) + store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.CreateThirdWallet)) + } + } + is CompletionResult.Failure -> { + } + } + } + } + is TwinCardsAction.Wallet.LaunchThirdStep -> { + val manager = twinCardsState.twinCardsManager ?: return + + scope.launch { + when (val result = manager.complete(action.message)) { + is Result.Success -> { + updateScanResponse(result.data) + delay(DELAY_SDK_DIALOG_CLOSE) + withMainContext { store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.TopUpWallet)) } + } + is Result.Failure -> { + } + } + } + } + + is TwinCardsAction.Balance.Update -> { + val walletManager = if (twinCardsState.walletManager != null) { + twinCardsState.walletManager + } else { + val wmFactory = globalState.tapWalletManager.walletManagerFactory + val walletManager = wmFactory.makePrimaryWalletManager(getScanResponse()).guard { + val message = "Loading cancelled. Cause: wallet manager didn't created" + val customError = TapError.CustomError(message) + store.dispatchErrorNotification(customError) + return + } + dispatch(TwinCardsAction.SetWalletManager(walletManager)) + walletManager + } + val isLoadedBefore = twinCardsState.walletBalance.state != ProgressState.Loading + val balanceIsLoading = twinCardsState.walletBalance.copy( + currency = Currency.Blockchain(walletManager.wallet.blockchain), + state = ProgressState.Loading, + error = null, + criticalError = null + ) + store.dispatch(TwinCardsAction.Balance.Set(balanceIsLoading)) + + scope.launch { + val loadedBalance = onboardingManager?.updateBalance(walletManager) ?: return@launch + loadedBalance.criticalError?.let { store.dispatchErrorNotification(it) } + delay(if (isLoadedBefore) 0 else 300) + withMainContext { store.dispatch(TwinCardsAction.Balance.Set(loadedBalance)) } + } + + } + is TwinCardsAction.Balance.Set -> { + if (action.balance.balanceIsToppedUp()) { + scope.launch { + withMainContext { store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.Done)) } + } + } + } + is TwinCardsAction.ShowAddressInfoDialog -> { + val addressData = twinCardsState.walletManager?.getAddressData() ?: return + + val addressWasCopied = globalState.resources.strings.addressWasCopied + val appDialog = AppDialog.AddressInfoDialog( + addressData, + onCopyAddress = { store.dispatchToastNotification(addressWasCopied) }, + onExploreAddress = { store.dispatchOpenUrl(addressData.exploreUrl) } + ) + store.dispatchDialogShow(appDialog) + } + is TwinCardsAction.TopUp -> { + val topUpUrl = twinCardsState.walletManager?.getToUpUrl() ?: return + store.dispatchOpenUrl(topUpUrl) + } + TwinCardsAction.Done -> { + scope.launch { + val scanResponse = getScanResponse() + store.onCardScanned(scanResponse) + withMainContext { + when (twinCardsState.mode) { + CreateTwinWalletMode.CreateWallet -> { + store.dispatch(GlobalAction.Onboarding.Stop) + store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet)) + } + CreateTwinWalletMode.RecreateWallet -> { + store.dispatch(NavigationAction.PopBackTo()) + } + } + } + } + } + } +} diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt new file mode 100644 index 0000000000..1d18eb4dec --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt @@ -0,0 +1,64 @@ +package com.tangem.tap.features.onboarding.products.twins.redux + +import com.tangem.tap.common.redux.AppState +import com.tangem.tap.domain.twins.getTwinCardNumber +import org.rekotlin.Action + +class TwinCardsReducer { + companion object { + fun reduce(action: Action, state: AppState): TwinCardsState = internalReduce(action, state) + } +} + +private fun internalReduce(action: Action, state: AppState): TwinCardsState { + if (action !is TwinCardsAction) return state.twinCardsState + + var state = state.twinCardsState + + when (action) { + is TwinCardsAction.IfTwinsPrepareState -> { + state = if (action.scanResponse.isTangemTwins()) { + val cardNumber = action.scanResponse.card.getTwinCardNumber() ?: return state + + TwinCardsState( + cardNumber = cardNumber, + mode = CreateTwinWalletMode.CreateWallet, + ) + } else { + TwinCardsState() + } + } + is TwinCardsAction.SetMode -> { + state = state.copy(mode = action.mode) + } + is TwinCardsAction.SetStepOfScreen -> { + state = state.copy(currentStep = action.step) + } + is TwinCardsAction.SetUserUnderstand -> { + state = state.copy(userWasUnderstandIfWalletRecreate = action.isUnderstand) + } + is TwinCardsAction.CardsManager.Set -> { + state = state.copy(twinCardsManager = action.manager) + } + TwinCardsAction.CardsManager.Release -> { + state = state.copy(twinCardsManager = null) + } + is TwinCardsAction.SetPairCardId -> { + state = state.copy(pairCardId = action.cardId) + } + is TwinCardsAction.SetWalletManager -> { + state = state.copy(walletManager = action.walletManager) + } + is TwinCardsAction.Balance.Set -> { + state = state.copy(walletBalance = action.balance) + } + is TwinCardsAction.Confetti.Show -> { + state = state.copy(showConfetti = true) + } + is TwinCardsAction.Confetti.Hide -> { + state = state.copy(showConfetti = false) + } + } + + return state +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsState.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsState.kt new file mode 100644 index 0000000000..ac731df22a --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsState.kt @@ -0,0 +1,61 @@ +package com.tangem.tap.features.onboarding.products.twins.redux + +import com.tangem.blockchain.common.WalletManager +import com.tangem.tap.domain.twins.TwinCardNumber +import com.tangem.tap.domain.twins.TwinCardsManager +import com.tangem.tap.features.onboarding.OnboardingWalletBalance +import org.rekotlin.StateType + +/** +[REDACTED_AUTHOR] + */ +data class TwinCardsState( + // if cardNumber = null -> the scanned card is not Twin + val cardNumber: TwinCardNumber? = null, + val mode: CreateTwinWalletMode = CreateTwinWalletMode.CreateWallet, + val currentStep: TwinCardsStep = TwinCardsStep.Welcome, + val userWasUnderstandIfWalletRecreate: Boolean = false, + // available only when creating or recreating wallets + val twinCardsManager: TwinCardsManager? = null, + + // for the onboarding + val pairCardId: String? = null, // available after create\recreate wallets + val walletManager: WalletManager? = null, + val walletBalance: OnboardingWalletBalance = OnboardingWalletBalance.loading(), + val showConfetti: Boolean = false, +) : StateType { + + val steps: List + get() = when (mode) { + CreateTwinWalletMode.CreateWallet -> listOf( + TwinCardsStep.None, + TwinCardsStep.CreateFirstWallet, + TwinCardsStep.CreateSecondWallet, + TwinCardsStep.CreateThirdWallet, + TwinCardsStep.TopUpWallet, + TwinCardsStep.Done + ) + CreateTwinWalletMode.RecreateWallet -> listOf( + TwinCardsStep.None, + TwinCardsStep.CreateFirstWallet, + TwinCardsStep.CreateSecondWallet, + TwinCardsStep.CreateThirdWallet, + TwinCardsStep.Done + ) + } + + val progress: Int + get() = steps.indexOf(currentStep) + + val showAlert: Boolean + get() = currentStep == TwinCardsStep.CreateSecondWallet || currentStep == TwinCardsStep.CreateThirdWallet +} + +enum class CreateTwinWalletMode { CreateWallet, RecreateWallet } + +enum class TwinCardsStep { + None, WelcomeOnly, Welcome, Warning, CreateFirstWallet, CreateSecondWallet, CreateThirdWallet, + + // for the onboarding + TopUpWallet, Done +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt new file mode 100644 index 0000000000..3a1f683cca --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt @@ -0,0 +1,366 @@ +package com.tangem.tap.features.onboarding.products.twins.ui + +import android.os.Bundle +import android.view.View +import android.view.animation.OvershootInterpolator +import androidx.annotation.LayoutRes +import androidx.constraintlayout.widget.ConstraintSet +import androidx.core.view.isVisible +import androidx.transition.TransitionInflater +import androidx.transition.TransitionManager +import com.squareup.picasso.Picasso +import com.tangem.Message +import com.tangem.blockchain.common.Blockchain +import com.tangem.common.extensions.VoidCallback +import com.tangem.tap.common.extensions.* +import com.tangem.tap.common.leapfrogWidget.LeapfrogWidget +import com.tangem.tap.common.postUi +import com.tangem.tap.common.redux.navigation.AppScreen +import com.tangem.tap.common.redux.navigation.NavigationAction +import com.tangem.tap.common.redux.navigation.ShareElement +import com.tangem.tap.common.toggleWidget.RefreshBalanceWidget +import com.tangem.tap.common.transitions.InternalNoteLayoutTransition +import com.tangem.tap.domain.twins.AssetReader +import com.tangem.tap.domain.twins.TwinCardNumber +import com.tangem.tap.domain.twins.TwinsCardWidget +import com.tangem.tap.features.onboarding.products.BaseOnboardingFragment +import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode +import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction +import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState +import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep +import com.tangem.tap.features.wallet.redux.Artwork +import com.tangem.tap.store +import com.tangem.wallet.R +import kotlinx.android.synthetic.main.fragment_onboarding_main.* +import kotlinx.android.synthetic.main.layout_onboarding_container_bottom.* +import kotlinx.android.synthetic.main.layout_onboarding_container_top.* +import kotlinx.android.synthetic.main.view_bg_twins_welcome.* +import kotlinx.android.synthetic.main.view_onboarding_progress.* +import kotlinx.android.synthetic.main.view_onboarding_tv_balance.* +import org.rekotlin.Action + +class TwinsCardsFragment : BaseOnboardingFragment() { + + private var previousStep = TwinCardsStep.None + + private lateinit var twinsWidget: TwinsCardWidget + private lateinit var btnRefreshBalanceWidget: RefreshBalanceWidget + + private val assetReader: AssetReader by lazy { + object : AssetReader { + override fun readAssetAsString(name: String): String = requireContext().readAssetAsString(name) + } + } + + override fun getOnboardingTopContainerId(): Int = R.layout.layout_onboarding_container_top + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + postponeEnterTransition() + store.dispatch(TwinCardsAction.Init) + } + + override fun configureTransitions() { + when (store.state.twinCardsState.mode) { + CreateTwinWalletMode.CreateWallet -> super.configureTransitions() + CreateTwinWalletMode.RecreateWallet -> { + val inflater = TransitionInflater.from(requireContext()) + enterTransition = inflater.inflateTransition(R.transition.slide_right) + exitTransition = inflater.inflateTransition(R.transition.fade) + } + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + reconfigureLayoutForTwins() + twinsWidget = TwinsCardWidget(LeapfrogWidget(cards_container)) { 250f } + btnRefreshBalanceWidget = RefreshBalanceWidget(onboarding_main_container) + + toolbar.title = getText(R.string.twins_recreate_toolbar) + + Picasso.get() + .load(Artwork.TWIN_CARD_1) + .placeholder(R.drawable.card_placeholder_black) + ?.into(imv_twin_front_card) + + Picasso.get() + .load(Artwork.TWIN_CARD_2) + .placeholder(R.drawable.card_placeholder_white) + ?.into(imv_twin_back_card) + } + + private fun reconfigureLayoutForTwins() { + imv_front_card.hide() + imv_card_background.hide() + cards_container.show() + + imv_twin_front_card.transitionName = ShareElement.imvFrontCard + imv_twin_back_card.transitionName = ShareElement.imvBackCard + } + + override fun subscribeToStore() { + store.subscribe(this) { state -> + state.skipRepeats { oldState, newState -> + oldState.twinCardsState == newState.twinCardsState + }.select { it.twinCardsState } + } + storeSubscribersList.add(this) + } + + override fun newState(state: TwinCardsState) { + if (activity == null) return + +// toolbar.title = when (state.mode) { +// CreateTwinWalletMode.CreateWallet -> getText(R.string.wallet_button_create_wallet) +// CreateTwinWalletMode.RecreateWallet -> getText(R.string.twins_recreate_toolbar) +// } + + pb_state.max = state.steps.size - 1 + pb_state.progress = state.progress + + when (state.currentStep) { + TwinCardsStep.WelcomeOnly -> setupWelcomeOnlyState(state) + TwinCardsStep.Welcome -> setupWelcomeState(state) + TwinCardsStep.Warning -> setupWarningState(state) + TwinCardsStep.CreateFirstWallet -> setupCreateFirstWalletState(state) + TwinCardsStep.CreateSecondWallet -> setupCreateSecondWalletState(state) + TwinCardsStep.CreateThirdWallet -> setupCreateThirdWalletState(state) + TwinCardsStep.TopUpWallet -> setupTopUpWalletState(state) + TwinCardsStep.Done -> setupDoneState(state) + } + + setBalance(state) + showConfetti(state.showConfetti) + previousStep = state.currentStep + } + + private fun setBalance(state: TwinCardsState) { + if (state.walletBalance.currency.blockchain == Blockchain.Unknown) return + + val balanceValue = state.walletBalance.value.stripZeroPlainString() + val currency = state.walletBalance.currency.currencySymbol + tv_balance_value.text = "$balanceValue $currency" + } + + private fun setupWelcomeOnlyState(state: TwinCardsState) { + setupWelcomeState(state, NavigationAction.NavigateTo(AppScreen.Wallet)) + } + + private fun setupWelcomeState(state: TwinCardsState) { + setupWelcomeState(state, TwinCardsAction.SetStepOfScreen(TwinCardsStep.CreateFirstWallet)) + } + + private fun setupWelcomeState(state: TwinCardsState, mainAction: Action) { + twinsWidget.toWelcome(false) { startPostponedEnterTransition() } + + pb_state.hide() + + tv_header.setText(R.string.twins_onboarding_subtitle) + tv_body.text = getString(R.string.twins_onboarding_description_format, state.cardNumber?.pairIndexNumber()) + + btn_main_action.setText(R.string.common_continue) + btn_main_action.setOnClickListener { store.dispatch(mainAction) } + } + + private fun setupWarningState(state: TwinCardsState) { + twinsWidget.toWelcome(false) { startPostponedEnterTransition() } + pb_state.hide() + chb_understand.show() + + tv_header.setText(R.string.common_warning) + tv_body.setText(R.string.twins_recreate_warning) + + chb_understand.setOnCheckedChangeListener { buttonView, isChecked -> + store.dispatch(TwinCardsAction.SetUserUnderstand(isChecked)) + } + btn_main_action.isEnabled = state.userWasUnderstandIfWalletRecreate + btn_main_action.setText(R.string.common_continue) + btn_main_action.setOnClickListener { + store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.CreateFirstWallet)) + } + } + + private fun setupCreateFirstWalletState(state: TwinCardsState) { + bg_circle_large.hide() + bg_circle_medium.hide() + bg_circle_min.hide() + chb_understand.hide() + pb_state.show() + + onboarding_main_container.beginDelayedTransition() + + when (previousStep) { + TwinCardsStep.None -> { + twinsWidget.toLeapfrog(false) { + when (state.cardNumber) { + TwinCardNumber.First -> startPostponedEnterTransition() + TwinCardNumber.Second -> { + switchToCard(state.cardNumber, false) { startPostponedEnterTransition() } + } + } + } + } + TwinCardsStep.Welcome, TwinCardsStep.Warning -> { + twinsWidget.toLeapfrog(onEnd = { switchToCard(state.cardNumber) }) + } + } + + val twinIndexNumber = state.cardNumber?.indexNumber() + tv_header.text = getString(R.string.twins_recreate_title_format, twinIndexNumber) + tv_body.setText(R.string.onboarding_twins_interrupt_warning) + + btn_main_action.text = getString(R.string.twins_recreate_button_format, twinIndexNumber) + btn_main_action.setOnClickListener { + store.dispatch(TwinCardsAction.Wallet.LaunchFirstStep( + Message(getString(R.string.twins_recreate_title_format, twinIndexNumber)), + assetReader + )) + } + + btn_alternative_action.isVisible = false + btn_alternative_action.isClickable = false + } + + private fun setupCreateSecondWalletState(state: TwinCardsState) { + switchToCard(state.cardNumber?.pairNumber()) + + val twinPairIndexNumber = state.cardNumber?.pairIndexNumber() + tv_header.text = getString(R.string.twins_recreate_title_format, twinPairIndexNumber) + tv_body.setText(R.string.onboarding_twins_interrupt_warning) + + btn_main_action.text = getString(R.string.twins_recreate_button_format, twinPairIndexNumber) + btn_main_action.setOnClickListener { + store.dispatch(TwinCardsAction.Wallet.LaunchSecondStep( + Message(getString(R.string.twins_recreate_title_format, twinPairIndexNumber)), + Message(getString(R.string.twins_recreate_title_preparing)), + Message(getString(R.string.twins_recreate_title_creating_wallet)), + )) + } + } + + private fun setupCreateThirdWalletState(state: TwinCardsState) { + switchToCard(state.cardNumber) + + val twinIndexNumber = state.cardNumber?.indexNumber() + tv_header.text = getString(R.string.twins_recreate_title_format, twinIndexNumber) + tv_body.setText(R.string.onboarding_twins_interrupt_warning) + + btn_main_action.text = getString(R.string.twins_recreate_button_format, twinIndexNumber) + btn_main_action.setOnClickListener { + store.dispatch(TwinCardsAction.Wallet.LaunchThirdStep( + Message(getString(R.string.twins_recreate_title_format, twinIndexNumber)) + )) + } + } + + + private fun setupTopUpWalletState(state: TwinCardsState) { + when (previousStep) { + TwinCardsStep.None -> { + when (state.cardNumber) { + TwinCardNumber.First -> { + twinsWidget.leapfrogWidget.unfold(false) { + twinsWidget.toActivate(false) { + startPostponedEnterTransition() + } + } + } + TwinCardNumber.Second -> { + switchToCard(state.cardNumber, false) { + twinsWidget.toActivate(false) + startPostponedEnterTransition() + } + } + } + } + TwinCardsStep.CreateThirdWallet -> { + twinsWidget.toActivate() + } + } + + btn_main_action.setText(R.string.onboarding_top_up_button_but_crypto) + btn_main_action.setOnClickListener { + store.dispatch(TwinCardsAction.TopUp) + } + + btn_alternative_action.setText(R.string.onboarding_top_up_button_show_wallet_address) + btn_alternative_action.setOnClickListener { + store.dispatch(TwinCardsAction.ShowAddressInfoDialog) + } + + tv_header.setText(R.string.onboarding_top_up_header) + tv_body.setText(R.string.onboarding_top_up_body) + + btnRefreshBalanceWidget.changeState(state.walletBalance.state) + if (btnRefreshBalanceWidget.isShowing != true) { + postUi(300) { + btnRefreshBalanceWidget.mainView.setOnClickListener { + store.dispatch(TwinCardsAction.Balance.Update) + } + } + } + + imv_card_background.setBackgroundDrawable(requireContext().getDrawableCompat(R.drawable.shape_rectangle_rounded_8)) + updateConstraints(state.currentStep, R.layout.lp_onboarding_topup_wallet_twins) + } + + private fun setupDoneState(state: TwinCardsState) { + btn_main_action.setText(R.string.onboarding_done_button_continue) + btn_main_action.setOnClickListener { + store.dispatch(TwinCardsAction.Confetti.Hide) + store.dispatch(TwinCardsAction.Done) + } + + btn_alternative_action.isVisible = false + btn_alternative_action.isClickable = false + + tv_header.setText(R.string.onboarding_done_header) + tv_body.setText(R.string.onboarding_done_body) + + val layout = when (state.mode) { + CreateTwinWalletMode.CreateWallet -> R.layout.lp_onboarding_done_activation_twins + CreateTwinWalletMode.RecreateWallet -> R.layout.lp_onboarding_done + } + updateConstraints(state.currentStep, layout) + } + + private fun updateConstraints(currentStep: TwinCardsStep, @LayoutRes layoutId: Int) { + if (this.previousStep == currentStep) return + + val constraintSet = ConstraintSet() + constraintSet.clone(requireContext(), layoutId) + constraintSet.applyTo(onboarding_main_container) + val transition = InternalNoteLayoutTransition() + transition.interpolator = OvershootInterpolator() + TransitionManager.beginDelayedTransition(onboarding_main_container, transition) + } + + private fun switchToCard(cardNumber: TwinCardNumber?, animate: Boolean = true, onEnd: VoidCallback = {}) { + val position = cardNumber?.number ?: return + + if (twinsWidget.leapfrogWidget.getViewPositionByIndex(1) != position - 1) { + twinsWidget.leapfrogWidget.leap(animate, onEnd) + } else { + onEnd() + } + } + + override fun handleOnBackPressed() { + store.dispatch(TwinCardsAction.Wallet.HandleOnBackPressed { should, popAction -> + store.dispatch(TwinCardsAction.Confetti.Hide) + showConfetti(false) + if (should) switchToCard(TwinCardNumber.First, true, popAction) + else popAction() + }) + } +} + +private fun TwinCardNumber?.indexNumber(): String { + return this?.number?.toString() ?: "" +} + +private fun TwinCardNumber?.pairIndexNumber(): String { + return this?.pairNumber()?.number?.toString() ?: "" +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/twins/ui/dialog/CreateWalletInterruptDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/dialog/CreateWalletInterruptDialog.kt similarity index 66% rename from app/src/main/java/com/tangem/tap/features/twins/ui/dialog/CreateWalletInterruptDialog.kt rename to app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/dialog/CreateWalletInterruptDialog.kt index ab34b78039..0020137a82 100644 --- a/app/src/main/java/com/tangem/tap/features/twins/ui/dialog/CreateWalletInterruptDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/dialog/CreateWalletInterruptDialog.kt @@ -1,10 +1,10 @@ -package com.tangem.tap.features.twins.ui.dialog +package com.tangem.tap.features.onboarding.products.twins.ui.dialog import android.content.Context import androidx.appcompat.app.AlertDialog import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.tangem.tap.common.extensions.dispatchDialogHide -import com.tangem.tap.features.twins.redux.TwinCardsAction +import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.store import com.tangem.wallet.R @@ -13,10 +13,10 @@ import com.tangem.wallet.R */ class CreateWalletInterruptDialog { companion object { - fun create(state: TwinCardsAction.Wallet.InterruptDialog, context: Context): AlertDialog { + fun create(state: TwinCardsAction.Wallet.ShowInterruptDialog, context: Context): AlertDialog { return MaterialAlertDialogBuilder(context) - .setMessage(R.string.details_twins_recreate_alert) - .setPositiveButton(R.string.common_ok) { _, _ -> state.interrupt() } + .setMessage(R.string.twins_recreate_alert) + .setPositiveButton(R.string.common_ok) { _, _ -> state.onOk() } .setNegativeButton(R.string.common_cancel) { _, _ -> } .setOnDismissListener { store.dispatchDialogHide() } .create() diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/OnboardingWalletFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/OnboardingWalletFragment.kt index d0463040bd..69c66581a6 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/OnboardingWalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/OnboardingWalletFragment.kt @@ -3,8 +3,8 @@ package com.tangem.tap.features.onboarding.products.wallet import android.os.Bundle import android.view.View import androidx.transition.TransitionInflater +import com.tangem.tap.features.BaseStoreFragment import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletState -import com.tangem.tap.features.send.BaseStoreFragment import com.tangem.tap.store import com.tangem.wallet.R import org.rekotlin.StoreSubscriber diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt index bb675cf3fe..4c35c25b24 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt @@ -7,7 +7,6 @@ import android.text.method.DigitsKeyListener import android.view.View import android.view.inputmethod.EditorInfo import android.widget.EditText -import androidx.activity.OnBackPressedCallback import androidx.core.view.postDelayed import androidx.core.widget.addTextChangedListener import androidx.recyclerview.widget.LinearLayoutManager @@ -25,7 +24,7 @@ import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.common.snackBar.MaxAmountSnackbar import com.tangem.tap.common.text.truncateMiddleWith import com.tangem.tap.common.toggleWidget.* -import com.tangem.tap.features.send.BaseStoreFragment +import com.tangem.tap.features.BaseStoreFragment import com.tangem.tap.features.send.redux.* import com.tangem.tap.features.send.redux.AddressPayIdActionUi.* import com.tangem.tap.features.send.redux.AmountActionUi.* @@ -63,23 +62,6 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) { private val sendSubscriber = SendStateSubscriber(this) private lateinit var keyboardObserver: KeyboardObserver - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - val externalTransactionData = store.state.sendState.externalTransactionData - if (externalTransactionData == null) { - store.dispatch(NavigationAction.PopBackTo()) - } else { - store.dispatch( - WalletAction.TradeCryptoAction.FinishSelling(externalTransactionData.transactionId) - ) - } - } - }) - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -97,7 +79,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) { private fun initSendButtonStates() { btnSend.setOnClickListener { store.dispatch(SendActionUi.SendAmountToRecipient( - Message(getString(R.string.initial_message_sign_header)) + Message(getString(R.string.initial_message_sign_header)) )) } sendBtn = IndeterminateProgressButtonWidget(btnSend, progress) @@ -124,8 +106,8 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) { } imvQrCode.setOnClickListener { startActivityForResult( - Intent(requireContext(), ScanQrCodeActivity::class.java), - ScanQrCodeActivity.SCAN_QR_REQUEST_CODE + Intent(requireContext(), ScanQrCodeActivity::class.java), + ScanQrCodeActivity.SCAN_QR_REQUEST_CODE ) } } @@ -281,6 +263,17 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) { sp.edit().putString("mainCurrency", type.name).apply() } + override fun handleOnBackPressed() { + val externalTransactionData = store.state.sendState.externalTransactionData + if (externalTransactionData == null) { + store.dispatch(NavigationAction.PopBackTo()) + } else { + store.dispatch( + WalletAction.TradeCryptoAction.FinishSelling(externalTransactionData.transactionId) + ) + } + } + override fun onDestroy() { keyboardObserver.unregisterListener() store.dispatch(ReleaseSendState) diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/FragmentStateSubscriber.kt b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/FragmentStateSubscriber.kt index aa129ebbb5..17dfb7a5fc 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/FragmentStateSubscriber.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/FragmentStateSubscriber.kt @@ -1,6 +1,6 @@ package com.tangem.tap.features.send.ui.stateSubscribers -import com.tangem.tap.features.send.BaseStoreFragment +import com.tangem.tap.features.BaseStoreFragment import org.rekotlin.StateType import org.rekotlin.StoreSubscriber import java.lang.ref.WeakReference diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt index 2471b257de..a8987dcd0e 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt @@ -12,7 +12,7 @@ import com.tangem.tap.common.redux.getMessageString import com.tangem.tap.common.text.DecimalDigitsInputFilter import com.tangem.tap.domain.MultiMessageError import com.tangem.tap.domain.assembleErrors -import com.tangem.tap.features.send.BaseStoreFragment +import com.tangem.tap.features.BaseStoreFragment import com.tangem.tap.features.send.redux.AddressPayIdVerifyAction.Error import com.tangem.tap.features.send.redux.FeeAction import com.tangem.tap.features.send.redux.SendAction @@ -188,15 +188,15 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber (fg as? SendFragment)?.saveMainCurrency(state.mainCurrency.type) val balanceText = fg.getString(R.string.send_balance_subtitle_format, - state.mainCurrency.currencySymbol, - state.viewBalanceValue) + state.mainCurrency.currencySymbol, + state.viewBalanceValue) fg.tvBalance.update(balanceText) fg.tilAmountToSend.isEnabled = state.inputIsEnabled val imageRes = if (state.inputIsEnabled) R.drawable.ic_arrows_up_down else 0 fg.tvAmountCurrency.setCompoundDrawablesWithIntrinsicBounds(0, 0, imageRes, 0) - val textColor = if (state.inputIsEnabled) R.color.blue else R.color.textGray + val textColor = if (state.inputIsEnabled) R.color.blue else R.color.textGray fg.tvAmountCurrency.setTextColor(fg.getColor(textColor)) } @@ -245,7 +245,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber totalLayout.tvTotalValue.update("${roughOrEmpty(receipt.totalFiat)} ${receipt.symbols.fiat}") val willSent = getString(R.string.send_total_subtitle_format, - receipt.willSentCrypto, receipt.symbols.crypto) + receipt.willSentCrypto, receipt.symbols.crypto) totalLayout.tvWillBeSentValue.update(willSent) } @@ -277,9 +277,9 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber totalLayout.tvTotalValue.update("${roughOrEmpty(receipt.totalFiat)} ${receipt.symbols.fiat}") val willSent = getString( - R.string.send_total_subtitle_asset_format, - receipt.symbols.token ?: "", receipt.willSentToken, - receipt.symbols.crypto, receipt.willSentFeeCoin + R.string.send_total_subtitle_asset_format, + receipt.symbols.token ?: "", receipt.willSentToken, + receipt.symbols.crypto, receipt.willSentFeeCoin ) totalLayout.tvWillBeSentValue.update(willSent) } diff --git a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsAction.kt b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsAction.kt deleted file mode 100644 index 383481a905..0000000000 --- a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsAction.kt +++ /dev/null @@ -1,62 +0,0 @@ -package com.tangem.tap.features.twins.redux - -import com.tangem.Message -import com.tangem.tap.common.redux.StateDialog -import com.tangem.tap.domain.tasks.product.ScanResponse -import com.tangem.tap.domain.twins.AssetReader -import com.tangem.tap.domain.twins.TwinCardNumber -import com.tangem.tap.domain.twins.TwinCardsManager -import org.rekotlin.Action - -/** -[REDACTED_AUTHOR] - */ -sealed class TwinCardsAction : Action { - - data class SetResources(val resources: TwinCardsResources) : TwinCardsAction() - - data class SetTwinCard( - val number: TwinCardNumber, - val secondCardId: String?, - val isCreatingTwinCardsAllowed: Boolean, - ) : TwinCardsAction() - - sealed class CardsManager { - data class Set(val manager: TwinCardsManager) : TwinCardsAction() - object Release : TwinCardsAction() - } - - object ShowOnboarding : TwinCardsAction() - object SetOnboardingShown : TwinCardsAction() - object ProceedToCreateWallet : TwinCardsAction() - - sealed class Wallet : TwinCardsAction() { - object HandleOnBackPressed : TwinCardsAction() - - data class Create( - val number: TwinCardNumber, - val createTwinWalletMode: CreateTwinWalletMode - ) : TwinCardsAction() - - data class InterruptDialog(val interrupt: () -> Unit) : TwinCardsAction(), StateDialog - - data class LaunchFirstStep( - val initialMessage: Message, - val reader: AssetReader - ) : TwinCardsAction() { - object Success : TwinCardsAction() - } - - data class LaunchSecondStep( - val initialMessage: Message, - val preparingMessage: Message, - val creatingWalletMessage: Message, - ) : TwinCardsAction() { - object Success : TwinCardsAction() - } - - data class LaunchThirdStep(val message: Message) : TwinCardsAction() { - data class Success(val scanResponse: ScanResponse) : TwinCardsAction() - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsMiddleware.kt deleted file mode 100644 index 84c837d778..0000000000 --- a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsMiddleware.kt +++ /dev/null @@ -1,139 +0,0 @@ -package com.tangem.tap.features.twins.redux - -import com.tangem.blockchain.extensions.Result -import com.tangem.blockchain.extensions.SimpleResult -import com.tangem.tap.common.extensions.dispatchDialogShow -import com.tangem.tap.common.extensions.dispatchNotification -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.extensions.toSendableAmounts -import com.tangem.tap.domain.twins.TwinCardsManager -import com.tangem.tap.preferencesStorage -import com.tangem.tap.scope -import com.tangem.tap.store -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import org.rekotlin.Action -import org.rekotlin.DispatchFunction -import org.rekotlin.Middleware - -class TwinCardsMiddleware { - companion object { - val handler = twinsWalletMiddleware - } -} - -private val twinsWalletMiddleware: Middleware = { dispatch, state -> - { next -> - { action -> - handle(action, dispatch) - next(action) - } - } -} - -private fun handle(action: Action, dispatch: DispatchFunction) { - val action = action as? TwinCardsAction ?: return - - val twinCardsState = store.state.twinCardsState - - when (action) { - is TwinCardsAction.SetTwinCard -> { - val showOnboarding = !preferencesStorage.wasTwinsOnboardingShown() - if (showOnboarding) store.dispatch(TwinCardsAction.ShowOnboarding) - } - TwinCardsAction.SetOnboardingShown -> { - preferencesStorage.saveTwinsOnboardingShown() - } - is TwinCardsAction.ProceedToCreateWallet -> { - store.dispatch(NavigationAction.NavigateTo(AppScreen.CreateTwinWallet)) - } - is TwinCardsAction.Wallet.HandleOnBackPressed -> { - if (twinCardsState.createWalletState?.showAlert == true) { - val stateDialog = TwinCardsAction.Wallet.InterruptDialog { - store.dispatch(TwinCardsAction.CardsManager.Release) - store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) - } - store.dispatchDialogShow(stateDialog) - } else { - store.dispatch(TwinCardsAction.CardsManager.Release) - store.dispatch(NavigationAction.PopBackTo()) - } - } - is TwinCardsAction.Wallet.Create -> { - val wallet = store.state.walletState.walletManagers.map { it.wallet }.firstOrNull() - if (wallet == null) { - store.dispatch(NavigationAction.NavigateTo(AppScreen.CreateTwinWalletWarning)) - return - } - val notEmpty = wallet.recentTransactions.isNotEmpty() || wallet.amounts.toSendableAmounts().isNotEmpty() - if (notEmpty) { - store.dispatchNotification(twinCardsState.resources.strings.walletIsNotEmpty) - } else { - store.dispatch(NavigationAction.NavigateTo(AppScreen.CreateTwinWalletWarning)) - } - } - is TwinCardsAction.Wallet.LaunchFirstStep -> { - val scanResponse = store.state.globalState.scanResponse ?: return - - val manager = TwinCardsManager(scanResponse, action.reader) - store.dispatch(TwinCardsAction.CardsManager.Set(manager)) - - scope.launch { - val result = manager.createFirstWallet(action.initialMessage) - withContext(Dispatchers.Main) { - when (result) { - SimpleResult.Success -> { - store.dispatch(TwinCardsAction.Wallet.LaunchFirstStep.Success) - } - is SimpleResult.Failure -> { - } - } - } - } - } - is TwinCardsAction.Wallet.LaunchSecondStep -> { - val manager = twinCardsState.twinCardsManager ?: return - - scope.launch { - val result = manager.createSecondWallet(action.initialMessage, - action.preparingMessage, action.creatingWalletMessage) - withContext(Dispatchers.Main) { - when (result) { - SimpleResult.Success -> { - store.dispatch(TwinCardsAction.Wallet.LaunchSecondStep.Success) - } - is SimpleResult.Failure -> { - } - } - } - } - } - is TwinCardsAction.Wallet.LaunchThirdStep -> { - val manager = twinCardsState.twinCardsManager ?: return - - scope.launch { - val result = manager.complete(action.message) - withContext(Dispatchers.Main) { - when (result) { - is Result.Success -> { - store.dispatch(TwinCardsAction.Wallet.LaunchThirdStep.Success(result.data)) - } - is Result.Failure -> { - - } - } - } - } - } - is TwinCardsAction.Wallet.LaunchThirdStep.Success -> { - scope.launch { - store.state.globalState.tapWalletManager.onCardScanned(action.scanResponse) - } - store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) - store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet)) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsReducer.kt b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsReducer.kt deleted file mode 100644 index 89978790a1..0000000000 --- a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsReducer.kt +++ /dev/null @@ -1,60 +0,0 @@ -package com.tangem.tap.features.twins.redux - -import com.tangem.tap.common.redux.AppState -import org.rekotlin.Action - -class TwinCardsReducer { - companion object { - fun reduce(action: Action, state: AppState): TwinCardsState = internalReduce(action, state) - } -} - -private fun internalReduce(action: Action, state: AppState): TwinCardsState { - if (action !is TwinCardsAction) return state.twinCardsState - - val state = state.twinCardsState - return when (action) { - is TwinCardsAction.SetResources -> { - state.copy(resources = action.resources) - } - is TwinCardsAction.SetTwinCard -> { - state.copy( - cardNumber = action.number, - secondCardId = action.secondCardId, - showTwinOnboarding = state.showTwinOnboarding, - isCreatingTwinCardsAllowed = action.isCreatingTwinCardsAllowed, - ) - } - is TwinCardsAction.CardsManager.Set -> { - state.copy(twinCardsManager = action.manager) - } - TwinCardsAction.CardsManager.Release -> { - state.copy(twinCardsManager = null) - } - is TwinCardsAction.ShowOnboarding -> { - state.copy(showTwinOnboarding = true) - } - is TwinCardsAction.SetOnboardingShown -> { - state.copy(showTwinOnboarding = false) - } - is TwinCardsAction.Wallet.Create -> { - val prevState = state.createWalletState - state.copy(createWalletState = CreateTwinWalletState( - prevState?.scanResponse, - prevState?.number ?: action.number, - prevState?.mode ?: action.createTwinWalletMode, - )) - } - TwinCardsAction.Wallet.LaunchFirstStep.Success -> { - state.copy(createWalletState = state.createWalletState?.copy( - step = CreateTwinWalletStep.SecondStep - )) - } - TwinCardsAction.Wallet.LaunchSecondStep.Success -> - state.copy(createWalletState = state.createWalletState?.copy( - step = CreateTwinWalletStep.ThirdStep - )) - else -> state - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsState.kt b/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsState.kt deleted file mode 100644 index f23ac31930..0000000000 --- a/app/src/main/java/com/tangem/tap/features/twins/redux/TwinCardsState.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.tangem.tap.features.twins.redux - -import com.tangem.tap.domain.tasks.product.ScanResponse -import com.tangem.tap.domain.twins.TwinCardNumber -import com.tangem.tap.domain.twins.TwinCardsManager -import org.rekotlin.StateType - -/** -[REDACTED_AUTHOR] - */ -data class TwinCardsState( - val twinCardsManager: TwinCardsManager? = null, - // if cardNumber is not set -> the scanned card is not Twin - val cardNumber: TwinCardNumber? = null, - val secondCardId: String? = null, - val showTwinOnboarding: Boolean = false, - val isCreatingTwinCardsAllowed: Boolean = false, - val createWalletState: CreateTwinWalletState? = null, - val resources: TwinCardsResources = TwinCardsResources(), -) : StateType - -data class CreateTwinWalletState( - val scanResponse: ScanResponse?, - val number: TwinCardNumber = TwinCardNumber.First, - val mode: CreateTwinWalletMode = CreateTwinWalletMode.CreateWallet, - val step: CreateTwinWalletStep = CreateTwinWalletStep.FirstStep, -) { - val showAlert: Boolean - get() = step != CreateTwinWalletStep.FirstStep -} - -enum class CreateTwinWalletStep { FirstStep, SecondStep, ThirdStep } - -enum class CreateTwinWalletMode { CreateWallet, RecreateWallet } - -data class TwinCardsResources( - val strings: Strings = Strings() -) { - //TODO: create global structure for StringRes. Set it from the MainActivity. - data class Strings( - val walletIsNotEmpty: Int = -1 - ) -} diff --git a/app/src/main/java/com/tangem/tap/features/twins/ui/CreateTwinWalletFragment.kt b/app/src/main/java/com/tangem/tap/features/twins/ui/CreateTwinWalletFragment.kt deleted file mode 100644 index 94c5a099bc..0000000000 --- a/app/src/main/java/com/tangem/tap/features/twins/ui/CreateTwinWalletFragment.kt +++ /dev/null @@ -1,162 +0,0 @@ -package com.tangem.tap.features.twins.ui - -import android.os.Bundle -import android.view.View -import androidx.activity.OnBackPressedCallback -import androidx.core.content.ContextCompat.getColor -import androidx.fragment.app.Fragment -import androidx.transition.TransitionInflater -import com.squareup.picasso.Picasso -import com.tangem.Message -import com.tangem.tap.common.extensions.readAssetAsString -import com.tangem.tap.domain.twins.AssetReader -import com.tangem.tap.domain.twins.TwinCardNumber -import com.tangem.tap.features.twins.redux.* -import com.tangem.tap.features.wallet.redux.Artwork -import com.tangem.tap.store -import com.tangem.wallet.R -import kotlinx.android.synthetic.main.fragment_twin_cards_create.* -import org.rekotlin.StoreSubscriber - -class CreateTwinWalletFragment : Fragment(R.layout.fragment_twin_cards_create), - StoreSubscriber { - - private val assetReader: AssetReader by lazy { - object : AssetReader { - override fun readAssetAsString(name: String): String = requireContext().readAssetAsString(name) - } - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - store.dispatch(TwinCardsAction.Wallet.HandleOnBackPressed) - } - }) - - initResources() - val inflater = TransitionInflater.from(requireContext()) - enterTransition = inflater.inflateTransition(R.transition.slide_right) - exitTransition = inflater.inflateTransition(R.transition.fade) - } - - private fun initResources() { - val resources = TwinCardsResources( - TwinCardsResources.Strings( - R.string.details_notification_erase_wallet_not_possible - ) - ) - store.dispatch(TwinCardsAction.SetResources(resources)) - } - - override fun onStart() { - super.onStart() - store.subscribe(this) { state -> - state.skipRepeats { oldState, newState -> - oldState.twinCardsState == newState.twinCardsState - }.select { it.twinCardsState } - } - } - - override fun onStop() { - super.onStop() - store.unsubscribe(this) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - toolbar.setNavigationOnClickListener { store.dispatch(TwinCardsAction.Wallet.HandleOnBackPressed) } - - Picasso.get() - .load(Artwork.TWIN_CARD_1) - .placeholder(R.drawable.card_placeholder) - ?.error(R.drawable.card_placeholder) - ?.into(iv_card_1) - - Picasso.get() - .load(Artwork.TWIN_CARD_2) - .placeholder(R.drawable.card_placeholder) - ?.error(R.drawable.card_placeholder) - ?.into(iv_card_2) - } - - - override fun newState(state: TwinCardsState) { - if (activity == null) return - - toolbar.title = when (state.createWalletState?.mode) { - CreateTwinWalletMode.CreateWallet -> getText(R.string.wallet_button_create_wallet) - CreateTwinWalletMode.RecreateWallet, null -> getText(R.string.details_twins_recreate_toolbar) - - } - - val selectedColor = getColor(requireContext(), R.color.colorSecondary) - val defaultColor = getColor(requireContext(), R.color.blue_pale) - - val twinCardNumber = state.createWalletState?.number ?: TwinCardNumber.First - - val cardNumber = when (state.createWalletState?.step) { - CreateTwinWalletStep.FirstStep -> { - val twinCardNumberString = twinCardNumber.number.toString() - tv_step_number.text = - getString(R.string.details_twins_recreate_step_format, "1") - v_step_1.setBackgroundColor(selectedColor) - v_step_2.setBackgroundColor(defaultColor) - v_step_3.setBackgroundColor(defaultColor) - btn_tap.setOnClickListener { - store.dispatch(TwinCardsAction.Wallet.LaunchFirstStep( - Message(getString( - R.string.details_twins_recreate_title_format, - twinCardNumberString - )), - assetReader - )) - } - btn_tap.text = getString(R.string.details_twins_recreate_button_format, - twinCardNumber.number.toString()) - twinCardNumberString - } - CreateTwinWalletStep.SecondStep -> { - val twinCardNumberString = twinCardNumber.pairNumber().number.toString() - - tv_step_number.text = - getString(R.string.details_twins_recreate_step_format, "2") - v_step_1.setBackgroundColor(selectedColor) - v_step_2.setBackgroundColor(selectedColor) - v_step_3.setBackgroundColor(defaultColor) - btn_tap.setOnClickListener { - store.dispatch(TwinCardsAction.Wallet.LaunchSecondStep( - Message(getString(R.string.details_twins_recreate_title_format, twinCardNumberString)), - Message(getString(R.string.details_twins_recreate_title_preparing)), - Message(getString(R.string.details_twins_recreate_title_creating_wallet)), - )) - } - btn_tap.text = getString(R.string.details_twins_recreate_button_format, "2") - twinCardNumberString - } - CreateTwinWalletStep.ThirdStep -> { - val twinCardNumberString = twinCardNumber.number.toString() - - tv_step_number.text = - getString(R.string.details_twins_recreate_step_format, "3") - v_step_1.setBackgroundColor(selectedColor) - v_step_2.setBackgroundColor(selectedColor) - v_step_3.setBackgroundColor(selectedColor) - btn_tap.setOnClickListener { - store.dispatch(TwinCardsAction.Wallet.LaunchThirdStep( - Message(getString( - R.string.details_twins_recreate_title_format, twinCardNumberString) - ) - )) - } - btn_tap.text = getString(R.string.details_twins_recreate_button_format, twinCardNumberString) - twinCardNumberString - } - else -> null - } - btn_tap.text = getString(R.string.details_twins_recreate_button_format, cardNumber) - tv_twin_title.text = getString(R.string.details_twins_recreate_title_format, cardNumber) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/twins/ui/TwinWalletWarningFragment.kt b/app/src/main/java/com/tangem/tap/features/twins/ui/TwinWalletWarningFragment.kt deleted file mode 100644 index 18f779a400..0000000000 --- a/app/src/main/java/com/tangem/tap/features/twins/ui/TwinWalletWarningFragment.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.tangem.tap.features.twins.ui - -import android.os.Bundle -import android.view.View -import androidx.activity.OnBackPressedCallback -import androidx.fragment.app.Fragment -import androidx.transition.TransitionInflater -import com.squareup.picasso.Picasso -import com.tangem.tap.common.redux.navigation.NavigationAction -import com.tangem.tap.features.twins.redux.CreateTwinWalletMode -import com.tangem.tap.features.twins.redux.TwinCardsAction -import com.tangem.tap.features.wallet.redux.Artwork -import com.tangem.tap.store -import com.tangem.wallet.R -import kotlinx.android.synthetic.main.fragment_twin_cards_warning.* -import kotlinx.android.synthetic.main.layout_twin_cards_orange.* - -class TwinWalletWarningFragment : Fragment(R.layout.fragment_twin_cards_warning) { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - store.dispatch(NavigationAction.PopBackTo()) - } - }) - val inflater = TransitionInflater.from(requireContext()) - enterTransition = inflater.inflateTransition(R.transition.slide_right) - exitTransition = inflater.inflateTransition(R.transition.fade) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - val createTwinWallet = store.state.twinCardsState.createWalletState?.mode - if (createTwinWallet == CreateTwinWalletMode.CreateWallet) { - tv_twin_cards_description.text = getText(R.string.details_twins_recreate_subtitle) - } else if (createTwinWallet == CreateTwinWalletMode.RecreateWallet) { - tv_twin_cards_description.text = getText(R.string.details_twins_recreate_warning) - } - - btn_cancel.setOnClickListener { store.dispatch(NavigationAction.PopBackTo()) } - btn_start.setOnClickListener { store.dispatch(TwinCardsAction.ProceedToCreateWallet) } - Picasso.get() - .load(Artwork.TWIN_CARD_1) - .placeholder(R.drawable.card_placeholder) - ?.error(R.drawable.card_placeholder) - ?.into(iv_twin_card_1) - - Picasso.get() - .load(Artwork.TWIN_CARD_2) - .placeholder(R.drawable.card_placeholder) - ?.error(R.drawable.card_placeholder) - ?.into(iv_twin_card_2) - } - - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/models/PendingTransaction.kt b/app/src/main/java/com/tangem/tap/features/wallet/models/PendingTransaction.kt index 29fe72df99..a449bb17ea 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/models/PendingTransaction.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/models/PendingTransaction.kt @@ -5,12 +5,13 @@ import com.tangem.blockchain.common.TransactionData import com.tangem.blockchain.common.TransactionStatus import com.tangem.blockchain.common.Wallet import com.tangem.tap.common.extensions.toFormattedString +import com.tangem.tap.domain.extensions.toSendableAmounts data class PendingTransaction( - val address: String?, - val amount: String?, - val currency: String, - val type: PendingTransactionType + val address: String?, + val amount: String?, + val currency: String, + val type: PendingTransactionType ) enum class PendingTransactionType { Incoming, Outgoing, Unknown } @@ -36,10 +37,10 @@ fun TransactionData.toPendingTransaction(walletAddress: String): PendingTransact } return PendingTransaction( - if (address == "unknown") null else address, - this.amount.value?.toFormattedString(amount.decimals), - this.amount.currencySymbol, - type + if (address == "unknown") null else address, + this.amount.value?.toFormattedString(amount.decimals), + this.amount.currencySymbol, + type ) } @@ -66,4 +67,8 @@ fun Wallet.getPendingTransactions(): List { fun Wallet.hasPendingTransactions(): Boolean { return getPendingTransactions().isNotEmpty() +} + +fun Wallet.hasSendableAmountsOrPendingTransactions(): Boolean { + return hasPendingTransactions() || amounts.toSendableAmounts().isNotEmpty() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt index aa6094f26c..54e7f12586 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt @@ -12,7 +12,7 @@ import com.tangem.tap.common.toggleWidget.WidgetState import com.tangem.tap.domain.configurable.warningMessage.WarningMessage import com.tangem.tap.domain.extensions.toSendableAmounts import com.tangem.tap.domain.topup.TradeCryptoHelper -import com.tangem.tap.features.twins.redux.TwinCardsState +import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState import com.tangem.tap.features.wallet.models.PendingTransaction import com.tangem.tap.features.wallet.models.toPendingTransactions import com.tangem.tap.features.wallet.models.toPendingTransactionsForToken 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 bdf79de67a..513627f250 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 @@ -19,8 +19,6 @@ import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.extensions.toSendableAmounts import com.tangem.tap.features.home.redux.HomeAction import com.tangem.tap.features.send.redux.PrepareSendScreen -import com.tangem.tap.features.twins.redux.CreateTwinWalletMode -import com.tangem.tap.features.twins.redux.TwinCardsAction import com.tangem.tap.features.wallet.redux.* import com.tangem.tap.network.NetworkStateChanged import kotlinx.coroutines.launch @@ -96,31 +94,22 @@ class WalletMiddleware { } } is WalletAction.CreateWallet -> { - if (walletState.isTangemTwins) { - store.dispatch(TwinCardsAction.Wallet.Create( - walletState.twinCardsState.cardNumber!!, - CreateTwinWalletMode.CreateWallet - )) - } else { - scope.launch { - val result = tangemSdkManager.createWallet( - globalState.scanResponse?.card?.cardId - ) - when (result) { - is CompletionResult.Success -> { - val scanNoteResponse = globalState.scanResponse?.copy(card = result.data) - scanNoteResponse?.let { - globalState.tapWalletManager.onCardScanned(scanNoteResponse) - } - } - is CompletionResult.Failure -> { - (result.error as? TangemSdkError)?.let { error -> - FirebaseAnalyticsHandler.logCardSdkError( - error, - FirebaseAnalyticsHandler.ActionToLog.CreateWallet, - card = store.state.detailsState.card - ) - } + scope.launch { + val result = tangemSdkManager.createWallet( + globalState.scanResponse?.card?.cardId + ) + when (result) { + is CompletionResult.Success -> { + val scanNoteResponse = globalState.scanResponse?.copy(card = result.data) + scanNoteResponse?.let { store.onCardScanned(scanNoteResponse) } + } + is CompletionResult.Failure -> { + (result.error as? TangemSdkError)?.let { error -> + FirebaseAnalyticsHandler.logCardSdkError( + error, + FirebaseAnalyticsHandler.ActionToLog.CreateWallet, + card = store.state.detailsState.card + ) } } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt index 8e0e9df126..ba5d6c7d56 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt @@ -38,13 +38,12 @@ private fun internalReduce(action: Action, state: AppState): WalletState { is WalletAction.ResetState -> newState = WalletState() is WalletAction.SetIfTestnetCard -> newState = newState.copy(isTestnet = action.isTestnet) is WalletAction.EmptyWallet -> { - val creatingWalletAllowed = state.twinCardsState.isCreatingTwinCardsAllowed newState = newState.copy( state = ProgressState.Done, wallets = listOf( WalletData( currencyData = BalanceWidgetData(BalanceStatus.EmptyCard), - mainButton = WalletMainButton.CreateWalletButton(creatingWalletAllowed), + mainButton = WalletMainButton.CreateWalletButton(true), ) ) ) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index b12080f1bd..f7978e35d8 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -150,8 +150,8 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber tv_twin_card_number.show() @@ -107,11 +105,6 @@ class SingleWalletView : WalletView { if (twinCardsState?.cardNumber == null) { tv_twin_card_number.hide() } - if (twinCardsState?.showTwinOnboarding == true) { - store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingTwins)) - } - - } private fun setupButtons( diff --git a/app/src/main/res/drawable/card_placeholder.xml b/app/src/main/res/drawable/card_placeholder.xml deleted file mode 100644 index 1cfef76e78..0000000000 --- a/app/src/main/res/drawable/card_placeholder.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/card_placeholder_black.xml b/app/src/main/res/drawable/card_placeholder_black.xml new file mode 100644 index 0000000000..0fef87ee39 --- /dev/null +++ b/app/src/main/res/drawable/card_placeholder_black.xml @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/card_placeholder_white.xml b/app/src/main/res/drawable/card_placeholder_white.xml new file mode 100644 index 0000000000..d980dc5599 --- /dev/null +++ b/app/src/main/res/drawable/card_placeholder_white.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_home_back_card.xml b/app/src/main/res/drawable/ic_home_back_card.xml deleted file mode 100644 index f15c47ba3f..0000000000 --- a/app/src/main/res/drawable/ic_home_back_card.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_home_front_card.xml b/app/src/main/res/drawable/ic_home_front_card.xml deleted file mode 100644 index 19969e806e..0000000000 --- a/app/src/main/res/drawable/ic_home_front_card.xml +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout-h680dp/layout_onboarding_bottom_action_views.xml b/app/src/main/res/layout-h680dp/layout_onboarding_container_bottom.xml similarity index 83% rename from app/src/main/res/layout-h680dp/layout_onboarding_bottom_action_views.xml rename to app/src/main/res/layout-h680dp/layout_onboarding_container_bottom.xml index a603013d47..e635e3ee6f 100644 --- a/app/src/main/res/layout-h680dp/layout_onboarding_bottom_action_views.xml +++ b/app/src/main/res/layout-h680dp/layout_onboarding_container_bottom.xml @@ -7,6 +7,7 @@ android:clipChildren="false"> + + diff --git a/app/src/main/res/layout/fragment_twin_cards_create.xml b/app/src/main/res/layout/fragment_twin_cards_create.xml deleted file mode 100644 index 7549f32998..0000000000 --- a/app/src/main/res/layout/fragment_twin_cards_create.xml +++ /dev/null @@ -1,160 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_twin_cards_warning.xml b/app/src/main/res/layout/fragment_twin_cards_warning.xml deleted file mode 100644 index 6ca8d8f68c..0000000000 --- a/app/src/main/res/layout/fragment_twin_cards_warning.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_twin_cards_welcome.xml b/app/src/main/res/layout/fragment_twin_cards_welcome.xml deleted file mode 100644 index c92e2adeb5..0000000000 --- a/app/src/main/res/layout/fragment_twin_cards_welcome.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_wallet.xml b/app/src/main/res/layout/fragment_wallet.xml index 3733c23089..bc98ff9e41 100644 --- a/app/src/main/res/layout/fragment_wallet.xml +++ b/app/src/main/res/layout/fragment_wallet.xml @@ -58,7 +58,7 @@ android:elevation="3dp" android:maxHeight="215dp" android:scaleType="fitCenter" - android:src="@drawable/card_placeholder" + android:src="@drawable/card_placeholder_black" app:layout_constraintTop_toTopOf="parent" /> + + + + + + + + + + + + - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/layout_twin_cards_orange.xml b/app/src/main/res/layout/layout_twin_cards_orange.xml deleted file mode 100644 index f524c5dd49..0000000000 --- a/app/src/main/res/layout/layout_twin_cards_orange.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/lp_onboarding_create_wallet.xml b/app/src/main/res/layout/lp_onboarding_create_wallet.xml index fa4505f353..3c5cd91655 100644 --- a/app/src/main/res/layout/lp_onboarding_create_wallet.xml +++ b/app/src/main/res/layout/lp_onboarding_create_wallet.xml @@ -6,6 +6,11 @@ android:layout_height="match_parent" android:visibility="visible"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/lp_onboarding_topup_wallet.xml b/app/src/main/res/layout/lp_onboarding_topup_wallet.xml index 65705f3fce..6b924ea771 100644 --- a/app/src/main/res/layout/lp_onboarding_topup_wallet.xml +++ b/app/src/main/res/layout/lp_onboarding_topup_wallet.xml @@ -6,6 +6,11 @@ android:layout_height="match_parent" android:visibility="visible"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/test_leapfrog_widget.xml b/app/src/main/res/layout/test_leapfrog_widget.xml index 3fbf992180..c4fddb3183 100644 --- a/app/src/main/res/layout/test_leapfrog_widget.xml +++ b/app/src/main/res/layout/test_leapfrog_widget.xml @@ -11,13 +11,12 @@ + android:src="@drawable/card_placeholder_black" + android:tint="@color/colorPrimary" /> + android:src="@drawable/card_placeholder_black" /> \ No newline at end of file diff --git a/app/src/main/res/layout/view_bg_twins_welcome.xml b/app/src/main/res/layout/view_bg_twins_welcome.xml new file mode 100644 index 0000000000..5202b1851b --- /dev/null +++ b/app/src/main/res/layout/view_bg_twins_welcome.xml @@ -0,0 +1,46 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_onboarding_progress.xml b/app/src/main/res/layout/view_onboarding_progress.xml index 415f8bd19c..8b2e151d1a 100644 --- a/app/src/main/res/layout/view_onboarding_progress.xml +++ b/app/src/main/res/layout/view_onboarding_progress.xml @@ -1,10 +1,13 @@ - + + + + diff --git a/app/src/main/res/layout/view_onboarding_tv_balance.xml b/app/src/main/res/layout/view_onboarding_tv_balance.xml index 5dd54d7067..6577933837 100644 --- a/app/src/main/res/layout/view_onboarding_tv_balance.xml +++ b/app/src/main/res/layout/view_onboarding_tv_balance.xml @@ -12,6 +12,7 @@ android:id="@+id/tv_balance" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:elevation="0dp" android:fontFamily="sans-serif-medium" android:text="@string/onboarding_balance_title" android:textAllCaps="true" diff --git a/app/src/main/res/values/strings_untranslated.xml b/app/src/main/res/values/strings_untranslated.xml index 17edb1b769..0d8661c471 100644 --- a/app/src/main/res/values/strings_untranslated.xml +++ b/app/src/main/res/values/strings_untranslated.xml @@ -14,25 +14,22 @@ Tangem Twin One wallet. Two cards. - This one that you are holding in your hands -and the other one with number %s.\n\nBoth cards can be used to extract funds from -this wallet. - + This one that you are holding in your handsand the other one with number #%s. Card %s of 2 Re-create twin wallet - This action is irreversible. You will not have access to the old wallet.\nThe wallet re-creation procedure consists of three steps. You must complete it to the end, otherwise you will have to start from the beginning. - Re-create wallet - Step %s - Tap the #%s twin card - Preparing card - Creating wallet - The wallet creation procedure consists of three steps. You must complete it to the end, otherwise you will have to start from the beginning. - Tap the card #%s - You have already started the process of recreating twin wallet. If you interrupt it, you won\'t be able to use your twin cards until you start it again and complete recreating the wallet. Card terms of use + Tangem Twin + This action is irreversible. You will not have access to the old wallet. + Tap the #%s twin card + Preparing card + Creating wallet + The wallet creation procedure consists of three steps. You must complete it to the end, otherwise you will have to start from the beginning. + Tap the card #%s + You have already started the process of recreating twin wallet. If you interrupt it, you won\'t be able to use your twin cards until you start it again and complete recreating the wallet. + The twin address was successfully created //Common @@ -188,11 +185,13 @@ this wallet. Show the wallet’s address Scan the address to top up your wallet - Done! + Success! Your crypto card is activated and ready to be used Continue Balance + If the process of re-creating the wallet gets interrupted in any way, you’ll have to start over. + Internal error: can\'t create wallet manager diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index f008a00608..fe7f02a527 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -5,8 +5,7 @@ @color/colorPrimary @color/colorSecondary @color/darkGray6 - @color/backgroundLightGray - false + true true true @null From 9febfba3218717f6c149ce36b96c8795288f7204 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 28 Oct 2021 00:24:35 +0300 Subject: [PATCH 13/18] Updated on 2026-08-14 --- .../tangem/tap/common/redux/navigation/NavigationReducer.kt | 3 +-- app/src/main/java/com/tangem/tap/features/BaseFragment.kt | 5 ----- .../onboarding/products/note/OnboardingNoteFragment.kt | 2 ++ .../products/otherCards/OnboardingOtherCardsFragment.kt | 2 ++ .../onboarding/products/twins/ui/TwinsCardsFragment.kt | 2 ++ .../java/com/tangem/tap/features/send/ui/SendFragment.kt | 2 ++ 6 files changed, 9 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationReducer.kt index 80cd5e3260..e742aa2e6b 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationReducer.kt @@ -20,8 +20,7 @@ private fun internalReduce(action: Action, state: AppState): NavigationState { navState.copy(backStack = navState.backStack + navigationAction.screen) } is NavigationAction.PopBackTo -> { - val screen = - navigationAction.screen ?: navState.activity?.get()?.getPreviousScreen() + val screen = navigationAction.screen ?: navState.activity?.get()?.getPreviousScreen() val index = navState.backStack.lastIndexOf(screen) + 1 state.navigationState.copy(backStack = navState.backStack.subList(0, index)) } diff --git a/app/src/main/java/com/tangem/tap/features/BaseFragment.kt b/app/src/main/java/com/tangem/tap/features/BaseFragment.kt index 8e1c2e098a..8b4d0d3f70 100644 --- a/app/src/main/java/com/tangem/tap/features/BaseFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/BaseFragment.kt @@ -38,11 +38,6 @@ abstract class BaseFragment(layoutId: Int) : Fragment(layoutId), FragmentOnBackP return mainView } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - addBackPressHandler(this) - } - override fun handleOnBackPressed() { store.dispatch(NavigationAction.PopBackTo()) } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt index 80b671393f..94eebeac22 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt @@ -19,6 +19,7 @@ import com.tangem.tap.common.postUi import com.tangem.tap.common.redux.navigation.ShareElement import com.tangem.tap.common.toggleWidget.RefreshBalanceWidget import com.tangem.tap.common.transitions.InternalNoteLayoutTransition +import com.tangem.tap.features.addBackPressHandler import com.tangem.tap.features.onboarding.products.BaseOnboardingFragment import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteAction import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteState @@ -49,6 +50,7 @@ class OnboardingNoteFragment : BaseOnboardingFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + addBackPressHandler(this) imv_front_card.transitionName = ShareElement.imvFrontCard startPostponedEnterTransition() diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt index f57e92fe03..cdd2871e00 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt @@ -10,6 +10,7 @@ import androidx.transition.TransitionManager import com.tangem.tap.common.extensions.getDrawableCompat import com.tangem.tap.common.redux.navigation.ShareElement import com.tangem.tap.common.transitions.InternalNoteLayoutTransition +import com.tangem.tap.features.addBackPressHandler import com.tangem.tap.features.onboarding.products.BaseOnboardingFragment import com.tangem.tap.features.onboarding.products.note.swapToBitmapDrawable import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsAction @@ -36,6 +37,7 @@ class OnboardingOtherCardsFragment : BaseOnboardingFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + addBackPressHandler(this) reconfigureLayoutForTwins() twinsWidget = TwinsCardWidget(LeapfrogWidget(cards_container)) { 250f } diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt index 4c35c25b24..4d9528605a 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt @@ -25,6 +25,7 @@ import com.tangem.tap.common.snackBar.MaxAmountSnackbar import com.tangem.tap.common.text.truncateMiddleWith import com.tangem.tap.common.toggleWidget.* import com.tangem.tap.features.BaseStoreFragment +import com.tangem.tap.features.addBackPressHandler import com.tangem.tap.features.send.redux.* import com.tangem.tap.features.send.redux.AddressPayIdActionUi.* import com.tangem.tap.features.send.redux.AmountActionUi.* @@ -64,6 +65,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + addBackPressHandler(this) etAmountToSend = view.findViewById(R.id.etAmountToSend) From d5cfa5a8bb75f819995efb3811a0b8b4ff6df177 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 28 Oct 2021 01:51:17 +0300 Subject: [PATCH 14/18] Updated on 2026-08-14 --- .../tap/features/onboarding/OnboardingManager.kt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt index 2b4894d5b9..984f512d4f 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt @@ -55,7 +55,7 @@ class OnboardingManager( } suspend fun updateBalance(walletManager: WalletManager): OnboardingWalletBalance { - return when (val result = walletManager.safeUpdate()) { + val balance = when (val result = walletManager.safeUpdate()) { is Result.Success -> { val wallet = walletManager.wallet val valueOfAmount = wallet.amounts[AmountType.Coin]?.value @@ -63,11 +63,10 @@ class OnboardingManager( val customError = TapError.CustomError("Amount is NULL") OnboardingWalletBalance.criticalError(customError) } else { - val currency = Currency.Blockchain(walletManager.wallet.blockchain) val balance = if (valueOfAmount.isZero()) { - OnboardingWalletBalance.done(valueOfAmount, wallet.hasPendingTransactions(), currency) + OnboardingWalletBalance.done(valueOfAmount, wallet.hasPendingTransactions()) } else { - OnboardingWalletBalance.done(valueOfAmount, false, currency) + OnboardingWalletBalance.done(valueOfAmount, false) } balance } @@ -81,6 +80,8 @@ class OnboardingManager( } } } + + return balance.copy(currency = Currency.Blockchain(walletManager.wallet.blockchain)) } fun activationStarted(cardId: String) { @@ -122,7 +123,10 @@ data class OnboardingWalletBalance( state = ProgressState.Loading ) - fun done(value: BigDecimal, hasTransactions: Boolean, currency: Currency.Blockchain): OnboardingWalletBalance = - OnboardingWalletBalance(value, currency, hasTransactions, ProgressState.Done) + fun done(value: BigDecimal, hasTransactions: Boolean): OnboardingWalletBalance = OnboardingWalletBalance( + value, + hasIncomingTransaction = hasTransactions, + state = ProgressState.Done + ) } } \ No newline at end of file From b96179be53643e5ebdb066699e66885471ccdac5 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 28 Oct 2021 01:52:07 +0300 Subject: [PATCH 15/18] Updated on 2026-08-14 --- .../toggleWidget/RefreshBalanceWidget.kt | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/toggleWidget/RefreshBalanceWidget.kt b/app/src/main/java/com/tangem/tap/common/toggleWidget/RefreshBalanceWidget.kt index e7ef08e026..277f839c05 100644 --- a/app/src/main/java/com/tangem/tap/common/toggleWidget/RefreshBalanceWidget.kt +++ b/app/src/main/java/com/tangem/tap/common/toggleWidget/RefreshBalanceWidget.kt @@ -41,30 +41,31 @@ class RefreshBalanceWidget( val progressState = state as? ProgressState ?: return val currentStateByView = getState() - - if (progressState == currentStateByView) return + when { + currentStateByView == progressState -> return + currentStateByView == ProgressState.Done -> if (progressState == ProgressState.Error) return + } animateState(progressState) viewSwitcher.showNext() - } private fun animateState(state: ProgressState) { when (state) { ProgressState.Done, ProgressState.Error -> { progressViewAnimation?.cancel() + progressViewAnimation = null } ProgressState.Loading -> { - val animation = RotateAnimation( - 0f, 360f, - Animation.RELATIVE_TO_SELF, 0.5f, - Animation.RELATIVE_TO_SELF, 0.5f + progressViewAnimation = RotateAnimation( + 0f, 360f, + Animation.RELATIVE_TO_SELF, 0.5f, + Animation.RELATIVE_TO_SELF, 0.5f ) - animation.duration = 700 - animation.interpolator = AccelerateInterpolator() - animation.repeatCount = -1 - arrowView.startAnimation(animation) - progressViewAnimation = animation + progressViewAnimation?.duration = 700 + progressViewAnimation?.interpolator = AccelerateInterpolator() + progressViewAnimation?.repeatCount = -1 + progressViewAnimation?.let { arrowView.startAnimation(it) } } } } @@ -88,10 +89,10 @@ class RefreshBalanceWidget( class ShowAnimation : AnimationSet(true) { init { addAnimation(ScaleAnimation( - 0f, 1f, - 0f, 1f, - Animation.RELATIVE_TO_SELF, 0.5f, - Animation.RELATIVE_TO_SELF, 0.5f) + 0f, 1f, + 0f, 1f, + Animation.RELATIVE_TO_SELF, 0.5f, + Animation.RELATIVE_TO_SELF, 0.5f) ) addAnimation(AlphaAnimation(0f, 1f)) duration = 300 From f94f78eb487a498aacdb20b9b5142e6f679b9751 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 28 Oct 2021 01:53:25 +0300 Subject: [PATCH 16/18] Updated on 2026-08-14 --- .../tap/domain/extensions/Blockchain.kt | 6 +++--- .../products/note/OnboardingNoteFragment.kt | 19 +++++++++++++------ .../note/redux/OnboardingNoteAction.kt | 2 ++ .../note/redux/OnboardingNoteMiddleware.kt | 6 ++++-- .../note/redux/OnboardingNoteReducer.kt | 3 +++ .../note/redux/OnboardingNoteState.kt | 2 ++ .../main/res/values/strings_untranslated.xml | 1 + 7 files changed, 28 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/extensions/Blockchain.kt b/app/src/main/java/com/tangem/tap/domain/extensions/Blockchain.kt index d658847574..4be4dda58f 100644 --- a/app/src/main/java/com/tangem/tap/domain/extensions/Blockchain.kt +++ b/app/src/main/java/com/tangem/tap/domain/extensions/Blockchain.kt @@ -13,10 +13,10 @@ fun Blockchain.isNoAccountError(exception: Throwable): Boolean { } } -fun Blockchain.amountToCreateAccount(token: Token? = null): Double? { +fun Blockchain.amountToCreateAccount(token: Token? = null): BigDecimal? { return when (this) { - Blockchain.Stellar -> if (token?.symbol == NODL) 1.5 else 1.toDouble() - Blockchain.XRP -> 10.toDouble() + Blockchain.Stellar -> if (token?.symbol == NODL) BigDecimal(1.5) else BigDecimal.ZERO + Blockchain.XRP -> BigDecimal(10) else -> null } } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt index 94eebeac22..b59e7ea667 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt @@ -15,7 +15,6 @@ import com.tangem.tangem_sdk_new.extensions.fadeIn import com.tangem.tangem_sdk_new.extensions.fadeOut import com.tangem.tap.common.extensions.getDrawableCompat import com.tangem.tap.common.extensions.stripZeroPlainString -import com.tangem.tap.common.postUi import com.tangem.tap.common.redux.navigation.ShareElement import com.tangem.tap.common.toggleWidget.RefreshBalanceWidget import com.tangem.tap.common.transitions.InternalNoteLayoutTransition @@ -137,14 +136,22 @@ class OnboardingNoteFragment : BaseOnboardingFragment() { } tv_header.setText(R.string.onboarding_top_up_header) - tv_body.setText(R.string.onboarding_top_up_body) + if (state.balanceNonCriticalError == null) { + tv_body.setText(R.string.onboarding_top_up_body) + } else { + state.walletBalance.amountToCreateAccount?.let { amount -> + val tvBodyMessage = getString( + R.string.onboarding_top_up_body_no_account_error, + amount, state.walletBalance.currency.currencySymbol + ) + tv_body.text = tvBodyMessage + } + } btnRefreshBalanceWidget.changeState(state.walletBalance.state) if (btnRefreshBalanceWidget.isShowing != true) { - postUi(300) { - btnRefreshBalanceWidget.mainView.setOnClickListener { - store.dispatch(OnboardingNoteAction.Balance.Update) - } + btnRefreshBalanceWidget.mainView.setOnClickListener { + store.dispatch(OnboardingNoteAction.Balance.Update) } } imv_card_background.setBackgroundDrawable(requireContext().getDrawableCompat(R.drawable.shape_rectangle_rounded_8)) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt index 73b588ee69..3a370e6c72 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt @@ -1,6 +1,7 @@ package com.tangem.tap.features.onboarding.products.note.redux import com.tangem.blockchain.common.WalletManager +import com.tangem.tap.domain.TapError import com.tangem.tap.features.onboarding.OnboardingWalletBalance import com.tangem.tap.features.wallet.redux.Artwork import org.rekotlin.Action @@ -26,6 +27,7 @@ sealed class OnboardingNoteAction : Action { sealed class Balance { object Update : OnboardingNoteAction() data class Set(val balance: OnboardingWalletBalance) : OnboardingNoteAction() + data class SetNonCriticalError(val error: TapError?) : OnboardingNoteAction() } sealed class Confetti { 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 0ef12f9c8f..125ba49fff 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 @@ -119,9 +119,11 @@ private fun handleNoteAction(action: Action, dispatch: DispatchFunction) { val loadedBalance = onboardingManager.updateBalance(walletManager) loadedBalance.criticalError?.let { store.dispatchErrorNotification(it) } delay(if (isLoadedBefore) 0 else 300) - withMainContext { store.dispatch(OnboardingNoteAction.Balance.Set(loadedBalance)) } + withMainContext { + store.dispatch(OnboardingNoteAction.Balance.Set(loadedBalance)) + store.dispatch(OnboardingNoteAction.Balance.SetNonCriticalError(loadedBalance.error)) + } } - } is OnboardingNoteAction.Balance.Set -> { if (action.balance.balanceIsToppedUp()) { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteReducer.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteReducer.kt index 206a4893ab..260f41fc20 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteReducer.kt @@ -26,6 +26,9 @@ private fun internalReduce(action: Action, appState: AppState): OnboardingNoteSt is OnboardingNoteAction.Balance.Set -> { state = state.copy(walletBalance = action.balance) } + is OnboardingNoteAction.Balance.SetNonCriticalError -> { + state = state.copy(balanceNonCriticalError = action.error) + } is OnboardingNoteAction.SetStepOfScreen -> { if (action.step != state.currentStep && state.steps.contains(action.step)) { state = state.copy(currentStep = action.step) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteState.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteState.kt index 23def7368f..3cf07bea6b 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteState.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteState.kt @@ -1,6 +1,7 @@ package com.tangem.tap.features.onboarding.products.note.redux import com.tangem.blockchain.common.WalletManager +import com.tangem.tap.domain.TapError import com.tangem.tap.features.onboarding.OnboardingWalletBalance import com.tangem.tap.features.wallet.redux.Artwork import org.rekotlin.StateType @@ -13,6 +14,7 @@ data class OnboardingNoteState( // UI val cardArtwork: Artwork? = null, val walletBalance: OnboardingWalletBalance = OnboardingWalletBalance.loading(), + val balanceNonCriticalError: TapError? = null, val currentStep: OnboardingNoteStep = OnboardingNoteStep.None, val steps: List = OnboardingNoteStep.values().toList(), val showConfetti: Boolean = false, diff --git a/app/src/main/res/values/strings_untranslated.xml b/app/src/main/res/values/strings_untranslated.xml index 0d8661c471..cb9cdc7224 100644 --- a/app/src/main/res/values/strings_untranslated.xml +++ b/app/src/main/res/values/strings_untranslated.xml @@ -181,6 +181,7 @@ Top up your wallet To get started, simply top up the card with any amount + To get started, simply top up the wallet with more than %s %s. Buy crypto Show the wallet’s address Scan the address to top up your wallet From 4bf16417fb988c6d4c1fff250db2ce808a3c021f Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 28 Oct 2021 01:54:15 +0300 Subject: [PATCH 17/18] Updated on 2026-08-14 --- .../tap/domain/twins/TwinCardsManager.kt | 13 +++-------- .../twins/redux/TwinCardsMiddleware.kt | 22 +++---------------- 2 files changed, 6 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt index e16ccd79cb..861f3db801 100644 --- a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt @@ -26,14 +26,9 @@ class TwinCardsManager(private val card: Card, assetReader: AssetReader) { private val issuerKeyPair: KeyPair = getIssuerKeys(assetReader, card.issuer.publicKey.toHexString()) suspend fun createFirstWallet(message: Message): CompletionResult { - val response = tangemSdkManager.runTaskAsync( - CreateFirstTwinWalletTask(), currentCardId, message - ) + val response = tangemSdkManager.runTaskAsync(CreateFirstTwinWalletTask(), currentCardId, message) when (response) { - is CompletionResult.Success -> { - currentCardPublicKey = response.data.wallet.publicKey.toHexString() - return response - } + is CompletionResult.Success -> currentCardPublicKey = response.data.wallet.publicKey.toHexString() is CompletionResult.Failure -> { (response.error as? TangemSdkError)?.let { error -> FirebaseAnalyticsHandler.logCardSdkError( @@ -42,13 +37,11 @@ class TwinCardsManager(private val card: Card, assetReader: AssetReader) { card = card ) } - return response } } - + return response } - suspend fun createSecondWallet( initialMessage: Message, preparingMessage: Message, diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt index f56502e209..26fbfb104b 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt @@ -72,7 +72,6 @@ private fun handle(action: Action, dispatch: DispatchFunction) { if (twinCardsState.mode == CreateTwinWalletMode.CreateWallet) { onboardingManager?.activationFinished(getScanResponse().card.cardId) twinCardsState.pairCardId?.let { onboardingManager?.activationFinished(it) } - } } @@ -121,23 +120,9 @@ private fun handle(action: Action, dispatch: DispatchFunction) { } is TwinCardsAction.SetStepOfScreen -> { when (action.step) { - TwinCardsStep.WelcomeOnly -> { - preferencesStorage.saveTwinsOnboardingShown() - } - TwinCardsStep.Welcome -> { - preferencesStorage.saveTwinsOnboardingShown() - } - TwinCardsStep.Warning -> { - } - TwinCardsStep.CreateFirstWallet -> { - } - TwinCardsStep.CreateSecondWallet -> { - } - TwinCardsStep.CreateThirdWallet -> { - } - TwinCardsStep.TopUpWallet -> { - store.dispatch(TwinCardsAction.Balance.Update) - } + TwinCardsStep.WelcomeOnly -> preferencesStorage.saveTwinsOnboardingShown() + TwinCardsStep.Welcome -> preferencesStorage.saveTwinsOnboardingShown() + TwinCardsStep.TopUpWallet -> store.dispatch(TwinCardsAction.Balance.Update) TwinCardsStep.Done -> { finishCardActivation() postUi(500) { store.dispatch(TwinCardsAction.Confetti.Show) } @@ -200,7 +185,6 @@ private fun handle(action: Action, dispatch: DispatchFunction) { } } } - is TwinCardsAction.Balance.Update -> { val walletManager = if (twinCardsState.walletManager != null) { twinCardsState.walletManager From 2f7c0447fc83891d458fc989231a2644b12c6aad Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 28 Oct 2021 02:17:42 +0300 Subject: [PATCH 18/18] Updated on 2026-08-14 --- app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt b/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt index 01ef833c3d..d734698fd5 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt @@ -58,7 +58,7 @@ object TapWorkarounds { "AB02" to Blockchain.Ethereum, "AB03" to Blockchain.CardanoShelley, "AB04" to Blockchain.Dogecoin, - "AB05" to Blockchain.Binance, + "AB05" to Blockchain.BSC, "AB06" to Blockchain.XRP, ) }