diff --git a/app/src/main/java/com/tangem/tap/TangemApplication.kt b/app/src/main/java/com/tangem/tap/TangemApplication.kt index 0e2e83f67f..78c59931bf 100644 --- a/app/src/main/java/com/tangem/tap/TangemApplication.kt +++ b/app/src/main/java/com/tangem/tap/TangemApplication.kt @@ -258,6 +258,7 @@ abstract class TangemApplication : Application(), ImageLoaderFactory { onrampFeatureToggles = onrampFeatureToggles, environmentConfigStorage = environmentConfigStorage, onboardingV2FeatureToggles = onboardingV2FeatureToggles, + appPreferencesStore = appPreferencesStore, ), ), ) 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 8bc1f8e7ae..333923e760 100644 --- a/app/src/main/java/com/tangem/tap/common/DialogManager.kt +++ b/app/src/main/java/com/tangem/tap/common/DialogManager.kt @@ -159,6 +159,12 @@ class DialogManager : StoreSubscriber { ), context = context, ) + is AppDialog.WalletAlreadyWasUsedDialog -> WalletAlreadyWasUsedDialog.create( + context = context, + onOk = state.dialog.onOk, + onSupport = state.dialog.onSupportClick, + onCancel = state.dialog.onCancel, + ) is AppDialog.RemoveWalletDialog -> SimpleCancelableAlertDialog.create( title = context.getString(state.dialog.titleRes, state.dialog.currencyTitle), messageRes = state.dialog.messageRes, diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppDialog.kt b/app/src/main/java/com/tangem/tap/common/redux/AppDialog.kt index 04a76036c3..4586881efc 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppDialog.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppDialog.kt @@ -48,4 +48,10 @@ sealed class AppDialog : StateDialog { val messageRes: Int = R.string.token_details_unable_hide_alert_message val titleRes: Int = R.string.token_details_unable_hide_alert_title } + + data class WalletAlreadyWasUsedDialog( + val onOk: () -> Unit, + val onSupportClick: () -> Unit, + val onCancel: () -> Unit, + ) : AppDialog() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt index 09ca2e1778..2de5746b8e 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt @@ -9,18 +9,25 @@ import com.tangem.core.analytics.Analytics import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.Basic +import com.tangem.datasource.api.tangemTech.models.UserTokensResponse +import com.tangem.datasource.local.preferences.PreferencesKeys +import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull import com.tangem.domain.common.TapWorkarounds.canSkipBackup import com.tangem.domain.common.extensions.withMainContext import com.tangem.domain.common.util.twinsIsTwinned +import com.tangem.domain.feedback.models.FeedbackEmailType import com.tangem.domain.models.scan.ScanResponse +import com.tangem.domain.wallets.builder.UserWalletIdBuilder import com.tangem.tap.common.analytics.paramsInterceptor.CardContextInterceptor import com.tangem.tap.common.extensions.* +import com.tangem.tap.common.redux.AppDialog import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.features.disclaimer.createDisclaimer 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.onboarding.products.wallet.redux.BackupStartedSource +import com.tangem.tap.mainScope import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope import com.tangem.tap.store @@ -135,32 +142,79 @@ internal object LegacyScanProcessor { ) { store.dispatchOnMain(TwinCardsAction.IfTwinsPrepareState(scanResponse)) - if (OnboardingHelper.isOnboardingCase(scanResponse)) { - Analytics.addContext(scanResponse) - onWalletNotCreated() - // must check skip backup using card canSkipBackup - store.dispatchOnMain( - GlobalAction.Onboarding.Start( - scanResponse = scanResponse, - source = BackupStartedSource.Onboarding, - canSkipBackup = scanResponse.card.canSkipBackup, + checkCardWasUsedInApp( + scanResponse = scanResponse, + onCancel = { mainScope.launch { onProgressStateChange.invoke(false) } }, + ) { + if (OnboardingHelper.isOnboardingCase(scanResponse)) { + Analytics.addContext(scanResponse) + onWalletNotCreated() + // must check skip backup using card canSkipBackup + store.dispatchOnMain( + GlobalAction.Onboarding.Start( + scanResponse = scanResponse, + source = BackupStartedSource.Onboarding, + canSkipBackup = scanResponse.card.canSkipBackup, + ), + ) + val appScreen = OnboardingHelper.whereToNavigate(scanResponse) + navigateTo(appScreen) { onProgressStateChange(it) } + } else { + Analytics.setContext(scanResponse) + + val wasTwinsOnboardingShown = + store.inject(DaggerGraphState::wasTwinsOnboardingShownUseCase).invokeSync() + + if (scanResponse.twinsIsTwinned() && !wasTwinsOnboardingShown) { + onWalletNotCreated() + store.dispatchOnMain(TwinCardsAction.SetStepOfScreen(TwinCardsStep.WelcomeOnly(scanResponse))) + navigateTo(AppRoute.OnboardingTwins) { onProgressStateChange(it) } + } else { + delay(DELAY_SDK_DIALOG_CLOSE) + onSuccess(scanResponse) + } + } + } + } + + /** + * Checks if card has password and never login at this app + * Show alert in this case + */ + private suspend fun checkCardWasUsedInApp( + scanResponse: ScanResponse, + onCancel: () -> Unit, + onSuccess: suspend () -> Unit, + ) { + val userWalletId = UserWalletIdBuilder.card(scanResponse.card).build() + if (userWalletId == null) { + onSuccess() + return + } + val appPrefStoreStore = store.inject(DaggerGraphState::appPreferencesStore) + val tokens = appPrefStoreStore.getObjectSyncOrNull( + key = PreferencesKeys.getUserTokensKey(userWalletId.stringValue), + ) + if (scanResponse.card.isAccessCodeSet && tokens == null) { + store.dispatchDialogShow( + AppDialog.WalletAlreadyWasUsedDialog( + onOk = { mainScope.launch { onSuccess() } }, + onSupportClick = { + val cardInfo = + store.inject(DaggerGraphState::getCardInfoUseCase).invoke(scanResponse).getOrNull() + ?: error("CardInfo must be not null") + + scope.launch { + store.inject(DaggerGraphState::sendFeedbackEmailUseCase) + .invoke(type = FeedbackEmailType.PreActivatedWallet(cardInfo)) + } + onCancel() + }, + onCancel = { onCancel() }, ), ) - val appScreen = OnboardingHelper.whereToNavigate(scanResponse) - navigateTo(appScreen) { onProgressStateChange(it) } } else { - Analytics.setContext(scanResponse) - - val wasTwinsOnboardingShown = store.inject(DaggerGraphState::wasTwinsOnboardingShownUseCase).invokeSync() - - if (scanResponse.twinsIsTwinned() && !wasTwinsOnboardingShown) { - onWalletNotCreated() - store.dispatchOnMain(TwinCardsAction.SetStepOfScreen(TwinCardsStep.WelcomeOnly(scanResponse))) - navigateTo(AppRoute.OnboardingTwins) { onProgressStateChange(it) } - } else { - delay(DELAY_SDK_DIALOG_CLOSE) - onSuccess(scanResponse) - } + onSuccess() } } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/WalletAlreadyWasUsedDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/WalletAlreadyWasUsedDialog.kt new file mode 100644 index 0000000000..6d5875be78 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/WalletAlreadyWasUsedDialog.kt @@ -0,0 +1,33 @@ +package com.tangem.tap.features.onboarding.products.wallet.ui.dialogs + +import android.content.Context +import androidx.appcompat.app.AlertDialog +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.tangem.tap.common.redux.global.GlobalAction +import com.tangem.tap.store +import com.tangem.wallet.R + +object WalletAlreadyWasUsedDialog { + + fun create(context: Context, onOk: () -> Unit, onCancel: () -> Unit, onSupport: () -> Unit): AlertDialog { + return MaterialAlertDialogBuilder(context, R.style.CustomMaterialDialog).apply { + setTitle(R.string.security_alert_title) + setMessage(R.string.wallet_been_activated_message) + setPositiveButton(R.string.this_is_my_wallet_title) { dialog, _ -> + onOk() + dialog.dismiss() + } + setNeutralButton(R.string.common_cancel) { dialog, _ -> + onCancel() + dialog.dismiss() + } + setNegativeButton(R.string.alert_button_request_support) { dialog, _ -> + onSupport() + dialog.dismiss() + } + setOnDismissListener { + store.dispatch(GlobalAction.HideDialog) + } + }.create() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeAction.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeAction.kt index 97138375c6..fbae455ce2 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeAction.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeAction.kt @@ -19,6 +19,7 @@ internal sealed interface WelcomeAction : Action { object ProceedWithCard : WelcomeAction { object Success : WelcomeAction data class Error(val error: TangemError) : WelcomeAction + data class ChangeProgress(val showProgress: Boolean) : WelcomeAction } data class ProceedWithIntent(val intent: Intent) : WelcomeAction diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt index 8bd3ee34fc..b9f8660cf1 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt @@ -197,6 +197,9 @@ internal class WelcomeMiddleware { } } }, + onProgressStateChange = { + store.dispatchWithMain(WelcomeAction.ProceedWithCard.ChangeProgress(it)) + }, onWalletNotCreated = { store.dispatchOnMain(WelcomeAction.ProceedWithCard.Success) }, diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeReducer.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeReducer.kt index 85db06dc63..35f81371fa 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeReducer.kt @@ -27,6 +27,9 @@ internal object WelcomeReducer { error = action.error, isUnlockWithCardInProgress = false, ) + is WelcomeAction.ProceedWithCard.ChangeProgress -> state.copy( + isUnlockWithCardInProgress = action.showProgress, + ) is WelcomeAction.ProceedWithBiometrics.Success -> state.copy(isUnlockWithBiometricsInProgress = false) is WelcomeAction.ProceedWithCard.Success -> state.copy(isUnlockWithCardInProgress = false) is WelcomeAction.CloseError -> state.copy(error = null) diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt index 075686701f..cb94b5b0cc 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt @@ -8,6 +8,7 @@ import com.tangem.core.navigation.url.UrlOpener import com.tangem.datasource.connection.NetworkConnectionManager import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage import com.tangem.datasource.local.config.issuers.IssuersConfigStorage +import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.domain.appcurrency.repository.AppCurrencyRepository import com.tangem.domain.apptheme.repository.AppThemeModeRepository import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository @@ -71,4 +72,5 @@ data class DaggerGraphState( val onrampFeatureToggles: OnrampFeatureToggles? = null, val environmentConfigStorage: EnvironmentConfigStorage? = null, val onboardingV2FeatureToggles: OnboardingV2FeatureToggles? = null, + val appPreferencesStore: AppPreferencesStore? = null, ) : StateType \ No newline at end of file diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 6e9a779cef..403c45a975 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -650,6 +650,7 @@ Сканировать Отсканируйте карту или кольцо, чтобы изменить ее настройки. Изменения затронут только ту карту или кольцо, которые вы отсканировали, и не повлияют на другие устройства, привязанные к вашему кошельку. Приготовьте свой Tangem! + Уведомление безопасности Уже содержится во введенном адресе Сумма комиссии в %s раз превышает рекомендованную. Убедитесь, что указанная комиссия верна. Вы указали комиссию ниже рекомендуемой, это может привести к задержке исполнения вашей транзакции. Продолжить? @@ -861,6 +862,7 @@ Вы получите Выберите токен не доступен + Это мой кошелек Балансы скрыты Балансы показаны Отменить @@ -929,6 +931,7 @@ Разблокировать все с %s Блокчейн недоступен. Попробуйте позже. Отсканируйте карту или кольцо + Этот кошелек уже был активирован ранее.\nЕсли это сделали не вы, свяжитесь со службой поддержки.\nTangem никогда не продает кошелек вместе с предустановленным кодом доступа. Запрос на подпись сообщения.\n\n%s Dapp %1$s, запрос на\nподпись транзакции с BNB.\n\n%2$s Торговый ордер на %1$s\nЦена: %2$s\nСумма к получению: %3$s\nСумма к оплате: %4$s diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 1f7c527b60..818d75da17 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -307,6 +307,7 @@ Please tell us what card or ring do you have Hi support team, Please tell us more about your issue. Every small detail can help. + Previously activated wallet My suggestions Can\'t scan a card/ring Feedback @@ -648,6 +649,7 @@ Scan card or ring Scan the card or ring to change its settings. The changes will impact only the card or ring you\'ve scanned and will not affect other devices tied to your wallet. Get your Tangem ready! + Security Alert Already included in the entered address Your commission amount is %s times higher than the recommended amount. Please review and adjust your custom settings. You specified a commission below the recommended amount, which could cause a delay in your transaction. Continue? @@ -860,6 +862,7 @@ You receive Choose token not available + This is my wallet Balances hidden Balances shown Undo @@ -928,6 +931,7 @@ Unlock all with %s Blockchain is unreachable. Try later Scan card or ring + This wallet has already been activated earlier.\nIf it was done not by you please contact support.\nTangem never sells wallets along with the pre-generated access code. Requesting to sign a message.\n\n%s Dapp %1$s, requesting to\nsign BNB transaction.\n\n%2$s Trade order for %1$s\nPrice: %2$s\nAmount to receive: %3$s\nAmount to pay: %4$s diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/SendFeedbackEmailUseCase.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/SendFeedbackEmailUseCase.kt index 2f9578ed40..302680f4c6 100644 --- a/domain/feedback/src/main/java/com/tangem/domain/feedback/SendFeedbackEmailUseCase.kt +++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/SendFeedbackEmailUseCase.kt @@ -57,6 +57,7 @@ class SendFeedbackEmailUseCase( return when (type) { is FeedbackEmailType.ScanningProblem, is FeedbackEmailType.CurrencyDescriptionError, + is FeedbackEmailType.PreActivatedWallet, -> this is FeedbackEmailType.DirectUserRequest, is FeedbackEmailType.RateCanBeBetter, diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/models/FeedbackEmailType.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/models/FeedbackEmailType.kt index 70d4017993..2ec928f7ab 100644 --- a/domain/feedback/src/main/java/com/tangem/domain/feedback/models/FeedbackEmailType.kt +++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/models/FeedbackEmailType.kt @@ -46,4 +46,6 @@ sealed interface FeedbackEmailType { data class CurrencyDescriptionError(val currencyId: String, val currencyName: String) : FeedbackEmailType { override val cardInfo: CardInfo? = null } + + data class PreActivatedWallet(override val cardInfo: CardInfo) : FeedbackEmailType } \ No newline at end of file diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageBodyResolver.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageBodyResolver.kt index c6d5bd52eb..9983e4bcc4 100644 --- a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageBodyResolver.kt +++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageBodyResolver.kt @@ -26,6 +26,7 @@ internal class EmailMessageBodyResolver( is FeedbackEmailType.StakingProblem -> addStakingProblemBody(type) is FeedbackEmailType.SwapProblem -> addSwapProblemBody(type) is FeedbackEmailType.CurrencyDescriptionError -> addTokenInfo(type) + is FeedbackEmailType.PreActivatedWallet -> addUserRequestBody(type.cardInfo) } return build() diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageTitleResolver.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageTitleResolver.kt index d0768aff1f..1311a3016e 100644 --- a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageTitleResolver.kt +++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageTitleResolver.kt @@ -25,6 +25,7 @@ internal class EmailMessageTitleResolver(private val resources: Resources) { is FeedbackEmailType.StakingProblem, is FeedbackEmailType.SwapProblem, -> R.string.feedback_preface_tx_failed + is FeedbackEmailType.PreActivatedWallet -> R.string.feedback_preface_support } .let(resources::getString) } diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailSubjectResolver.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailSubjectResolver.kt index a833d1b6d3..e373d8d496 100644 --- a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailSubjectResolver.kt +++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailSubjectResolver.kt @@ -29,6 +29,7 @@ internal class EmailSubjectResolver(private val resources: Resources) { is FeedbackEmailType.StakingProblem, is FeedbackEmailType.SwapProblem, -> R.string.feedback_subject_tx_failed + is FeedbackEmailType.PreActivatedWallet -> R.string.feedback_subject_pre_activated_wallet is FeedbackEmailType.CurrencyDescriptionError -> R.string.feedback_token_description_error } .let(resources::getString) diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 2d7317203b..b15619d568 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -89,7 +89,7 @@ markdownComposeView = "0.5.4" # region Tangem tangemBlockchainSdk = "release-app_5.18-874" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "release-app_5.18-409" +tangemCardSdk = "release-app_5.18-413" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ tangemVico = "2.0.0-alpha.25-tangem17" #tangemVico = "0.0.1" # Keep it! - used for local builds ^