diff --git a/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt b/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt index b7b4d6a9a0..5099008e5d 100644 --- a/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt +++ b/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt @@ -20,6 +20,7 @@ import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase import com.tangem.domain.settings.repositories.SettingsRepository import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.NetworksRepository +import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.domain.wallets.repository.WalletsRepository @@ -86,6 +87,8 @@ interface ApplicationEntryPoint { fun getSaveTwinsOnboardingShownUseCase(): SaveTwinsOnboardingShownUseCase + fun getWalletNameGenerateUseCase(): GenerateWalletNameUseCase + fun getCardRepository(): CardRepository fun getFeedbackManagerFeatureToggles(): FeedbackManagerFeatureToggles diff --git a/app/src/main/java/com/tangem/tap/TangemApplication.kt b/app/src/main/java/com/tangem/tap/TangemApplication.kt index 5a22b825cb..80c118ae61 100644 --- a/app/src/main/java/com/tangem/tap/TangemApplication.kt +++ b/app/src/main/java/com/tangem/tap/TangemApplication.kt @@ -37,6 +37,7 @@ import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase import com.tangem.domain.settings.repositories.SettingsRepository import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.NetworksRepository +import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.domain.wallets.repository.WalletsRepository @@ -152,6 +153,9 @@ abstract class TangemApplication : Application(), ImageLoaderFactory { private val saveTwinsOnboardingShownUseCase: SaveTwinsOnboardingShownUseCase get() = entryPoint.getSaveTwinsOnboardingShownUseCase() + private val generateWalletNameUseCase: GenerateWalletNameUseCase + get() = entryPoint.getWalletNameGenerateUseCase() + private val cardRepository: CardRepository get() = entryPoint.getCardRepository() @@ -243,6 +247,7 @@ abstract class TangemApplication : Application(), ImageLoaderFactory { generalUserWalletsListManager = generalUserWalletsListManager, wasTwinsOnboardingShownUseCase = wasTwinsOnboardingShownUseCase, saveTwinsOnboardingShownUseCase = saveTwinsOnboardingShownUseCase, + generateWalletNameUseCase = generateWalletNameUseCase, cardRepository = cardRepository, feedbackManagerFeatureToggles = feedbackManagerFeatureToggles, tangemSdkLogger = tangemSdkLogger, diff --git a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt index 9ba9bbbf87..e7c6feee04 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt @@ -5,7 +5,7 @@ import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.ProductType import com.tangem.domain.models.scan.ScanResponse -import com.tangem.domain.userwallets.UserWalletIdBuilder +import com.tangem.domain.wallets.builder.UserWalletIdBuilder import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.IntroductionProcess diff --git a/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt b/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt index 975fb1fb2f..e87ca04616 100644 --- a/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt +++ b/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt @@ -6,7 +6,7 @@ import com.tangem.blockchain.common.address.Address import com.tangem.crypto.NetworkType import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse -import com.tangem.domain.userwallets.UserWalletIdBuilder +import com.tangem.domain.wallets.builder.UserWalletIdBuilder import com.tangem.tap.common.extensions.stripZeroPlainString import java.util.concurrent.CopyOnWriteArrayList diff --git a/app/src/main/java/com/tangem/tap/di/domain/CardLegacyDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/CardLegacyDomainModule.kt index 3cfbe41b23..9654238c85 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/CardLegacyDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/CardLegacyDomainModule.kt @@ -1,6 +1,8 @@ package com.tangem.tap.di.domain import com.tangem.domain.card.* +import com.tangem.domain.wallets.legacy.UserWalletsListManager +import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase import com.tangem.tap.domain.scanCard.DefaultScanCardProcessor import dagger.Module import dagger.Provides @@ -14,5 +16,11 @@ internal object CardLegacyDomainModule { @Provides @Singleton - fun provideScanCardUseCase(): ScanCardProcessor = DefaultScanCardProcessor() + fun provideScanCardProcessor(): ScanCardProcessor = DefaultScanCardProcessor() + + @Provides + @Singleton + fun providesWalletNameGenerateUseCase(userWalletsListManager: UserWalletsListManager): GenerateWalletNameUseCase { + return GenerateWalletNameUseCase(userWalletsListManager) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/di/domain/WalletsDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/WalletsDomainModule.kt index de5aa6d294..444ce645e5 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/WalletsDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/WalletsDomainModule.kt @@ -4,8 +4,10 @@ import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.domain.wallets.repository.WalletAddressServiceRepository +import com.tangem.domain.wallets.repository.WalletNamesMigrationRepository import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.domain.wallets.usecase.* +import com.tangem.feature.wallet.presentation.wallet.domain.WalletNameMigrationUseCase import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module import dagger.Provides @@ -23,6 +25,18 @@ internal object WalletsDomainModule { return GetWalletsUseCase(userWalletsListManager = userWalletsListManager) } + @Provides + @ViewModelScoped + fun providesWalletNameMigrationUseCase( + userWalletsListManager: UserWalletsListManager, + walletNamesMigrationRepository: WalletNamesMigrationRepository, + ): WalletNameMigrationUseCase { + return WalletNameMigrationUseCase( + userWalletsListManager = userWalletsListManager, + walletNamesMigrationRepository = walletNamesMigrationRepository, + ) + } + @Provides @ViewModelScoped fun providesGetUserWalletUseCase(userWalletsListManager: UserWalletsListManager): GetUserWalletUseCase { @@ -76,6 +90,18 @@ internal object WalletsDomainModule { return UpdateWalletUseCase(userWalletsListManager = userWalletsListManager) } + @Provides + @ViewModelScoped + fun providesRenameWalletUseCase(userWalletsListManager: UserWalletsListManager): RenameWalletUseCase { + return RenameWalletUseCase(userWalletsListManager = userWalletsListManager) + } + + @Provides + @ViewModelScoped + fun providesGetWalletsSyncUseCase(userWalletsListManager: UserWalletsListManager): GetWalletNamesUseCase { + return GetWalletNamesUseCase(userWalletsListManager = userWalletsListManager) + } + @Provides @ViewModelScoped fun providesDeleteWalletUseCase(userWalletsListManager: UserWalletsListManager): DeleteWalletUseCase { diff --git a/app/src/main/java/com/tangem/tap/domain/card/DefaultDerivationsRepository.kt b/app/src/main/java/com/tangem/tap/domain/card/DefaultDerivationsRepository.kt index d5fe11422f..b7ad02d630 100644 --- a/app/src/main/java/com/tangem/tap/domain/card/DefaultDerivationsRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/card/DefaultDerivationsRepository.kt @@ -9,7 +9,7 @@ import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey import com.tangem.datasource.local.userwallet.UserWalletsStore import com.tangem.domain.card.repository.DerivationsRepository import com.tangem.domain.tokens.model.CryptoCurrency -import com.tangem.domain.userwallets.UserWalletIdBuilder +import com.tangem.domain.wallets.builder.UserWalletIdBuilder import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.operations.derivation.ExtendedPublicKeysMap diff --git a/app/src/main/java/com/tangem/tap/domain/extensions/Card.kt b/app/src/main/java/com/tangem/tap/domain/extensions/Card.kt index c71548c0bd..9497f54791 100644 --- a/app/src/main/java/com/tangem/tap/domain/extensions/Card.kt +++ b/app/src/main/java/com/tangem/tap/domain/extensions/Card.kt @@ -5,7 +5,7 @@ import com.tangem.common.services.Result import com.tangem.domain.common.TwinCardNumber import com.tangem.domain.common.getTwinCardNumber import com.tangem.domain.models.scan.CardDTO -import com.tangem.domain.userwallets.Artwork +import com.tangem.domain.wallets.models.Artwork import com.tangem.operations.attestation.CardVerifyAndGetInfo import com.tangem.operations.attestation.OnlineCardVerifier @@ -20,8 +20,8 @@ suspend fun CardDTO.getOrLoadCardArtworkUrl(cardInfo: Result Artwork.MARTA_CARD_URL else -> { when (getTwinCardNumber()) { - TwinCardNumber.First -> Artwork.TWIN_CARD_1 - TwinCardNumber.Second -> Artwork.TWIN_CARD_2 + TwinCardNumber.First -> Artwork.TWIN_CARD_1_URL + TwinCardNumber.Second -> Artwork.TWIN_CARD_2_URL else -> Artwork.DEFAULT_IMG_URL } } diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/DerivationsFinder.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/DerivationsFinder.kt index cb4b7918e9..d1f7b8a3d6 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/DerivationsFinder.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/DerivationsFinder.kt @@ -9,7 +9,7 @@ import com.tangem.datasource.local.token.UserTokensStore import com.tangem.domain.common.DerivationStyleProvider import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation import com.tangem.domain.models.scan.CardDTO -import com.tangem.domain.userwallets.UserWalletIdBuilder +import com.tangem.domain.wallets.builder.UserWalletIdBuilder import com.tangem.domain.wallets.models.UserWalletId import com.tangem.tap.features.demo.DemoHelper import com.tangem.utils.coroutines.CoroutineDispatcherProvider diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt index 96419972cb..e359900a32 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt @@ -43,6 +43,9 @@ internal class BiometricUserWalletsListManager( .filterNotNull() .distinctUntilChanged() + override val userWalletsSync: List + get() = state.value.userWallets + override val selectedUserWalletSync: UserWallet? get() = findSelectedUserWallet() diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/GeneralUserWalletsListManager.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/GeneralUserWalletsListManager.kt index abec2ac6e8..09818c2351 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/GeneralUserWalletsListManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/GeneralUserWalletsListManager.kt @@ -61,6 +61,9 @@ internal class GeneralUserWalletsListManager( } } + override val userWalletsSync: List + get() = requireImplementation.userWalletsSync + override val selectedUserWalletSync: UserWallet? get() = requireImplementation.selectedUserWalletSync diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/RuntimeUserWalletsListManager.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/RuntimeUserWalletsListManager.kt index ca9a5bd68e..4d211d9b88 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/RuntimeUserWalletsListManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/RuntimeUserWalletsListManager.kt @@ -26,6 +26,9 @@ internal class RuntimeUserWalletsListManager : UserWalletsListManager { .filterNotNull() .distinctUntilChanged() + override val userWalletsSync: List + get() = listOfNotNull(state.value.userWallet) + override val selectedUserWalletSync: UserWallet? get() = state.value.userWallet 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 edef362685..495afd0915 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 @@ -15,8 +15,8 @@ import com.tangem.domain.apptheme.model.AppThemeMode import com.tangem.domain.common.TapWorkarounds.isTangemTwins import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.ScanResponse -import com.tangem.domain.userwallets.UserWalletBuilder -import com.tangem.domain.userwallets.UserWalletIdBuilder +import com.tangem.domain.wallets.builder.UserWalletBuilder +import com.tangem.domain.wallets.builder.UserWalletIdBuilder import com.tangem.domain.wallets.legacy.asLockable import com.tangem.tap.* import com.tangem.tap.common.analytics.events.AnalyticsParam @@ -522,7 +522,8 @@ class DetailsMiddleware { } private suspend fun saveUserWalletAndPopBackToWalletScreen(scanResponse: ScanResponse): CompletionResult { - val userWallet = UserWalletBuilder(scanResponse).build() + val walletNameGenerateUseCase = store.inject(DaggerGraphState::generateWalletNameUseCase) + val userWallet = UserWalletBuilder(scanResponse, walletNameGenerateUseCase).build() ?: return CompletionResult.Failure(TangemSdkError.WalletIsNotCreated()) val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager) 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 862e4ccb8a..17e8d7dd0a 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 @@ -11,7 +11,7 @@ import com.tangem.core.navigation.AppScreen import com.tangem.core.navigation.NavigationAction import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.ScanResponse -import com.tangem.domain.userwallets.UserWalletBuilder +import com.tangem.domain.wallets.builder.UserWalletBuilder import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter import com.tangem.tap.common.analytics.events.IntroductionProcess import com.tangem.tap.common.analytics.events.Shop @@ -103,7 +103,8 @@ private suspend fun readCard() { } private fun proceedWithScanResponse(scanResponse: ScanResponse) = scope.launch { - val userWallet = UserWalletBuilder(scanResponse).build().guard { + val walletNameGenerateUseCase = store.inject(DaggerGraphState::generateWalletNameUseCase) + val userWallet = UserWalletBuilder(scanResponse, walletNameGenerateUseCase).build().guard { Timber.e("User wallet not created") return@launch } 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 0c6c5601a2..f03dc73425 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,8 +12,8 @@ import com.tangem.domain.common.util.twinsIsTwinned import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ProductType import com.tangem.domain.models.scan.ScanResponse -import com.tangem.domain.userwallets.UserWalletBuilder -import com.tangem.domain.userwallets.UserWalletIdBuilder +import com.tangem.domain.wallets.builder.UserWalletBuilder +import com.tangem.domain.wallets.builder.UserWalletIdBuilder import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter import com.tangem.tap.common.extensions.* import com.tangem.tap.features.demo.DemoHelper @@ -142,7 +142,8 @@ object OnboardingHelper { backupCardsIds: List?, hasBackupError: Boolean, ) { - val userWallet = UserWalletBuilder(scanResponse = scanResponse) + val walletNameGenerateUseCase = store.inject(DaggerGraphState::generateWalletNameUseCase) + val userWallet = UserWalletBuilder(scanResponse, walletNameGenerateUseCase) .hasBackupError(hasBackupError) .backupCardsIds(backupCardsIds?.toSet()) .build() 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 a1c84cb01a..b59d2efa0b 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 @@ -12,7 +12,7 @@ import com.tangem.domain.common.extensions.withMainContext import com.tangem.domain.common.util.derivationStyleProvider import com.tangem.domain.common.util.twinsIsTwinned import com.tangem.domain.models.scan.ScanResponse -import com.tangem.domain.userwallets.UserWalletIdBuilder +import com.tangem.domain.wallets.builder.UserWalletIdBuilder import com.tangem.domain.wallets.legacy.asLockable import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Onboarding diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/OnboardingTwinsFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/OnboardingTwinsFragment.kt index ca8d61618e..b4260dd2e8 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/OnboardingTwinsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/OnboardingTwinsFragment.kt @@ -18,7 +18,7 @@ import com.tangem.core.ui.extensions.setStatusBarColor import com.tangem.datasource.asset.reader.AssetReader import com.tangem.domain.common.TwinCardNumber import com.tangem.domain.models.scan.ScanResponse -import com.tangem.domain.userwallets.Artwork +import com.tangem.domain.wallets.models.Artwork import com.tangem.sdk.ui.widget.leapfrogWidget.LeapfrogWidget import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.extensions.* @@ -88,13 +88,13 @@ internal class OnboardingTwinsFragment : BaseOnboardingFragment( binding.toolbar.title = getText(R.string.twins_recreate_toolbar) - mainBinding.onboardingTopContainer.imvTwinFrontCard.load(Artwork.TWIN_CARD_1) { + mainBinding.onboardingTopContainer.imvTwinFrontCard.load(Artwork.TWIN_CARD_1_URL) { placeholder(R.drawable.card_placeholder_black) error(R.drawable.card_placeholder_black) fallback(R.drawable.card_placeholder_black) } - mainBinding.onboardingTopContainer.imvTwinBackCard.load(Artwork.TWIN_CARD_2) { + mainBinding.onboardingTopContainer.imvTwinBackCard.load(Artwork.TWIN_CARD_2_URL) { placeholder(R.drawable.card_placeholder_white) error(R.drawable.card_placeholder_white) fallback(R.drawable.card_placeholder_white) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt index 3a6b93da1a..925dc9bcc2 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt @@ -15,8 +15,8 @@ import com.tangem.domain.common.extensions.withMainContext import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse -import com.tangem.domain.userwallets.Artwork -import com.tangem.domain.userwallets.UserWalletBuilder +import com.tangem.domain.wallets.models.Artwork +import com.tangem.domain.wallets.builder.UserWalletBuilder import com.tangem.feature.onboarding.data.model.CreateWalletResponse import com.tangem.feature.onboarding.presentation.wallet2.analytics.SeedPhraseSource import com.tangem.feature.wallet.presentation.wallet.domain.BackupValidator @@ -548,7 +548,8 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) } if (scanResponse != null) { - val userWallet = UserWalletBuilder(scanResponse) + val walletNameGenerateUseCase = store.inject(DaggerGraphState::generateWalletNameUseCase) + val userWallet = UserWalletBuilder(scanResponse, walletNameGenerateUseCase) .backupCardsIds(backupState.backupCardIds.toSet()) .build() .guard { diff --git a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt index bdfffe8f9f..45eb5225a2 100644 --- a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt @@ -6,7 +6,7 @@ import com.tangem.common.extensions.guard import com.tangem.core.analytics.Analytics import com.tangem.core.navigation.AppScreen import com.tangem.core.navigation.NavigationAction -import com.tangem.domain.userwallets.UserWalletBuilder +import com.tangem.domain.wallets.builder.UserWalletBuilder import com.tangem.domain.wallets.models.UserWallet import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.MainScreen @@ -64,7 +64,8 @@ internal class SaveWalletMiddleware { scope.launch { val backupInfo = state.backupInfo ?: error("Backup info is null") - val userWallet = UserWalletBuilder(backupInfo.scanResponse) + val walletNameGenerateUseCase = store.inject(DaggerGraphState::generateWalletNameUseCase) + val userWallet = UserWalletBuilder(backupInfo.scanResponse, walletNameGenerateUseCase) .backupCardsIds(state.backupInfo.backupCardsIds) .hasBackupError(hasBackupError) .build() 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 4956441790..1f1c3132a0 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 @@ -13,7 +13,7 @@ import com.tangem.core.navigation.AppScreen import com.tangem.core.navigation.NavigationAction import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.ScanResponse -import com.tangem.domain.userwallets.UserWalletBuilder +import com.tangem.domain.wallets.builder.UserWalletBuilder import com.tangem.domain.wallets.legacy.UserWalletsListManager.Lockable.UnlockType import com.tangem.domain.wallets.legacy.unlockIfLockable import com.tangem.tap.backupService @@ -117,7 +117,9 @@ internal class WelcomeMiddleware { ) scanCardInternal { scanResponse -> - val userWallet = UserWalletBuilder(scanResponse).build() ?: return@scanCardInternal + val walletNameGenerateUseCase = store.inject(DaggerGraphState::generateWalletNameUseCase) + val userWallet = UserWalletBuilder(scanResponse, walletNameGenerateUseCase).build() + ?: return@scanCardInternal val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager) userWalletsListManager.save(userWallet, canOverride = true) 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 9001b33eea..0c09261f91 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 @@ -16,6 +16,7 @@ import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase import com.tangem.domain.settings.repositories.SettingsRepository import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.NetworksRepository +import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.domain.wallets.repository.WalletsRepository @@ -62,6 +63,7 @@ data class DaggerGraphState( val generalUserWalletsListManager: UserWalletsListManager? = null, val wasTwinsOnboardingShownUseCase: WasTwinsOnboardingShownUseCase? = null, val saveTwinsOnboardingShownUseCase: SaveTwinsOnboardingShownUseCase? = null, + val generateWalletNameUseCase: GenerateWalletNameUseCase? = null, val cardRepository: CardRepository? = null, val feedbackManagerFeatureToggles: FeedbackManagerFeatureToggles? = null, val tangemSdkLogger: TangemSdkLogger? = null, diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt index cfafab3c05..e069422752 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt @@ -91,6 +91,8 @@ object PreferencesKeys { val SHOULD_SAVE_ACCESS_CODES_KEY by lazy { booleanPreferencesKey(name = "saveAccessCodes") } + val IS_WALLET_NAMES_MIGRATION_DONE_KEY by lazy { booleanPreferencesKey(name = "isWalletNamesMigrationDone") } + fun getStart2CoinTOSAcceptedKey(region: String?) = booleanPreferencesKey(name = "start2Coin_tos_accepted_$region") } diff --git a/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletNamesMigrationRepository.kt b/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletNamesMigrationRepository.kt new file mode 100644 index 0000000000..60d442028e --- /dev/null +++ b/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletNamesMigrationRepository.kt @@ -0,0 +1,23 @@ +package com.tangem.data.wallets + +import com.tangem.datasource.local.preferences.AppPreferencesStore +import com.tangem.datasource.local.preferences.PreferencesKeys +import com.tangem.datasource.local.preferences.utils.getSyncOrDefault +import com.tangem.datasource.local.preferences.utils.store +import com.tangem.domain.wallets.repository.WalletNamesMigrationRepository + +class DefaultWalletNamesMigrationRepository( + private val appPreferencesStore: AppPreferencesStore, +) : WalletNamesMigrationRepository { + + override suspend fun isMigrationDone(): Boolean { + return appPreferencesStore.getSyncOrDefault( + key = PreferencesKeys.IS_WALLET_NAMES_MIGRATION_DONE_KEY, + default = false, + ) + } + + override suspend fun setMigrationDone() { + appPreferencesStore.store(PreferencesKeys.IS_WALLET_NAMES_MIGRATION_DONE_KEY, true) + } +} \ No newline at end of file diff --git a/data/wallets/src/main/java/com/tangem/data/wallets/di/WalletsDataModule.kt b/data/wallets/src/main/java/com/tangem/data/wallets/di/WalletsDataModule.kt index 26e9f82859..9748691618 100644 --- a/data/wallets/src/main/java/com/tangem/data/wallets/di/WalletsDataModule.kt +++ b/data/wallets/src/main/java/com/tangem/data/wallets/di/WalletsDataModule.kt @@ -1,9 +1,11 @@ package com.tangem.data.wallets.di +import com.tangem.data.wallets.DefaultWalletNamesMigrationRepository import com.tangem.data.wallets.DefaultWalletAddressServiceRepository import com.tangem.data.wallets.DefaultWalletsRepository import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.domain.walletmanager.WalletManagersFacade +import com.tangem.domain.wallets.repository.WalletNamesMigrationRepository import com.tangem.domain.wallets.repository.WalletAddressServiceRepository import com.tangem.domain.wallets.repository.WalletsRepository import dagger.Module @@ -29,4 +31,10 @@ internal object WalletsDataModule { ): WalletAddressServiceRepository { return DefaultWalletAddressServiceRepository(walletManagersFacade) } + + @Provides + @Singleton + fun provideMigrateNamesRepository(appPreferencesStore: AppPreferencesStore): WalletNamesMigrationRepository { + return DefaultWalletNamesMigrationRepository(appPreferencesStore) + } } \ No newline at end of file diff --git a/domain/legacy/build.gradle.kts b/domain/legacy/build.gradle.kts index f21bb97aa5..f13641bdc1 100644 --- a/domain/legacy/build.gradle.kts +++ b/domain/legacy/build.gradle.kts @@ -9,17 +9,16 @@ android { } dependencies { - implementation(project(":core:datasource")) - implementation(project(":core:utils")) - implementation(project(":common")) - implementation(project(":libs:auth")) + implementation(projects.core.datasource) + implementation(projects.core.utils) + implementation(projects.common) + implementation(projects.libs.auth) implementation(projects.libs.blockchainSdk) implementation(projects.domain.demo) implementation(projects.domain.models) implementation(projects.domain.tokens.models) implementation(projects.domain.txhistory.models) implementation(projects.domain.wallets.models) - /** Tangem libraries */ implementation(deps.tangem.blockchain) { exclude(module = "joda-time") diff --git a/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletBuilder.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/builder/UserWalletBuilder.kt similarity index 69% rename from domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletBuilder.kt rename to domain/wallets/src/main/java/com/tangem/domain/wallets/builder/UserWalletBuilder.kt index 325fb2efa7..ffa69e47ae 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletBuilder.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/builder/UserWalletBuilder.kt @@ -1,36 +1,22 @@ -package com.tangem.domain.userwallets +package com.tangem.domain.wallets.builder import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.CardDTO -import com.tangem.domain.models.scan.ProductType import com.tangem.domain.models.scan.ScanResponse +import com.tangem.domain.wallets.usecase.GetCardImageUseCase import com.tangem.domain.wallets.models.UserWallet +import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase class UserWalletBuilder( private val scanResponse: ScanResponse, + private val generateWalletNameUseCase: GenerateWalletNameUseCase, private val getCardImageUseCase: GetCardImageUseCase = GetCardImageUseCase(), ) { private var backupCardsIds: Set = emptySet() private var hasBackupError: Boolean = false private val CardDTO.isBackupNotAllowed: Boolean - get() = !this.settings.isBackupAllowed - - private val ScanResponse.userWalletName: String - get() = when (productType) { - ProductType.Note -> "Note" - ProductType.Twins -> "Twin" - ProductType.Start2Coin -> "Start2Coin" - ProductType.Visa -> "Tangem Visa" - ProductType.Wallet, - ProductType.Wallet2, - ProductType.Ring, - -> when { - card.isBackupNotAllowed -> "Tangem card" - cardTypesResolver.isStart2Coin() -> "Start2Coin" - else -> "Wallet" - } - } + get() = !settings.isBackupAllowed /** * DANGEROUS!!! @@ -56,7 +42,11 @@ class UserWalletBuilder( ?.let { UserWallet( walletId = it, - name = userWalletName, + name = generateWalletNameUseCase( + productType = productType, + isBackupNotAllowed = card.isBackupNotAllowed, + isStartToCoin = cardTypesResolver.isStart2Coin(), + ), artworkUrl = getCardImageUseCase.invoke(card.cardId, card.cardPublicKey), cardsInWallet = backupCardsIds.plus(card.cardId), scanResponse = this, diff --git a/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletIdBuilder.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/builder/UserWalletIdBuilder.kt similarity index 98% rename from domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletIdBuilder.kt rename to domain/wallets/src/main/java/com/tangem/domain/wallets/builder/UserWalletIdBuilder.kt index 607484d8a8..7c916ecec1 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletIdBuilder.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/builder/UserWalletIdBuilder.kt @@ -1,4 +1,4 @@ -package com.tangem.domain.userwallets +package com.tangem.domain.wallets.builder import com.tangem.common.extensions.calculateSha256 import com.tangem.common.extensions.hexToBytes diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/legacy/UserWalletsListManager.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/legacy/UserWalletsListManager.kt index e51ef51dc7..d98eb009aa 100644 --- a/domain/wallets/src/main/java/com/tangem/domain/wallets/legacy/UserWalletsListManager.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/legacy/UserWalletsListManager.kt @@ -18,6 +18,9 @@ interface UserWalletsListManager { /** [Flow] with selected [UserWallet] updates */ val selectedUserWallet: Flow + /** All saved [UserWallet]s */ + val userWalletsSync: List + /** Selected [UserWallet] */ val selectedUserWalletSync: UserWallet? diff --git a/domain/legacy/src/main/java/com/tangem/domain/userwallets/Artwork.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/models/Artwork.kt similarity index 66% rename from domain/legacy/src/main/java/com/tangem/domain/userwallets/Artwork.kt rename to domain/wallets/src/main/java/com/tangem/domain/wallets/models/Artwork.kt index d788aed532..00b7961d48 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/userwallets/Artwork.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/models/Artwork.kt @@ -1,4 +1,4 @@ -package com.tangem.domain.userwallets +package com.tangem.domain.wallets.models data class Artwork(val artworkId: String) { @@ -6,9 +6,9 @@ data class Artwork(val artworkId: String) { const val DEFAULT_IMG_URL = "https://app.tangem.com/cards/card_default.png" const val SERGIO_CARD_URL = "https://app.tangem.com/cards/card_tg059.png" const val MARTA_CARD_URL = "https://app.tangem.com/cards/card_tg083.png" + const val TWIN_CARD_1_URL = "https://app.tangem.com/cards/card_tg085.png" + const val TWIN_CARD_2_URL = "https://app.tangem.com/cards/card_tg086.png" const val SERGIO_CARD_ID = "BC01" const val MARTA_CARD_ID = "BC02" - const val TWIN_CARD_1 = "https://app.tangem.com/cards/card_tg085.png" - const val TWIN_CARD_2 = "https://app.tangem.com/cards/card_tg086.png" } } \ No newline at end of file diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/models/UpdateWalletError.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/models/UpdateWalletError.kt index 48a93dd33b..b15ec332d1 100644 --- a/domain/wallets/src/main/java/com/tangem/domain/wallets/models/UpdateWalletError.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/models/UpdateWalletError.kt @@ -2,5 +2,7 @@ package com.tangem.domain.wallets.models sealed interface UpdateWalletError { - object DataError : UpdateWalletError + data object DataError : UpdateWalletError + + data object NameAlreadyExists : UpdateWalletError } \ No newline at end of file diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletNamesMigrationRepository.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletNamesMigrationRepository.kt new file mode 100644 index 0000000000..0fa502f042 --- /dev/null +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletNamesMigrationRepository.kt @@ -0,0 +1,11 @@ +package com.tangem.domain.wallets.repository + +/** + * Access to migrate names flag + */ +interface WalletNamesMigrationRepository { + + suspend fun isMigrationDone(): Boolean + + suspend fun setMigrationDone() +} \ No newline at end of file diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GenerateWalletNameUseCase.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GenerateWalletNameUseCase.kt new file mode 100644 index 0000000000..f1d1852f0c --- /dev/null +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GenerateWalletNameUseCase.kt @@ -0,0 +1,60 @@ +package com.tangem.domain.wallets.usecase + +import com.tangem.domain.models.scan.ProductType +import com.tangem.domain.wallets.legacy.UserWalletsListManager + +/** + * Use case for user wallet name generation + */ +class GenerateWalletNameUseCase( + private val userWalletsListManager: UserWalletsListManager, +) { + + operator fun invoke(productType: ProductType, isBackupNotAllowed: Boolean, isStartToCoin: Boolean): String { + val defaultName = getDefaultName( + productType = productType, + isBackupNotAllowed = isBackupNotAllowed, + isStartToCoin = isStartToCoin, + ) + + val existingNames = userWalletsListManager.userWalletsSync.map { it.name }.toSet() + return suggestedWalletName(defaultName, existingNames) + } + + private fun suggestedWalletName(defaultName: String, existingNames: Set): String { + val startIndex = 2 + if (!existingNames.contains(defaultName)) { + return defaultName + } + + for (index in startIndex..MAX_WALLETS_LIMIT) { + val potentialName = "$defaultName $index" + if (!existingNames.contains(potentialName)) { + return potentialName + } + } + + return defaultName + } + + private fun getDefaultName(productType: ProductType, isBackupNotAllowed: Boolean, isStartToCoin: Boolean): String { + return when (productType) { + ProductType.Note -> "Note" + ProductType.Twins -> "Twin" + ProductType.Start2Coin -> "Start2Coin" + ProductType.Visa -> "Tangem Visa" + ProductType.Wallet, + ProductType.Wallet2, + ProductType.Ring, + -> when { + isBackupNotAllowed -> "Tangem card" + isStartToCoin -> "Start2Coin" + else -> "Wallet" + } + } + } + + companion object { + const val MAX_WALLETS_LIMIT = 10000 + } +} \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/userwallets/GetCardImageUseCase.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetCardImageUseCase.kt similarity index 89% rename from domain/legacy/src/main/java/com/tangem/domain/userwallets/GetCardImageUseCase.kt rename to domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetCardImageUseCase.kt index afa5eaaa37..3d92875a5b 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/userwallets/GetCardImageUseCase.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetCardImageUseCase.kt @@ -1,9 +1,10 @@ -package com.tangem.domain.userwallets +package com.tangem.domain.wallets.usecase import com.tangem.common.extensions.toHexString import com.tangem.common.services.Result import com.tangem.domain.common.TwinCardNumber import com.tangem.domain.common.TwinsHelper +import com.tangem.domain.wallets.models.Artwork import com.tangem.operations.attestation.OnlineCardVerifier import com.tangem.operations.attestation.TangemApi @@ -42,8 +43,8 @@ class GetCardImageUseCase(private val verifier: OnlineCardVerifier = OnlineCardV cardId.startsWith(Artwork.SERGIO_CARD_ID) -> Artwork.SERGIO_CARD_URL cardId.startsWith(Artwork.MARTA_CARD_ID) -> Artwork.MARTA_CARD_URL else -> when (TwinsHelper.getTwinCardNumber(cardId)) { - TwinCardNumber.First -> Artwork.TWIN_CARD_1 - TwinCardNumber.Second -> Artwork.TWIN_CARD_2 + TwinCardNumber.First -> Artwork.TWIN_CARD_1_URL + TwinCardNumber.Second -> Artwork.TWIN_CARD_2_URL else -> Artwork.DEFAULT_IMG_URL } } diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetWalletNamesUseCase.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetWalletNamesUseCase.kt new file mode 100644 index 0000000000..0108e03b67 --- /dev/null +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetWalletNamesUseCase.kt @@ -0,0 +1,13 @@ +package com.tangem.domain.wallets.usecase + +import com.tangem.domain.wallets.legacy.UserWalletsListManager + +/** + * Use case for getting list of user wallets names. + * + * @property userWalletsListManager user wallets list manager + */ +class GetWalletNamesUseCase(private val userWalletsListManager: UserWalletsListManager) { + + operator fun invoke(): List = userWalletsListManager.userWalletsSync.map { it.name } +} \ No newline at end of file diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/RenameWalletUseCase.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/RenameWalletUseCase.kt new file mode 100644 index 0000000000..e03da26f6b --- /dev/null +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/RenameWalletUseCase.kt @@ -0,0 +1,36 @@ +package com.tangem.domain.wallets.usecase + +import arrow.core.Either +import arrow.core.left +import arrow.core.raise.either +import arrow.core.right +import com.tangem.common.doOnFailure +import com.tangem.common.doOnSuccess +import com.tangem.domain.wallets.legacy.UserWalletsListManager +import com.tangem.domain.wallets.models.UpdateWalletError +import com.tangem.domain.wallets.models.UserWallet +import com.tangem.domain.wallets.models.UserWalletId + +/** + * Use case for rename user wallet + * + * @property userWalletsListManager user wallets list manager + */ +class RenameWalletUseCase(private val userWalletsListManager: UserWalletsListManager) { + + suspend operator fun invoke(userWalletId: UserWalletId, name: String): Either { + val existingNames = userWalletsListManager.userWalletsSync + + if (existingNames.any { it.name == name && it.walletId != userWalletId }) { + return UpdateWalletError.NameAlreadyExists.left() + } + + return either { + userWalletsListManager.update(userWalletId) { it.copy(name = name) } + .doOnSuccess { return it.right() } + .doOnFailure { return UpdateWalletError.DataError.left() } + + return UpdateWalletError.DataError.left() + } + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/ScanCardToUnlockWalletClickHandler.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/ScanCardToUnlockWalletClickHandler.kt index 1a4a34780d..e528262365 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/ScanCardToUnlockWalletClickHandler.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/ScanCardToUnlockWalletClickHandler.kt @@ -6,7 +6,8 @@ import arrow.core.raise.ensure import com.tangem.common.CompletionResult import com.tangem.common.core.TangemSdkError import com.tangem.domain.card.ScanCardProcessor -import com.tangem.domain.userwallets.UserWalletBuilder +import com.tangem.domain.wallets.builder.UserWalletBuilder +import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.usecase.SaveWalletUseCase import javax.inject.Inject @@ -14,6 +15,7 @@ import javax.inject.Inject internal class ScanCardToUnlockWalletClickHandler @Inject constructor( private val scanCardProcessor: ScanCardProcessor, private val saveWalletUseCase: SaveWalletUseCase, + private val generateWalletNameUseCase: GenerateWalletNameUseCase, ) { private var scanFailsCounter = 0 @@ -31,7 +33,7 @@ internal class ScanCardToUnlockWalletClickHandler @Inject constructor( scanFailsCounter = 0 // If card's public key is null then user wallet will be null - val scannedWallet = UserWalletBuilder(scanResponse = result.data).build() + val scannedWallet = UserWalletBuilder(result.data, generateWalletNameUseCase).build() ensure(walletId == scannedWallet?.walletId) { ScanCardToUnlockWalletError.WrongCardIsScanned diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/WalletNameMigrationUseCase.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/WalletNameMigrationUseCase.kt new file mode 100644 index 0000000000..99e60b3682 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/WalletNameMigrationUseCase.kt @@ -0,0 +1,49 @@ +package com.tangem.feature.wallet.presentation.wallet.domain + +import com.tangem.domain.wallets.legacy.UserWalletsListManager +import com.tangem.domain.wallets.repository.WalletNamesMigrationRepository +import timber.log.Timber + +class WalletNameMigrationUseCase( + private val userWalletsListManager: UserWalletsListManager, + private val walletNamesMigrationRepository: WalletNamesMigrationRepository, +) { + + suspend operator fun invoke() { + val wallets = userWalletsListManager.userWalletsSync + + if (walletNamesMigrationRepository.isMigrationDone()) { + return + } + + val existingNames: MutableSet = mutableSetOf() + wallets.indices.forEach { i -> + val defaultName = wallets[i].name + val suggestedWalletName = suggestedWalletName(defaultName, existingNames) + if (defaultName != suggestedWalletName) { + userWalletsListManager.update(wallets[i].walletId) { it.copy(name = suggestedWalletName) } + } + Timber.tag("Migrated names").e(i.toString() + " " + suggestedWalletName) + } + + walletNamesMigrationRepository.setMigrationDone() + } + + private fun suggestedWalletName(defaultName: String, existingNames: MutableSet): String { + val startIndex = 1 + for (index in startIndex..MAX_WALLETS_LIMIT) { + val name = if (index == startIndex) defaultName else "$defaultName $index" + + if (!existingNames.contains(name)) { + existingNames.add(name) + return name + } + } + + return defaultName + } + + companion object { + const val MAX_WALLETS_LIMIT = 10000 + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletAlertState.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletAlertState.kt index 34afb01364..03fb7f7902 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletAlertState.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletAlertState.kt @@ -25,6 +25,7 @@ internal sealed interface WalletAlertState { open val text: String = "" open val confirmButtonText: TextReference = resourceReference(id = R.string.common_ok) abstract val onConfirmClick: (String) -> Unit + abstract val errorTextProvider: (String) -> TextReference? } data class DefaultAlert( @@ -36,6 +37,7 @@ internal sealed interface WalletAlertState { data class RenameWalletAlert( override val text: String, override val onConfirmClick: (String) -> Unit, + override val errorTextProvider: (String) -> TextReference?, ) : TextInput() { override val title: TextReference = resourceReference(id = R.string.user_wallet_list_rename_popup_title) override val label: TextReference = resourceReference(id = R.string.user_wallet_list_rename_popup_placeholder) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletAlert.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletAlert.kt index c5303e085e..48e959ad54 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletAlert.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletAlert.kt @@ -64,7 +64,9 @@ private fun TextInputAlert(state: WalletAlertState.TextInput, onDismiss: () -> U fieldValue = value, confirmButton = DialogButton( title = state.confirmButtonText.resolveReference(), - enabled = value.text.isNotEmpty() && value.text != state.text, + enabled = value.text.isNotEmpty() && + value.text != state.text && + state.errorTextProvider(value.text) == null, onClick = { state.onConfirmClick(value.text) onDismiss() @@ -76,6 +78,8 @@ private fun TextInputAlert(state: WalletAlertState.TextInput, onDismiss: () -> U dismissButton = DialogButton(title = stringResource(id = R.string.common_cancel), onClick = onDismiss), textFieldParams = AdditionalTextInputDialogParams( label = state.label.resolveReference(), + isError = state.errorTextProvider(value.text) != null, + caption = state.errorTextProvider(value.text)?.resolveReference(), ), ) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index d7865401e0..912b4c81a3 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -15,6 +15,7 @@ import com.tangem.feature.wallet.presentation.deeplink.WalletDeepLinksHandler import com.tangem.feature.wallet.presentation.router.InnerWalletRouter import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent import com.tangem.feature.wallet.presentation.wallet.analytics.utils.SelectedWalletAnalyticsSender +import com.tangem.feature.wallet.presentation.wallet.domain.WalletNameMigrationUseCase import com.tangem.feature.wallet.presentation.wallet.loaders.WalletScreenContentLoader import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.model.WalletEvent @@ -57,6 +58,7 @@ internal class WalletViewModel @Inject constructor( private val screenLifecycleProvider: ScreenLifecycleProvider, private val selectedWalletAnalyticsSender: SelectedWalletAnalyticsSender, private val walletDeepLinksHandler: WalletDeepLinksHandler, + private val walletNameMigrationUseCase: WalletNameMigrationUseCase, ) : ViewModel() { val uiState: StateFlow = stateHolder.uiState @@ -71,12 +73,19 @@ internal class WalletViewModel @Inject constructor( suggestToEnableBiometrics() + maybeMigrateNames() subscribeToUserWalletsUpdates() subscribeOnBalanceHiding() subscribeOnSelectedWalletFlow() subscribeToScreenBackgroundState() } + private fun maybeMigrateNames() { + viewModelScope.launch { + walletNameMigrationUseCase() + } + } + fun setWalletRouter(router: InnerWalletRouter) { this.router = router clickIntents.initialize(router, viewModelScope) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCardClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCardClickIntents.kt index d2208db001..5b4bf78f5d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCardClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCardClickIntents.kt @@ -2,6 +2,11 @@ package com.tangem.feature.wallet.presentation.wallet.viewmodels.intents import arrow.core.getOrElse import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.wrappedList +import com.tangem.domain.wallets.usecase.GetWalletNamesUseCase +import com.tangem.domain.wallets.usecase.RenameWalletUseCase +import com.tangem.feature.wallet.impl.R import com.tangem.domain.card.DeleteSavedAccessCodesUseCase import com.tangem.core.navigation.AppScreen import com.tangem.core.navigation.NavigationAction @@ -11,7 +16,6 @@ import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.usecase.DeleteWalletUseCase import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase import com.tangem.domain.wallets.usecase.GetUserWalletUseCase -import com.tangem.domain.wallets.usecase.UpdateWalletUseCase import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.MainScreen import com.tangem.feature.wallet.presentation.wallet.loaders.WalletScreenContentLoader import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController @@ -40,9 +44,10 @@ internal class WalletCardClickIntentsImplementor @Inject constructor( private val stateHolder: WalletStateController, private val walletEventSender: WalletEventSender, private val walletScreenContentLoader: WalletScreenContentLoader, + private val renameWalletUseCase: RenameWalletUseCase, + private val getWalletNamesUseCase: GetWalletNamesUseCase, private val getUserWalletUseCase: GetUserWalletUseCase, private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, - private val updateWalletUseCase: UpdateWalletUseCase, private val deleteWalletUseCase: DeleteWalletUseCase, private val deleteSavedAccessCodesUseCase: DeleteSavedAccessCodesUseCase, private val analyticsEventHandler: AnalyticsEventHandler, @@ -54,19 +59,33 @@ internal class WalletCardClickIntentsImplementor @Inject constructor( override fun onRenameBeforeConfirmationClick(userWalletId: UserWalletId) { analyticsEventHandler.send(MainScreen.EditWalletTapped) - walletEventSender.send( - event = WalletEvent.ShowAlert( - state = WalletAlertState.RenameWalletAlert( - text = stateHolder.getSelectedWallet().walletCardState.title, - onConfirmClick = { onRenameAfterConfirmationClick(userWalletId, it) }, + viewModelScope.launch(dispatchers.main) { + val walletNames = getWalletNamesUseCase() + val currentWalletName = stateHolder.getSelectedWallet().walletCardState.title + walletEventSender.send( + event = WalletEvent.ShowAlert( + state = WalletAlertState.RenameWalletAlert( + text = currentWalletName, + onConfirmClick = { onRenameAfterConfirmationClick(userWalletId, it) }, + errorTextProvider = { enteredName -> + if (walletNames.contains(enteredName) && enteredName != currentWalletName) { + resourceReference( + R.string.user_wallet_list_rename_popup_error_already_exists, + wrappedList(enteredName), + ) + } else { + null + } + }, + ), ), - ), - ) + ) + } } override fun onRenameAfterConfirmationClick(userWalletId: UserWalletId, name: String) { viewModelScope.launch(dispatchers.main) { - updateWalletUseCase(userWalletId = userWalletId, update = { it.copy(name = name) }) + renameWalletUseCase(userWalletId = userWalletId, name) } }