diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 07f7cd8b81..75db227f9d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -25,7 +25,7 @@ dependencies { implementation(project(":domain:legacy")) implementation(project(":domain:models")) implementation(project(":domain:core")) - implementation(project(":domain:card")) + implementation(projects.domain.card) implementation(project(":domain:wallets")) implementation(project(":domain:wallets:models")) implementation(projects.domain.tokens) @@ -41,6 +41,7 @@ dependencies { implementation(project(":libs:crypto")) implementation(project(":libs:auth")) implementation(project(":data:source:preferences")) + implementation(projects.data.card) implementation(projects.data.tokens) /** Features */ diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index 2eb8371482..1c4395d748 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -10,10 +10,11 @@ import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsControllerCompat import by.kirich1409.viewbindingdelegate.viewBinding import com.google.android.material.snackbar.Snackbar -import com.tangem.TangemSdk import com.tangem.core.navigation.AppScreen import com.tangem.core.navigation.NavigationAction +import com.tangem.data.card.sdk.CardSdkLifecycleObserver import com.tangem.domain.card.ScanCardUseCase +import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.features.tester.api.TesterRouter import com.tangem.features.tokendetails.navigation.TokenDetailsRouter @@ -56,7 +57,6 @@ import java.lang.ref.WeakReference import javax.inject.Inject import kotlin.coroutines.CoroutineContext -lateinit var tangemSdk: TangemSdk lateinit var tangemSdkManager: TangemSdkManager lateinit var backupService: BackupService internal var lockUserWalletsTimer: LockUserWalletsTimer? = null @@ -88,7 +88,10 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac lateinit var testerRouter: TesterRouter @Inject - lateinit var injectedTangemSdk: TangemSdk + lateinit var cardSdkLifecycleObserver: CardSdkLifecycleObserver + + @Inject + lateinit var cardSdkConfigRepository: CardSdkConfigRepository @Inject lateinit var injectedTangemSdkManager: TangemSdkManager @@ -122,11 +125,11 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac systemActions() store.dispatch(NavigationAction.ActivityCreated(WeakReference(this))) - tangemSdk = injectedTangemSdk + cardSdkLifecycleObserver.onCreate(context = this) + tangemSdkManager = injectedTangemSdkManager appStateHolder.tangemSdkManager = tangemSdkManager - appStateHolder.tangemSdk = tangemSdk - backupService = BackupService.init(tangemSdk, this) + backupService = BackupService.init(cardSdkConfigRepository.sdk, this) lockUserWalletsTimer = LockUserWalletsTimer(owner = this) initUserWalletsListManager() @@ -144,10 +147,37 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac walletRouter = walletRouter, walletConnectInteractor = walletConnectInteractor, tokenDetailsRouter = tokenDetailsRouter, + cardSdkConfigRepository = cardSdkConfigRepository, ), ) } + override fun onStart() { + super.onStart() + dialogManager.onStart(this) + } + + override fun onResume() { + super.onResume() + // TODO: RESEARCH! NotificationsHandler is created in onResume and destroyed in onStop + notificationsHandler = NotificationsHandler(binding.fragmentContainer) + + navigateToInitialScreenIfNeededOnResume(intent) + } + + override fun onStop() { + notificationsHandler = null + dialogManager.onStop() + super.onStop() + } + + override fun onDestroy() { + store.dispatch(NavigationAction.ActivityDestroyed(WeakReference(this))) + intentProcessor.removeAll() + cardSdkLifecycleObserver.onDestroy() + super.onDestroy() + } + private fun initIntentHandlers() { val hasSavedWalletsProvider = { store.state.globalState.userWalletsListManager?.hasUserWallets == true } intentProcessor.addHandler(BackgroundScanIntentHandler(hasSavedWalletsProvider)) @@ -183,13 +213,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT } - override fun onResume() { - super.onResume() - notificationsHandler = NotificationsHandler(binding.fragmentContainer) - - navigateToInitialScreenIfNeededOnResume(intent) - } - override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) scope.launch { @@ -197,23 +220,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac } } - override fun onStart() { - super.onStart() - dialogManager.onStart(this) - } - - override fun onStop() { - notificationsHandler = null - dialogManager.onStop() - super.onStop() - } - - override fun onDestroy() { - store.dispatch(NavigationAction.ActivityDestroyed(WeakReference(this))) - intentProcessor.removeAll() - super.onDestroy() - } - override fun showSnackbar(text: Int, buttonTitle: Int?, action: View.OnClickListener?) { if (snackbar != null) return diff --git a/app/src/main/java/com/tangem/tap/common/redux/AccessCodeRequestPolicyMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/AccessCodeRequestPolicyMiddleware.kt index a96f1c1e06..c385b121ae 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AccessCodeRequestPolicyMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AccessCodeRequestPolicyMiddleware.kt @@ -3,7 +3,8 @@ package com.tangem.tap.common.redux import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.preferencesStorage -import com.tangem.tap.tangemSdkManager +import com.tangem.tap.proxy.redux.DaggerGraphState +import com.tangem.tap.store import org.rekotlin.Middleware class AccessCodeRequestPolicyMiddleware { @@ -19,9 +20,8 @@ class AccessCodeRequestPolicyMiddleware { } private fun updateAccessCodeRequestPolicy(scanResponse: ScanResponse) { - tangemSdkManager.setAccessCodeRequestPolicy( - useBiometricsForAccessCode = preferencesStorage.shouldSaveAccessCodes && - scanResponse.card.isAccessCodeSet, + store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy( + isBiometricsRequestPolicy = preferencesStorage.shouldSaveAccessCodes && scanResponse.card.isAccessCodeSet, ) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/di/ActivityModule.kt b/app/src/main/java/com/tangem/tap/di/ActivityModule.kt index 96639f64e4..a894d7c4fe 100644 --- a/app/src/main/java/com/tangem/tap/di/ActivityModule.kt +++ b/app/src/main/java/com/tangem/tap/di/ActivityModule.kt @@ -1,42 +1,43 @@ package com.tangem.tap.di import android.content.Context -import androidx.fragment.app.FragmentActivity -import com.tangem.TangemSdk import com.tangem.domain.card.ScanCardUseCase -import com.tangem.sdk.extensions.initWithBiometrics +import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.tap.domain.TangemSdkManager import com.tangem.tap.domain.scanCard.repository.DefaultScanCardRepository import com.tangem.tap.userTokensRepository import dagger.Module import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.android.components.ActivityComponent -import dagger.hilt.android.qualifiers.ActivityContext -import dagger.hilt.android.scopes.ActivityScoped +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton @Module -@InstallIn(ActivityComponent::class) +@InstallIn(SingletonComponent::class) internal object ActivityModule { @Provides - @ActivityScoped - fun provideTangemSdk(@ActivityContext context: Context): TangemSdk { - return TangemSdk.initWithBiometrics(context as FragmentActivity, TangemSdkManager.config) + @Singleton + fun provideTangemSdkManager( + @ApplicationContext context: Context, + cardSdkConfigRepository: CardSdkConfigRepository, + ): TangemSdkManager { + return TangemSdkManager(cardSdkConfigRepository = cardSdkConfigRepository, resources = context.resources) } @Provides - @ActivityScoped - fun provideTangemSdkManager(@ActivityContext context: Context, tangemSdk: TangemSdk): TangemSdkManager { - return TangemSdkManager(tangemSdk, context) - } - - @Provides - @ActivityScoped - fun provideScanCardUseCase(tangemSdk: TangemSdk, tangemSdkManager: TangemSdkManager): ScanCardUseCase { + @Singleton + fun provideScanCardUseCase( + tangemSdkManager: TangemSdkManager, + cardSdkConfigRepository: CardSdkConfigRepository, + ): ScanCardUseCase { return ScanCardUseCase( - tangemSdk = tangemSdk, - scanCardRepository = DefaultScanCardRepository(userTokensRepository, tangemSdkManager), + cardSdkConfigRepository = cardSdkConfigRepository, + scanCardRepository = DefaultScanCardRepository( + userTokensRepository = userTokensRepository, + tangemSdkManager = tangemSdkManager, + ), ) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt index c395569c5c..2ac23842a6 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -1,27 +1,25 @@ package com.tangem.tap.domain -import android.content.Context +import android.content.res.Resources import androidx.annotation.StringRes import com.tangem.Message import com.tangem.TangemSdk import com.tangem.blockchain.common.Blockchain import com.tangem.common.* import com.tangem.common.biometric.BiometricManager -import com.tangem.common.card.FirmwareVersion import com.tangem.common.core.* import com.tangem.common.extensions.ByteArrayKey import com.tangem.common.usersCode.UserCodeRepository import com.tangem.core.analytics.Analytics import com.tangem.crypto.bip39.DefaultMnemonic import com.tangem.crypto.hdWallet.DerivationPath +import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse import com.tangem.operations.ScanTask import com.tangem.operations.derivation.DerivationTaskResponse import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask -import com.tangem.operations.pins.CheckUserCodesCommand -import com.tangem.operations.pins.CheckUserCodesResponse import com.tangem.operations.pins.SetUserCodeCommand import com.tangem.operations.usersetttings.SetUserCodeRecoveryAllowedTask import com.tangem.tap.common.analytics.events.Basic @@ -38,7 +36,10 @@ import kotlinx.coroutines.withContext import kotlin.coroutines.resume @Suppress("TooManyFunctions") -class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Context) { +class TangemSdkManager(private val cardSdkConfigRepository: CardSdkConfigRepository, private val resources: Resources) { + + private val tangemSdk: TangemSdk + get() = cardSdkConfigRepository.sdk private val userCodeRepository by lazy { UserCodeRepository( @@ -63,7 +64,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co messageRes: Int? = null, allowsRequestAccessCodeFromRepository: Boolean = false, ): CompletionResult { - val message = Message(context.getString(messageRes ?: R.string.initial_message_scan_header)) + val message = Message(resources.getString(messageRes ?: R.string.initial_message_scan_header)) return runTaskAsyncReturnOnMain( runnable = ScanProductTask( card = null, @@ -80,7 +81,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co return runTaskAsync( CreateProductWalletTask(scanResponse.cardTypesResolver), scanResponse.card.cardId, - Message(context.getString(R.string.initial_message_create_wallet_body)), + Message(resources.getString(R.string.initial_message_create_wallet_body)), ) } @@ -92,7 +93,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co is CompletionResult.Success -> runTaskAsync( CreateProductWalletTask(scanResponse.cardTypesResolver, seedResult.data), scanResponse.card.cardId, - Message(context.getString(R.string.initial_message_create_wallet_body)), + Message(resources.getString(R.string.initial_message_create_wallet_body)), ) is CompletionResult.Failure -> CompletionResult.Failure(seedResult.error) @@ -111,7 +112,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co return runTaskAsyncReturnOnMain( CreateWalletAndRescanTask(), cardId, - initialMessage = Message(context.getString(R.string.initial_message_create_wallet_body)), + initialMessage = Message(resources.getString(R.string.initial_message_create_wallet_body)), ) .map { CardDTO(it) } } @@ -127,7 +128,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co return runTaskAsyncReturnOnMain( runnable = ResetToFactorySettingsTask(), cardId = cardId, - initialMessage = Message(context.getString(R.string.card_settings_reset_card_to_factory)), + initialMessage = Message(resources.getString(R.string.card_settings_reset_card_to_factory)), ) .map { CardDTO(it) } } @@ -154,7 +155,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co return runTaskAsyncReturnOnMain( SetUserCodeCommand.changePasscode(null), cardId, - initialMessage = Message(context.getString(R.string.initial_message_change_passcode_body)), + initialMessage = Message(resources.getString(R.string.initial_message_change_passcode_body)), ) } @@ -162,7 +163,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co return runTaskAsyncReturnOnMain( SetUserCodeCommand.changeAccessCode(null), cardId, - initialMessage = Message(context.getString(R.string.initial_message_change_access_code_body)), + initialMessage = Message(resources.getString(R.string.initial_message_change_access_code_body)), ) } @@ -170,15 +171,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co return runTaskAsyncReturnOnMain( SetUserCodeCommand.resetUserCodes(), cardId, - initialMessage = Message(context.getString(R.string.initial_message_tap_header)), - ) - } - - suspend fun checkUserCodes(cardId: String?): CompletionResult { - return runTaskAsyncReturnOnMain( - CheckUserCodesCommand(), - cardId, - initialMessage = Message(context.getString(R.string.initial_message_tap_header)), + initialMessage = Message(resources.getString(R.string.initial_message_tap_header)), ) } @@ -186,7 +179,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co return runTaskAsyncReturnOnMain( SetUserCodeRecoveryAllowedTask(enabled), cardId, - initialMessage = Message(context.getString(R.string.initial_message_tap_header)), + initialMessage = Message(resources.getString(R.string.initial_message_tap_header)), ) } @@ -197,7 +190,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co return runTaskAsyncReturnOnMain( runnable = ScanTask(allowRequestAccessCodeFromRepository), cardId = cardId, - initialMessage = Message(context.getString(R.string.initial_message_tap_header)), + initialMessage = Message(resources.getString(R.string.initial_message_tap_header)), ) .map { CardDTO(it) } } @@ -233,31 +226,8 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co } } + @Deprecated("TangemSdkManager shouldn't returns a string from resources") fun getString(@StringRes stringResId: Int, vararg formatArgs: Any?): String { - return context.getString(stringResId, *formatArgs) - } - - fun setAccessCodeRequestPolicy(useBiometricsForAccessCode: Boolean) { - tangemSdk.config.userCodeRequestPolicy = if (useBiometricsForAccessCode) { - UserCodeRequestPolicy.AlwaysWithBiometrics(codeType = UserCodeType.AccessCode) - } else { - UserCodeRequestPolicy.Default - } - } - - fun useBiometricsForAccessCode(): Boolean { - val policy = tangemSdk.config.userCodeRequestPolicy - return policy is UserCodeRequestPolicy.AlwaysWithBiometrics && policy.codeType == UserCodeType.AccessCode - } - - companion object { - val config = Config( - linkedTerminal = true, - allowUntrustedCards = true, - filter = CardFilter( - allowedCardTypes = FirmwareVersion.FirmwareType.values().toList(), - maxFirmwareVersion = FirmwareVersion(major = 4, minor = 52), - ), - ) + return resources.getString(stringResId, *formatArgs) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt index 6466ac2f85..03f8cf7d40 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt @@ -36,8 +36,8 @@ import com.tangem.tap.domain.walletconnect2.domain.models.binance.WcBinanceTrans import com.tangem.tap.features.details.redux.walletconnect.* import com.tangem.tap.features.details.ui.walletconnect.dialogs.PersonalSignDialogData import com.tangem.tap.features.details.ui.walletconnect.dialogs.TransactionRequestDialogData +import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.store -import com.tangem.tap.tangemSdk import com.tangem.tap.tangemSdkManager import com.trustwallet.walletconnect.models.ethereum.WCEthereumSignMessage.WCSignType.* import timber.log.Timber @@ -163,7 +163,10 @@ class WalletConnectSdkHelper { private suspend fun sendTransaction(data: WcTransactionData, cardId: String?): String? { val result = (data.walletManager as TransactionSender).send( transactionData = data.transaction, - signer = CommonSigner(tangemSdk, cardId), + signer = CommonSigner( + tangemSdk = store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository).sdk, + cardId = cardId, + ), ) return when (result) { SimpleResult.Success -> { 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 b93e243322..e665b7cee3 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 @@ -372,9 +372,9 @@ class DetailsMiddleware { Analytics.send(Settings.AppSettings.SaveAccessCodeSwitcherChanged(AnalyticsParam.OnOffState.On)) preferencesStorage.shouldSaveAccessCodes = true - tangemSdkManager.setAccessCodeRequestPolicy( - useBiometricsForAccessCode = scanResponse?.card?.isAccessCodeSet == true, - ) + store.state.daggerGraphState + .get(DaggerGraphState::cardSdkConfigRepository) + .setAccessCodeRequestPolicy(isBiometricsRequestPolicy = scanResponse?.card?.isAccessCodeSet == true) return CompletionResult.Success(Unit) } @@ -385,9 +385,9 @@ class DetailsMiddleware { Analytics.send(Settings.AppSettings.SaveAccessCodeSwitcherChanged(AnalyticsParam.OnOffState.Off)) preferencesStorage.shouldSaveAccessCodes = false - tangemSdkManager.setAccessCodeRequestPolicy( - useBiometricsForAccessCode = false, - ) + store.state.daggerGraphState + .get(DaggerGraphState::cardSdkConfigRepository) + .setAccessCodeRequestPolicy(isBiometricsRequestPolicy = false) } .doOnFailure { error -> Timber.e(error, "Unable to delete saved access codes") 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 01e2d50c0d..547440e96f 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 @@ -9,7 +9,6 @@ import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.core.navigation.AppScreen import com.tangem.core.navigation.NavigationAction import com.tangem.domain.models.scan.ScanResponse -import com.tangem.tap.* import com.tangem.tap.common.analytics.events.Basic import com.tangem.tap.common.analytics.events.IntroductionProcess import com.tangem.tap.common.analytics.events.Shop @@ -26,7 +25,11 @@ 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.preferencesStorage import com.tangem.tap.proxy.redux.DaggerGraphState +import com.tangem.tap.scope +import com.tangem.tap.store +import com.tangem.tap.userWalletsListManager import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.rekotlin.Action @@ -74,8 +77,8 @@ private fun handleHomeAction(action: Action) { private fun readCard(analyticsEvent: AnalyticsEvent?) = scope.launch { delay(timeMillis = 200) - tangemSdkManager.setAccessCodeRequestPolicy( - useBiometricsForAccessCode = preferencesStorage.shouldSaveAccessCodes, + store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy( + isBiometricsRequestPolicy = preferencesStorage.shouldSaveAccessCodes, ) store.state.daggerGraphState.get(DaggerGraphState::scanCardProcessor).scan( 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 67921cce64..fe5800266a 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 @@ -30,9 +30,9 @@ import com.tangem.tap.features.onboarding.OnboardingDialog import com.tangem.tap.features.onboarding.OnboardingHelper import com.tangem.tap.features.wallet.models.toCurrencies import com.tangem.tap.features.wallet.redux.Artwork +import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.launch import org.rekotlin.Action -import org.rekotlin.DispatchFunction import org.rekotlin.Middleware object OnboardingWalletMiddleware { @@ -43,8 +43,8 @@ private val onboardingWalletMiddleware: Middleware = { dispatch, state { next -> { action -> when (action) { - is OnboardingWallet2Action -> handleWallet2Action(action, state) - else -> handleWalletAction(action, state, dispatch) + is OnboardingWallet2Action -> handleWallet2Action(action) + else -> handleWalletAction(action) } next(action) } @@ -52,7 +52,7 @@ private val onboardingWalletMiddleware: Middleware = { dispatch, state } @Suppress("LongMethod", "ComplexMethod") -private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: DispatchFunction) { +private fun handleWalletAction(action: Action) { if (action !is OnboardingWalletAction) return val globalState = store.state.globalState @@ -178,7 +178,7 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: } @Suppress("LongMethod", "ComplexMethod") -private fun handleWallet2Action(action: OnboardingWallet2Action, state: () -> AppState?) { +private fun handleWallet2Action(action: OnboardingWallet2Action) { val globalState = store.state.globalState val onboardingManager = globalState.onboardingState.onboardingManager @@ -329,7 +329,9 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) is BackupAction.AddBackupCard -> { backupService.addBackupCard { result -> backupService.skipCompatibilityChecks = false - tangemSdk.config.filter.cardIdFilter = null + store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository).sdk + .config.filter.cardIdFilter = null + when (result) { is CompletionResult.Success -> { store.dispatchOnMain(BackupAction.AddBackupCard.Success) 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 945fc90afd..370e759dff 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 @@ -22,6 +22,7 @@ import com.tangem.tap.domain.model.builders.UserWalletBuilder import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation import com.tangem.tap.domain.userWalletList.isLockable import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.launch import org.rekotlin.Middleware import timber.log.Timber @@ -110,9 +111,10 @@ internal class SaveWalletMiddleware { // Enable saving access codes only if this is the first time user save the wallet if (isFirstSavedWallet) { preferencesStorage.shouldSaveAccessCodes = true - tangemSdkManager.setAccessCodeRequestPolicy( - useBiometricsForAccessCode = userWallet.hasAccessCode, - ) + store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository) + .setAccessCodeRequestPolicy( + isBiometricsRequestPolicy = userWallet.hasAccessCode, + ) } val savedUserWallet = userWalletsListManager.selectedUserWalletSync.guard { diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt index 69891195d6..a76724c7c3 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt @@ -7,7 +7,6 @@ import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider import com.tangem.blockchain.blockchains.stellar.StellarTransactionExtras import com.tangem.blockchain.blockchains.ton.TonTransactionExtras import com.tangem.blockchain.blockchains.xrp.XrpTransactionBuilder.XrpTransactionExtras -import com.tangem.core.navigation.NavigationAction import com.tangem.blockchain.common.* import com.tangem.blockchain.common.transaction.Fee import com.tangem.blockchain.extensions.SimpleResult @@ -15,6 +14,7 @@ import com.tangem.common.core.TangemSdkError import com.tangem.common.extensions.guard import com.tangem.common.services.Result import com.tangem.core.analytics.Analytics +import com.tangem.core.navigation.NavigationAction import com.tangem.domain.common.TapWorkarounds.isStart2Coin import com.tangem.domain.common.extensions.withMainContext import com.tangem.domain.models.scan.CardDTO @@ -39,6 +39,7 @@ import com.tangem.tap.features.send.redux.FeeAction.RequestFee import com.tangem.tap.features.send.redux.states.* import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay @@ -201,6 +202,7 @@ private fun sendTransaction( return@launch } + val tangemSdk = store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository).sdk val linkedTerminalState = tangemSdk.config.linkedTerminal if (card.isStart2Coin) { tangemSdk.config.linkedTerminal = false diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt index fbb76f391a..65be537ac8 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt @@ -72,7 +72,7 @@ class TradeCryptoMiddleware { } scope.launch { - exchangeManager.buyErc20TestnetTokens( + buyErc20TestnetTokens( card = card, walletManager = walletManager, token = currency.token, 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 148e95d323..a331a52719 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 @@ -126,11 +126,13 @@ internal class WalletSelectorMiddleware { private fun addWallet() = scope.launch { Analytics.send(MyWallets.Button.ScanNewCard()) - val prevUseBiometricsForAccessCode = tangemSdkManager.useBiometricsForAccessCode() + val cardSdkConfigRepository = store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository) + + val prevUseBiometricsForAccessCode = cardSdkConfigRepository.isBiometricsRequestPolicy() // Update access code policy for access code saving when a card was scanned - tangemSdkManager.setAccessCodeRequestPolicy( - useBiometricsForAccessCode = preferencesStorage.shouldSaveAccessCodes, + cardSdkConfigRepository.setAccessCodeRequestPolicy( + isBiometricsRequestPolicy = preferencesStorage.shouldSaveAccessCodes, ) store.state.daggerGraphState.get(DaggerGraphState::scanCardProcessor).scan( @@ -147,14 +149,14 @@ internal class WalletSelectorMiddleware { saveUserWalletAndPopBackToWalletScreen(scanResponse) .doOnFailure { error -> // Rollback policy if card saving was failed - tangemSdkManager.setAccessCodeRequestPolicy(prevUseBiometricsForAccessCode) + cardSdkConfigRepository.setAccessCodeRequestPolicy(prevUseBiometricsForAccessCode) Timber.e(error, "Unable to save user wallet") store.dispatchOnMain(WalletSelectorAction.AddWallet.Error(error)) } }, onFailure = { error -> // Rollback policy if card scanning was failed - tangemSdkManager.setAccessCodeRequestPolicy(prevUseBiometricsForAccessCode) + cardSdkConfigRepository.setAccessCodeRequestPolicy(prevUseBiometricsForAccessCode) Timber.e(error, "Unable to scan card") store.dispatchOnMain(WalletSelectorAction.AddWallet.Error(error)) }, 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 7fab7c2a4f..c10e1bcad2 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 @@ -100,8 +100,8 @@ internal class WelcomeMiddleware { } private suspend inline fun scanCardInternal(crossinline onCardScanned: suspend (ScanResponse) -> Unit) { - tangemSdkManager.setAccessCodeRequestPolicy( - useBiometricsForAccessCode = preferencesStorage.shouldSaveAccessCodes, + store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy( + isBiometricsRequestPolicy = preferencesStorage.shouldSaveAccessCodes, ) store.state.daggerGraphState.get(DaggerGraphState::scanCardProcessor).scan( analyticsEvent = Basic.CardWasScanned(AnalyticsParam.ScannedFrom.SignIn), diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt index d886b5873f..ae3e244978 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt @@ -13,8 +13,8 @@ import com.tangem.tap.common.redux.global.CryptoCurrencyName import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.TangemSigner import com.tangem.tap.features.wallet.models.Currency +import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.store -import com.tangem.tap.tangemSdk import java.math.BigDecimal /** @@ -86,11 +86,7 @@ class CurrencyExchangeManager( } } -suspend fun CurrencyExchangeManager.buyErc20TestnetTokens( - card: CardDTO, - walletManager: EthereumWalletManager, - token: Token, -) { +suspend fun buyErc20TestnetTokens(card: CardDTO, walletManager: EthereumWalletManager, token: Token) { walletManager.safeUpdate() val amountToSend = Amount(walletManager.wallet.blockchain) @@ -109,7 +105,7 @@ suspend fun CurrencyExchangeManager.buyErc20TestnetTokens( val signer = TangemSigner( card = card, - tangemSdk = tangemSdk, + tangemSdk = store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository).sdk, initialMessage = Message(), ) { signResponse -> store.dispatch( diff --git a/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt b/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt index cf6015d446..7533a00f58 100644 --- a/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt +++ b/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt @@ -1,6 +1,5 @@ package com.tangem.tap.proxy -import com.tangem.TangemSdk import com.tangem.core.navigation.NavigationAction import com.tangem.core.navigation.NavigationStateHolder import com.tangem.domain.models.scan.CardDTO @@ -30,7 +29,6 @@ class AppStateHolder @Inject constructor() : WalletsStateHolder, NavigationState var userTokensRepository: UserTokensRepository? = null var mainStore: Store? = null var tangemSdkManager: TangemSdkManager? = null - var tangemSdk: TangemSdk? = null var walletStoresManager: WalletStoresManager? = null var appFiatCurrency: FiatCurrency = FiatCurrency.Default diff --git a/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt index fe86122123..7c3e6f8b1e 100644 --- a/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt @@ -14,6 +14,7 @@ import com.tangem.blockchain.extensions.isNetworkError import com.tangem.common.core.TangemSdkError import com.tangem.common.extensions.hexToBytes import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.common.BlockchainNetwork import com.tangem.domain.common.extensions.fromNetworkId import com.tangem.lib.crypto.TransactionManager @@ -24,7 +25,6 @@ import com.tangem.tap.common.analytics.events.Basic import com.tangem.tap.common.analytics.events.Basic.TransactionSent.MemoType import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.TangemSigner -import com.tangem.tap.tangemSdk import java.math.BigDecimal import java.math.BigInteger import java.math.MathContext @@ -34,6 +34,7 @@ import java.math.RoundingMode class TransactionManagerImpl( private val appStateHolder: AppStateHolder, private val analytics: AnalyticsEventHandler, + private val cardSdkConfigRepository: CardSdkConfigRepository, ) : TransactionManager { override suspend fun sendApproveTransaction( @@ -395,7 +396,7 @@ class TransactionManagerImpl( val actualCard = requireNotNull(appStateHolder.getActualCard()) { "no card found" } return TangemSigner( card = actualCard, - tangemSdk = tangemSdk, + tangemSdk = cardSdkConfigRepository.sdk, initialMessage = Message(), ) { signResponse -> appStateHolder.mainStore?.dispatch( diff --git a/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt b/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt index 371f1e21bf..cc2e04969d 100644 --- a/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt +++ b/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt @@ -2,6 +2,7 @@ package com.tangem.tap.proxy.di import androidx.compose.ui.text.intl.Locale import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.feature.learn2earn.domain.api.Learn2earnDependencyProvider import com.tangem.lib.crypto.DerivationManager import com.tangem.lib.crypto.TransactionManager @@ -39,8 +40,13 @@ class ProxyModule { fun provideTransactionManager( appStateHolder: AppStateHolder, analytics: AnalyticsEventHandler, + cardSdkConfigRepository: CardSdkConfigRepository, ): TransactionManager { - return TransactionManagerImpl(appStateHolder, analytics) + return TransactionManagerImpl( + appStateHolder = appStateHolder, + analytics = analytics, + cardSdkConfigRepository = cardSdkConfigRepository, + ) } @Provides diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt index e83ed33f3a..1b0f19c9fe 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt @@ -1,6 +1,7 @@ package com.tangem.tap.proxy.redux import com.tangem.domain.card.ScanCardUseCase +import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.features.tester.api.TesterRouter import com.tangem.features.tokendetails.navigation.TokenDetailsRouter import com.tangem.features.wallet.navigation.WalletRouter @@ -15,5 +16,6 @@ sealed interface DaggerGraphAction : Action { val walletRouter: WalletRouter, val walletConnectInteractor: WalletConnectInteractor, val tokenDetailsRouter: TokenDetailsRouter, + val cardSdkConfigRepository: CardSdkConfigRepository, ) : DaggerGraphAction } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt index bdd590be4d..aec162a122 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt @@ -18,6 +18,7 @@ object DaggerGraphReducer { walletRouter = action.walletRouter, walletConnectInteractor = action.walletConnectInteractor, tokenDetailsRouter = action.tokenDetailsRouter, + cardSdkConfigRepository = action.cardSdkConfigRepository, ) } } 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 7bdabd80a3..228d3f014b 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 @@ -4,6 +4,7 @@ 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.domain.card.repository.CardSdkConfigRepository import com.tangem.features.tester.api.TesterRouter import com.tangem.features.tokendetails.featuretoggles.TokenDetailsFeatureToggles import com.tangem.features.tokendetails.navigation.TokenDetailsRouter @@ -29,6 +30,7 @@ data class DaggerGraphState( val tokenDetailsFeatureToggles: TokenDetailsFeatureToggles? = null, val tokenDetailsRouter: TokenDetailsRouter? = null, val scanCardProcessor: ScanCardProcessor? = null, + val cardSdkConfigRepository: CardSdkConfigRepository? = null, ) : StateType { inline fun get(getDependency: DaggerGraphState.() -> T?): T { diff --git a/data/card/.gitignore b/data/card/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/data/card/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/data/card/build.gradle.kts b/data/card/build.gradle.kts new file mode 100644 index 0000000000..69bbb44e78 --- /dev/null +++ b/data/card/build.gradle.kts @@ -0,0 +1,21 @@ +plugins { + alias(deps.plugins.android.library) + alias(deps.plugins.kotlin.android) + alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.hilt.android) + id("configuration") +} + +android { + namespace = "com.tangem.data.card" +} + +dependencies { + implementation(deps.hilt.android) + kapt(deps.hilt.kapt) + implementation(deps.tangem.card.android) + implementation(deps.tangem.card.core) + + implementation(projects.domain.card) + implementation(projects.domain.models) +} \ No newline at end of file diff --git a/data/card/src/main/java/com/tangem/data/card/DefaultCardSdkConfigRepository.kt b/data/card/src/main/java/com/tangem/data/card/DefaultCardSdkConfigRepository.kt new file mode 100644 index 0000000000..e263616c2f --- /dev/null +++ b/data/card/src/main/java/com/tangem/data/card/DefaultCardSdkConfigRepository.kt @@ -0,0 +1,53 @@ +package com.tangem.data.card + +import com.tangem.TangemSdk +import com.tangem.common.UserCodeType +import com.tangem.common.core.CardIdDisplayFormat +import com.tangem.common.core.UserCodeRequestPolicy +import com.tangem.data.card.sdk.CardSdkProvider +import com.tangem.domain.card.repository.CardSdkConfigRepository +import com.tangem.domain.models.scan.ProductType + +/** + * Implementation of repository for managing with CardSDK config + * + * @property cardSdkProvider CardSDK instance provider + * +[REDACTED_AUTHOR] + */ +internal class DefaultCardSdkConfigRepository( + private val cardSdkProvider: CardSdkProvider, +) : CardSdkConfigRepository { + + @Deprecated("Use CardSdkConfigRepository's methods instead of this property") + override val sdk: TangemSdk + get() = cardSdkProvider.sdk + + override fun setAccessCodeRequestPolicy(isBiometricsRequestPolicy: Boolean) { + sdk.config.userCodeRequestPolicy = if (isBiometricsRequestPolicy) { + UserCodeRequestPolicy.AlwaysWithBiometrics(codeType = UserCodeType.AccessCode) + } else { + UserCodeRequestPolicy.Default + } + } + + override fun isBiometricsRequestPolicy(): Boolean { + return with(sdk.config.userCodeRequestPolicy) { + this is UserCodeRequestPolicy.AlwaysWithBiometrics && codeType == UserCodeType.AccessCode + } + } + + override fun resetCardIdDisplayFormat() { + sdk.config.cardIdDisplayFormat = CardIdDisplayFormat.Full + } + + override fun updateCardIdDisplayFormat(productType: ProductType) { + sdk.config.cardIdDisplayFormat = when (productType) { + ProductType.Twins -> CardIdDisplayFormat.LastLuhn(numbers = 4) + ProductType.Note, + ProductType.Wallet, + ProductType.Start2Coin, + -> CardIdDisplayFormat.Full + } + } +} \ No newline at end of file diff --git a/data/card/src/main/java/com/tangem/data/card/di/CardDataModule.kt b/data/card/src/main/java/com/tangem/data/card/di/CardDataModule.kt new file mode 100644 index 0000000000..4ed7adf268 --- /dev/null +++ b/data/card/src/main/java/com/tangem/data/card/di/CardDataModule.kt @@ -0,0 +1,21 @@ +package com.tangem.data.card.di + +import com.tangem.data.card.DefaultCardSdkConfigRepository +import com.tangem.data.card.sdk.CardSdkProvider +import com.tangem.domain.card.repository.CardSdkConfigRepository +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 CardDataModule { + + @Provides + @Singleton + fun provideCardSdkConfigRepository(cardSdkProvider: CardSdkProvider): CardSdkConfigRepository { + return DefaultCardSdkConfigRepository(cardSdkProvider = cardSdkProvider) + } +} \ No newline at end of file diff --git a/data/card/src/main/java/com/tangem/data/card/di/CardSdkModule.kt b/data/card/src/main/java/com/tangem/data/card/di/CardSdkModule.kt new file mode 100644 index 0000000000..c88f2dbfc2 --- /dev/null +++ b/data/card/src/main/java/com/tangem/data/card/di/CardSdkModule.kt @@ -0,0 +1,23 @@ +package com.tangem.data.card.di + +import com.tangem.data.card.sdk.CardSdkLifecycleObserver +import com.tangem.data.card.sdk.CardSdkProvider +import com.tangem.data.card.sdk.DefaultCardSdkProvider +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal interface CardSdkModule { + + @Binds + @Singleton + fun provideCardSdkProvider(defaultCardSdkProvider: DefaultCardSdkProvider): CardSdkProvider + + @Binds + @Singleton + fun providerCardSdkLifecycleObserver(defaultCardSdkProvider: DefaultCardSdkProvider): CardSdkLifecycleObserver +} \ No newline at end of file diff --git a/data/card/src/main/java/com/tangem/data/card/sdk/CardSdkLifecycleObserver.kt b/data/card/src/main/java/com/tangem/data/card/sdk/CardSdkLifecycleObserver.kt new file mode 100644 index 0000000000..f5f6781392 --- /dev/null +++ b/data/card/src/main/java/com/tangem/data/card/sdk/CardSdkLifecycleObserver.kt @@ -0,0 +1,17 @@ +package com.tangem.data.card.sdk + +import android.content.Context + +/** + * Lifecycle observer for creating Card SDK instance + * +[REDACTED_AUTHOR] + */ +interface CardSdkLifecycleObserver { + + /** Callback of creating activity [context] */ + fun onCreate(context: Context) + + /** Callback of destroying activity */ + fun onDestroy() +} \ No newline at end of file diff --git a/data/card/src/main/java/com/tangem/data/card/sdk/CardSdkProvider.kt b/data/card/src/main/java/com/tangem/data/card/sdk/CardSdkProvider.kt new file mode 100644 index 0000000000..0d0b88fa41 --- /dev/null +++ b/data/card/src/main/java/com/tangem/data/card/sdk/CardSdkProvider.kt @@ -0,0 +1,14 @@ +package com.tangem.data.card.sdk + +import com.tangem.TangemSdk + +/** + * CardSDK instance provider + * +[REDACTED_AUTHOR] + */ +internal interface CardSdkProvider { + + /** CardSDK instance */ + val sdk: TangemSdk +} \ No newline at end of file diff --git a/data/card/src/main/java/com/tangem/data/card/sdk/DefaultCardSdkProvider.kt b/data/card/src/main/java/com/tangem/data/card/sdk/DefaultCardSdkProvider.kt new file mode 100644 index 0000000000..dddff7e3da --- /dev/null +++ b/data/card/src/main/java/com/tangem/data/card/sdk/DefaultCardSdkProvider.kt @@ -0,0 +1,45 @@ +package com.tangem.data.card.sdk + +import android.content.Context +import androidx.fragment.app.FragmentActivity +import com.tangem.TangemSdk +import com.tangem.common.CardFilter +import com.tangem.common.card.FirmwareVersion +import com.tangem.common.core.Config +import com.tangem.sdk.extensions.initWithBiometrics +import javax.inject.Inject +import javax.inject.Singleton + +/** + * Implementation of CardSDK instance provider + * +[REDACTED_AUTHOR] + */ +@Singleton +internal class DefaultCardSdkProvider @Inject constructor() : CardSdkProvider, CardSdkLifecycleObserver { + + override val sdk: TangemSdk + get() = requireNotNull(value = _sdk) { "Impossible to get the TangemSdk when activity is destroyed" } + + private var _sdk: TangemSdk? = null + + override fun onCreate(context: Context) { + _sdk = TangemSdk.initWithBiometrics(activity = context as FragmentActivity, config = config) + } + + override fun onDestroy() { + _sdk = null + } + + private companion object { + + val config = Config( + linkedTerminal = true, + allowUntrustedCards = true, + filter = CardFilter( + allowedCardTypes = FirmwareVersion.FirmwareType.values().toList(), + maxFirmwareVersion = FirmwareVersion(major = 4, minor = 52), + ), + ) + } +} \ No newline at end of file diff --git a/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardUseCase.kt b/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardUseCase.kt index 46312c439f..69dbc7a617 100644 --- a/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardUseCase.kt +++ b/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardUseCase.kt @@ -4,47 +4,46 @@ import arrow.core.Either import arrow.core.EitherNel import arrow.core.flatMap import com.tangem.TangemSdk -import com.tangem.common.core.CardIdDisplayFormat +import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.card.repository.ScanCardRepository import com.tangem.domain.core.chain.Chain import com.tangem.domain.core.chain.ChainProcessor -import com.tangem.domain.models.scan.ProductType import com.tangem.domain.models.scan.ScanResponse /** - * Use case responsible for scanning a card and returning a [ScanResponse] object. - * @property scanCardRepository A repository object implementing [ScanCardRepository] interface. - * @property tangemSdk An instance of [TangemSdk] to configure the display format of the card ID. - * @constructor Create a new instance of [ScanCardUseCase] with the given dependencies. + * Use case responsible for scanning a card and returning a [ScanResponse] object + * + * @property scanCardRepository a repository object implementing [ScanCardRepository] interface + * @property cardSdkConfigRepository an instance of [TangemSdk] to configure the display format of the card ID + * + * @constructor create a new instance of [ScanCardUseCase] with the given dependencies */ class ScanCardUseCase( private val scanCardRepository: ScanCardRepository, - private val tangemSdk: TangemSdk, + private val cardSdkConfigRepository: CardSdkConfigRepository, ) { - /** - * A [ChainProcessor] object to launch the after-scan chains. - */ + /** A [ChainProcessor] object to launch the after-scan chains */ private val scanChainProcessor by lazy { ChainProcessor() } /** * Scan a card and return a [ScanResponse] object. - * @param cardId an optional card ID to scan. If null, can scan any card present. - * Defaults to null. - * @param allowRequestAccessCodeFromStorage whether to prompt the user for an access code if needed. - * Defaults to false. - * @param afterScanChains A list of chains that should be executed after a successful card scan operation. - * Defaults to an empty array. - * @return A [EitherNel] object with either a non-empty list of [ScanCardException] or a [ScanResponse]. + * + * @param cardId an optional card ID to scan. If null, can scan any card present + * @param allowRequestAccessCodeFromStorage whether to prompt the user for an access code if needed + * @param afterScanChains a list of chains that should be executed after a successful card scan + * operation. Defaults to an empty array + * + * @return a [EitherNel] object with either a non-empty list of [ScanCardException] or a [ScanResponse] */ suspend operator fun invoke( cardId: String? = null, allowRequestAccessCodeFromStorage: Boolean = false, afterScanChains: List> = emptyList(), ): Either { - resetCardIdDisplayFormat() + cardSdkConfigRepository.resetCardIdDisplayFormat() scanChainProcessor.addChains(afterScanChains) return scanCardRepository.scanCard( @@ -52,31 +51,10 @@ class ScanCardUseCase( allowRequestAccessCodeFromStorage = allowRequestAccessCodeFromStorage, ) .onRight { scanResponse -> - updateCardIdDisplayFormat(scanResponse.productType) + cardSdkConfigRepository.updateCardIdDisplayFormat(scanResponse.productType) } .flatMap { response -> scanChainProcessor.launchChains(initial = response) } } - - /** - * Reset the card ID display format to [CardIdDisplayFormat.Full]. - */ - private fun resetCardIdDisplayFormat() { - tangemSdk.config.cardIdDisplayFormat = CardIdDisplayFormat.Full - } - - /** - * Update the card ID display format according to the [ProductType] of the scanned card. - * @param productType The [ProductType] of the scanned card. - */ - private fun updateCardIdDisplayFormat(productType: ProductType) { - tangemSdk.config.cardIdDisplayFormat = when (productType) { - ProductType.Twins -> CardIdDisplayFormat.LastLuhn(numbers = 4) - ProductType.Note, - ProductType.Wallet, - ProductType.Start2Coin, - -> CardIdDisplayFormat.Full - } - } } \ No newline at end of file diff --git a/domain/card/src/main/kotlin/com/tangem/domain/card/repository/CardSdkConfigRepository.kt b/domain/card/src/main/kotlin/com/tangem/domain/card/repository/CardSdkConfigRepository.kt new file mode 100644 index 0000000000..11fa7e26e1 --- /dev/null +++ b/domain/card/src/main/kotlin/com/tangem/domain/card/repository/CardSdkConfigRepository.kt @@ -0,0 +1,28 @@ +package com.tangem.domain.card.repository + +import com.tangem.TangemSdk +import com.tangem.domain.models.scan.ProductType + +/** + * Repository for managing with CardSDK config + * +[REDACTED_AUTHOR] + */ +interface CardSdkConfigRepository { + + /** Tangem SDK instance */ + @Deprecated("Use CardSdkConfigRepository's methods instead of this property") + val sdk: TangemSdk + + /** Set access code request policy by [isBiometricsRequestPolicy] */ + fun setAccessCodeRequestPolicy(isBiometricsRequestPolicy: Boolean) + + /** Check if config has biometrics request policy */ + fun isBiometricsRequestPolicy(): Boolean + + /** Reset the card ID display format to start value */ + fun resetCardIdDisplayFormat() + + /** Update the card ID display format according to the [productType] of the scanned card */ + fun updateCardIdDisplayFormat(productType: ProductType) +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 423368f3d8..4cd9f9833e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -85,6 +85,7 @@ include(":domain:tokens") // endregion Domain modules // region Data modules +include(":data:card") include(":data:tokens") include(":data:source:preferences") // endregion Data modules \ No newline at end of file