Updated on 2026-08-14
This commit is contained in:
parent
40a5e13ad4
commit
f8268dbe6e
20 changed files with 126 additions and 125 deletions
|
|
@ -8,6 +8,7 @@ import com.tangem.common.core.TangemSdkError
|
|||
import com.tangem.common.extensions.clickAndWaitFor
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.domain.card.ScanFailsRequester
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.launch
|
||||
import com.tangem.scenarios.checkFailedTransactionDialog
|
||||
|
|
@ -28,16 +29,19 @@ import com.tangem.screens.onStoriesScreen
|
|||
import com.tangem.screens.onTokenDetailsScreen
|
||||
import com.tangem.screens.onMainScreenTopBar
|
||||
import com.tangem.tap.domain.sdk.mocks.MockProvider
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltAndroidTest
|
||||
class FeedbackTest : BaseTestCase() {
|
||||
|
||||
@Inject
|
||||
lateinit var scanFailsRequester: ScanFailsRequester
|
||||
|
||||
@AllureId("894")
|
||||
@DisplayName("Send feedback: from details")
|
||||
@Test
|
||||
|
|
@ -177,9 +181,8 @@ class FeedbackTest : BaseTestCase() {
|
|||
}
|
||||
step("Force show 'Scan warning' dialog"){
|
||||
runOnUiThread {
|
||||
val requester = store.state.daggerGraphState.scanFailsRequester!!
|
||||
MainScope().launch {
|
||||
requester.show(AnalyticsParam.ScreensSources.Main)
|
||||
scanFailsRequester.show(AnalyticsParam.ScreensSources.Main)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@ import androidx.lifecycle.LifecycleOwner
|
|||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.WorkManager
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.wallets.hot.HotWalletPasswordRequester
|
||||
import com.tangem.domain.wallets.usecase.ClearAllHotWalletContextualUnlockUseCase
|
||||
import com.tangem.tap.LockTimerWorker.Companion.TAG
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
|
|
@ -30,6 +30,7 @@ internal class LockUserWalletsTimer(
|
|||
private val coroutineScope: CoroutineScope,
|
||||
private val clearAllHotWalletContextualUnlockUseCase: ClearAllHotWalletContextualUnlockUseCase,
|
||||
private val passwordRequester: HotWalletPasswordRequester,
|
||||
private val appRouter: AppRouter,
|
||||
) : LifecycleOwner by context as LifecycleOwner,
|
||||
DefaultLifecycleObserver {
|
||||
|
||||
|
|
@ -57,7 +58,7 @@ internal class LockUserWalletsTimer(
|
|||
if (shouldOpenWelcomeScreenOnResume) {
|
||||
passwordRequester.dismiss()
|
||||
clearAllHotWalletContextualUnlockUseCase.invoke()
|
||||
store.dispatchNavigationAction { replaceAll(AppRoute.Welcome()) }
|
||||
appRouter.replaceAll(AppRoute.Welcome())
|
||||
settingsRepository.setShouldOpenWelcomeScreenOnResume(value = false)
|
||||
}
|
||||
}
|
||||
|
|
@ -121,7 +122,7 @@ internal class LockUserWalletsTimer(
|
|||
.onRight {
|
||||
passwordRequester.dismiss()
|
||||
clearAllHotWalletContextualUnlockUseCase.invoke()
|
||||
store.dispatchNavigationAction { replaceAll(AppRoute.Welcome()) }
|
||||
appRouter.replaceAll(AppRoute.Welcome())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
|||
import androidx.lifecycle.flowWithLifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.routing.deeplink.DeeplinkConst.WEBLINK_KEY
|
||||
import com.tangem.common.routing.deeplink.PayloadToDeeplinkConverter
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
|
|
@ -39,7 +40,6 @@ import com.tangem.core.navigation.url.UrlOpener
|
|||
import com.tangem.data.balancehiding.DefaultDeviceFlipDetector
|
||||
import com.tangem.data.card.sdk.CardSdkOwner
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
import com.tangem.domain.card.ScanCardUseCase
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
|
|
@ -61,7 +61,6 @@ import com.tangem.tap.common.analytics.events.Push
|
|||
import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder
|
||||
import com.tangem.tap.features.intentHandler.handlers.BackgroundScanIntentHandler
|
||||
import com.tangem.tap.features.main.MainViewModel
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphAction
|
||||
import com.tangem.tap.routing.component.RoutingComponent
|
||||
import com.tangem.tap.routing.configurator.AppRouterConfig
|
||||
import com.tangem.tap.routing.utils.DeepLinkFactory
|
||||
|
|
@ -104,9 +103,6 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
@Inject
|
||||
lateinit var injectedTangemSdkManager: TangemSdkManager
|
||||
|
||||
@Inject
|
||||
lateinit var scanCardUseCase: ScanCardUseCase
|
||||
|
||||
@Inject
|
||||
lateinit var settingsRepository: SettingsRepository
|
||||
|
||||
|
|
@ -123,6 +119,9 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
@Inject
|
||||
internal lateinit var appRouterConfig: AppRouterConfig
|
||||
|
||||
@Inject
|
||||
internal lateinit var appRouter: AppRouter
|
||||
|
||||
@Inject
|
||||
internal lateinit var routingComponentFactory: RoutingComponent.Factory
|
||||
|
||||
|
|
@ -269,13 +268,7 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
userWalletsListRepository = userWalletsListRepository,
|
||||
clearAllHotWalletContextualUnlockUseCase = clearAllHotWalletContextualUnlockUseCase,
|
||||
passwordRequester = passwordRequester,
|
||||
)
|
||||
|
||||
store.dispatch(
|
||||
DaggerGraphAction.SetActivityDependencies(
|
||||
scanCardUseCase = scanCardUseCase,
|
||||
cardSdkConfigRepository = cardSdkConfigRepository,
|
||||
),
|
||||
appRouter = appRouter,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,8 @@ import org.rekotlin.Store
|
|||
|
||||
lateinit var store: Store<AppState>
|
||||
|
||||
lateinit var walletsRepository: WalletsRepository
|
||||
|
||||
val foregroundActivityObserver = ForegroundActivityObserver
|
||||
|
||||
open class TangemApplication : Application(), ImageLoaderFactory, Configuration.Provider {
|
||||
|
|
@ -129,9 +131,6 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
|
|||
val getAppThemeModeUseCase: GetAppThemeModeUseCase
|
||||
get() = entryPoint.getGetAppThemeModeUseCase()
|
||||
|
||||
private val walletsRepository: WalletsRepository
|
||||
get() = entryPoint.getWalletsRepository()
|
||||
|
||||
private val oneTimeEventFilter: OneTimeEventFilter
|
||||
get() = entryPoint.getOneTimeEventFilter()
|
||||
|
||||
|
|
@ -276,6 +275,8 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
|
|||
}
|
||||
|
||||
fun init() {
|
||||
walletsRepository = entryPoint.getWalletsRepository()
|
||||
|
||||
apiConfigsManager.initialize()
|
||||
|
||||
store = createReduxStore()
|
||||
|
|
|
|||
|
|
@ -10,10 +10,8 @@ import com.tangem.domain.card.common.util.cardTypesResolver
|
|||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.walletsRepository
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
/**
|
||||
|
|
@ -23,8 +21,6 @@ class CardContextInterceptor(
|
|||
private val scanResponse: ScanResponse,
|
||||
) : ParamsInterceptor {
|
||||
|
||||
private val walletsRepository = store.inject(DaggerGraphState::walletsRepository)
|
||||
|
||||
private val userWalletId = UserWalletIdBuilder.scanResponse(scanResponse).build()
|
||||
|
||||
override fun id(): String = CardContextInterceptor.id()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.tap.di
|
|||
import android.content.Context
|
||||
import com.tangem.core.analytics.api.AnalyticsErrorHandler
|
||||
import com.tangem.domain.card.BuildConfig
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.dynamicaddresses.DynamicAddressesFeatureToggles
|
||||
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
|
||||
|
|
@ -36,6 +37,7 @@ internal class TangemSdkManagerModule {
|
|||
dynamicAddressesFeatureToggles: DynamicAddressesFeatureToggles,
|
||||
blockchainToDeriveFinder: BlockchainToDeriveFinder,
|
||||
analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
cardRepository: CardRepository,
|
||||
): TangemSdkManager {
|
||||
return if (BuildConfig.MOCK_DATA_SOURCE) {
|
||||
MockTangemSdkManager(resources = context.resources)
|
||||
|
|
@ -50,6 +52,7 @@ internal class TangemSdkManagerModule {
|
|||
dynamicAddressesFeatureToggles = dynamicAddressesFeatureToggles,
|
||||
blockchainToDeriveFinder = blockchainToDeriveFinder,
|
||||
analyticsErrorHandler = analyticsErrorHandler,
|
||||
cardRepository = cardRepository,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
|
|||
import com.tangem.tap.domain.scanCard.CardScanningFeatureToggles
|
||||
import com.tangem.tap.domain.scanCard.DefaultScanCardProcessor
|
||||
import com.tangem.tap.domain.scanCard.LegacyScanProcessor
|
||||
import com.tangem.tap.domain.scanCard.UseCaseScanProcessor
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -25,8 +26,16 @@ internal object CardLegacyDomainModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideScanCardProcessor(legacyScanProcessor: LegacyScanProcessor): ScanCardProcessor {
|
||||
return DefaultScanCardProcessor(legacyScanProcessor = legacyScanProcessor)
|
||||
fun provideScanCardProcessor(
|
||||
legacyScanProcessor: LegacyScanProcessor,
|
||||
useCaseScanProcessor: UseCaseScanProcessor,
|
||||
cardScanningFeatureToggles: CardScanningFeatureToggles,
|
||||
): ScanCardProcessor {
|
||||
return DefaultScanCardProcessor(
|
||||
legacyScanProcessor = legacyScanProcessor,
|
||||
useCaseScanProcessor = useCaseScanProcessor,
|
||||
cardScanningFeatureToggles = cardScanningFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -5,16 +5,15 @@ import com.tangem.common.core.TangemError
|
|||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.domain.card.ScanCardProcessor
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
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 class DefaultScanCardProcessor(
|
||||
private val legacyScanProcessor: LegacyScanProcessor,
|
||||
private val useCaseScanProcessor: UseCaseScanProcessor,
|
||||
private val cardScanningFeatureToggles: CardScanningFeatureToggles,
|
||||
) : ScanCardProcessor {
|
||||
private val isNewCardScanningEnabled: Boolean
|
||||
get() = store.inject(DaggerGraphState::cardScanningFeatureToggles).isNewCardScanningEnabled
|
||||
get() = cardScanningFeatureToggles.isNewCardScanningEnabled
|
||||
|
||||
override suspend fun scan(
|
||||
cardId: String?,
|
||||
|
|
@ -23,7 +22,7 @@ internal class DefaultScanCardProcessor(
|
|||
shouldCheckIsAlreadyActivated: Boolean,
|
||||
): CompletionResult<ScanResponse> {
|
||||
return if (isNewCardScanningEnabled) {
|
||||
UseCaseScanProcessor.scan(cardId, allowsRequestAccessCodeFromRepository)
|
||||
useCaseScanProcessor.scan(cardId, allowsRequestAccessCodeFromRepository)
|
||||
} else {
|
||||
legacyScanProcessor.scan(
|
||||
analyticsSource = analyticsSource,
|
||||
|
|
@ -47,7 +46,7 @@ internal class DefaultScanCardProcessor(
|
|||
onSuccess: suspend (scanResponse: ScanResponse) -> Unit,
|
||||
) {
|
||||
if (isNewCardScanningEnabled) {
|
||||
UseCaseScanProcessor.scan(
|
||||
useCaseScanProcessor.scan(
|
||||
analyticsSource = analyticsSource,
|
||||
cardId = cardId,
|
||||
onProgressStateChange = onProgressStateChange,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.common.core.TangemSdkError
|
|||
import com.tangem.common.doOnFailure
|
||||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
|
@ -21,19 +22,18 @@ import com.tangem.core.ui.extensions.toWrappedList
|
|||
import com.tangem.core.ui.message.dialog.Dialogs
|
||||
import com.tangem.domain.card.ScanFailsCounter
|
||||
import com.tangem.domain.card.common.util.twinsIsTwinned
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase
|
||||
import com.tangem.sdk.extensions.localizedDescriptionRes
|
||||
import com.tangem.tap.common.analytics.paramsInterceptor.CardContextInterceptor
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.features.disclaimer.createDisclaimer
|
||||
import com.tangem.tap.features.onboarding.OnboardingHelper
|
||||
import com.tangem.tap.mainScope
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -44,11 +44,17 @@ import javax.inject.Inject
|
|||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Suppress("LongParameterList")
|
||||
internal class LegacyScanProcessor @Inject constructor(
|
||||
@GlobalUiMessageSender private val uiMessageSender: UiMessageSender,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val trackingContextProxy: TrackingContextProxy,
|
||||
private val scanFailsCounter: ScanFailsCounter,
|
||||
private val appRouter: AppRouter,
|
||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||
private val wasTwinsOnboardingShownUseCase: WasTwinsOnboardingShownUseCase,
|
||||
private val cardRepository: CardRepository,
|
||||
private val onboardingHelper: OnboardingHelper,
|
||||
) {
|
||||
|
||||
suspend fun scan(
|
||||
|
|
@ -146,7 +152,7 @@ internal class LegacyScanProcessor @Inject constructor(
|
|||
crossinline disclaimerWillShow: () -> Unit = {},
|
||||
crossinline nextHandler: suspend (ScanResponse) -> Unit,
|
||||
) {
|
||||
val disclaimer = scanResponse.card.createDisclaimer()
|
||||
val disclaimer = scanResponse.card.createDisclaimer(cardRepository)
|
||||
|
||||
if (disclaimer.isAccepted()) {
|
||||
nextHandler(scanResponse)
|
||||
|
|
@ -157,9 +163,7 @@ internal class LegacyScanProcessor @Inject constructor(
|
|||
withContext(Dispatchers.Main.immediate) {
|
||||
disclaimerWillShow()
|
||||
|
||||
store.dispatchNavigationAction {
|
||||
push(AppRoute.Disclaimer(isTosAccepted = false))
|
||||
}
|
||||
appRouter.push(AppRoute.Disclaimer(isTosAccepted = false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -189,7 +193,7 @@ internal class LegacyScanProcessor @Inject constructor(
|
|||
mainScope.launch {
|
||||
onCancel()
|
||||
|
||||
store.inject(DaggerGraphState::sendFeedbackEmailUseCase).invoke(
|
||||
sendFeedbackEmailUseCase.invoke(
|
||||
type = FeedbackEmailType.CardAttestationFailed,
|
||||
)
|
||||
}
|
||||
|
|
@ -209,7 +213,7 @@ internal class LegacyScanProcessor @Inject constructor(
|
|||
crossinline onWalletNotCreated: suspend () -> Unit,
|
||||
crossinline onSuccess: suspend (ScanResponse) -> Unit,
|
||||
) {
|
||||
if (OnboardingHelper.isOnboardingCase(scanResponse)) {
|
||||
if (onboardingHelper.isOnboardingCase(scanResponse)) {
|
||||
trackingContextProxy.addContext(scanResponse)
|
||||
onWalletNotCreated()
|
||||
navigateTo(
|
||||
|
|
@ -221,8 +225,7 @@ internal class LegacyScanProcessor @Inject constructor(
|
|||
} else {
|
||||
trackingContextProxy.setContext(scanResponse)
|
||||
|
||||
val wasTwinsOnboardingShown =
|
||||
store.inject(DaggerGraphState::wasTwinsOnboardingShownUseCase).invokeSync()
|
||||
val wasTwinsOnboardingShown = wasTwinsOnboardingShownUseCase.invokeSync()
|
||||
|
||||
if (scanResponse.twinsIsTwinned() && !wasTwinsOnboardingShown) {
|
||||
onWalletNotCreated()
|
||||
|
|
@ -241,7 +244,7 @@ internal class LegacyScanProcessor @Inject constructor(
|
|||
|
||||
private suspend inline fun navigateTo(route: AppRoute, onProgressStateChange: (showProgress: Boolean) -> Unit) {
|
||||
delay(DELAY_SDK_DIALOG_CLOSE)
|
||||
store.dispatchNavigationAction { push(route) }
|
||||
appRouter.push(route)
|
||||
onProgressStateChange(false)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,33 +4,46 @@ import arrow.fx.coroutines.resourceScope
|
|||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.core.analytics.models.ExceptionAnalyticsEvent
|
||||
import com.tangem.core.analytics.utils.TrackingContextProxy
|
||||
import com.tangem.domain.card.ScanCardException
|
||||
import com.tangem.domain.card.ScanCardUseCase
|
||||
import com.tangem.domain.card.ScanFailsRequester
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase
|
||||
import com.tangem.tap.common.analytics.events.TangemSdkErrorEvent
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.domain.scanCard.chains.*
|
||||
import com.tangem.tap.domain.scanCard.utils.ScanCardExceptionConverter
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.features.onboarding.OnboardingHelper
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
internal object UseCaseScanProcessor {
|
||||
@Singleton
|
||||
@Suppress("LongParameterList")
|
||||
internal class UseCaseScanProcessor @Inject constructor(
|
||||
private val scanCardUseCase: ScanCardUseCase,
|
||||
private val scanFailsRequester: ScanFailsRequester,
|
||||
private val appRouter: AppRouter,
|
||||
private val trackingContextProxy: TrackingContextProxy,
|
||||
private val wasTwinsOnboardingShownUseCase: WasTwinsOnboardingShownUseCase,
|
||||
private val cardRepository: CardRepository,
|
||||
private val onboardingHelper: OnboardingHelper,
|
||||
) {
|
||||
private val scanCardExceptionConverter = ScanCardExceptionConverter()
|
||||
|
||||
suspend fun scan(
|
||||
cardId: String? = null,
|
||||
allowsRequestAccessCodeFromRepository: Boolean = false,
|
||||
): CompletionResult<ScanResponse> {
|
||||
val scanCardUseCase = store.inject(DaggerGraphState::scanCardUseCase)
|
||||
|
||||
return scanCardUseCase(cardId, allowsRequestAccessCodeFromRepository)
|
||||
.fold(
|
||||
ifLeft = { scanCardException ->
|
||||
|
|
@ -53,7 +66,6 @@ internal object UseCaseScanProcessor {
|
|||
onFailure: suspend (error: TangemError) -> Unit,
|
||||
onSuccess: suspend (scanResponse: ScanResponse) -> Unit,
|
||||
) = progressScope(onProgressStateChange) {
|
||||
val scanCardUseCase = store.inject(DaggerGraphState::scanCardUseCase)
|
||||
val chains = buildList {
|
||||
add(
|
||||
FailedScansCounterChain(
|
||||
|
|
@ -61,8 +73,8 @@ internal object UseCaseScanProcessor {
|
|||
),
|
||||
)
|
||||
add(AnalyticsChain(Basic.CardWasScanned(analyticsSource)))
|
||||
add(DisclaimerChain(store, disclaimerWillShow))
|
||||
add(CheckForOnboardingChain(store))
|
||||
add(DisclaimerChain(appRouter, cardRepository, disclaimerWillShow))
|
||||
add(CheckForOnboardingChain(trackingContextProxy, wasTwinsOnboardingShownUseCase, onboardingHelper))
|
||||
}
|
||||
|
||||
scanCardUseCase(cardId, afterScanChains = chains).fold(
|
||||
|
|
@ -73,7 +85,7 @@ internal object UseCaseScanProcessor {
|
|||
|
||||
private fun showScanFailsDialog(source: AnalyticsParam.ScreensSources) {
|
||||
scope.launch {
|
||||
store.inject(DaggerGraphState::scanFailsRequester).show(source)
|
||||
scanFailsRequester.show(source)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -86,7 +98,6 @@ internal object UseCaseScanProcessor {
|
|||
is ScanCardException.ChainException -> proceedWithScanChainException(
|
||||
exception,
|
||||
onWalletNotCreated,
|
||||
onFailure,
|
||||
)
|
||||
is ScanCardException.UnknownException,
|
||||
is ScanCardException.UserCancelled,
|
||||
|
|
@ -109,16 +120,12 @@ internal object UseCaseScanProcessor {
|
|||
private suspend fun proceedWithScanChainException(
|
||||
exception: ScanCardException.ChainException,
|
||||
onWalletNotCreated: suspend () -> Unit,
|
||||
onFailure: suspend (error: TangemError) -> Unit,
|
||||
) {
|
||||
when (exception) {
|
||||
is ScanChainException.OnboardingNeeded -> {
|
||||
navigateTo(exception.onboardingRoute)
|
||||
onWalletNotCreated()
|
||||
}
|
||||
is ScanChainException.DisclaimerWasCanceled -> {
|
||||
onFailure(scanCardExceptionConverter.convertBack(exception))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -136,6 +143,6 @@ internal object UseCaseScanProcessor {
|
|||
|
||||
private suspend inline fun navigateTo(route: AppRoute) {
|
||||
delay(DELAY_SDK_DIALOG_CLOSE)
|
||||
store.dispatchNavigationAction { push(route) }
|
||||
appRouter.push(route)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,18 +3,16 @@ package com.tangem.tap.domain.scanCard.chains
|
|||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.utils.TrackingContextProxy
|
||||
import com.tangem.domain.card.ScanCardException
|
||||
import com.tangem.domain.card.common.util.twinsIsTwinned
|
||||
import com.tangem.domain.core.chain.Chain
|
||||
import com.tangem.domain.core.chain.ResultChain
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase
|
||||
import com.tangem.tap.features.onboarding.OnboardingHelper
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
|
||||
import kotlinx.coroutines.delay
|
||||
import org.rekotlin.Store
|
||||
|
||||
/**
|
||||
* Handles the verification process to determine if the scanned card requires onboarding.
|
||||
|
|
@ -22,19 +20,17 @@ import org.rekotlin.Store
|
|||
* Returns:
|
||||
* - [ScanChainException.OnboardingNeeded] if onboarding required.
|
||||
*
|
||||
* @param store the [Store] that holds the state of the app.
|
||||
*
|
||||
* @see Chain for more information about the Chain interface.
|
||||
*/
|
||||
class CheckForOnboardingChain(
|
||||
private val store: Store<AppState>,
|
||||
private val trackingContextProxy: TrackingContextProxy,
|
||||
private val wasTwinsOnboardingShownUseCase: WasTwinsOnboardingShownUseCase,
|
||||
private val onboardingHelper: OnboardingHelper,
|
||||
) : ResultChain<ScanCardException, ScanResponse>() {
|
||||
|
||||
override suspend fun launch(previousChainResult: ScanResponse): ScanChainResult {
|
||||
val trackingContextProxy = store.inject(DaggerGraphState::trackingContextProxy)
|
||||
|
||||
return when {
|
||||
OnboardingHelper.isOnboardingCase(previousChainResult) -> {
|
||||
onboardingHelper.isOnboardingCase(previousChainResult) -> {
|
||||
trackingContextProxy.addContext(previousChainResult)
|
||||
ScanChainException.OnboardingNeeded(
|
||||
AppRoute.Onboarding(
|
||||
|
|
@ -46,8 +42,7 @@ class CheckForOnboardingChain(
|
|||
else -> {
|
||||
trackingContextProxy.setContext(previousChainResult)
|
||||
|
||||
val wasTwinsOnboardingShown = store.inject(DaggerGraphState::wasTwinsOnboardingShownUseCase)
|
||||
.invokeSync()
|
||||
val wasTwinsOnboardingShown = wasTwinsOnboardingShownUseCase.invokeSync()
|
||||
|
||||
// If twins was twinned previously but twins welcome not shown
|
||||
if (previousChainResult.twinsIsTwinned() && !wasTwinsOnboardingShown) {
|
||||
|
|
|
|||
|
|
@ -2,33 +2,30 @@ package com.tangem.tap.domain.scanCard.chains
|
|||
|
||||
import arrow.core.right
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.domain.card.ScanCardException
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.core.chain.Chain
|
||||
import com.tangem.domain.core.chain.ResultChain
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.disclaimer.createDisclaimer
|
||||
import org.rekotlin.Store
|
||||
|
||||
/**
|
||||
* Handles disclaimer display after the card scanning operation.
|
||||
*
|
||||
* Returns [ScanChainException.DisclaimerWasCanceled] if the disclaimer is dismissed by the user.
|
||||
*
|
||||
* @param store the [Store] that holds the state of the app, used here to dispatch actions related to disclaimers.
|
||||
* @param disclaimerWillShow an optional function to be invoked when a disclaimer is about to be shown. Default is an
|
||||
* empty function.
|
||||
*
|
||||
* @see Chain for more information about the Chain interface.
|
||||
*/
|
||||
internal class DisclaimerChain(
|
||||
private val store: Store<AppState>,
|
||||
private val appRouter: AppRouter,
|
||||
private val cardRepository: CardRepository,
|
||||
private val disclaimerWillShow: () -> Unit = {},
|
||||
) : ResultChain<ScanCardException, ScanResponse>() {
|
||||
|
||||
override suspend fun launch(previousChainResult: ScanResponse): ScanChainResult {
|
||||
val disclaimer = previousChainResult.card.createDisclaimer()
|
||||
val disclaimer = previousChainResult.card.createDisclaimer(cardRepository)
|
||||
|
||||
return if (disclaimer.isAccepted()) {
|
||||
previousChainResult.right()
|
||||
|
|
@ -36,9 +33,7 @@ internal class DisclaimerChain(
|
|||
disclaimerWillShow()
|
||||
|
||||
// TODO: [REDACTED_JIRA]
|
||||
store.dispatchNavigationAction {
|
||||
push(route = AppRoute.Disclaimer(isTosAccepted = false))
|
||||
}
|
||||
appRouter.push(route = AppRoute.Disclaimer(isTosAccepted = false))
|
||||
|
||||
previousChainResult.right()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,15 +5,6 @@ import com.tangem.domain.card.ScanCardException
|
|||
|
||||
sealed class ScanChainException : ScanCardException.ChainException() {
|
||||
|
||||
/**
|
||||
* May be returned from [DisclaimerChain]
|
||||
* */
|
||||
class DisclaimerWasCanceled : ScanChainException() {
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
private fun readResolve(): Any = DisclaimerWasCanceled()
|
||||
}
|
||||
|
||||
/**
|
||||
* May be returned from [CheckForOnboardingChain]
|
||||
*
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ internal class ScanCardExceptionConverter : TwoWayConverter<TangemError, ScanCar
|
|||
|
||||
private fun concertScanChainException(value: ScanCardException.ChainException): TangemSdkError {
|
||||
return when (val e = value as? ScanChainException) {
|
||||
is ScanChainException.DisclaimerWasCanceled -> TangemSdkError.UserCancelled()
|
||||
is ScanChainException.OnboardingNeeded,
|
||||
null,
|
||||
-> TangemSdkError.ExceptionError(e?.cause)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.tangem.crypto.bip39.DefaultMnemonic
|
|||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
|
@ -72,6 +73,7 @@ internal class DefaultTangemSdkManager(
|
|||
private val dynamicAddressesFeatureToggles: DynamicAddressesFeatureToggles,
|
||||
private val blockchainToDeriveFinder: BlockchainToDeriveFinder,
|
||||
private val analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
private val cardRepository: CardRepository,
|
||||
) : TangemSdkManager {
|
||||
|
||||
private val tangemSdk: TangemSdk
|
||||
|
|
@ -146,6 +148,7 @@ internal class DefaultTangemSdkManager(
|
|||
shouldCheckIsAlreadyActivated = shouldCheckIsAlreadyActivated,
|
||||
isDynamicAddressesEnabled = dynamicAddressesFeatureToggles.isDynamicAddressesEnabled,
|
||||
onboardingV2FeatureToggles = onboardingV2FeatureToggles,
|
||||
cardRepository = cardRepository,
|
||||
),
|
||||
cardId = cardId,
|
||||
initialMessage = message,
|
||||
|
|
@ -453,6 +456,7 @@ internal class DefaultTangemSdkManager(
|
|||
twinPublicKey = secondCardPublicKey,
|
||||
issuerKeys = issuerKeyPair,
|
||||
isDynamicAddressesEnabled = dynamicAddressesFeatureToggles.isDynamicAddressesEnabled,
|
||||
cardRepository = cardRepository,
|
||||
),
|
||||
cardId = cardId,
|
||||
initialMessage = initialMessage,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import com.tangem.domain.card.common.TapWorkarounds.isTangemTwins
|
|||
import com.tangem.domain.card.common.TapWorkarounds.isVisa
|
||||
import com.tangem.domain.card.common.TwinsHelper
|
||||
import com.tangem.domain.card.common.visa.VisaUtilities
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.CardDTO.Companion.RING_BATCH_IDS
|
||||
import com.tangem.domain.models.scan.CardDTO.Companion.RING_BATCH_PREFIX
|
||||
|
|
@ -34,13 +35,10 @@ import com.tangem.operations.backup.StartPrimaryCardLinkingTask
|
|||
import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask
|
||||
import com.tangem.operations.files.ReadFilesTask
|
||||
import com.tangem.operations.issuerAndUserData.ReadIssuerDataCommand
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.domain.TapSdkError
|
||||
import com.tangem.tap.domain.visa.VisaCardScanHandler
|
||||
import com.tangem.tap.mainScope
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
|
@ -53,6 +51,7 @@ internal class ScanProductTask(
|
|||
private val onboardingV2FeatureToggles: OnboardingV2FeatureToggles?,
|
||||
private val shouldCheckIsAlreadyActivated: Boolean,
|
||||
private val isDynamicAddressesEnabled: Boolean,
|
||||
private val cardRepository: CardRepository,
|
||||
override val allowsRequestAccessCodeFromRepository: Boolean = false,
|
||||
) : CardSessionRunnable<ScanResponse> {
|
||||
|
||||
|
|
@ -80,7 +79,11 @@ internal class ScanProductTask(
|
|||
readVisaCard(
|
||||
session = session,
|
||||
cardDto = cardDto,
|
||||
scanWalletProcessor = ScanWalletProcessor(blockchainToDeriveFinder, isDynamicAddressesEnabled),
|
||||
scanWalletProcessor = ScanWalletProcessor(
|
||||
blockchainToDeriveFinder = blockchainToDeriveFinder,
|
||||
isDynamicAddressesEnabled = isDynamicAddressesEnabled,
|
||||
cardRepository = cardRepository,
|
||||
),
|
||||
callback = callback,
|
||||
)
|
||||
return
|
||||
|
|
@ -88,7 +91,11 @@ internal class ScanProductTask(
|
|||
|
||||
val commandProcessor = when {
|
||||
cardDto.isTangemTwins -> ScanTwinProcessor()
|
||||
else -> ScanWalletProcessor(blockchainToDeriveFinder, isDynamicAddressesEnabled)
|
||||
else -> ScanWalletProcessor(
|
||||
blockchainToDeriveFinder = blockchainToDeriveFinder,
|
||||
isDynamicAddressesEnabled = isDynamicAddressesEnabled,
|
||||
cardRepository = cardRepository,
|
||||
)
|
||||
}
|
||||
commandProcessor.proceed(cardDto, session) { processorResult ->
|
||||
when (processorResult) {
|
||||
|
|
@ -114,7 +121,7 @@ internal class ScanProductTask(
|
|||
return if (shouldCheckIsAlreadyActivated) {
|
||||
PreflightReadMode.FullCardReadWithAccessCodeCheck
|
||||
} else {
|
||||
return super.preflightReadMode()
|
||||
super.preflightReadMode()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -171,6 +178,7 @@ internal class ScanProductTask(
|
|||
private class ScanWalletProcessor(
|
||||
private val blockchainToDeriveFinder: BlockchainToDeriveFinder?,
|
||||
private val isDynamicAddressesEnabled: Boolean,
|
||||
private val cardRepository: CardRepository,
|
||||
) : ProductCommandProcessor<ScanResponse> {
|
||||
|
||||
var primaryCard: PrimaryCard? = null
|
||||
|
|
@ -262,8 +270,7 @@ private class ScanWalletProcessor(
|
|||
callback: (result: CompletionResult<ScanResponse>) -> Unit,
|
||||
) {
|
||||
mainScope.launch {
|
||||
val isActivationInProgress = store.inject(DaggerGraphState::cardRepository)
|
||||
.isActivationInProgress(card.cardId)
|
||||
val isActivationInProgress = cardRepository.isActivationInProgress(card.cardId)
|
||||
|
||||
@Suppress("ComplexCondition")
|
||||
if (card.backupStatus == CardDTO.BackupStatus.NoBackup &&
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.tangem.common.CompletionResult
|
|||
import com.tangem.common.KeyPair
|
||||
import com.tangem.common.core.CardSession
|
||||
import com.tangem.common.core.CardSessionRunnable
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.operations.PreflightReadMode
|
||||
import com.tangem.operations.PreflightReadTask
|
||||
|
|
@ -13,6 +14,7 @@ class FinalizeTwinTask(
|
|||
private val twinPublicKey: ByteArray,
|
||||
private val issuerKeys: KeyPair,
|
||||
private val isDynamicAddressesEnabled: Boolean,
|
||||
private val cardRepository: CardRepository,
|
||||
) : CardSessionRunnable<ScanResponse> {
|
||||
|
||||
override val allowsRequestAccessCodeFromRepository: Boolean = false
|
||||
|
|
@ -35,6 +37,7 @@ class FinalizeTwinTask(
|
|||
shouldCheckIsAlreadyActivated = false,
|
||||
isDynamicAddressesEnabled = isDynamicAddressesEnabled,
|
||||
onboardingV2FeatureToggles = null,
|
||||
cardRepository = cardRepository,
|
||||
).run(session, callback)
|
||||
is CompletionResult.Failure ->
|
||||
callback(CompletionResult.Failure(readResult.error))
|
||||
|
|
|
|||
|
|
@ -1,18 +1,15 @@
|
|||
package com.tangem.tap.features.disclaimer
|
||||
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
import java.util.Locale
|
||||
|
||||
fun CardDTO.createDisclaimer(): Disclaimer {
|
||||
val dataProvider = provideDisclaimerDataProvider(cardId)
|
||||
fun CardDTO.createDisclaimer(cardRepository: CardRepository): Disclaimer {
|
||||
val dataProvider = provideDisclaimerDataProvider(cardId, cardRepository)
|
||||
return TangemDisclaimer(dataProvider)
|
||||
}
|
||||
|
||||
private fun provideDisclaimerDataProvider(cardId: String): DisclaimerDataProvider {
|
||||
val cardRepository = store.inject(DaggerGraphState::cardRepository)
|
||||
private fun provideDisclaimerDataProvider(cardId: String, cardRepository: CardRepository): DisclaimerDataProvider {
|
||||
return object : DisclaimerDataProvider {
|
||||
override fun getLanguage(): String = Locale.getDefault().language
|
||||
override fun getCardId(): String = cardId
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ import com.tangem.domain.wallets.usecase.UpdateRemoteWalletsInfoUseCase
|
|||
import com.tangem.feature.swap.analytics.StoriesEvents
|
||||
import com.tangem.security.DeviceSecurityInfoProvider
|
||||
import com.tangem.tap.network.exchangeServices.SellService
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import com.tangem.tap.routing.configurator.AppRouterConfig
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
|
|
@ -77,7 +76,6 @@ internal class MainViewModel @Inject constructor(
|
|||
private val sendPushTokenUseCase: SendPushTokenUseCase,
|
||||
private val apiConfigsManager: ApiConfigsManager,
|
||||
private val multiQuoteUpdater: MultiQuoteUpdater,
|
||||
private val appStateHolder: AppStateHolder,
|
||||
private val appRouterConfig: AppRouterConfig,
|
||||
private val sellService: SellService,
|
||||
private val deviceSecurityInfoProvider: DeviceSecurityInfoProvider,
|
||||
|
|
@ -176,8 +174,6 @@ internal class MainViewModel @Inject constructor(
|
|||
|
||||
private fun initializeOffRamp() {
|
||||
viewModelScope.launch {
|
||||
appStateHolder.sellService = sellService
|
||||
|
||||
sellService.update()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,19 +2,18 @@ package com.tangem.tap.features.onboarding
|
|||
|
||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||
import com.tangem.domain.card.common.util.twinsIsTwinned
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
object OnboardingHelper {
|
||||
@Singleton
|
||||
class OnboardingHelper @Inject constructor(
|
||||
private val cardRepository: CardRepository,
|
||||
) {
|
||||
suspend fun isOnboardingCase(response: ScanResponse): Boolean {
|
||||
val cardRepository = store.inject(DaggerGraphState::cardRepository)
|
||||
val cardId = response.card.cardId
|
||||
|
||||
return when {
|
||||
|
|
@ -22,7 +21,7 @@ object OnboardingHelper {
|
|||
// if (response.visaCardActivationStatus == null) error("Visa card activation status is null")
|
||||
//
|
||||
// response.visaCardActivationStatus !is VisaCardActivationStatus.Activated
|
||||
return true
|
||||
true
|
||||
}
|
||||
|
||||
response.cardTypesResolver.isTangemTwins() -> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue