From 82fa3edf458f9bf7b40a491a9c83fc5d08539eba Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 19 Dec 2025 14:16:53 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../com/tangem/common/TangemBlogUrlBuilder.kt | 23 +++++----- .../com/tangem/common/TangemSiteUrlBuilder.kt | 42 +++++++++++++++++++ .../com/tangem/utils/SupportedLanguages.kt | 2 +- .../com/tangem/utils/TangemBlogUrlBuilder.kt | 1 + domain/wallets/build.gradle.kts | 2 + .../GenerateBuyTangemCardLinkUseCase.kt | 29 ++++++------- .../CreateWalletStartModel.kt | 3 +- .../features/details/model/DetailsModel.kt | 4 +- .../features/home/impl/model/HomeModel.kt | 2 +- .../CreateHardwareWalletModel.kt | 3 +- .../upgradewallet/UpgradeWalletModel.kt | 3 +- .../walletbackup/model/WalletBackupModel.kt | 3 +- .../model/WalletHardwareBackupModel.kt | 3 +- features/onboarding-v2/impl/build.gradle.kts | 1 + .../model/MultiWalletSeedPhraseModel.kt | 7 +++- .../impl/child/seedphrase/model/Utils.kt | 28 ------------- .../tangem/feature/swap/ui/StateBuilder.kt | 1 + .../model/WcSendTransactionModel.kt | 1 + 18 files changed, 97 insertions(+), 61 deletions(-) create mode 100644 common/src/main/kotlin/com/tangem/common/TangemSiteUrlBuilder.kt delete mode 100644 features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/Utils.kt diff --git a/common/src/main/kotlin/com/tangem/common/TangemBlogUrlBuilder.kt b/common/src/main/kotlin/com/tangem/common/TangemBlogUrlBuilder.kt index 4966d2d7b0..0319e1c59f 100644 --- a/common/src/main/kotlin/com/tangem/common/TangemBlogUrlBuilder.kt +++ b/common/src/main/kotlin/com/tangem/common/TangemBlogUrlBuilder.kt @@ -1,20 +1,15 @@ package com.tangem.common -import com.tangem.utils.SupportedLanguages - /** [REDACTED_AUTHOR] */ object TangemBlogUrlBuilder { - fun build(post: Post): String { - val code = SupportedLanguages.getCurrentSupportedLanguageCode() - .takeIf { code -> - code == SupportedLanguages.RUSSIAN || code == SupportedLanguages.ENGLISH - } - ?: SupportedLanguages.ENGLISH - - return "https://tangem.com/$code/blog/post/${post.path}/" + suspend fun build(post: Post): String { + return TangemSiteUrlBuilder.url( + path = "/blog/post/${post.path}/", + campaign = "articles", + ) } sealed interface Post { @@ -28,5 +23,13 @@ object TangemBlogUrlBuilder { data object SeedNotifySecond : Post { override val path: String = "tangem-resolves-log-issue" } + + data object SeedPhraseRiskySolution : Post { + override val path: String = "seed-phrase-a-risky-solution" + } + + data object WhatWalletToChoose : Post { + override val path: String = "mobile-wallet" + } } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/tangem/common/TangemSiteUrlBuilder.kt b/common/src/main/kotlin/com/tangem/common/TangemSiteUrlBuilder.kt new file mode 100644 index 0000000000..573b95bdfb --- /dev/null +++ b/common/src/main/kotlin/com/tangem/common/TangemSiteUrlBuilder.kt @@ -0,0 +1,42 @@ +package com.tangem.common + +import android.content.res.Resources +import com.google.firebase.analytics.ktx.analytics +import com.google.firebase.ktx.Firebase +import java.util.Locale +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine + +object TangemSiteUrlBuilder { + + suspend fun getUtmTags(campaign: String?): String { + val langCode = Locale.getDefault().language + val utmCampaignPart = campaign?.let { "&utm_campaign=$it-$langCode" }.orEmpty() + val utmContent = deviceLang()?.let { "&utm_content=devicelang-$it" }.orEmpty() + val appInstanceIdPart = getAppInstanceId()?.let { "&app_instance_id=$it" }.orEmpty() + return "utm_source=tangem-app&utm_medium=app$utmCampaignPart$utmContent$appInstanceIdPart" + } + + suspend fun url(path: String, campaign: String): String { + val normalizedPath = path.trim('/') + return "https://tangem.com/$normalizedPath?${getUtmTags(campaign)}" + } + + private fun deviceLang(): String? { + return runCatching { + Resources.getSystem().configuration.locales.get(0).toLanguageTag() + }.getOrNull() + } + + private suspend fun getAppInstanceId(): String? { + return suspendCoroutine { cont -> + Firebase.analytics.appInstanceId + .addOnSuccessListener { id -> + cont.resume(id) + } + .addOnFailureListener { + cont.resume(null) + } + } + } +} \ No newline at end of file diff --git a/core/utils/src/main/java/com/tangem/utils/SupportedLanguages.kt b/core/utils/src/main/java/com/tangem/utils/SupportedLanguages.kt index b85a35b477..420547d13c 100644 --- a/core/utils/src/main/java/com/tangem/utils/SupportedLanguages.kt +++ b/core/utils/src/main/java/com/tangem/utils/SupportedLanguages.kt @@ -10,7 +10,7 @@ object SupportedLanguages { const val ITALIAN = "it" const val JAPANESE = "ja" const val UKRAINIAN = "uk" - const val CHINESE = "uk" + const val CHINESE = "zh" const val SPANISH = "es" val supportedLangugeCodes = listOf( diff --git a/core/utils/src/main/java/com/tangem/utils/TangemBlogUrlBuilder.kt b/core/utils/src/main/java/com/tangem/utils/TangemBlogUrlBuilder.kt index 5d8f4ba63f..d24267a527 100644 --- a/core/utils/src/main/java/com/tangem/utils/TangemBlogUrlBuilder.kt +++ b/core/utils/src/main/java/com/tangem/utils/TangemBlogUrlBuilder.kt @@ -2,6 +2,7 @@ package com.tangem.utils import java.util.Locale +@Deprecated("Use TangemBlogUrlBuilder from common module") object TangemBlogUrlBuilder { private const val RU_LOCALE = "ru" diff --git a/domain/wallets/build.gradle.kts b/domain/wallets/build.gradle.kts index a5779a9b3f..b7b3798d96 100644 --- a/domain/wallets/build.gradle.kts +++ b/domain/wallets/build.gradle.kts @@ -35,6 +35,8 @@ dependencies { implementation(projects.domain.hotWallet) // endregion + implementation(projects.common) + // region Tangem libraries implementation(tangemDeps.blockchain) // android-library implementation(tangemDeps.card.core) diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GenerateBuyTangemCardLinkUseCase.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GenerateBuyTangemCardLinkUseCase.kt index 7c80707cb6..7a7cac1d2b 100644 --- a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GenerateBuyTangemCardLinkUseCase.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GenerateBuyTangemCardLinkUseCase.kt @@ -1,23 +1,24 @@ package com.tangem.domain.wallets.usecase -import com.google.firebase.analytics.ktx.analytics -import com.google.firebase.ktx.Firebase -import kotlin.coroutines.resume -import kotlin.coroutines.suspendCoroutine +import com.tangem.common.TangemSiteUrlBuilder +import java.util.Locale class GenerateBuyTangemCardLinkUseCase { - suspend operator fun invoke(): String = suspendCoroutine { cont -> - Firebase.analytics.appInstanceId - .addOnSuccessListener { id -> - cont.resume("$NEW_BUY_WALLET_URL&app_instance_id=$id") - } - .addOnFailureListener { - cont.resume(NEW_BUY_WALLET_URL) - } + suspend operator fun invoke(source: Source): String { + return invoke(source.utmCampaign) } - companion object { - private const val NEW_BUY_WALLET_URL = "https://buy.tangem.com/?utm_source=tangem-app&utm_medium=app" + suspend operator fun invoke(utmCampaign: String?): String { + val langCode = Locale.getDefault().language + val utmTags = TangemSiteUrlBuilder.getUtmTags(utmCampaign) + return "https://buy.tangem.com/$langCode?$utmTags" + } + + enum class Source(val utmCampaign: String) { + Creation("prospect"), + Settings("users"), + Backup("backup"), + Upgrade("upgrade"), } } \ No newline at end of file diff --git a/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt b/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt index ef8ef65b13..8c7bb0d2eb 100644 --- a/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt +++ b/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt @@ -162,7 +162,8 @@ internal class CreateWalletStartModel @Inject constructor( private fun onBuyClick() { analyticsEventHandler.send(Basic.ButtonBuy(source = AnalyticsParam.ScreensSources.CreateWalletIntro)) modelScope.launch { - generateBuyTangemCardLinkUseCase.invoke().let { urlOpener.openUrl(it) } + generateBuyTangemCardLinkUseCase + .invoke(GenerateBuyTangemCardLinkUseCase.Source.Creation).let { urlOpener.openUrl(it) } } } diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt index f5d5d79eb5..b730125b22 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt @@ -232,8 +232,10 @@ internal class DetailsModel @Inject constructor( modelScope.launch { if (hotWalletFeatureToggles.isHotWalletEnabled) { analyticsEventHandler.send(Basic.ButtonBuy(source = AnalyticsParam.ScreensSources.Settings)) - generateBuyTangemCardLinkUseCase.invoke().let { urlOpener.openUrl(it) } + generateBuyTangemCardLinkUseCase + .invoke(GenerateBuyTangemCardLinkUseCase.Source.Settings).let { urlOpener.openUrl(it) } } else { + // This is incorrect implementation of buy link generation, but it is left here urlOpener.openUrl(buildBuyLink()) } } diff --git a/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/model/HomeModel.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/model/HomeModel.kt index 1dbc4c7a1f..e650912dc6 100644 --- a/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/model/HomeModel.kt +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/model/HomeModel.kt @@ -135,7 +135,7 @@ internal class HomeModel @Inject constructor( analyticsEventHandler.send(IntroductionProcess.ButtonBuyCards()) analyticsEventHandler.send(Shop.ScreenOpened()) modelScope.launch { - generateBuyTangemCardLinkUseCase.invoke().let { urlOpener.openUrl(it) } + generateBuyTangemCardLinkUseCase.invoke(null).let { urlOpener.openUrl(it) } } } diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/CreateHardwareWalletModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/CreateHardwareWalletModel.kt index 2d4b71b076..0373179468 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/CreateHardwareWalletModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/CreateHardwareWalletModel.kt @@ -78,7 +78,8 @@ internal class CreateHardwareWalletModel @Inject constructor( private fun onBuyTangemWalletClick() { analyticsEventHandler.send(Basic.ButtonBuy(source = AnalyticsParam.ScreensSources.CreateWallet)) modelScope.launch { - generateBuyTangemCardLinkUseCase.invoke().let { urlOpener.openUrl(it) } + generateBuyTangemCardLinkUseCase + .invoke(GenerateBuyTangemCardLinkUseCase.Source.Upgrade).let { urlOpener.openUrl(it) } } } diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/UpgradeWalletModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/UpgradeWalletModel.kt index 7b675b8238..c7252d49c4 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/UpgradeWalletModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/UpgradeWalletModel.kt @@ -94,7 +94,8 @@ internal class UpgradeWalletModel @Inject constructor( private fun onBuyTangemWalletClick() { analyticsEventHandler.send(Basic.ButtonBuy(source = AnalyticsParam.ScreensSources.Upgrade)) modelScope.launch { - generateBuyTangemCardLinkUseCase.invoke().let { urlOpener.openUrl(it) } + generateBuyTangemCardLinkUseCase + .invoke(GenerateBuyTangemCardLinkUseCase.Source.Upgrade).let { urlOpener.openUrl(it) } } } diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/model/WalletBackupModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/model/WalletBackupModel.kt index f1a729835a..bdc95378ca 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/model/WalletBackupModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/model/WalletBackupModel.kt @@ -132,7 +132,8 @@ internal class WalletBackupModel @Inject constructor( private fun onBuyClick() { analyticsEventHandler.send(Basic.ButtonBuy(source = AnalyticsParam.ScreensSources.Backup)) modelScope.launch { - generateBuyTangemCardLinkUseCase.invoke().let { urlOpener.openUrl(it) } + generateBuyTangemCardLinkUseCase + .invoke(GenerateBuyTangemCardLinkUseCase.Source.Backup).let { urlOpener.openUrl(it) } } } diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/wallethardwarebackup/model/WalletHardwareBackupModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/wallethardwarebackup/model/WalletHardwareBackupModel.kt index 31d5ebdf25..efcd39aa14 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/wallethardwarebackup/model/WalletHardwareBackupModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/wallethardwarebackup/model/WalletHardwareBackupModel.kt @@ -171,7 +171,8 @@ internal class WalletHardwareBackupModel @Inject constructor( private fun onBuyClick() { analyticsEventHandler.send(Basic.ButtonBuy(source = AnalyticsParam.ScreensSources.HardwareWallet)) modelScope.launch { - generateBuyTangemCardLinkUseCase.invoke().let { urlOpener.openUrl(it) } + generateBuyTangemCardLinkUseCase + .invoke(GenerateBuyTangemCardLinkUseCase.Source.Backup).let { urlOpener.openUrl(it) } } } diff --git a/features/onboarding-v2/impl/build.gradle.kts b/features/onboarding-v2/impl/build.gradle.kts index 7febfb81ba..a992e7daea 100644 --- a/features/onboarding-v2/impl/build.gradle.kts +++ b/features/onboarding-v2/impl/build.gradle.kts @@ -34,6 +34,7 @@ dependencies { /** Common */ implementation(projects.common.ui) implementation(projects.common.routing) + implementation(projects.common) /** Domain */ implementation(projects.domain.models) diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/MultiWalletSeedPhraseModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/MultiWalletSeedPhraseModel.kt index 0f18033dd3..3468f7a11c 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/MultiWalletSeedPhraseModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/MultiWalletSeedPhraseModel.kt @@ -3,6 +3,7 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.mode import androidx.compose.runtime.Stable import arrow.core.getOrElse import com.tangem.common.CompletionResult +import com.tangem.common.TangemBlogUrlBuilder import com.tangem.common.core.TangemSdkError import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam @@ -161,7 +162,11 @@ internal class MultiWalletSeedPhraseModel @Inject constructor( openGeneratedSeedPhrase() }, onLearnMoreClicked = { - urlOpener.openUrl(seedPhraseLearnMoreUrl()) + modelScope.launch { + urlOpener.openUrl( + TangemBlogUrlBuilder.build(TangemBlogUrlBuilder.Post.SeedPhraseRiskySolution), + ) + } }, ) } diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/Utils.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/Utils.kt deleted file mode 100644 index dbfeee4003..0000000000 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/Utils.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model - -import android.net.Uri -import com.tangem.utils.SupportedLanguages -import java.util.Locale - -// TODO: [REDACTED_JIRA] -internal fun seedPhraseLearnMoreUrl(): String { - val language = Locale.getDefault().language - - val languageBy = "by" - if (SupportedLanguages.RUSSIAN.equals(language, true) || - languageBy.equals(language, true) - ) { - SupportedLanguages.RUSSIAN - } else { - SupportedLanguages.ENGLISH - } - - val webUri = Uri.Builder() - .scheme("https") - .authority("tangem.com") - .appendPath(language) - .appendPath("blog/post/seed-phrase-a-risky-solution") - .build() - - return webUri.toString() -} \ No newline at end of file diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index 64ac9aa044..6ab1d4af06 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -1194,6 +1194,7 @@ internal class StateBuilder( ) } + @Deprecated("Use TangemBlockUrlBuilder instead") private fun buildReadMoreUrl(): String { return buildString { append(FEE_READ_MORE_URL_FIRST_PART) diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt index 611010e6f2..d305e4a233 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt @@ -297,6 +297,7 @@ internal class WcSendTransactionModel @Inject constructor( stackNavigation.pop() } + @Deprecated("Use TangemBlockUrlBuilder instead") private fun onApproveLearnMoreClick() { val code = SupportedLanguages.getCurrentSupportedLanguageCode() .takeIf { it == SupportedLanguages.RUSSIAN }