Updated on 2026-08-14
This commit is contained in:
parent
a2c8e7e95a
commit
505413483e
26 changed files with 467 additions and 321 deletions
|
|
@ -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.appsflyer.AppsFlyerLib
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.routing.deeplink.DeeplinkConst.WEBLINK_KEY
|
||||
import com.tangem.common.routing.deeplink.PayloadToDeeplinkConverter
|
||||
|
|
@ -367,6 +368,9 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
super.onNewIntent(intent)
|
||||
TangemLogger.i("onNewIntent: data=${intent.data}, extras=${intent.extras?.keySet()}")
|
||||
|
||||
// Warm start: let the AppsFlyer SDK resolve a OneLink delivered while the app is already running.
|
||||
AppsFlyerLib.getInstance().performOnDeepLinking(intent, this)
|
||||
|
||||
val isFromPush = intent.extras?.containsKey(OPENED_FROM_GCM_PUSH) == true
|
||||
if (isFromPush) {
|
||||
analyticsEventsHandler.send(Push.PushNotificationOpened())
|
||||
|
|
|
|||
|
|
@ -13,17 +13,9 @@ class AppsFlyerDeepLinkListener @Inject constructor(
|
|||
|
||||
override fun onDeepLinking(p0: DeepLinkResult) {
|
||||
when (p0.status) {
|
||||
DeepLinkResult.Status.FOUND -> {
|
||||
referralParamsHandler.handleDeeplink(deepLink = p0.deepLink)
|
||||
}
|
||||
DeepLinkResult.Status.NOT_FOUND -> {
|
||||
referralParamsHandler.handleNoDeeplink()
|
||||
TangemLogger.i("No deep link found")
|
||||
}
|
||||
DeepLinkResult.Status.ERROR -> {
|
||||
referralParamsHandler.handleNoDeeplink()
|
||||
TangemLogger.e("Deep link error: ${p0.error}")
|
||||
}
|
||||
DeepLinkResult.Status.FOUND -> referralParamsHandler.handleDeeplink(deepLink = p0.deepLink)
|
||||
DeepLinkResult.Status.NOT_FOUND -> TangemLogger.i("No deep link found")
|
||||
DeepLinkResult.Status.ERROR -> TangemLogger.e("Deep link error: ${p0.error}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
package com.tangem.tap.common.analytics.appsflyer
|
||||
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.configtoggle.FeatureToggles
|
||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import com.tangem.datasource.local.appsflyer.AppsFlyerStore
|
||||
import com.tangem.domain.appsflyer.AppsFlyerDeeplink
|
||||
import com.tangem.domain.appsflyer.usecase.ClearAppsFlyerDeeplinkUseCase
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Reactively routes AppsFlyer deep links persisted by [AppsFlyerReferralParamsHandler].
|
||||
*
|
||||
* To add a deep link: add it to [AppsFlyerDeeplink] and a branch in [onDeeplinkPending] (the `when` is exhaustive).
|
||||
*/
|
||||
@Singleton
|
||||
class AppsFlyerDeeplinkRouter @Inject constructor(
|
||||
private val appsFlyerStore: AppsFlyerStore,
|
||||
private val userWalletsListRepository: UserWalletsListRepository,
|
||||
private val clearAppsFlyerDeeplinkUseCase: ClearAppsFlyerDeeplinkUseCase,
|
||||
private val featureTogglesManager: FeatureTogglesManager,
|
||||
private val appRouter: AppRouter,
|
||||
) {
|
||||
|
||||
fun observe(scope: CoroutineScope, currentRoute: Flow<AppRoute?>) {
|
||||
combine(
|
||||
appsFlyerStore.observeNavigationDeeplink(),
|
||||
currentRoute.distinctUntilChanged(),
|
||||
) { deepLinkValue, route ->
|
||||
if (deepLinkValue != null && route != null) deepLinkValue to route else null
|
||||
}
|
||||
.filterNotNull()
|
||||
.onEach { (deepLinkValue, route) -> onDeeplinkPending(deepLinkValue, route) }
|
||||
.launchIn(scope)
|
||||
}
|
||||
|
||||
private suspend fun onDeeplinkPending(deepLinkValue: String, currentRoute: AppRoute) {
|
||||
when (AppsFlyerDeeplink.from(deepLinkValue)) {
|
||||
AppsFlyerDeeplink.TangemPayMobileOnboarding -> routeTangemPayOnboarding(currentRoute)
|
||||
AppsFlyerDeeplink.Referral -> routeReferral(currentRoute)
|
||||
null -> TangemLogger.i("Ignoring unknown AppsFlyer deep link value: $deepLinkValue")
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun routeTangemPayOnboarding(currentRoute: AppRoute) {
|
||||
val isEnabled = featureTogglesManager.isFeatureEnabled(
|
||||
FeatureToggles.AND_15101_TANGEM_PAY_HOT_WALLET_ONBOARDING,
|
||||
)
|
||||
if (!isEnabled) return
|
||||
|
||||
// Not on an idle entry screen yet: keep the deep link pending, re-evaluate on next route change.
|
||||
if (!isIdleEntryPoint(currentRoute)) return
|
||||
|
||||
if (userWalletsListRepository.userWalletsSync().isNotEmpty()) {
|
||||
TangemLogger.i("[TangemPay][HWO] Routing AppsFlyer deep link to Tangem Pay onboarding")
|
||||
// Authorized: push onto the wallet screen so Back returns to it.
|
||||
appRouter.push(AppRoute.TangemPayOnboarding(AppRoute.TangemPayOnboarding.Mode.MobileOnboardingDeeplink))
|
||||
} else {
|
||||
TangemLogger.i("[TangemPay][HWO] Routing AppsFlyer deep link to hot wallet onboarding")
|
||||
// Not authorized: open onboarding as the root, skipping Home/stories (original cold-start flow).
|
||||
appRouter.replaceAll(AppRoute.TangemPayHotWalletOnboarding)
|
||||
}
|
||||
// One-shot: consume the deep link once routed so the user isn't forced back here on relaunch.
|
||||
clearAppsFlyerDeeplinkUseCase()
|
||||
}
|
||||
|
||||
private suspend fun routeReferral(currentRoute: AppRoute) {
|
||||
val isEnabled = featureTogglesManager.isFeatureEnabled(
|
||||
FeatureToggles.TWI_1512_HIDE_STORIES_FOR_REFERRAL_ENABLED,
|
||||
)
|
||||
if (!isEnabled) return
|
||||
|
||||
// Referral targets fresh installs: from an idle entry screen, go straight to hot wallet creation
|
||||
// (skips stories). The deep link is NOT cleared here — it stays as referral attribution (read by
|
||||
// IsReferralInstallUseCase, cleared on wallet creation); replaceAll keeps it off the back stack.
|
||||
if (!isIdleEntryPoint(currentRoute)) return
|
||||
if (userWalletsListRepository.userWalletsSync().isNotEmpty()) return
|
||||
|
||||
TangemLogger.i("[Referral] Routing AppsFlyer referral deep link to hot wallet creation")
|
||||
appRouter.replaceAll(AppRoute.CreateWalletStart(mode = AppRoute.CreateWalletStart.Mode.HotWallet))
|
||||
}
|
||||
}
|
||||
|
||||
// Route only from idle entry screens so an in-progress flow (scan, KYC, onboarding…) isn't interrupted.
|
||||
internal fun isIdleEntryPoint(currentRoute: AppRoute?): Boolean =
|
||||
currentRoute is AppRoute.Home || currentRoute is AppRoute.Stories || currentRoute is AppRoute.Wallet
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
package com.tangem.tap.common.analytics.appsflyer
|
||||
|
||||
import com.appsflyer.deeplink.DeepLink
|
||||
import com.tangem.datasource.local.appsflyer.AppsFlyerDeeplinkSource
|
||||
import com.tangem.datasource.local.appsflyer.AppsFlyerStore
|
||||
import com.tangem.domain.appsflyer.AppsFlyerDeeplink
|
||||
import com.tangem.domain.wallets.models.AppsFlyerConversionData
|
||||
import com.tangem.utils.coroutines.AppCoroutineScope
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
|
@ -19,8 +18,6 @@ class AppsFlyerReferralParamsHandler @Inject constructor(
|
|||
private val coroutineScope: AppCoroutineScope,
|
||||
) {
|
||||
|
||||
private val deepLinkDeferred = CompletableDeferred<String?>()
|
||||
|
||||
fun handle(params: Map<String?, Any?>) {
|
||||
handle(
|
||||
deepLinkValue = params[DEEP_LINK_VALUE] as? String,
|
||||
|
|
@ -35,40 +32,15 @@ class AppsFlyerReferralParamsHandler @Inject constructor(
|
|||
deepLinkSub1 = deepLink.getStringValue(DEEP_LINK_SUB_1),
|
||||
deepLinkSub2 = deepLink.getStringValue(DEEP_LINK_SUB_2),
|
||||
)
|
||||
deepLinkDeferred.complete(deepLink.deepLinkValue)
|
||||
}
|
||||
|
||||
fun handleNoDeeplink() {
|
||||
deepLinkDeferred.complete(null)
|
||||
}
|
||||
|
||||
suspend fun waitForDeeplink(deeplinkSource: AppsFlyerDeeplinkSource): String? {
|
||||
appsFlyerStore.getDeeplink(deeplinkSource)?.let { return it }
|
||||
|
||||
val expectedValue = when (deeplinkSource) {
|
||||
AppsFlyerDeeplinkSource.TangemPayHotWalletOnboarding -> TANGEM_PAY_HOT_WALLET_ONBOARDING_DEEP_LINK_VALUE
|
||||
AppsFlyerDeeplinkSource.Referral -> REFERRAL_DEEP_LINK_VALUE
|
||||
}
|
||||
val resolvedValue = deepLinkDeferred.await().takeIf { it == expectedValue }
|
||||
|
||||
// The deep link may have been persisted to the store while we were awaiting (e.g. from
|
||||
// conversion-data handling, which stores the deep link but doesn't complete the deferred).
|
||||
return resolvedValue ?: appsFlyerStore.getDeeplink(deeplinkSource)
|
||||
}
|
||||
|
||||
private fun handle(deepLinkValue: String?, deepLinkSub1: String?, deepLinkSub2: String?) {
|
||||
TangemLogger.i("AppsFlyer deeplink received: value=$deepLinkValue")
|
||||
when (deepLinkValue) {
|
||||
REFERRAL_DEEP_LINK_VALUE -> handleReferral(deepLinkSub1, deepLinkSub2)
|
||||
TANGEM_PAY_HOT_WALLET_ONBOARDING_DEEP_LINK_VALUE -> handleTangemPayHotWalletOnboarding(deepLinkValue)
|
||||
else -> TangemLogger.i("Ignoring deep link with value: ${deepLinkValue ?: "null"}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleTangemPayHotWalletOnboarding(deepLinkValue: String) {
|
||||
coroutineScope.launch {
|
||||
appsFlyerStore.storeDeeplink(AppsFlyerDeeplinkSource.TangemPayHotWalletOnboarding, deepLinkValue)
|
||||
TangemLogger.i("[TangemPay][HWO] Deep link stored")
|
||||
when (AppsFlyerDeeplink.from(deepLinkValue)) {
|
||||
AppsFlyerDeeplink.Referral -> handleReferral(deepLinkSub1, deepLinkSub2)
|
||||
AppsFlyerDeeplink.TangemPayMobileOnboarding ->
|
||||
storeNavigationDeeplink(AppsFlyerDeeplink.TangemPayMobileOnboarding.deepLinkValue)
|
||||
null -> TangemLogger.i("Ignoring deep link with value: ${deepLinkValue ?: "null"}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,9 +48,7 @@ class AppsFlyerReferralParamsHandler @Inject constructor(
|
|||
@Suppress("NullableToStringCall")
|
||||
TangemLogger.i("refcode=$deepLinkSub1\ncampaign=$deepLinkSub2")
|
||||
|
||||
coroutineScope.launch {
|
||||
appsFlyerStore.storeDeeplink(AppsFlyerDeeplinkSource.Referral, REFERRAL_DEEP_LINK_VALUE)
|
||||
}
|
||||
storeNavigationDeeplink(AppsFlyerDeeplink.Referral.deepLinkValue)
|
||||
|
||||
if (!isValidParam(deepLinkSub1)) {
|
||||
TangemLogger.e("Deeplink conversion data is invalid")
|
||||
|
|
@ -97,6 +67,13 @@ class AppsFlyerReferralParamsHandler @Inject constructor(
|
|||
return value != null && value.isNotBlank() && !value.equals("null", ignoreCase = true)
|
||||
}
|
||||
|
||||
private fun storeNavigationDeeplink(deepLinkValue: String) {
|
||||
coroutineScope.launch {
|
||||
appsFlyerStore.storeNavigationDeeplink(deepLinkValue)
|
||||
TangemLogger.i("AppsFlyer navigation deep link stored: $deepLinkValue")
|
||||
}
|
||||
}
|
||||
|
||||
private fun storeConversionData(refcode: String, campaign: String?) {
|
||||
coroutineScope.launch {
|
||||
appsFlyerStore.storeIfAbsent(
|
||||
|
|
@ -107,9 +84,6 @@ class AppsFlyerReferralParamsHandler @Inject constructor(
|
|||
|
||||
private companion object {
|
||||
|
||||
const val REFERRAL_DEEP_LINK_VALUE = "referral"
|
||||
const val TANGEM_PAY_HOT_WALLET_ONBOARDING_DEEP_LINK_VALUE = "tpay_mobileonboard"
|
||||
|
||||
const val DEEP_LINK_VALUE = "deep_link_value"
|
||||
const val DEEP_LINK_SUB_1 = "deep_link_sub1"
|
||||
const val DEEP_LINK_SUB_2 = "deep_link_sub2"
|
||||
|
|
|
|||
|
|
@ -36,9 +36,9 @@ class AppsFlyerClient @AssistedInject constructor(
|
|||
setAppId(context.packageName)
|
||||
setDebugLog(true)
|
||||
|
||||
subscribeForDeepLink(appsFlyerDeepLinkListener)
|
||||
|
||||
init(apiKey, tangemAFConversionListener, context)
|
||||
subscribeForDeepLink(appsFlyerDeepLinkListener)
|
||||
setOneLinkCustomDomain(BRANDED_ONELINK_DOMAIN)
|
||||
|
||||
TangemLogger.i("Starting AppsFlyer SDK")
|
||||
start(context, apiKey, InitializationListener)
|
||||
|
|
@ -100,4 +100,9 @@ class AppsFlyerClient @AssistedInject constructor(
|
|||
interface Factory {
|
||||
fun create(apiKey: String): AppsFlyerClient
|
||||
}
|
||||
|
||||
private companion object {
|
||||
// Branded AppsFlyer OneLink domain (matches the join.tangem.com App Link filter in AndroidManifest).
|
||||
const val BRANDED_ONELINK_DOMAIN = "join.tangem.com"
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,6 @@ import com.tangem.core.analytics.utils.TrackingContextProxy
|
|||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
import com.tangem.datasource.local.preferences.utils.getSyncOrDefault
|
||||
import com.tangem.domain.appsflyer.AppsFlyerDeeplinkSource
|
||||
import com.tangem.domain.appsflyer.usecase.ClearAppsFlyerDeeplinkUseCase
|
||||
import com.tangem.domain.common.wallets.UserWalletSelectedHandler
|
||||
import com.tangem.domain.common.wallets.UserWalletTransformAction
|
||||
|
|
@ -622,12 +621,12 @@ internal class DefaultUserWalletsListRepository(
|
|||
|
||||
private suspend fun onFirstWalletCreated() {
|
||||
// reset the referral attribution (set from AF deeplink) after creating a new wallet
|
||||
clearAppsFlyerDeeplinkUseCase(AppsFlyerDeeplinkSource.Referral)
|
||||
clearAppsFlyerDeeplinkUseCase()
|
||||
}
|
||||
|
||||
private suspend fun onAllWalletsDeleted() {
|
||||
// reset the referral attribution (set from AF deeplink) after removing the last wallet
|
||||
clearAppsFlyerDeeplinkUseCase(AppsFlyerDeeplinkSource.Referral)
|
||||
clearAppsFlyerDeeplinkUseCase()
|
||||
appPreferencesStore.editData { it.remove(PreferencesKeys.USEDESK_CLIENT_ID_KEY) }
|
||||
}
|
||||
}
|
||||
|
|
@ -19,8 +19,6 @@ import com.tangem.core.analytics.models.Basic
|
|||
import com.tangem.core.analytics.models.ExceptionAnalyticsEvent
|
||||
import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent
|
||||
import com.tangem.core.analytics.utils.TrackingContextProxy
|
||||
import com.tangem.core.configtoggle.FeatureToggles
|
||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.child
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
|
|
@ -31,7 +29,6 @@ import com.tangem.core.ui.extensions.resourceReference
|
|||
import com.tangem.core.ui.message.DialogMessage
|
||||
import com.tangem.core.ui.message.EventMessageAction
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.datasource.local.appsflyer.AppsFlyerDeeplinkSource
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
|
@ -52,7 +49,7 @@ import com.tangem.hot.sdk.TangemHotSdk
|
|||
import com.tangem.hot.sdk.android.create
|
||||
import com.tangem.sdk.api.BackupServiceHolder
|
||||
import com.tangem.tap.common.SnackbarHandler
|
||||
import com.tangem.tap.common.analytics.appsflyer.AppsFlyerReferralParamsHandler
|
||||
import com.tangem.tap.common.analytics.appsflyer.AppsFlyerDeeplinkRouter
|
||||
import com.tangem.tap.features.hot.TangemHotSDKProxy
|
||||
import com.tangem.tap.features.scanfails.ScanFailsComponent
|
||||
import com.tangem.tap.features.scanfails.ScanFailsRequesterProxy
|
||||
|
|
@ -68,11 +65,8 @@ import com.tangem.wallet.R
|
|||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@Suppress("LongParameterList", "LargeClass")
|
||||
internal class DefaultRoutingComponent @AssistedInject constructor(
|
||||
|
|
@ -91,7 +85,7 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
|||
private val userWalletsListRepository: UserWalletsListRepository,
|
||||
private val cardRepository: CardRepository,
|
||||
private val onboardingRepository: OnboardingRepository,
|
||||
private val appsFlyerReferralParamsHandler: AppsFlyerReferralParamsHandler,
|
||||
private val appsFlyerDeeplinkRouter: AppsFlyerDeeplinkRouter,
|
||||
private val trackingContextProxy: TrackingContextProxy,
|
||||
private val scanFailsComponentFactory: ScanFailsComponent.Factory,
|
||||
private val scanFailsRequesterProxy: ScanFailsRequesterProxy,
|
||||
|
|
@ -102,7 +96,6 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
|||
private val neverToInitiallyAskPermissionUseCase: NeverToInitiallyAskPermissionUseCase,
|
||||
private val shouldInitiallyAskPermissionUseCase: ShouldInitiallyAskPermissionUseCase,
|
||||
private val neverRequestPermissionUseCase: NeverRequestPermissionUseCase,
|
||||
private val featureTogglesManager: FeatureTogglesManager,
|
||||
) : RoutingComponent,
|
||||
AppComponentContext by context,
|
||||
SnackbarHandler {
|
||||
|
|
@ -146,6 +139,8 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
|||
},
|
||||
)
|
||||
|
||||
private val currentRoute = MutableStateFlow<AppRoute?>(null)
|
||||
|
||||
init {
|
||||
appRouterConfig.routerScope = componentScope
|
||||
appRouterConfig.componentRouter = router
|
||||
|
|
@ -160,6 +155,7 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
|||
|
||||
val stackItems = stack.items.map { it.configuration }
|
||||
|
||||
currentRoute.value = stack.active.configuration
|
||||
wcRoutingComponent.onAppRouteChange(stack.active.configuration)
|
||||
deeplinkFactory.checkRoutingReadiness(stack.active.configuration)
|
||||
|
||||
|
|
@ -170,6 +166,7 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
|||
|
||||
configureProxies()
|
||||
initializeInitialNavigation()
|
||||
appsFlyerDeeplinkRouter.observe(scope = componentScope, currentRoute = currentRoute)
|
||||
}
|
||||
|
||||
private fun initializeInitialNavigation() {
|
||||
|
|
@ -206,8 +203,9 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
|||
}
|
||||
|
||||
private suspend fun navigateForEmptyWallets(): AppRoute {
|
||||
val afterEmptyRoute = resolveAppsFlyerOnboardingRoute()
|
||||
?: AppRoute.Home(launchMode = launchMode)
|
||||
// AppsFlyer deep links (referral, tpay_mobileonboard) are routed reactively by AppsFlyerDeeplinkRouter
|
||||
// once we settle on an idle screen — not resolved here.
|
||||
val afterEmptyRoute = AppRoute.Home(launchMode = launchMode)
|
||||
|
||||
val shouldAskPushPermission = shouldInitiallyAskPermissionUseCase(PUSH_PERMISSION).getOrNull()
|
||||
?: return afterEmptyRoute
|
||||
|
|
@ -227,44 +225,6 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun resolveAppsFlyerOnboardingRoute(): AppRoute? = coroutineScope {
|
||||
val tangemPayRoute = async { resolveTangemPayHotWalletOnboardingRoute() }
|
||||
val referralRoute = async { resolveReferralRoute() }
|
||||
tangemPayRoute.await() ?: referralRoute.await()
|
||||
}
|
||||
|
||||
private suspend fun resolveTangemPayHotWalletOnboardingRoute(): AppRoute? {
|
||||
val isEnabled = featureTogglesManager.isFeatureEnabled(
|
||||
FeatureToggles.AND_15101_TANGEM_PAY_HOT_WALLET_ONBOARDING,
|
||||
)
|
||||
TangemLogger.i("[TangemPay][HWO] Feature toggle enabled=$isEnabled")
|
||||
if (!isEnabled) return null
|
||||
|
||||
val deepLink = awaitAppsFlyerDeeplink(AppsFlyerDeeplinkSource.TangemPayHotWalletOnboarding)
|
||||
TangemLogger.i("[TangemPay][HWO] Deep link present=${deepLink != null}")
|
||||
return if (deepLink != null) AppRoute.TangemPayHotWalletOnboarding else null
|
||||
}
|
||||
|
||||
private suspend fun resolveReferralRoute(): AppRoute? {
|
||||
val isEnabled = featureTogglesManager.isFeatureEnabled(
|
||||
FeatureToggles.TWI_1512_HIDE_STORIES_FOR_REFERRAL_ENABLED,
|
||||
)
|
||||
if (!isEnabled) return null
|
||||
|
||||
val referralDeepLink = awaitAppsFlyerDeeplink(AppsFlyerDeeplinkSource.Referral)
|
||||
return if (referralDeepLink != null) {
|
||||
AppRoute.CreateWalletStart(mode = AppRoute.CreateWalletStart.Mode.HotWallet)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun awaitAppsFlyerDeeplink(source: AppsFlyerDeeplinkSource): String? {
|
||||
return withTimeoutOrNull(2.seconds) {
|
||||
appsFlyerReferralParamsHandler.waitForDeeplink(source)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
RootContent(
|
||||
|
|
|
|||
|
|
@ -690,6 +690,7 @@ internal class ChildFactory @Inject constructor(
|
|||
)
|
||||
is AppRoute.TangemPayOnboarding.Mode.FromBannerInSettings -> FromBannerInSettings
|
||||
is AppRoute.TangemPayOnboarding.Mode.FromBannerOnMain -> FromBannerOnMain
|
||||
is AppRoute.TangemPayOnboarding.Mode.MobileOnboardingDeeplink -> MobileOnboardingDeeplink
|
||||
},
|
||||
componentFactory = tangemPayOnboardingComponentFactory,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue