Updated on 2026-08-14
This commit is contained in:
parent
0de7027fbc
commit
a078b7bffa
5 changed files with 74 additions and 43 deletions
|
|
@ -245,7 +245,7 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
|
||||
if (routingFeatureToggle.isDeepLinkNavigationEnabled.not() && intent != null && savedInstanceState == null) {
|
||||
// handle intent only on start, not on recreate
|
||||
handleDeepLink(intent)
|
||||
handleDeepLink(intent = intent, isFromOnNewIntent = false)
|
||||
}
|
||||
|
||||
lifecycle.addObserver(WindowObscurationObserver)
|
||||
|
|
@ -397,7 +397,7 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
}
|
||||
|
||||
if (intent != null) {
|
||||
handleDeepLink(intent)
|
||||
handleDeepLink(intent = intent, isFromOnNewIntent = true)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -479,13 +479,13 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
}
|
||||
|
||||
if (routingFeatureToggle.isDeepLinkNavigationEnabled && intent != null) {
|
||||
handleDeepLink(intent)
|
||||
handleDeepLink(intent = intent, isFromOnNewIntent = false)
|
||||
}
|
||||
|
||||
viewModel.checkForUnfinishedBackup()
|
||||
}
|
||||
|
||||
private fun handleDeepLink(intent: Intent) {
|
||||
private fun handleDeepLink(intent: Intent, isFromOnNewIntent: Boolean) {
|
||||
if (routingFeatureToggle.isDeepLinkNavigationEnabled) {
|
||||
val deepLinkExtras = intent.getStringExtra(DEEPLINK_KEY)?.toUri()
|
||||
val webLink = intent.getStringExtra(WEBLINK_KEY)
|
||||
|
|
@ -494,7 +494,11 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
|
||||
when {
|
||||
receivedDeepLink != null -> {
|
||||
deeplinkFactory.handleDeeplink(deeplinkUri = receivedDeepLink, coroutineScope = lifecycleScope)
|
||||
deeplinkFactory.handleDeeplink(
|
||||
deeplinkUri = receivedDeepLink,
|
||||
coroutineScope = lifecycleScope,
|
||||
isFromOnNewIntent = isFromOnNewIntent,
|
||||
)
|
||||
}
|
||||
webLink?.uriValidate() == true -> {
|
||||
urlOpener.openUrl(webLink)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ internal class DeepLinkFactory @Inject constructor(
|
|||
private val deepLinkHandlerJobHolder = JobHolder()
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
fun handleDeeplink(deeplinkUri: Uri, coroutineScope: CoroutineScope) {
|
||||
fun handleDeeplink(deeplinkUri: Uri, coroutineScope: CoroutineScope, isFromOnNewIntent: Boolean) {
|
||||
lastDeepLink = deeplinkUri
|
||||
|
||||
Timber.i(
|
||||
|
|
@ -55,7 +55,7 @@ internal class DeepLinkFactory @Inject constructor(
|
|||
.transformLatest<Boolean, Unit> { isPermitted ->
|
||||
if (isPermitted) {
|
||||
lastDeepLink?.let {
|
||||
launchDeepLink(it, coroutineScope)
|
||||
launchDeepLink(it, coroutineScope, isFromOnNewIntent)
|
||||
}
|
||||
lastDeepLink = null
|
||||
}
|
||||
|
|
@ -80,9 +80,9 @@ internal class DeepLinkFactory @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun launchDeepLink(deeplinkUri: Uri, coroutineScope: CoroutineScope) {
|
||||
private fun launchDeepLink(deeplinkUri: Uri, coroutineScope: CoroutineScope, isFromOnNewIntent: Boolean) {
|
||||
when (deeplinkUri.scheme) {
|
||||
DeepLinkScheme.Tangem.scheme -> handleTangemDeepLinks(deeplinkUri, coroutineScope)
|
||||
DeepLinkScheme.Tangem.scheme -> handleTangemDeepLinks(deeplinkUri, coroutineScope, isFromOnNewIntent)
|
||||
DeepLinkScheme.WalletConnect.scheme -> walletConnectDeepLink.create(deeplinkUri)
|
||||
else -> {
|
||||
Timber.i(
|
||||
|
|
@ -95,7 +95,7 @@ internal class DeepLinkFactory @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleTangemDeepLinks(deeplinkUri: Uri, coroutineScope: CoroutineScope) {
|
||||
private fun handleTangemDeepLinks(deeplinkUri: Uri, coroutineScope: CoroutineScope, isFromOnNewIntent: Boolean) {
|
||||
val queryParams = getQueryParams(deeplinkUri)
|
||||
when (deeplinkUri.host) {
|
||||
DeepLinkRoute.Onramp.host -> onrampDeepLink.create(coroutineScope, queryParams)
|
||||
|
|
@ -103,7 +103,11 @@ internal class DeepLinkFactory @Inject constructor(
|
|||
DeepLinkRoute.Buy.host -> buyDeepLink.create(coroutineScope)
|
||||
DeepLinkRoute.Referral.host -> referralDeepLink.create()
|
||||
DeepLinkRoute.Wallet.host -> walletDeepLink.create()
|
||||
DeepLinkRoute.TokenDetails.host -> tokenDetailsDeepLink.create(coroutineScope, queryParams)
|
||||
DeepLinkRoute.TokenDetails.host -> tokenDetailsDeepLink.create(
|
||||
coroutineScope = coroutineScope,
|
||||
queryParams = queryParams,
|
||||
isFromOnNewIntent = isFromOnNewIntent,
|
||||
)
|
||||
DeepLinkRoute.Staking.host -> stakingDeepLink.create(coroutineScope, queryParams)
|
||||
else -> {
|
||||
Timber.i(
|
||||
|
|
|
|||
|
|
@ -44,13 +44,14 @@ class DeepLinkFactoryTest {
|
|||
every { create() } returns mockk()
|
||||
}
|
||||
private val tokenDetailsDeepLinkFactory = mockk<TokenDetailsDeepLinkHandler.Factory>(relaxed = true) {
|
||||
every { create(any(), any()) } returns mockk()
|
||||
every { create(any(), any(), any()) } returns mockk()
|
||||
}
|
||||
private val stakingDeepLinkFactory = mockk<StakingDeepLinkHandler.Factory>(relaxed = true) {
|
||||
every { create(any(), any()) } returns mockk()
|
||||
}
|
||||
|
||||
private val mockedUri = mockk<Uri>(relaxed = true)
|
||||
private val isFromOnNewIntent: Boolean = false
|
||||
|
||||
private lateinit var testDispatcher: TestDispatcher
|
||||
private lateinit var testScope: TestScope
|
||||
|
|
@ -101,7 +102,7 @@ class DeepLinkFactoryTest {
|
|||
every { mockedUri.getQueryParameter("param") } returns "value"
|
||||
|
||||
// Set permittedAppRoute to true
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
deepLinkFactory.checkRoutingReadiness(AppRoute.Wallet)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
|
@ -120,7 +121,7 @@ class DeepLinkFactoryTest {
|
|||
every { mockedUri.queryParameterNames } returns setOf("param")
|
||||
every { mockedUri.getQueryParameter("param") } returns "value"
|
||||
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
deepLinkFactory.checkRoutingReadiness(AppRoute.Initial)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
|
@ -138,7 +139,7 @@ class DeepLinkFactoryTest {
|
|||
every { mockedUri.getQueryParameter("param") } returns "value"
|
||||
|
||||
deepLinkFactory.checkRoutingReadiness(AppRoute.Wallet)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
|
|
@ -153,7 +154,7 @@ class DeepLinkFactoryTest {
|
|||
every { mockedUri.host } returns ""
|
||||
|
||||
deepLinkFactory.checkRoutingReadiness(AppRoute.Wallet)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
|
|
@ -167,7 +168,7 @@ class DeepLinkFactoryTest {
|
|||
every { mockedUri.scheme } returns "https"
|
||||
every { mockedUri.host } returns "example.com"
|
||||
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
|
|
@ -178,7 +179,7 @@ class DeepLinkFactoryTest {
|
|||
referralDeepLinkFactory.create()
|
||||
walletConnectDeepLinkFactory.create(any())
|
||||
walletDeepLinkFactory.create()
|
||||
tokenDetailsDeepLinkFactory.create(any(), any())
|
||||
tokenDetailsDeepLinkFactory.create(any(), any(), any())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -193,27 +194,39 @@ class DeepLinkFactoryTest {
|
|||
|
||||
// Test Onramp
|
||||
every { mockedUri.host } returns "onramp"
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
advanceUntilIdle()
|
||||
verify { onrampDeepLinkFactory.create(eq(testScope), eq(mapOf("param" to "value"))) }
|
||||
|
||||
// Test Sell
|
||||
every { mockedUri.host } returns "redirect_sell"
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
advanceUntilIdle()
|
||||
verify { sellDeepLinkFactory.create(eq(testScope), eq(mapOf("param" to "value"))) }
|
||||
|
||||
// Test Token Details
|
||||
every { mockedUri.host } returns "token"
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
advanceUntilIdle()
|
||||
verify { tokenDetailsDeepLinkFactory.create(eq(testScope), eq(mapOf("param" to "value"))) }
|
||||
verify {
|
||||
tokenDetailsDeepLinkFactory.create(
|
||||
eq(testScope),
|
||||
eq(mapOf("param" to "value")),
|
||||
eq(isFromOnNewIntent),
|
||||
)
|
||||
}
|
||||
|
||||
// Test Staking
|
||||
every { mockedUri.host } returns "staking"
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
advanceUntilIdle()
|
||||
verify { tokenDetailsDeepLinkFactory.create(eq(testScope), eq(mapOf("param" to "value"))) }
|
||||
verify {
|
||||
tokenDetailsDeepLinkFactory.create(
|
||||
eq(testScope),
|
||||
eq(mapOf("param" to "value")),
|
||||
eq(isFromOnNewIntent),
|
||||
)
|
||||
}
|
||||
|
||||
// Reset params
|
||||
every { mockedUri.queryParameterNames } returns emptySet()
|
||||
|
|
@ -221,19 +234,19 @@ class DeepLinkFactoryTest {
|
|||
|
||||
// Test Buy
|
||||
every { mockedUri.host } returns "redirect"
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
advanceUntilIdle()
|
||||
verify { buyDeepLinkFactory.create(eq(testScope)) }
|
||||
|
||||
// Test Referral
|
||||
every { mockedUri.host } returns "referral"
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
advanceUntilIdle()
|
||||
verify { referralDeepLinkFactory.create() }
|
||||
|
||||
// Test Wallet
|
||||
every { mockedUri.host } returns "main"
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
advanceUntilIdle()
|
||||
verify { walletDeepLinkFactory.create() }
|
||||
}
|
||||
|
|
@ -244,7 +257,7 @@ class DeepLinkFactoryTest {
|
|||
every { mockedUri.host } returns "unknown"
|
||||
|
||||
deepLinkFactory.checkRoutingReadiness(AppRoute.Wallet)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
|
|
@ -255,7 +268,7 @@ class DeepLinkFactoryTest {
|
|||
referralDeepLinkFactory.create()
|
||||
walletConnectDeepLinkFactory.create(any())
|
||||
walletDeepLinkFactory.create()
|
||||
tokenDetailsDeepLinkFactory.create(any(), any())
|
||||
tokenDetailsDeepLinkFactory.create(any(), any(), any())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -270,7 +283,7 @@ class DeepLinkFactoryTest {
|
|||
every { mockedUri.getQueryParameter("quote") } returns "O'Brien"
|
||||
|
||||
deepLinkFactory.checkRoutingReadiness(AppRoute.Wallet)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
advanceUntilIdle()
|
||||
|
||||
verify { onrampDeepLinkFactory.create(eq(testScope), eq(mapOf("safe" to "ok"))) }
|
||||
|
|
@ -286,49 +299,49 @@ class DeepLinkFactoryTest {
|
|||
every { mockedUri.query } returns "safe=ok"
|
||||
every { mockedUri.queryParameterNames } returns setOf("safe")
|
||||
every { mockedUri.getQueryParameter("safe") } returns "ok"
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
advanceUntilIdle()
|
||||
verify { onrampDeepLinkFactory.create(eq(testScope), eq(mapOf("safe" to "ok"))) }
|
||||
|
||||
every { mockedUri.query } returns "param123=ok"
|
||||
every { mockedUri.queryParameterNames } returns setOf("param123")
|
||||
every { mockedUri.getQueryParameter("param123") } returns "ok"
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
advanceUntilIdle()
|
||||
verify { onrampDeepLinkFactory.create(eq(testScope), eq(mapOf("param123" to "ok"))) }
|
||||
|
||||
every { mockedUri.query } returns "unsafe=<script>"
|
||||
every { mockedUri.queryParameterNames } returns setOf("unsafe")
|
||||
every { mockedUri.getQueryParameter("unsafe") } returns "<script>"
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
advanceUntilIdle()
|
||||
verify { onrampDeepLinkFactory.create(eq(testScope), eq(emptyMap())) }
|
||||
|
||||
every { mockedUri.query } returns "unsafe=O'Brien"
|
||||
every { mockedUri.queryParameterNames } returns setOf("unsafe")
|
||||
every { mockedUri.getQueryParameter("unsafe") } returns "O'Brien"
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
advanceUntilIdle()
|
||||
verify { onrampDeepLinkFactory.create(eq(testScope), eq(emptyMap())) }
|
||||
|
||||
every { mockedUri.query } returns "unsafe=test;"
|
||||
every { mockedUri.queryParameterNames } returns setOf("unsafe")
|
||||
every { mockedUri.getQueryParameter("unsafe") } returns "test;"
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
advanceUntilIdle()
|
||||
verify { onrampDeepLinkFactory.create(eq(testScope), eq(emptyMap())) }
|
||||
|
||||
every { mockedUri.query } returns "unsafe=test+attack"
|
||||
every { mockedUri.queryParameterNames } returns setOf("unsafe")
|
||||
every { mockedUri.getQueryParameter("unsafe") } returns "test+attack"
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
advanceUntilIdle()
|
||||
verify { onrampDeepLinkFactory.create(eq(testScope), eq(emptyMap())) }
|
||||
|
||||
every { mockedUri.query } returns "unsafe=test\\path"
|
||||
every { mockedUri.queryParameterNames } returns setOf("unsafe")
|
||||
every { mockedUri.getQueryParameter("unsafe") } returns "test\\path"
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope)
|
||||
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
|
||||
advanceUntilIdle()
|
||||
verify { onrampDeepLinkFactory.create(eq(testScope), eq(emptyMap())) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,10 @@ import kotlinx.coroutines.CoroutineScope
|
|||
interface TokenDetailsDeepLinkHandler {
|
||||
|
||||
interface Factory {
|
||||
fun create(coroutineScope: CoroutineScope, queryParams: Map<String, String>): TokenDetailsDeepLinkHandler
|
||||
fun create(
|
||||
coroutineScope: CoroutineScope,
|
||||
queryParams: Map<String, String>,
|
||||
isFromOnNewIntent: Boolean,
|
||||
): TokenDetailsDeepLinkHandler
|
||||
}
|
||||
}
|
||||
|
|
@ -16,9 +16,11 @@ import kotlinx.coroutines.CoroutineScope
|
|||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class DefaultTokenDetailsDeepLinkHandler @AssistedInject constructor(
|
||||
@Assisted private val scope: CoroutineScope,
|
||||
@Assisted private val queryParams: Map<String, String>,
|
||||
@Assisted private val isFromOnNewIntent: Boolean,
|
||||
private val appRouter: AppRouter,
|
||||
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
|
||||
private val getCryptoCurrenciesUseCase: GetCryptoCurrenciesUseCase,
|
||||
|
|
@ -69,11 +71,14 @@ internal class DefaultTokenDetailsDeepLinkHandler @AssistedInject constructor(
|
|||
currency = cryptoCurrency,
|
||||
),
|
||||
)
|
||||
fetchCurrencyStatusUseCase.invoke(
|
||||
userWalletId = userWalletId,
|
||||
id = cryptoCurrency.id,
|
||||
refresh = true,
|
||||
)
|
||||
|
||||
if (isFromOnNewIntent) {
|
||||
fetchCurrencyStatusUseCase.invoke(
|
||||
userWalletId = userWalletId,
|
||||
id = cryptoCurrency.id,
|
||||
refresh = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -83,6 +88,7 @@ internal class DefaultTokenDetailsDeepLinkHandler @AssistedInject constructor(
|
|||
override fun create(
|
||||
coroutineScope: CoroutineScope,
|
||||
queryParams: Map<String, String>,
|
||||
isFromOnNewIntent: Boolean,
|
||||
): DefaultTokenDetailsDeepLinkHandler
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue