From dffa8b2658c8392758b1d418a9203a9ff12b7e82 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 8 Dec 2025 16:51:34 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../tap/di/domain/HotWalletDomainModule.kt | 9 +++++++ .../tangem/core/ui/message/dialog/Dialogs.kt | 24 +++++++++++++++++++ .../hotwallet/DefaultHotWalletRepository.kt | 9 +++++++ .../hotwallet/IsHotWalletCreationSupported.kt | 9 +++++++ .../repository/HotWalletRepository.kt | 4 ++++ domain/wallets/build.gradle.kts | 1 + .../wallets/builder/HotUserWalletBuilder.kt | 10 ++++++++ .../impl/build.gradle.kts | 1 + .../CreateWalletSelectionModel.kt | 12 ++++++++++ .../create-wallet-start/impl/build.gradle.kts | 1 + .../CreateWalletStartModel.kt | 10 ++++++++ .../CreateMobileWalletModel.kt | 20 +++++++++++++++- 12 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 domain/hot-wallet/src/main/kotlin/com/tangem/domain/hotwallet/IsHotWalletCreationSupported.kt diff --git a/app/src/main/java/com/tangem/tap/di/domain/HotWalletDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/HotWalletDomainModule.kt index 57fd8da9ae..6eb397fb4e 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/HotWalletDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/HotWalletDomainModule.kt @@ -1,6 +1,7 @@ package com.tangem.tap.di.domain import com.tangem.domain.hotwallet.GetAccessCodeSkippedUseCase +import com.tangem.domain.hotwallet.IsHotWalletCreationSupported import com.tangem.domain.hotwallet.SetAccessCodeSkippedUseCase import com.tangem.domain.hotwallet.repository.HotWalletRepository import dagger.Module @@ -24,4 +25,12 @@ internal object HotWalletDomainModule { fun provideSetAccessCodeSkippedUseCase(hotWalletRepository: HotWalletRepository): SetAccessCodeSkippedUseCase { return SetAccessCodeSkippedUseCase(hotWalletRepository) } + + @Provides + @Singleton + fun provideIsWalletCreationSupportedUseCase( + hotWalletRepository: HotWalletRepository, + ): IsHotWalletCreationSupported { + return IsHotWalletCreationSupported(hotWalletRepository) + } } \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/message/dialog/Dialogs.kt b/core/ui/src/main/java/com/tangem/core/ui/message/dialog/Dialogs.kt index 08fb5a9e46..dec4c24085 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/message/dialog/Dialogs.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/message/dialog/Dialogs.kt @@ -39,6 +39,30 @@ object Dialogs { ) } + /** + * Hot wallet creation not supported dialog + * + * @param leastSupportedVersion least supported OS version name ex. "Android 10" + * @param onDismiss lambda be invoked when dialog is dismissed + */ + fun hotWalletCreationNotSupportedDialog(leastSupportedVersion: String, onDismiss: () -> Unit = {}): DialogMessage { + return DialogMessage( + title = resourceReference( + id = R.string.mobile_wallet_requires_min_os_warning_title, + formatArgs = wrappedList(leastSupportedVersion), + ), + message = resourceReference( + id = R.string.mobile_wallet_requires_min_os_warning_body, + formatArgs = wrappedList(leastSupportedVersion), + ), + firstAction = EventMessageAction( + title = resourceReference(R.string.common_got_it), + onClick = {}, + ), + onDismissRequest = onDismiss, + ) + } + /** * Universal error dialog */ diff --git a/data/hot-wallet/src/main/java/com/tangem/data/hotwallet/DefaultHotWalletRepository.kt b/data/hot-wallet/src/main/java/com/tangem/data/hotwallet/DefaultHotWalletRepository.kt index 4670884954..5754358efa 100644 --- a/data/hot-wallet/src/main/java/com/tangem/data/hotwallet/DefaultHotWalletRepository.kt +++ b/data/hot-wallet/src/main/java/com/tangem/data/hotwallet/DefaultHotWalletRepository.kt @@ -1,5 +1,7 @@ package com.tangem.data.hotwallet +import android.os.Build +import androidx.annotation.ChecksSdkIntAtLeast import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.datasource.local.preferences.PreferencesKeys import com.tangem.datasource.local.preferences.utils.getObjectMap @@ -12,6 +14,13 @@ internal class DefaultHotWalletRepository( private val appPreferencesStore: AppPreferencesStore, ) : HotWalletRepository { + @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.Q) + override fun isWalletCreationSupported(): Boolean { + return BuildConfig.DEBUG || Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q + } + + override fun getLeastSupportedAndroidVersionName(): String = "Android 10" + override fun accessCodeSkipped(userWalletId: UserWalletId): Flow = appPreferencesStore .getObjectMap(PreferencesKeys.ACCESS_CODE_SKIPPED_STATES_KEY) .map { it[userWalletId.stringValue] == true } diff --git a/domain/hot-wallet/src/main/kotlin/com/tangem/domain/hotwallet/IsHotWalletCreationSupported.kt b/domain/hot-wallet/src/main/kotlin/com/tangem/domain/hotwallet/IsHotWalletCreationSupported.kt new file mode 100644 index 0000000000..f3e4a3c05f --- /dev/null +++ b/domain/hot-wallet/src/main/kotlin/com/tangem/domain/hotwallet/IsHotWalletCreationSupported.kt @@ -0,0 +1,9 @@ +package com.tangem.domain.hotwallet + +import com.tangem.domain.hotwallet.repository.HotWalletRepository + +class IsHotWalletCreationSupported(private val hotWalletRepository: HotWalletRepository) { + operator fun invoke(): Boolean = hotWalletRepository.isWalletCreationSupported() + + fun getLeastVersionName(): String = hotWalletRepository.getLeastSupportedAndroidVersionName() +} \ No newline at end of file diff --git a/domain/hot-wallet/src/main/kotlin/com/tangem/domain/hotwallet/repository/HotWalletRepository.kt b/domain/hot-wallet/src/main/kotlin/com/tangem/domain/hotwallet/repository/HotWalletRepository.kt index 5bc636f2dd..e228cd4419 100644 --- a/domain/hot-wallet/src/main/kotlin/com/tangem/domain/hotwallet/repository/HotWalletRepository.kt +++ b/domain/hot-wallet/src/main/kotlin/com/tangem/domain/hotwallet/repository/HotWalletRepository.kt @@ -5,6 +5,10 @@ import kotlinx.coroutines.flow.Flow interface HotWalletRepository { + fun isWalletCreationSupported(): Boolean + + fun getLeastSupportedAndroidVersionName(): String + fun accessCodeSkipped(userWalletId: UserWalletId): Flow suspend fun setAccessCodeSkipped(userWalletId: UserWalletId, skipped: Boolean) diff --git a/domain/wallets/build.gradle.kts b/domain/wallets/build.gradle.kts index ad9162e60a..a5779a9b3f 100644 --- a/domain/wallets/build.gradle.kts +++ b/domain/wallets/build.gradle.kts @@ -32,6 +32,7 @@ dependencies { implementation(projects.domain.wallets.models) implementation(projects.domain.notifications.models) implementation(projects.domain.demo.models) + implementation(projects.domain.hotWallet) // endregion // region Tangem libraries diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/builder/HotUserWalletBuilder.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/builder/HotUserWalletBuilder.kt index eaa1c7dc7c..de81ddc111 100644 --- a/domain/wallets/src/main/java/com/tangem/domain/wallets/builder/HotUserWalletBuilder.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/builder/HotUserWalletBuilder.kt @@ -3,6 +3,7 @@ package com.tangem.domain.wallets.builder import com.tangem.blockchain.blockchains.cardano.CardanoUtils import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.derivation.DerivationStyle +import com.tangem.domain.hotwallet.IsHotWalletCreationSupported import com.tangem.domain.models.MobileWallet import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase @@ -22,9 +23,12 @@ class HotUserWalletBuilder @AssistedInject constructor( private val hotSdk: TangemHotSdk, private val generateWalletNameUseCase: GenerateWalletNameUseCase, private val dispatcherProvider: CoroutineDispatcherProvider, + private val isHotWalletCreationSupported: IsHotWalletCreationSupported, ) { suspend fun build(): UserWallet.Hot = withContext(dispatcherProvider.default) { + checkHotWalletCreationSupported() + val allNetworks = Blockchain.entries.filter { it.isTestnet().not() } val curves = allNetworks.map { it.getSupportedCurves() }.flatten().toSet() val requests = curves.sortedBy { it.ordinal }.map { curve -> @@ -73,6 +77,12 @@ class HotUserWalletBuilder @AssistedInject constructor( ) } + fun checkHotWalletCreationSupported() { + require(isHotWalletCreationSupported()) { + "Hot wallet creation is supported only from ${isHotWalletCreationSupported.getLeastVersionName()}" + } + } + @AssistedFactory interface Factory { fun create(hotWalletId: HotWalletId): HotUserWalletBuilder diff --git a/features/create-wallet-selection/impl/build.gradle.kts b/features/create-wallet-selection/impl/build.gradle.kts index da58579502..4f1fb170a2 100644 --- a/features/create-wallet-selection/impl/build.gradle.kts +++ b/features/create-wallet-selection/impl/build.gradle.kts @@ -23,6 +23,7 @@ dependencies { implementation(projects.domain.settings) implementation(projects.domain.wallets) implementation(projects.domain.models) + implementation(projects.domain.hotWallet) /** Core modules */ implementation(projects.core.configToggles) diff --git a/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionModel.kt b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionModel.kt index 7e9fcbc7f5..ba67d8e99a 100644 --- a/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionModel.kt +++ b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionModel.kt @@ -7,10 +7,13 @@ import com.tangem.core.analytics.models.Basic import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.navigation.Router +import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.navigation.url.UrlOpener import com.tangem.core.ui.components.label.entity.LabelStyle import com.tangem.core.ui.components.label.entity.LabelUM import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.message.dialog.Dialogs.hotWalletCreationNotSupportedDialog +import com.tangem.domain.hotwallet.IsHotWalletCreationSupported import com.tangem.domain.wallets.usecase.GenerateBuyTangemCardLinkUseCase import com.tangem.features.createwalletselection.entity.CreateWalletSelectionUM import com.tangem.features.createwalletselection.impl.R @@ -31,6 +34,8 @@ internal class CreateWalletSelectionModel @Inject constructor( private val analyticsEventHandler: AnalyticsEventHandler, private val generateBuyTangemCardLinkUseCase: GenerateBuyTangemCardLinkUseCase, private val urlOpener: UrlOpener, + private val isHotWalletCreationSupported: IsHotWalletCreationSupported, + private val uiMessageSender: UiMessageSender, ) : Model() { internal val uiState: StateFlow @@ -93,6 +98,13 @@ internal class CreateWalletSelectionModel @Inject constructor( } private fun onMobileWalletClick() { + if (!isHotWalletCreationSupported()) { + uiMessageSender.send( + hotWalletCreationNotSupportedDialog(isHotWalletCreationSupported.getLeastVersionName()), + ) + return + } + router.push(AppRoute.CreateMobileWallet) } diff --git a/features/create-wallet-start/impl/build.gradle.kts b/features/create-wallet-start/impl/build.gradle.kts index 6909f9d54c..8552f7b7d9 100644 --- a/features/create-wallet-start/impl/build.gradle.kts +++ b/features/create-wallet-start/impl/build.gradle.kts @@ -20,6 +20,7 @@ dependencies { implementation(projects.domain.settings) implementation(projects.domain.wallets) implementation(projects.domain.models) + implementation(projects.domain.hotWallet) /** Core modules */ implementation(projects.core.configToggles) diff --git a/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt b/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt index 6e138c594d..9a74037170 100644 --- a/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt +++ b/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt @@ -17,11 +17,13 @@ import com.tangem.core.navigation.url.UrlOpener import com.tangem.core.ui.R import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.message.DialogMessage +import com.tangem.core.ui.message.dialog.Dialogs.hotWalletCreationNotSupportedDialog import com.tangem.domain.card.ScanCardProcessor import com.tangem.domain.card.analytics.IntroductionProcess import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.common.wallets.error.SaveWalletError +import com.tangem.domain.hotwallet.IsHotWalletCreationSupported import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.settings.repositories.SettingsRepository import com.tangem.domain.wallets.builder.ColdUserWalletBuilder @@ -52,6 +54,7 @@ internal class CreateWalletStartModel @Inject constructor( private val appRouter: AppRouter, private val coldUserWalletBuilderFactory: ColdUserWalletBuilder.Factory, private val saveWalletUseCase: SaveWalletUseCase, + private val isHotWalletCreationSupported: IsHotWalletCreationSupported, private val userWalletsListRepository: UserWalletsListRepository, @GlobalUiMessageSender private val uiMessageSender: UiMessageSender, private val generateBuyTangemCardLinkUseCase: GenerateBuyTangemCardLinkUseCase, @@ -131,6 +134,13 @@ internal class CreateWalletStartModel @Inject constructor( } private fun onStartWithMobileWalletClick() { + if (!isHotWalletCreationSupported()) { + uiMessageSender.send( + hotWalletCreationNotSupportedDialog(isHotWalletCreationSupported.getLeastVersionName()), + ) + return + } + router.push(AppRoute.CreateMobileWallet) } diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/CreateMobileWalletModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/CreateMobileWalletModel.kt index 47d9334760..49a136ea47 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/CreateMobileWalletModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/CreateMobileWalletModel.kt @@ -5,6 +5,9 @@ import com.tangem.core.analytics.utils.TrackingContextProxy import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.navigation.Router +import com.tangem.core.decompose.ui.UiMessageSender +import com.tangem.core.ui.message.dialog.Dialogs.hotWalletCreationNotSupportedDialog +import com.tangem.domain.hotwallet.IsHotWalletCreationSupported import com.tangem.domain.wallets.builder.HotUserWalletBuilder import com.tangem.domain.wallets.usecase.SaveWalletUseCase import com.tangem.domain.wallets.usecase.SyncWalletWithRemoteUseCase @@ -32,6 +35,8 @@ internal class CreateMobileWalletModel @Inject constructor( private val router: Router, private val tangemHotSdk: TangemHotSdk, private val trackingContextProxy: TrackingContextProxy, + private val isHotWalletCreationSupported: IsHotWalletCreationSupported, + private val uiMessageSender: UiMessageSender, ) : Model() { internal val uiState: StateFlow @@ -54,10 +59,13 @@ internal class CreateMobileWalletModel @Inject constructor( } private fun onImportClick() { + checkHotWalletCreationSupported(notSupported = { return }) router.push(AppRoute.AddExistingWallet) } private fun onCreateClick() { + checkHotWalletCreationSupported(notSupported = { return }) + modelScope.launch { uiState.update { it.copy(createButtonLoading = true) @@ -70,9 +78,10 @@ internal class CreateMobileWalletModel @Inject constructor( saveUserWalletUseCase(userWallet) - launch(NonCancellable) { + launch(dispatchers.main + NonCancellable) { syncWalletWithRemoteUseCase(userWalletId = userWallet.walletId) } + router.replaceAll(AppRoute.Wallet) }.onFailure { throwable -> Timber.e(throwable) @@ -81,4 +90,13 @@ internal class CreateMobileWalletModel @Inject constructor( } } } + + private inline fun checkHotWalletCreationSupported(notSupported: () -> Unit) { + if (!isHotWalletCreationSupported()) { + uiMessageSender.send( + hotWalletCreationNotSupportedDialog(isHotWalletCreationSupported.getLeastVersionName()), + ) + notSupported() + } + } } \ No newline at end of file