diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b61add5332..06a868e0a4 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -186,6 +186,28 @@
android:host="staking"
android:scheme="tangem" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/tangem/tap/routing/utils/DeepLinkFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/DeepLinkFactory.kt
index 00e016b292..f33be6d875 100644
--- a/app/src/main/java/com/tangem/tap/routing/utils/DeepLinkFactory.kt
+++ b/app/src/main/java/com/tangem/tap/routing/utils/DeepLinkFactory.kt
@@ -5,6 +5,8 @@ import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.DeepLinkRoute
import com.tangem.common.routing.DeepLinkScheme
import com.tangem.feature.referral.api.deeplink.ReferralDeepLinkHandler
+import com.tangem.features.markets.deeplink.MarketsDeepLinkHandler
+import com.tangem.features.markets.deeplink.MarketsTokenDetailDeepLinkHandler
import com.tangem.features.onramp.deeplink.BuyDeepLinkHandler
import com.tangem.features.onramp.deeplink.OnrampDeepLinkHandler
import com.tangem.features.send.v2.api.deeplink.SellDeepLinkHandler
@@ -35,6 +37,8 @@ internal class DeepLinkFactory @Inject constructor(
private val walletDeepLink: WalletDeepLinkHandler.Factory,
private val tokenDetailsDeepLink: TokenDetailsDeepLinkHandler.Factory,
private val stakingDeepLink: StakingDeepLinkHandler.Factory,
+ private val marketsDeepLink: MarketsDeepLinkHandler.Factory,
+ private val marketsTokenDetailDeepLink: MarketsTokenDetailDeepLinkHandler.Factory,
) {
private val permittedAppRoute = MutableStateFlow(false)
@@ -109,6 +113,8 @@ internal class DeepLinkFactory @Inject constructor(
isFromOnNewIntent = isFromOnNewIntent,
)
DeepLinkRoute.Staking.host -> stakingDeepLink.create(coroutineScope, queryParams)
+ DeepLinkRoute.Markets.host -> marketsDeepLink.create()
+ DeepLinkRoute.MarketTokenDetail.host -> marketsTokenDetailDeepLink.create(coroutineScope, queryParams)
else -> {
Timber.i(
"""
diff --git a/app/src/test/kotlin/com/tangem/tap/routing/utils/DeepLinkFactoryTest.kt b/app/src/test/kotlin/com/tangem/tap/routing/utils/DeepLinkFactoryTest.kt
index 40a82fad7e..8078f58b05 100644
--- a/app/src/test/kotlin/com/tangem/tap/routing/utils/DeepLinkFactoryTest.kt
+++ b/app/src/test/kotlin/com/tangem/tap/routing/utils/DeepLinkFactoryTest.kt
@@ -3,6 +3,8 @@ package com.tangem.tap.routing.utils
import android.net.Uri
import com.tangem.common.routing.AppRoute
import com.tangem.feature.referral.api.deeplink.ReferralDeepLinkHandler
+import com.tangem.features.markets.deeplink.MarketsDeepLinkHandler
+import com.tangem.features.markets.deeplink.MarketsTokenDetailDeepLinkHandler
import com.tangem.features.onramp.deeplink.BuyDeepLinkHandler
import com.tangem.features.onramp.deeplink.OnrampDeepLinkHandler
import com.tangem.features.send.v2.api.deeplink.SellDeepLinkHandler
@@ -49,6 +51,12 @@ class DeepLinkFactoryTest {
private val stakingDeepLinkFactory = mockk(relaxed = true) {
every { create(any(), any()) } returns mockk()
}
+ private val marketsDeepLinkFactory = mockk(relaxed = true) {
+ every { create() } returns mockk()
+ }
+ private val marketsTokenDetailDeepLinkFactory = mockk(relaxed = true) {
+ every { create(any(), any()) } returns mockk()
+ }
private val mockedUri = mockk(relaxed = true)
private val isFromOnNewIntent: Boolean = false
@@ -65,6 +73,8 @@ class DeepLinkFactoryTest {
walletDeepLinkFactory,
tokenDetailsDeepLinkFactory,
stakingDeepLinkFactory,
+ marketsDeepLinkFactory,
+ marketsTokenDetailDeepLinkFactory,
)
@OptIn(ExperimentalCoroutinesApi::class)
@@ -220,13 +230,13 @@ class DeepLinkFactoryTest {
every { mockedUri.host } returns "staking"
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
advanceUntilIdle()
- verify {
- tokenDetailsDeepLinkFactory.create(
- eq(testScope),
- eq(mapOf("param" to "value")),
- eq(isFromOnNewIntent),
- )
- }
+ verify { stakingDeepLinkFactory.create(eq(testScope), eq(mapOf("param" to "value"))) }
+
+ // Test Market Token Detail
+ every { mockedUri.host } returns "token_chart"
+ deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
+ advanceUntilIdle()
+ verify { marketsTokenDetailDeepLinkFactory.create(eq(testScope), eq(mapOf("param" to "value"))) }
// Reset params
every { mockedUri.queryParameterNames } returns emptySet()
@@ -249,6 +259,12 @@ class DeepLinkFactoryTest {
deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
advanceUntilIdle()
verify { walletDeepLinkFactory.create() }
+
+ // Test Markets
+ every { mockedUri.host } returns "markets"
+ deepLinkFactory.handleDeeplink(mockedUri, testScope, isFromOnNewIntent)
+ advanceUntilIdle()
+ verify { marketsDeepLinkFactory.create() }
}
@Test
diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/DeepLinkRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/DeepLinkRoute.kt
index 3d7be7ec68..26a1ac0ce5 100644
--- a/common/routing/src/main/kotlin/com/tangem/common/routing/DeepLinkRoute.kt
+++ b/common/routing/src/main/kotlin/com/tangem/common/routing/DeepLinkRoute.kt
@@ -31,6 +31,14 @@ sealed class DeepLinkRoute {
data object Staking : DeepLinkRoute() {
override val host: String = "staking"
}
+
+ data object Markets : DeepLinkRoute() {
+ override val host: String = "markets"
+ }
+
+ data object MarketTokenDetail : DeepLinkRoute() {
+ override val host: String = "token_chart"
+ }
}
enum class DeepLinkScheme(val scheme: String) {
diff --git a/features/markets/api/src/main/kotlin/com/tangem/features/markets/deeplink/MarketsDeepLinkHandler.kt b/features/markets/api/src/main/kotlin/com/tangem/features/markets/deeplink/MarketsDeepLinkHandler.kt
new file mode 100644
index 0000000000..e88a78c729
--- /dev/null
+++ b/features/markets/api/src/main/kotlin/com/tangem/features/markets/deeplink/MarketsDeepLinkHandler.kt
@@ -0,0 +1,8 @@
+package com.tangem.features.markets.deeplink
+
+interface MarketsDeepLinkHandler {
+
+ interface Factory {
+ fun create(): MarketsDeepLinkHandler
+ }
+}
\ No newline at end of file
diff --git a/features/markets/api/src/main/kotlin/com/tangem/features/markets/deeplink/MarketsTokenDetailDeepLinkHandler.kt b/features/markets/api/src/main/kotlin/com/tangem/features/markets/deeplink/MarketsTokenDetailDeepLinkHandler.kt
new file mode 100644
index 0000000000..45ff62203c
--- /dev/null
+++ b/features/markets/api/src/main/kotlin/com/tangem/features/markets/deeplink/MarketsTokenDetailDeepLinkHandler.kt
@@ -0,0 +1,10 @@
+package com.tangem.features.markets.deeplink
+
+import kotlinx.coroutines.CoroutineScope
+
+interface MarketsTokenDetailDeepLinkHandler {
+
+ interface Factory {
+ fun create(coroutineScope: CoroutineScope, params: Map): MarketsTokenDetailDeepLinkHandler
+ }
+}
\ No newline at end of file
diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/deeplink/DefaultMarketsDeepLinkHandler.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/deeplink/DefaultMarketsDeepLinkHandler.kt
new file mode 100644
index 0000000000..e620aaae47
--- /dev/null
+++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/deeplink/DefaultMarketsDeepLinkHandler.kt
@@ -0,0 +1,20 @@
+package com.tangem.features.markets.deeplink
+
+import com.tangem.common.routing.AppRoute
+import com.tangem.common.routing.AppRouter
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+internal class DefaultMarketsDeepLinkHandler @AssistedInject constructor(
+ appRouter: AppRouter,
+) : MarketsDeepLinkHandler {
+
+ init {
+ appRouter.push(AppRoute.Markets)
+ }
+
+ @AssistedFactory
+ interface Factory : MarketsDeepLinkHandler.Factory {
+ override fun create(): DefaultMarketsDeepLinkHandler
+ }
+}
\ No newline at end of file
diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/deeplink/DefaultMarketsTokenDetailDeepLinkHandler.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/deeplink/DefaultMarketsTokenDetailDeepLinkHandler.kt
new file mode 100644
index 0000000000..5007ac70ab
--- /dev/null
+++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/deeplink/DefaultMarketsTokenDetailDeepLinkHandler.kt
@@ -0,0 +1,79 @@
+package com.tangem.features.markets.deeplink
+
+import arrow.core.getOrElse
+import com.tangem.common.routing.AppRoute
+import com.tangem.common.routing.AppRouter
+import com.tangem.data.common.currency.getTokenIconUrlFromDefaultHost
+import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
+import com.tangem.domain.appcurrency.model.AppCurrency
+import com.tangem.domain.markets.GetTokenMarketInfoUseCase
+import com.tangem.domain.markets.TokenMarketParams
+import com.tangem.domain.models.currency.CryptoCurrency
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import timber.log.Timber
+
+internal class DefaultMarketsTokenDetailDeepLinkHandler @AssistedInject constructor(
+ @Assisted scope: CoroutineScope,
+ @Assisted queryParams: Map,
+ appRouter: AppRouter,
+ getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
+ getTokenMarketInfoUseCase: GetTokenMarketInfoUseCase,
+) : MarketsTokenDetailDeepLinkHandler {
+
+ init {
+ val tokenId = queryParams[TOKEN_ID_KEY]
+
+ val rawTokenId = CryptoCurrency.RawID(tokenId.orEmpty())
+
+ scope.launch {
+ val appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse {
+ AppCurrency.Default
+ }
+ val tokenInfo = getTokenMarketInfoUseCase(
+ appCurrency = appCurrency,
+ tokenId = rawTokenId,
+ tokenSymbol = TOKEN_SYMBOL_KEY,
+ ).getOrElse {
+ Timber.e("Failed to get market token info")
+ return@launch
+ }
+
+ appRouter.push(
+ AppRoute.MarketsTokenDetails(
+ token = TokenMarketParams(
+ id = rawTokenId,
+ name = tokenInfo.name,
+ symbol = tokenInfo.symbol,
+ tokenQuotes = TokenMarketParams.Quotes(
+ currentPrice = tokenInfo.quotes.currentPrice,
+ h24Percent = tokenInfo.quotes.h24ChangePercent,
+ weekPercent = tokenInfo.quotes.weekChangePercent,
+ monthPercent = tokenInfo.quotes.monthChangePercent,
+ ),
+ imageUrl = getTokenIconUrlFromDefaultHost(rawTokenId),
+ ),
+ appCurrency = appCurrency,
+ showPortfolio = true,
+ analyticsParams = null,
+ ),
+ )
+ }
+ }
+
+ @AssistedFactory
+ interface Factory : MarketsTokenDetailDeepLinkHandler.Factory {
+ override fun create(
+ coroutineScope: CoroutineScope,
+ queryParams: Map,
+ ): DefaultMarketsTokenDetailDeepLinkHandler
+ }
+
+ private companion object {
+ const val TOKEN_ID_KEY = "token_id"
+ const val TOKEN_SYMBOL_KEY = "token_symbol"
+ }
+}
\ No newline at end of file
diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/deeplink/di/MarketsDeepLinkModule.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/deeplink/di/MarketsDeepLinkModule.kt
new file mode 100644
index 0000000000..168ea58a46
--- /dev/null
+++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/deeplink/di/MarketsDeepLinkModule.kt
@@ -0,0 +1,26 @@
+package com.tangem.features.markets.deeplink.di
+
+import com.tangem.features.markets.deeplink.DefaultMarketsDeepLinkHandler
+import com.tangem.features.markets.deeplink.DefaultMarketsTokenDetailDeepLinkHandler
+import com.tangem.features.markets.deeplink.MarketsDeepLinkHandler
+import com.tangem.features.markets.deeplink.MarketsTokenDetailDeepLinkHandler
+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 MarketsDeepLinkModule {
+
+ @Binds
+ @Singleton
+ fun bindMarketsDeepLinkHandlerFactory(impl: DefaultMarketsDeepLinkHandler.Factory): MarketsDeepLinkHandler.Factory
+
+ @Binds
+ @Singleton
+ fun bindMarketsTokenDetailDeepLinkHandlerFactory(
+ impl: DefaultMarketsTokenDetailDeepLinkHandler.Factory,
+ ): MarketsTokenDetailDeepLinkHandler.Factory
+}
\ No newline at end of file