Updated on 2026-08-14
This commit is contained in:
commit
50fe9e603d
1919 changed files with 94940 additions and 15178 deletions
|
|
@ -10,31 +10,33 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
/* Core */
|
||||
implementation(projects.core.decompose)
|
||||
implementation(projects.core.configToggles)
|
||||
implementation(projects.core.utils)
|
||||
|
||||
/* Domain */
|
||||
implementation(projects.domain.qrScanning.models)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.wallets.models)
|
||||
implementation(projects.domain.staking)
|
||||
implementation(projects.domain.markets.models)
|
||||
implementation(projects.domain.onramp.models)
|
||||
implementation(projects.domain.appCurrency.models)
|
||||
implementation(projects.domain.nft.models)
|
||||
implementation(projects.domain.feedback.models)
|
||||
implementation(projects.domain.visa.models)
|
||||
|
||||
/* Libs - Other */
|
||||
// region Kotlin
|
||||
api(deps.kotlin.serialization)
|
||||
implementation(deps.androidx.core.ktx)
|
||||
// endregion
|
||||
|
||||
/* Tests */
|
||||
testImplementation(deps.test.junit5)
|
||||
// region Core
|
||||
api(projects.core.analytics.models)
|
||||
api(projects.core.decompose)
|
||||
api(projects.core.utils)
|
||||
// endregion
|
||||
|
||||
// region Domain
|
||||
api(projects.domain.appCurrency.models)
|
||||
api(projects.domain.feedback.models)
|
||||
api(projects.domain.markets.models)
|
||||
api(projects.domain.models)
|
||||
api(projects.domain.nft.models)
|
||||
api(projects.domain.onramp.models)
|
||||
api(projects.domain.staking)
|
||||
api(projects.domain.tokens.models)
|
||||
implementation(projects.domain.visa.models)
|
||||
// endregion
|
||||
|
||||
// region Tests
|
||||
testImplementation(deps.test.coroutine)
|
||||
testImplementation(deps.test.truth)
|
||||
testImplementation(deps.test.junit5)
|
||||
testImplementation(deps.test.mockk)
|
||||
testImplementation(deps.test.truth)
|
||||
// endregion
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import android.annotation.SuppressLint
|
|||
import android.os.Bundle
|
||||
import com.tangem.common.routing.bundle.RouteBundleParams
|
||||
import com.tangem.common.routing.bundle.bundle
|
||||
import com.tangem.common.routing.entity.AddressBookOpenMode
|
||||
import com.tangem.common.routing.entity.InitScreenLaunchMode
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.decompose.navigation.Route
|
||||
|
|
@ -100,9 +101,19 @@ sealed class AppRoute(val path: String) : Route {
|
|||
val userWalletId: UserWalletId,
|
||||
) : AppRoute(path = "/details/security")
|
||||
|
||||
/**
|
||||
* Support chat (Usedesk) screen.
|
||||
*
|
||||
* @property walletMetaInfo wallet meta info; its user wallet id is sent to Usedesk as the client email
|
||||
* @property source source of the chat opening (Settings by default, Swap for FR-02). Drives both
|
||||
* analytics and the Usedesk additional fields mapped by the component.
|
||||
* @property prefilledMessage optional message sent to the chat on behalf of the user right after init
|
||||
*/
|
||||
@Serializable
|
||||
data class Usedesk(
|
||||
val walletMetaInfo: WalletMetaInfo,
|
||||
val source: AnalyticsParam.ScreensSources = AnalyticsParam.ScreensSources.Settings,
|
||||
val prefilledMessage: String? = null,
|
||||
) : AppRoute(path = "/usedesk/${walletMetaInfo.userWalletId}")
|
||||
|
||||
@Serializable
|
||||
|
|
@ -175,8 +186,15 @@ sealed class AppRoute(val path: String) : Route {
|
|||
|
||||
@Serializable
|
||||
data class AddressBook(
|
||||
val predefinedAddress: String? = null,
|
||||
) : AppRoute(path = "/address_book/predefinedAddress/$predefinedAddress")
|
||||
val addressBookOpenMode: AddressBookOpenMode = AddressBookOpenMode.Default,
|
||||
) : AppRoute(
|
||||
path = when (addressBookOpenMode) {
|
||||
is AddressBookOpenMode.WithContactCreation ->
|
||||
"/address_book/${addressBookOpenMode.address}-${addressBookOpenMode.networkId}"
|
||||
is AddressBookOpenMode.ContactSelection -> "/address_book/select/${addressBookOpenMode.networkId}"
|
||||
AddressBookOpenMode.Default -> "/address_book"
|
||||
},
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class QrScanning(val source: Source) : AppRoute(path = "/$source/qr_scanning${source.path}") {
|
||||
|
|
@ -188,6 +206,7 @@ sealed class AppRoute(val path: String) : Route {
|
|||
is Send -> "/$networkName"
|
||||
WalletConnect -> ""
|
||||
MainScreen -> ""
|
||||
AddressBook -> ""
|
||||
}
|
||||
|
||||
data class Send(val networkName: String) : Source()
|
||||
|
|
@ -195,6 +214,8 @@ sealed class AppRoute(val path: String) : Route {
|
|||
data object WalletConnect : Source()
|
||||
|
||||
data object MainScreen : Source()
|
||||
|
||||
data object AddressBook : Source()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -325,11 +346,6 @@ sealed class AppRoute(val path: String) : Route {
|
|||
val userWalletId: UserWalletId,
|
||||
) : AppRoute(path = "/sell_crypto/${userWalletId.stringValue}")
|
||||
|
||||
@Serializable
|
||||
data class SwapCrypto(
|
||||
val userWalletId: UserWalletId,
|
||||
) : AppRoute(path = "/swap_crypto/${userWalletId.stringValue}")
|
||||
|
||||
/**
|
||||
* Onboarding V2
|
||||
* @property scanResponse scan response, determines onboarding route by the product type
|
||||
|
|
@ -503,12 +519,33 @@ sealed class AppRoute(val path: String) : Route {
|
|||
|
||||
@Serializable
|
||||
data object FromBannerInSettings : Mode()
|
||||
|
||||
@Serializable
|
||||
data object MobileOnboardingDeeplink : Mode()
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Kyc(val userWalletId: UserWalletId) : AppRoute(path = "/kyc")
|
||||
|
||||
@Serializable
|
||||
data class VirtualAccountOnboarding(
|
||||
val mode: Mode,
|
||||
) : AppRoute(path = "/virtual_account_onboarding/$mode") {
|
||||
|
||||
@Serializable
|
||||
sealed class Mode {
|
||||
@Serializable
|
||||
data class Deeplink(val userWalletId: UserWalletId, val deeplink: String) : Mode()
|
||||
|
||||
@Serializable
|
||||
data class FromMain(val userWalletId: UserWalletId) : Mode()
|
||||
|
||||
@Serializable
|
||||
data class FromDetailsScreen(val userWalletId: UserWalletId) : Mode()
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Survey(val token: String, val displayId: String? = null) : AppRoute(path = "/survey")
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,10 @@ sealed class DeepLinkRoute {
|
|||
override val host: String = "onboard-visa"
|
||||
}
|
||||
|
||||
data object OnboardVirtualAccounts : DeepLinkRoute() {
|
||||
override val host: String = "onboard-virtual-account"
|
||||
}
|
||||
|
||||
data object PayApp : DeepLinkRoute() {
|
||||
override val host: String = "tangem.com"
|
||||
}
|
||||
|
|
@ -91,6 +95,10 @@ sealed class DeepLinkRoute {
|
|||
data object Survey : DeepLinkRoute() {
|
||||
override val host: String = "survey"
|
||||
}
|
||||
|
||||
data object Campaigns : DeepLinkRoute() {
|
||||
override val host: String = "campaigns"
|
||||
}
|
||||
}
|
||||
|
||||
enum class DeepLinkScheme(val scheme: String) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ object DeeplinkConst {
|
|||
const val PROMO_CODE_KEY = "promo_code"
|
||||
const val REF_KEY = "ref"
|
||||
const val CAMPAIGN_KEY = "campaign"
|
||||
const val CAMPAIGN_ID_KEY = "campaignId"
|
||||
const val NAME_KEY = "name"
|
||||
const val ORDER_KEY = "order"
|
||||
const val INTERVAL_KEY = "interval"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
package com.tangem.common.routing.deeplink
|
||||
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.DeepLinkRoute
|
||||
import com.tangem.common.routing.DeepLinkScheme
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.onramp.model.OnrampSource
|
||||
import java.net.URI
|
||||
|
||||
/**
|
||||
* Classification of a marketing-banner deeplink used to decide how a banner tap is routed.
|
||||
*
|
||||
* Only the `tangem://` scheme with a swap/buy host triggers contextual in-app routing; everything
|
||||
* else (external `https://` T&S links, unknown hosts, malformed input) is [EXTERNAL] and handed off
|
||||
* to the generic deeplink launcher. This mirrors iOS `DefaultIncomingLinkParser`, where
|
||||
* `https://tangem.com/...` links always resolve to an external link, not an in-app destination.
|
||||
*/
|
||||
enum class MarketingDeeplink {
|
||||
/** `tangem://swap` — open swap for the current token. */
|
||||
SWAP,
|
||||
|
||||
/** `tangem://buy` — open onramp for the current token. */
|
||||
BUY,
|
||||
|
||||
/** External or unrecognized link — route through the generic deeplink launcher. */
|
||||
EXTERNAL,
|
||||
}
|
||||
|
||||
// TODO: [temporary] Banner taps are intercepted in-host and mapped to an AppRoute directly because the
|
||||
// shared tangem://swap and tangem://buy deeplinks open context-less screens (generic swap / BuyCrypto
|
||||
// hub) with no current-token prefill. Replace with targeted swap/onramp deeplinks and drop this
|
||||
// interception: [REDACTED_JIRA]
|
||||
/**
|
||||
* Resolves a marketing-banner [link] into a [MarketingDeeplink]. Never throws: malformed input
|
||||
* degrades to [MarketingDeeplink.EXTERNAL].
|
||||
*/
|
||||
fun resolveMarketingDeeplink(link: String): MarketingDeeplink {
|
||||
val uri = runCatching { URI(link) }.getOrNull() ?: return MarketingDeeplink.EXTERNAL
|
||||
|
||||
if (!uri.scheme.equals(DeepLinkScheme.Tangem.scheme, ignoreCase = true)) {
|
||||
return MarketingDeeplink.EXTERNAL
|
||||
}
|
||||
|
||||
return when (uri.host) {
|
||||
DeepLinkRoute.Swap.host -> MarketingDeeplink.SWAP
|
||||
DeepLinkRoute.Buy.host -> MarketingDeeplink.BUY
|
||||
else -> MarketingDeeplink.EXTERNAL
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the contextual in-app route for a marketing-banner deeplink on a token-scoped screen (staking,
|
||||
* yield, swap, onramp): swap for the current token, or onramp to buy it. Returns `null` for
|
||||
* [MarketingDeeplink.EXTERNAL] so the caller falls back to the generic deeplink launcher.
|
||||
*/
|
||||
fun MarketingDeeplink.toContextualRoute(
|
||||
userWalletId: UserWalletId,
|
||||
currency: CryptoCurrency,
|
||||
screenSource: AnalyticsParam.ScreensSources,
|
||||
onrampSource: OnrampSource = OnrampSource.MARKETING_BANNER,
|
||||
): AppRoute? = when (this) {
|
||||
MarketingDeeplink.SWAP -> AppRoute.Swap(
|
||||
userWalletId = userWalletId,
|
||||
fromCryptoCurrency = currency,
|
||||
screenSource = screenSource.value,
|
||||
)
|
||||
MarketingDeeplink.BUY -> AppRoute.Onramp(
|
||||
userWalletId = userWalletId,
|
||||
currency = currency,
|
||||
source = onrampSource,
|
||||
)
|
||||
MarketingDeeplink.EXTERNAL -> null
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.common.routing.entity
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/** How the address book is opened — part of the navigation contract, carried by [com.tangem.common.routing.AppRoute.AddressBook]. */
|
||||
@Serializable
|
||||
sealed interface AddressBookOpenMode {
|
||||
|
||||
@Serializable
|
||||
data object Default : AddressBookOpenMode
|
||||
|
||||
@Serializable
|
||||
data class WithContactCreation(
|
||||
val address: String,
|
||||
val networkId: String,
|
||||
) : AddressBookOpenMode
|
||||
|
||||
/**
|
||||
* Opened from the Send flow to pick a recipient. The list is filtered by [networkId] (the current send network),
|
||||
* and the chosen contact's address is delivered back via `ContactSelectionTrigger` rather than navigation.
|
||||
*/
|
||||
@Serializable
|
||||
data class ContactSelection(
|
||||
val networkId: String,
|
||||
) : AddressBookOpenMode
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.tangem.common.routing.deeplink
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.MethodSource
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
internal class MarketingDeeplinkTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideTestModels")
|
||||
fun resolveMarketingDeeplink(model: ResolveModel) {
|
||||
// Act
|
||||
val actual = resolveMarketingDeeplink(model.link)
|
||||
|
||||
// Assert
|
||||
assertThat(actual).isEqualTo(model.expected)
|
||||
}
|
||||
|
||||
internal data class ResolveModel(val link: String, val expected: MarketingDeeplink)
|
||||
|
||||
private fun provideTestModels() = listOf(
|
||||
// tangem:// swap/buy -> contextual
|
||||
ResolveModel(link = "tangem://swap", expected = MarketingDeeplink.SWAP),
|
||||
ResolveModel(link = "tangem://buy", expected = MarketingDeeplink.BUY),
|
||||
ResolveModel(link = "tangem://swap?foo=bar", expected = MarketingDeeplink.SWAP),
|
||||
ResolveModel(link = "tangem://buy/extra", expected = MarketingDeeplink.BUY),
|
||||
ResolveModel(link = "TANGEM://swap", expected = MarketingDeeplink.SWAP),
|
||||
// tangem:// other hosts -> external
|
||||
ResolveModel(link = "tangem://token", expected = MarketingDeeplink.EXTERNAL),
|
||||
ResolveModel(link = "tangem://promo", expected = MarketingDeeplink.EXTERNAL),
|
||||
// https T&S links -> external (iOS treats these as .link too)
|
||||
ResolveModel(link = "https://tangem.com/swap", expected = MarketingDeeplink.EXTERNAL),
|
||||
ResolveModel(link = "https://tangem.com/buy", expected = MarketingDeeplink.EXTERNAL),
|
||||
ResolveModel(link = "https://tangem.com/promo/summer", expected = MarketingDeeplink.EXTERNAL),
|
||||
// other schemes / garbage -> external
|
||||
ResolveModel(link = "wc://connect", expected = MarketingDeeplink.EXTERNAL),
|
||||
ResolveModel(link = "not a uri", expected = MarketingDeeplink.EXTERNAL),
|
||||
ResolveModel(link = "", expected = MarketingDeeplink.EXTERNAL),
|
||||
)
|
||||
}
|
||||
|
|
@ -9,30 +9,36 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.core.datasource)
|
||||
implementation(projects.core.utils)
|
||||
|
||||
implementation(projects.data.common)
|
||||
implementation(projects.data.staking)
|
||||
|
||||
implementation(projects.domain.legacy)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.card)
|
||||
implementation(projects.domain.staking.models)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.txhistory.models)
|
||||
implementation(projects.domain.wallets)
|
||||
implementation(projects.domain.wallets.models)
|
||||
|
||||
implementation(projects.libs.blockchainSdk)
|
||||
|
||||
implementation(deps.androidx.datastore)
|
||||
// region Other libraries
|
||||
implementation(deps.jodatime)
|
||||
implementation(deps.test.coroutine)
|
||||
// endregion
|
||||
|
||||
implementation(tangemDeps.blockchain)
|
||||
implementation(tangemDeps.card.core)
|
||||
// region Tangem SDK
|
||||
api(tangemDeps.blockchain)
|
||||
api(tangemDeps.card.core)
|
||||
// endregion
|
||||
|
||||
implementation(deps.test.junit5)
|
||||
implementation(deps.test.truth)
|
||||
// region Core
|
||||
api(projects.core.datasource)
|
||||
implementation(projects.core.utils)
|
||||
// endregion
|
||||
|
||||
// region Data
|
||||
implementation(projects.data.common)
|
||||
// endregion
|
||||
|
||||
// region Domain
|
||||
api(projects.domain.card)
|
||||
api(projects.domain.models)
|
||||
implementation(projects.domain.wallets)
|
||||
// endregion
|
||||
|
||||
// region Domain models
|
||||
api(projects.domain.staking.models)
|
||||
// endregion
|
||||
|
||||
// region Libs
|
||||
api(projects.libs.blockchainSdk)
|
||||
// endregion
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@ class MockCryptoCurrencyFactory(private val userWallet: UserWallet.Cold = defaul
|
|||
|
||||
private val factory = CryptoCurrencyFactory(excludedBlockchains = ExcludedBlockchains())
|
||||
|
||||
val bitcoin by lazy { createCoin(Blockchain.Bitcoin) }
|
||||
val cardano by lazy { createCoin(blockchain = Blockchain.Cardano) }
|
||||
val chia by lazy { createCoin(Blockchain.Chia) }
|
||||
val ethereum by lazy { createCoin(Blockchain.Ethereum) }
|
||||
|
|
|
|||
|
|
@ -9,19 +9,30 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
/** Project - Core */
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.core.utils)
|
||||
// region Kotlin
|
||||
api(deps.kotlin.coroutines)
|
||||
api(deps.kotlin.immutable.collections)
|
||||
// endregion
|
||||
|
||||
/** Compose */
|
||||
implementation(tangemDeps.vico.core)
|
||||
implementation(tangemDeps.vico.compose)
|
||||
implementation(tangemDeps.vico.compose.m3)
|
||||
|
||||
implementation(deps.lifecycle.compose)
|
||||
implementation(deps.compose.foundation)
|
||||
// region Compose
|
||||
api(deps.compose.foundation)
|
||||
implementation(deps.compose.material3)
|
||||
implementation(deps.compose.ui.tooling)
|
||||
implementation(deps.compose.ui.utils)
|
||||
implementation(deps.kotlin.immutable.collections)
|
||||
// endregion
|
||||
|
||||
// region Other libraries
|
||||
implementation(deps.androidx.annotation)
|
||||
implementation(deps.jodatime)
|
||||
// endregion
|
||||
|
||||
// region Vico
|
||||
implementation(tangemDeps.vico.core)
|
||||
implementation(tangemDeps.vico.compose)
|
||||
// endregion
|
||||
|
||||
// region Project - Core
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.core.utils)
|
||||
// endregion
|
||||
}
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
alias(deps.plugins.kotlin.kapt)
|
||||
alias(deps.plugins.hilt.android)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
|
|
@ -11,41 +9,59 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
/** Project - Core */
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.core.utils)
|
||||
implementation(projects.core.navigation)
|
||||
implementation(projects.core.analytics)
|
||||
|
||||
/** Project - Common */
|
||||
implementation(projects.common.uiCharts)
|
||||
implementation(projects.common.ui)
|
||||
implementation(projects.common.routing)
|
||||
// region Kotlin
|
||||
api(deps.kotlin.coroutines)
|
||||
api(deps.kotlin.immutable.collections)
|
||||
// endregion
|
||||
|
||||
/** Project - Domain */
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.tokens)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.staking)
|
||||
implementation(projects.domain.staking.models)
|
||||
implementation(projects.domain.onramp.models)
|
||||
implementation(projects.domain.offramp)
|
||||
implementation(projects.domain.demo)
|
||||
implementation(projects.domain.card)
|
||||
implementation(projects.domain.feedback)
|
||||
|
||||
implementation(deps.lifecycle.compose)
|
||||
implementation(deps.compose.foundation)
|
||||
implementation(deps.compose.material3)
|
||||
// region Compose
|
||||
api(deps.compose.foundation)
|
||||
implementation(deps.compose.ui.tooling)
|
||||
implementation(deps.compose.material3)
|
||||
implementation(deps.compose.ui.utils)
|
||||
implementation(deps.kotlin.immutable.collections)
|
||||
// endregion
|
||||
|
||||
/** DI */
|
||||
// region Other libraries
|
||||
implementation(deps.androidx.annotation)
|
||||
implementation(deps.arrow.core)
|
||||
implementation(deps.haze)
|
||||
implementation(deps.hilt.android)
|
||||
kapt(deps.hilt.kapt)
|
||||
// endregion
|
||||
|
||||
/** Test */
|
||||
testImplementation(projects.test.core)
|
||||
// region Project - Core
|
||||
api(projects.core.analytics)
|
||||
api(projects.core.decompose)
|
||||
api(projects.core.navigation)
|
||||
api(projects.core.ui)
|
||||
api(projects.core.utils)
|
||||
implementation(projects.core.analytics.models)
|
||||
// endregion
|
||||
|
||||
// region Project - Common
|
||||
api(projects.common.routing)
|
||||
api(projects.common.uiCharts)
|
||||
implementation(projects.common.ui)
|
||||
// endregion
|
||||
|
||||
// region Project - Domain
|
||||
api(projects.domain.appCurrency.models)
|
||||
api(projects.domain.card)
|
||||
api(projects.domain.demo)
|
||||
api(projects.domain.feedback)
|
||||
api(projects.domain.models)
|
||||
api(projects.domain.offramp)
|
||||
api(projects.domain.tokens)
|
||||
implementation(projects.domain.onramp.models)
|
||||
implementation(projects.domain.staking)
|
||||
implementation(projects.domain.tokens.models)
|
||||
// endregion
|
||||
|
||||
// region Test
|
||||
testImplementation(deps.test.coroutine)
|
||||
testImplementation(deps.test.junit5)
|
||||
testImplementation(deps.test.mockk)
|
||||
testImplementation(deps.test.truth)
|
||||
testImplementation(projects.common.test)
|
||||
// endregion
|
||||
}
|
||||
|
|
@ -8,47 +8,70 @@ android {
|
|||
namespace = "com.tangem.common.ui"
|
||||
}
|
||||
dependencies {
|
||||
api(projects.common)
|
||||
|
||||
/** Compose */
|
||||
implementation(deps.compose.material3)
|
||||
implementation(deps.compose.foundation)
|
||||
implementation(deps.compose.ui)
|
||||
implementation(deps.compose.ui.tooling)
|
||||
implementation(deps.compose.navigation)
|
||||
implementation(deps.compose.navigation.hilt)
|
||||
// region Kotlin
|
||||
api(deps.kotlin.immutable.collections)
|
||||
implementation(deps.kotlin.coroutines)
|
||||
// endregion
|
||||
|
||||
// region Compose
|
||||
api(deps.compose.foundation)
|
||||
api(deps.compose.material3)
|
||||
implementation(deps.compose.coil)
|
||||
implementation(deps.compose.constraintLayout)
|
||||
implementation(deps.compose.ui)
|
||||
implementation(deps.compose.ui.tooling)
|
||||
// endregion
|
||||
|
||||
/** Deps */
|
||||
implementation(deps.kotlin.immutable.collections)
|
||||
// region Other libraries
|
||||
api(deps.arrow.core)
|
||||
implementation(deps.hilt.android)
|
||||
implementation(deps.androidx.annotation)
|
||||
implementation(deps.androidx.core.ktx)
|
||||
implementation(deps.haze)
|
||||
// endregion
|
||||
|
||||
/** Project - Common */
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.core.utils)
|
||||
implementation(projects.core.res)
|
||||
implementation(projects.libs.crypto)
|
||||
implementation(projects.libs.blockchainSdk)
|
||||
|
||||
/** Project - Domain */
|
||||
implementation(projects.domain.appCurrency.models)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.legacy)
|
||||
implementation(projects.domain.card)
|
||||
implementation(projects.domain.staking.models)
|
||||
implementation(projects.domain.staking)
|
||||
implementation(projects.domain.account)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.transaction.models)
|
||||
implementation(projects.domain.wallets.models)
|
||||
implementation(projects.domain.onramp.models)
|
||||
implementation(projects.domain.common)
|
||||
|
||||
implementation(tangemDeps.card.core)
|
||||
implementation(tangemDeps.blockchain) {
|
||||
// region Tangem SDK
|
||||
api(tangemDeps.blockchain) {
|
||||
exclude(module = "joda-time")
|
||||
}
|
||||
// endregion
|
||||
|
||||
/** Tests */
|
||||
// region Project - Core
|
||||
api(projects.core.analytics)
|
||||
api(projects.core.ui)
|
||||
api(projects.core.utils)
|
||||
implementation(projects.core.analytics.models)
|
||||
implementation(projects.core.res)
|
||||
// endregion
|
||||
|
||||
// region Project - Common
|
||||
// :common is intentionally re-exported (api): common:ui is a ubiquitous UI dependency and many
|
||||
// feature modules rely on TangemBlogUrlBuilder / common types through it. Demoting to implementation
|
||||
// cascades across the feature graph, so keep it api despite DAGP's advice (suppressed below).
|
||||
api(projects.common)
|
||||
// endregion
|
||||
|
||||
// region Project - Domain
|
||||
api(projects.domain.account)
|
||||
api(projects.domain.appCurrency.models)
|
||||
api(projects.domain.common)
|
||||
api(projects.domain.core)
|
||||
api(projects.domain.models)
|
||||
api(projects.domain.onramp.models)
|
||||
api(projects.domain.staking)
|
||||
api(projects.domain.tokens.models)
|
||||
api(projects.domain.transaction.models)
|
||||
implementation(projects.domain.card)
|
||||
implementation(projects.domain.staking.models)
|
||||
// endregion
|
||||
|
||||
// region Project - Libs
|
||||
implementation(projects.libs.blockchainSdk)
|
||||
implementation(projects.libs.crypto)
|
||||
// endregion
|
||||
|
||||
// region Tests
|
||||
testImplementation(projects.test.core)
|
||||
// endregion
|
||||
}
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
package com.tangem.common.ui.account
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon.Color
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon.Icon
|
||||
|
||||
@Immutable
|
||||
sealed class AccountIconUM {
|
||||
data class CryptoPortfolio(val value: Icon, val color: Color) : AccountIconUM()
|
||||
|
||||
|
|
|
|||
|
|
@ -306,7 +306,9 @@ private fun EarnBlockTitle(titleUM: EarnBlockUM.TitleUM, type: Type, modifier: M
|
|||
iconRes = icon.tone.iconRes(),
|
||||
tintReference = { icon.tone.tint() },
|
||||
),
|
||||
modifier = Modifier.size(TangemTheme.dimens2.x4),
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens2.x4)
|
||||
.testTag(TokenDetailsScreenTestTags.EARN_BLOCK_TITLE_ICON),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
package com.tangem.common.ui.navigationButtons
|
||||
|
||||
import com.tangem.core.decompose.navigation.Route
|
||||
|
||||
interface NavigationModelCallback {
|
||||
fun onNavigationResult(navigationUM: NavigationUM)
|
||||
fun onBackClick()
|
||||
fun onNextClick()
|
||||
fun onBackClick(currentRoute: Route)
|
||||
fun onNextClick(currentRoute: Route)
|
||||
}
|
||||
|
|
@ -244,6 +244,11 @@ sealed class NotificationUM(val config: NotificationConfig) {
|
|||
subtitle = resourceReference(id = R.string.send_notification_fee_too_high_text, wrappedList(value)),
|
||||
)
|
||||
|
||||
data object HighNetworkFee : Warning(
|
||||
title = resourceReference(id = R.string.high_fee_warning_title),
|
||||
subtitle = resourceReference(id = R.string.high_fee_warning_description),
|
||||
)
|
||||
|
||||
data class NetworkFeeUnreachable(val onRefresh: () -> Unit) : Warning(
|
||||
title = resourceReference(R.string.send_fee_unreachable_error_title),
|
||||
subtitle = resourceReference(R.string.send_fee_unreachable_error_text),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue