From ffc38eb02de4d50f427d4cce9561d9ffd4f2fc58 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 11 Jul 2023 22:21:20 +0800 Subject: [PATCH] Updated on 2026-08-14 --- .../java/com/tangem/tap/TapApplication.kt | 5 +++ .../tangem/tap/di/domain/CardDomainModule.kt | 18 ++++++++++ ...ocessor.kt => DefaultScanCardProcessor.kt} | 27 ++++++++------- .../details/redux/DetailsMiddleware.kt | 5 +-- .../tap/features/home/redux/HomeMiddleware.kt | 4 +-- .../middlewares/MultiWalletMiddleware.kt | 5 +-- .../redux/WalletSelectorMiddleware.kt | 6 ++-- .../welcome/redux/WelcomeMiddleware.kt | 4 +-- .../tap/proxy/redux/DaggerGraphState.kt | 2 ++ .../tangem/domain/card/ScanCardProcessor.kt | 25 ++++++++++++++ .../wallet/viewmodels/WalletViewModel.kt | 34 ++++++++++++++++--- 11 files changed, 106 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/di/domain/CardDomainModule.kt rename app/src/main/java/com/tangem/tap/domain/scanCard/{ScanCardProcessor.kt => DefaultScanCardProcessor.kt} (76%) create mode 100644 domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardProcessor.kt diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 9c3d7f67cb..b1c5862c9b 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -22,6 +22,7 @@ import com.tangem.datasource.config.FeaturesLocalLoader import com.tangem.datasource.config.models.Config import com.tangem.datasource.connection.NetworkConnectionManager import com.tangem.domain.DomainLayer +import com.tangem.domain.card.ScanCardProcessor import com.tangem.domain.common.LogConfig import com.tangem.domain.wallets.legacy.WalletManagersRepository import com.tangem.feature.learn2earn.domain.api.Learn2earnInteractor @@ -152,6 +153,9 @@ class TapApplication : Application(), ImageLoaderFactory { @Inject lateinit var tokenDetailsFeatureToggles: TokenDetailsFeatureToggles + @Inject + lateinit var scanCardProcessor: ScanCardProcessor + override fun onCreate() { super.onCreate() @@ -169,6 +173,7 @@ class TapApplication : Application(), ImageLoaderFactory { walletConnectRepository = walletConnect2Repository, walletConnectSessionsRepository = walletConnectSessionsRepository, tokenDetailsFeatureToggles = tokenDetailsFeatureToggles, + scanCardProcessor = scanCardProcessor, ), ), ) diff --git a/app/src/main/java/com/tangem/tap/di/domain/CardDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/CardDomainModule.kt new file mode 100644 index 0000000000..27d0e3e8df --- /dev/null +++ b/app/src/main/java/com/tangem/tap/di/domain/CardDomainModule.kt @@ -0,0 +1,18 @@ +package com.tangem.tap.di.domain + +import com.tangem.domain.card.ScanCardProcessor +import com.tangem.tap.domain.scanCard.DefaultScanCardProcessor +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal object CardDomainModule { + + @Provides + @Singleton + fun provideScanCardUseCase(): ScanCardProcessor = DefaultScanCardProcessor() +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/DefaultScanCardProcessor.kt similarity index 76% rename from app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt rename to app/src/main/java/com/tangem/tap/domain/scanCard/DefaultScanCardProcessor.kt index 808f338f85..7c21a8a2f2 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/DefaultScanCardProcessor.kt @@ -3,20 +3,21 @@ package com.tangem.tap.domain.scanCard import com.tangem.common.CompletionResult import com.tangem.common.core.TangemError import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.domain.card.ScanCardProcessor import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.store // TODO: Remove this object after feature toggle was removed and use ScanCardUseCase instead -internal object ScanCardProcessor { +internal class DefaultScanCardProcessor : ScanCardProcessor { private val isNewCardScanningEnabled: Boolean get() = store.state.daggerGraphState .get(DaggerGraphState::customTokenFeatureToggles) .isNewCardScanningEnabled - suspend fun scan( - cardId: String? = null, - allowsRequestAccessCodeFromRepository: Boolean = false, + override suspend fun scan( + cardId: String?, + allowsRequestAccessCodeFromRepository: Boolean, ): CompletionResult { return if (isNewCardScanningEnabled) { UseCaseScanProcessor.scan(cardId, allowsRequestAccessCodeFromRepository) @@ -26,15 +27,15 @@ internal object ScanCardProcessor { } @Suppress("LongParameterList") - suspend fun scan( - analyticsEvent: AnalyticsEvent? = null, - cardId: String? = null, - onProgressStateChange: suspend (showProgress: Boolean) -> Unit = {}, - onScanStateChange: suspend (scanInProgress: Boolean) -> Unit = {}, - onWalletNotCreated: suspend () -> Unit = {}, - disclaimerWillShow: () -> Unit = {}, - onFailure: suspend (error: TangemError) -> Unit = {}, - onSuccess: suspend (scanResponse: ScanResponse) -> Unit = {}, + override suspend fun scan( + analyticsEvent: AnalyticsEvent?, + cardId: String?, + onProgressStateChange: suspend (showProgress: Boolean) -> Unit, + onScanStateChange: suspend (scanInProgress: Boolean) -> Unit, + onWalletNotCreated: suspend () -> Unit, + disclaimerWillShow: () -> Unit, + onFailure: suspend (error: TangemError) -> Unit, + onSuccess: suspend (scanResponse: ScanResponse) -> Unit, ) { if (isNewCardScanningEnabled) { UseCaseScanProcessor.scan( 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 a992489911..b93e243322 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 @@ -25,7 +25,6 @@ import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.model.builders.UserWalletBuilder import com.tangem.tap.domain.model.builders.UserWalletIdBuilder -import com.tangem.tap.domain.scanCard.ScanCardProcessor import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation import com.tangem.tap.domain.userWalletList.di.provideRuntimeImplementation import com.tangem.tap.domain.userWalletList.isLockedSync @@ -33,6 +32,7 @@ import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.tangemSdkManager import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers @@ -74,7 +74,8 @@ class DetailsMiddleware { is DetailsAction.AccessCodeRecovery -> accessCodeRecoveryMiddleware.handle(state, action) DetailsAction.ScanCard -> { scope.launch { - ScanCardProcessor.scan(allowsRequestAccessCodeFromRepository = true) + store.state.daggerGraphState.get(DaggerGraphState::scanCardProcessor) + .scan(allowsRequestAccessCodeFromRepository = true) .doOnSuccess { scanResponse -> // if we use biometric, scanResponse in GlobalState is null, and crashes NPE on twin cards store.dispatch(GlobalAction.SaveScanResponse(scanResponse)) 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 8a225afa8a..01e2d50c0d 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 @@ -21,12 +21,12 @@ import com.tangem.tap.common.extensions.onUserWalletSelected import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.model.builders.UserWalletBuilder -import com.tangem.tap.domain.scanCard.ScanCardProcessor import com.tangem.tap.features.home.BELARUS_COUNTRY_CODE import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE import com.tangem.tap.features.home.redux.HomeMiddleware.BUY_WALLET_URL import com.tangem.tap.features.send.redux.states.ButtonState import com.tangem.tap.features.signin.redux.SignInAction +import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.rekotlin.Action @@ -78,7 +78,7 @@ private fun readCard(analyticsEvent: AnalyticsEvent?) = scope.launch { useBiometricsForAccessCode = preferencesStorage.shouldSaveAccessCodes, ) - ScanCardProcessor.scan( + store.state.daggerGraphState.get(DaggerGraphState::scanCardProcessor).scan( analyticsEvent = analyticsEvent, onProgressStateChange = { showProgress -> if (showProgress) { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt index d008d1b2e0..3f080d645a 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt @@ -15,10 +15,10 @@ import com.tangem.tap.common.extensions.dispatchErrorNotification import com.tangem.tap.common.extensions.dispatchWithMain import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.TapError -import com.tangem.tap.domain.scanCard.ScanCardProcessor import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletState import com.tangem.tap.features.wallet.redux.models.WalletDialog +import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.userWalletsListManager @@ -102,7 +102,8 @@ class MultiWalletMiddleware { } private fun scanAndUpdateCard(selectedUserWallet: UserWallet) = scope.launch(Dispatchers.Default) { - ScanCardProcessor.scan(selectedUserWallet.cardId, allowsRequestAccessCodeFromRepository = true) + store.state.daggerGraphState.get(DaggerGraphState::scanCardProcessor) + .scan(cardId = selectedUserWallet.cardId, allowsRequestAccessCodeFromRepository = true) .flatMap { scanResponse -> userWalletsListManager.update( userWalletId = selectedUserWallet.walletId, diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt index 00d1e687bb..148e95d323 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt @@ -20,8 +20,8 @@ import com.tangem.tap.domain.model.TotalFiatBalance import com.tangem.tap.domain.model.WalletStoreModel import com.tangem.tap.domain.model.builders.UserWalletBuilder import com.tangem.tap.domain.model.builders.UserWalletIdBuilder -import com.tangem.tap.domain.scanCard.ScanCardProcessor import com.tangem.tap.domain.userWalletList.unlockIfLockable +import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.firstOrNull @@ -133,7 +133,7 @@ internal class WalletSelectorMiddleware { useBiometricsForAccessCode = preferencesStorage.shouldSaveAccessCodes, ) - ScanCardProcessor.scan( + store.state.daggerGraphState.get(DaggerGraphState::scanCardProcessor).scan( analyticsEvent = Basic.CardWasScanned(AnalyticsParam.ScannedFrom.MyWallets), onWalletNotCreated = { // No need to rollback policy, continue with the policy set before the card scan @@ -208,7 +208,7 @@ internal class WalletSelectorMiddleware { private suspend fun unlockUserWalletWithScannedCard(userWallet: UserWallet): CompletionResult { Analytics.send(MyWallets.Button.WalletUnlockTapped()) tangemSdkManager.changeDisplayedCardIdNumbersCount(userWallet.scanResponse) - return ScanCardProcessor.scan() + return store.state.daggerGraphState.get(DaggerGraphState::scanCardProcessor).scan() .map { scanResponse -> val scannedUserWalletId = UserWalletIdBuilder.scanResponse(scanResponse).build() if (scannedUserWalletId == userWallet.walletId) { 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 8a96417455..7fab7c2a4f 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 @@ -16,10 +16,10 @@ import com.tangem.tap.common.extensions.dispatchWithMain import com.tangem.tap.common.extensions.onUserWalletSelected import com.tangem.tap.common.redux.AppState import com.tangem.tap.domain.model.builders.UserWalletBuilder -import com.tangem.tap.domain.scanCard.ScanCardProcessor import com.tangem.tap.domain.userWalletList.unlockIfLockable import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler import com.tangem.tap.features.signin.redux.SignInAction +import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.launch import org.rekotlin.Middleware import timber.log.Timber @@ -103,7 +103,7 @@ internal class WelcomeMiddleware { tangemSdkManager.setAccessCodeRequestPolicy( useBiometricsForAccessCode = preferencesStorage.shouldSaveAccessCodes, ) - ScanCardProcessor.scan( + store.state.daggerGraphState.get(DaggerGraphState::scanCardProcessor).scan( analyticsEvent = Basic.CardWasScanned(AnalyticsParam.ScannedFrom.SignIn), onSuccess = { scanResponse -> scope.launch { onCardScanned(scanResponse) } 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 84409d4e36..7bdabd80a3 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 @@ -2,6 +2,7 @@ package com.tangem.tap.proxy.redux import com.tangem.datasource.asset.AssetReader import com.tangem.datasource.connection.NetworkConnectionManager +import com.tangem.domain.card.ScanCardProcessor import com.tangem.domain.card.ScanCardUseCase import com.tangem.features.tester.api.TesterRouter import com.tangem.features.tokendetails.featuretoggles.TokenDetailsFeatureToggles @@ -27,6 +28,7 @@ data class DaggerGraphState( val walletConnectInteractor: WalletConnectInteractor? = null, val tokenDetailsFeatureToggles: TokenDetailsFeatureToggles? = null, val tokenDetailsRouter: TokenDetailsRouter? = null, + val scanCardProcessor: ScanCardProcessor? = null, ) : StateType { inline fun get(getDependency: DaggerGraphState.() -> T?): T { diff --git a/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardProcessor.kt b/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardProcessor.kt new file mode 100644 index 0000000000..961d9acd07 --- /dev/null +++ b/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardProcessor.kt @@ -0,0 +1,25 @@ +package com.tangem.domain.card + +import com.tangem.common.CompletionResult +import com.tangem.common.core.TangemError +import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.domain.models.scan.ScanResponse + +interface ScanCardProcessor { + + suspend fun scan( + cardId: String? = null, + allowsRequestAccessCodeFromRepository: Boolean = false, + ): CompletionResult + + suspend fun scan( + analyticsEvent: AnalyticsEvent? = null, + cardId: String? = null, + onProgressStateChange: suspend (showProgress: Boolean) -> Unit = {}, + onScanStateChange: suspend (scanInProgress: Boolean) -> Unit = {}, + onWalletNotCreated: suspend () -> Unit = {}, + disclaimerWillShow: () -> Unit = {}, + onFailure: suspend (error: TangemError) -> Unit = {}, + onSuccess: suspend (scanResponse: ScanResponse) -> Unit = {}, + ) +} \ 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 9c80b75b31..2a2f30dcbb 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 @@ -5,12 +5,18 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.tangem.common.doOnFailure +import com.tangem.common.doOnSuccess +import com.tangem.domain.card.ScanCardProcessor import com.tangem.domain.tokens.GetTokenListUseCase import com.tangem.feature.wallet.presentation.common.WalletPreviewData import com.tangem.feature.wallet.presentation.router.InnerWalletRouter import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder import com.tangem.feature.wallet.presentation.wallet.state.WalletTopBarConfig +import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch import javax.inject.Inject import kotlin.properties.Delegates @@ -23,6 +29,8 @@ import kotlin.properties.Delegates internal class WalletViewModel @Inject constructor( @Suppress("unused") // TODO: [REDACTED_JIRA] private val getTokenListUseCase: GetTokenListUseCase, + private val scanCardProcessor: ScanCardProcessor, + private val dispatchers: CoroutineDispatcherProvider, ) : ViewModel() { /** Feature router */ @@ -34,16 +42,32 @@ internal class WalletViewModel @Inject constructor( // TODO: [REDACTED_TASK_KEY] Use production data instead of WalletPreviewData private fun getInitialState(): WalletStateHolder = WalletPreviewData.multicurrencyWalletScreenState.copy( - onBackClick = { router.popBackStack() }, - topBarConfig = WalletTopBarConfig( - onScanCardClick = { router.openOrganizeTokensScreen() }, - onMoreClick = { router.openDetailsScreen() }, - ), + onBackClick = ::onBackClick, + topBarConfig = createTopBarConfig(), walletsListConfig = WalletPreviewData.multicurrencyWalletScreenState.walletsListConfig.copy( onWalletChange = ::selectWallet, ), ) + private fun onBackClick() { + router.popBackStack() + } + + private fun createTopBarConfig(): WalletTopBarConfig { + return WalletTopBarConfig( + onScanCardClick = ::onScanCardClick, + onMoreClick = { router.openDetailsScreen() }, + ) + } + + private fun onScanCardClick() { + viewModelScope.launch(dispatchers.io) { + scanCardProcessor.scan(allowsRequestAccessCodeFromRepository = true) + .doOnSuccess { /* [REDACTED_TODO_COMMENT] */ } + .doOnFailure { /* [REDACTED_TODO_COMMENT] */ } + } + } + // TODO: [REDACTED_TASK_KEY] Use production data instead of WalletPreviewData private fun selectWallet(index: Int) { if (uiState.walletsListConfig.selectedWalletIndex == index) return