From c763f84aadc4b8616bda0f17a20beef8600424ba Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 30 May 2025 19:28:40 +0500 Subject: [PATCH] Updated on 2026-08-14 --- app/src/main/AndroidManifest.xml | 22 ++++++ .../tap/routing/utils/DeepLinkFactory.kt | 6 ++ .../tap/routing/utils/DeepLinkFactoryTest.kt | 30 +++++-- .../tangem/common/routing/DeepLinkRoute.kt | 8 ++ .../deeplink/MarketsDeepLinkHandler.kt | 8 ++ .../MarketsTokenDetailDeepLinkHandler.kt | 10 +++ .../deeplink/DefaultMarketsDeepLinkHandler.kt | 20 +++++ ...efaultMarketsTokenDetailDeepLinkHandler.kt | 79 +++++++++++++++++++ .../deeplink/di/MarketsDeepLinkModule.kt | 26 ++++++ 9 files changed, 202 insertions(+), 7 deletions(-) create mode 100644 features/markets/api/src/main/kotlin/com/tangem/features/markets/deeplink/MarketsDeepLinkHandler.kt create mode 100644 features/markets/api/src/main/kotlin/com/tangem/features/markets/deeplink/MarketsTokenDetailDeepLinkHandler.kt create mode 100644 features/markets/impl/src/main/kotlin/com/tangem/features/markets/deeplink/DefaultMarketsDeepLinkHandler.kt create mode 100644 features/markets/impl/src/main/kotlin/com/tangem/features/markets/deeplink/DefaultMarketsTokenDetailDeepLinkHandler.kt create mode 100644 features/markets/impl/src/main/kotlin/com/tangem/features/markets/deeplink/di/MarketsDeepLinkModule.kt 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