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 baec3d76f4..0c8de5dc8d 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 @@ -23,7 +23,7 @@ val globalMiddleware: Middleware = { dispatch, appState -> if (it.hideWarning(action.warning)) { if (WarningMessagesManager.isAlreadySignedHashesWarning(action.warning)) { //TODO: No appropriate warningMessage identification. Make it better later - store.dispatch(WalletAction.CheckSignedHashes.SaveCardId) + store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId) } store.dispatch(WalletAction.Warnings.SetWarnings( 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 51883d2e9a..3456649d7f 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -140,7 +140,6 @@ class TapWalletManager { suspend fun loadData(data: ScanNoteResponse) { withContext(Dispatchers.Main) { - //TODO: I made it to WalletAction.CheckSignedHashes.CheckIfWarningNeeded store.dispatch(WalletAction.Warnings.CheckIfNeeded) val artworkId = data.verifyResponse?.artworkInfo?.id if (data.walletManager != null) { 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 182e1d63d5..760383cfed 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 @@ -1,12 +1,11 @@ package com.tangem.tap.features.wallet.redux import android.content.Context -import com.tangem.blockchain.common.* import com.tangem.TangemError -import com.tangem.blockchain.common.Amount -import com.tangem.blockchain.common.Wallet +import com.tangem.blockchain.common.* import com.tangem.blockchain.common.address.AddressType import com.tangem.commands.common.card.Card +import com.tangem.tap.common.redux.ErrorAction import com.tangem.tap.common.redux.NotificationAction import com.tangem.tap.common.redux.global.CryptoCurrencyName import com.tangem.tap.domain.TapError @@ -63,21 +62,20 @@ sealed class WalletAction : Action { data class SetPrimaryToken(val token: Token) : MultiWallet() } - sealed class CheckSignedHashes : WalletAction() { - object CheckIfWarningNeeded : CheckSignedHashes() - object CheckHashesCountOnline : CheckSignedHashes() - object NeedToCheckHashesCountOnline : CheckSignedHashes() - object ConfirmHashesCount : CheckSignedHashes() - object SaveCardId : CheckSignedHashes() - } + sealed class Warnings : WalletAction() { + object CheckHashesCount : Warnings() { + object CheckHashesCountOnline : Warnings() + object NeedToCheckHashesCountOnline : Warnings() + object ConfirmHashesCount : Warnings() + object SaveCardId : Warnings() + } - object Warnings : WalletAction() { - object CheckIfNeeded : WalletAction() - data class SetWarnings(val warningList: List) : WalletAction() + object CheckIfNeeded : Warnings() + data class SetWarnings(val warningList: List) : Warnings() - object AppRating : WalletAction() { - object SetNeverToShow : WalletAction() - object RemindLater : WalletAction() + object AppRating : Warnings() { + object SetNeverToShow : Warnings() + object RemindLater : Warnings() } } @@ -107,51 +105,43 @@ sealed class WalletAction : Action { object Cancel : WalletAction() } - object CreatePayId : WalletAction() { - data class CompleteCreatingPayId(val payId: String) : WalletAction() - data class Success(val payId: String) : WalletAction() - object EmptyField : WalletAction(), ErrorAction { - override val error = TapError.PayIdEmptyField + + object EmptyField : WalletAction(), ErrorAction { + override val error = TapError.PayIdEmptyField + } + + data class CopyAddress(val address: String, val context: Context) : WalletAction() { + object Success : WalletAction(), NotificationAction { + override val messageResource = R.string.wallet_notification_address_copied } + } - data class CopyAddress(val address: String, val context: Context) : WalletAction() { - object Success : WalletAction(), NotificationAction { - override val messageResource = R.string.wallet_notification_address_copied - } - } + data class ShareAddress(val address: String, val context: Context) : WalletAction() - data class ShareAddress(val address: String, val context: Context) : WalletAction() + object ShowDialog : WalletAction() { + object QrCode : WalletAction() + object ScanFails : WalletAction() + } - object ShowDialog : WalletAction() { - object QrCode : WalletAction() - object ScanFails : WalletAction() - } + object HideDialog : WalletAction() - object HideDialog : WalletAction() + data class ExploreAddress(val exploreUrl: String, val context: Context) : WalletAction() - data class ExploreAddress(val exploreUrl: String, val context: Context) : WalletAction() + object CreateWallet : WalletAction() + object EmptyWallet : WalletAction() - object CreateWallet : WalletAction() - object EmptyWallet : WalletAction() - object Scan : WalletAction() + sealed class TopUpAction : WalletAction() { + data class TopUp(val context: Context, val toolbarColor: Int) : TopUpAction() + } - data class Send(val amount: Amount? = null) : WalletAction() { - data class ChooseCurrency(val amounts: List?) : WalletAction() - object Cancel : WalletAction() - } + data class ChangeSelectedAddress(val type: AddressType) : WalletAction() - sealed class TopUpAction : WalletAction() { - data class TopUp(val context: Context, val toolbarColor: Int) : TopUpAction() - } - - 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 + 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/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletMiddleware.kt deleted file mode 100644 index 3f3534891e..0000000000 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletMiddleware.kt +++ /dev/null @@ -1,356 +0,0 @@ -package com.tangem.tap.features.wallet.redux - -import android.content.Intent -import android.net.Uri -import androidx.browser.customtabs.CustomTabsIntent -import androidx.core.content.ContextCompat -import com.tangem.TangemSdkError -import com.tangem.blockchain.common.* -import com.tangem.blockchain.extensions.SimpleResult -import com.tangem.commands.common.card.Card -import com.tangem.commands.common.card.CardType -import com.tangem.commands.common.network.Result -import com.tangem.common.CompletionResult -import com.tangem.common.extensions.getType -import com.tangem.common.extensions.toHexString -import com.tangem.tap.common.analytics.AnalyticsEvent -import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler -import com.tangem.tap.common.extensions.copyToClipboard -import com.tangem.tap.common.extensions.isGreaterThan -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.PayIdManager -import com.tangem.tap.domain.TapError -import com.tangem.tap.domain.TopUpHelper -import com.tangem.tap.domain.configurable.warningMessage.WarningMessage -import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager -import com.tangem.tap.domain.extensions.toSendableAmounts -import com.tangem.tap.domain.twins.TwinsHelper -import com.tangem.tap.domain.twins.isTwinCard -import com.tangem.tap.features.details.redux.DetailsAction -import com.tangem.tap.features.details.redux.twins.CreateTwinWallet -import com.tangem.tap.features.send.redux.PrepareSendScreen -import com.tangem.tap.features.wallet.models.toPendingTransactions -import com.tangem.tap.network.NetworkConnectivity -import com.tangem.tap.network.NetworkStateChanged -import com.tangem.tap.preferencesStorage -import com.tangem.tap.scope -import com.tangem.tap.store -import com.tangem.tap.tangemSdkManager -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import org.rekotlin.Action -import org.rekotlin.Middleware -import java.math.BigDecimal - -class WalletMiddleware { - private val topUpMiddleware = TopUpMiddleware() - - val walletMiddleware: Middleware = { dispatch, state -> - { next -> - { action -> - when (action) { - is WalletAction.TopUpAction -> topUpMiddleware.handle(action) - is WalletAction.LoadWallet -> { - scope.launch { - store.state.globalState.tapWalletManager.loadWalletData() - } - } - is WalletAction.LoadPayId -> { - scope.launch { - store.state.globalState.tapWalletManager.loadPayId() - } - } - is WalletAction.LoadFiatRate -> { - scope.launch { - store.state.globalState.tapWalletManager.loadFiatRate(store.state.globalState.appCurrency) - } - } - is WalletAction.CreateWallet -> { - if (store.state.walletState.twinCardsState != null) { - store.dispatch(DetailsAction.CreateTwinWalletAction.ShowWarning( - store.state.globalState.scanNoteResponse?.card?.cardId?.let { - TwinsHelper.getTwinCardNumber(it) - }, - CreateTwinWallet.CreateWallet - )) - } else { - scope.launch { - val result = tangemSdkManager.createWallet( - store.state.globalState.scanNoteResponse?.card?.cardId - ) - when (result) { - is CompletionResult.Success -> { - store.state.globalState.tapWalletManager - .onCardScanned(result.data) - } - - } - } - } - } - is WalletAction.UpdateWallet -> { - if (store.state.walletState.state == ProgressState.Done) { - scope.launch { store.state.globalState.tapWalletManager.updateWallet() } - } - } - is WalletAction.UpdateWallet.Success -> setupWalletUpdate(action.wallet) - is WalletAction.LoadWallet.Success -> { - store.dispatch(WalletAction.CheckHashesCountOnline) - if (!store.state.walletState.updatingWallet) setupWalletUpdate(action.wallet) - tryToShowAppRatingWarning(action.wallet) - } - is WalletAction.CreatePayId.CompleteCreatingPayId -> { - scope.launch { - val cardId = store.state.globalState.scanNoteResponse?.card?.cardId - val wallet = store.state.globalState.scanNoteResponse?.walletManager?.wallet - val publicKey = store.state.globalState.scanNoteResponse?.card?.cardPublicKey - if (cardId != null && wallet != null && publicKey != null) { - val result = PayIdManager().setPayId( - cardId, publicKey.toHexString(), - action.payId, wallet.address, wallet.blockchain - ) - withContext(Dispatchers.Main) { - when (result) { - is Result.Success -> - store.dispatch(WalletAction.CreatePayId.Success(action.payId)) - is Result.Failure -> { - val error = result.error as? TapError - ?: TapError.PayIdCreatingError - store.dispatch(WalletAction.CreatePayId.Failure(error)) - } - } - } - } - } - } - is WalletAction.Scan -> { - scope.launch { - val result = tangemSdkManager.scanNote(FirebaseAnalyticsHandler) - when (result) { - is CompletionResult.Success -> { - tangemSdkManager.changeDisplayedCardIdNumbersCount(result.data.card) - store.state.globalState.tapWalletManager - .onCardScanned(result.data, true) - if (store.state.walletState.twinCardsState != null) { - val showOnboarding = !preferencesStorage.wasTwinsOnboardingShown() - if (showOnboarding) { - store.dispatch(NavigationAction.NavigateTo(AppScreen.TwinsOnboarding)) - } - } - store.dispatch(WalletAction.ScanCardFinished()) - } - is CompletionResult.Failure -> { - if (result.error !is TangemSdkError.UserCancelled) { - // Weird things... If you run the code below without coroutines, - // then rescanning will be impossible - scope.launch(Dispatchers.Main) { - store.dispatch(WalletAction.ScanCardFinished(result.error)) - if (store.state.walletState.scanCardFailsCounter >= 2) { - store.dispatch(WalletAction.ShowDialog.ScanFails) - } - } - } - } - } - } - } - is WalletAction.LoadData -> { - scope.launch { - store.state.globalState.scanNoteResponse?.let { - store.state.globalState.tapWalletManager.loadData(it) - } - } - } - is NetworkStateChanged -> { - store.state.globalState.scanNoteResponse?.let { scanNoteResponse -> - store.dispatch(WalletAction.CheckHashesCountOnline) - scope.launch { - store.state.globalState.tapWalletManager.onCardScanned(scanNoteResponse) - } - } - } - is WalletAction.CopyAddress -> { - store.state.walletState.walletAddresses?.selectedAddress?.address?.let { - action.context.copyToClipboard(it) - store.dispatch(WalletAction.CopyAddress.Success) - } - } - is WalletAction.ExploreAddress -> { - val uri = Uri.parse(store.state.walletState.walletAddresses?.selectedAddress?.exploreUrl) - val intent = Intent(Intent.ACTION_VIEW, uri) - ContextCompat.startActivity(action.context, intent, null) - } - is WalletAction.Send -> { - val newAction = prepareSendAction(action.amount) - store.dispatch(newAction) - if (newAction is PrepareSendScreen) { - store.dispatch(NavigationAction.NavigateTo(AppScreen.Send)) - } - } - is WalletAction.Warnings.CheckIfNeeded -> { - val globalState = store.state.globalState - val validator = globalState.scanNoteResponse?.walletManager as? SignatureCountValidator - globalState.scanNoteResponse?.card?.let { card -> - store.state.globalState.warningManager?.removeWarnings(WarningMessage.Origin.Local) - if (card.getType() != CardType.Release) addWarningMessage(WarningMessagesManager.devCardWarning()) - if (!preferencesStorage.wasCardScannedBefore(card.cardId)) { - checkIfWarningNeeded(card, validator)?.let { addWarningMessage(it) } - } - updateWarningMessages() - } - } - is WalletAction.CheckHashesCountOnline -> checkHashesCountOnline() - is WalletAction.SaveCardId -> { - val cardId = store.state.globalState.scanNoteResponse?.card?.cardId - cardId?.let { preferencesStorage.saveScannedCardId(it) } - } - is WalletAction.TwinsAction.SetTwinCard -> { - val showOnboarding = !preferencesStorage.wasTwinsOnboardingShown() - if (showOnboarding) store.dispatch(WalletAction.TwinsAction.ShowOnboarding) - } - is WalletAction.TwinsAction.SetOnboardingShown -> { - preferencesStorage.saveTwinsOnboardingShown() - } - is WalletAction.Warnings.AppRating.RemindLater -> { - preferencesStorage.appRatingLaunchObserver.applyDelayedShowing() - } - is WalletAction.Warnings.AppRating.SetNeverToShow -> { - preferencesStorage.appRatingLaunchObserver.setNeverToShow() - } - } - next(action) - } - } - } - - private fun tryToShowAppRatingWarning(wallet: Wallet) { - val nonZeroWalletsCount = wallet.amounts.filter { - it.value.value?.isGreaterThan(BigDecimal.ZERO) ?: false - }.size - if (nonZeroWalletsCount > 0) { - preferencesStorage.appRatingLaunchObserver.foundWalletWithFunds() - } - if (preferencesStorage.appRatingLaunchObserver.isReadyToShow()) { - FirebaseAnalyticsHandler.triggerEvent(AnalyticsEvent.APP_RATING_DISPLAYED) - addWarningMessage(WarningMessagesManager.appRatingWarning(), true) - } - } - - private fun setupWalletUpdate(wallet: Wallet) { - if (!wallet.recentTransactions.toPendingTransactions(wallet.address).isNullOrEmpty()) { - store.dispatch(WalletAction.UpdateWallet.ScheduleUpdatingWallet) - scope.launch(Dispatchers.IO) { - delay(10000) - withContext(Dispatchers.Main) { - store.dispatch(WalletAction.UpdateWallet) - } - } - } - } - - - private fun prepareSendAction(amount: Amount?): Action { - return if (amount != null) { - if (amount.type is AmountType.Token) { - PrepareSendScreen(store.state.walletState.wallet?.amounts?.get(AmountType.Coin), amount) - } else { - PrepareSendScreen(amount) - } - } else { - val amounts = store.state.walletState.wallet?.amounts?.toSendableAmounts() - if (amounts?.size ?: 0 > 1) { - WalletAction.Send.ChooseCurrency(amounts) - } else { - val amountToSend = amounts?.first() - PrepareSendScreen(amountToSend) - } - } - } - - private fun checkIfWarningNeeded( - card: Card, signatureCountValidator: SignatureCountValidator? = null, - ): WarningMessage? { - if (card.isTwinCard()) return null - - return if (signatureCountValidator == null) { - if (card.walletSignedHashes ?: 0 > 0) { - WarningMessagesManager.alreadySignedHashesWarning() - } else { - store.dispatch(WalletAction.SaveCardId) - null - } - } else { - store.dispatch(WalletAction.NeedToCheckHashesCountOnline) - null - } - } - - private fun checkHashesCountOnline() { - if (store.state.walletState.hashesCountVerified != false) return - if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) return - - val card = store.state.globalState.scanNoteResponse?.card - if (card == null || preferencesStorage.wasCardScannedBefore(card.cardId)) return - - if (card.isTwinCard()) return - - val validator = store.state.globalState.scanNoteResponse?.walletManager - as? SignatureCountValidator - scope.launch { - val result = validator?.validateSignatureCount(card.walletSignedHashes ?: 0) - withContext(Dispatchers.Main) { - when (result) { - SimpleResult.Success -> { - store.dispatch(WalletAction.ConfirmHashesCount) - store.dispatch(WalletAction.SaveCardId) - } - is SimpleResult.Failure -> - if (result.error is BlockchainSdkError.SignatureCountNotMatched) { - addWarningMessage(WarningMessagesManager.alreadySignedHashesWarning(), true) - } else if (card.walletSignedHashes ?: 0 > 0) { - addWarningMessage(WarningMessagesManager.alreadySignedHashesWarning(), true) - } - } - } - } - } - - private fun addWarningMessage(warning: WarningMessage, autoUpdate: Boolean = false) { - store.state.globalState.warningManager?.addWarning(warning) - if (autoUpdate) updateWarningMessages() - } - - private fun updateWarningMessages() { - val warningManager = store.state.globalState.warningManager ?: return - store.dispatch(WalletAction.Warnings.SetWarnings( - warningManager.getWarnings(WarningMessage.Location.MainScreen))) - } -} - -private class TopUpMiddleware { - fun handle(action: WalletAction.TopUpAction) { - when (action) { - is WalletAction.TopUpAction.TopUp -> { - val config = store.state.globalState.configManager?.config ?: return - val addresses = store.state.walletState.walletAddresses ?: return - if (addresses.list.isEmpty()) return - - val defaultAddress = addresses.list[0].address - val url = TopUpHelper.getUrl( - store.state.walletState.currencyData.currencySymbol!!, - defaultAddress, - config.moonPayApiKey, - config.moonPayApiSecretKey - ) - val customTabsIntent = CustomTabsIntent.Builder() - .setToolbarColor(action.toolbarColor) - .build() - customTabsIntent.launchUrl(action.context, Uri.parse(url)); - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt index 282d78393a..2ced6e5201 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt @@ -39,7 +39,7 @@ private fun internalReduce(action: Action, state: AppState): WalletState { var newState = state.walletState when (action) { - is WalletAction.CheckSignedHashes -> newState = handleCheckSignedHashesActions(action, newState) + is WalletAction.Warnings -> newState = handleCheckSignedHashesActions(action, newState) is WalletAction.TwinsAction -> newState = twinsReducer.reduce(action, newState) is WalletAction.MultiWallet -> newState = multiWalletReducer.reduce(action, newState) @@ -235,10 +235,6 @@ private fun internalReduce(action: Action, state: AppState): WalletState { ) } is WalletAction.Send.Cancel -> newState = newState.copy(walletDialog = null) - is WalletAction.Warnings.SetWarnings -> newState = newState.copy(mainWarningsList = action.warningList) - is WalletAction.TopUpAction -> { - newState = newState.copy(topUpState = handleTopUpActions(action, newState.topUpState)) - } is WalletAction.TopUpAction -> return newState is WalletAction.ChangeSelectedAddress -> { val selectedWalletData = newState.getWalletData(newState.selectedWallet) @@ -286,13 +282,18 @@ fun createAddressList(wallet: Wallet?, walletAddresses: WalletAddresses? = null) return WalletAddresses(listOfAddressData[indexOfSelectedWallet], listOfAddressData) } -private fun handleCheckSignedHashesActions(action: WalletAction.CheckSignedHashes, state: WalletState): WalletState { +private fun handleCheckSignedHashesActions(action: WalletAction.Warnings, state: WalletState): WalletState { return when (action) { - WalletAction.CheckSignedHashes.CheckHashesCountOnline -> state - WalletAction.CheckSignedHashes.CheckIfWarningNeeded -> state - WalletAction.CheckSignedHashes.ConfirmHashesCount -> state.copy(hashesCountVerified = true) - WalletAction.CheckSignedHashes.NeedToCheckHashesCountOnline -> state.copy(hashesCountVerified = false) - WalletAction.CheckSignedHashes.SaveCardId -> state + WalletAction.Warnings.CheckHashesCount.CheckHashesCountOnline -> state + WalletAction.Warnings.CheckHashesCount.ConfirmHashesCount -> state.copy(hashesCountVerified = true) + WalletAction.Warnings.CheckHashesCount.NeedToCheckHashesCountOnline -> state.copy(hashesCountVerified = false) + WalletAction.Warnings.CheckHashesCount.SaveCardId -> state + is WalletAction.Warnings.SetWarnings -> state.copy(mainWarningsList = action.warningList) + WalletAction.Warnings.CheckIfNeeded -> state + WalletAction.Warnings.AppRating -> state + WalletAction.Warnings.CheckHashesCount -> state + WalletAction.Warnings.AppRating.RemindLater -> state + WalletAction.Warnings.AppRating.SetNeverToShow -> state } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TopUpMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TopUpMiddleware.kt index c155519eae..e0706570f7 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TopUpMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TopUpMiddleware.kt @@ -12,7 +12,10 @@ class TopUpMiddleware { is WalletAction.TopUpAction.TopUp -> { val selectedWalletData = store.state.walletState.getSelectedWalletData() val config = store.state.globalState.configManager?.config ?: return - val defaultAddress = selectedWalletData?.walletAddresses!!.list[0].address + val addresses = selectedWalletData?.walletAddresses ?: return + if (addresses.list.isEmpty()) return + + val defaultAddress = addresses.list[0].address val url = TopUpHelper.getUrl( selectedWalletData.currencyData.currencySymbol!!, defaultAddress, 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 a82debea08..54a51ff45e 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -3,6 +3,7 @@ package com.tangem.tap.features.wallet.redux.middlewares import android.content.Intent import android.net.Uri import androidx.core.content.ContextCompat +import com.tangem.TangemSdkError import com.tangem.blockchain.common.* import com.tangem.common.CompletionResult import com.tangem.tap.* @@ -22,6 +23,7 @@ import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletData import com.tangem.tap.features.wallet.redux.WalletState import com.tangem.tap.network.NetworkStateChanged +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.rekotlin.Action import org.rekotlin.Middleware @@ -29,7 +31,7 @@ import org.rekotlin.Middleware class WalletMiddleware { private val topUpMiddleware = TopUpMiddleware() private val twinsMiddleware = TwinsMiddleware() - private val checkSignedHashesMiddleware = CheckSignedHashesMiddleware() + private val warningsMiddleware = WarningsMiddleware() private val multiWalletMiddleware = MultiWalletMiddleware() val walletMiddleware: Middleware = { dispatch, state -> @@ -40,8 +42,7 @@ class WalletMiddleware { when (action) { is WalletAction.TopUpAction -> topUpMiddleware.handle(action) is WalletAction.TwinsAction -> twinsMiddleware.handle(action) - is WalletAction.CheckSignedHashes -> - checkSignedHashesMiddleware.handle(action, globalState) + is WalletAction.Warnings -> warningsMiddleware.handle(action, globalState) is WalletAction.MultiWallet -> multiWalletMiddleware.handle(action, walletState, globalState) @@ -57,6 +58,10 @@ class WalletMiddleware { } } } + is WalletAction.LoadWallet.Success -> { + store.dispatch(WalletAction.Warnings.CheckHashesCount.CheckHashesCountOnline) + warningsMiddleware.tryToShowAppRatingWarning(action.wallet) + } is WalletAction.LoadFiatRate -> { scope.launch { if (action.wallet != null) { @@ -118,9 +123,6 @@ class WalletMiddleware { } } - is WalletAction.LoadWallet.Success -> { - store.dispatch(WalletAction.CheckSignedHashes.CheckHashesCountOnline) - } is WalletAction.Scan -> { scope.launch { val result = tangemSdkManager.scanNote(FirebaseAnalyticsHandler) @@ -135,13 +137,25 @@ class WalletMiddleware { store.dispatch(NavigationAction.NavigateTo(AppScreen.TwinsOnboarding)) } } + store.dispatch(WalletAction.ScanCardFinished()) + } + is CompletionResult.Failure -> { + if (result.error !is TangemSdkError.UserCancelled) { + scope.launch(Dispatchers.Main) { + store.dispatch(WalletAction.ScanCardFinished(result.error)) + if (store.state.walletState.scanCardFailsCounter >= 2) { + store.dispatch(WalletAction.ShowDialog.ScanFails) + } + } + } } } } } is WalletAction.LoadData -> { scope.launch { - val scanNoteResponse = globalState?.scanNoteResponse ?: return@launch + val scanNoteResponse = globalState?.scanNoteResponse + ?: return@launch if (!walletState?.wallets.isNullOrEmpty()) { globalState.tapWalletManager.reloadData(scanNoteResponse) } else { @@ -151,7 +165,7 @@ class WalletMiddleware { } is NetworkStateChanged -> { globalState?.scanNoteResponse?.let { scanNoteResponse -> - store.dispatch(WalletAction.CheckSignedHashes.CheckHashesCountOnline) + store.dispatch(WalletAction.Warnings.CheckHashesCount.CheckHashesCountOnline) scope.launch { globalState.tapWalletManager.loadData(scanNoteResponse) } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/CheckSignedHashesMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt similarity index 64% rename from app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/CheckSignedHashesMiddleware.kt rename to app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt index 9ae002d4ad..9be3da6c55 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/CheckSignedHashesMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt @@ -2,10 +2,14 @@ package com.tangem.tap.features.wallet.redux.middlewares import com.tangem.blockchain.common.BlockchainSdkError import com.tangem.blockchain.common.SignatureCountValidator +import com.tangem.blockchain.common.Wallet import com.tangem.blockchain.extensions.SimpleResult import com.tangem.commands.common.card.Card import com.tangem.commands.common.card.CardType import com.tangem.common.extensions.getType +import com.tangem.tap.common.analytics.AnalyticsEvent +import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler +import com.tangem.tap.common.extensions.isGreaterThan import com.tangem.tap.common.redux.global.GlobalState import com.tangem.tap.domain.configurable.warningMessage.WarningMessage import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager @@ -19,11 +23,12 @@ import com.tangem.tap.store import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import java.math.BigDecimal -class CheckSignedHashesMiddleware { - fun handle(action: WalletAction.CheckSignedHashes, globalState: GlobalState?) { +class WarningsMiddleware { + fun handle(action: WalletAction.Warnings, globalState: GlobalState?) { when (action) { - is WalletAction.CheckSignedHashes.CheckIfWarningNeeded -> { + is WalletAction.Warnings.CheckIfNeeded -> { val validator = globalState?.scanNoteResponse?.walletManager as? SignatureCountValidator globalState?.scanNoteResponse?.card?.let { card -> globalState.warningManager?.removeWarnings(WarningMessage.Origin.Local) @@ -33,13 +38,33 @@ class CheckSignedHashesMiddleware { } updateWarningMessages() } - + val readyToShow = preferencesStorage.appRatingLaunchObserver.isReadyToShow() + if (readyToShow) addWarningMessage(WarningMessagesManager.appRatingWarning(), true) } - is WalletAction.CheckSignedHashes.CheckHashesCountOnline -> checkHashesCountOnline() - is WalletAction.CheckSignedHashes.SaveCardId -> { + is WalletAction.Warnings.CheckHashesCount.CheckHashesCountOnline -> checkHashesCountOnline() + is WalletAction.Warnings.CheckHashesCount.SaveCardId -> { val cardId = globalState?.scanNoteResponse?.card?.cardId cardId?.let { preferencesStorage.saveScannedCardId(it) } } + is WalletAction.Warnings.AppRating.RemindLater -> { + preferencesStorage.appRatingLaunchObserver.applyDelayedShowing() + } + is WalletAction.Warnings.AppRating.SetNeverToShow -> { + preferencesStorage.appRatingLaunchObserver.setNeverToShow() + } + } + } + + public fun tryToShowAppRatingWarning(wallet: Wallet) { + val nonZeroWalletsCount = wallet.amounts.filter { + it.value.value?.isGreaterThan(BigDecimal.ZERO) ?: false + }.size + if (nonZeroWalletsCount > 0) { + preferencesStorage.appRatingLaunchObserver.foundWalletWithFunds() + } + if (preferencesStorage.appRatingLaunchObserver.isReadyToShow()) { + FirebaseAnalyticsHandler.triggerEvent(AnalyticsEvent.APP_RATING_DISPLAYED) + addWarningMessage(WarningMessagesManager.appRatingWarning(), true) } } @@ -52,11 +77,11 @@ class CheckSignedHashesMiddleware { if (card.walletSignedHashes ?: 0 > 0) { WarningMessagesManager.alreadySignedHashesWarning() } else { - store.dispatch(WalletAction.CheckSignedHashes.SaveCardId) + store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId) null } } else { - store.dispatch(WalletAction.CheckSignedHashes.NeedToCheckHashesCountOnline) + store.dispatch(WalletAction.Warnings.CheckHashesCount.NeedToCheckHashesCountOnline) null } } @@ -77,8 +102,8 @@ class CheckSignedHashesMiddleware { withContext(Dispatchers.Main) { when (result) { SimpleResult.Success -> { - store.dispatch(WalletAction.CheckSignedHashes.ConfirmHashesCount) - store.dispatch(WalletAction.CheckSignedHashes.SaveCardId) + store.dispatch(WalletAction.Warnings.CheckHashesCount.ConfirmHashesCount) + store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId) } is SimpleResult.Failure -> if (result.error is BlockchainSdkError.SignatureCountNotMatched) { @@ -98,6 +123,6 @@ class CheckSignedHashesMiddleware { private fun updateWarningMessages() { val warningManager = store.state.globalState.warningManager ?: return - store.dispatch(WalletAction.SetWarnings(warningManager.getWarnings(WarningMessage.Location.MainScreen))) + store.dispatch(WalletAction.Warnings.SetWarnings(warningManager.getWarnings(WarningMessage.Location.MainScreen))) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/MultipleAddressUiHelper.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/MultipleAddressUiHelper.kt index 6570cee834..f7b06a5b5e 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/MultipleAddressUiHelper.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/MultipleAddressUiHelper.kt @@ -31,14 +31,14 @@ class MultipleAddressUiHelper { return when (id) { R.id.chip_default -> { when (blockchain) { - Blockchain.Bitcoin -> BitcoinAddressType.Segwit + Blockchain.Bitcoin, Blockchain.BitcoinTestnet -> BitcoinAddressType.Segwit Blockchain.CardanoShelley -> CardanoAddressType.Shelley else -> null } } R.id.chip_legacy -> { when (blockchain) { - Blockchain.Bitcoin -> BitcoinAddressType.Legacy + Blockchain.Bitcoin, Blockchain.BitcoinTestnet -> BitcoinAddressType.Legacy Blockchain.CardanoShelley -> CardanoAddressType.Byron else -> null } 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 bbdc67d33f..8b98eba79d 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 @@ -87,7 +87,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS btn_confirm.text = getString(R.string.wallet_button_send) btn_confirm.setOnClickListener { store.dispatch(WalletAction.Send()) } - btn_share.setOnClickListener { store.dispatch(WalletAction.ShowQrCode) } + btn_share.setOnClickListener { store.dispatch(WalletAction.ShowDialog.QrCode) } btn_top_up.setOnClickListener { store.dispatch( 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 4e87055b3d..ec1c7cdf74 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 @@ -20,7 +20,6 @@ import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.configurable.warningMessage.WarningMessage import com.tangem.tap.domain.termsOfUse.CardTou -import com.tangem.tap.domain.twins.TwinCardNumber import com.tangem.tap.features.details.redux.DetailsAction import com.tangem.tap.features.wallet.redux.* import com.tangem.tap.features.wallet.ui.adapters.SpacesItemDecoration @@ -28,10 +27,6 @@ import com.tangem.tap.features.wallet.ui.adapters.WarningMessagesAdapter import com.tangem.tap.features.wallet.ui.wallet.MultiWalletView import com.tangem.tap.features.wallet.ui.wallet.SingleWalletView import com.tangem.tap.features.wallet.ui.wallet.WalletView -import com.tangem.tap.features.wallet.ui.dialogs.AmountToSendDialog -import com.tangem.tap.features.wallet.ui.dialogs.PayIdDialog -import com.tangem.tap.features.wallet.ui.dialogs.QrDialog -import com.tangem.tap.features.wallet.ui.dialogs.ScanFailsDialog import com.tangem.tap.store import com.tangem.wallet.R import kotlinx.android.synthetic.main.fragment_wallet.* @@ -182,79 +177,4 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber R.id.chip_legacy -// is BitcoinAddressType.Segwit -> R.id.chip_default -// is CardanoAddressType.Byron -> R.id.chip_legacy -// is CardanoAddressType.Shelley -> R.id.chip_default -// else -> View.NO_ID -// } -// } -// -// fun idToType(id: Int, blockchain: Blockchain?): AddressType? { -// return when (id) { -// R.id.chip_default -> { -// when (blockchain) { -// Blockchain.Bitcoin, Blockchain.BitcoinTestnet -> BitcoinAddressType.Segwit -// Blockchain.CardanoShelley -> CardanoAddressType.Shelley -// else -> null -// } -// } -// R.id.chip_legacy -> { -// when (blockchain) { -// Blockchain.Bitcoin, Blockchain.BitcoinTestnet -> BitcoinAddressType.Legacy -// Blockchain.CardanoShelley -> CardanoAddressType.Byron -// else -> null -// } -// } -// else -> null -// } -// } -// } -//} - -//TODO: handle scan failed dialog: -//private fun handleDialogs(walletDialog: WalletDialog?) { -// when (walletDialog) { -// is WalletDialog.QrDialog -> { -// if (walletDialog.qrCode != null && walletDialog.shareUrl != null) { -// if (dialog == null) dialog = QrDialog(requireContext()).apply { -// this.showQr( -// walletDialog.qrCode, walletDialog.shareUrl, walletDialog.currencyName -// ) -// } -// } -// } -// is WalletDialog.CreatePayIdDialog -> { -// when (walletDialog.creatingPayIdState) { -// CreatingPayIdState.EnterPayId -> { -// if (dialog == null) dialog = PayIdDialog(requireContext()).apply { -// this.show() -// } -// (dialog as? PayIdDialog)?.stopProgress() -// } -// CreatingPayIdState.Waiting -> (dialog as? PayIdDialog)?.showProgress() -// } -// } -// is WalletDialog.SelectAmountToSendDialog -> { -// if (dialog == null) dialog = AmountToSendDialog(requireContext()).apply { -// this.show(walletDialog.amounts) -// } -// } -// is WalletDialog.ScanFailsDialog -> { -// if (dialog == null) dialog = ScanFailsDialog.create(requireContext()).apply { -// this.show() -// } -// } -// null -> { -// dialog?.dismiss() -// dialog = null -// } -// } -//} \ No newline at end of file +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt index 2fb7ab8876..51f47fc82d 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt @@ -1,5 +1,6 @@ package com.tangem.tap.features.wallet.ui.wallet +import android.app.Dialog import androidx.recyclerview.widget.LinearLayoutManager import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.show @@ -7,10 +8,12 @@ import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.features.tokens.redux.TokensAction import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.features.wallet.redux.WalletDialog import com.tangem.tap.features.wallet.redux.WalletState import com.tangem.tap.features.wallet.ui.BalanceStatus import com.tangem.tap.features.wallet.ui.WalletFragment import com.tangem.tap.features.wallet.ui.adapters.WalletAdapter +import com.tangem.tap.features.wallet.ui.dialogs.ScanFailsDialog import com.tangem.tap.store import com.tangem.wallet.R import kotlinx.android.synthetic.main.card_balance.* @@ -22,8 +25,11 @@ import kotlinx.android.synthetic.main.layout_wallet_long_buttons.* class MultiWalletView : WalletView { private var fragment: WalletFragment? = null + private var dialog: Dialog? = null + private lateinit var walletsAdapter: WalletAdapter + override fun changeWalletView(fragment: WalletFragment) { setFragment(fragment) onViewCreated() @@ -82,6 +88,7 @@ class MultiWalletView : WalletView { store.dispatch(NavigationAction.NavigateTo(AppScreen.AddTokens)) } handleErrorStates(state, fragment) + handleDialogs(state.walletDialog) } private fun handleErrorStates(state: WalletState, fragment: WalletFragment) { @@ -123,4 +130,20 @@ class MultiWalletView : WalletView { fragment.btn_confirm_long.setOnClickListener { store.dispatch(WalletAction.CreateWallet) } fragment.btn_confirm_long.text = fragment.getText(R.string.wallet_button_create_wallet) } + + private fun handleDialogs(walletDialog: WalletDialog?) { + val fragment = fragment ?: return + val context = fragment.context ?: return + when (walletDialog) { + is WalletDialog.ScanFailsDialog -> { + if (dialog == null) dialog = ScanFailsDialog.create(context).apply { + this.show() + } + } + else -> { + dialog?.dismiss() + dialog = null + } + } + } } \ No newline at end of file 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 34cab5caf0..cc14fa932e 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 @@ -15,6 +15,7 @@ import com.tangem.tap.features.wallet.ui.WalletFragment import com.tangem.tap.features.wallet.ui.adapters.PendingTransactionsAdapter import com.tangem.tap.features.wallet.ui.dialogs.AmountToSendDialog import com.tangem.tap.features.wallet.ui.dialogs.QrDialog +import com.tangem.tap.features.wallet.ui.dialogs.ScanFailsDialog import com.tangem.tap.store import com.tangem.wallet.R import kotlinx.android.synthetic.main.card_balance.* @@ -135,7 +136,7 @@ class SingleWalletView : WalletView { store.dispatch(WalletAction.CopyAddress(addressString, fragment.requireContext())) } } - fragment.btn_show_qr.setOnClickListener { store.dispatch(WalletAction.ShowQrCode) } + fragment.btn_show_qr.setOnClickListener { store.dispatch(WalletAction.ShowDialog.QrCode) } fragment.btn_top_up.setOnClickListener { store.dispatch( @@ -211,10 +212,11 @@ class SingleWalletView : WalletView { private fun handleDialogs(walletDialog: WalletDialog?) { val fragment = fragment ?: return + val context = fragment.context ?: return when (walletDialog) { is WalletDialog.QrDialog -> { if (walletDialog.qrCode != null && walletDialog.shareUrl != null) { - if (dialog == null) dialog = QrDialog(fragment.requireContext()).apply { + if (dialog == null) dialog = QrDialog(context).apply { this.showQr( walletDialog.qrCode, walletDialog.shareUrl, walletDialog.currencyName ) @@ -222,10 +224,15 @@ class SingleWalletView : WalletView { } } is WalletDialog.SelectAmountToSendDialog -> { - if (dialog == null) dialog = AmountToSendDialog(fragment.requireContext()).apply { + if (dialog == null) dialog = AmountToSendDialog(context).apply { this.show(walletDialog.amounts) } } + is WalletDialog.ScanFailsDialog -> { + if (dialog == null) dialog = ScanFailsDialog.create(context).apply { + this.show() + } + } null -> { dialog?.dismiss() dialog = null