Updated on 2026-08-14
This commit is contained in:
parent
b004f8df6b
commit
1964b3cfad
22 changed files with 204 additions and 173 deletions
|
|
@ -16,14 +16,6 @@ object TangemBlogUrlBuilder {
|
|||
|
||||
val path: String
|
||||
|
||||
data object SeedNotify : Post {
|
||||
override val path: String = "seed-notify"
|
||||
}
|
||||
|
||||
data object SeedNotifySecond : Post {
|
||||
override val path: String = "tangem-resolves-log-issue"
|
||||
}
|
||||
|
||||
data object SeedPhraseRiskySolution : Post {
|
||||
override val path: String = "seed-phrase-faq"
|
||||
}
|
||||
|
|
@ -39,5 +31,21 @@ object TangemBlogUrlBuilder {
|
|||
data object HowToScan : Post {
|
||||
override val path: String = "scan-tangem-card"
|
||||
}
|
||||
|
||||
data object HowToStake : Post {
|
||||
override val path: String = "how-to-stake-cryptocurrency"
|
||||
}
|
||||
|
||||
data object GiveRevokePermission : Post {
|
||||
override val path: String = "give-revoke-permission"
|
||||
}
|
||||
|
||||
data object HowYieldModeWorks : Post {
|
||||
override val path: String = "yield-mode"
|
||||
}
|
||||
|
||||
data object AboutCrossChainBridges : Post {
|
||||
override val path: String = "an-overview-of-cross-chain-bridges"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ object SupportedLanguages {
|
|||
const val CHINESE = "zh"
|
||||
const val SPANISH = "es"
|
||||
|
||||
val supportedLangugeCodes = listOf(
|
||||
val supportedLanguageCodes = listOf(
|
||||
ENGLISH,
|
||||
RUSSIAN,
|
||||
GERMAN,
|
||||
|
|
@ -25,10 +25,17 @@ object SupportedLanguages {
|
|||
SPANISH,
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns the ISO 639-1 code of the device's current language when it belongs to
|
||||
* [supportedLanguageCodes], otherwise falls back to [ENGLISH].
|
||||
*
|
||||
* Intended for callers that need a plain two-letter language code (e.g. URL path segments
|
||||
* like `tangem.com/{en|ru}/...`).
|
||||
*/
|
||||
fun getCurrentSupportedLanguageCode(): String {
|
||||
val locale = Locale.getDefault()
|
||||
|
||||
return if (supportedLangugeCodes.contains(locale.language)) {
|
||||
return if (supportedLanguageCodes.contains(locale.language)) {
|
||||
locale.language
|
||||
} else {
|
||||
ENGLISH
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
package com.tangem.utils
|
||||
|
||||
import java.util.Locale
|
||||
|
||||
@Deprecated("Use TangemBlogUrlBuilder from common module")
|
||||
object TangemBlogUrlBuilder {
|
||||
|
||||
private const val RU_LOCALE = "ru"
|
||||
private const val EN_LOCALE = "en"
|
||||
|
||||
private const val TANGEM_MAIN = "https://tangem.com/"
|
||||
|
||||
val FEE_BLOG_LINK: String
|
||||
get(): String {
|
||||
val locale = if (Locale.getDefault().language == RU_LOCALE) RU_LOCALE else EN_LOCALE
|
||||
return buildString {
|
||||
append(TANGEM_MAIN)
|
||||
append(locale)
|
||||
append("/blog/post/what-is-a-transaction-fee-and-why-do-we-need-it/")
|
||||
}
|
||||
}
|
||||
|
||||
const val RESOURCE_TO_LEARN_ABOUT_APPROVING_IN_SWAP = "https://tangem.com/en/blog/post/give-revoke-permission/"
|
||||
|
||||
const val YIELD_SUPPLY_HOW_IT_WORKS_URL = "https://tangem.com/en/blog/post/yield-mode"
|
||||
const val YIELD_SUPPLY_TOS_URL = "https://aave.com/terms-of-service"
|
||||
const val YIELD_SUPPLY_PRIVACY_URL = "https://aave.com/privacy-policy"
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
package com.tangem.utils
|
||||
|
||||
import com.google.common.truth.Truth
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import java.util.Locale
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class SupportedLanguagesTest {
|
||||
|
||||
private lateinit var originalLocale: Locale
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
originalLocale = Locale.getDefault()
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun tearDown() {
|
||||
Locale.setDefault(originalLocale)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getCurrentSupportedLanguageCode returns primary language when locale is supported`() {
|
||||
// Arrange
|
||||
Locale.setDefault(Locale("en", "US"))
|
||||
|
||||
// Act
|
||||
val actual = SupportedLanguages.getCurrentSupportedLanguageCode()
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).isEqualTo("en")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getCurrentSupportedLanguageCode drops region for supported language`() {
|
||||
// Arrange
|
||||
Locale.setDefault(Locale("zh", "CN"))
|
||||
|
||||
// Act
|
||||
val actual = SupportedLanguages.getCurrentSupportedLanguageCode()
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).isEqualTo("zh")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getCurrentSupportedLanguageCode returns ENGLISH when locale is not supported`() {
|
||||
// Arrange — pt (Portuguese) is not in supportedLanguageCodes
|
||||
Locale.setDefault(Locale("pt", "BR"))
|
||||
|
||||
// Act
|
||||
val actual = SupportedLanguages.getCurrentSupportedLanguageCode()
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).isEqualTo(SupportedLanguages.ENGLISH)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getCurrentSupportedLanguageCode returns ENGLISH for empty language`() {
|
||||
// Arrange
|
||||
Locale.setDefault(Locale("", ""))
|
||||
|
||||
// Act
|
||||
val actual = SupportedLanguages.getCurrentSupportedLanguageCode()
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).isEqualTo(SupportedLanguages.ENGLISH)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getCurrentSupportedLanguageCode supports every code in supportedLanguageCodes`() {
|
||||
SupportedLanguages.supportedLanguageCodes.forEach { code ->
|
||||
// Arrange
|
||||
Locale.setDefault(Locale(code))
|
||||
|
||||
// Act
|
||||
val actual = SupportedLanguages.getCurrentSupportedLanguageCode()
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).isEqualTo(code)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `supportedLanguageCodes contains the expected nine ISO 639-1 codes`() {
|
||||
// Assert
|
||||
Truth.assertThat(SupportedLanguages.supportedLanguageCodes)
|
||||
.containsExactly("en", "ru", "de", "fr", "it", "ja", "uk", "zh", "es")
|
||||
.inOrder()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
package com.tangem.data.common.locale
|
||||
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultLocaleProvider : LocaleProvider {
|
||||
|
||||
override fun getLocale(): Locale {
|
||||
return Locale.getDefault()
|
||||
}
|
||||
|
||||
override fun getWebUriLocaleLanguage(): String {
|
||||
val language = getLocale().language
|
||||
return if (LOCALE_LANG_RU.equals(language, true) || LOCALE_LANG_BY.equals(language, true)) {
|
||||
LOCALE_LANG_RU
|
||||
} else {
|
||||
LOCALE_LANG_EN
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val LOCALE_LANG_RU = "ru"
|
||||
const val LOCALE_LANG_BY = "by"
|
||||
const val LOCALE_LANG_EN = "en"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
package com.tangem.data.common.locale
|
||||
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface LocaleProvider {
|
||||
|
||||
fun getLocale(): Locale
|
||||
|
||||
fun getWebUriLocaleLanguage(): String
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
package com.tangem.data.common.locale.di
|
||||
|
||||
import com.tangem.data.common.locale.DefaultLocaleProvider
|
||||
import com.tangem.data.common.locale.LocaleProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object LocaleProviderModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideCacheRegistry(): LocaleProvider {
|
||||
return DefaultLocaleProvider()
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import com.tangem.blockchain.common.TransactionData
|
|||
import com.tangem.blockchain.common.TransactionSender.MultipleTransactionSendMode
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.common.TangemBlogUrlBuilder
|
||||
import com.tangem.common.ui.bottomsheet.permission.state.ApproveType
|
||||
import com.tangem.common.ui.userwallet.ext.walletInterationIcon
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
|
|
@ -16,10 +17,7 @@ import com.tangem.core.analytics.models.Basic
|
|||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.message.DialogMessage
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
|
|
@ -37,7 +35,6 @@ import com.tangem.features.approval.api.GiveApprovalComponent
|
|||
import com.tangem.features.send.v2.api.callbacks.FeeSelectorModelCallback
|
||||
import com.tangem.features.send.v2.api.entity.FeeItem
|
||||
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
|
||||
import com.tangem.utils.TangemBlogUrlBuilder.RESOURCE_TO_LEARN_ABOUT_APPROVING_IN_SWAP
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
|
@ -61,7 +58,6 @@ internal class GiveApprovalModel @Inject constructor(
|
|||
private val getFeeForGaslessUseCase: GetFeeForGaslessUseCase,
|
||||
private val getFeeForTokenUseCase: GetFeeForTokenUseCase,
|
||||
private val createAndSendGaslessTransactionUseCase: CreateAndSendGaslessTransactionUseCase,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
private val urlOpener: UrlOpener,
|
||||
private val getUserWalletUseCase: GetUserWalletUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
|
|
@ -119,16 +115,9 @@ internal class GiveApprovalModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun onOpenLearnMoreAboutApproveClick() {
|
||||
urlOpener.openUrl(RESOURCE_TO_LEARN_ABOUT_APPROVING_IN_SWAP)
|
||||
modelScope.launch {
|
||||
urlOpener.openUrl(TangemBlogUrlBuilder.build(TangemBlogUrlBuilder.Post.GiveRevokePermission))
|
||||
}
|
||||
|
||||
fun showPermissionInfoDialog() {
|
||||
uiMessageSender.send(
|
||||
DialogMessage(
|
||||
message = resourceReference(com.tangem.common.ui.R.string.give_permission_staking_footer),
|
||||
title = resourceReference(com.tangem.common.ui.R.string.common_approve),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun loadFee(): Either<GetFeeError, TransactionFee> {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
package com.tangem.features.details.model
|
||||
|
||||
import android.content.res.Resources
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
|
|
@ -37,6 +35,7 @@ import com.tangem.features.details.utils.ItemsBuilder
|
|||
import com.tangem.features.details.utils.SocialsBuilder
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.info.AppInfoProvider
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
|
|
@ -44,7 +43,6 @@ import kotlinx.coroutines.flow.onEach
|
|||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
|
|
@ -270,13 +268,4 @@ internal class DetailsModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun getAppVersion(): String = "${appInfoProvider.appVersion} (${appInfoProvider.appVersionCode})"
|
||||
|
||||
private companion object {
|
||||
val SYSTEM_LANGUAGE = runCatching { Resources.getSystem().configuration.locales[0].language }.getOrElse { "" }
|
||||
val APP_LANGUAGE = Locale.getDefault().language
|
||||
val UTM_MARKS = "utm_source=tangem-app" +
|
||||
"&utm_medium=app" +
|
||||
"&utm_campaign=users-$SYSTEM_LANGUAGE" +
|
||||
"&utm_content=devicelang-$APP_LANGUAGE"
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import com.arkivanov.decompose.router.slot.dismiss
|
|||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.common.TangemBlogUrlBuilder
|
||||
import com.tangem.common.getValidatorsCount
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.ui.amountScreen.converters.AmountReduceByTransformer.ReduceByData
|
||||
|
|
@ -95,7 +96,6 @@ import com.tangem.features.staking.impl.presentation.state.utils.isSingleAction
|
|||
import com.tangem.features.staking.impl.presentation.state.utils.withStubUnstakeAction
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isTon
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.TangemBlogUrlBuilder.RESOURCE_TO_LEARN_ABOUT_APPROVING_IN_SWAP
|
||||
import com.tangem.utils.coroutines.*
|
||||
import com.tangem.utils.extensions.isSingleItem
|
||||
import com.tangem.utils.extensions.orZero
|
||||
|
|
@ -603,7 +603,9 @@ internal class StakingModel @Inject constructor(
|
|||
|
||||
override fun onInitialInfoBannerClick() {
|
||||
analyticsEventHandler.send(StakingAnalyticsEvent.WhatIsStaking())
|
||||
innerRouter.openUrl(WHAT_IS_STAKING_ARTICLE_URL)
|
||||
modelScope.launch {
|
||||
innerRouter.openUrl(TangemBlogUrlBuilder.build(TangemBlogUrlBuilder.Post.HowToStake))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onInfoClick(infoType: InfoType) {
|
||||
|
|
@ -1100,7 +1102,9 @@ internal class StakingModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onOpenLearnMoreAboutApproveClick() {
|
||||
urlOpener.openUrl(RESOURCE_TO_LEARN_ABOUT_APPROVING_IN_SWAP)
|
||||
modelScope.launch {
|
||||
urlOpener.openUrl(TangemBlogUrlBuilder.build(TangemBlogUrlBuilder.Post.GiveRevokePermission))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivateTonAccountNotificationClick() {
|
||||
|
|
@ -1495,7 +1499,6 @@ internal class StakingModel @Inject constructor(
|
|||
}
|
||||
|
||||
private companion object {
|
||||
const val WHAT_IS_STAKING_ARTICLE_URL = "https://tangem.com/en/blog/post/how-to-stake-cryptocurrency/"
|
||||
const val ALLOWANCE_UPDATE_DELAY = 10_000L
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.staking.impl.presentation.model
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.common.TangemBlogUrlBuilder
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.core.ui.haptic.TangemHapticEffect
|
||||
import com.tangem.core.ui.message.DialogMessage
|
||||
|
|
@ -300,21 +301,24 @@ internal class StakingModelNavigationTest : StakingModelTestBase() {
|
|||
|
||||
@Test
|
||||
fun `WHEN onInitialInfoBannerClick THEN analytics sent and url opened`() = runTest {
|
||||
val expectedUrl = "https://tangem.com/blog/post/how-to-stake-cryptocurrency/?utm_source=tangem-app"
|
||||
mockkObject(TangemBlogUrlBuilder)
|
||||
coEvery { TangemBlogUrlBuilder.build(TangemBlogUrlBuilder.Post.HowToStake) } returns expectedUrl
|
||||
every { innerRouter.openUrl(any()) } just Runs
|
||||
|
||||
val model = createModel(testScope = this)
|
||||
advanceUntilIdle()
|
||||
|
||||
model.onInitialInfoBannerClick()
|
||||
advanceUntilIdle()
|
||||
|
||||
verify {
|
||||
analyticsEventHandler.send(match { it is StakingAnalyticsEvent.WhatIsStaking })
|
||||
}
|
||||
verify {
|
||||
innerRouter.openUrl("https://tangem.com/en/blog/post/how-to-stake-cryptocurrency/")
|
||||
}
|
||||
verify { innerRouter.openUrl(expectedUrl) }
|
||||
|
||||
model.onDestroy()
|
||||
unmockkObject(TangemBlogUrlBuilder)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -478,15 +482,20 @@ internal class StakingModelNavigationTest : StakingModelTestBase() {
|
|||
|
||||
@Test
|
||||
fun `WHEN onOpenLearnMoreAboutApproveClick THEN urlOpener opens approve url`() = runTest {
|
||||
val expectedUrl = "https://tangem.com/blog/post/give-revoke-permission/?utm_source=tangem-app"
|
||||
mockkObject(TangemBlogUrlBuilder)
|
||||
coEvery { TangemBlogUrlBuilder.build(TangemBlogUrlBuilder.Post.GiveRevokePermission) } returns expectedUrl
|
||||
every { urlOpener.openUrl(any()) } just Runs
|
||||
|
||||
val model = createModel(testScope = this)
|
||||
advanceUntilIdle()
|
||||
|
||||
model.onOpenLearnMoreAboutApproveClick()
|
||||
advanceUntilIdle()
|
||||
|
||||
verify { urlOpener.openUrl("https://tangem.com/en/blog/post/give-revoke-permission/") }
|
||||
verify { urlOpener.openUrl(expectedUrl) }
|
||||
|
||||
unmockkObject(TangemBlogUrlBuilder)
|
||||
model.onDestroy()
|
||||
}
|
||||
}
|
||||
|
|
@ -96,6 +96,7 @@ import com.tangem.feature.swap.utils.getContractAddress
|
|||
import com.tangem.features.approval.api.GiveApprovalComponent
|
||||
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
|
||||
import com.tangem.features.send.v2.api.subcomponents.feeSelector.FeeSelectorReloadTrigger
|
||||
import com.tangem.common.TangemBlogUrlBuilder
|
||||
import com.tangem.features.swap.SwapComponent
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.*
|
||||
|
|
@ -1357,13 +1358,17 @@ internal class SwapModel @Inject constructor(
|
|||
val selectedFee = (getSelectedFee() as? TxFee.Legacy)?.feeType ?: FeeType.NORMAL
|
||||
val txFeeState =
|
||||
dataState.getCurrentLoadedSwapState()?.txFee as? TxFeeState.MultipleFeeState ?: return@UiActions
|
||||
modelScope.launch {
|
||||
val readMoreUrl = TangemBlogUrlBuilder.build(TangemBlogUrlBuilder.Post.WhatIsTransactionFee)
|
||||
uiState = stateBuilder.showSelectFeeBottomSheet(
|
||||
uiState = uiState,
|
||||
selectedFee = selectedFee,
|
||||
txFeeState = txFeeState,
|
||||
readMoreUrl = readMoreUrl,
|
||||
) {
|
||||
uiState = stateBuilder.dismissBottomSheet(uiState)
|
||||
}
|
||||
}
|
||||
},
|
||||
onSelectFeeType = { txFee ->
|
||||
uiState = stateBuilder.dismissBottomSheet(uiState)
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ import com.tangem.utils.Provider
|
|||
import com.tangem.utils.StringsSigns
|
||||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||
import com.tangem.utils.StringsSigns.TILDE_SIGN
|
||||
import com.tangem.utils.TangemBlogUrlBuilder.FEE_BLOG_LINK
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
|
@ -984,6 +983,7 @@ internal class StateBuilder(
|
|||
uiState: SwapStateHolder,
|
||||
selectedFee: FeeType,
|
||||
txFeeState: TxFeeState.MultipleFeeState,
|
||||
readMoreUrl: String,
|
||||
onDismiss: () -> Unit,
|
||||
): SwapStateHolder {
|
||||
val config = ChooseFeeBottomSheetConfig(
|
||||
|
|
@ -995,7 +995,7 @@ internal class StateBuilder(
|
|||
}
|
||||
actions.onSelectFeeType.invoke(selectedItem)
|
||||
},
|
||||
readMoreUrl = FEE_BLOG_LINK,
|
||||
readMoreUrl = readMoreUrl,
|
||||
feeItems = txFeeState.toFeeItemState(),
|
||||
readMore = resourceReference(R.string.common_read_more),
|
||||
onReadMoreClick = actions.onLinkClick,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.model
|
|||
|
||||
import androidx.compose.runtime.Stable
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.TangemBlogUrlBuilder
|
||||
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionsBlockState
|
||||
|
|
@ -114,6 +115,12 @@ internal class ExpressTransactionsModel @Inject constructor(
|
|||
router.openUrl(url)
|
||||
}
|
||||
|
||||
override fun onReadAboutCrossChainBridgesClick() {
|
||||
modelScope.launch {
|
||||
router.openUrl(TangemBlogUrlBuilder.build(TangemBlogUrlBuilder.Post.AboutCrossChainBridges))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConfirmDisposeExpressStatus() {
|
||||
uiMessageSender.send(
|
||||
DialogMessage(
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ interface ExpressTransactionsClickIntents {
|
|||
|
||||
fun onOpenUrlClick(url: String)
|
||||
|
||||
fun onReadAboutCrossChainBridgesClick()
|
||||
|
||||
fun onConfirmDisposeExpressStatus()
|
||||
|
||||
fun onDisposeExpressStatus()
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import com.tangem.domain.dynamicaddresses.DynamicAddressesDerivationChecker
|
|||
import com.tangem.domain.dynamicaddresses.DynamicAddressesFeatureToggles
|
||||
import com.tangem.domain.dynamicaddresses.DynamicAddressesSupportedBlockchains
|
||||
import com.tangem.domain.dynamicaddresses.IsXpubSupportedUseCase
|
||||
import com.tangem.common.TangemBlogUrlBuilder
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.ui.bottomsheet.receive.AddressModel
|
||||
|
|
@ -960,6 +961,12 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
router.openUrl(url)
|
||||
}
|
||||
|
||||
override fun onReadAboutCrossChainBridgesClick() {
|
||||
modelScope.launch {
|
||||
router.openUrl(TangemBlogUrlBuilder.build(TangemBlogUrlBuilder.Post.AboutCrossChainBridges))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSwapPromoDismiss(promoId: PromoId) {
|
||||
modelScope.launch(dispatchers.main) {
|
||||
shouldShowPromoTokenUseCase.neverToShow(promoId)
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ import kotlinx.collections.immutable.persistentListOf
|
|||
import kotlinx.collections.immutable.toPersistentList
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import java.math.BigDecimal
|
||||
import java.util.Locale
|
||||
|
||||
// Fixme [REDACTED_JIRA]
|
||||
@Suppress("LargeClass")
|
||||
|
|
@ -232,7 +231,7 @@ internal class TokenDetailsSwapTransactionsStateConverter(
|
|||
} else {
|
||||
ExchangeStatusNotification.TokenRefunded(
|
||||
cryptoCurrency = refundToken,
|
||||
onReadMoreClick = { clickIntents.onOpenUrlClick(url = getAboutCrossChainBridgesLink()) },
|
||||
onReadMoreClick = clickIntents::onReadAboutCrossChainBridgesClick,
|
||||
onGoToTokenClick = { clickIntents.onGoToRefundedTokenClick(refundToken) },
|
||||
)
|
||||
}
|
||||
|
|
@ -424,12 +423,4 @@ internal class TokenDetailsSwapTransactionsStateConverter(
|
|||
isDone = isSendingDone,
|
||||
)
|
||||
}
|
||||
|
||||
private fun getAboutCrossChainBridgesLink(): String {
|
||||
return if (Locale.getDefault().country == "RU") {
|
||||
"https://tangem.com/ru/blog/post/an-overview-of-cross-chain-bridges/"
|
||||
} else {
|
||||
"https://tangem.com/en/blog/post/an-overview-of-cross-chain-bridges/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ import com.domain.blockaid.models.transaction.SimulationResult
|
|||
import com.domain.blockaid.models.transaction.ValidationResult
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.common.TangemBlogUrlBuilder
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
|
|
@ -59,7 +60,6 @@ import com.tangem.features.walletconnect.transaction.entity.send.WcSendTransacti
|
|||
import com.tangem.features.walletconnect.transaction.routes.WcTransactionRoutes
|
||||
import com.tangem.features.walletconnect.transaction.ui.blockaid.WcSendAndReceiveBlockAidUiConverter
|
||||
import com.tangem.features.walletconnect.utils.WcNotificationsFactory
|
||||
import com.tangem.utils.SupportedLanguages
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -301,14 +301,10 @@ internal class WcSendTransactionModel @Inject constructor(
|
|||
stackNavigation.pop()
|
||||
}
|
||||
|
||||
@Deprecated("Use TangemBlockUrlBuilder instead")
|
||||
private fun onApproveLearnMoreClick() {
|
||||
val code = SupportedLanguages.getCurrentSupportedLanguageCode()
|
||||
.takeIf { it == SupportedLanguages.RUSSIAN }
|
||||
?: SupportedLanguages.ENGLISH
|
||||
|
||||
val url = "https://tangem.com/$code/blog/post/give-revoke-permission/"
|
||||
urlOpener.openUrl(url)
|
||||
modelScope.launch {
|
||||
urlOpener.openUrl(TangemBlogUrlBuilder.build(TangemBlogUrlBuilder.Post.GiveRevokePermission))
|
||||
}
|
||||
}
|
||||
|
||||
private fun isMultipleSignRequired(useCase: WcSignUseCase<*>): Boolean {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import arrow.core.getOrElse
|
|||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.arkivanov.decompose.router.slot.dismiss
|
||||
import com.tangem.common.TangemBlogUrlBuilder
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
|
|
@ -34,13 +35,12 @@ import com.tangem.features.yield.supply.impl.active.model.transformers.YieldSupp
|
|||
import com.tangem.features.yield.supply.impl.subcomponents.approve.YieldSupplyApproveComponent
|
||||
import com.tangem.features.yield.supply.impl.subcomponents.stopearning.YieldSupplyStopEarningComponent
|
||||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||
import com.tangem.utils.TangemBlogUrlBuilder
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import com.tangem.utils.transformer.update
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList", "LargeClass")
|
||||
|
|
@ -160,7 +160,9 @@ internal class YieldSupplyActiveModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun onReadMoreClick() {
|
||||
urlOpener.openUrl(TangemBlogUrlBuilder.YIELD_SUPPLY_HOW_IT_WORKS_URL)
|
||||
modelScope.launch {
|
||||
urlOpener.openUrl(TangemBlogUrlBuilder.build(TangemBlogUrlBuilder.Post.HowYieldModeWorks))
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeOnCurrencyStatusUpdates() {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.features.yield.supply.impl.promo.model
|
|||
|
||||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.tangem.common.TangemBlogUrlBuilder
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
|
|
@ -11,13 +12,12 @@ import com.tangem.core.navigation.url.UrlOpener
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyPromoComponent
|
||||
import com.tangem.features.yield.supply.impl.R
|
||||
import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics
|
||||
import com.tangem.features.yield.supply.impl.R
|
||||
import com.tangem.features.yield.supply.impl.promo.YieldSupplyPromoConfig
|
||||
import com.tangem.features.yield.supply.impl.promo.entity.YieldSupplyPromoUM
|
||||
import com.tangem.utils.TangemBlogUrlBuilder
|
||||
import com.tangem.utils.TangemBlogUrlBuilder.YIELD_SUPPLY_HOW_IT_WORKS_URL
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
|
|
@ -32,8 +32,8 @@ internal class YieldSupplyPromoModel @Inject constructor(
|
|||
val params: YieldSupplyPromoComponent.Params = paramsContainer.require()
|
||||
|
||||
val uiState: YieldSupplyPromoUM = YieldSupplyPromoUM(
|
||||
tosLink = TangemBlogUrlBuilder.YIELD_SUPPLY_TOS_URL,
|
||||
policyLink = TangemBlogUrlBuilder.YIELD_SUPPLY_PRIVACY_URL,
|
||||
tosLink = AAVE_TOS_URL,
|
||||
policyLink = AAVE_PRIVACY_URL,
|
||||
tokenSymbol = params.currency.symbol,
|
||||
title = resourceReference(
|
||||
R.string.yield_module_promo_screen_title_v2,
|
||||
|
|
@ -69,10 +69,17 @@ internal class YieldSupplyPromoModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onHowItWorksClick() {
|
||||
urlOpener.openUrl(YIELD_SUPPLY_HOW_IT_WORKS_URL)
|
||||
modelScope.launch {
|
||||
urlOpener.openUrl(TangemBlogUrlBuilder.build(TangemBlogUrlBuilder.Post.HowYieldModeWorks))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartEarningClick() {
|
||||
bottomSheetNavigation.activate(YieldSupplyPromoConfig.Action)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val AAVE_TOS_URL = "https://aave.com/terms-of-service"
|
||||
const val AAVE_PRIVACY_URL = "https://aave.com/privacy-policy"
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package com.tangem.features.yield.supply.impl.subcomponents.approve.model
|
|||
import arrow.core.getOrElse
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.common.TangemBlogUrlBuilder
|
||||
import com.tangem.common.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
|
|
@ -39,7 +40,6 @@ import com.tangem.features.yield.supply.impl.subcomponents.approve.YieldSupplyAp
|
|||
import com.tangem.features.yield.supply.impl.subcomponents.notifications.YieldSupplyNotificationsComponent
|
||||
import com.tangem.features.yield.supply.impl.subcomponents.notifications.YieldSupplyNotificationsUpdateTrigger
|
||||
import com.tangem.features.yield.supply.impl.subcomponents.notifications.entity.YieldSupplyNotificationData
|
||||
import com.tangem.utils.TangemBlogUrlBuilder
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import com.tangem.utils.transformer.update
|
||||
|
|
@ -113,7 +113,9 @@ internal class YieldSupplyApproveModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun onReadMoreClick() {
|
||||
urlOpener.openUrl(TangemBlogUrlBuilder.FEE_BLOG_LINK)
|
||||
modelScope.launch {
|
||||
urlOpener.openUrl(TangemBlogUrlBuilder.build(TangemBlogUrlBuilder.Post.WhatIsTransactionFee))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFeeReload() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.yield.supply.impl.subcomponents.stopearning.model
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.TangemBlogUrlBuilder
|
||||
import com.tangem.common.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
|
|
@ -39,7 +40,6 @@ import com.tangem.features.yield.supply.impl.subcomponents.notifications.YieldSu
|
|||
import com.tangem.features.yield.supply.impl.subcomponents.notifications.entity.YieldSupplyNotificationData
|
||||
import com.tangem.features.yield.supply.impl.subcomponents.stopearning.YieldSupplyStopEarningComponent
|
||||
import com.tangem.features.yield.supply.impl.subcomponents.stopearning.model.transformer.YieldSupplyStopEarningFeeContentTransformer
|
||||
import com.tangem.utils.TangemBlogUrlBuilder
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
|
|
@ -128,7 +128,9 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun onReadMoreClick() {
|
||||
urlOpener.openUrl(TangemBlogUrlBuilder.FEE_BLOG_LINK)
|
||||
modelScope.launch {
|
||||
urlOpener.openUrl(TangemBlogUrlBuilder.build(TangemBlogUrlBuilder.Post.WhatIsTransactionFee))
|
||||
}
|
||||
}
|
||||
|
||||
fun onClick() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue