Updated on 2026-08-14
This commit is contained in:
commit
43c11d0460
384 changed files with 19228 additions and 3308 deletions
|
|
@ -1,4 +1,9 @@
|
|||
plugins {
|
||||
alias(deps.plugins.kotlin.jvm)
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(deps.kotlin.serialization)
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.core.analytics.models
|
|||
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.REFERRAL
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.REFERRAL_ID
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
const val IS_NOT_HTTP_ERROR = "Is not http error"
|
||||
|
||||
|
|
@ -67,39 +68,40 @@ sealed class AnalyticsParam {
|
|||
data object BlockchainSdk : Error("Blockchain Sdk Error")
|
||||
}
|
||||
|
||||
sealed class ScreensSources(val value: String) {
|
||||
data object Settings : ScreensSources("Settings")
|
||||
data object Main : ScreensSources("Main")
|
||||
data object SignIn : ScreensSources("Sign In")
|
||||
data object Send : ScreensSources("Send")
|
||||
data object Intro : ScreensSources("Introduction")
|
||||
data object MyWallets : ScreensSources("My Wallets")
|
||||
data object Token : ScreensSources("Token")
|
||||
data object Stories : ScreensSources("Stories")
|
||||
data object Buy : ScreensSources("Buy")
|
||||
data object Swap : ScreensSources("Swap")
|
||||
data object Sell : ScreensSources("Sell")
|
||||
data object Backup : ScreensSources("Backup")
|
||||
data object Onboarding : ScreensSources("Onboarding")
|
||||
data object LongTap : ScreensSources("Long Tap")
|
||||
data object Market : ScreensSources("Market")
|
||||
data object Markets : ScreensSources("Markets")
|
||||
data object MarketPulse : ScreensSources("Market Pulse")
|
||||
data object TangemPay : ScreensSources("Tangem Pay")
|
||||
data object WalletSettings : ScreensSources("Wallet Settings")
|
||||
data object Upgrade : ScreensSources("Upgrade")
|
||||
data object HardwareWallet : ScreensSources("Hardware Wallet")
|
||||
data object ImportWallet : ScreensSources("Import Wallet")
|
||||
data object CreateWalletIntro : ScreensSources("Create Wallet Intro")
|
||||
data object AddNewWallet : ScreensSources("Add New Wallet")
|
||||
data object AddNew : ScreensSources("Add New")
|
||||
data object CreateWallet : ScreensSources("Create Wallet")
|
||||
data object NewsList : ScreensSources("News List")
|
||||
data object NewsLink : ScreensSources("News Link")
|
||||
data object NewsPage : ScreensSources("News Page")
|
||||
data object Portfolio : ScreensSources("Portfolio")
|
||||
data object Staking : ScreensSources("Staking")
|
||||
data object Earn : ScreensSources("Earn")
|
||||
@Serializable
|
||||
enum class ScreensSources(val value: String) {
|
||||
Settings("Settings"),
|
||||
Main("Main"),
|
||||
SignIn("Sign In"),
|
||||
Send("Send"),
|
||||
Intro("Introduction"),
|
||||
MyWallets("My Wallets"),
|
||||
Token("Token"),
|
||||
Stories("Stories"),
|
||||
Buy("Buy"),
|
||||
Swap("Swap"),
|
||||
Sell("Sell"),
|
||||
Backup("Backup"),
|
||||
Onboarding("Onboarding"),
|
||||
LongTap("Long Tap"),
|
||||
Market("Market"),
|
||||
Markets("Markets"),
|
||||
MarketPulse("Market Pulse"),
|
||||
TangemPay("Tangem Pay"),
|
||||
WalletSettings("Wallet Settings"),
|
||||
Upgrade("Upgrade"),
|
||||
HardwareWallet("Hardware Wallet"),
|
||||
ImportWallet("Import Wallet"),
|
||||
CreateWalletIntro("Create Wallet Intro"),
|
||||
AddNewWallet("Add New Wallet"),
|
||||
AddNew("Add New"),
|
||||
CreateWallet("Create Wallet"),
|
||||
NewsList("News List"),
|
||||
NewsLink("News Link"),
|
||||
NewsPage("News Page"),
|
||||
Portfolio("Portfolio"),
|
||||
Staking("Staking"),
|
||||
Earn("Earn"),
|
||||
}
|
||||
|
||||
sealed class TxSentFrom(val value: String) {
|
||||
|
|
@ -191,9 +193,9 @@ sealed class AnalyticsParam {
|
|||
}
|
||||
|
||||
sealed class WalletCreationType(val value: String) {
|
||||
data object PrivateKey : WalletCreationType("Private key")
|
||||
data object NewSeed : WalletCreationType("New seed")
|
||||
data object SeedImport : WalletCreationType("Seed import")
|
||||
data object PrivateKey : WalletCreationType(value = "Private Key")
|
||||
data object NewSeed : WalletCreationType(value = "New Seed")
|
||||
data object SeedImport : WalletCreationType(value = "Seed Import")
|
||||
}
|
||||
|
||||
sealed class WalletType(val value: String) {
|
||||
|
|
@ -239,6 +241,13 @@ sealed class AnalyticsParam {
|
|||
MobileWallet("Mobile Wallet"),
|
||||
}
|
||||
|
||||
enum class SignInType(val value: String) {
|
||||
Card("Card"),
|
||||
Biometric("Biometric"),
|
||||
NoSecurity("No Security"),
|
||||
AccessCode("Access Code"),
|
||||
}
|
||||
|
||||
companion object Key {
|
||||
const val BLOCKCHAIN = "Blockchain"
|
||||
const val TOKEN_PARAM = "Token"
|
||||
|
|
@ -297,6 +306,11 @@ sealed class AnalyticsParam {
|
|||
const val REFERRAL_ID = "Referral_ID"
|
||||
const val SEARCHED = "Searched"
|
||||
const val RATE_TYPE = "Rate Type"
|
||||
const val SIGN_IN_TYPE = "Sign in type"
|
||||
const val WALLETS_COUNT = "Wallets Count"
|
||||
const val WALLET_TYPE = "Wallet Type"
|
||||
const val BACKUPED = "Backuped"
|
||||
const val MEMO = "Memo"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,65 +2,41 @@ package com.tangem.core.analytics.models
|
|||
|
||||
sealed class Basic(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
) : AnalyticsEvent("Basic", event, params) {
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : AnalyticsEvent(category = "Basic", event = event, params = params) {
|
||||
|
||||
/**
|
||||
* Tracks card scanning from specific entry points (Introduction, Main, My Wallets, Sign In).
|
||||
* The originating screen is reported via the [AnalyticsParam.SOURCE] parameter.
|
||||
*/
|
||||
class CardWasScanned(
|
||||
source: AnalyticsParam.ScreensSources,
|
||||
) : Basic(
|
||||
event = "Card Was Scanned",
|
||||
params = mapOf(
|
||||
AnalyticsParam.Key.SOURCE to source.value,
|
||||
AnalyticsParam.SOURCE to source.value,
|
||||
),
|
||||
)
|
||||
|
||||
class SignedInLegacy(
|
||||
currency: AnalyticsParam.WalletType,
|
||||
batch: String,
|
||||
signInType: SignInType,
|
||||
walletsCount: String,
|
||||
isImported: Boolean,
|
||||
hasBackup: Boolean?,
|
||||
) : Basic(
|
||||
event = "Signed in",
|
||||
params = buildMap {
|
||||
put(AnalyticsParam.Key.CURRENCY, currency.value)
|
||||
put(AnalyticsParam.Key.BATCH, batch)
|
||||
put("Wallet Type", if (isImported) "Seed Phrase" else "Seedless")
|
||||
put("Sign in type", signInType.name)
|
||||
put("Wallets Count", walletsCount)
|
||||
if (hasBackup != null) {
|
||||
put("Backuped", if (hasBackup) "Yes" else "No")
|
||||
}
|
||||
},
|
||||
) {
|
||||
enum class SignInType {
|
||||
Card, Biometric
|
||||
}
|
||||
}
|
||||
), CriticalEvent
|
||||
|
||||
/**
|
||||
* Tracks any sign-in into a wallet (card scan, FaceID, or wallet switch).
|
||||
* Counted as a single sign-in per session — subsequent card scans within the same session are ignored.
|
||||
*/
|
||||
class SignedIn(
|
||||
signInType: SignInType,
|
||||
signInType: AnalyticsParam.SignInType,
|
||||
walletsCount: Int,
|
||||
isImported: Boolean,
|
||||
hasBackup: Boolean?,
|
||||
isBackedUp: Boolean,
|
||||
) : Basic(
|
||||
event = "Signed in",
|
||||
params = buildMap {
|
||||
put("Sign in type", signInType.value)
|
||||
put("Wallets Count", walletsCount.toString())
|
||||
put("Wallet Type", if (isImported) "Seed Phrase" else "Seedless")
|
||||
if (hasBackup != null) {
|
||||
put("Backuped", if (hasBackup) "Yes" else "No")
|
||||
}
|
||||
put(AnalyticsParam.SIGN_IN_TYPE, signInType.value)
|
||||
put(AnalyticsParam.WALLETS_COUNT, walletsCount.toString())
|
||||
put(AnalyticsParam.WALLET_TYPE, if (isImported) "Seed Phrase" else "Seedless")
|
||||
put(AnalyticsParam.BACKUPED, if (isBackedUp) "Yes" else "No")
|
||||
},
|
||||
) {
|
||||
enum class SignInType(val value: String) {
|
||||
Card("Card"),
|
||||
Biometric("Biometric"),
|
||||
NoSecurity("No Security"),
|
||||
AccessCode("Access Code"),
|
||||
}
|
||||
), CriticalEvent, OneTimePerSessionEvent {
|
||||
override val oneTimeEventId: String = id
|
||||
}
|
||||
|
||||
class ButtonBuy(
|
||||
|
|
@ -68,39 +44,46 @@ sealed class Basic(
|
|||
) : Basic(
|
||||
event = "Button - Buy",
|
||||
params = buildMap {
|
||||
put(AnalyticsParam.Key.SOURCE, source.value)
|
||||
put(AnalyticsParam.SOURCE, source.value)
|
||||
},
|
||||
)
|
||||
|
||||
class ToppedUp(userWalletId: String, currency: AnalyticsParam.WalletType) :
|
||||
/**
|
||||
* Tracks the first time a user wallet is topped up. Sent once per wallet, when the balance
|
||||
* transitions from zero to positive (Total Balance for multi-currency wallets, or Balance for Note).
|
||||
* A wallet scanned with a non-zero balance does not count as a top-up — the event must be sent
|
||||
* only after all tokens have finished loading.
|
||||
*/
|
||||
class ToppedUp(userWalletId: String, walletType: AnalyticsParam.WalletType) :
|
||||
Basic(
|
||||
event = "Topped up",
|
||||
params = mapOf(AnalyticsParam.Key.CURRENCY to currency.value),
|
||||
params = mapOf(AnalyticsParam.CURRENCY to walletType.value),
|
||||
),
|
||||
OneTimeAnalyticsEvent {
|
||||
OneTimeAnalyticsEvent, AppsFlyerIncludedEvent, CriticalEvent {
|
||||
|
||||
override val oneTimeEventId: String = id + userWalletId
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks transaction submission from various screens (Send, Swap, WalletConnect, Sell, Approve, Staking).
|
||||
*/
|
||||
class TransactionSent(sentFrom: AnalyticsParam.TxSentFrom, memoType: MemoType) :
|
||||
Basic(
|
||||
event = "Transaction sent",
|
||||
params = buildMap {
|
||||
this[AnalyticsParam.Key.SOURCE] = sentFrom.value
|
||||
put(AnalyticsParam.SOURCE, sentFrom.value)
|
||||
if (sentFrom is AnalyticsParam.TxData) {
|
||||
this[AnalyticsParam.Key.BLOCKCHAIN] = sentFrom.blockchain
|
||||
this[AnalyticsParam.Key.TOKEN_PARAM] = sentFrom.token
|
||||
sentFrom.feeType?.value?.let {
|
||||
this[AnalyticsParam.Key.FEE_TYPE] = it
|
||||
}
|
||||
this[AnalyticsParam.Key.FEE_TOKEN] = sentFrom.feeToken
|
||||
put(AnalyticsParam.BLOCKCHAIN, sentFrom.blockchain)
|
||||
put(AnalyticsParam.TOKEN_PARAM, sentFrom.token)
|
||||
sentFrom.feeType?.value?.let { put(AnalyticsParam.FEE_TYPE, it) }
|
||||
put(AnalyticsParam.FEE_TOKEN, sentFrom.feeToken)
|
||||
}
|
||||
if (sentFrom is AnalyticsParam.TxSentFrom.Approve) {
|
||||
this[AnalyticsParam.Key.PERMISSION_TYPE] = sentFrom.permissionType
|
||||
put(AnalyticsParam.PERMISSION_TYPE, sentFrom.permissionType)
|
||||
}
|
||||
this["Memo"] = memoType.name
|
||||
put(AnalyticsParam.MEMO, memoType.name)
|
||||
},
|
||||
), AppsFlyerIncludedEvent {
|
||||
), AppsFlyerIncludedEvent, CriticalEvent {
|
||||
enum class MemoType {
|
||||
Empty, Full, Null
|
||||
}
|
||||
|
|
@ -110,31 +93,33 @@ sealed class Basic(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks the user invoking the "Request Support" email flow from various screens of the app.
|
||||
*/
|
||||
class ButtonSupport(source: AnalyticsParam.ScreensSources) : Basic(
|
||||
event = "Request Support",
|
||||
params = mapOf(
|
||||
AnalyticsParam.Key.SOURCE to source.value,
|
||||
AnalyticsParam.SOURCE to source.value,
|
||||
),
|
||||
), CriticalEvent
|
||||
|
||||
/**
|
||||
* Tracks loading of the user's total balance after sign-in. Reports whether the balance is
|
||||
* empty, has funds, failed to load, or could not be returned because of a custom token.
|
||||
*/
|
||||
class BalanceLoaded(balance: AnalyticsParam.CardBalanceState, tokensCount: Int?) : Basic(
|
||||
event = "Balance Loaded",
|
||||
params = buildMap {
|
||||
put(AnalyticsParam.BALANCE, balance.value)
|
||||
tokensCount?.let { put(AnalyticsParam.TOKENS_COUNT, it.toString()) }
|
||||
},
|
||||
), AppsFlyerIncludedEvent, CriticalEvent
|
||||
|
||||
class TokenBalance(balance: AnalyticsParam.EmptyFull, token: String) : Basic(
|
||||
event = "Token Balance",
|
||||
params = mapOf(
|
||||
AnalyticsParam.STATE to balance.value,
|
||||
AnalyticsParam.TOKEN_PARAM to token,
|
||||
),
|
||||
)
|
||||
|
||||
class BiometryFailed(
|
||||
source: AnalyticsParam.ScreensSources,
|
||||
reason: BiometricFailReason,
|
||||
) : Basic(
|
||||
event = "Biometry Failed",
|
||||
params = mapOf(
|
||||
AnalyticsParam.Key.SOURCE to source.value,
|
||||
"Reason" to reason.value,
|
||||
),
|
||||
) {
|
||||
sealed class BiometricFailReason(val value: String) {
|
||||
data object AuthenticationLockout : BiometricFailReason("BiometricsAuthenticationLockout")
|
||||
data object AuthenticationLockoutPermanent : BiometricFailReason("BiometricsAuthenticationLockoutPermanent")
|
||||
data object BiometricsAuthenticationDisabled : BiometricFailReason("BiometricsAuthenticationDisabled")
|
||||
data object AllKeysInvalidated : BiometricFailReason("AllKeysInvalidated")
|
||||
data object AuthenticationCancelled : BiometricFailReason("AuthenticationCancelled")
|
||||
data object AuthenticationAlreadyInProgress : BiometricFailReason("AuthenticationAlreadyInProgress")
|
||||
data class Other(val reason: String) : BiometricFailReason(reason)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.core.analytics.models
|
||||
|
||||
/**
|
||||
* Marker interface for analytics events that require special attention.
|
||||
*
|
||||
* Implemented by events listed in the analytics specification (events.csv).
|
||||
*/
|
||||
interface CriticalEvent
|
||||
|
|
@ -1,9 +1,6 @@
|
|||
package com.tangem.core.analytics.models.event
|
||||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.AppsFlyerIncludedEvent
|
||||
import com.tangem.core.analytics.models.getReferralParams
|
||||
import com.tangem.core.analytics.models.*
|
||||
|
||||
sealed class OnboardingAnalyticsEvent(
|
||||
category: String,
|
||||
|
|
@ -16,23 +13,29 @@ sealed class OnboardingAnalyticsEvent(
|
|||
params: Map<String, String> = mapOf(),
|
||||
) : OnboardingAnalyticsEvent(category = "Onboarding", event = event, params = params) {
|
||||
|
||||
/**
|
||||
* Tracks the start of the onboarding process.
|
||||
*/
|
||||
class Started(
|
||||
source: String,
|
||||
source: AnalyticsParam.ScreensSources? = null,
|
||||
) : Onboarding(
|
||||
event = "Onboarding Started",
|
||||
params = mapOf(
|
||||
AnalyticsParam.SOURCE to source,
|
||||
),
|
||||
)
|
||||
params = buildMap {
|
||||
source?.value?.let { put(AnalyticsParam.SOURCE, it) }
|
||||
},
|
||||
), CriticalEvent
|
||||
|
||||
/**
|
||||
* Tracks the completion of the onboarding process.
|
||||
*/
|
||||
class Finished(
|
||||
source: String,
|
||||
source: AnalyticsParam.ScreensSources? = null,
|
||||
) : Onboarding(
|
||||
event = "Onboarding Finished",
|
||||
params = mapOf(
|
||||
AnalyticsParam.SOURCE to source,
|
||||
),
|
||||
)
|
||||
params = buildMap {
|
||||
source?.value?.let { put(AnalyticsParam.SOURCE, it) }
|
||||
},
|
||||
), CriticalEvent
|
||||
|
||||
class ButtonMobileWallet(
|
||||
source: String,
|
||||
|
|
@ -49,31 +52,42 @@ sealed class OnboardingAnalyticsEvent(
|
|||
params: Map<String, String> = mapOf(),
|
||||
) : OnboardingAnalyticsEvent(category = "Onboarding / Create Wallet", event = event, params = params) {
|
||||
|
||||
class ButtonCreateWallet : CreateWallet("Button - Create Wallet")
|
||||
/**
|
||||
* Tracks opening of the create wallet screen.
|
||||
*/
|
||||
class ScreenOpened : CreateWallet("Create Wallet Screen Opened"), CriticalEvent
|
||||
|
||||
/**
|
||||
* Tracks the user clicking the "Create Wallet" button.
|
||||
*/
|
||||
class ButtonCreateWallet : CreateWallet("Button - Create Wallet"), CriticalEvent
|
||||
|
||||
/**
|
||||
* Tracks the user clicking the "Other Options" button on the create wallet screen.
|
||||
*/
|
||||
class ButtonOtherOptions : CreateWallet("Button - Other Options"), CriticalEvent
|
||||
|
||||
/**
|
||||
* Tracks successful wallet creation, either on a Tangem card or as a mobile wallet.
|
||||
*/
|
||||
class WalletCreatedSuccessfully(
|
||||
source: String,
|
||||
creationType: WalletCreationType = WalletCreationType.NewSeed,
|
||||
creationType: AnalyticsParam.WalletCreationType = AnalyticsParam.WalletCreationType.PrivateKey,
|
||||
seedPhraseLength: Int? = null,
|
||||
passPhraseState: AnalyticsParam.EmptyFull,
|
||||
referralId: String?,
|
||||
source: AnalyticsParam.ScreensSources? = null,
|
||||
) : CreateWallet(
|
||||
event = "Wallet Created Successfully",
|
||||
params = buildMap {
|
||||
put(AnalyticsParam.SOURCE, source)
|
||||
put("Creation Type", creationType.value)
|
||||
put("Passphrase", passPhraseState.value)
|
||||
if (seedPhraseLength != null) {
|
||||
put("Seed Phrase Length", seedPhraseLength.toString())
|
||||
}
|
||||
source?.value?.let { put(AnalyticsParam.SOURCE, it) }
|
||||
putAll(getReferralParams(referralId))
|
||||
},
|
||||
), AppsFlyerIncludedEvent
|
||||
|
||||
sealed class WalletCreationType(val value: String) {
|
||||
data object NewSeed : WalletCreationType(value = "New Seed")
|
||||
data object SeedImport : WalletCreationType(value = "Seed Import")
|
||||
}
|
||||
), AppsFlyerIncludedEvent, CriticalEvent
|
||||
}
|
||||
|
||||
sealed class SeedPhrase(
|
||||
|
|
@ -82,16 +96,19 @@ sealed class OnboardingAnalyticsEvent(
|
|||
) : OnboardingAnalyticsEvent(category = "Onboarding / Seed Phrase", event = event, params = params) {
|
||||
|
||||
class CreateMobileScreenOpened(
|
||||
source: String,
|
||||
source: AnalyticsParam.ScreensSources,
|
||||
) : SeedPhrase(
|
||||
event = "Create Mobile Screen Opened",
|
||||
params = mapOf(
|
||||
AnalyticsParam.SOURCE to source,
|
||||
AnalyticsParam.SOURCE to source.value,
|
||||
),
|
||||
), AppsFlyerIncludedEvent
|
||||
|
||||
class ButtonImportWallet : SeedPhrase("Button - Import Wallet")
|
||||
class ImportSeedPhraseScreenOpened : SeedPhrase("Import Seed Phrase Screen Opened")
|
||||
/**
|
||||
* Tracks opening of the seed phrase import screen.
|
||||
*/
|
||||
class ImportSeedPhraseScreenOpened : SeedPhrase("Import Seed Phrase Screen Opened"), CriticalEvent
|
||||
class ButtonImport : SeedPhrase("Button - Import")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,20 +2,22 @@ package com.tangem.core.analytics.models.event
|
|||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.CriticalEvent
|
||||
|
||||
sealed class SignIn(
|
||||
event: String,
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : AnalyticsEvent("Sign In", event, params) {
|
||||
) : AnalyticsEvent(category = "Sign In", event = event, params = params) {
|
||||
|
||||
data class ScreenOpened(
|
||||
val walletsCount: Int,
|
||||
) : SignIn(
|
||||
/**
|
||||
* Tracks the user landing on the app's sign-in screen when a saved card exists.
|
||||
*/
|
||||
class ScreenOpened(walletsCount: Int) : SignIn(
|
||||
event = "Sign In Screen Opened",
|
||||
params = mapOf(
|
||||
"Wallets Count" to walletsCount.toString(),
|
||||
AnalyticsParam.WALLETS_COUNT to walletsCount.toString(),
|
||||
),
|
||||
)
|
||||
), CriticalEvent
|
||||
|
||||
class ButtonBiometricSignIn : SignIn(event = "Button - Biometric Sign In")
|
||||
|
||||
|
|
@ -26,24 +28,17 @@ sealed class SignIn(
|
|||
) : SignIn(event = "Error - Biometric Updated")
|
||||
|
||||
class ButtonWallet(
|
||||
signInType: SignInType,
|
||||
signInType: AnalyticsParam.SignInType,
|
||||
walletsCount: Int,
|
||||
) : SignIn(
|
||||
event = "Button - Wallet",
|
||||
params = buildMap {
|
||||
put("Wallets Count", walletsCount.toString())
|
||||
put("Sign in type", signInType.value)
|
||||
put(AnalyticsParam.WALLETS_COUNT, walletsCount.toString())
|
||||
put(AnalyticsParam.SIGN_IN_TYPE, signInType.value)
|
||||
},
|
||||
) {
|
||||
enum class SignInType(val value: String) {
|
||||
Card("Card"),
|
||||
Biometric("Biometric"),
|
||||
NoSecurity("No Security"),
|
||||
AccessCode("Access Code"),
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
data class ButtonAddWallet(
|
||||
class ButtonAddWallet(
|
||||
val sources: AnalyticsParam.ScreensSources,
|
||||
) : SignIn(
|
||||
event = "Button - Add Wallet",
|
||||
|
|
|
|||
|
|
@ -15,10 +15,6 @@
|
|||
"name": "USEDESK_ENABLED",
|
||||
"version": "undefined"
|
||||
},
|
||||
{
|
||||
"name": "SWAP_REDESIGN_ENABLED",
|
||||
"version": "undefined"
|
||||
},
|
||||
{
|
||||
"name": "APP_REDESIGN_ENABLED",
|
||||
"version": "undefined"
|
||||
|
|
@ -66,5 +62,17 @@
|
|||
{
|
||||
"name": "ADDRESS_SYNC_ENABLED",
|
||||
"version": "undefined"
|
||||
},
|
||||
{
|
||||
"name": "SWAP_SWITCH_TO_TRANSFER_ENABLED",
|
||||
"version": "undefined"
|
||||
},
|
||||
{
|
||||
"name": "SWAP_INTEGRATED_APPROVE",
|
||||
"version": "undefined"
|
||||
},
|
||||
{
|
||||
"name": "SWAP_AB_ENABLED",
|
||||
"version": "undefined"
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -150,6 +150,8 @@ data class YieldDTO(
|
|||
data class PeriodDTO(
|
||||
@Json(name = "days")
|
||||
val days: Int?,
|
||||
@Json(name = "seconds")
|
||||
val seconds: Int?,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ object PreferencesKeys {
|
|||
|
||||
val LAST_SWAPPED_CRYPTOCURRENCY_ID_KEY by lazy { stringPreferencesKey(name = "lastSwappedCryptoCurrency") }
|
||||
|
||||
val SWAP_UI_MODE_KEY by lazy { stringPreferencesKey(name = "swapUiMode") }
|
||||
|
||||
val WAS_TWINS_ONBOARDING_SHOWN by lazy { booleanPreferencesKey(name = "twinsOnboardingShown") }
|
||||
|
||||
val IS_TANGEM_TOS_ACCEPTED_KEY by lazy { booleanPreferencesKey(name = "tangem_tos_accepted") }
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ sealed interface PaymentAccountStatusValueDM {
|
|||
data class DeactivatedAccount(
|
||||
@Json(name = "deactivated_account") val marker: Boolean = true,
|
||||
@Json(name = "fiat_balance") val fiatBalance: FiatBalanceDM,
|
||||
@Json(name = "crypto_balance") val cryptoBalance: CryptoBalanceDM,
|
||||
) : PaymentAccountStatusValueDM
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@
|
|||
<string name="backup_complete_description">Du hast Deine Wallet erfolgreich gesichert.</string>
|
||||
<string name="backup_complete_seed_description">Diese Wörter können bei Verlust nicht wiederhergestellt werden. Bewahre diese an einem sicheren Ort auf.</string>
|
||||
<string name="backup_complete_title">Sicherung abgeschlossen</string>
|
||||
<string name="backup_info_description">Deine geheime Wiederherstellungsphrase ist eine feste Folge von %s zufälligen Wörtern, mit denen Du auf Deiner Wallet zugreifefst und sie wiederherstellen kannst.</string>
|
||||
<string name="backup_info_description">Deine geheime Wiederherstellungsphrase ist eine feste Folge von %s zufälligen Wörtern, mit denen Du auf Deiner Wallet zugreifst und sie wiederherstellen kannst.</string>
|
||||
<string name="backup_info_keep_description">Diese Worte sind unwiederbringlich verloren. Bewahre diese gut auf.</string>
|
||||
<string name="backup_info_keep_title">Sicher aufbewahren</string>
|
||||
<string name="backup_info_save_description">Speicher diese %s Wörter an einem sicheren Ort und gebe diese niemals an andere weiter.</string>
|
||||
|
|
@ -217,8 +217,10 @@
|
|||
<string name="common_access_denied">Zugang verweigert</string>
|
||||
<string name="common_account">Konto</string>
|
||||
<string name="common_accounts">Konten</string>
|
||||
<string name="common_action_failed">%s fehlgeschlagen</string>
|
||||
<string name="common_activate">Aktivieren</string>
|
||||
<string name="common_add">Hinzufügen</string>
|
||||
<string name="common_add_funds">Guthaben hinzufügen</string>
|
||||
<string name="common_add_to_portfolio">Zum Portfolio hinzufügen</string>
|
||||
<string name="common_add_token">Token hinzufügen</string>
|
||||
<string name="common_add_tokens">Token hinzufügen</string>
|
||||
|
|
@ -232,6 +234,8 @@
|
|||
<string name="common_apply">Anwenden</string>
|
||||
<string name="common_approval">Genehmigung</string>
|
||||
<string name="common_approve">Genehmigen</string>
|
||||
<string name="common_approved">Genehmigt</string>
|
||||
<string name="common_approving">Genehmigen</string>
|
||||
<string name="common_attention">Achtung</string>
|
||||
<string name="common_available_networks">Verfügbare Netzwerke</string>
|
||||
<string name="common_backup">Sicherungskopie</string>
|
||||
|
|
@ -274,14 +278,20 @@
|
|||
<item quantity="one">Tag</item>
|
||||
<item quantity="other">Tage</item>
|
||||
</plurals>
|
||||
<plurals name="common_days_time_ago">
|
||||
<item quantity="one">%d Tag zuvor</item>
|
||||
<item quantity="other">%d Tage zuvor</item>
|
||||
</plurals>
|
||||
<string name="common_delete">Entfernen</string>
|
||||
<string name="common_disable">Deaktivieren</string>
|
||||
<string name="common_disabled">Deaktiviert</string>
|
||||
<string name="common_disabling">Deaktivieren</string>
|
||||
<string name="common_disconnect">Trennen</string>
|
||||
<string name="common_done">Erledigt</string>
|
||||
<string name="common_edit">Bearbeiten</string>
|
||||
<string name="common_enable">Aktivieren</string>
|
||||
<string name="common_enabled">Aktiviert</string>
|
||||
<string name="common_enabling">Aktivieren</string>
|
||||
<string name="common_error">Fehler</string>
|
||||
<string name="common_estimated_fee">Aufladegebühr</string>
|
||||
<string name="common_exchange">Umtausch</string>
|
||||
|
|
@ -308,11 +318,16 @@
|
|||
<string name="common_hide">Ausblenden</string>
|
||||
<string name="common_hold_to">Halten bis %s</string>
|
||||
<string name="common_hour">Stunde</string>
|
||||
<plurals name="common_hours">
|
||||
<item quantity="one">Stunde</item>
|
||||
<item quantity="other">Stunde</item>
|
||||
</plurals>
|
||||
<plurals name="common_hours_time_ago">
|
||||
<item quantity="one">%dStunde her</item>
|
||||
<item quantity="other">%dStunden her</item>
|
||||
</plurals>
|
||||
<string name="common_import">Importieren</string>
|
||||
<string name="common_in">in</string>
|
||||
<string name="common_in_progress">In Arbeit</string>
|
||||
<string name="common_insufficient_balance">Unzureichende Mittel</string>
|
||||
<string name="common_later">Später</string>
|
||||
|
|
@ -327,6 +342,7 @@
|
|||
<item quantity="other">%dMinuten her</item>
|
||||
</plurals>
|
||||
<string name="common_month">Monat</string>
|
||||
<string name="common_more">Mehr</string>
|
||||
<string name="common_network_fee_title">Netzgebühr</string>
|
||||
<string name="common_network_fee_warning_content">Der überwiesene Betrag wird um %1$s (%2$s) gekürzt, um die gewählte Gebührenhöhe zu decken.</string>
|
||||
<plurals name="common_networks_count">
|
||||
|
|
@ -356,6 +372,8 @@
|
|||
<string name="common_range_with_space">%1$s — %2$s</string>
|
||||
<string name="common_read_more">Weiterlesen</string>
|
||||
<string name="common_receive">Empfangen</string>
|
||||
<string name="common_received">Erhalten</string>
|
||||
<string name="common_receiving">Empfang</string>
|
||||
<string name="common_recommended">Empfohlen</string>
|
||||
<string name="common_reject">Ablehnen</string>
|
||||
<string name="common_reload">Neu laden</string>
|
||||
|
|
@ -372,7 +390,10 @@
|
|||
<string name="common_select_action">Aktion auswählen</string>
|
||||
<string name="common_sell">Verkaufen</string>
|
||||
<string name="common_send">Senden</string>
|
||||
<string name="common_send_colon">Senden:</string>
|
||||
<string name="common_send_tx_error">Absenden der Transaktion fehlgeschlagen</string>
|
||||
<string name="common_sending">Senden</string>
|
||||
<string name="common_sent">Gesendet</string>
|
||||
<string name="common_server_unavailable">Der Server ist nicht verfügbar. Bitte versuche es später erneut.</string>
|
||||
<string name="common_share">Teilen</string>
|
||||
<string name="common_share_link">Link teilen</string>
|
||||
|
|
@ -383,6 +404,7 @@
|
|||
<string name="common_skip">Überspringen</string>
|
||||
<string name="common_something_went_wrong">Etwas ist schiefgelaufen.</string>
|
||||
<string name="common_stake">Staken</string>
|
||||
<string name="common_staked">Einsatz</string>
|
||||
<string name="common_staking">Staking</string>
|
||||
<string name="common_start">Start</string>
|
||||
<string name="common_submit">Einreichen</string>
|
||||
|
|
@ -390,6 +412,8 @@
|
|||
<string name="common_support">Unterstützung</string>
|
||||
<string name="common_supported_networks">Unterstützte Netzwerke</string>
|
||||
<string name="common_swap">Tauschen</string>
|
||||
<string name="common_swapped">Tauschen</string>
|
||||
<string name="common_swapping">Tauschen</string>
|
||||
<string name="common_tangem">Tangem</string>
|
||||
<string name="common_tangem_wallet">Tangem Wallet</string>
|
||||
<string name="common_tap_and_hold_hint">Tippen und halten</string>
|
||||
|
|
@ -398,6 +422,7 @@
|
|||
<string name="common_to">An</string>
|
||||
<string name="common_to_wallet_name">Zu %s</string>
|
||||
<string name="common_today">Heute</string>
|
||||
<string name="common_token">Token</string>
|
||||
<string name="common_token_send">Zu sendendes Token</string>
|
||||
<plurals name="common_tokens_count">
|
||||
<item quantity="one">%d Token</item>
|
||||
|
|
@ -407,6 +432,7 @@
|
|||
<string name="common_transaction_status">Transaktionsstatus</string>
|
||||
<string name="common_transactions">Transaktionen</string>
|
||||
<string name="common_transfer">Überweisung</string>
|
||||
<string name="common_transferred">Übertragen</string>
|
||||
<string name="common_unable_to_load">Die Daten konnten nicht geladen werden…</string>
|
||||
<string name="common_understand">Ich verstehe</string>
|
||||
<string name="common_understand_continue">Ich verstehe, fahre bitte fort.</string>
|
||||
|
|
@ -416,10 +442,12 @@
|
|||
<string name="common_unstake">Staking beenden</string>
|
||||
<string name="common_utxo_validate_withdrawal_message_warning">Aufgrund der Beschränkungen von %1$s können nur %2$d UTXOs in eine einzige Transaktion passen. Das bedeutet, dass du nur %3$s oder weniger senden kannst. Du musst den Betrag reduzieren.</string>
|
||||
<string name="common_value_copied">Wert kopiert</string>
|
||||
<string name="common_voting">Abstimmen</string>
|
||||
<string name="common_wallets">Meine Wallet</string>
|
||||
<string name="common_warning">Warnung</string>
|
||||
<string name="common_week">Woche</string>
|
||||
<string name="common_with">mit</string>
|
||||
<string name="common_withdrawing">Überweisen</string>
|
||||
<string name="common_yes">Ja</string>
|
||||
<string name="common_yield_mode">Ertragsmodus</string>
|
||||
<string name="contract_address_copied_message">Vertragsadresse kopiert!</string>
|
||||
|
|
@ -505,6 +533,10 @@
|
|||
<string name="dynamic_addresses_error_has_custom_token_title">Nicht verfügbar</string>
|
||||
<string name="dynamic_addresses_error_service_unavailable_description">Wir können im Moment keine Verbindung zum Provider herstellen. Bitte versuchen Sie es später noch einmal.</string>
|
||||
<string name="dynamic_addresses_error_service_unavailable_title">Der Dienst ist nicht verfügbar. Bitte versuchen Sie es erneut.</string>
|
||||
<string name="dynamic_addresses_notification_funds_found_description">Es wurden Gelder an zusätzlichen Adressen gefunden. Aktivieren deine Dynamische Adressen, um auf diese zuzugreifen.</string>
|
||||
<string name="dynamic_addresses_notification_funds_found_title">Auf weiteren Adressen gefundene Gelder</string>
|
||||
<string name="dynamic_addresses_receive_badge">Dynamische Adresse</string>
|
||||
<string name="dynamic_addresses_unavailability_reason_pending_transaction_send">Die Verwaltung dynamischer Adressen wird verfügbar sein, sobald die ausstehenden Transaktionen im Netzwerk eingegangen sind. %@ ist abgeschlossen</string>
|
||||
<string name="earn_best_opportunities">Beste Gelegenheiten</string>
|
||||
<string name="earn_clear_filter">Filter löschen</string>
|
||||
<string name="earn_empty">Die Liste ist vorübergehend leer, da sie gerade aktualisiert wird. Schauen Sie in Kürze wieder rein.</string>
|
||||
|
|
@ -515,7 +547,7 @@
|
|||
<string name="earn_filter_networks">Netzwerke</string>
|
||||
<string name="earn_mostly_used">Meist verwendet</string>
|
||||
<string name="earn_no_results">Keine Ergebnisse</string>
|
||||
<string name="earn_title">Verdienen</string>
|
||||
<string name="earn_title">Verdiene</string>
|
||||
<string name="email_preface_wc_error">Hallo Support-Team, ich habe einen Fehler mit dem Code %s festgestellt.</string>
|
||||
<string name="email_subject_wc_error">WalletConnect-Fehler</string>
|
||||
<string name="error_wrong_wallet_tapped">Du hast eine Karte oder Ring aus einer anderen Wallet verwendet. Tippe auf die Karte oder Ring, die dieser Wallet zugeordnet ist.</string>
|
||||
|
|
@ -577,12 +609,14 @@
|
|||
<string name="express_provider_best_rate">Bester Preis</string>
|
||||
<string name="express_provider_fca_warning_list">Warnliste der FCA</string>
|
||||
<string name="express_provider_fixed_rate_is_unavailable">Der Festzins ist nicht verfügbar</string>
|
||||
<string name="express_provider_for_swap">Anbieter für Tausch</string>
|
||||
<string name="express_provider_great_rate">Beste Wahl</string>
|
||||
<string name="express_provider_in_fca_warning_list">Anbieter in FCA-Warnliste</string>
|
||||
<string name="express_provider_max_amount">Verfügbar bis zu %s</string>
|
||||
<string name="express_provider_min_amount">Erhältlich bei %s</string>
|
||||
<string name="express_provider_not_available">Für dieses Paar nicht verfügbar</string>
|
||||
<string name="express_provider_permission_needed">Erlaubnis erforderlich</string>
|
||||
<string name="express_provider_permission_needed_v2">Genehmigung erforderlich</string>
|
||||
<string name="express_provider_recommended">Empfohlen</string>
|
||||
<string name="express_status_bought">Gekauft %s</string>
|
||||
<string name="express_status_buying">Kauf %s</string>
|
||||
|
|
@ -629,6 +663,7 @@
|
|||
<string name="give_permission_staking_footer">Die Genehmigungsfunktion ist erforderlich, um einer anderen Adresse die Berechtigung zur Verwendung einer bestimmten Menge Ihrer Token zu erteilen. Standardmäßig können Smart Contracts nicht auf deine Token zugreifen, es sei denn, du stimmen zu. Indem du deine Token \"freischaltest\", autorisierst du den StakeKit Smart Contract, sie zu verwenden. Die Miner des Netzwerks erhalten eine Gasgebühr (von dir bezahlt), um diese Aktion in der Blockchain aufzuzeichnen. Du kannst deine Token einsetzen, nachdem du die Genehmigung erteilt hast.</string>
|
||||
<string name="give_permission_staking_subtitle">Um fortzufahren, musst du Polygon Smart Contract erlauben, deine %s zu verwenden</string>
|
||||
<string name="give_permission_swap_subtitle" formatted="false">Um fortzufahren, erteile %1s Smart Contracts die Berechtigung, dein zu %2s verwenden.</string>
|
||||
<string name="give_permission_swap_subtitle_v2">Dezentrale Börsen benötigen eine Berechtigung, um mit Ihrer Wallet zu interagieren. %1s</string>
|
||||
<string name="give_permission_title">Erlaubnis erteilen</string>
|
||||
<string name="give_permission_unlimited">Unbegrenzt</string>
|
||||
<string name="hardware_wallet_backup_feature_description">Die Adressen werden direkt auf Deiner Tangem-Hardware-Wallet generiert – sofort einsatzbereit und vollständig geschützt.</string>
|
||||
|
|
@ -656,6 +691,8 @@
|
|||
<string name="hw_backup_banner_description">Hält Deine Kryptowährungen sicher und offline. Schlank wie eine Kreditkarte, sicherer als ein Banktresor.</string>
|
||||
<string name="hw_backup_close_description">Wenn dies der Fall ist, musst Du von vorne beginnen.</string>
|
||||
<string name="hw_backup_google_drive_description">Vorhandene Wallet über Google Drive-Backup wiederherstellen</string>
|
||||
<string name="hw_backup_google_drive_dialog_message">Wir arbeiten an einer Google Drive-Datensicherung, um die Wiederherstellung der Wallet noch einfacher zu gestalten.</string>
|
||||
<string name="hw_backup_google_drive_dialog_title">Google Drive-Sicherung kommt bald</string>
|
||||
<string name="hw_backup_google_drive_title">Google Drive-Backup</string>
|
||||
<string name="hw_backup_hardware_create_description">Erstelle eine neue, sichere Wallet und übertrage Deine Gelder, um zusätzlichen Schutz zu gewährleisten.</string>
|
||||
<string name="hw_backup_hardware_create_title">Neue Wallet erstellen</string>
|
||||
|
|
@ -713,7 +750,7 @@
|
|||
<string name="hw_upgrade_key_migration_title">Schlüsselmigration</string>
|
||||
<string name="hw_upgrade_scan_device">Gerät scannen</string>
|
||||
<string name="hw_upgrade_start_action">Upgrade starten</string>
|
||||
<string name="hw_upgrade_start_description">Du stehst kurz vor dem Upgrade auf unsere Hardware-Wallet. Damit werden Deine Vermögenswerte sicher in Offline-Speichern aufbewahrt.</string>
|
||||
<string name="hw_upgrade_start_description">Du stehst kurz vor dem Upgrade auf unsere Hardware-Wallet. Deine Vermögenswerte werden darin sicher im Offline-Speicher aufbewahrt.</string>
|
||||
<string name="hw_upgrade_start_title">Tangem Wallet</string>
|
||||
<string name="hw_upgrade_title">Upgrade auf Hardware Wallet</string>
|
||||
<string name="hw_upgrade_to_cold_banner_description">Schütze Deine Kryptowährungen mit Tangems erstklassiger Hardware-Wallet.</string>
|
||||
|
|
@ -775,6 +812,7 @@
|
|||
<string name="markets_add_to_my_portfolio_unavailable_for_wallet_description">Dieses Asset ist für dieses Wallet nicht verfügbar</string>
|
||||
<string name="markets_add_token">Hinzufügen</string>
|
||||
<string name="markets_apy_placeholder">APY %s</string>
|
||||
<string name="markets_common_market_price">Marktpreis</string>
|
||||
<string name="markets_common_my_portfolio">Mein Portfolio</string>
|
||||
<string name="markets_common_title">Markt</string>
|
||||
<string name="markets_earn_common_title">Verdiene Geld mit Tangem</string>
|
||||
|
|
@ -787,10 +825,11 @@
|
|||
<string name="markets_loading_no_data_title">Keine Daten</string>
|
||||
<string name="markets_portfolio_block_add_token_title">**Hinzufügen zu Ihrem Portfolio**, um mit dem Kauf, Tausch oder Erhalt dieses Vermögenswerts zu beginnen</string>
|
||||
<string name="markets_portfolio_block_subtitle">Zum Portfolio hinzufügen</string>
|
||||
<string name="markets_portfolio_block_title">Dein Portfolio</string>
|
||||
<string name="markets_pulse_common_title">Marktimpuls</string>
|
||||
<string name="markets_quick_actions">Schnelle Aktionen</string>
|
||||
<string name="markets_search_clear_all_hints">Alles löschen</string>
|
||||
<string name="markets_search_header_title">Markt durchsuchen</string>
|
||||
<string name="markets_search_header_title">Token suchen</string>
|
||||
<string name="markets_search_hint_header">Neueste</string>
|
||||
<string name="markets_search_portfolio_header">In Ihrem Portfolio</string>
|
||||
<string name="markets_search_result_title">Ergebnis</string>
|
||||
|
|
@ -816,6 +855,7 @@
|
|||
<string name="markets_sort_by_yield_mode_title">Ertragsmodus</string>
|
||||
<string name="markets_staking_banner_description_placeholder">Staking ist der einfachste Weg, um Belohnungen für Deine Kryptowährung zu erhalten. %s</string>
|
||||
<string name="markets_staking_banner_title">Verdiene bis zu %s APY</string>
|
||||
<string name="markets_token_add_subtitle">in einem anderen Netzwerk oder Konto</string>
|
||||
<string name="markets_token_added">Token hinzugefügt</string>
|
||||
<string name="markets_token_details_about_token_title">Über %s</string>
|
||||
<plurals name="markets_token_details_amount_exchanges">
|
||||
|
|
@ -980,7 +1020,7 @@
|
|||
<string name="notification_visa_waitlist_promo_text">Trage dich in die Warteliste ein und erhalte eine Zahlungskarte, die es so noch nie gab.</string>
|
||||
<string name="notification_visa_waitlist_promo_title">Tangem Visa Card</string>
|
||||
<string name="notification_yield_promo_button">Bedingungen</string>
|
||||
<string name="notification_yield_promo_text">Zahlen Sie mindestens $100 ein, halten Sie den Betrag 30 Tage und erhalten Sie $10.</string>
|
||||
<string name="notification_yield_promo_text">Zahle mindestens $100 ein, halten den Betrag 30 Tage und erhalte $10.</string>
|
||||
<string name="notification_yield_promo_title">Yield-Mode-Kampagne</string>
|
||||
<string name="onboarding_access_code_feature_1_description">Du musst einen einzigen Zugangscode einrichten, um alle deine Geräte zu schützen</string>
|
||||
<string name="onboarding_access_code_feature_1_title">Schützen</string>
|
||||
|
|
@ -997,6 +1037,11 @@
|
|||
<string name="onboarding_activation_error_message">Bitte wiederhole den Vorgang. Die Karte oder Ring wird auf Werkseinstellungen zurückgesetzt.</string>
|
||||
<string name="onboarding_activation_error_title">Aktivierungsfehler</string>
|
||||
<string name="onboarding_add_tokens">Token hinzufügen</string>
|
||||
<plurals name="onboarding_address_sync_description">
|
||||
<item quantity="one">Adressen synchronisieren, um eine Adresse für das Netzwerk %d zu erhalten</item>
|
||||
<item quantity="other">Adressen synchronisieren, um eine Adresse für das Netzwerk %d zu erhalten</item>
|
||||
</plurals>
|
||||
<string name="onboarding_address_sync_title">Synchronisiere dein Wallet</string>
|
||||
<string name="onboarding_alert_message_not_max_backup_cards_added">Du hast eine Backup-Karte oder einen Backup-Ring hinzugefügt. Nach Abschluss des Backup-Vorgangs kannst Du keine weiteren Backup-Geräte hinzufügen. Wenn Du eine weitere Karte oder einen weiteren Ring hast, fügen diesen dem Backup jetzt hinzu. Möchtest Du den Backup-Vorgang fortsetzen?</string>
|
||||
<string name="onboarding_backup_exit_warning">Der Sicherungsvorgang ist teilweise abgeschlossen. Du kannst ihn jetzt nicht beenden.</string>
|
||||
<string name="onboarding_bottom_sheet_passphrase_description">Eine Passphrase ist eine optionale Sicherheitsfunktion, die Deiner Wiederherstellungsphrase ein Wort oder eine Phrase hinzufügt und so einen neuen Satz von Wallet-Adressen für zusätzlichen Schutz erstellt.</string>
|
||||
|
|
@ -1026,7 +1071,9 @@
|
|||
<string name="onboarding_getting_started">Erste Schritte</string>
|
||||
<string name="onboarding_linking_error_card_with_wallets">Für die Karte oder Ring, die du hinzufügen möchtest, wurde bereits eine andere Wallets erstellt. Wenn du Guthaben auf dieser Wallets hast, hebe es bitte ab, setze diese Karte oder Ring zurück und füge sie als Backup hinzu.</string>
|
||||
<string name="onboarding_navbar_save_wallet">Sicher deine Wallet</string>
|
||||
<string name="onboarding_navbar_title_biometrics">Biometrische Daten nutzen</string>
|
||||
<string name="onboarding_navbar_title_creating_backup">Backups anlegen</string>
|
||||
<string name="onboarding_navbar_title_last_step">Letzter Schritt</string>
|
||||
<string name="onboarding_navbar_upgrade_wallet_biometrics">Biometrische Daten</string>
|
||||
<string name="onboarding_seed_button_read_more">Lese mehr über die Seed-Phrase</string>
|
||||
<plurals name="onboarding_seed_generate_message_words_count">
|
||||
|
|
@ -1093,12 +1140,20 @@
|
|||
<string name="onramp_error_transaction_already_processed">Diese Transaktion wurde bereits verarbeitet. Es sind keine weiteren Maßnahmen erforderlich.</string>
|
||||
<string name="onramp_fetching_best_rates">Die besten Preise erzielen...</string>
|
||||
<string name="onramp_instant_status">Sofort</string>
|
||||
<string name="onramp_kyc_verification_bullet_free">Die Verifizierung ist kostenlos und dauert in der Regel 1-2 Minuten</string>
|
||||
<string name="onramp_kyc_verification_bullet_privacy">Tangem hat keinen Zugriff auf Ihre Identitätsinformationen; Sie teilen Daten direkt mit dem regulierten Anbieter.</string>
|
||||
<string name="onramp_kyc_verification_bullet_unlocks">Die Verifizierung schaltet den vollen Zugang zu zukünftigen Transaktionen mit diesem Anbieter frei</string>
|
||||
<string name="onramp_kyc_verification_choose_another">Wählen Sie eine andere Methode</string>
|
||||
<string name="onramp_kyc_verification_subtitle">Zur Einhaltung der örtlichen Vorschriften verlangt %@ eine Identitätsprüfung.</string>
|
||||
<string name="onramp_kyc_verification_title">Identitätsprüfung durch den Zahlungsanbieter erforderlich</string>
|
||||
<string name="onramp_kyc_verification_verify_button">Verifizieren</string>
|
||||
<string name="onramp_kyc_verification_whats_important">Was ist wichtig?</string>
|
||||
<string name="onramp_legal">Durch die Nutzung der Onramp-Funktionalität stimmst Du den %1$s und %2$s des Anbieters zu.</string>
|
||||
<string name="onramp_legal_text">Der Service wird von einem externen Anbieter bereitgestellt. \n Tangem übernimmt keine Verantwortung.</string>
|
||||
<string name="onramp_max_amount_restriction">Der Kaufbetrag sollte nicht höher sein als %s</string>
|
||||
<string name="onramp_min_amount_restriction">Der zu kaufende Betrag muss mindestens %s betragen</string>
|
||||
<string name="onramp_no_available_providers">Keine verfügbaren Anbieter für diese Währung</string>
|
||||
<string name="onramp_offer_type_fastet">Schnellste</string>
|
||||
<string name="onramp_offer_type_fastet">Schnellste Bearbeitung</string>
|
||||
<string name="onramp_pay_with">Bezahlen mit</string>
|
||||
<string name="onramp_payment_method_subtitle">Zahlungsmethode</string>
|
||||
<string name="onramp_provider_max_amount">Verfügbar bis zu %s</string>
|
||||
|
|
@ -1156,6 +1211,13 @@
|
|||
<string name="qr_scanner_error_unsupported_network_title">Keine unterstützten Token gefunden</string>
|
||||
<string name="qr_scanner_warning_unknown_parameters_message">Dieser QR-Code enthält Parameter, die nicht erkannt werden: %s. Einige Zahlungsdetails können verloren gehen, wenn Sie fortfahren.</string>
|
||||
<string name="qr_scanner_warning_unknown_parameters_title">Unbekannte Parameter</string>
|
||||
<string name="quick_action_buy_description">Kreditkarte oder Bankkonto</string>
|
||||
<string name="quick_action_receive_description">Teilen deine Adresse oder dein QR-Code</string>
|
||||
<string name="quick_action_sell_description">Sicherer Verkauf von Kryptowährungen</string>
|
||||
<string name="quick_action_send_description">An eine andere Wallet senden</string>
|
||||
<string name="quick_action_swap_description">Zwischen deinen Portfolios</string>
|
||||
<string name="quick_top_up_chip_other">Andere</string>
|
||||
<string name="quick_top_up_title">Schnell aufladen</string>
|
||||
<string name="receive_bottom_sheet_no_memo_required_message">Kein Memo erforderlich</string>
|
||||
<string name="receive_bottom_sheet_warning_message">%1$s ( %2$s ) im %3$s Netzwerk</string>
|
||||
<string name="receive_bottom_sheet_warning_message_compact">%1$s im %2$s Netzwerk</string>
|
||||
|
|
@ -1512,23 +1574,34 @@
|
|||
<string name="sui_not_enough_coin_for_fee_description">Zum Fortfahren ist eine eingehende Transaktion von mindestens %1$s erforderlich</string>
|
||||
<string name="sui_not_enough_coin_for_fee_title">Unzureichende Mittel</string>
|
||||
<string name="swap_approve_description">Durch die Genehmigung erlaubst Du dem Smart Contract, Deine Token in zukünftigen Transaktionen zu verwenden.</string>
|
||||
<string name="swap_detailed_mode">Detaillierter Modus</string>
|
||||
<string name="swap_fixed_rate">Fester Zinssatz</string>
|
||||
<string name="swap_give_permission_fee_footer">Das Netzwerk erhebt eine Token-Genehmigungsgebühr, um zu überprüfen, ob Sie die Verwendung Ihres Tokens für den Swap genehmigen.</string>
|
||||
<string name="swap_in_progress">Tausch läuft</string>
|
||||
<string name="swap_promo_text">Tausche mehr Token zu besseren Kursen direkt in deiner Brieftasche.</string>
|
||||
<string name="swap_promo_title">Neuer Swap-Anbieter verfügbar!</string>
|
||||
<string name="swap_search_suggestion_hint">Suchen Sie etwas anderes?\n Versuchen Sie es mit der Suche oder erkunden Sie eine andere Kryptowährung!</string>
|
||||
<string name="swap_search_tooltip_description">Suchen Sie nach einem beliebigen Token, auch wenn es noch nicht in Ihrer Liste ist.</string>
|
||||
<string name="swap_search_tooltip_description">Suche nach einem beliebigen Token, auch wenn es noch nicht in deiner Liste ist.</string>
|
||||
<string name="swap_search_tooltip_title">Nutzen Sie die Suche, um zu finden, was Sie benötigen.</string>
|
||||
<string name="swap_simple_mode">Einfacher Modus</string>
|
||||
<string name="swap_story_fifth_subtitle">Vertraue auf den rund um die Uhr verfügbaren Support bei allen Problemen</string>
|
||||
<string name="swap_story_fifth_title">Immer für Dich da</string>
|
||||
<string name="swap_story_first_subtitle">Mehrere vertrauenswürdige Anbieter an einem Ort – tausche mühelos alle Vermögenswerte in Deiner Wallet</string>
|
||||
<string name="swap_story_first_subtitle_v2">Tauschen Sie Kryptowährungen direkt in Tangem\nkeine zusätzlichen Überweisungen\nkeine Verschiebung von Geldern zu Börsen</string>
|
||||
<string name="swap_story_first_title">Tausche mit uns</string>
|
||||
<string name="swap_story_first_title_v2">Tausche innerhalb deiner Wallet</string>
|
||||
<string name="swap_story_forth_subtitle">Keine Fummeleien, keine Umsätze, keine blinden Flecken – Deine Transaktion ist immer geschützt</string>
|
||||
<string name="swap_story_forth_subtitle_v2">Tauschvorgänge werden über vertrauenswürdige Anbieter abgewickelt. Deine Schlüssel verbleiben jederzeit in deiner Tangem-Wallet. Klar. Transparent. Selbstverwahrung.</string>
|
||||
<string name="swap_story_forth_title">Undurchdringliche Verteidigung</string>
|
||||
<string name="swap_story_forth_title_v2">Du behältst die Kontrolle</string>
|
||||
<string name="swap_story_second_subtitle">Maximiere Deine Wert mit Tarifen aus einem breiten Netzwerk vertrauenswürdiger Anbieter und wähle immer den Besten aus</string>
|
||||
<string name="swap_story_second_subtitle_v2">Tangem vergleicht mehrere Anbieter, sowohl DEX als auch CEX. Der beste Kurs wird automatisch ausgewählt. Bevorzugst Du einen anderen Anbieter? Dann kannst du ihn manuell auswählen.</string>
|
||||
<string name="swap_story_second_title">Unschlagbare Preise</string>
|
||||
<string name="swap_story_second_title_v2">Bester verfügbarer Preis</string>
|
||||
<string name="swap_story_third_subtitle">Problemlos und intuitiv, sodass Deine Token mit nur wenigen Handgriffen getauscht werden können</string>
|
||||
<string name="swap_story_third_subtitle_v2">Tauschen Token über viele Netzwerke und Tausende von Token hinweg 0% Gebühr für Stablecoin-zu-Stablecoin-swaps</string>
|
||||
<string name="swap_story_third_title">Einfach bequem</string>
|
||||
<string name="swap_story_third_title_v2">90+ Blockchains\n16.000+ Vermögenswerte</string>
|
||||
<string name="swap_via_provider">Tausch über Anbieter</string>
|
||||
<string name="swap_your_assets_title">Dein Vermögen</string>
|
||||
<string name="swapping_alert_cex_description">Der Betrag umfasst:\n- Gebühr des Dienstanbieters\n- Netzgebühr für die Rücksendung von %s von der Vermittlungsstelle an die Adresse des Nutzers.</string>
|
||||
|
|
@ -1539,7 +1612,9 @@
|
|||
<string name="swapping_approve_information_text">Alle dezentralen Börsen benötigen Genehmigungen, um zu verhindern, dass intelligente Verträge ohne Ihre Erlaubnis auf Ihre Geldbörse zugreifen. Smart Contracts können nicht auf Ihre Token zugreifen, wenn Sie nicht zustimmen. Indem Sie Ihre Token \"freischalten\", ermächtigen Sie den 1-Zoll-Smart-Contract, sie auszugeben. Die Miner des Netzwerks erhalten eine (von Ihnen bezahlte) Gasgebühr, um diese Aktion in der Blockchain aufzuzeichnen. Sie können Ihre Token tauschen, nachdem Sie Ihre Zustimmung gegeben haben.</string>
|
||||
<string name="swapping_approve_information_title">Genehmigen</string>
|
||||
<string name="swapping_fee_estimation_error_text">Fehler bei der Gebührenschätzung. Bitte sende dein Feedback an den Support.</string>
|
||||
<string name="swapping_from_account_title">Du sendest vom</string>
|
||||
<string name="swapping_from_title">Du wechselst</string>
|
||||
<string name="swapping_from_title_v2">De sendest</string>
|
||||
<string name="swapping_high_price_impact_description">Der Tausch dieser Menge ausgewählter Token hat erhebliche Auswirkungen auf den Preis und verringert dein Ergebnis.</string>
|
||||
<string name="swapping_high_price_impact_text">Aufgrund geringer Liquidität erhalten Sie möglicherweise deutlich weniger. Versuchen Sie es mit einem kleineren Betrag oder einem anderen Anbieter.</string>
|
||||
<string name="swapping_high_price_impact_title">Hoher Einfluss auf den Preis</string>
|
||||
|
|
@ -1548,11 +1623,14 @@
|
|||
<string name="swapping_permission_header">Erlaubnis erteilen</string>
|
||||
<string name="swapping_swap_action">Tauschen</string>
|
||||
<string name="swapping_swap_action_in_progress">Tauschen...</string>
|
||||
<string name="swapping_to_account_title">Zu erhaltender Betrag</string>
|
||||
<string name="swapping_to_title">Du erhältst</string>
|
||||
<string name="swapping_token_list_title">Token auswählen</string>
|
||||
<string name="swapping_token_not_available">Nicht verfügbar</string>
|
||||
<string name="swapping_trade_too_large_text">Nicht genug Liquidität für diesen Handel. Reduzieren Sie den Betrag oder wählen Sie einen anderen Anbieter.</string>
|
||||
<string name="swapping_trade_too_large_title">Handel zu groß</string>
|
||||
<string name="swapping_transfer_action">Übertragung</string>
|
||||
<string name="swapping_transfer_action_in_progress">Übertragung</string>
|
||||
<string name="tangem_pay_beta_notification_subtitle">Wir freuen uns über Ihr Feedback</string>
|
||||
<string name="tangem_pay_beta_notification_title">Tangem Pay jetzt in der Beta</string>
|
||||
<string name="tangem_pay_card_details_unable_to_rename_card_title">Karte kann nicht umbenannt werden</string>
|
||||
|
|
@ -1633,7 +1711,7 @@
|
|||
<string name="tangempay_card_details_show_details">Details anzeigen</string>
|
||||
<string name="tangempay_card_details_swap_description">Tausche beliebige Vermögenswerte in Deinem Portfolio für deine Karte.</string>
|
||||
<string name="tangempay_card_details_title">Kartendetails</string>
|
||||
<string name="tangempay_card_details_unable_to_rename_card_description">Bitte versuchen Sie es später noch einmal.</string>
|
||||
<string name="tangempay_card_details_unable_to_rename_card_description">Bitte versuche es später noch einmal.</string>
|
||||
<string name="tangempay_card_details_unfreeze_card">Karte entsperren</string>
|
||||
<string name="tangempay_card_details_view_pin_code_description">Komm zurück zur App, falls du es vergisst.</string>
|
||||
<string name="tangempay_card_details_view_pin_code_title">Dein PIN-Code</string>
|
||||
|
|
@ -1641,6 +1719,7 @@
|
|||
<string name="tangempay_card_details_withdraw_error_title">Auszahlung derzeit nicht möglich</string>
|
||||
<string name="tangempay_card_details_withdraw_in_progress_description">Sie können keinen Tausch oder eine neue Auszahlung starten, bis die aktuelle abgeschlossen ist.</string>
|
||||
<string name="tangempay_card_details_withdraw_in_progress_title">Auszahlung läuft</string>
|
||||
<string name="tangempay_card_edit_name_placeholder">Kartenname</string>
|
||||
<string name="tangempay_card_limit_setup_amount_subtitle">Limit festlegen ab %s</string>
|
||||
<string name="tangempay_card_limit_setup_error_message">Das Limit konnte nicht festgelegt werden. Bitte versuchen Sie es erneut.</string>
|
||||
<string name="tangempay_card_page_daily_limit_change">Ändern</string>
|
||||
|
|
@ -1692,6 +1771,8 @@
|
|||
<string name="tangempay_onboarding_purchases_title">Zahlen Sie genau das, was Sie sehen</string>
|
||||
<string name="tangempay_onboarding_security_description">Ein separates Zahlungskonto wird erstellt, ohne Ihre Adressen und Vermögenswerte offenzulegen</string>
|
||||
<string name="tangempay_onboarding_security_title">Unerreichte Privatsphäre</string>
|
||||
<string name="tangempay_onboarding_setup_wallet_description">Verknüpfen Sie eine Zahlungskarte</string>
|
||||
<string name="tangempay_onboarding_setup_wallet_title">Wir richten eine Wallet ein.</string>
|
||||
<string name="tangempay_onboarding_title">Erhalten Sie Ihre kostenlose Tangem Pay Card in wenigen Minuten</string>
|
||||
<string name="tangempay_pay_support">Bezahlen mit</string>
|
||||
<string name="tangempay_payment_account">Zahlungskonto</string>
|
||||
|
|
@ -1741,6 +1822,7 @@
|
|||
<string name="token_button_unavailability_reason_yield_supply_approval">Die Genehmigung wurde widerrufen. Dein Guthaben befindet sich weiterhin im Ertragsmodus. Um Aktionen durchzuführen, wechsel bitte in den Ertragsmodus und erteilen die Berechtigung erneut.</string>
|
||||
<string name="token_details_balance_available">Verfügbares Guthaben</string>
|
||||
<string name="token_details_balance_total">Gesamtsaldo</string>
|
||||
<string name="token_details_earn_staking_subtitle">Bis zu %s effektiver Jahreszins</string>
|
||||
<string name="token_details_generate_xpub">Generiere XPUB</string>
|
||||
<string name="token_details_hide_alert_hide">Ausblenden</string>
|
||||
<string name="token_details_hide_alert_message">Du bist dabei, dieses Token vom Hauptbildschirm auszublenden. Du kannst es jederzeit über die Seite „Token verwalten“ wieder hinzufügen.</string>
|
||||
|
|
@ -1761,17 +1843,26 @@
|
|||
<string name="token_swap_changelly_promotion_message">Tausche diesen Token gegen einen anderen zu %1$s Servicegebühren von Februar %2$s-%3$s.</string>
|
||||
<string name="token_swap_changelly_promotion_title">Tausche mit Changelly, %s Gebühren</string>
|
||||
<string name="token_swap_promotion_button">Jetzt tauschen</string>
|
||||
<string name="tokens_list_hot_crypto_header">Hot Krypto 🔥</string>
|
||||
<string name="tokens_list_hot_crypto_header">Markttrend 🔥</string>
|
||||
<string name="tokens_list_unavailable_to_purchase_header">Nicht verfügbar zum Kauf</string>
|
||||
<string name="tokens_list_unavailable_to_sell_header">Nicht zum Verkauf verfügbar</string>
|
||||
<string name="tokens_list_unavailable_to_swap_header">Nicht verfügbar für Tausch von %s</string>
|
||||
<string name="tokens_list_unavailable_to_swap_source_header">Nicht zum Tausch verfügbar</string>
|
||||
<string name="transaction_history_claiming_reward">Belohnung einfordern</string>
|
||||
<string name="transaction_history_contract_address">Vertrag: %s</string>
|
||||
<string name="transaction_history_disabling_yield_mode">Deaktivierung des Ertragsmodus</string>
|
||||
<string name="transaction_history_earned_from_stake">Verdient aus dem Einsatz</string>
|
||||
<string name="transaction_history_empty_transactions">Du hast noch keine Transaktionen</string>
|
||||
<string name="transaction_history_error_failed_to_load">Der Transaktionsverlauf konnte nicht geladen werden.\nKlicke auf die Schaltfläche Neu laden, um die Informationen zu aktualisieren.</string>
|
||||
<string name="transaction_history_from_inline_address">aus: %%image%% %s</string>
|
||||
<string name="transaction_history_multiple_addresses">Mehrere Adressen</string>
|
||||
<string name="transaction_history_not_supported_description">Die Transaktionshistorie wird für diese Blockchain derzeit nicht verfügbar. Aber keine Sorge, wir arbeiten daran! In der Zwischenzeit kannst du es im Explorer überprüfen.</string>
|
||||
<string name="transaction_history_operation">Operation</string>
|
||||
<string name="transaction_history_pending">Ausstehend</string>
|
||||
<string name="transaction_history_rewards_restaked">Belohnungen neu stecken</string>
|
||||
<string name="transaction_history_rewards_restaking">Belohnungen</string>
|
||||
<string name="transaction_history_staking_reward">Staking-Belohnungen</string>
|
||||
<string name="transaction_history_to_inline_address">zu: %%image%% %s</string>
|
||||
<string name="transaction_history_transaction_for_address">für: %s</string>
|
||||
<string name="transaction_history_transaction_from_address">von: %s</string>
|
||||
<string name="transaction_history_transaction_to_address">zu: %s</string>
|
||||
|
|
@ -2051,6 +2142,10 @@
|
|||
<item quantity="one">Verwende deine Karte oder Ring, um eine Adresse für das %d-Netz zu erhalten</item>
|
||||
<item quantity="other">Verwende deine Karte oder Ring, um mehrere Adressen für die %d-Netzwerke zu erhalten</item>
|
||||
</plurals>
|
||||
<plurals name="warning_missing_derivation_no_nfc_message">
|
||||
<item quantity="one">Adressen synchronisieren, um eine Adresse für das Netzwerk %d zu erhalten</item>
|
||||
<item quantity="other">Adressen synchronisieren, um eine Adresse für das Netzwerk %d zu erhalten</item>
|
||||
</plurals>
|
||||
<string name="warning_missing_derivation_title">Einige Adressen fehlen</string>
|
||||
<string name="warning_network_unreachable_message">Das Netzwerk ist derzeit nicht erreichbar. Bitte versuchen Sie es später erneut.</string>
|
||||
<string name="warning_network_unreachable_title">Netzwerk ist nicht erreichbar</string>
|
||||
|
|
@ -2217,6 +2312,7 @@
|
|||
<string name="yield_module_approve_sheet_fee_note">Die Gebühr wird abgezogen und Dein Vermögen wird erneut verliehen.</string>
|
||||
<string name="yield_module_approve_sheet_subtitle">Um weiterhin Geld verdienen zu können, ist eine Genehmigung erforderlich.</string>
|
||||
<string name="yield_module_approve_sheet_title">Genehmigung bestätigen</string>
|
||||
<string name="yield_module_average_apy">Durchschnittlicher Jahreszins %1$s%%</string>
|
||||
<string name="yield_module_balance_info_sheet_subtitle">Deine Gelder werden derzeit dem Aave-Protokoll bereitgestellt, Du kannst sie jedoch jederzeit verwalten.</string>
|
||||
<string name="yield_module_balance_info_sheet_title">Deine%s ist in Aave hinterlegt</string>
|
||||
<string name="yield_module_chart_loading_error">Chart konnte nicht geladen werden...</string>
|
||||
|
|
@ -2230,18 +2326,18 @@
|
|||
<string name="yield_module_earn_sheet_my_funds_title">Meine Mittel</string>
|
||||
<string name="yield_module_earn_sheet_provider_description">Deine %1$s sind nun bei Aave angelegt und erwirtschaften Rendite. Du besitzt %2$s -Token, die Dein Guthaben repräsentieren und automatisch Rendite generieren. Bei jeder Aufladung wird Dein Aave-Konto zusätzliches Guthaben gutgeschrieben, um weitere Rendite zu erzielen (abzüglich Gebühren).</string>
|
||||
<string name="yield_module_earn_sheet_title">Ertragsmodus</string>
|
||||
<string name="yield_module_earn_sheet_total_earnings_title">Gesamtverdienst</string>
|
||||
<string name="yield_module_earn_sheet_total_earnings_title">Gesamtertrag</string>
|
||||
<string name="yield_module_earn_sheet_transfers_title">Übertragungen zu Aave</string>
|
||||
<string name="yield_module_explore_sheet_explore_aave_button_title">Entdecke Aave</string>
|
||||
<string name="yield_module_fee_policy_sheet_current_fee_note">Dies ist die aktuelle Liefergebühr auf %s. Die tatsächlichen Kosten werden auf der Registerkarte \"Aktivierung\" angezeigt.</string>
|
||||
<string name="yield_module_fee_policy_sheet_current_fee_title">Aktuelle Gebühr</string>
|
||||
<string name="yield_module_fee_policy_sheet_description">Alle zukünftigen %s-Einzahlungen werden automatisch an Aave geliefert, wobei die Transaktionsgebühr abgezogen wird.</string>
|
||||
<string name="yield_module_fee_policy_sheet_description">Alle zukünftigen %s Das Guthaben wird Aave automatisch gutgeschrieben, nachdem die Transaktionsgebühr abgezogen wurde.</string>
|
||||
<string name="yield_module_fee_policy_sheet_fee_note">Von jeder zukünftigen Aufladung wird eine ungefähre Netzwerkgebühr von %1$s ( %2$s ) abgezogen, die Dein Limit von %3$s ( %4$s ) nicht überschreiten wird.</string>
|
||||
<string name="yield_module_fee_policy_sheet_max_fee_note">Wenn die Netzwerkgebühren über die maximale Gebühr steigen, wird die Transaktion erst durchgeführt, wenn diese sinken. Du kannst dieses Limit später ändern.</string>
|
||||
<string name="yield_module_fee_policy_sheet_max_fee_title">Maximale Gebühr</string>
|
||||
<string name="yield_module_fee_policy_sheet_min_amount_note">Der Mindestbetrag wird auf Grundlage der aktuellen Netzwerkgebühr berechnet, sodass er 4%% des Aufladebetrags nicht überschreitet, was einen Mindestbetrag von %1$s (%2$s) ergibt.</string>
|
||||
<string name="yield_module_fee_policy_sheet_min_amount_title">Mindestaufladung</string>
|
||||
<string name="yield_module_fee_policy_sheet_title">Gebührenpolitik</string>
|
||||
<string name="yield_module_fee_policy_sheet_title">Gebührenregelung für Aufladungen</string>
|
||||
<string name="yield_module_fee_policy_tangem_service_fee_title">Tangem erhebt außerdem eine Servicegebühr von 15% auf den erzielten Ertrag.</string>
|
||||
<string name="yield_module_high_fee_error">Deine Gelder werden automatisch an Aave überwiesen, sobald die Netzwerkgebühren niedriger sind oder Dein Guthaben den erforderlichen Mindestbetrag erreicht.</string>
|
||||
<string name="yield_module_high_network_fees_notification_description">Die Gebühren sind aufgrund der hohen Marktaktivität derzeit höher als üblich. Du kannst jetzt fortfahren oder später noch einmal vorbeischauen, wenn die Gebühren niedriger sind.</string>
|
||||
|
|
@ -2252,13 +2348,13 @@
|
|||
<string name="yield_module_main_view_approve_notification_title">Token-Genehmigung erforderlich</string>
|
||||
<string name="yield_module_network_fee_unreachable_notification_description">Prüfe Deine Netzwerkverbindung</string>
|
||||
<string name="yield_module_network_fee_unreachable_notification_title">Informationen zu den Netzwerkgebühren nicht erreichbar</string>
|
||||
<string name="yield_module_promo_screen_auto_balance_subtitle">Jede Einzahlung, die Du tätigst, wird automatisch an Aave weitergeleitet.</string>
|
||||
<string name="yield_module_promo_screen_auto_balance_subtitle">Jede Aufladung wird automatisch an Aave übermittelt.</string>
|
||||
<string name="yield_module_promo_screen_auto_balance_subtitle_v2">Alle %1$s auf Ihrem Konto werden automatisch an Aave bereitgestellt.</string>
|
||||
<string name="yield_module_promo_screen_auto_balance_title">Automatische Übertragung zu Aave</string>
|
||||
<string name="yield_module_promo_screen_cash_out_subtitle">Senden, tauschen oder verkaufen Deine Gelder sofort, wann immer Du willst.</string>
|
||||
<string name="yield_module_promo_screen_cash_out_title">Sofort verfügbar</string>
|
||||
<string name="yield_module_promo_screen_how_it_works_button_title">Wie funktioniert das?</string>
|
||||
<string name="yield_module_promo_screen_self_custodial_subtitle">Aave ist ein On-Chain-Protokoll zur Erstellung von nicht-kustodialen Liquiditätsmärkten, um Zinsen mit variablem Satz zu verdienen.</string>
|
||||
<string name="yield_module_promo_screen_self_custodial_subtitle">Aave ist ein On-Chain-Protokoll, das Non-Custodial-Liquiditätsmärkte bietet und es Nutzern ermöglicht, Renditen zu variablen Zinssätzen zu erzielen.</string>
|
||||
<string name="yield_module_promo_screen_self_custodial_title">Dezentral und selbstverwahrend</string>
|
||||
<string name="yield_module_promo_screen_terms_disclaimer">Durch die Nutzung dieses Dienstes erklärst Du Dich mit provider\n%1$s und %2$s einverstanden</string>
|
||||
<string name="yield_module_promo_screen_title">Mit Aave verbinden</string>
|
||||
|
|
@ -2268,18 +2364,18 @@
|
|||
<string name="yield_module_provider">Aave</string>
|
||||
<string name="yield_module_rate_info_sheet_chart_average">Durchschnitt %s</string>
|
||||
<string name="yield_module_rate_info_sheet_chart_title">Renditen des letzten Jahres</string>
|
||||
<string name="yield_module_rate_info_sheet_description">Der aktuelle Zinssatz ist immer variabel und wird automatisch vom Aave On-Chain-Smart-Contract auf der Grundlage von Angebot und Nachfrage in Echtzeit berechnet.</string>
|
||||
<string name="yield_module_rate_info_sheet_description">Der aktuelle Zinssatz ist stets variabel und wird automatisch vom On-Chain-Smart-Contract von Aave auf Basis von Angebot und Nachfrage in Echtzeit berechnet.</string>
|
||||
<string name="yield_module_rate_info_sheet_powered_by">Unterstützt durch</string>
|
||||
<string name="yield_module_rate_info_sheet_title">Der Zinssatz ist variabel</string>
|
||||
<string name="yield_module_receive_sheet_description">Wenn Du dein Guthaben auflädst, wird es automatisch an Aave weitergeleitet, um Zinsen zu verdienen. zur Deckung der Transaktionsgebühr wird ein Betrag von %s abgezogen.</string>
|
||||
<string name="yield_module_receive_sheet_description">Wenn du dein Guthaben auflädst, wird es automatisch an Aave weitergeleitet, um Zinsen zu verdienen. zur Deckung der Transaktionsgebühr wird ein Betrag von %s abgezogen.</string>
|
||||
<string name="yield_module_start_earning">Vermögenswerte liefern</string>
|
||||
<string name="yield_module_start_earning_sheet_description">Dein %s wird an Aave übermittelt, bleibt aber verwaltbar.</string>
|
||||
<string name="yield_module_start_earning_sheet_fee_policy">Siehe Gebührenrichtlinie</string>
|
||||
<string name="yield_module_start_earning_sheet_next_deposits">Deine nächste Aufladung wird automatisch an Aave weitergeleitet.</string>
|
||||
<string name="yield_module_start_earning_sheet_description">Dein %s wird Aave ohne Abschließmöglichkeiten zur Verfügung gestellt und bleibt uneingeschränkt zugänglich.</string>
|
||||
<string name="yield_module_start_earning_sheet_fee_policy">Siehe die Gebührenrichtlinien für Aufladungen.</string>
|
||||
<string name="yield_module_start_earning_sheet_next_deposits">Deine nächste Aufladungen werden automatisch an Aave übermittelt.</string>
|
||||
<string name="yield_module_start_earning_sheet_next_deposits_v2">Alle Ihre zukünftigen eingehenden %1$s-Einlagen werden automatisch an Aave bereitgestellt.</string>
|
||||
<string name="yield_module_status_active">Aktiv</string>
|
||||
<string name="yield_module_status_paused">Pausiert</string>
|
||||
<string name="yield_module_stop_earning">Deaktiviere den Yield-Modus</string>
|
||||
<string name="yield_module_stop_earning">Deaktiviere den Ertragsmodus</string>
|
||||
<string name="yield_module_stop_earning_sheet_description">Wenn Du diese Option deaktivierst, werden Deine Vermögenswerte von Aave abgezogen, in Deiner Wallet wieder in %s umgewandelt und die Zinsgutschrift gestoppt.</string>
|
||||
<string name="yield_module_stop_earning_sheet_fee_note">Eine Netzwerkgebühr wird von der Blockchain erhoben, wenn Sie den Yield-Modus verlassen.</string>
|
||||
<string name="yield_module_stop_earning_sheet_title">Deaktiviere den Yield-Modus</string>
|
||||
|
|
@ -2289,7 +2385,8 @@
|
|||
<string name="yield_module_token_details_earn_notification_description">Zinsen fallen automatisch an.</string>
|
||||
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_subtitle">Zinsen fallen automatisch an</string>
|
||||
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_title">Ertragsmodus</string>
|
||||
<string name="yield_module_token_details_earn_notification_processing">Bearbeitung Deiner Einzahlung</string>
|
||||
<string name="yield_module_token_details_earn_notification_processing">Aktivierung des Ertragsmodus</string>
|
||||
<string name="yield_module_token_details_earn_notification_subtitle">Renditemodus - %1$s%% APY</string>
|
||||
<string name="yield_module_token_details_earn_notification_title">Ertragsmodus</string>
|
||||
<string name="yield_module_transaction_deploy_contract">Yield-Mode-Vertragsbereitstellung</string>
|
||||
<string name="yield_module_transaction_enter">Ertragsmodus aktivieren</string>
|
||||
|
|
@ -2305,6 +2402,6 @@
|
|||
<string name="yield_module_unable_to_cover_fee_description">Einzahlung von %1$s %2$s zur Deckung der Netzwerkgebühr für Transaktionen</string>
|
||||
<string name="yield_module_unable_to_cover_fee_title">Die Gebühr %s kann nicht gedeckt werden</string>
|
||||
<string name="yield_module_unavailable_subtitle">Der Yield-Modus ist momentan nicht verfügbar. Bitte versuche es später erneut.</string>
|
||||
<string name="yield_module_unavailable_title">Ausweichmodus nicht verfügbar</string>
|
||||
<string name="yield_module_unavailable_title">Yield Mode nicht verfügbar</string>
|
||||
<string name="yield_supply_chart_loading_error">Chart konnte nicht geladen werden...</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -309,6 +309,7 @@
|
|||
<item quantity="other">Hace %dh</item>
|
||||
</plurals>
|
||||
<string name="common_import">Importe</string>
|
||||
<string name="common_in">en</string>
|
||||
<string name="common_in_progress">En progreso</string>
|
||||
<string name="common_insufficient_balance">Fondos insuficientes</string>
|
||||
<string name="common_later">Más tarde</string>
|
||||
|
|
@ -394,6 +395,7 @@
|
|||
<string name="common_to">A</string>
|
||||
<string name="common_to_wallet_name">A %s</string>
|
||||
<string name="common_today">Hoy</string>
|
||||
<string name="common_token">Token</string>
|
||||
<string name="common_token_send">Token para enviar</string>
|
||||
<plurals name="common_tokens_count">
|
||||
<item quantity="one">%d token</item>
|
||||
|
|
|
|||
|
|
@ -309,6 +309,7 @@
|
|||
<item quantity="other">Il y a %dh</item>
|
||||
</plurals>
|
||||
<string name="common_import">Importez</string>
|
||||
<string name="common_in">dans</string>
|
||||
<string name="common_in_progress">En cours</string>
|
||||
<string name="common_later">Plus tard</string>
|
||||
<string name="common_learn_more">En savoir plus</string>
|
||||
|
|
@ -392,6 +393,7 @@
|
|||
<string name="common_to">À</string>
|
||||
<string name="common_to_wallet_name">À %s</string>
|
||||
<string name="common_today">Aujourd\'hui</string>
|
||||
<string name="common_token">Token</string>
|
||||
<plurals name="common_tokens_count">
|
||||
<item quantity="one">%d token</item>
|
||||
<item quantity="other">%d tokens</item>
|
||||
|
|
@ -624,6 +626,8 @@
|
|||
<string name="hw_backup_banner_description">Gardez vos cryptomonnaies en sécurité et hors ligne. Aussi fin qu\'une carte de crédit, plus sûr qu\'un coffre-fort bancaire.</string>
|
||||
<string name="hw_backup_close_description">Si vous le faites, vous devrez recommencer depuis le début.</string>
|
||||
<string name="hw_backup_google_drive_description">Récupérer un portefeuille existant via la sauvegarde Google Drive</string>
|
||||
<string name="hw_backup_google_drive_dialog_message">Nous travaillons actuellement sur la sauvegarde de votre portefeuille via Google Drive afin de faciliter encore davantage la restauration de celui-ci.</string>
|
||||
<string name="hw_backup_google_drive_dialog_title">La sauvegarde via Google Drive sera bientôt disponible</string>
|
||||
<string name="hw_backup_google_drive_title">Sauvegarde Google Drive</string>
|
||||
<string name="hw_backup_hardware_create_description">Créez un portefeuille sécurisé et transférez vos fonds pour bénéficier d\'une protection supplémentaire.</string>
|
||||
<string name="hw_backup_hardware_create_title">Créer un nouveau portefeuille</string>
|
||||
|
|
|
|||
|
|
@ -16,12 +16,14 @@
|
|||
<string name="common_done">Fatto</string>
|
||||
<string name="common_error">Errore</string>
|
||||
<string name="common_fee_error">Impossibile ottenere la commissione</string>
|
||||
<string name="common_in">in</string>
|
||||
<string name="common_network_fee_title">Costi della rete</string>
|
||||
<string name="common_ok">OK</string>
|
||||
<string name="common_save_changes">Mantieni le modifiche</string>
|
||||
<string name="common_send">Invia</string>
|
||||
<string name="common_send_tx_error">Impossibile inviare la transazione</string>
|
||||
<string name="common_success">Con successo</string>
|
||||
<string name="common_token">Token</string>
|
||||
<plurals name="common_tokens_count">
|
||||
<item quantity="one">%d gettone</item>
|
||||
<item quantity="other">%d gettoni</item>
|
||||
|
|
|
|||
|
|
@ -214,6 +214,7 @@
|
|||
<string name="common_access_denied">アクセスが拒否されました</string>
|
||||
<string name="common_account">アカウント</string>
|
||||
<string name="common_accounts">アカウント</string>
|
||||
<string name="common_action_failed">%s に失敗しました</string>
|
||||
<string name="common_activate">有効化</string>
|
||||
<string name="common_add">追加</string>
|
||||
<string name="common_add_funds">資金を追加</string>
|
||||
|
|
@ -230,6 +231,8 @@
|
|||
<string name="common_apply">適用する</string>
|
||||
<string name="common_approval">承認</string>
|
||||
<string name="common_approve">承認</string>
|
||||
<string name="common_approved">承認済み</string>
|
||||
<string name="common_approving">承認中</string>
|
||||
<string name="common_attention">注意</string>
|
||||
<string name="common_available_networks">利用可能なネットワーク</string>
|
||||
<string name="common_backup">バックアップ</string>
|
||||
|
|
@ -309,10 +312,14 @@
|
|||
<string name="common_hide">非表示</string>
|
||||
<string name="common_hold_to">%sまで長押し</string>
|
||||
<string name="common_hour">時間</string>
|
||||
<plurals name="common_hours">
|
||||
<item quantity="other">%d 時間</item>
|
||||
</plurals>
|
||||
<plurals name="common_hours_time_ago">
|
||||
<item quantity="other">%d時間前</item>
|
||||
</plurals>
|
||||
<string name="common_import">インポート</string>
|
||||
<string name="common_in">で</string>
|
||||
<string name="common_in_progress">進行中</string>
|
||||
<string name="common_insufficient_balance">残高不足</string>
|
||||
<string name="common_later">後で</string>
|
||||
|
|
@ -355,6 +362,8 @@
|
|||
<string name="common_range_with_space">%1$s — %2$s</string>
|
||||
<string name="common_read_more">続きを読む</string>
|
||||
<string name="common_receive">受け取る</string>
|
||||
<string name="common_received">受け取り済み</string>
|
||||
<string name="common_receiving">受け取り中</string>
|
||||
<string name="common_recommended">おすすめ</string>
|
||||
<string name="common_reject">拒否</string>
|
||||
<string name="common_reload">リロード</string>
|
||||
|
|
@ -373,6 +382,8 @@
|
|||
<string name="common_send">送る</string>
|
||||
<string name="common_send_colon">送金:</string>
|
||||
<string name="common_send_tx_error">取引の送信に失敗しました</string>
|
||||
<string name="common_sending">送金中</string>
|
||||
<string name="common_sent">送金済み</string>
|
||||
<string name="common_server_unavailable">サーバーが利用できません。しばらくしてからもう一度お試しください。</string>
|
||||
<string name="common_share">共有</string>
|
||||
<string name="common_share_link">リンクを共有</string>
|
||||
|
|
@ -383,6 +394,7 @@
|
|||
<string name="common_skip">スキップ</string>
|
||||
<string name="common_something_went_wrong">問題が発生しました</string>
|
||||
<string name="common_stake">ステーキング</string>
|
||||
<string name="common_staked">ステーキング済み</string>
|
||||
<string name="common_staking">ステーキング</string>
|
||||
<string name="common_start">始める</string>
|
||||
<string name="common_submit">送信</string>
|
||||
|
|
@ -390,6 +402,8 @@
|
|||
<string name="common_support">サポート</string>
|
||||
<string name="common_supported_networks">対応ネットワーク</string>
|
||||
<string name="common_swap">スワップ</string>
|
||||
<string name="common_swapped">スワップ済み</string>
|
||||
<string name="common_swapping">スワップ中</string>
|
||||
<string name="common_tangem">Tangem</string>
|
||||
<string name="common_tangem_wallet">Tangem Wallet</string>
|
||||
<string name="common_tap_and_hold_hint">タップして長押し</string>
|
||||
|
|
@ -398,6 +412,7 @@
|
|||
<string name="common_to">宛先</string>
|
||||
<string name="common_to_wallet_name">%sへ</string>
|
||||
<string name="common_today">今日</string>
|
||||
<string name="common_token">トークン</string>
|
||||
<string name="common_token_send">送信するトークン</string>
|
||||
<plurals name="common_tokens_count">
|
||||
<item quantity="other">%d トークン</item>
|
||||
|
|
@ -406,6 +421,7 @@
|
|||
<string name="common_transaction_status">取引状況</string>
|
||||
<string name="common_transactions">取引</string>
|
||||
<string name="common_transfer">送金</string>
|
||||
<string name="common_transferred">送金済み</string>
|
||||
<string name="common_unable_to_load">データを読み込めません…</string>
|
||||
<string name="common_understand">わかりました</string>
|
||||
<string name="common_understand_continue">理解して続行</string>
|
||||
|
|
@ -415,10 +431,12 @@
|
|||
<string name="common_unstake">ステーキング解除</string>
|
||||
<string name="common_utxo_validate_withdrawal_message_warning">%1$sの制限により、1つのトランザクションに収まるUTXOは%2$d個のみです。つまり、 %3$s以下しか送信できません。量を減らす必要があります。</string>
|
||||
<string name="common_value_copied">値がコピーされました</string>
|
||||
<string name="common_voting">投票</string>
|
||||
<string name="common_wallets">ウォレット</string>
|
||||
<string name="common_warning">警告</string>
|
||||
<string name="common_week">週</string>
|
||||
<string name="common_with">で</string>
|
||||
<string name="common_withdrawing">引き出し中</string>
|
||||
<string name="common_yes">はい</string>
|
||||
<string name="common_yield_mode">利息モード</string>
|
||||
<string name="contract_address_copied_message">コントラクトアドレスをコピーしました!</string>
|
||||
|
|
@ -580,12 +598,14 @@
|
|||
<string name="express_provider_best_rate">ベストレート</string>
|
||||
<string name="express_provider_fca_warning_list">FCA警告リスト</string>
|
||||
<string name="express_provider_fixed_rate_is_unavailable">固定レートは利用できません</string>
|
||||
<string name="express_provider_for_swap">スワッププロバイダー</string>
|
||||
<string name="express_provider_great_rate">お得なレート</string>
|
||||
<string name="express_provider_in_fca_warning_list">FCA警告リストに掲載されたプロバイダー</string>
|
||||
<string name="express_provider_max_amount">最大 %s まで使用可能</string>
|
||||
<string name="express_provider_min_amount">%s 以上で利用可能</string>
|
||||
<string name="express_provider_not_available">このペアは利用できません</string>
|
||||
<string name="express_provider_permission_needed">許可が必要です</string>
|
||||
<string name="express_provider_permission_needed_v2">権限が必要です</string>
|
||||
<string name="express_provider_recommended">推奨</string>
|
||||
<string name="express_status_bought">%sを買い付けました</string>
|
||||
<string name="express_status_buying">%sを買い付けています</string>
|
||||
|
|
@ -633,6 +653,7 @@
|
|||
<string name="give_permission_staking_footer">承認機能は、別のアドレスに特定の量のトークンを使用する許可を与えるために必要です。設計上スマートコントラクトは、承認しない限りトークンにアクセスできません。トークンを「ロック解除」すると、StakeKitスマート コントラクトがトークンを使用する権限が与えられます。ネットワークのマイナーは、このアクションをブロックチェーンに記録するためにガス料金(あなたが支払う)を受け取ります。承認後、トークンをステーキングできます。</string>
|
||||
<string name="give_permission_staking_subtitle">続行するには、Polygonスマートコントラクトが%sを使用することを許可する必要があります</string>
|
||||
<string name="give_permission_swap_subtitle" formatted="false">続行するには、%1sスマートコントラクトに%2sを使用する権限を付与してください</string>
|
||||
<string name="give_permission_swap_subtitle_v2">分散型取引所がウォレットと連携するには、許可が必要です。%1s</string>
|
||||
<string name="give_permission_title">許可を与える</string>
|
||||
<string name="give_permission_unlimited">無制限</string>
|
||||
<string name="hardware_wallet_backup_feature_description">アドレスはTangemハードウェアウォレット上で直接生成され、そのまま安全に使用できます。</string>
|
||||
|
|
@ -660,6 +681,8 @@
|
|||
<string name="hw_backup_banner_description">暗号資産をオフラインで厳重保管。カードサイズで、金庫以上の安心を。</string>
|
||||
<string name="hw_backup_close_description">実行すると、最初からやり直す必要があります。</string>
|
||||
<string name="hw_backup_google_drive_description">Googleドライブのバックアップから既存のウォレットを復元する</string>
|
||||
<string name="hw_backup_google_drive_dialog_message">ウォレットの復元をさらに簡単にするため、Googleドライブバックアップ機能を準備しています。</string>
|
||||
<string name="hw_backup_google_drive_dialog_title">Googleドライブバックアップは近日対応予定です</string>
|
||||
<string name="hw_backup_google_drive_title">Googleドライブのバックアップ</string>
|
||||
<string name="hw_backup_hardware_create_description">さらに強固なセキュリティのために、新しいウォレットを作成して資産を移動しましょう。</string>
|
||||
<string name="hw_backup_hardware_create_title">新しいウォレットを作成</string>
|
||||
|
|
@ -1103,6 +1126,8 @@
|
|||
<string name="onramp_kyc_verification_choose_another">別の方法を選択してください。</string>
|
||||
<string name="onramp_kyc_verification_subtitle">現地の規制要件に準拠するため、%@の利用には本人確認が必要です。</string>
|
||||
<string name="onramp_kyc_verification_title">決済プロバイダーによる本人確認が必要です。</string>
|
||||
<string name="onramp_kyc_verification_verify_button">認証する</string>
|
||||
<string name="onramp_kyc_verification_whats_important">重要事項</string>
|
||||
<string name="onramp_legal">オンランプ機能を使用することにより、プロバイダの%1$sおよび%2$sに同意するものとします</string>
|
||||
<string name="onramp_legal_text">サービスは外部プロバイダーによって提供されます。 \nTangemは責任を負いません。</string>
|
||||
<string name="onramp_max_amount_restriction">買付金額は%s以下にしてください</string>
|
||||
|
|
@ -1166,7 +1191,11 @@
|
|||
<string name="qr_scanner_warning_unknown_parameters_title">不明なパラメータ</string>
|
||||
<string name="quick_action_buy_description">クレジットカードまたは銀行口座</string>
|
||||
<string name="quick_action_receive_description">アドレスまたはQRコードを共有してください</string>
|
||||
<string name="quick_action_sell_description">暗号資産を安全に売却</string>
|
||||
<string name="quick_action_send_description">別のウォレットに送信</string>
|
||||
<string name="quick_action_swap_description">ポートフォリオ間で</string>
|
||||
<string name="quick_top_up_chip_other">その他</string>
|
||||
<string name="quick_top_up_title">クイック入金</string>
|
||||
<string name="receive_bottom_sheet_no_memo_required_message">メモ不要</string>
|
||||
<string name="receive_bottom_sheet_warning_message">%3$sネットワーク上の%1$s ( %2$s )</string>
|
||||
<string name="receive_bottom_sheet_warning_message_compact">%2$sネットワーク上の%1$s</string>
|
||||
|
|
@ -1522,6 +1551,7 @@
|
|||
<string name="swap_approve_description">承認すると、このスマートコントラクトが今後の取引でトークンを利用できるようになります。</string>
|
||||
<string name="swap_fixed_rate">固定レート</string>
|
||||
<string name="swap_give_permission_fee_footer">ネットワークは、あなたがトークンのスワップを承認していることを確認するために、トークン承認手数料を請求します。</string>
|
||||
<string name="swap_in_progress">スワップ中</string>
|
||||
<string name="swap_promo_text">より多くのトークンをより良いレートで、ウォレット内にて直接交換します。</string>
|
||||
<string name="swap_promo_title">新しいスワッププロバイダーが利用可能になりました!</string>
|
||||
<string name="swap_search_suggestion_hint">他のものをお探しですか?\n検索してみるか、別の暗号資産をチェックしてみましょう!</string>
|
||||
|
|
@ -1530,11 +1560,11 @@
|
|||
<string name="swap_story_fifth_subtitle">24時間体制のサポートであらゆる問題に対応します。</string>
|
||||
<string name="swap_story_fifth_title">いつもここに</string>
|
||||
<string name="swap_story_first_subtitle">複数の信頼できるプロバイダーが一箇所に集結。ウォレット内で様々な暗号資産を簡単に交換できます。</string>
|
||||
<string name="swap_story_first_subtitle_v2">Tangem内で暗号資産を直接交換\n追加の送金は不要\n取引所に資産を移す必要なし</string>
|
||||
<string name="swap_story_first_subtitle_v2">Tangem内で暗号資産を直接交換できます\n追加の送金は不要です\n取引所に資金を移す必要もありません</string>
|
||||
<string name="swap_story_first_title">ぜひスワップしてください</string>
|
||||
<string name="swap_story_first_title_v2">ウォレット内でスワップ</string>
|
||||
<string name="swap_story_forth_subtitle">失敗も死角もありません。取引は常に保護されます。</string>
|
||||
<string name="swap_story_forth_subtitle_v2">スワップは信頼できるプロバイダーを通じて実行されます。秘密鍵は常にTangemウォレット内に保持されます。シンプル。透明。自己管理。</string>
|
||||
<string name="swap_story_forth_subtitle_v2">スワップは信頼できるプロバイダーを通じて実行されます。秘密鍵は常にTangemウォレット内に保持されます。明確で、透明性が高く、自己管理型です。</string>
|
||||
<string name="swap_story_forth_title">難攻不落の防御</string>
|
||||
<string name="swap_story_forth_title_v2">主導権はあなたの手にあります</string>
|
||||
<string name="swap_story_second_subtitle">幅広いネットワークの中から、常に最適なプロバイダーと料金レートを選択します</string>
|
||||
|
|
@ -1555,7 +1585,9 @@
|
|||
<string name="swapping_approve_information_text">すべての分散型取引所は、スマートコントラクトがあなたの許可なくウォレットにアクセスするのを防ぐために承認を必要とします。設計上、スマートコントラクトは承認なしでトークンにアクセスできません。トークンを「ロック解除」することで、あなたは1-inchのスマートコントラクトがトークンを使うことを承認します。ネットワークのマイナーは、このアクションをブロックチェーンに記録するためのガス料金(あなたが支払う)を受け取ります。承認後、トークンを交換することができます。</string>
|
||||
<string name="swapping_approve_information_title">承認</string>
|
||||
<string name="swapping_fee_estimation_error_text">手数料見積りエラーです。サポートにフィードバックをお送りください。</string>
|
||||
<string name="swapping_from_account_title">送信元</string>
|
||||
<string name="swapping_from_title">スワップする</string>
|
||||
<string name="swapping_from_title_v2">送信</string>
|
||||
<string name="swapping_high_price_impact_description">選択したトークンをこの量を交換すると、価格に大きな影響が生じ、結果が減少します。</string>
|
||||
<string name="swapping_high_price_impact_text">流動性が低いため、受取額が大幅に少なくなる可能性があります。金額を減らすか、別のプロバイダーをお試しください。</string>
|
||||
<string name="swapping_high_price_impact_title">価格への影響が甚大です</string>
|
||||
|
|
@ -1564,11 +1596,14 @@
|
|||
<string name="swapping_permission_header">許可を与える</string>
|
||||
<string name="swapping_swap_action">スワップ</string>
|
||||
<string name="swapping_swap_action_in_progress">スワップ中…</string>
|
||||
<string name="swapping_to_account_title">受け取り先</string>
|
||||
<string name="swapping_to_title">受け取る</string>
|
||||
<string name="swapping_token_list_title">トークンを選択</string>
|
||||
<string name="swapping_token_not_available">利用不可</string>
|
||||
<string name="swapping_trade_too_large_text">この取引に十分な流動性がありません。\n金額を減らすか、別のプロバイダーを選択してください。</string>
|
||||
<string name="swapping_trade_too_large_title">取引額が大きすぎます</string>
|
||||
<string name="swapping_transfer_action">送金</string>
|
||||
<string name="swapping_transfer_action_in_progress">送金...</string>
|
||||
<string name="tangem_pay_beta_notification_subtitle">皆様からのフィードバックをお待ちしております</string>
|
||||
<string name="tangem_pay_beta_notification_title">Tangem Payのベータ版を公開しました</string>
|
||||
<string name="tangem_pay_card_details_unable_to_rename_card_title">カード名を変更できません</string>
|
||||
|
|
@ -1657,6 +1692,7 @@
|
|||
<string name="tangempay_card_details_withdraw_error_title">現在、出金ができません</string>
|
||||
<string name="tangempay_card_details_withdraw_in_progress_description">現在の処理が完了するまでは、スワップや新しい出金を開始することはできません。</string>
|
||||
<string name="tangempay_card_details_withdraw_in_progress_title">出金処理中です</string>
|
||||
<string name="tangempay_card_edit_name_placeholder">カード名</string>
|
||||
<string name="tangempay_card_limit_setup_amount_subtitle">%s以上の金額を設定してください</string>
|
||||
<string name="tangempay_card_limit_setup_error_message">限度額を設定できませんでした。もう一度お試しください</string>
|
||||
<string name="tangempay_card_page_daily_limit_change">変更</string>
|
||||
|
|
@ -1708,6 +1744,8 @@
|
|||
<string name="tangempay_onboarding_purchases_title">余計な費用なしで、表示金額のみを支払う</string>
|
||||
<string name="tangempay_onboarding_security_description">あなたの住所や資産を開示することなく、個別の支払い用アカウントが作成されます。</string>
|
||||
<string name="tangempay_onboarding_security_title">他に類を見ないプライバシー</string>
|
||||
<string name="tangempay_onboarding_setup_wallet_description">そして支払いカードを連携します</string>
|
||||
<string name="tangempay_onboarding_setup_wallet_title">ウォレットを設定します</string>
|
||||
<string name="tangempay_onboarding_title">無料のTangem Payカードを数分でゲットしましょう</string>
|
||||
<string name="tangempay_pay_support">Payサポート</string>
|
||||
<string name="tangempay_payment_account">支払いアカウント</string>
|
||||
|
|
@ -1757,7 +1795,7 @@
|
|||
<string name="token_button_unavailability_reason_yield_supply_approval">承認が取り消されましたが、あなたの資金は引き続き利息モードです。操作を行うには、利息モードに移動し、再度承認を付与してください。</string>
|
||||
<string name="token_details_balance_available">利用可能残高</string>
|
||||
<string name="token_details_balance_total">合計残高</string>
|
||||
<string name="token_details_earn_staking_subtitle">年間で最大%sを獲得</string>
|
||||
<string name="token_details_earn_staking_subtitle">年利最大%s</string>
|
||||
<string name="token_details_generate_xpub">XPUBを生成する</string>
|
||||
<string name="token_details_hide_alert_hide">非表示</string>
|
||||
<string name="token_details_hide_alert_message">このトークンをメイン画面から非表示にします。トークンの管理ページからいつでも再度追加できます。</string>
|
||||
|
|
@ -1783,12 +1821,21 @@
|
|||
<string name="tokens_list_unavailable_to_sell_header">売却できません</string>
|
||||
<string name="tokens_list_unavailable_to_swap_header">%sからのスワップは利用できません</string>
|
||||
<string name="tokens_list_unavailable_to_swap_source_header">スワップはできません</string>
|
||||
<string name="transaction_history_claiming_reward">報酬を請求中</string>
|
||||
<string name="transaction_history_contract_address">コントラクト: %s</string>
|
||||
<string name="transaction_history_disabling_yield_mode">利息モードを無効化中</string>
|
||||
<string name="transaction_history_earned_from_stake">ステーキングで獲得した金額</string>
|
||||
<string name="transaction_history_empty_transactions">まだ取引はありません</string>
|
||||
<string name="transaction_history_error_failed_to_load">取引履歴の読み込みに失敗しました。\n情報を更新するには、リロードボタンをクリックしてください。</string>
|
||||
<string name="transaction_history_from_inline_address">%%image%% %s から</string>
|
||||
<string name="transaction_history_multiple_addresses">複数のアドレス</string>
|
||||
<string name="transaction_history_not_supported_description">現在、このブロックチェーンでは取引履歴はサポートされていません。しかしご心配なく!弊社で対応中です。その間、エクスプローラーで確認することができます。</string>
|
||||
<string name="transaction_history_operation">オペレーション</string>
|
||||
<string name="transaction_history_pending">保留中</string>
|
||||
<string name="transaction_history_rewards_restaked">報酬を再ステーキングしました</string>
|
||||
<string name="transaction_history_rewards_restaking">報酬の再ステーキング</string>
|
||||
<string name="transaction_history_staking_reward">ステーキング報酬</string>
|
||||
<string name="transaction_history_to_inline_address">%%image%% %s へ</string>
|
||||
<string name="transaction_history_transaction_for_address">対象:%s</string>
|
||||
<string name="transaction_history_transaction_from_address">送金元: %s</string>
|
||||
<string name="transaction_history_transaction_to_address">送金先: %s</string>
|
||||
|
|
@ -2064,7 +2111,7 @@
|
|||
<string name="warning_matic_migration_message">MATICはPOLに移行中です。ただし、期限は設定されておらず、MATICはまだ廃止されていません。MATICトークンを引き続き安全に使用することも、POLに交換することもできます。</string>
|
||||
<string name="warning_matic_migration_title">MATICからPOLへの移行</string>
|
||||
<plurals name="warning_missing_derivation_message">
|
||||
<item quantity="other">%d ネットワークのアドレスを取得するために、カードまたはリングを利用してください</item>
|
||||
<item quantity="other">カードまたはリングを使って、%dネットワークのアドレスを取得します</item>
|
||||
</plurals>
|
||||
<string name="warning_missing_derivation_title">一部のアドレスが見つかりません</string>
|
||||
<string name="warning_network_unreachable_message">現在、ネットワークにアクセスできません。しばらくしてからもう一度お試しください。</string>
|
||||
|
|
|
|||
|
|
@ -176,8 +176,8 @@
|
|||
<string name="button_start_backup_process">Iniciar processo de backup</string>
|
||||
<string name="buy_token_description">Use um cartão bancário ou outros métodos de pagamento.</string>
|
||||
<plurals name="card_label_card_count">
|
||||
<item quantity="one">dispositivo</item>
|
||||
<item quantity="other">dispositivos</item>
|
||||
<item quantity="one">%d dispositivo</item>
|
||||
<item quantity="other">%d dispositivos</item>
|
||||
</plurals>
|
||||
<plurals name="card_label_token_count">
|
||||
<item quantity="one">token</item>
|
||||
|
|
@ -320,6 +320,7 @@
|
|||
<item quantity="other">OUTRO</item>
|
||||
</plurals>
|
||||
<string name="common_import">Importar</string>
|
||||
<string name="common_in">em</string>
|
||||
<string name="common_in_progress">Em andamento</string>
|
||||
<string name="common_insufficient_balance">Saldo insuficiente</string>
|
||||
<string name="common_later">Mais tarde</string>
|
||||
|
|
@ -407,6 +408,7 @@
|
|||
<string name="common_to">Para</string>
|
||||
<string name="common_to_wallet_name">Para %s</string>
|
||||
<string name="common_today">Hoje</string>
|
||||
<string name="common_token">Token</string>
|
||||
<string name="common_token_send">Token a ser enviado</string>
|
||||
<plurals name="common_tokens_count">
|
||||
<item quantity="one">token</item>
|
||||
|
|
@ -2099,8 +2101,8 @@
|
|||
<string name="warning_matic_migration_message">O MATIC está sendo migrado para o POL. No entanto, não há prazo definido e o MATIC ainda não foi descontinuado. Você pode continuar usando o token MATIC com segurança ou trocá-lo pelo POL.</string>
|
||||
<string name="warning_matic_migration_title">Migração de MATIC para POL</string>
|
||||
<plurals name="warning_missing_derivation_message">
|
||||
<item quantity="one">Use seu Cartão ou Anel para obter o endereço de uma rede.</item>
|
||||
<item quantity="other">Use seu Cartão ou Anel para obter endereços de rede.</item>
|
||||
<item quantity="one">Use seu Cartão ou Anel para obter o endereço de uma rede %d.</item>
|
||||
<item quantity="other">Use seu Cartão ou Anel para obter endereços de redes %d.</item>
|
||||
</plurals>
|
||||
<string name="warning_missing_derivation_title">Alguns endereços estão faltando.</string>
|
||||
<string name="warning_network_unreachable_message">A rede está inacessível no momento. Tente novamente mais tarde.</string>
|
||||
|
|
|
|||
|
|
@ -326,6 +326,12 @@
|
|||
<string name="common_hide">Скрыть</string>
|
||||
<string name="common_hold_to">Удерживайте, чтобы %s</string>
|
||||
<string name="common_hour">час</string>
|
||||
<plurals name="common_hours">
|
||||
<item quantity="one">%d час</item>
|
||||
<item quantity="few">%d часa</item>
|
||||
<item quantity="many">%d часов</item>
|
||||
<item quantity="other">%d часа</item>
|
||||
</plurals>
|
||||
<plurals name="common_hours_time_ago">
|
||||
<item quantity="one">%dч назад</item>
|
||||
<item quantity="few">%dч назад</item>
|
||||
|
|
@ -333,6 +339,7 @@
|
|||
<item quantity="other">%dч назад</item>
|
||||
</plurals>
|
||||
<string name="common_import">Импортировать</string>
|
||||
<string name="common_in">в</string>
|
||||
<string name="common_in_progress">В процессе</string>
|
||||
<string name="common_insufficient_balance">Недостаточный баланс</string>
|
||||
<string name="common_later">Позже</string>
|
||||
|
|
@ -423,6 +430,7 @@
|
|||
<string name="common_to">На</string>
|
||||
<string name="common_to_wallet_name">На %s</string>
|
||||
<string name="common_today">Сегодня</string>
|
||||
<string name="common_token">Токен</string>
|
||||
<string name="common_token_send">Токен к отправке</string>
|
||||
<plurals name="common_tokens_count">
|
||||
<item quantity="one">%d токен</item>
|
||||
|
|
|
|||
|
|
@ -321,6 +321,7 @@
|
|||
<item quantity="other">%d годин тому</item>
|
||||
</plurals>
|
||||
<string name="common_import">Імпортувати</string>
|
||||
<string name="common_in">у</string>
|
||||
<string name="common_in_progress">В процесі</string>
|
||||
<string name="common_later">Пізніше</string>
|
||||
<string name="common_learn_more">Дізнатися більше</string>
|
||||
|
|
@ -408,6 +409,7 @@
|
|||
<string name="common_to">До</string>
|
||||
<string name="common_to_wallet_name">На %s</string>
|
||||
<string name="common_today">Сьогодні</string>
|
||||
<string name="common_token">Токен</string>
|
||||
<plurals name="common_tokens_count">
|
||||
<item quantity="one">%d токен</item>
|
||||
<item quantity="few">%d токени</item>
|
||||
|
|
|
|||
|
|
@ -214,8 +214,10 @@
|
|||
<string name="common_access_denied">拒绝访问</string>
|
||||
<string name="common_account">账户</string>
|
||||
<string name="common_accounts">账户</string>
|
||||
<string name="common_action_failed">%s 失败</string>
|
||||
<string name="common_activate">激活</string>
|
||||
<string name="common_add">添加</string>
|
||||
<string name="common_add_funds">增加资金</string>
|
||||
<string name="common_add_to_portfolio">添加到投资组合</string>
|
||||
<string name="common_add_token">添加代币</string>
|
||||
<string name="common_add_tokens">添加代币</string>
|
||||
|
|
@ -229,6 +231,8 @@
|
|||
<string name="common_apply">申请</string>
|
||||
<string name="common_approval">批准</string>
|
||||
<string name="common_approve">批准</string>
|
||||
<string name="common_approved">已批准</string>
|
||||
<string name="common_approving">批准</string>
|
||||
<string name="common_attention">请注意</string>
|
||||
<string name="common_available_networks">可用网络</string>
|
||||
<string name="common_backup">备份</string>
|
||||
|
|
@ -308,10 +312,14 @@
|
|||
<string name="common_hide">隐藏</string>
|
||||
<string name="common_hold_to">保持到 %s</string>
|
||||
<string name="common_hour">小时</string>
|
||||
<plurals name="common_hours">
|
||||
<item quantity="other">%d小时</item>
|
||||
</plurals>
|
||||
<plurals name="common_hours_time_ago">
|
||||
<item quantity="other">小时之前</item>
|
||||
</plurals>
|
||||
<string name="common_import">导入</string>
|
||||
<string name="common_in">在</string>
|
||||
<string name="common_in_progress">进行中</string>
|
||||
<string name="common_insufficient_balance">余额不足</string>
|
||||
<string name="common_later">稍后</string>
|
||||
|
|
@ -354,6 +362,8 @@
|
|||
<string name="common_range_with_space">%1$s — %2$s</string>
|
||||
<string name="common_read_more">阅读更多</string>
|
||||
<string name="common_receive">接收</string>
|
||||
<string name="common_received">已收到</string>
|
||||
<string name="common_receiving">接收中</string>
|
||||
<string name="common_recommended">推荐</string>
|
||||
<string name="common_reject">拒绝</string>
|
||||
<string name="common_reload">重新加载</string>
|
||||
|
|
@ -372,6 +382,8 @@
|
|||
<string name="common_send">发送</string>
|
||||
<string name="common_send_colon">发送:</string>
|
||||
<string name="common_send_tx_error">交易发送失败</string>
|
||||
<string name="common_sending">发送中</string>
|
||||
<string name="common_sent">发送</string>
|
||||
<string name="common_server_unavailable">服务器不可用,请稍后再试。</string>
|
||||
<string name="common_share">分享</string>
|
||||
<string name="common_share_link">分享链接</string>
|
||||
|
|
@ -382,6 +394,7 @@
|
|||
<string name="common_skip">跳过</string>
|
||||
<string name="common_something_went_wrong">出问题了</string>
|
||||
<string name="common_stake">质押</string>
|
||||
<string name="common_staked">已质押</string>
|
||||
<string name="common_staking">质押</string>
|
||||
<string name="common_start">开始</string>
|
||||
<string name="common_submit">提交</string>
|
||||
|
|
@ -389,6 +402,8 @@
|
|||
<string name="common_support">支持</string>
|
||||
<string name="common_supported_networks">支持的网络</string>
|
||||
<string name="common_swap">兑换</string>
|
||||
<string name="common_swapped">已兑换</string>
|
||||
<string name="common_swapping">兑换...</string>
|
||||
<string name="common_tangem">Tangem</string>
|
||||
<string name="common_tangem_wallet">Tangem钱包</string>
|
||||
<string name="common_tap_and_hold_hint">点击并按住</string>
|
||||
|
|
@ -397,6 +412,7 @@
|
|||
<string name="common_to">至</string>
|
||||
<string name="common_to_wallet_name">到 %s</string>
|
||||
<string name="common_today">今天</string>
|
||||
<string name="common_token">代币</string>
|
||||
<string name="common_token_send">要发送的代币</string>
|
||||
<plurals name="common_tokens_count">
|
||||
<item quantity="other">%d代币</item>
|
||||
|
|
@ -405,6 +421,7 @@
|
|||
<string name="common_transaction_status">交易状态</string>
|
||||
<string name="common_transactions">交易</string>
|
||||
<string name="common_transfer">转让</string>
|
||||
<string name="common_transferred">已转账</string>
|
||||
<string name="common_unable_to_load">无法加载数据……</string>
|
||||
<string name="common_understand">我明白</string>
|
||||
<string name="common_understand_continue">我明白,请继续</string>
|
||||
|
|
@ -414,10 +431,12 @@
|
|||
<string name="common_unstake">取消抵押</string>
|
||||
<string name="common_utxo_validate_withdrawal_message_warning">由于 %1$s 的限制,一次交易只能发送 %2$d 个UTXO。这意味着您只能发送 %3$s 或更少。您需要减少金额。</string>
|
||||
<string name="common_value_copied">通用值已拷贝</string>
|
||||
<string name="common_voting">表决</string>
|
||||
<string name="common_wallets">钱包</string>
|
||||
<string name="common_warning">警告</string>
|
||||
<string name="common_week">周</string>
|
||||
<string name="common_with">与</string>
|
||||
<string name="common_withdrawing">撤回</string>
|
||||
<string name="common_yes">是</string>
|
||||
<string name="common_yield_mode">收益模式</string>
|
||||
<string name="contract_address_copied_message">合约地址已复制!</string>
|
||||
|
|
@ -506,6 +525,7 @@
|
|||
<string name="dynamic_addresses_notification_funds_found_description">在其他地址发现了资金。启用动态地址即可访问这些地址。</string>
|
||||
<string name="dynamic_addresses_notification_funds_found_title">在其他地址发现的资金</string>
|
||||
<string name="dynamic_addresses_receive_badge">动态地址</string>
|
||||
<string name="dynamic_addresses_unavailability_reason_pending_transaction_send">一旦网络 %@ 中的待处理交易完成,即可进行动态地址管理</string>
|
||||
<string name="earn_best_opportunities">最佳机会</string>
|
||||
<string name="earn_clear_filter">清除筛选</string>
|
||||
<string name="earn_empty">列表正在刷新,暂时为空。请稍后再查看。</string>
|
||||
|
|
@ -578,12 +598,14 @@
|
|||
<string name="express_provider_best_rate">最佳汇率</string>
|
||||
<string name="express_provider_fca_warning_list">FCA警告清单</string>
|
||||
<string name="express_provider_fixed_rate_is_unavailable">固定利率不可用</string>
|
||||
<string name="express_provider_for_swap">兑换提供商</string>
|
||||
<string name="express_provider_great_rate">有竞争力的费率</string>
|
||||
<string name="express_provider_in_fca_warning_list">被列入 FCA 警告名单的提供商</string>
|
||||
<string name="express_provider_max_amount">最多可 %s</string>
|
||||
<string name="express_provider_min_amount">可用 %s</string>
|
||||
<string name="express_provider_not_available">此交易对不可用</string>
|
||||
<string name="express_provider_permission_needed">需要许可</string>
|
||||
<string name="express_provider_permission_needed_v2">需要许可</string>
|
||||
<string name="express_provider_recommended">推荐</string>
|
||||
<string name="express_status_bought">已购买 %s</string>
|
||||
<string name="express_status_buying">购买 %s</string>
|
||||
|
|
@ -631,6 +653,7 @@
|
|||
<string name="give_permission_staking_footer">您需要使用“批准”功能来授权其他地址使用您指定数量的代币。根据设计,智能合约只有在您批准后才能访问您的代币。通过“解锁”您的代币,您授权 StakeKit 智能合约使用它们。网络矿工会收到 Gas 费(由您支付)来记录区块链上的此操作。批准后,您可以质押您的代币。</string>
|
||||
<string name="give_permission_staking_subtitle">要继续,您需要允许 Polygon 智能合约使用您的 %s</string>
|
||||
<string name="give_permission_swap_subtitle" formatted="false">要继续,请授权 %1s 智能合约使用您的 %2s</string>
|
||||
<string name="give_permission_swap_subtitle_v2">去中心化交易所需要获得许可才能与您的钱包互动。 %1s</string>
|
||||
<string name="give_permission_title">给予许可</string>
|
||||
<string name="give_permission_unlimited">无限制</string>
|
||||
<string name="hardware_wallet_backup_feature_description">地址直接在您的 Tangem 硬件钱包上生成,随时可用,并受到全面保护。</string>
|
||||
|
|
@ -658,6 +681,8 @@
|
|||
<string name="hw_backup_banner_description">让您的加密货币安全离线存储。轻薄如信用卡,安全胜过银行金库。</string>
|
||||
<string name="hw_backup_close_description">如果确定现在退出,您需要从头再来。</string>
|
||||
<string name="hw_backup_google_drive_description">通过 Google 云端硬盘备份恢复现有钱包</string>
|
||||
<string name="hw_backup_google_drive_dialog_message">我们正在改进 Google 云盘备份功能,使钱包恢复更加便捷。</string>
|
||||
<string name="hw_backup_google_drive_dialog_title">Google 云盘备份功能即将推出</string>
|
||||
<string name="hw_backup_google_drive_title">Google 云端硬盘备份</string>
|
||||
<string name="hw_backup_hardware_create_description">创建一个安全的钱包并转移资金,以加强保护。</string>
|
||||
<string name="hw_backup_hardware_create_title">创建新钱包</string>
|
||||
|
|
@ -819,6 +844,7 @@
|
|||
<string name="markets_sort_by_yield_mode_title">收益模式</string>
|
||||
<string name="markets_staking_banner_description_placeholder">质押是获取加密货币奖励的最简单方式。 %s</string>
|
||||
<string name="markets_staking_banner_title">年利率最高可达 %s</string>
|
||||
<string name="markets_token_add_subtitle">在另一个网络或帐户中</string>
|
||||
<string name="markets_token_added">代币已添加</string>
|
||||
<string name="markets_token_details_about_token_title">关于 %s</string>
|
||||
<plurals name="markets_token_details_amount_exchanges">
|
||||
|
|
@ -1094,6 +1120,14 @@
|
|||
<string name="onramp_error_transaction_already_processed">此交易已处理完毕,无需进一步操作。</string>
|
||||
<string name="onramp_fetching_best_rates">获得最佳利率...</string>
|
||||
<string name="onramp_instant_status">即时</string>
|
||||
<string name="onramp_kyc_verification_bullet_free">验证是免费的,通常需要 1-2 分钟。</string>
|
||||
<string name="onramp_kyc_verification_bullet_privacy">Tangem无法获取您的身份信息,您直接与受监管的服务提供商共享数据。</string>
|
||||
<string name="onramp_kyc_verification_bullet_unlocks">通过验证后,即可完全访问该提供商的未来交易</string>
|
||||
<string name="onramp_kyc_verification_choose_another">选择其他方法</string>
|
||||
<string name="onramp_kyc_verification_subtitle">为遵守当地监管要求 %@ 需要进行身份验证。</string>
|
||||
<string name="onramp_kyc_verification_title">支付提供商要求进行身份验证</string>
|
||||
<string name="onramp_kyc_verification_verify_button">验证</string>
|
||||
<string name="onramp_kyc_verification_whats_important">什么是重要的</string>
|
||||
<string name="onramp_legal">使用 onramp 功能即表示您同意提供商的 %1$s 和 %2$s</string>
|
||||
<string name="onramp_legal_text">服务由外部供应商提供。\nTangem对此不承担任何责任。</string>
|
||||
<string name="onramp_max_amount_restriction">购买金额不应超过 %s</string>
|
||||
|
|
@ -1157,7 +1191,11 @@
|
|||
<string name="qr_scanner_warning_unknown_parameters_title">未知参数</string>
|
||||
<string name="quick_action_buy_description">信用卡或银行账户</string>
|
||||
<string name="quick_action_receive_description">分享您的地址或二维码</string>
|
||||
<string name="quick_action_sell_description">安全出售加密货币</string>
|
||||
<string name="quick_action_send_description">发送到另一个钱包</string>
|
||||
<string name="quick_action_swap_description">在您的投资组合之间</string>
|
||||
<string name="quick_top_up_chip_other">其他</string>
|
||||
<string name="quick_top_up_title">快速充值</string>
|
||||
<string name="receive_bottom_sheet_no_memo_required_message">无需备忘录</string>
|
||||
<string name="receive_bottom_sheet_warning_message">%1$s (%2$s) 在 %3$s 网络</string>
|
||||
<string name="receive_bottom_sheet_warning_message_compact">%1$s 在 %2$s 网络</string>
|
||||
|
|
@ -1511,13 +1549,16 @@
|
|||
<string name="sui_not_enough_coin_for_fee_description">至少需要有 %1$s 的转入交易才能继续进行</string>
|
||||
<string name="sui_not_enough_coin_for_fee_title">资金不足</string>
|
||||
<string name="swap_approve_description">批准后,您即允许智能合约在未来的交易中使用您的代币。</string>
|
||||
<string name="swap_detailed_mode">详细模式</string>
|
||||
<string name="swap_fixed_rate">固定利率</string>
|
||||
<string name="swap_give_permission_fee_footer">网络将收取代币批准费,以验证您是否授权使用您的代币进行兑换。</string>
|
||||
<string name="swap_in_progress">兑换中</string>
|
||||
<string name="swap_promo_text">直接在您的钱包中以更优惠的汇率兑换更多代币。</string>
|
||||
<string name="swap_promo_title">新增兑换服务提供商!</string>
|
||||
<string name="swap_search_suggestion_hint">还在寻找其他代币?\n尝试搜索或探索其他加密货币!</string>
|
||||
<string name="swap_search_tooltip_description">搜索任何代币,即使它还不在你的列表中。</string>
|
||||
<string name="swap_search_tooltip_title">使用搜索查找所需内容</string>
|
||||
<string name="swap_simple_mode">简易模式</string>
|
||||
<string name="swap_story_fifth_subtitle">我们提供全天候支持,让您安心无忧,任何问题都能得到帮助。</string>
|
||||
<string name="swap_story_fifth_title">永远在这里</string>
|
||||
<string name="swap_story_first_subtitle">多个值得信赖的供应商汇聚一处——在您的钱包中轻松兑换任何资产</string>
|
||||
|
|
@ -1546,7 +1587,9 @@
|
|||
<string name="swapping_approve_information_text">所有去中心化交易所都要求用户授权,以防止智能合约未经许可访问您的钱包。根据设计,智能合约只有在您授权后才能访问您的代币。通过“解锁”您的代币,您授权 1-inch 智能合约使用这些代币。网络矿工会收到 Gas 费(由您支付)来记录区块链上的此操作。授权后,您可以兑换您的代币。</string>
|
||||
<string name="swapping_approve_information_title">批准</string>
|
||||
<string name="swapping_fee_estimation_error_text">费用估算错误。请联系客服反馈。</string>
|
||||
<string name="swapping_from_account_title">您发送自</string>
|
||||
<string name="swapping_from_title">您兑换</string>
|
||||
<string name="swapping_from_title_v2">您发送</string>
|
||||
<string name="swapping_high_price_impact_description">兑换如此数量的选定代币将对价格产生重大影响,并降低您的收益。</string>
|
||||
<string name="swapping_high_price_impact_text">由于流动性低,您收到的资金可能会大大减少。请尝试较小的金额或另一个提供商。</string>
|
||||
<string name="swapping_high_price_impact_title">价格影响大</string>
|
||||
|
|
@ -1555,11 +1598,14 @@
|
|||
<string name="swapping_permission_header">给予许可</string>
|
||||
<string name="swapping_swap_action">兑换</string>
|
||||
<string name="swapping_swap_action_in_progress">互换...</string>
|
||||
<string name="swapping_to_account_title">您收到</string>
|
||||
<string name="swapping_to_title">您收到</string>
|
||||
<string name="swapping_token_list_title">选择代币</string>
|
||||
<string name="swapping_token_not_available">无法使用</string>
|
||||
<string name="swapping_trade_too_large_text">此交易流动性不足,请减少金额或选择其他供应商。</string>
|
||||
<string name="swapping_trade_too_large_title">交易额过大</string>
|
||||
<string name="swapping_transfer_action">转账</string>
|
||||
<string name="swapping_transfer_action_in_progress">转账...</string>
|
||||
<string name="tangem_pay_beta_notification_subtitle">我们非常乐意收到您的反馈。</string>
|
||||
<string name="tangem_pay_beta_notification_title">Tangem Pay 现已进入测试阶段</string>
|
||||
<string name="tangem_pay_card_details_unable_to_rename_card_title">无法重命名卡片</string>
|
||||
|
|
@ -1648,6 +1694,7 @@
|
|||
<string name="tangempay_card_details_withdraw_error_title">目前无法提款</string>
|
||||
<string name="tangempay_card_details_withdraw_in_progress_description">当前提款交易完成之前,您无法发起新的提款交易或互换交易。</string>
|
||||
<string name="tangempay_card_details_withdraw_in_progress_title">提款进行中</string>
|
||||
<string name="tangempay_card_edit_name_placeholder">卡片名称</string>
|
||||
<string name="tangempay_card_limit_setup_amount_subtitle">从 %s设定一个限额</string>
|
||||
<string name="tangempay_card_limit_setup_error_message">我们无法设置限额,请稍后再试。</string>
|
||||
<string name="tangempay_card_page_daily_limit_change">改变</string>
|
||||
|
|
@ -1699,6 +1746,8 @@
|
|||
<string name="tangempay_onboarding_purchases_title">实际支付金额与所示金额一致</string>
|
||||
<string name="tangempay_onboarding_security_description">将在不透露您的地址和资产的情况下创建一个单独的付款账户</string>
|
||||
<string name="tangempay_onboarding_security_title">无与伦比的隐私保护</string>
|
||||
<string name="tangempay_onboarding_setup_wallet_description">并将其与支付卡关联。</string>
|
||||
<string name="tangempay_onboarding_setup_wallet_title">我们将设置一个钱包。</string>
|
||||
<string name="tangempay_onboarding_title">几分钟内即可获得免费的 Tangem Pay 卡</string>
|
||||
<string name="tangempay_pay_support">支付支持</string>
|
||||
<string name="tangempay_payment_account">支付账户</string>
|
||||
|
|
@ -1774,12 +1823,21 @@
|
|||
<string name="tokens_list_unavailable_to_sell_header">无法出售</string>
|
||||
<string name="tokens_list_unavailable_to_swap_header">无法从 %s兑换</string>
|
||||
<string name="tokens_list_unavailable_to_swap_source_header">无法兑换</string>
|
||||
<string name="transaction_history_claiming_reward">领取奖励</string>
|
||||
<string name="transaction_history_contract_address">合约: %s</string>
|
||||
<string name="transaction_history_disabling_yield_mode">禁用收益模式</string>
|
||||
<string name="transaction_history_earned_from_stake">质押收益</string>
|
||||
<string name="transaction_history_empty_transactions">您目前还没有任何交易记录。</string>
|
||||
<string name="transaction_history_error_failed_to_load">加载交易历史记录失败。\n点击刷新按钮更新信息。</string>
|
||||
<string name="transaction_history_from_inline_address">%image%%s</string>
|
||||
<string name="transaction_history_multiple_addresses">多个地址</string>
|
||||
<string name="transaction_history_not_supported_description">本区块链目前不支持交易历史记录。不过不用担心,我们正在努力!在此期间,您可以在资源管理器中查看。</string>
|
||||
<string name="transaction_history_operation">操作</string>
|
||||
<string name="transaction_history_pending">待定</string>
|
||||
<string name="transaction_history_rewards_restaked">奖励已再质押</string>
|
||||
<string name="transaction_history_rewards_restaking">奖励再质押</string>
|
||||
<string name="transaction_history_staking_reward">质押奖励</string>
|
||||
<string name="transaction_history_to_inline_address">%image%%s</string>
|
||||
<string name="transaction_history_transaction_for_address">为 %s</string>
|
||||
<string name="transaction_history_transaction_from_address">来自 %s</string>
|
||||
<string name="transaction_history_transaction_to_address">到: %s</string>
|
||||
|
|
@ -2057,6 +2115,9 @@
|
|||
<plurals name="warning_missing_derivation_message">
|
||||
<item quantity="other">使用您的卡片或指环获取%d网络地址</item>
|
||||
</plurals>
|
||||
<plurals name="warning_missing_derivation_no_nfc_message">
|
||||
<item quantity="other">Adressen synchronisieren, um eine Adresse für das Netzwerk %d zu erhalten</item>
|
||||
</plurals>
|
||||
<string name="warning_missing_derivation_title">部分地址缺失</string>
|
||||
<string name="warning_network_unreachable_message">目前网络无法连接,请稍后再试。</string>
|
||||
<string name="warning_network_unreachable_title">网络无法访问</string>
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@
|
|||
<string name="common_error">錯誤</string>
|
||||
<string name="common_fee_error">獲取費用失敗</string>
|
||||
<string name="common_import">導入</string>
|
||||
<string name="common_in">在</string>
|
||||
<string name="common_in_progress">進行中</string>
|
||||
<string name="common_network_fee_title">網路費</string>
|
||||
<string name="common_no">否</string>
|
||||
|
|
@ -92,6 +93,7 @@
|
|||
<string name="common_success">成功</string>
|
||||
<string name="common_swap">交換</string>
|
||||
<string name="common_terms_and_conditions">條款和條件</string>
|
||||
<string name="common_token">代幣</string>
|
||||
<plurals name="common_tokens_count">
|
||||
<item quantity="other">%d 代幣</item>
|
||||
</plurals>
|
||||
|
|
|
|||
|
|
@ -217,6 +217,7 @@
|
|||
<string name="common_access_denied">Access denied</string>
|
||||
<string name="common_account">Account</string>
|
||||
<string name="common_accounts">Accounts</string>
|
||||
<string name="common_action_failed">%s failed</string>
|
||||
<string name="common_activate">Activate</string>
|
||||
<string name="common_add">Add</string>
|
||||
<string name="common_add_funds">Add funds</string>
|
||||
|
|
@ -233,6 +234,8 @@
|
|||
<string name="common_apply">Apply</string>
|
||||
<string name="common_approval">Approval</string>
|
||||
<string name="common_approve">Approve</string>
|
||||
<string name="common_approved">Approved</string>
|
||||
<string name="common_approving">Approving</string>
|
||||
<string name="common_attention">Attention</string>
|
||||
<string name="common_available_networks">Available networks</string>
|
||||
<string name="common_backup">Backup</string>
|
||||
|
|
@ -315,11 +318,16 @@
|
|||
<string name="common_hide">Hide</string>
|
||||
<string name="common_hold_to">Hold to %s</string>
|
||||
<string name="common_hour">hour</string>
|
||||
<plurals name="common_hours">
|
||||
<item quantity="one">%d hour</item>
|
||||
<item quantity="other">%d hours</item>
|
||||
</plurals>
|
||||
<plurals name="common_hours_time_ago">
|
||||
<item quantity="one">%dh ago</item>
|
||||
<item quantity="other">%dh ago</item>
|
||||
</plurals>
|
||||
<string name="common_import">Import</string>
|
||||
<string name="common_in">in</string>
|
||||
<string name="common_in_progress">In progress</string>
|
||||
<string name="common_insufficient_balance">Insufficient balance</string>
|
||||
<string name="common_later">Later</string>
|
||||
|
|
@ -364,6 +372,8 @@
|
|||
<string name="common_range_with_space">%1$s — %2$s</string>
|
||||
<string name="common_read_more">Read more</string>
|
||||
<string name="common_receive">Receive</string>
|
||||
<string name="common_received">Received</string>
|
||||
<string name="common_receiving">Receiving</string>
|
||||
<string name="common_recommended">Recommended</string>
|
||||
<string name="common_reject">Reject</string>
|
||||
<string name="common_reload">Reload</string>
|
||||
|
|
@ -382,6 +392,8 @@
|
|||
<string name="common_send">Send</string>
|
||||
<string name="common_send_colon">Send:</string>
|
||||
<string name="common_send_tx_error">Failed to send transaction</string>
|
||||
<string name="common_sending">Sending</string>
|
||||
<string name="common_sent">Sent</string>
|
||||
<string name="common_server_unavailable">The server is not available, please try again later</string>
|
||||
<string name="common_share">Share</string>
|
||||
<string name="common_share_link">Share Link</string>
|
||||
|
|
@ -392,6 +404,7 @@
|
|||
<string name="common_skip">Skip</string>
|
||||
<string name="common_something_went_wrong">Something went wrong</string>
|
||||
<string name="common_stake">Stake</string>
|
||||
<string name="common_staked">Staked</string>
|
||||
<string name="common_staking">Staking</string>
|
||||
<string name="common_start">Start</string>
|
||||
<string name="common_submit">Submit</string>
|
||||
|
|
@ -399,6 +412,8 @@
|
|||
<string name="common_support">Support</string>
|
||||
<string name="common_supported_networks">Supported networks</string>
|
||||
<string name="common_swap">Swap</string>
|
||||
<string name="common_swapped">Swapped</string>
|
||||
<string name="common_swapping">Swapping</string>
|
||||
<string name="common_tangem">Tangem</string>
|
||||
<string name="common_tangem_wallet">Tangem Wallet</string>
|
||||
<string name="common_tap_and_hold_hint">Tap and hold</string>
|
||||
|
|
@ -407,6 +422,7 @@
|
|||
<string name="common_to">To</string>
|
||||
<string name="common_to_wallet_name">To %s</string>
|
||||
<string name="common_today">Today</string>
|
||||
<string name="common_token">Token</string>
|
||||
<string name="common_token_send">Token to send</string>
|
||||
<plurals name="common_tokens_count">
|
||||
<item quantity="one">%d token</item>
|
||||
|
|
@ -416,6 +432,7 @@
|
|||
<string name="common_transaction_status">Transaction status</string>
|
||||
<string name="common_transactions">Transactions</string>
|
||||
<string name="common_transfer">Transfer</string>
|
||||
<string name="common_transferred">Transferred</string>
|
||||
<string name="common_unable_to_load">Unable to load data…</string>
|
||||
<string name="common_understand">I understand</string>
|
||||
<string name="common_understand_continue">I understand, continue</string>
|
||||
|
|
@ -425,10 +442,12 @@
|
|||
<string name="common_unstake">Unstake</string>
|
||||
<string name="common_utxo_validate_withdrawal_message_warning">Due to %1$s limitations only %2$d UTXOs can fit in a single transaction. This means you can only send %3$s or less. You need to reduce the amount.</string>
|
||||
<string name="common_value_copied">Value copied</string>
|
||||
<string name="common_voting">Voting</string>
|
||||
<string name="common_wallets">Wallets</string>
|
||||
<string name="common_warning">Warning</string>
|
||||
<string name="common_week">week</string>
|
||||
<string name="common_with">with</string>
|
||||
<string name="common_withdrawing">Withdrawing</string>
|
||||
<string name="common_yes">Yes</string>
|
||||
<string name="common_yield_mode">Yield Mode</string>
|
||||
<string name="contract_address_copied_message">Contract address copied!</string>
|
||||
|
|
@ -590,6 +609,7 @@
|
|||
<string name="express_provider_best_rate">Best rate</string>
|
||||
<string name="express_provider_fca_warning_list">FCA Warning List</string>
|
||||
<string name="express_provider_fixed_rate_is_unavailable">Fixed rate is unavailable</string>
|
||||
<string name="express_provider_for_swap">Provider for swap</string>
|
||||
<string name="express_provider_great_rate">Competitive rate</string>
|
||||
<string name="express_provider_in_fca_warning_list">Provider in FCA warning list</string>
|
||||
<string name="express_provider_max_amount">Available up to %s</string>
|
||||
|
|
@ -1194,6 +1214,8 @@
|
|||
<string name="qr_scanner_warning_unknown_parameters_title">Unknown Parameters</string>
|
||||
<string name="quick_action_buy_description">Credit card or bank account</string>
|
||||
<string name="quick_action_receive_description">Share your address or QR-code</string>
|
||||
<string name="quick_action_sell_description">Sell crypto securely</string>
|
||||
<string name="quick_action_send_description">Send to another wallet</string>
|
||||
<string name="quick_action_swap_description">Between your portfolios</string>
|
||||
<string name="quick_top_up_chip_other">Other</string>
|
||||
<string name="quick_top_up_title">Quick top up</string>
|
||||
|
|
@ -1443,6 +1465,7 @@
|
|||
<string name="staking_details_unbonding_period_info">The period you must wait after requesting to withdraw funds from staking before the tokens become available.</string>
|
||||
<string name="staking_details_warmup_period">Warmup period</string>
|
||||
<string name="staking_details_warmup_period_info">The allocated time for activating participation in staking.</string>
|
||||
<string name="staking_enabled">Staking enabled</string>
|
||||
<string name="staking_error_no_validators_message">No available validators at the moment. Please try again later.</string>
|
||||
<string name="staking_error_no_validators_title">Staking Unavailable</string>
|
||||
<string name="staking_give_permission_fee_footer">The network will charge a token approval fee to verify that you are authorizing the use of your token for the staking.</string>
|
||||
|
|
@ -1553,6 +1576,7 @@
|
|||
<string name="sui_not_enough_coin_for_fee_description">An incoming transaction of at least %1$s is required to proceed</string>
|
||||
<string name="sui_not_enough_coin_for_fee_title">Insufficient funds</string>
|
||||
<string name="swap_approve_description">By approving, you allow the smart contract to use your tokens in future transactions.</string>
|
||||
<string name="swap_detailed_mode">Detailed mode</string>
|
||||
<string name="swap_fixed_rate">Fixed Rate</string>
|
||||
<string name="swap_give_permission_fee_footer">The network will charge a token approval fee to verify that you are authorizing the use of your token for the swap.</string>
|
||||
<string name="swap_in_progress">Swap in progress</string>
|
||||
|
|
@ -1561,6 +1585,7 @@
|
|||
<string name="swap_search_suggestion_hint">Looking for something else?\nTry searching or explore another crypto!</string>
|
||||
<string name="swap_search_tooltip_description">Search for any token, even if it’s not in your list yet.</string>
|
||||
<string name="swap_search_tooltip_title">Use search to find what you need</string>
|
||||
<string name="swap_simple_mode">Simple mode</string>
|
||||
<string name="swap_story_fifth_subtitle">Feel confident with round-the-clock support to help with any issues</string>
|
||||
<string name="swap_story_fifth_title">Always Here</string>
|
||||
<string name="swap_story_first_subtitle">Multiple trusted providers in one place—swap any asset effortlessly in your wallet</string>
|
||||
|
|
@ -1606,6 +1631,8 @@
|
|||
<string name="swapping_token_not_available">not available</string>
|
||||
<string name="swapping_trade_too_large_text">Not enough liquidity for this trade.\nReduce the amount or choose another provider.</string>
|
||||
<string name="swapping_trade_too_large_title">Trade too large</string>
|
||||
<string name="swapping_transfer_action">Transfer</string>
|
||||
<string name="swapping_transfer_action_in_progress">Transfer...</string>
|
||||
<string name="tangem_pay_beta_notification_subtitle">We would be happy to receive your feedback</string>
|
||||
<string name="tangem_pay_beta_notification_title">Tangem Pay is now in beta</string>
|
||||
<string name="tangem_pay_card_details_unable_to_rename_card_title">Unable to rename card</string>
|
||||
|
|
@ -1682,6 +1709,7 @@
|
|||
<string name="tangempay_card_details_reissue_card">Replace card</string>
|
||||
<string name="tangempay_card_details_rename_card_invalid_description">Only letters and numbers are allowed</string>
|
||||
<string name="tangempay_card_details_rename_card_invalid_title">Invalid characters</string>
|
||||
<string name="tangempay_card_details_rename_card_placeholder">Card name</string>
|
||||
<string name="tangempay_card_details_reveal_text">Reveal</string>
|
||||
<string name="tangempay_card_details_show_details">Show details</string>
|
||||
<string name="tangempay_card_details_swap_description">Swap any asset in your portfolio for card</string>
|
||||
|
|
@ -1705,6 +1733,10 @@
|
|||
<string name="tangempay_card_page_daily_limit_success_title">Daily limit is set</string>
|
||||
<string name="tangempay_card_page_daily_limit_title">Daily limit</string>
|
||||
<string name="tangempay_card_page_settings_title">Card settings</string>
|
||||
<plurals name="tangempay_cards_count">
|
||||
<item quantity="one">%d card</item>
|
||||
<item quantity="other">%d cards</item>
|
||||
</plurals>
|
||||
<string name="tangempay_change_pin_code">Change PIN-code</string>
|
||||
<string name="tangempay_come_back_if_forget_pin">Come back to the app if you forget it.</string>
|
||||
<string name="tangempay_daily_limit_hint" formatted="false">Set a limit from %s to %s</string>
|
||||
|
|
@ -1719,8 +1751,14 @@
|
|||
<string name="tangempay_get_banner_description">Get your free Tangem Visa virtual card</string>
|
||||
<string name="tangempay_get_tangem_pay">Get Tangem Pay</string>
|
||||
<string name="tangempay_go_to_support">Go to Support</string>
|
||||
<string name="tangempay_issue_additional_card_description">It generates a new set of card details</string>
|
||||
<string name="tangempay_issue_additional_card_fee_label">Issue fee</string>
|
||||
<string name="tangempay_issue_additional_card_insufficient_funds_subtitle">Deposit USDC to payment account to cover the issuing fee</string>
|
||||
<string name="tangempay_issue_additional_card_insufficient_funds_title">Unable to cover fee</string>
|
||||
<string name="tangempay_issue_additional_card_title">Issue an additional card?</string>
|
||||
<string name="tangempay_issue_card_notification_description">It usually takes up to 15 minutes</string>
|
||||
<string name="tangempay_issue_card_notification_title">Setting up your Tangem Card</string>
|
||||
<string name="tangempay_issuing_new_digital_card_title">Issuing a new digital card</string>
|
||||
<string name="tangempay_issuing_your_card">Issuing your card</string>
|
||||
<string name="tangempay_issuing_your_card_description">The card is usually issued automatically within 5 minutes. In rare cases, if manual review is required, it may take up to 48 hours.</string>
|
||||
<string name="tangempay_kyc_card_ready_notification_title">Tangem Pay</string>
|
||||
|
|
@ -1737,6 +1775,8 @@
|
|||
<string name="tangempay_kyc_rejected_button_text">Hide KYC block</string>
|
||||
<string name="tangempay_kyc_rejected_description">Sorry, we couldn\'t verify</string>
|
||||
<string name="tangempay_kyc_rejected_description_span">your profile.</string>
|
||||
<string name="tangempay_maximum_cards_issued_description">You can have up to 3 cards. Delete one to add a new card.</string>
|
||||
<string name="tangempay_maximum_cards_issued_title">Maximum Cards Issued</string>
|
||||
<string name="tangempay_onboarding_banner_description">Get your free Tangem Visa virtual card</string>
|
||||
<string name="tangempay_onboarding_banner_title">Use USDC for everyday payments</string>
|
||||
<string name="tangempay_onboarding_get_card_button_text">Get card</string>
|
||||
|
|
@ -1746,6 +1786,8 @@
|
|||
<string name="tangempay_onboarding_purchases_title">Pay exactly what you see</string>
|
||||
<string name="tangempay_onboarding_security_description">A separate payment account will be created without disclosing your addresses and assets</string>
|
||||
<string name="tangempay_onboarding_security_title">Unrivaled privacy</string>
|
||||
<string name="tangempay_onboarding_setup_wallet_description">And link a payment card to it</string>
|
||||
<string name="tangempay_onboarding_setup_wallet_title">We\'ll set up a wallet</string>
|
||||
<string name="tangempay_onboarding_title">Get your free Tangem Pay Card in minutes</string>
|
||||
<string name="tangempay_pay_support">Pay Support</string>
|
||||
<string name="tangempay_payment_account">Payment account</string>
|
||||
|
|
@ -1795,7 +1837,7 @@
|
|||
<string name="token_button_unavailability_reason_yield_supply_approval">Approval has been revoked. Your funds remain in Yield mode. To perform actions, please go to Yield mode and grant permission again.</string>
|
||||
<string name="token_details_balance_available">Available balance</string>
|
||||
<string name="token_details_balance_total">Total balance</string>
|
||||
<string name="token_details_earn_staking_subtitle">Earn up to %s a year</string>
|
||||
<string name="token_details_earn_staking_subtitle">Up to %s APR</string>
|
||||
<string name="token_details_generate_xpub">Generate XPUB</string>
|
||||
<string name="token_details_hide_alert_hide">Hide</string>
|
||||
<string name="token_details_hide_alert_message">You are about to hide this token from the main screen. You can add it back anytime through the manage tokens page.</string>
|
||||
|
|
@ -1821,12 +1863,21 @@
|
|||
<string name="tokens_list_unavailable_to_sell_header">Unavailable to sell</string>
|
||||
<string name="tokens_list_unavailable_to_swap_header">Unavailable for swap from %s</string>
|
||||
<string name="tokens_list_unavailable_to_swap_source_header">Unavailable for swap</string>
|
||||
<string name="transaction_history_claiming_reward">Claiming reward</string>
|
||||
<string name="transaction_history_contract_address">contract: %s</string>
|
||||
<string name="transaction_history_disabling_yield_mode">Disabling Yield mode</string>
|
||||
<string name="transaction_history_earned_from_stake">Earned from stake</string>
|
||||
<string name="transaction_history_empty_transactions">You don\'t have any transactions yet</string>
|
||||
<string name="transaction_history_error_failed_to_load">Failed to load transaction history.\nClick on reload button to update the information.</string>
|
||||
<string name="transaction_history_from_inline_address">from: %%image%% %s</string>
|
||||
<string name="transaction_history_multiple_addresses">Multiple addresses</string>
|
||||
<string name="transaction_history_not_supported_description">Transaction history is currently not supported for this blockchain. But don\'t worry, we\'re working on it! In the meantime you can check it in the explorer.</string>
|
||||
<string name="transaction_history_operation">Operation</string>
|
||||
<string name="transaction_history_pending">Pending</string>
|
||||
<string name="transaction_history_rewards_restaked">Rewards restaked</string>
|
||||
<string name="transaction_history_rewards_restaking">Rewards restaking</string>
|
||||
<string name="transaction_history_staking_reward">Staking reward</string>
|
||||
<string name="transaction_history_to_inline_address">to: %%image%% %s</string>
|
||||
<string name="transaction_history_transaction_for_address">for: %s</string>
|
||||
<string name="transaction_history_transaction_from_address">from: %s</string>
|
||||
<string name="transaction_history_transaction_to_address">to: %s</string>
|
||||
|
|
@ -2104,7 +2155,11 @@
|
|||
<string name="warning_matic_migration_title">MATIC to POL Migration</string>
|
||||
<plurals name="warning_missing_derivation_message">
|
||||
<item quantity="one">Use your card or ring to get an address for %d network</item>
|
||||
<item quantity="other">Use your card or ring to get an addresses for %d networks</item>
|
||||
<item quantity="other">Use your card or ring to get addresses for %d networks</item>
|
||||
</plurals>
|
||||
<plurals name="warning_missing_derivation_no_nfc_message">
|
||||
<item quantity="one">Sync addresses to get an address for %d network</item>
|
||||
<item quantity="other">Sync addresses to get an addresses for %d networks</item>
|
||||
</plurals>
|
||||
<string name="warning_missing_derivation_title">Some addresses are missing</string>
|
||||
<string name="warning_network_unreachable_message">The network is currently unreachable. Please try again later.</string>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ abstract class VerifyDesignTokensTask : DefaultTask() {
|
|||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||
abstract val tokensDir: DirectoryProperty
|
||||
|
||||
@get:InputDirectory
|
||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||
abstract val iconsDir: DirectoryProperty
|
||||
|
||||
@get:InputFile
|
||||
@get:PathSensitive(PathSensitivity.NONE)
|
||||
abstract val hashFile: RegularFileProperty
|
||||
|
|
@ -37,21 +41,21 @@ abstract class VerifyDesignTokensTask : DefaultTask() {
|
|||
"Run: git submodule update --init --recursive"
|
||||
}
|
||||
|
||||
val digest = MessageDigest.getInstance("SHA-256")
|
||||
val jsonFiles = tokensDirValue.walkTopDown()
|
||||
.filter { it.isFile && it.extension == "json" }
|
||||
.sortedBy { it.relativeTo(tokensDirValue).path }
|
||||
.toList()
|
||||
|
||||
val nul = byteArrayOf(0)
|
||||
for (file in jsonFiles) {
|
||||
digest.update(file.relativeTo(tokensDirValue).invariantSeparatorsPath.toByteArray())
|
||||
digest.update(nul)
|
||||
digest.update(file.readBytes())
|
||||
digest.update(nul)
|
||||
val iconsDirValue = iconsDir.get().asFile
|
||||
require(iconsDirValue.exists() && iconsDirValue.isDirectory) {
|
||||
"ds-tokens icons folder not found: ${iconsDirValue.absolutePath}\n" +
|
||||
"Run: git submodule update --init --recursive"
|
||||
}
|
||||
|
||||
val actual = digest.digest()
|
||||
val tokensInputHash = hashTreeHex(tokensDirValue, "json")
|
||||
val iconsHash = hashTreeHex(iconsDirValue, "svg")
|
||||
|
||||
// Mirror build-tokens.mjs: sha256(tokensInputHash + 0x00 + iconsHash), all hex strings.
|
||||
val outer = MessageDigest.getInstance("SHA-256")
|
||||
outer.update(tokensInputHash.toByteArray())
|
||||
outer.update(0)
|
||||
outer.update(iconsHash.toByteArray())
|
||||
val actual = outer.digest()
|
||||
.joinToString("") { b: Byte -> b.toInt().and(0xFF).toString(16).padStart(2, '0') }
|
||||
val expected = hashFileValue.readText().trim()
|
||||
|
||||
|
|
@ -64,6 +68,23 @@ abstract class VerifyDesignTokensTask : DefaultTask() {
|
|||
|
||||
stampFile.get().asFile.writeText(actual)
|
||||
}
|
||||
|
||||
private fun hashTreeHex(root: java.io.File, extension: String): String {
|
||||
val digest = MessageDigest.getInstance("SHA-256")
|
||||
val files = root.walkTopDown()
|
||||
.filter { it.isFile && it.extension == extension }
|
||||
.sortedBy { it.relativeTo(root).invariantSeparatorsPath }
|
||||
.toList()
|
||||
val nul = byteArrayOf(0)
|
||||
for (file in files) {
|
||||
digest.update(file.relativeTo(root).invariantSeparatorsPath.toByteArray())
|
||||
digest.update(nul)
|
||||
digest.update(file.readBytes())
|
||||
digest.update(nul)
|
||||
}
|
||||
return digest.digest()
|
||||
.joinToString("") { b: Byte -> b.toInt().and(0xFF).toString(16).padStart(2, '0') }
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<Test>().configureEach {
|
||||
|
|
@ -83,6 +104,7 @@ android {
|
|||
|
||||
val verifyDesignTokens = tasks.register<VerifyDesignTokensTask>("verifyDesignTokens") {
|
||||
tokensDir.set(file("ds-tokens/tokens"))
|
||||
iconsDir.set(file("ds-tokens/icons"))
|
||||
hashFile.set(file("src/main/java/com/tangem/core/ui/res/generated/.tokens-hash"))
|
||||
stampFile.set(layout.buildDirectory.file("tokens-verified.stamp"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 27202508b606f54c276afa577a2f3e7a3da27e8b
|
||||
Subproject commit 06d801c92ac499d787093c30783e9ccb1f7e43dc
|
||||
|
|
@ -47,6 +47,18 @@ fun BottomFade(
|
|||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TopFade(vararg colorStops: Pair<Float, Color>, modifier: Modifier = Modifier, height: Dp = 100.dp) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(height)
|
||||
.background(
|
||||
brush = Brush.verticalGradient(colorStops = colorStops),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A composable that draws a fade effect at the bottom of the screen. Used on screens with a list of repeating
|
||||
* elements and floating button at the bottom of the screen.
|
||||
|
|
|
|||
|
|
@ -25,10 +25,8 @@ fun Modifier.edgeFade(
|
|||
isVisible: Boolean = true,
|
||||
animationSpec: AnimationSpec<Dp>? = null,
|
||||
color: Color = TangemTheme.colors.background.secondary,
|
||||
solidStop: Float = 0f,
|
||||
): Modifier = composed {
|
||||
require(value = size > 0.dp) {
|
||||
"Size must be greater than '0'"
|
||||
}
|
||||
val animatedSize = animationSpec?.let { spec ->
|
||||
animateDpAsState(
|
||||
targetValue = if (isVisible) size else 0.dp,
|
||||
|
|
@ -45,6 +43,7 @@ fun Modifier.edgeFade(
|
|||
|
||||
val staticSizePx = if (isVisible) size.toPx() else 0f
|
||||
val sizePx = animatedSize?.value?.toPx() ?: staticSizePx
|
||||
if (sizePx <= 0f) return@forEach
|
||||
|
||||
val fraction = when (side) {
|
||||
FadePosition.LEFT, FadePosition.RIGHT -> sizePx / this.size.width
|
||||
|
|
@ -54,6 +53,7 @@ fun Modifier.edgeFade(
|
|||
drawRect(
|
||||
brush = Brush.linearGradient(
|
||||
0f to color,
|
||||
solidStop.coerceIn(minimumValue = 0f, maximumValue = 1f) * fraction to color,
|
||||
fraction to Color.Transparent,
|
||||
start = start,
|
||||
end = end,
|
||||
|
|
@ -74,6 +74,25 @@ fun Modifier.bottomFade(
|
|||
color = color,
|
||||
)
|
||||
|
||||
/**
|
||||
* Draws a vertical gradient fade over the top edge of the content.
|
||||
*
|
||||
* @param height the fade region height
|
||||
* @param color the solid color at the top edge that fades to transparent at the bottom of the region
|
||||
* @param solidStop fraction (0..1) of [height] kept fully [color] before the fade starts
|
||||
*/
|
||||
@Composable
|
||||
fun Modifier.topFade(
|
||||
height: Dp,
|
||||
color: Color = TangemTheme.colors.background.secondary,
|
||||
solidStop: Float = 0f,
|
||||
): Modifier = edgeFade(
|
||||
FadePosition.TOP,
|
||||
size = height,
|
||||
color = color,
|
||||
solidStop = solidStop,
|
||||
)
|
||||
|
||||
enum class FadePosition {
|
||||
TOP, BOTTOM, LEFT, RIGHT
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ enum class AccountIconSize {
|
|||
@Composable
|
||||
fun AccountResIcon(@DrawableRes resId: Int, color: Color, size: AccountIconSize, modifier: Modifier = Modifier) {
|
||||
val boxSize by animateDpAsState(
|
||||
targetValue = size.boxSizeInDp(),
|
||||
targetValue = size.toBoxSize(),
|
||||
animationSpec = animation(),
|
||||
)
|
||||
val boxShapeCornerSize by animateDpAsState(
|
||||
|
|
@ -84,7 +84,7 @@ fun AccountResIcon(@DrawableRes resId: Int, color: Color, size: AccountIconSize,
|
|||
@Composable
|
||||
fun PaymentAccountIcon(size: AccountIconSize, modifier: Modifier = Modifier) {
|
||||
val boxSize by animateDpAsState(
|
||||
targetValue = size.boxSizeInDp(),
|
||||
targetValue = size.toBoxSize(),
|
||||
animationSpec = animation(),
|
||||
)
|
||||
val boxShapeCornerSize by animateDpAsState(
|
||||
|
|
@ -115,7 +115,7 @@ fun PaymentAccountIcon(size: AccountIconSize, modifier: Modifier = Modifier) {
|
|||
@Composable
|
||||
fun AccountCharIcon(char: Char, color: Color, size: AccountIconSize, modifier: Modifier = Modifier) {
|
||||
val boxSize by animateDpAsState(
|
||||
size.boxSizeInDp(),
|
||||
size.toBoxSize(),
|
||||
animationSpec = animation(),
|
||||
)
|
||||
val boxShapeCornerSize by animateDpAsState(
|
||||
|
|
@ -163,7 +163,7 @@ private fun AccountIconSize.iconSizeInDp(): Dp = when (this) {
|
|||
AccountIconSize.RedesignedDefault -> 20.dp
|
||||
}
|
||||
|
||||
private fun AccountIconSize.boxSizeInDp(): Dp = when (this) {
|
||||
fun AccountIconSize.toBoxSize(): Dp = when (this) {
|
||||
AccountIconSize.Default -> 36.dp
|
||||
AccountIconSize.Large -> 88.dp
|
||||
AccountIconSize.Medium -> 28.dp
|
||||
|
|
|
|||
|
|
@ -225,7 +225,6 @@ inline fun <reified T : TangemBottomSheetConfigContent> BasicBottomSheet(
|
|||
|
||||
val contentModifier = when (type) {
|
||||
Default -> Modifier
|
||||
.padding(bottom = bottomBarHeight)
|
||||
.clip(
|
||||
RoundedCornerShape(
|
||||
topStart = TangemTheme.dimens2.x8,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.core.ui.components.bottomsheets.modal
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.LocalOverscrollFactory
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
|
|
@ -13,13 +12,18 @@ import androidx.compose.runtime.*
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Velocity
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.PrimaryButton
|
||||
|
|
@ -31,6 +35,7 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
|||
import com.tangem.core.ui.components.bottomsheets.internal.ModalBottomSheetWithBackHandling
|
||||
import com.tangem.core.ui.components.bottomsheets.internal.collapse
|
||||
import com.tangem.core.ui.res.LocalBottomSheetAlwaysVisible
|
||||
import com.tangem.core.ui.res.LocalCanScrollBackward
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.utils.WindowInsetsZero
|
||||
|
|
@ -111,17 +116,13 @@ inline fun <reified T : TangemBottomSheetConfigContent> DefaultModalBottomSheet(
|
|||
sheetState = sheetState,
|
||||
onBack = onBack,
|
||||
bsContent = {
|
||||
CompositionLocalProvider(
|
||||
LocalOverscrollFactory provides null,
|
||||
) {
|
||||
BsContent(
|
||||
config = config,
|
||||
containerColor = containerColor,
|
||||
scrollableContent = scrollableContent,
|
||||
title = title,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
BsContent(
|
||||
config = config,
|
||||
containerColor = containerColor,
|
||||
scrollableContent = scrollableContent,
|
||||
title = title,
|
||||
content = content,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -178,6 +179,18 @@ inline fun <reified T : TangemBottomSheetConfigContent> BsContent(
|
|||
|
||||
val maxHeight = LocalConfiguration.current.screenHeightDp * MODAL_SHEET_MAX_HEIGHT
|
||||
|
||||
val canScrollBackward = LocalCanScrollBackward.current
|
||||
|
||||
val nestedScrollConnection = remember(canScrollBackward) {
|
||||
object : NestedScrollConnection {
|
||||
override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset =
|
||||
if (canScrollBackward) available else Offset.Zero
|
||||
|
||||
override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity =
|
||||
if (canScrollBackward) available else Velocity.Zero
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.systemBarsPadding()
|
||||
|
|
@ -185,7 +198,8 @@ inline fun <reified T : TangemBottomSheetConfigContent> BsContent(
|
|||
.clip(TangemTheme.shapes.roundedCornersLarge)
|
||||
.background(containerColor)
|
||||
.heightIn(max = maxHeight.dp)
|
||||
.fillMaxWidth(),
|
||||
.fillMaxWidth()
|
||||
.nestedScroll(nestedScrollConnection),
|
||||
) {
|
||||
Box(modifier = Modifier.fillMaxWidth()) {
|
||||
title(model)
|
||||
|
|
|
|||
|
|
@ -19,10 +19,49 @@ import androidx.compose.ui.unit.Dp
|
|||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.CircleShimmer
|
||||
import com.tangem.core.ui.extensions.conditional
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.test.TokenElementsTestTags
|
||||
import com.tangem.core.ui.utils.getGreyScaleColorFilter
|
||||
|
||||
/**
|
||||
* Cryptocurrency icon driven entirely by the supplied [modifier]: the icon and the network badge
|
||||
* lay out within the size set by the modifier — !!!no fixed icon/badge size params!!!.
|
||||
* Use the more configurable [CurrencyIcon] when custom sizing is required.
|
||||
*/
|
||||
@Composable
|
||||
fun TangemCurrencyIcon(state: CurrencyIconState, modifier: Modifier = Modifier, shouldDisplayNetwork: Boolean = true) {
|
||||
Box(modifier = modifier) {
|
||||
val iconModifier = Modifier.matchParentSize()
|
||||
|
||||
when (state) {
|
||||
is CurrencyIconState.Loading -> LoadingIcon(modifier = iconModifier)
|
||||
is CurrencyIconState.Locked -> LockedIcon(modifier = iconModifier)
|
||||
is CurrencyIconState.Empty -> EmptyIcon(resId = state.resId, modifier = iconModifier)
|
||||
is CurrencyIconState.CoinIcon,
|
||||
is CurrencyIconState.FiatIcon,
|
||||
is CurrencyIconState.CustomTokenIcon,
|
||||
is CurrencyIconState.TokenIcon,
|
||||
is CurrencyIconState.PaymentAccount,
|
||||
is CurrencyIconState.CryptoPortfolio.Icon,
|
||||
is CurrencyIconState.CryptoPortfolio.Letter,
|
||||
-> {
|
||||
ContentIconContainer(
|
||||
icon = state,
|
||||
modifier = iconModifier,
|
||||
shouldShowTopBadge = shouldDisplayNetwork,
|
||||
networkBadgeSize = 14.dp,
|
||||
networkBadgeBackground = if (LocalRedesignEnabled.current) {
|
||||
TangemTheme.colors2.surface.level1
|
||||
} else {
|
||||
TangemTheme.colors.background.primary
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cryptocurrency icon with network badge
|
||||
*
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ fun Modifier.hazeEffectTangem(
|
|||
val rootBackground by LocalRootBackgroundColor.current
|
||||
|
||||
return hazeEffect(state, style) {
|
||||
blurEnabled = isGlobalBlurEnabled
|
||||
fallbackTint = HazeTint(rootBackground.copy(alpha = 0.5f))
|
||||
configure()
|
||||
blurEnabled = blurEnabled && isGlobalBlurEnabled
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
package com.tangem.core.ui.components.transactions
|
||||
|
||||
import androidx.compose.foundation.text.InlineTextContent
|
||||
import androidx.compose.foundation.text.appendInlineContent
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.Placeholder
|
||||
import androidx.compose.ui.text.PlaceholderVerticalAlign
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
internal const val INLINE_IMAGE_PLACEHOLDER = "%image%"
|
||||
private const val INLINE_IMAGE_ID = "inline_subtitle_icon"
|
||||
|
||||
/**
|
||||
* Single-line caption with an inline icon between two text parts.
|
||||
*
|
||||
* Use a string resource of the shape `"prefix %%image%% %1\$s"` (escaped `%` so the marker
|
||||
* survives Lokalise round-trips), pre-format it via `stringResourceSafe`, and pass the result
|
||||
* here — [INLINE_IMAGE_PLACEHOLDER] is replaced with an [InlineTextContent] driven by [icon].
|
||||
*/
|
||||
@Composable
|
||||
internal fun InlineImageSubtitle(
|
||||
template: String,
|
||||
color: Color,
|
||||
modifier: Modifier = Modifier,
|
||||
afterIconColor: Color = color,
|
||||
iconSize: Dp = TangemTheme.dimens2.x4,
|
||||
icon: @Composable () -> Unit,
|
||||
) {
|
||||
val parts = remember(template) {
|
||||
val split = template.split(INLINE_IMAGE_PLACEHOLDER, limit = 2)
|
||||
if (split.size == 2) split[0] to split[1] else template to ""
|
||||
}
|
||||
val iconSizeSp = with(LocalDensity.current) { iconSize.toSp() }
|
||||
val inlineContent = remember(iconSizeSp) {
|
||||
mapOf(
|
||||
INLINE_IMAGE_ID to InlineTextContent(
|
||||
placeholder = Placeholder(
|
||||
width = iconSizeSp,
|
||||
height = iconSizeSp,
|
||||
placeholderVerticalAlign = PlaceholderVerticalAlign.Center,
|
||||
),
|
||||
children = { icon() },
|
||||
),
|
||||
)
|
||||
}
|
||||
val annotated = remember(parts, afterIconColor) {
|
||||
buildAnnotatedString {
|
||||
append(parts.first)
|
||||
appendInlineContent(INLINE_IMAGE_ID, INLINE_IMAGE_PLACEHOLDER)
|
||||
withStyle(SpanStyle(color = afterIconColor)) {
|
||||
append(parts.second)
|
||||
}
|
||||
}
|
||||
}
|
||||
Text(
|
||||
text = annotated,
|
||||
inlineContent = inlineContent,
|
||||
color = color,
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
|
@ -48,6 +48,10 @@ import java.util.UUID
|
|||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Deprecated(
|
||||
message = "Legacy. Use TransactionItem for redesigned screens",
|
||||
level = DeprecationLevel.WARNING,
|
||||
)
|
||||
@Composable
|
||||
@Suppress("LongMethod")
|
||||
fun Transaction(state: TransactionState, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
|
||||
|
|
@ -330,6 +334,7 @@ private fun TransactionState.isGoneIf(goneCondition: TransactionState.Content.()
|
|||
return if ((this as? TransactionState.Content)?.goneCondition() == true) Visibility.Gone else Visibility.Visible
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@Preview(showBackground = true, widthDp = 368)
|
||||
@Preview(showBackground = true, widthDp = 368, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -0,0 +1,442 @@
|
|||
package com.tangem.core.ui.components.transactions
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.layoutId
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.icons.identicon.IdentIcon
|
||||
import com.tangem.core.ui.components.transactions.state.TransactionItemUM
|
||||
import com.tangem.core.ui.components.transactions.state.TransactionItemUM.Content.Direction
|
||||
import com.tangem.core.ui.components.transactions.state.TransactionItemUM.Content.Status
|
||||
import com.tangem.core.ui.components.transactions.state.TransactionItemUM.ContentSubtitle
|
||||
import com.tangem.core.ui.ds.image.TangemDeviceIcon
|
||||
import com.tangem.core.ui.ds.row.TangemRowContainer
|
||||
import com.tangem.core.ui.ds.row.TangemRowLayoutId
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.orMaskWithStars
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
||||
@Composable
|
||||
fun TransactionItem(state: TransactionItemUM, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
|
||||
when (state) {
|
||||
is TransactionItemUM.Content -> ContentItem(
|
||||
state = state,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
modifier = modifier,
|
||||
)
|
||||
is TransactionItemUM.Pill -> TransactionStatusPill(
|
||||
state = state,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
modifier = modifier,
|
||||
)
|
||||
is TransactionItemUM.Loading,
|
||||
is TransactionItemUM.Locked,
|
||||
-> Unit
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ContentItem(state: TransactionItemUM.Content, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
|
||||
val rowModifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = state.onClick)
|
||||
|
||||
TangemRowContainer(
|
||||
modifier = rowModifier,
|
||||
contentPadding = PaddingValues(
|
||||
horizontal = TangemTheme.dimens2.x4,
|
||||
vertical = TangemTheme.dimens2.x3,
|
||||
),
|
||||
) {
|
||||
StatusCircle(
|
||||
iconRes = state.iconRes,
|
||||
status = state.status,
|
||||
modifier = Modifier
|
||||
.layoutId(TangemRowLayoutId.HEAD)
|
||||
.padding(end = TangemTheme.dimens2.x3)
|
||||
.size(TangemTheme.dimens2.x10),
|
||||
)
|
||||
TitleText(
|
||||
title = state.title,
|
||||
status = state.status,
|
||||
modifier = Modifier.layoutId(TangemRowLayoutId.START_TOP),
|
||||
)
|
||||
SubtitleText(
|
||||
subtitle = state.subtitle,
|
||||
status = state.status,
|
||||
modifier = Modifier
|
||||
.layoutId(TangemRowLayoutId.START_BOTTOM)
|
||||
.padding(top = TangemTheme.dimens2.x0_5),
|
||||
)
|
||||
AmountText(
|
||||
amount = state.amount,
|
||||
status = state.status,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
modifier = Modifier.layoutId(TangemRowLayoutId.END_TOP),
|
||||
)
|
||||
CurrencyText(
|
||||
symbol = state.currencySymbol,
|
||||
modifier = Modifier
|
||||
.layoutId(TangemRowLayoutId.END_BOTTOM)
|
||||
.padding(top = TangemTheme.dimens2.x0_5),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// region Status circle
|
||||
|
||||
@Composable
|
||||
private fun StatusCircle(iconRes: Int, status: Status, modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier.background(
|
||||
color = status.backgroundColor,
|
||||
shape = CircleShape,
|
||||
),
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(iconRes),
|
||||
contentDescription = null,
|
||||
tint = status.iconTint,
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens2.x5)
|
||||
.align(Alignment.Center),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val Status.backgroundColor: Color
|
||||
@Composable get() = when (this) {
|
||||
is Status.Confirmed -> TangemTheme.colors2.markers.backgroundTintedGray
|
||||
is Status.Unconfirmed -> TangemTheme.colors2.markers.backgroundTintedBlue
|
||||
is Status.Failed -> TangemTheme.colors2.markers.backgroundTintedRed
|
||||
}
|
||||
|
||||
private val Status.iconTint: Color
|
||||
@Composable get() = when (this) {
|
||||
is Status.Confirmed -> TangemTheme.colors2.fill.neutral.primary
|
||||
is Status.Unconfirmed -> TangemTheme.colors2.markers.iconBlue
|
||||
is Status.Failed -> TangemTheme.colors2.markers.iconRed
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region Title / Subtitle
|
||||
|
||||
@Composable
|
||||
private fun TitleText(title: TextReference, status: Status, modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
text = title.resolveReference(),
|
||||
color = status.titleColor,
|
||||
style = TangemTheme.typography2.bodyMedium16,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
private val Status.titleColor: Color
|
||||
@Composable get() = when (this) {
|
||||
is Status.Confirmed -> TangemTheme.colors2.text.neutral.primary
|
||||
is Status.Unconfirmed -> TangemTheme.colors2.text.status.accent
|
||||
is Status.Failed -> TangemTheme.colors2.text.status.warning
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun SubtitleText(subtitle: ContentSubtitle, status: Status, modifier: Modifier = Modifier) {
|
||||
val textStyle = TangemTheme.typography2.captionMedium12
|
||||
val tertiary = TangemTheme.colors2.text.neutral.tertiary
|
||||
val primary = TangemTheme.colors2.text.neutral.primary
|
||||
val isFailed = status is Status.Failed
|
||||
when (subtitle) {
|
||||
is ContentSubtitle.Plain -> Text(
|
||||
text = subtitle.text.resolveReference(),
|
||||
color = tertiary,
|
||||
style = textStyle,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = modifier,
|
||||
)
|
||||
is ContentSubtitle.ExternalAddress -> InlineImageSubtitle(
|
||||
template = stringResourceSafe(subtitle.direction.templateResId(), subtitle.briefAddress),
|
||||
color = tertiary,
|
||||
modifier = modifier,
|
||||
) {
|
||||
IdentIcon(
|
||||
address = subtitle.rawAddress,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clip(CircleShape),
|
||||
)
|
||||
}
|
||||
is ContentSubtitle.OwnAccount -> InlineImageSubtitle(
|
||||
template = stringResourceSafe(
|
||||
subtitle.direction.templateResId(),
|
||||
subtitle.accountName.resolveReference(),
|
||||
),
|
||||
color = tertiary,
|
||||
afterIconColor = if (isFailed) tertiary else primary,
|
||||
modifier = modifier,
|
||||
) {
|
||||
val backgroundColor = if (isFailed) {
|
||||
TangemTheme.colors2.graphic.neutral.quaternary
|
||||
} else {
|
||||
subtitle.iconBackgroundColor
|
||||
}
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clip(RoundedCornerShape(TangemTheme.dimens2.x1))
|
||||
.background(backgroundColor),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(id = subtitle.iconResId),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.text.constantWhite,
|
||||
modifier = Modifier.size(TangemTheme.dimens2.x2_5),
|
||||
)
|
||||
}
|
||||
}
|
||||
is ContentSubtitle.OwnWallet -> InlineImageSubtitle(
|
||||
template = stringResourceSafe(subtitle.direction.templateResId(), subtitle.walletName),
|
||||
color = tertiary,
|
||||
afterIconColor = primary,
|
||||
modifier = modifier,
|
||||
) {
|
||||
TangemDeviceIcon(
|
||||
state = subtitle.deviceIconUM,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ContentSubtitle.Direction.templateResId(): Int = when (this) {
|
||||
ContentSubtitle.Direction.TO -> R.string.transaction_history_to_inline_address
|
||||
ContentSubtitle.Direction.FROM -> R.string.transaction_history_from_inline_address
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region Amount
|
||||
|
||||
@Composable
|
||||
private fun AmountText(amount: String, status: Status, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
|
||||
val display = if (status is Status.Failed) amount.stripLeadingSign() else amount
|
||||
Text(
|
||||
text = display.orMaskWithStars(isBalanceHidden),
|
||||
color = if (status is Status.Confirmed) {
|
||||
TangemTheme.colors2.text.neutral.primary
|
||||
} else {
|
||||
TangemTheme.colors2.text.neutral.tertiary
|
||||
},
|
||||
textDecoration = if (status is Status.Failed) TextDecoration.LineThrough else null,
|
||||
style = TangemTheme.typography2.bodyMedium16,
|
||||
maxLines = 1,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CurrencyText(symbol: String, modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
text = symbol,
|
||||
color = TangemTheme.colors2.text.neutral.tertiary,
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
maxLines = 1,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
private fun String.stripLeadingSign(): String = when {
|
||||
startsWith('+') || startsWith('-') || startsWith('−') -> drop(1).trim()
|
||||
else -> this
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region Preview
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
private fun previewContent(
|
||||
txHash: String,
|
||||
iconRes: Int,
|
||||
direction: Direction,
|
||||
status: Status,
|
||||
title: String,
|
||||
subtitle: String,
|
||||
amount: String,
|
||||
currencySymbol: String = "USDT",
|
||||
): TransactionItemUM.Content = TransactionItemUM.Content(
|
||||
txHash = txHash,
|
||||
amount = amount,
|
||||
currencySymbol = currencySymbol,
|
||||
time = "",
|
||||
status = status,
|
||||
direction = direction,
|
||||
onClick = {},
|
||||
iconRes = iconRes,
|
||||
title = stringReference(title),
|
||||
subtitle = ContentSubtitle.Plain(stringReference(subtitle)),
|
||||
timestamp = 0L,
|
||||
)
|
||||
|
||||
@Composable
|
||||
private fun PreviewColumn(items: List<TransactionItemUM>) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors2.surface.level1)
|
||||
.padding(TangemTheme.dimens2.x2),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
|
||||
) {
|
||||
items.forEach { TransactionItem(state = it, isBalanceHidden = false) }
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_TransactionItem_Receive() {
|
||||
TangemThemePreviewRedesign {
|
||||
PreviewColumn(
|
||||
items = listOf(
|
||||
previewContent(
|
||||
txHash = "rcv-c",
|
||||
iconRes = R.drawable.ic_arrow_down_24,
|
||||
direction = Direction.INCOMING,
|
||||
status = Status.Confirmed,
|
||||
title = "Received",
|
||||
subtitle = "from: 33BdfS...ga2B",
|
||||
amount = "+350.00",
|
||||
),
|
||||
previewContent(
|
||||
txHash = "rcv-u",
|
||||
iconRes = R.drawable.ic_arrow_down_24,
|
||||
direction = Direction.INCOMING,
|
||||
status = Status.Unconfirmed,
|
||||
title = "Receiving",
|
||||
subtitle = "from: 33BdfS...ga2B",
|
||||
amount = "+350.00",
|
||||
),
|
||||
previewContent(
|
||||
txHash = "rcv-f",
|
||||
iconRes = R.drawable.ic_close_24,
|
||||
direction = Direction.INCOMING,
|
||||
status = Status.Failed,
|
||||
title = "Receiving failed",
|
||||
subtitle = "from: 33BdfS...ga2B",
|
||||
amount = "350.00",
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_TransactionItem_Send() {
|
||||
TangemThemePreviewRedesign {
|
||||
PreviewColumn(
|
||||
items = listOf(
|
||||
previewContent(
|
||||
txHash = "snd-c",
|
||||
iconRes = R.drawable.ic_arrow_up_24,
|
||||
direction = Direction.OUTGOING,
|
||||
status = Status.Confirmed,
|
||||
title = "Sent",
|
||||
subtitle = "to: 33BdfS...ga2B",
|
||||
amount = "-350.31",
|
||||
),
|
||||
previewContent(
|
||||
txHash = "snd-u",
|
||||
iconRes = R.drawable.ic_arrow_up_24,
|
||||
direction = Direction.OUTGOING,
|
||||
status = Status.Unconfirmed,
|
||||
title = "Sending",
|
||||
subtitle = "to: 33BdfS...ga2B",
|
||||
amount = "+350.31",
|
||||
),
|
||||
previewContent(
|
||||
txHash = "snd-f",
|
||||
iconRes = R.drawable.ic_close_24,
|
||||
direction = Direction.OUTGOING,
|
||||
status = Status.Failed,
|
||||
title = "Sending failed",
|
||||
subtitle = "to: 33BdfS...ga2B",
|
||||
amount = "350.31",
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_TransactionItem_Swap() {
|
||||
TangemThemePreviewRedesign {
|
||||
PreviewColumn(
|
||||
items = listOf(
|
||||
previewContent(
|
||||
txHash = "swp-c",
|
||||
iconRes = R.drawable.ic_exchange_vertical_24,
|
||||
direction = Direction.INCOMING,
|
||||
status = Status.Confirmed,
|
||||
title = "Swapped",
|
||||
subtitle = "to: POL",
|
||||
amount = "+350.00",
|
||||
),
|
||||
previewContent(
|
||||
txHash = "swp-u",
|
||||
iconRes = R.drawable.ic_exchange_vertical_24,
|
||||
direction = Direction.INCOMING,
|
||||
status = Status.Unconfirmed,
|
||||
title = "Swapping",
|
||||
subtitle = "to: POL",
|
||||
amount = "+350.00",
|
||||
),
|
||||
previewContent(
|
||||
txHash = "swp-f",
|
||||
iconRes = R.drawable.ic_close_24,
|
||||
direction = Direction.INCOMING,
|
||||
status = Status.Failed,
|
||||
title = "Swapping failed",
|
||||
subtitle = "to: POL",
|
||||
amount = "350.00",
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
|
@ -0,0 +1,313 @@
|
|||
package com.tangem.core.ui.components.transactions
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.icons.identicon.IdentIcon
|
||||
import com.tangem.core.ui.components.transactions.state.TransactionItemUM
|
||||
import com.tangem.core.ui.components.transactions.state.TransactionItemUM.Content.Status
|
||||
import com.tangem.core.ui.components.transactions.state.TransactionItemUM.PillKind
|
||||
import com.tangem.core.ui.components.transactions.state.TransactionItemUM.PillSubtitle
|
||||
import com.tangem.core.ui.extensions.orMaskWithStars
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
||||
@Composable
|
||||
internal fun TransactionStatusPill(
|
||||
state: TransactionItemUM.Pill,
|
||||
isBalanceHidden: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = state.onClick)
|
||||
.padding(horizontal = TangemTheme.dimens2.x4, vertical = TangemTheme.dimens2.x2),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
) {
|
||||
Pill(state = state, isBalanceHidden = isBalanceHidden)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Pill(state: TransactionItemUM.Pill, isBalanceHidden: Boolean) {
|
||||
val labelColor = state.status.labelColor()
|
||||
val secondaryColor = state.status.secondaryColor()
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(percent = 50))
|
||||
.background(TangemTheme.colors2.tabs.backgroundSecondary)
|
||||
.padding(horizontal = TangemTheme.dimens2.x2, vertical = TangemTheme.dimens2.x1),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x1),
|
||||
) {
|
||||
LeadingIcon(kind = state.kind, status = state.status)
|
||||
if (state.status is Status.Failed && state.amount != null) {
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.common_action_failed, state.failedBody(isBalanceHidden)),
|
||||
color = labelColor,
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
text = state.label.resolveReference(),
|
||||
color = labelColor,
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
)
|
||||
if (state.amount != null) {
|
||||
Text(
|
||||
text = state.amount.orMaskWithStars(isBalanceHidden),
|
||||
color = secondaryColor,
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
)
|
||||
state.currencySymbol?.let { symbol ->
|
||||
Text(
|
||||
text = symbol,
|
||||
color = secondaryColor,
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
val subtitle = state.subtitle
|
||||
if (subtitle is PillSubtitle.Address && state.status !is Status.Failed) {
|
||||
InlineImageSubtitle(
|
||||
template = stringResourceSafe(
|
||||
R.string.transaction_history_to_inline_address,
|
||||
subtitle.briefAddress,
|
||||
),
|
||||
color = secondaryColor,
|
||||
afterIconColor = labelColor,
|
||||
) {
|
||||
IdentIcon(
|
||||
address = subtitle.rawAddress,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clip(CircleShape),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LeadingIcon(kind: PillKind, status: Status) {
|
||||
if (status is Status.Unconfirmed) {
|
||||
CircularProgressIndicator(
|
||||
strokeWidth = 1.5.dp,
|
||||
color = TangemTheme.colors2.markers.iconBlue,
|
||||
modifier = Modifier.size(TangemTheme.dimens2.x4),
|
||||
)
|
||||
return
|
||||
}
|
||||
val iconRes = when (status) {
|
||||
is Status.Failed -> R.drawable.ic_close_24
|
||||
is Status.Confirmed -> when (kind) {
|
||||
PillKind.STAKING -> R.drawable.ic_transaction_history_staking_24
|
||||
PillKind.YIELD_MODE -> R.drawable.ic_yield_mode_16
|
||||
PillKind.APPROVE -> null
|
||||
}
|
||||
is Status.Unconfirmed -> null
|
||||
} ?: return
|
||||
Icon(
|
||||
painter = painterResource(iconRes),
|
||||
contentDescription = null,
|
||||
tint = status.iconTint(),
|
||||
modifier = Modifier.size(TangemTheme.dimens2.x4),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Status.labelColor(): Color = when (this) {
|
||||
is Status.Confirmed -> TangemTheme.colors2.text.neutral.secondary
|
||||
is Status.Unconfirmed -> TangemTheme.colors2.text.status.accent
|
||||
is Status.Failed -> TangemTheme.colors2.text.status.warning
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Status.secondaryColor(): Color = when (this) {
|
||||
is Status.Confirmed -> TangemTheme.colors2.text.neutral.primary
|
||||
is Status.Unconfirmed -> TangemTheme.colors2.text.status.accent
|
||||
is Status.Failed -> TangemTheme.colors2.text.status.warning
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Status.iconTint(): Color = when (this) {
|
||||
is Status.Confirmed -> TangemTheme.colors2.fill.neutral.primary
|
||||
is Status.Unconfirmed -> TangemTheme.colors2.markers.iconBlue
|
||||
is Status.Failed -> TangemTheme.colors2.markers.iconRed
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TransactionItemUM.Pill.failedBody(isBalanceHidden: Boolean): String = buildString {
|
||||
append(label.resolveReference())
|
||||
amount?.let { value ->
|
||||
append(' ')
|
||||
append(value.orMaskWithStars(isBalanceHidden))
|
||||
}
|
||||
currencySymbol?.let { symbol ->
|
||||
append(' ')
|
||||
append(symbol)
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
|
||||
private fun previewPill(
|
||||
txHash: String,
|
||||
kind: PillKind,
|
||||
status: Status,
|
||||
label: String,
|
||||
amount: String? = null,
|
||||
currencySymbol: String? = null,
|
||||
subtitle: PillSubtitle? = null,
|
||||
): TransactionItemUM.Pill = TransactionItemUM.Pill(
|
||||
txHash = txHash,
|
||||
kind = kind,
|
||||
status = status,
|
||||
label = stringReference(label),
|
||||
amount = amount,
|
||||
currencySymbol = currencySymbol,
|
||||
subtitle = subtitle,
|
||||
timestamp = 0L,
|
||||
onClick = {},
|
||||
)
|
||||
|
||||
@Composable
|
||||
private fun PillPreviewColumn(items: List<TransactionItemUM.Pill>) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors2.surface.level1)
|
||||
.padding(vertical = TangemTheme.dimens2.x2),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x1),
|
||||
) {
|
||||
items.forEach { TransactionStatusPill(state = it, isBalanceHidden = false) }
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("NamedArguments")
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_TransactionStatusPill_Staking() {
|
||||
TangemThemePreviewRedesign {
|
||||
PillPreviewColumn(
|
||||
items = listOf(
|
||||
previewPill("stk-c", PillKind.STAKING, Status.Confirmed, "Staked", "950.43", "TRX"),
|
||||
previewPill("stk-u", PillKind.STAKING, Status.Unconfirmed, "Staking", "1,000.00", "TRX"),
|
||||
previewPill("stk-f", PillKind.STAKING, Status.Failed, "Staking failed"),
|
||||
previewPill("ust-c", PillKind.STAKING, Status.Confirmed, "Unstaked", "950.43", "TRX"),
|
||||
previewPill("ust-u", PillKind.STAKING, Status.Unconfirmed, "Unstaking", "1,000.00", "TRX"),
|
||||
previewPill("ust-f", PillKind.STAKING, Status.Failed, "Unstaking failed"),
|
||||
previewPill("rst-c", PillKind.STAKING, Status.Confirmed, "Rewards restaked", "20.15", "TRX"),
|
||||
previewPill("rst-u", PillKind.STAKING, Status.Unconfirmed, "Rewards restaking", "20.15", "TRX"),
|
||||
previewPill("rst-f", PillKind.STAKING, Status.Failed, "Rewards restaking failed"),
|
||||
previewPill("wd-c", PillKind.STAKING, Status.Confirmed, "Withdraw"),
|
||||
previewPill("wd-u", PillKind.STAKING, Status.Unconfirmed, "Withdrawing"),
|
||||
previewPill("wd-f", PillKind.STAKING, Status.Failed, "Withdraw failed"),
|
||||
previewPill("vt-c", PillKind.STAKING, Status.Confirmed, "Vote"),
|
||||
previewPill("vt-u", PillKind.STAKING, Status.Unconfirmed, "Voting"),
|
||||
previewPill("vt-f", PillKind.STAKING, Status.Failed, "Vote failed"),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("NamedArguments")
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_TransactionStatusPill_YieldMode() {
|
||||
TangemThemePreviewRedesign {
|
||||
PillPreviewColumn(
|
||||
items = listOf(
|
||||
previewPill("yon-c", PillKind.YIELD_MODE, Status.Confirmed, "Yield mode Enabled"),
|
||||
previewPill("yon-u", PillKind.YIELD_MODE, Status.Unconfirmed, "Activating Yield mode"),
|
||||
previewPill("yon-f", PillKind.YIELD_MODE, Status.Failed, "Yield mode failed"),
|
||||
previewPill("yof-c", PillKind.YIELD_MODE, Status.Confirmed, "Yield mode disabled"),
|
||||
previewPill("yof-u", PillKind.YIELD_MODE, Status.Unconfirmed, "Disabling Yield mode"),
|
||||
previewPill("yof-f", PillKind.YIELD_MODE, Status.Failed, "Disabling Yield mode failed"),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("NamedArguments")
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_TransactionStatusPill_Approve() {
|
||||
TangemThemePreviewRedesign {
|
||||
PillPreviewColumn(
|
||||
items = listOf(
|
||||
// dApp variant — no subtitle
|
||||
previewPill("apv-c", PillKind.APPROVE, Status.Confirmed, "Approved", "2,350.00", "USDT"),
|
||||
previewPill("apv-u", PillKind.APPROVE, Status.Unconfirmed, "Approving", "2,350.00", "USDT"),
|
||||
previewPill("apv-f", PillKind.APPROVE, Status.Failed, "Approving", "2,350.00", "USDT"),
|
||||
// Address variant — with subtitle
|
||||
previewPill(
|
||||
txHash = "apa-c",
|
||||
kind = PillKind.APPROVE,
|
||||
status = Status.Confirmed,
|
||||
label = "Approved",
|
||||
amount = "2,350.00",
|
||||
currencySymbol = "USDT",
|
||||
subtitle = PillSubtitle.Address(
|
||||
rawAddress = "33BdfSXXXXXXXXXXXXXXXXXXXXXXga2B",
|
||||
briefAddress = "33BdfS...ga2B",
|
||||
),
|
||||
),
|
||||
previewPill(
|
||||
txHash = "apa-u",
|
||||
kind = PillKind.APPROVE,
|
||||
status = Status.Unconfirmed,
|
||||
label = "Approving",
|
||||
amount = "2,350.00",
|
||||
currencySymbol = "USDT",
|
||||
subtitle = PillSubtitle.Address(
|
||||
rawAddress = "33BdfSXXXXXXXXXXXXXXXXXXXXXXga2B",
|
||||
briefAddress = "33BdfS...ga2B",
|
||||
),
|
||||
),
|
||||
previewPill(
|
||||
txHash = "apa-f",
|
||||
kind = PillKind.APPROVE,
|
||||
status = Status.Failed,
|
||||
label = "Approving",
|
||||
amount = "2,350.00",
|
||||
currencySymbol = "USDT",
|
||||
subtitle = PillSubtitle.Address(
|
||||
rawAddress = "33BdfSXXXXXXXXXXXXXXXXXXXXXXga2B",
|
||||
briefAddress = "33BdfS...ga2B",
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.tangem.core.ui.components.transactions
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
||||
@Composable
|
||||
fun TxHistoryDateHeader(title: String, modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
text = title,
|
||||
color = TangemTheme.colors2.text.neutral.primary,
|
||||
style = TangemTheme.typography2.bodyMedium16,
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
start = TangemTheme.dimens2.x4,
|
||||
end = TangemTheme.dimens2.x4,
|
||||
top = TangemTheme.dimens2.x6,
|
||||
bottom = TangemTheme.dimens2.x3,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_TxHistoryDateHeader() {
|
||||
TangemThemePreviewRedesign {
|
||||
TxHistoryDateHeader(title = "Today")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
package com.tangem.core.ui.components.transactions.state
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import com.tangem.core.ui.ds.image.DeviceIconUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
/**
|
||||
* UI model for the redesigned transaction list item ([REDACTED_TASK_KEY]).
|
||||
*
|
||||
* Mirrors the field set of the legacy [TransactionState] but splits the formatted amount string
|
||||
* into a numeric [Content.amount] (with sign) and a separate [Content.currencySymbol], so the
|
||||
* redesigned `TransactionItem` composable can render them on independent lines without parsing.
|
||||
*/
|
||||
@Immutable
|
||||
sealed interface TransactionItemUM {
|
||||
|
||||
/** Transaction hash */
|
||||
val txHash: String
|
||||
|
||||
/**
|
||||
* Content state.
|
||||
*
|
||||
* @property amount signed numeric value, e.g. "+0.500913" / "-350.31"; no currency symbol embedded
|
||||
* @property currencySymbol currency symbol shown alongside [amount], e.g. "BTC", "USDT"
|
||||
*/
|
||||
data class Content(
|
||||
override val txHash: String,
|
||||
val amount: String,
|
||||
val currencySymbol: String,
|
||||
val time: String,
|
||||
val status: Status,
|
||||
val direction: Direction,
|
||||
val onClick: () -> Unit,
|
||||
@DrawableRes val iconRes: Int,
|
||||
val title: TextReference,
|
||||
val subtitle: ContentSubtitle,
|
||||
val timestamp: Long,
|
||||
) : TransactionItemUM {
|
||||
|
||||
@Immutable
|
||||
sealed class Status {
|
||||
data object Failed : Status()
|
||||
data object Confirmed : Status()
|
||||
data object Unconfirmed : Status()
|
||||
}
|
||||
|
||||
enum class Direction {
|
||||
INCOMING,
|
||||
OUTGOING,
|
||||
}
|
||||
}
|
||||
|
||||
/** Subtitle variants for [Content] rows. */
|
||||
@Immutable
|
||||
sealed interface ContentSubtitle {
|
||||
/** Plain text — for types without a directly-displayable address (Operation, GaslessFee, ClaimRewards, etc.). */
|
||||
data class Plain(val text: TextReference) : ContentSubtitle
|
||||
|
||||
/**
|
||||
* External counterparty address — renders as "to/from: <identicon> <briefAddress>".
|
||||
* Used for Transfer to/from external addresses.
|
||||
*/
|
||||
data class ExternalAddress(
|
||||
val direction: Direction,
|
||||
val rawAddress: String,
|
||||
val briefAddress: String,
|
||||
) : ContentSubtitle
|
||||
|
||||
/**
|
||||
* Counterparty matches one of the user's own accounts — renders as "to/from: <accountIcon> <accountName>".
|
||||
*/
|
||||
data class OwnAccount(
|
||||
val direction: Direction,
|
||||
val accountName: TextReference,
|
||||
@DrawableRes val iconResId: Int,
|
||||
val iconBackgroundColor: Color,
|
||||
) : ContentSubtitle
|
||||
|
||||
/**
|
||||
* Counterparty matches one of the user's own wallets (cross-wallet transfer with accounts mode disabled) —
|
||||
* renders as "to/from: <walletIcon> <walletName>".
|
||||
*/
|
||||
data class OwnWallet(
|
||||
val direction: Direction,
|
||||
val walletName: String,
|
||||
val deviceIconUM: DeviceIconUM,
|
||||
) : ContentSubtitle
|
||||
|
||||
enum class Direction { TO, FROM }
|
||||
}
|
||||
|
||||
/**
|
||||
* Compact status pill — used for Staking / YieldMode / Approve transactions where the row format
|
||||
* is replaced by a single chip with status-aware colors.
|
||||
*
|
||||
* @property kind controls leading icon and color tint
|
||||
* @property status drives background/text colors and Failed/Unconfirmed icon override
|
||||
* @property label full pill label text (already composed by converter, e.g. "Staked")
|
||||
* @property amount optional signed numeric value rendered after [label] (e.g. "950.43");
|
||||
* null for kinds that don't carry amount (Vote, Withdraw, Yield mode)
|
||||
* @property currencySymbol currency symbol rendered after [amount]; null when [amount] is null
|
||||
* @property subtitle optional subtitle (e.g. "to: 33Bd...ga2B" with avatar) for Approve
|
||||
*/
|
||||
data class Pill(
|
||||
override val txHash: String,
|
||||
val kind: PillKind,
|
||||
val status: Content.Status,
|
||||
val label: TextReference,
|
||||
val amount: String?,
|
||||
val currencySymbol: String?,
|
||||
val subtitle: PillSubtitle?,
|
||||
val timestamp: Long,
|
||||
val onClick: () -> Unit,
|
||||
) : TransactionItemUM
|
||||
|
||||
enum class PillKind {
|
||||
STAKING,
|
||||
YIELD_MODE,
|
||||
APPROVE,
|
||||
}
|
||||
|
||||
@Immutable
|
||||
sealed interface PillSubtitle {
|
||||
/** Address subtitle with inline IdentIcon (Blockies 8×8, hashed from [rawAddress]). */
|
||||
data class Address(val rawAddress: String, val briefAddress: String) : PillSubtitle
|
||||
}
|
||||
|
||||
data class Loading(override val txHash: String) : TransactionItemUM
|
||||
|
||||
data class Locked(override val txHash: String) : TransactionItemUM
|
||||
}
|
||||
|
|
@ -147,7 +147,7 @@ private fun StartIcon(
|
|||
is TangemIconUM.Icon -> if (shouldRespectIconTint) {
|
||||
wrappedIconRes
|
||||
} else {
|
||||
wrappedIconRes.copy(tintReference = ColorReference2 { iconColor })
|
||||
wrappedIconRes.copy(tint = ColorReference2 { iconColor })
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
@ -180,7 +180,7 @@ private fun EndIcon(
|
|||
is TangemIconUM.Icon -> if (shouldRespectIconTint) {
|
||||
wrappedIconRes
|
||||
} else {
|
||||
wrappedIconRes.copy(tintReference = ColorReference2 { iconColor })
|
||||
wrappedIconRes.copy(tint = ColorReference2 { iconColor })
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ fun ActionButtons(buttons: ImmutableList<TangemButtonUM>, modifier: Modifier = M
|
|||
)
|
||||
Text(
|
||||
text = button.text.orEmpty().resolveReference(),
|
||||
style = TangemTheme.typography2.calloutSemibold15,
|
||||
style = TangemTheme.typography2.subheadlineMedium14,
|
||||
color = textColor,
|
||||
maxLines = 1,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -46,9 +46,11 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.components.haze.hazeEffectTangem
|
||||
import com.tangem.core.ui.ds.button.GhostTangemButton
|
||||
import com.tangem.core.ui.ds.button.TangemButtonSize
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
|
|
@ -177,7 +179,11 @@ private fun DecorationBox(
|
|||
contentAlignment = BiasAlignment(horizontalBias = alignmentBias, verticalBias = 0f),
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.background(color, shape.toShape())
|
||||
.clip(shape.toShape())
|
||||
.background(color)
|
||||
.hazeEffectTangem {
|
||||
blurRadius = 8.dp
|
||||
}
|
||||
.padding(TangemTheme.dimens2.x3),
|
||||
) {
|
||||
Row(
|
||||
|
|
|
|||
|
|
@ -6,18 +6,21 @@ import androidx.compose.foundation.background
|
|||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import arrow.core.Either
|
||||
import coil.compose.SubcomposeAsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.tangem.core.ui.components.CircleShimmer
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.currency.icon.TangemCurrencyIcon
|
||||
import com.tangem.core.ui.components.icons.identicon.IdentIcon
|
||||
import com.tangem.core.ui.extensions.ColorReference2
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
|
@ -37,14 +40,36 @@ sealed interface TangemIconUM {
|
|||
) : TangemIconUM
|
||||
|
||||
/** Icon represented by a drawable resource. */
|
||||
@Immutable
|
||||
data class Icon(
|
||||
@DrawableRes val iconRes: Int,
|
||||
val tintReference: ColorReference2 = ColorReference2 { TangemTheme.colors2.graphic.neutral.primary },
|
||||
) : TangemIconUM
|
||||
internal val icon: Either<Int, ImageVector>,
|
||||
val tint: ColorReference2?,
|
||||
) : TangemIconUM {
|
||||
|
||||
constructor(
|
||||
@DrawableRes iconRes: Int,
|
||||
tintReference: ColorReference2 = ColorReference2 { TangemTheme.colors2.graphic.neutral.primary },
|
||||
) : this(Either.Left(iconRes), tintReference)
|
||||
|
||||
constructor(
|
||||
imageVector: ImageVector,
|
||||
tintReference: ColorReference2? = null,
|
||||
) : this(Either.Right(imageVector), tintReference)
|
||||
|
||||
@Composable
|
||||
fun imageVector(): ImageVector = icon.fold(
|
||||
ifLeft = { resId -> ImageVector.vectorResource(resId) },
|
||||
ifRight = { it },
|
||||
)
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun tintReference() = tint?.invoke() ?: LocalContentColor.current
|
||||
}
|
||||
|
||||
/** Image represented by a drawable resource. */
|
||||
data class Image(
|
||||
@DrawableRes val imageRes: Int,
|
||||
@param:DrawableRes val imageRes: Int,
|
||||
) : TangemIconUM
|
||||
|
||||
/** Identicon represented by a text string (e.g., an address). */
|
||||
|
|
@ -69,13 +94,16 @@ sealed interface TangemIconUM {
|
|||
fun TangemIcon(tangemIconUM: TangemIconUM, modifier: Modifier = Modifier) {
|
||||
when (tangemIconUM) {
|
||||
is TangemIconUM.Currency -> {
|
||||
CurrencyIcon(
|
||||
TangemCurrencyIcon(
|
||||
state = tangemIconUM.currencyIconState,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
is TangemIconUM.Icon -> Icon(
|
||||
imageVector = ImageVector.vectorResource(tangemIconUM.iconRes),
|
||||
imageVector = tangemIconUM.icon.fold(
|
||||
ifLeft = { resId -> ImageVector.vectorResource(resId) },
|
||||
ifRight = { it },
|
||||
),
|
||||
contentDescription = null,
|
||||
modifier = modifier,
|
||||
tint = tangemIconUM.tintReference(),
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import org.burnoutcrew.reorderable.ReorderableLazyListState
|
|||
import org.burnoutcrew.reorderable.detectReorder
|
||||
|
||||
@Composable
|
||||
internal fun TangemRowTail(
|
||||
fun TangemRowTail(
|
||||
tangemRowTailUM: TangemRowTailUM,
|
||||
modifier: Modifier = Modifier,
|
||||
reorderableState: ReorderableLazyListState? = null,
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ fun TangemTokenRow(
|
|||
tangemIconUM = tokenRowUM.headIconUM,
|
||||
modifier = Modifier
|
||||
.layoutId(layoutId = TangemRowLayoutId.HEAD)
|
||||
.padding(end = TangemTheme.dimens2.x2)
|
||||
.size(TangemTheme.dimens2.x9)
|
||||
.padding(end = TangemTheme.dimens2.x3)
|
||||
.size(TangemTheme.dimens2.x10)
|
||||
.testTag(tag = TokenElementsTestTags.TOKEN_ICON),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,9 +9,6 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
|
@ -30,7 +27,7 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
||||
@Composable
|
||||
internal fun TokenRowEndContent(
|
||||
fun TokenRowEndContent(
|
||||
endContentUM: TangemTokenRowUM.EndContentUM,
|
||||
isBalanceHidden: Boolean,
|
||||
textStyle: TextStyle,
|
||||
|
|
@ -83,7 +80,7 @@ private fun Content(
|
|||
endContentUM.startIcons.fastForEach { icon ->
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens2.x3),
|
||||
painter = rememberVectorPainter(image = ImageVector.vectorResource(icon.iconRes)),
|
||||
imageVector = icon.imageVector(),
|
||||
tint = icon.tintReference(),
|
||||
contentDescription = null,
|
||||
)
|
||||
|
|
@ -117,7 +114,7 @@ private fun Content(
|
|||
endContentUM.endIcons.fastForEach { icon ->
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens2.x3),
|
||||
painter = rememberVectorPainter(image = ImageVector.vectorResource(icon.iconRes)),
|
||||
imageVector = icon.imageVector(),
|
||||
tint = icon.tintReference(),
|
||||
contentDescription = null,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import androidx.annotation.DrawableRes
|
|||
import androidx.compose.animation.*
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.text.TextAutoSize
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
|
|
@ -12,6 +13,9 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.Layout
|
||||
import androidx.compose.ui.layout.MeasurePolicy
|
||||
import androidx.compose.ui.layout.layoutId
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
|
@ -95,14 +99,39 @@ fun TangemTopBar(
|
|||
startContent: @Composable (() -> Unit)? = null,
|
||||
endContent: @Composable (() -> Unit)? = null,
|
||||
) {
|
||||
TangemTopBar(
|
||||
modifier = modifier,
|
||||
type = type,
|
||||
startContent = startContent,
|
||||
endContent = endContent,
|
||||
Layout(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = type.getSize())
|
||||
.padding(type.getPadding()),
|
||||
measurePolicy = TopBarMeasurePolicy,
|
||||
content = {
|
||||
Box(modifier = Modifier.layoutId(SLOT_START)) {
|
||||
AnimatedContent(
|
||||
targetState = startContent != null,
|
||||
modifier = Modifier.size(TangemTheme.dimens2.x11),
|
||||
label = "Start Content Visibility",
|
||||
) { isVisible ->
|
||||
if (isVisible) {
|
||||
startContent?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
Box(modifier = Modifier.layoutId(SLOT_END)) {
|
||||
AnimatedContent(
|
||||
targetState = endContent != null,
|
||||
modifier = Modifier
|
||||
.height(TangemTheme.dimens2.x11)
|
||||
.widthIn(min = TangemTheme.dimens2.x11),
|
||||
label = "End Content Visibility",
|
||||
) { isVisible ->
|
||||
if (isVisible) {
|
||||
endContent?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier.weight(1f),
|
||||
modifier = Modifier.layoutId(SLOT_TITLE),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x0_5),
|
||||
) {
|
||||
|
|
@ -125,6 +154,48 @@ fun TangemTopBar(
|
|||
)
|
||||
}
|
||||
|
||||
private const val SLOT_START = "start"
|
||||
private const val SLOT_END = "end"
|
||||
private const val SLOT_TITLE = "title"
|
||||
|
||||
/**
|
||||
* Measure policy for [TangemTopBar].
|
||||
*
|
||||
* Title is centered relative to the full bar width. To avoid overlap with side slots,
|
||||
* the larger of the two slot widths is reserved on both sides symmetrically.
|
||||
*/
|
||||
private val TopBarMeasurePolicy = MeasurePolicy { measurables, constraints ->
|
||||
val looseConstraints = constraints.copy(minWidth = 0, minHeight = 0)
|
||||
|
||||
val startPlaceable = measurables.first { it.layoutId == SLOT_START }.measure(looseConstraints)
|
||||
val endPlaceable = measurables.first { it.layoutId == SLOT_END }.measure(looseConstraints)
|
||||
|
||||
val totalWidth = constraints.maxWidth
|
||||
val sideReserve = maxOf(startPlaceable.width, endPlaceable.width)
|
||||
val titleMaxWidth = (totalWidth - sideReserve * 2).coerceAtLeast(0)
|
||||
|
||||
val titlePlaceable = measurables.first { it.layoutId == SLOT_TITLE }
|
||||
.measure(looseConstraints.copy(maxWidth = titleMaxWidth))
|
||||
|
||||
val height = maxOf(startPlaceable.height, endPlaceable.height, titlePlaceable.height)
|
||||
.coerceAtLeast(constraints.minHeight)
|
||||
|
||||
layout(totalWidth, height) {
|
||||
startPlaceable.placeRelative(
|
||||
x = 0,
|
||||
y = (height - startPlaceable.height) / 2,
|
||||
)
|
||||
endPlaceable.placeRelative(
|
||||
x = totalWidth - endPlaceable.width,
|
||||
y = (height - endPlaceable.height) / 2,
|
||||
)
|
||||
titlePlaceable.placeRelative(
|
||||
x = (totalWidth - titlePlaceable.width) / 2,
|
||||
y = (height - titlePlaceable.height) / 2,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A top bar composable that displays a title and optional start and end icons.
|
||||
* [Figma](https://www.figma.com/design/RU7AIgwHtGdMfy83T5UOoR/Core-Library?node-id=8435-74860&m=dev)
|
||||
|
|
@ -222,6 +293,10 @@ private fun TangemTopBarTitle(title: TextReference?, @DrawableRes titleIconRes:
|
|||
style = TangemTheme.typography2.headingSemibold17,
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 1,
|
||||
autoSize = TextAutoSize.StepBased(
|
||||
minFontSize = TangemTheme.typography2.captionRegular12.fontSize,
|
||||
maxFontSize = TangemTheme.typography2.headingSemibold17.fontSize,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,10 +28,7 @@ enum class TangemTopBarType {
|
|||
@ReadOnlyComposable
|
||||
@Composable
|
||||
fun getSideContentSize(): Dp {
|
||||
return when (this) {
|
||||
Default -> TangemTheme.dimens2.x8
|
||||
BottomSheet -> TangemTheme.dimens2.x7
|
||||
}
|
||||
return TangemTheme.dimens2.x7
|
||||
}
|
||||
|
||||
@ReadOnlyComposable
|
||||
|
|
|
|||
|
|
@ -0,0 +1,251 @@
|
|||
package com.tangem.core.ui.ds2.button
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.interaction.collectIsFocusedAsState
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.disabled
|
||||
import androidx.compose.ui.semantics.role
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.ds2.surface.TangemSurface
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
||||
/**
|
||||
* Design-system v2 button supporting an optional leading icon, label, and trailing icon.
|
||||
*
|
||||
* [Figma](https://www.figma.com/design/AsnJ5CPHib4Qxw12gszjMS/%F0%9F%92%A0-DS-Components?node-id=0-1)
|
||||
*
|
||||
* Behavior notes:
|
||||
* - When [isLoading] is `true` — or when no icon and no [text] are supplied — the content fades out
|
||||
* and a centered [com.tangem.core.ui.ds2.loader.TangemLoader] is shown in the variant's icon
|
||||
* color. Clicks are still routed to [onClick] unless [isEnabled] is `false`.
|
||||
* - When [text] is `null`, the button renders in icon-only mode (square footprint driven by
|
||||
* [size]); otherwise its width grows from [TangemButton.Size]'s `minWidth` and the label
|
||||
* truncates with an ellipsis when it can't fit. Pass `Modifier.fillMaxWidth()` (or any width
|
||||
* modifier) on [modifier] to switch to a fixed-width layout.
|
||||
* - [iconStart], [iconEnd], and [text] may be toggled at runtime — each slot fades and expands /
|
||||
* shrinks horizontally so the layout animates smoothly.
|
||||
* - Icon tints are always driven by [variant] (and swapped for the disabled tint when [isEnabled]
|
||||
* is `false`); any tint set on the supplied [TangemIconUM.Icon] is ignored.
|
||||
* - The focus ring is drawn whenever the button is focused, including when [isEnabled] is `false`,
|
||||
* so disabled buttons remain reachable via keyboard / accessibility focus.
|
||||
*
|
||||
* @param variant Visual style. See [TangemButton.Variant].
|
||||
* @param size Token-driven size preset controlling height, padding, and icon size.
|
||||
* See [TangemButton.Size].
|
||||
* @param isLoading When `true`, hides the content and shows a centered loader.
|
||||
* @param isEnabled When `false`, the button is dimmed by the variant's disabled alpha and clicks
|
||||
* are ignored.
|
||||
* @param iconStart Optional leading icon.
|
||||
* @param iconEnd Optional trailing icon.
|
||||
* @param text Optional label. `null` switches the button to icon-only mode.
|
||||
* @param contentDescription Accessibility label announced by TalkBack. Should be supplied for
|
||||
* icon-only buttons (e.g. `"Transfers"`), for the loading state to describe the action in
|
||||
* progress (e.g. `"Processing payment"`), and for disabled buttons to explain why they can't be
|
||||
* activated (e.g. `"Pay is disabled, amount is not filled"`). When non-null it overrides the
|
||||
* label text for screen readers.
|
||||
* @param interactionSource Interaction source for press/focus state. A focused state draws the
|
||||
* variant's focus ring around the button.
|
||||
* @param onClick Invoked when the button is clicked.
|
||||
*/
|
||||
@Composable
|
||||
fun TangemButton(
|
||||
modifier: Modifier = Modifier,
|
||||
variant: TangemButton.Variant = TangemButton.Variant.Primary,
|
||||
size: TangemButton.Size = TangemButton.Size.X10,
|
||||
isLoading: Boolean = false,
|
||||
isEnabled: Boolean = true,
|
||||
iconStart: TangemIconUM? = null,
|
||||
iconEnd: TangemIconUM? = null,
|
||||
text: TextReference? = null,
|
||||
contentDescription: String? = null,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
val isIconOnly = text == null
|
||||
val shouldShowLoader = isLoading || iconStart == null && iconEnd == null && text == null
|
||||
val colorTokens = variant.tokens()
|
||||
val sizeTokens = size.tokens()
|
||||
val isFocused by interactionSource.collectIsFocusedAsState()
|
||||
|
||||
// Disabled state fades the content + background + default border by `disabledAlpha`, but the
|
||||
// focus ring stays at full opacity so disabled-but-focused buttons remain clearly highlighted.
|
||||
val contentAlpha = if (isEnabled) 1f else colorTokens.disabledAlpha
|
||||
val backgroundColor = (if (isEnabled) colorTokens.backgroundColor else colorTokens.disabledBackgroundColor)
|
||||
.scaleAlpha(contentAlpha)
|
||||
|
||||
TangemSurface(
|
||||
modifier = modifier
|
||||
.semantics(mergeDescendants = true) {
|
||||
role = Role.Button
|
||||
if (!isEnabled) disabled()
|
||||
contentDescription?.let { this.contentDescription = it }
|
||||
},
|
||||
onClick = onClick,
|
||||
enabled = isEnabled,
|
||||
color = backgroundColor,
|
||||
border = resolveBorder(isFocused = isFocused, colorTokens = colorTokens, contentAlpha = contentAlpha),
|
||||
shape = RoundedCornerShape(TangemTheme.dimens3.borderRadius.full),
|
||||
interactionSource = interactionSource,
|
||||
isMaterial = variant == TangemButton.Variant.Material,
|
||||
) {
|
||||
TangemButtonInternal(
|
||||
modifier = Modifier.alpha(contentAlpha),
|
||||
isIconOnly = isIconOnly,
|
||||
isEnabled = isEnabled,
|
||||
isLoading = shouldShowLoader,
|
||||
iconStart = iconStart,
|
||||
iconEnd = iconEnd,
|
||||
text = text,
|
||||
colorTokens = colorTokens,
|
||||
sizeTokens = sizeTokens,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun resolveBorder(isFocused: Boolean, colorTokens: ColorTokens, contentAlpha: Float): BorderStroke? = when {
|
||||
isFocused -> BorderStroke(
|
||||
width = TangemTheme.dimens3.borderWidth.md,
|
||||
// Focus ring is intentionally NOT scaled by contentAlpha — see TangemButton above.
|
||||
color = colorTokens.focusRingColor,
|
||||
)
|
||||
colorTokens.defaultBorderColor != null -> BorderStroke(
|
||||
width = TangemTheme.dimens3.borderWidth.sm,
|
||||
color = colorTokens.defaultBorderColor.scaleAlpha(contentAlpha),
|
||||
)
|
||||
else -> null
|
||||
}
|
||||
|
||||
/** Multiplies the existing alpha channel by [factor]. */
|
||||
private fun Color.scaleAlpha(factor: Float): Color = if (factor == 1f) this else copy(alpha = alpha * factor)
|
||||
|
||||
object TangemButton {
|
||||
|
||||
/**
|
||||
* Visual style of the button.
|
||||
*
|
||||
* - [Brand] — brand-colored background, static-dark content.
|
||||
* - [Primary] — inverse-surface background, used for the dominant call to action.
|
||||
* - [Secondary] — opaque-surface background, used as a secondary action alongside [Primary].
|
||||
* - [Material] — translucent haze fill (rendered by [TangemSurface] when `isMaterial = true`),
|
||||
* used over content backgrounds.
|
||||
* - [Success] — success-colored background for positive confirmations.
|
||||
* - [Outline] — transparent background with a secondary border.
|
||||
* - [Ghost] — transparent background, no border. Lowest visual weight.
|
||||
*/
|
||||
enum class Variant {
|
||||
Brand,
|
||||
Primary,
|
||||
Secondary,
|
||||
Material,
|
||||
Success,
|
||||
Outline,
|
||||
Ghost,
|
||||
}
|
||||
|
||||
/**
|
||||
* Size preset. Names follow the design-system size scale (X7 = smallest, X14 = largest) and
|
||||
* map to height / padding / icon-size tokens via the internal `tokens()` extension.
|
||||
*/
|
||||
enum class Size {
|
||||
X14,
|
||||
X12,
|
||||
X11,
|
||||
X10,
|
||||
X9,
|
||||
X8,
|
||||
X7,
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(name = "Light", showBackground = true)
|
||||
@Preview(name = "Dark", uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES, showBackground = true)
|
||||
@Composable
|
||||
private fun TangemButtonPreview() {
|
||||
TangemThemePreviewRedesign {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors3.bg.primary)
|
||||
.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(20.dp),
|
||||
) {
|
||||
PreviewSection(label = "Variants (size X10)") {
|
||||
TangemButton.Variant.entries.forEach { variant ->
|
||||
PreviewVariantRow(variant = variant)
|
||||
}
|
||||
}
|
||||
PreviewSection(label = "Sizes (Primary)") {
|
||||
PreviewSizeRow()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PreviewSection(label: String, content: @Composable () -> Unit) {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Text(
|
||||
text = label,
|
||||
color = TangemTheme.colors3.text.secondary,
|
||||
style = TangemTheme.typography3.body.medium,
|
||||
)
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PreviewVariantRow(variant: TangemButton.Variant) {
|
||||
val info = remember { TangemIconUM.Icon(iconRes = R.drawable.ic_information_24) }
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.widthIn(min = 72.dp),
|
||||
text = variant.name,
|
||||
color = TangemTheme.colors3.text.tertiary,
|
||||
style = TangemTheme.typography3.body.medium,
|
||||
)
|
||||
TangemButton(variant = variant, text = stringReference("Label"), onClick = {})
|
||||
TangemButton(variant = variant, text = stringReference("Icons"), iconStart = info, iconEnd = info, onClick = {})
|
||||
TangemButton(variant = variant, text = stringReference("Loading"), isLoading = true, onClick = {})
|
||||
TangemButton(variant = variant, text = stringReference("Disabled"), isEnabled = false, onClick = {})
|
||||
TangemButton(variant = variant, iconStart = info, onClick = {})
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PreviewSizeRow() {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
TangemButton.Size.entries.forEach { size ->
|
||||
TangemButton(size = size, text = stringReference(size.name), onClick = {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,412 @@
|
|||
package com.tangem.core.ui.ds2.button
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.EnterTransition
|
||||
import androidx.compose.animation.ExitTransition
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.animation.expandHorizontally
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.shrinkHorizontally
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.PlatformTextStyle
|
||||
import androidx.compose.ui.text.style.LineHeightStyle
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Density
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.ds.image.TangemIcon
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.ds2.loader.TangemLoader
|
||||
import com.tangem.core.ui.extensions.ColorReference2
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.conditionalCompose
|
||||
import com.tangem.core.ui.extensions.rememberLastNonNull
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
/**
|
||||
* Inner content of [TangemButton]: an icon-text-icon row with a cross-fading loader overlay.
|
||||
*
|
||||
* Designed to be hosted inside a [com.tangem.core.ui.ds2.surface.TangemSurface] which owns sizing,
|
||||
* shape, color, border and click handling. This composable only renders the content.
|
||||
*/
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
internal fun TangemButtonInternal(
|
||||
isIconOnly: Boolean,
|
||||
isEnabled: Boolean,
|
||||
isLoading: Boolean,
|
||||
iconStart: TangemIconUM?,
|
||||
iconEnd: TangemIconUM?,
|
||||
text: TextReference?,
|
||||
colorTokens: ColorTokens,
|
||||
sizeTokens: SizeTokens,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val resolvedIconStart = iconStart?.resolveTint(colorTokens, isEnabled)
|
||||
val resolvedIconEnd = iconEnd?.resolveTint(colorTokens, isEnabled)
|
||||
|
||||
val contentAlpha by animateFloatAsState(if (isLoading) 0f else 1f, label = "contentAlpha")
|
||||
val loaderAlpha by animateFloatAsState(if (isLoading) 1f else 0f, label = "loaderAlpha")
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.conditionalCompose(
|
||||
condition = isIconOnly,
|
||||
otherModifier = {
|
||||
height(sizeTokens.minHeight)
|
||||
.widthIn(min = sizeTokens.minWidth)
|
||||
},
|
||||
modifier = { size(sizeTokens.minSizeIconOnly) },
|
||||
),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
ContentRow(
|
||||
modifier = Modifier
|
||||
.alpha(contentAlpha)
|
||||
.padding(
|
||||
horizontal = sizeTokens.containerHorizontalPadding,
|
||||
vertical = sizeTokens.containerVerticalPadding,
|
||||
),
|
||||
isEnabled = isEnabled,
|
||||
iconStart = resolvedIconStart,
|
||||
iconEnd = resolvedIconEnd,
|
||||
text = text,
|
||||
colorTokens = colorTokens,
|
||||
sizeTokens = sizeTokens,
|
||||
)
|
||||
|
||||
if (loaderAlpha > 0f) {
|
||||
TangemLoader(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.alpha(loaderAlpha),
|
||||
color = if (isEnabled) colorTokens.iconTint else colorTokens.disabledIconTint,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Row of `[iconStart] [text] [iconEnd]` where each slot animates in/out independently.
|
||||
*
|
||||
* Last non-null values are cached so that `AnimatedVisibility` exit transitions still have content
|
||||
* to render once the caller flips a slot back to `null`.
|
||||
*/
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
private fun ContentRow(
|
||||
isEnabled: Boolean,
|
||||
iconStart: TangemIconUM?,
|
||||
iconEnd: TangemIconUM?,
|
||||
text: TextReference?,
|
||||
colorTokens: ColorTokens,
|
||||
sizeTokens: SizeTokens,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val displayedIconStart = rememberLastNonNull(iconStart)
|
||||
val displayedIconEnd = rememberLastNonNull(iconEnd)
|
||||
val displayedText = rememberLastNonNull(text)
|
||||
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
visible = iconStart != null,
|
||||
enter = SlotEnterTransition,
|
||||
exit = SlotExitTransition,
|
||||
) {
|
||||
displayedIconStart?.let { icon ->
|
||||
TangemIcon(
|
||||
modifier = Modifier.size(sizeTokens.iconSize),
|
||||
tangemIconUM = icon,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = text != null,
|
||||
enter = SlotEnterTransition,
|
||||
exit = SlotExitTransition,
|
||||
) {
|
||||
displayedText?.let { textRef ->
|
||||
CompositionLocalProvider(LocalDensity provides cappedFontScaleDensity()) {
|
||||
Text(
|
||||
modifier = Modifier.padding(horizontal = sizeTokens.textPadding),
|
||||
text = textRef.resolveReference(),
|
||||
textAlign = TextAlign.Center,
|
||||
color = if (isEnabled) colorTokens.textColor else colorTokens.disabledTextColor,
|
||||
style = TangemTheme.typography3.body.medium.copy(
|
||||
platformStyle = PlatformTextStyle(includeFontPadding = false),
|
||||
lineHeightStyle = LineHeightStyle(
|
||||
alignment = LineHeightStyle.Alignment.Center,
|
||||
trim = LineHeightStyle.Trim.Both,
|
||||
),
|
||||
),
|
||||
maxLines = 1,
|
||||
softWrap = false,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = iconEnd != null,
|
||||
enter = SlotEnterTransition,
|
||||
exit = SlotExitTransition,
|
||||
) {
|
||||
displayedIconEnd?.let { icon ->
|
||||
TangemIcon(
|
||||
modifier = Modifier.size(sizeTokens.iconSize),
|
||||
tangemIconUM = icon,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a [Density] derived from [LocalDensity] with [Density.fontScale] capped at
|
||||
* [MAX_BUTTON_FONT_SCALE]. The button's height is fixed by design tokens, so unbounded user font
|
||||
* scales would clip the label vertically; capping the scale keeps the text visible while still
|
||||
* honoring user preferences up to a point. When the user's scale is already within the cap, the
|
||||
* current [LocalDensity] is returned unchanged.
|
||||
*/
|
||||
@Composable
|
||||
private fun cappedFontScaleDensity(): Density {
|
||||
val baseDensity = LocalDensity.current
|
||||
return remember(baseDensity.density, baseDensity.fontScale) {
|
||||
if (baseDensity.fontScale <= MAX_BUTTON_FONT_SCALE) {
|
||||
baseDensity
|
||||
} else {
|
||||
Density(density = baseDensity.density, fontScale = MAX_BUTTON_FONT_SCALE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val MAX_BUTTON_FONT_SCALE = 1.3f
|
||||
|
||||
// Shared, snappy specs so size and alpha animations stay in sync across the three slots.
|
||||
private val SlotSizeSpec = spring<IntSize>(stiffness = Spring.StiffnessMediumLow)
|
||||
private val SlotAlphaSpec = spring<Float>(stiffness = Spring.StiffnessMediumLow)
|
||||
private val SlotEnterTransition: EnterTransition =
|
||||
fadeIn(animationSpec = SlotAlphaSpec) + expandHorizontally(animationSpec = SlotSizeSpec)
|
||||
private val SlotExitTransition: ExitTransition =
|
||||
fadeOut(animationSpec = SlotAlphaSpec) + shrinkHorizontally(animationSpec = SlotSizeSpec)
|
||||
|
||||
/**
|
||||
* Forces the variant's icon color (or its disabled variant when [isEnabled] is `false`) onto
|
||||
* [TangemIconUM.Icon] — the button's variant always drives icon color, so any caller-supplied
|
||||
* tint is overridden. Other icon types pass through unchanged.
|
||||
*
|
||||
* Note: we cannot honor a caller-supplied tint conditionally, because [TangemIconUM.Icon]'s
|
||||
* convenience constructor defaults `tint` to a non-null `ColorReference2`, making "no tint
|
||||
* supplied" indistinguishable from "tint explicitly set" at the call site.
|
||||
*/
|
||||
@Composable
|
||||
private fun TangemIconUM.resolveTint(colorTokens: ColorTokens, isEnabled: Boolean): TangemIconUM {
|
||||
return when (this) {
|
||||
is TangemIconUM.Icon -> copy(
|
||||
tint = ColorReference2 {
|
||||
if (isEnabled) colorTokens.iconTint else colorTokens.disabledIconTint
|
||||
},
|
||||
)
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
/** Resolved per-variant colors used by [TangemButton]. */
|
||||
internal data class ColorTokens(
|
||||
val backgroundColor: Color,
|
||||
val textColor: Color,
|
||||
val iconTint: Color,
|
||||
val disabledBackgroundColor: Color,
|
||||
val disabledTextColor: Color,
|
||||
val disabledIconTint: Color,
|
||||
val focusRingColor: Color,
|
||||
val disabledAlpha: Float = 1f,
|
||||
val defaultBorderColor: Color? = null,
|
||||
)
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
internal fun TangemButton.Variant.tokens(): ColorTokens {
|
||||
return when (this) {
|
||||
TangemButton.Variant.Brand -> ColorTokens(
|
||||
backgroundColor = TangemTheme.colors3.bg.brand,
|
||||
textColor = TangemTheme.colors3.text.staticDark.primary,
|
||||
iconTint = TangemTheme.colors3.icon.staticDark,
|
||||
disabledBackgroundColor = TangemTheme.colors3.bg.disabled,
|
||||
disabledTextColor = TangemTheme.colors3.text.tertiary,
|
||||
disabledIconTint = TangemTheme.colors3.icon.tertiary,
|
||||
focusRingColor = TangemTheme.colors3.interaction.focusRing.default,
|
||||
)
|
||||
TangemButton.Variant.Primary -> ColorTokens(
|
||||
backgroundColor = TangemTheme.colors3.bg.inverse,
|
||||
textColor = TangemTheme.colors3.text.inverse.primary,
|
||||
iconTint = TangemTheme.colors3.icon.inverse,
|
||||
disabledBackgroundColor = TangemTheme.colors3.bg.disabled,
|
||||
disabledTextColor = TangemTheme.colors3.text.tertiary,
|
||||
disabledIconTint = TangemTheme.colors3.icon.tertiary,
|
||||
focusRingColor = TangemTheme.colors3.interaction.focusRing.brand,
|
||||
)
|
||||
TangemButton.Variant.Secondary -> ColorTokens(
|
||||
backgroundColor = TangemTheme.colors3.bg.opaque.primary,
|
||||
textColor = TangemTheme.colors3.text.primary,
|
||||
iconTint = TangemTheme.colors3.icon.primary,
|
||||
disabledBackgroundColor = TangemTheme.colors3.bg.opaque.primary,
|
||||
disabledTextColor = TangemTheme.colors3.text.primary,
|
||||
disabledIconTint = TangemTheme.colors3.icon.primary,
|
||||
focusRingColor = TangemTheme.colors3.interaction.focusRing.brand,
|
||||
disabledAlpha = TangemTheme.dimens3.opacity.disabled,
|
||||
)
|
||||
TangemButton.Variant.Material -> ColorTokens(
|
||||
// Background is the haze fill (FILL/MATERIAL) rendered by TangemSurface when isMaterial = true;
|
||||
// this slot is unused in that path.
|
||||
backgroundColor = Color.Transparent,
|
||||
textColor = TangemTheme.colors3.text.primary,
|
||||
iconTint = TangemTheme.colors3.icon.primary,
|
||||
disabledBackgroundColor = Color.Transparent,
|
||||
disabledTextColor = TangemTheme.colors3.text.tertiary,
|
||||
disabledIconTint = TangemTheme.colors3.icon.tertiary,
|
||||
focusRingColor = TangemTheme.colors3.interaction.focusRing.brand,
|
||||
)
|
||||
TangemButton.Variant.Success -> ColorTokens(
|
||||
backgroundColor = TangemTheme.colors3.bg.status.success,
|
||||
textColor = TangemTheme.colors3.text.staticDark.primary,
|
||||
iconTint = TangemTheme.colors3.icon.staticDark,
|
||||
disabledBackgroundColor = TangemTheme.colors3.bg.status.success,
|
||||
disabledTextColor = TangemTheme.colors3.text.staticDark.primary,
|
||||
disabledIconTint = TangemTheme.colors3.icon.staticDark,
|
||||
focusRingColor = TangemTheme.colors3.interaction.focusRing.default,
|
||||
disabledAlpha = TangemTheme.dimens3.opacity.disabled,
|
||||
)
|
||||
TangemButton.Variant.Outline -> ColorTokens(
|
||||
backgroundColor = Color.Transparent,
|
||||
textColor = TangemTheme.colors3.text.primary,
|
||||
iconTint = TangemTheme.colors3.icon.primary,
|
||||
disabledBackgroundColor = Color.Transparent,
|
||||
disabledTextColor = TangemTheme.colors3.text.primary,
|
||||
disabledIconTint = TangemTheme.colors3.icon.primary,
|
||||
focusRingColor = TangemTheme.colors3.interaction.focusRing.brand,
|
||||
disabledAlpha = TangemTheme.dimens3.opacity.disabled,
|
||||
defaultBorderColor = TangemTheme.colors3.border.secondary,
|
||||
)
|
||||
TangemButton.Variant.Ghost -> ColorTokens(
|
||||
backgroundColor = Color.Transparent,
|
||||
textColor = TangemTheme.colors3.text.primary,
|
||||
iconTint = TangemTheme.colors3.icon.primary,
|
||||
disabledBackgroundColor = Color.Transparent,
|
||||
disabledTextColor = TangemTheme.colors3.text.primary,
|
||||
disabledIconTint = TangemTheme.colors3.icon.primary,
|
||||
focusRingColor = TangemTheme.colors3.interaction.focusRing.brand,
|
||||
disabledAlpha = TangemTheme.dimens3.opacity.disabled,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Resolved per-size dimensions used by [TangemButton]. */
|
||||
internal data class SizeTokens(
|
||||
val minHeight: Dp,
|
||||
val minWidth: Dp,
|
||||
val minSizeIconOnly: Dp,
|
||||
val textPadding: Dp,
|
||||
val containerHorizontalPadding: Dp,
|
||||
val containerVerticalPadding: Dp,
|
||||
val iconSize: Dp,
|
||||
)
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
internal fun TangemButton.Size.tokens(): SizeTokens {
|
||||
val dimens = TangemTheme.dimens3
|
||||
return when (this) {
|
||||
TangemButton.Size.X14 -> SizeTokens(
|
||||
minHeight = dimens.size.s700,
|
||||
minWidth = dimens.size.s1100,
|
||||
minSizeIconOnly = dimens.size.s700,
|
||||
textPadding = dimens.spacing.s100,
|
||||
containerHorizontalPadding = dimens.spacing.s200,
|
||||
containerVerticalPadding = dimens.spacing.s200,
|
||||
iconSize = 24.dp,
|
||||
)
|
||||
TangemButton.Size.X12 -> SizeTokens(
|
||||
minHeight = dimens.size.s600,
|
||||
minWidth = dimens.size.s1000,
|
||||
minSizeIconOnly = dimens.size.s600,
|
||||
textPadding = dimens.spacing.s100,
|
||||
containerHorizontalPadding = dimens.spacing.s150,
|
||||
containerVerticalPadding = dimens.spacing.s150,
|
||||
iconSize = 24.dp,
|
||||
)
|
||||
TangemButton.Size.X11 -> SizeTokens(
|
||||
minHeight = dimens.size.s550,
|
||||
minWidth = dimens.size.s900,
|
||||
minSizeIconOnly = dimens.size.s550,
|
||||
textPadding = dimens.spacing.s075,
|
||||
containerHorizontalPadding = dimens.spacing.s150,
|
||||
containerVerticalPadding = dimens.spacing.s150,
|
||||
iconSize = 20.dp,
|
||||
)
|
||||
TangemButton.Size.X10 -> SizeTokens(
|
||||
minHeight = dimens.size.s500,
|
||||
minWidth = dimens.size.s800,
|
||||
minSizeIconOnly = dimens.size.s500,
|
||||
textPadding = dimens.spacing.s075,
|
||||
containerHorizontalPadding = dimens.spacing.s125,
|
||||
containerVerticalPadding = dimens.spacing.s125,
|
||||
iconSize = 20.dp,
|
||||
)
|
||||
TangemButton.Size.X9 -> SizeTokens(
|
||||
minHeight = dimens.size.s450,
|
||||
minWidth = dimens.size.s700,
|
||||
minSizeIconOnly = dimens.size.s450,
|
||||
textPadding = dimens.spacing.s075,
|
||||
containerHorizontalPadding = dimens.spacing.s100,
|
||||
containerVerticalPadding = dimens.spacing.s100,
|
||||
iconSize = 20.dp,
|
||||
)
|
||||
TangemButton.Size.X8 -> SizeTokens(
|
||||
minHeight = dimens.size.s400,
|
||||
minWidth = dimens.size.s600,
|
||||
minSizeIconOnly = dimens.size.s400,
|
||||
textPadding = dimens.spacing.s075,
|
||||
containerHorizontalPadding = dimens.spacing.s075,
|
||||
containerVerticalPadding = dimens.spacing.s075,
|
||||
iconSize = 20.dp,
|
||||
)
|
||||
TangemButton.Size.X7 -> SizeTokens(
|
||||
minHeight = dimens.size.s350,
|
||||
minWidth = dimens.size.s500,
|
||||
minSizeIconOnly = dimens.size.s350,
|
||||
textPadding = dimens.spacing.s075,
|
||||
containerHorizontalPadding = dimens.spacing.s075,
|
||||
containerVerticalPadding = dimens.spacing.s050,
|
||||
iconSize = 16.dp,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
package com.tangem.core.ui.ds2.loader
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.core.*
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.progressSemantics
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.core.ui.res.generated.icons.*
|
||||
|
||||
/**
|
||||
* Loader DS component.
|
||||
*
|
||||
* Indeterminate circular spinner that rotates continuously to indicate ongoing work.
|
||||
*
|
||||
* Version: 1.0
|
||||
*
|
||||
* [Figma](https://www.figma.com/design/AsnJ5CPHib4Qxw12gszjMS/%F0%9F%92%A0-DS-Components?node-id=25-5688&m=device-tdp-1&t=9n7s8Xo2l3mLh5j-4)
|
||||
*
|
||||
* @param modifier modifier applied to the loader's root.
|
||||
* @param color tint applied to the spinner asset. Defaults to the primary icon color from the
|
||||
* current theme.
|
||||
* @param size visual size of the spinner; selects both the icon dimensions and the matching
|
||||
* pre-rendered spinner asset. Defaults to [TangemLoaderSize.X24].
|
||||
*/
|
||||
@Composable
|
||||
fun TangemLoader(
|
||||
modifier: Modifier = Modifier,
|
||||
color: Color = TangemTheme.colors3.icon.primary,
|
||||
size: TangemLoaderSize = TangemLoaderSize.X24,
|
||||
) {
|
||||
val transition = rememberInfiniteTransition(label = "TangemLoaderRotation")
|
||||
val rotation by transition.animateFloat(
|
||||
initialValue = 0f,
|
||||
targetValue = 360f,
|
||||
animationSpec = infiniteRepeatable(
|
||||
animation = tween(durationMillis = 800, easing = LinearEasing),
|
||||
repeatMode = RepeatMode.Restart,
|
||||
),
|
||||
label = "TangemLoaderRotationAngle",
|
||||
)
|
||||
|
||||
Icon(
|
||||
modifier = modifier
|
||||
.progressSemantics()
|
||||
.size(size.sizeDp)
|
||||
.graphicsLayer { rotationZ = rotation },
|
||||
imageVector = size.imageVector,
|
||||
tint = color,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Size variants for [TangemLoader]. Each entry pairs a fixed pixel size with a
|
||||
* pre-rendered spinner asset of the matching dimensions.
|
||||
*
|
||||
* @property sizeDp side length applied to the loader via `Modifier.size(...)`.
|
||||
* @property imageVector pre-rendered spinner asset matching [sizeDp]; rotated at runtime to animate.
|
||||
*/
|
||||
enum class TangemLoaderSize(
|
||||
internal val sizeDp: Dp,
|
||||
internal val imageVector: ImageVector,
|
||||
) {
|
||||
X12(sizeDp = 12.dp, imageVector = Icons.ic_loading_spinner_12),
|
||||
X16(sizeDp = 16.dp, imageVector = Icons.ic_loading_spinner_16),
|
||||
X20(sizeDp = 20.dp, imageVector = Icons.ic_loading_spinner_20),
|
||||
X24(sizeDp = 24.dp, imageVector = Icons.ic_loading_spinner_24),
|
||||
X28(sizeDp = 28.dp, imageVector = Icons.ic_loading_spinner_28),
|
||||
X32(sizeDp = 32.dp, imageVector = Icons.ic_loading_spinner_32),
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun TangemLoader_Preview() {
|
||||
TangemThemePreviewRedesign {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors3.bg.secondary)
|
||||
.padding(12.dp),
|
||||
) {
|
||||
TangemLoaderSize.entries.forEach { size ->
|
||||
TangemLoader(size = size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
package com.tangem.core.ui.ds2.surface
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.LocalIndication
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.ripple.RippleAlpha
|
||||
import androidx.compose.material3.LocalRippleConfiguration
|
||||
import androidx.compose.material3.RippleConfiguration
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.NonRestartableComposable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.unit.DpOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.haze.hazeEffectTangem
|
||||
import com.tangem.core.ui.extensions.conditionalCompose
|
||||
import com.tangem.core.ui.extensions.softLayerShadow
|
||||
import com.tangem.core.ui.res.LocalHazeState
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import dev.chrisbanes.haze.HazeStyle
|
||||
import dev.chrisbanes.haze.HazeTint
|
||||
|
||||
/**
|
||||
* Design-system v2 surface: a clipped, optionally-bordered, optionally-clickable container that
|
||||
* renders either as a flat colored surface or as a translucent "material" surface backed by a
|
||||
* haze blur effect.
|
||||
*
|
||||
* Rendering modes:
|
||||
* - **Flat** (`isMaterial = false`, default): a solid [color] background clipped to [shape].
|
||||
* - **Material** (`isMaterial = true`): the [color] parameter is ignored. The surface adds a soft
|
||||
* drop shadow and a gradient stroke (`material.border`), then renders a haze-blurred backdrop
|
||||
* tinted with `material.fill.blur`. When `LocalHazeState.blurEnabled` is `false` (e.g.
|
||||
* previews, low-end devices), the surface falls back to opaque `material.fill.solid` overlaid
|
||||
* with translucent `material.tint.solid` so both layers remain visible.
|
||||
*
|
||||
* Interaction:
|
||||
* - When [onClick] is non-null the surface is clickable. The v2 ripple configuration is provided
|
||||
* via [LocalRippleConfiguration] for the [content] subtree as well.
|
||||
* - [enabled] only gates the click handler — disabled surfaces don't change appearance here;
|
||||
* callers are expected to handle visual disabled state themselves (e.g. via alpha).
|
||||
*
|
||||
* @param color Background color used in flat mode. Ignored when [isMaterial] is `true`.
|
||||
* @param isMaterial Switches to the haze-based translucent rendering.
|
||||
* @param border Optional outer stroke. Drawn underneath the material gradient stroke when both
|
||||
* are present.
|
||||
* @param shape Shape used for clipping, background, and borders.
|
||||
* @param onClick Click handler. `null` makes the surface non-interactive.
|
||||
* @param enabled Forwarded to the click handler.
|
||||
|
||||
* @param content Content rendered inside the clipped surface.
|
||||
*/
|
||||
@Suppress("UnsafeCallOnNullableType", "")
|
||||
@Composable
|
||||
@NonRestartableComposable
|
||||
fun TangemSurface(
|
||||
modifier: Modifier = Modifier,
|
||||
color: Color = TangemTheme.colors3.bg.primary,
|
||||
isMaterial: Boolean = false,
|
||||
border: BorderStroke? = null,
|
||||
shape: Shape = RoundedCornerShape(TangemTheme.dimens3.borderRadius.b200),
|
||||
onClick: (() -> Unit)? = null,
|
||||
enabled: Boolean = true,
|
||||
interactionSource: MutableInteractionSource? = null,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
val resolvedInteractionSource = interactionSource ?: remember { MutableInteractionSource() }
|
||||
|
||||
val surface: @Composable () -> Unit = {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.conditionalCompose(isMaterial) { materialShadow(shape) }
|
||||
.conditionalCompose(border != null) { border(border!!, shape) }
|
||||
.conditionalCompose(isMaterial) { materialBorder(shape) }
|
||||
.clip(shape)
|
||||
.background(if (isMaterial) Color.Transparent else color, shape)
|
||||
.conditionalCompose(isMaterial) { materialFill() }
|
||||
.conditionalCompose(onClick != null) {
|
||||
clickable(
|
||||
interactionSource = resolvedInteractionSource,
|
||||
indication = LocalIndication.current,
|
||||
enabled = enabled,
|
||||
onClick = onClick!!,
|
||||
)
|
||||
},
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
if (onClick != null) {
|
||||
CompositionLocalProvider(LocalRippleConfiguration provides tangemSurfaceRipple()) {
|
||||
surface()
|
||||
}
|
||||
} else {
|
||||
surface()
|
||||
}
|
||||
}
|
||||
|
||||
// region material rendering
|
||||
|
||||
/** Drop shadow for the material variant. */
|
||||
@Composable
|
||||
private fun Modifier.materialShadow(shape: Shape): Modifier = softLayerShadow(
|
||||
radius = 40.dp,
|
||||
color = Color.Black.copy(alpha = 0.10f),
|
||||
shape = shape,
|
||||
spread = 0.dp,
|
||||
offset = DpOffset(x = 0.dp, y = 8.dp),
|
||||
)
|
||||
|
||||
/** Diagonal gradient stroke that wraps the material variant. */
|
||||
@Composable
|
||||
private fun Modifier.materialBorder(shape: Shape): Modifier = border(
|
||||
width = TangemTheme.dimens3.borderWidth.sm,
|
||||
brush = materialBorderBrush(),
|
||||
shape = shape,
|
||||
)
|
||||
|
||||
/**
|
||||
* Translucent fill for the material variant.
|
||||
*
|
||||
* When the haze state is enabled, paints a haze-blurred backdrop. When disabled, layers two
|
||||
* solid colors so the result still reads as "tinted fill" instead of going transparent.
|
||||
*/
|
||||
@Composable
|
||||
private fun Modifier.materialFill(): Modifier {
|
||||
val hazed = hazeEffectTangem(
|
||||
style = HazeStyle(
|
||||
backgroundColor = TangemTheme.colors3.material.fill.blur,
|
||||
blurRadius = TangemTheme.dimens3.blur.Button,
|
||||
tints = emptyList(),
|
||||
),
|
||||
) {
|
||||
fallbackTint = HazeTint(Color.Transparent)
|
||||
}
|
||||
return hazed.conditionalCompose(!LocalHazeState.current.blurEnabled) {
|
||||
// Paint the opaque fill first, then layer the translucent tint on top so both are visible.
|
||||
background(TangemTheme.colors3.material.fill.solid)
|
||||
.background(TangemTheme.colors3.material.tint.solid)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
private fun materialBorderBrush(): Brush {
|
||||
val border = TangemTheme.colors3.material.border
|
||||
return Brush.linearGradient(
|
||||
0f to border.start,
|
||||
0.5f to border.mid,
|
||||
1f to border.end,
|
||||
start = Offset.Zero,
|
||||
end = Offset.Infinite,
|
||||
)
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
private fun tangemSurfaceRipple(): RippleConfiguration = RippleConfiguration(
|
||||
color = TangemTheme.colors3.interaction.press.default,
|
||||
rippleAlpha = RippleAlpha(
|
||||
draggedAlpha = 0f,
|
||||
focusedAlpha = 0f,
|
||||
hoveredAlpha = 0.05f,
|
||||
pressedAlpha = 0.1f,
|
||||
),
|
||||
)
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.core.ui.extensions
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
|
|
@ -27,4 +29,35 @@ fun rememberHapticFeedback(
|
|||
onAction.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns [value] when it is non-null, otherwise the most recent non-null value seen at this call
|
||||
* site. The cached value is updated in a [SideEffect] so this function never writes to a snapshot
|
||||
* state during composition.
|
||||
*
|
||||
* Typical use case: pairing transient nullable inputs with `AnimatedVisibility` (or any other
|
||||
* exit-animating wrapper). When the caller flips the input back to `null` to trigger an exit
|
||||
* transition, the last non-null value is still available for the wrapped content to render until
|
||||
* the transition finishes — without it, the content would disappear instantly and the exit
|
||||
* animation would have nothing to animate.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* val displayedIcon = rememberLastNonNull(iconStart)
|
||||
* AnimatedVisibility(visible = iconStart != null) {
|
||||
* displayedIcon?.let { TangemIcon(it) }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Note: the cache is per call site, so calling this multiple times in the same composable yields
|
||||
* independent caches.
|
||||
*/
|
||||
@Composable
|
||||
fun <T : Any> rememberLastNonNull(value: T?): T? {
|
||||
val cache = remember { mutableStateOf(value) }
|
||||
SideEffect {
|
||||
if (value != null && cache.value !== value) cache.value = value
|
||||
}
|
||||
return value ?: cache.value
|
||||
}
|
||||
|
|
@ -472,6 +472,8 @@ val LocalMessageEffectAnimation = compositionLocalOf<MessageEffectAnimation> {
|
|||
error("No MessageEffectAnimation provided")
|
||||
}
|
||||
|
||||
val LocalCanScrollBackward = compositionLocalOf { false }
|
||||
|
||||
/**
|
||||
* Determines whether the dark theme should be used based on the given [AppThemeMode].
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
84387e888f54e5056380c38e077962bdfa4a32cfca194d822c13aa7e35661968
|
||||
2eb71d4ac556a6608e34adac157e599b5250677fe1b1727363fcb82218320be1
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
c1f3db82744567cdd0c59a29761e1b3b4bd4bb81acce832fb0391c7ab24be491
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_arrow_down_12: ImageVector? = null
|
||||
|
||||
val Icons.ic_arrow_down_12: ImageVector
|
||||
get() {
|
||||
if (_ic_arrow_down_12 != null) return _ic_arrow_down_12!!
|
||||
_ic_arrow_down_12 = ImageVector.Builder(
|
||||
name = "ic_arrow_down_12",
|
||||
defaultWidth = 12.dp,
|
||||
defaultHeight = 12.dp,
|
||||
viewportWidth = 12f,
|
||||
viewportHeight = 12f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M5.5 2L5.5 9.04297L2.35352 5.89648C2.15825 5.70122 1.84175 5.70122 1.64649 5.89648C1.45122 6.09175 1.45122 6.40825 1.64649 6.60352L5.64648 10.6035L5.72266 10.666C5.80419 10.7204 5.90056 10.75 6 10.75C6.13261 10.75 6.25975 10.6973 6.35352 10.6035L10.3535 6.60352C10.5488 6.40826 10.5488 6.09175 10.3535 5.89649C10.1583 5.70122 9.84175 5.70122 9.64649 5.89649L6.5 9.04297L6.5 2C6.5 1.72386 6.27614 1.5 6 1.5C5.72386 1.5 5.5 1.72386 5.5 2Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_arrow_down_12!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcArrowDown12Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_arrow_down_12,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_arrow_down_16: ImageVector? = null
|
||||
|
||||
val Icons.ic_arrow_down_16: ImageVector
|
||||
get() {
|
||||
if (_ic_arrow_down_16 != null) return _ic_arrow_down_16!!
|
||||
_ic_arrow_down_16 = ImageVector.Builder(
|
||||
name = "ic_arrow_down_16",
|
||||
defaultWidth = 16.dp,
|
||||
defaultHeight = 16.dp,
|
||||
viewportWidth = 16f,
|
||||
viewportHeight = 16f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M7.4997 2.66669L7.4997 12.4597L3.02021 7.98016C2.82494 7.7849 2.50844 7.7849 2.31318 7.98016C2.11808 8.17544 2.11797 8.49199 2.31318 8.68719L7.64618 14.0202C7.73987 14.1139 7.86721 14.1666 7.9997 14.1667C8.13223 14.1667 8.25946 14.1139 8.35321 14.0202L13.6872 8.6872C13.8824 8.49204 13.8821 8.17545 13.6872 7.98017C13.4919 7.7849 13.1754 7.7849 12.9802 7.98017L8.4997 12.4606L8.4997 2.66669C8.4997 2.39055 8.27584 2.16669 7.9997 2.16669C7.72371 2.16686 7.4997 2.39065 7.4997 2.66669Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_arrow_down_16!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcArrowDown16Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_arrow_down_16,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_arrow_down_20: ImageVector? = null
|
||||
|
||||
val Icons.ic_arrow_down_20: ImageVector
|
||||
get() {
|
||||
if (_ic_arrow_down_20 != null) return _ic_arrow_down_20!!
|
||||
_ic_arrow_down_20 = ImageVector.Builder(
|
||||
name = "ic_arrow_down_20",
|
||||
defaultWidth = 20.dp,
|
||||
defaultHeight = 20.dp,
|
||||
viewportWidth = 20f,
|
||||
viewportHeight = 20f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M9.25031 3.33331L9.2503 15.2728L3.86359 9.88605C3.57073 9.59337 3.09589 9.59337 2.80304 9.88605C2.5102 10.1789 2.51031 10.6537 2.80304 10.9466L9.47003 17.6136L9.58429 17.7073C9.70654 17.7888 9.85124 17.8333 10.0003 17.8333C10.1991 17.8332 10.39 17.7542 10.5306 17.6136L17.1966 10.9466C17.4895 10.6537 17.4895 10.1789 17.1966 9.88605C16.9037 9.59348 16.4288 9.59326 16.136 9.88605L10.7503 15.2728L10.7503 3.33331C10.7503 2.91921 10.4144 2.58349 10.0003 2.58331C9.58609 2.58331 9.25031 2.9191 9.25031 3.33331Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_arrow_down_20!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcArrowDown20Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_arrow_down_20,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_arrow_down_24: ImageVector? = null
|
||||
|
||||
val Icons.ic_arrow_down_24: ImageVector
|
||||
get() {
|
||||
if (_ic_arrow_down_24 != null) return _ic_arrow_down_24!!
|
||||
_ic_arrow_down_24 = ImageVector.Builder(
|
||||
name = "ic_arrow_down_24",
|
||||
defaultWidth = 24.dp,
|
||||
defaultHeight = 24.dp,
|
||||
viewportWidth = 24f,
|
||||
viewportHeight = 24f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M11 4L11 18.0859L4.70703 11.793C4.31651 11.4024 3.6835 11.4024 3.29297 11.793C2.90245 12.1835 2.90245 12.8165 3.29297 13.207L11.293 21.207L11.3662 21.2734C11.5442 21.4193 11.7679 21.5 12 21.5C12.2652 21.5 12.5195 21.3946 12.707 21.207L20.707 13.207C21.0976 12.8165 21.0976 12.1835 20.707 11.793C20.3165 11.4024 19.6835 11.4024 19.293 11.793L13 18.0859L13 4C13 3.44772 12.5523 3 12 3C11.4477 3 11 3.44772 11 4Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_arrow_down_24!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcArrowDown24Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_arrow_down_24,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_arrow_down_28: ImageVector? = null
|
||||
|
||||
val Icons.ic_arrow_down_28: ImageVector
|
||||
get() {
|
||||
if (_ic_arrow_down_28 != null) return _ic_arrow_down_28!!
|
||||
_ic_arrow_down_28 = ImageVector.Builder(
|
||||
name = "ic_arrow_down_28",
|
||||
defaultWidth = 28.dp,
|
||||
defaultHeight = 28.dp,
|
||||
viewportWidth = 28f,
|
||||
viewportHeight = 28f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M12.7496 4.66669L12.7496 20.8991L5.55042 13.6999C5.06226 13.2117 4.27099 13.2117 3.78284 13.6999C3.29485 14.1881 3.29474 14.9794 3.78284 15.4675L13.1158 24.8005C13.3502 25.0348 13.6682 25.1666 13.9996 25.1667C14.3311 25.1667 14.649 25.0348 14.8834 24.8005L24.2174 15.4675C24.7055 14.9794 24.7052 14.1881 24.2174 13.6999C23.7293 13.2117 22.938 13.2117 22.4498 13.6999L15.2496 20.9001L15.2496 4.66669C15.2496 3.97633 14.69 3.41669 13.9996 3.41669C13.3094 3.41686 12.7496 3.97644 12.7496 4.66669Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_arrow_down_28!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcArrowDown28Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_arrow_down_28,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_arrow_down_32: ImageVector? = null
|
||||
|
||||
val Icons.ic_arrow_down_32: ImageVector
|
||||
get() {
|
||||
if (_ic_arrow_down_32 != null) return _ic_arrow_down_32!!
|
||||
_ic_arrow_down_32 = ImageVector.Builder(
|
||||
name = "ic_arrow_down_32",
|
||||
defaultWidth = 32.dp,
|
||||
defaultHeight = 32.dp,
|
||||
viewportWidth = 32f,
|
||||
viewportHeight = 32f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M14.5003 5.33331L14.5003 23.7122L6.39387 15.6058C5.80812 15.0202 4.85852 15.0202 4.27277 15.6058C3.68704 16.1915 3.68715 17.1411 4.27277 17.7269L14.9398 28.3939L15.0491 28.4935C15.3161 28.7123 15.6521 28.8333 16.0003 28.8333C16.398 28.8332 16.7796 28.6751 17.0609 28.3939L27.7269 17.7269C28.3127 17.1411 28.3127 16.1916 27.7269 15.6058C27.1411 15.0203 26.1915 15.0201 25.6058 15.6058L17.5003 23.7122L17.5003 5.33332C17.5003 4.505 16.8286 3.83349 16.0003 3.83332C15.1719 3.83331 14.5003 4.50489 14.5003 5.33331Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_arrow_down_32!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcArrowDown32Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_arrow_down_32,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_arrow_swap_horizontal_12: ImageVector? = null
|
||||
|
||||
val Icons.ic_arrow_swap_horizontal_12: ImageVector
|
||||
get() {
|
||||
if (_ic_arrow_swap_horizontal_12 != null) return _ic_arrow_swap_horizontal_12!!
|
||||
_ic_arrow_swap_horizontal_12 = ImageVector.Builder(
|
||||
name = "ic_arrow_swap_horizontal_12",
|
||||
defaultWidth = 12.dp,
|
||||
defaultHeight = 12.dp,
|
||||
viewportWidth = 12f,
|
||||
viewportHeight = 12f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M10.5 5.5C10.7761 5.5 11 5.72386 11 6C10.9999 8.18874 9.37753 9.75 7.25 9.75H2.61035C2.70332 9.82714 2.78927 9.90003 2.8623 9.95703C2.91927 10.0015 2.98043 10.0639 3.0459 10.0967C3.2682 10.2604 3.31608 10.5745 3.15234 10.7969C3.00907 10.991 2.7519 11.0514 2.54102 10.9541L2.45312 10.9023L2.39453 10.8584C2.28672 10.777 2.04429 10.5908 1.79688 10.376C1.63446 10.235 1.45893 10.0719 1.32031 9.91504C1.25161 9.83725 1.18177 9.74877 1.12598 9.65625C1.07837 9.57728 1.00003 9.43037 1 9.25C1.00001 8.78513 1.48359 8.39606 1.79688 8.12402C2.04428 7.90921 2.28669 7.72306 2.39453 7.6416L2.45312 7.59765C2.67535 7.43398 2.98852 7.48108 3.15234 7.70312C3.31603 7.92547 3.26822 8.23958 3.0459 8.40332C2.98043 8.43605 2.91927 8.49851 2.8623 8.54297C2.78925 8.59998 2.70334 8.67284 2.61035 8.75H7.25C8.83566 8.75 9.99994 7.6261 10 6C10 5.72386 10.2239 5.5 10.5 5.5Z"),
|
||||
)
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M8.84766 1.20312C9.01149 0.981078 9.32465 0.933983 9.54688 1.09765L9.60547 1.1416C9.71331 1.22306 9.95572 1.40921 10.2031 1.62402C10.3655 1.76505 10.5411 1.92809 10.6797 2.08496C10.7484 2.16275 10.8182 2.25123 10.874 2.34375C10.9216 2.42275 11 2.56965 11 2.75C10.9999 3.2149 10.5165 3.6039 10.2031 3.87597C9.95571 4.09078 9.71328 4.27696 9.60547 4.3584L9.54688 4.40234C9.32468 4.56593 9.01149 4.51882 8.84766 4.29687C8.68392 4.07454 8.7318 3.76044 8.9541 3.59668C9.01957 3.56394 9.08073 3.50148 9.1377 3.45703C9.21073 3.40003 9.29668 3.32714 9.38965 3.25H4.75C3.1643 3.25 2 4.37383 2 6C1.99993 6.27608 1.7761 6.5 1.5 6.5C1.2239 6.5 1.00007 6.27608 1 6C1 3.8112 2.62242 2.25 4.75 2.25H9.38965C9.29666 2.17284 9.21075 2.09998 9.1377 2.04297C9.08073 1.99851 9.01957 1.93605 8.9541 1.90332C8.73178 1.73958 8.68397 1.42547 8.84766 1.20312Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_arrow_swap_horizontal_12!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcArrowSwapHorizontal12Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_arrow_swap_horizontal_12,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_arrow_swap_horizontal_16: ImageVector? = null
|
||||
|
||||
val Icons.ic_arrow_swap_horizontal_16: ImageVector
|
||||
get() {
|
||||
if (_ic_arrow_swap_horizontal_16 != null) return _ic_arrow_swap_horizontal_16!!
|
||||
_ic_arrow_swap_horizontal_16 = ImageVector.Builder(
|
||||
name = "ic_arrow_swap_horizontal_16",
|
||||
defaultWidth = 16.dp,
|
||||
defaultHeight = 16.dp,
|
||||
viewportWidth = 16f,
|
||||
viewportHeight = 16f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M14.5038 7.50422C14.7798 7.50444 15.0038 7.72822 15.0038 8.00422C15.0037 11.0405 12.7618 13.1984 9.80948 13.1986H2.51163C2.58365 13.2652 2.658 13.3346 2.73526 13.4017C3.01657 13.6459 3.3084 13.8774 3.60635 14.1009C3.82835 14.2646 3.87617 14.5779 3.7128 14.8001C3.5517 15.0188 3.22177 15.0713 3.00772 14.9017C2.68924 14.6658 2.37925 14.4174 2.07999 14.1575C1.84813 13.9562 1.60275 13.7279 1.41202 13.512C1.31737 13.4049 1.22518 13.2888 1.15421 13.1712C1.10709 13.0931 1.04672 12.9776 1.01944 12.8411L1.00479 12.6986L1.01944 12.555C1.04678 12.4189 1.10716 12.3039 1.15421 12.2259C1.22525 12.1081 1.31723 11.9914 1.41202 11.8841C1.60273 11.6683 1.84818 11.4408 2.07999 11.2396C2.37597 10.9826 2.73594 10.7672 3.0126 10.4905C3.23486 10.3271 3.54905 10.3739 3.7128 10.596C4.12667 11.1585 3.02979 11.7387 2.73526 11.9945C2.65746 12.062 2.58217 12.1314 2.50967 12.1986H9.80948C12.2199 12.1984 14.0037 10.4779 14.0038 8.00422C14.0038 7.72809 14.2277 7.50422 14.5038 7.50422Z"),
|
||||
)
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M12.2958 1.20735C12.4792 0.958959 12.7528 0.98075 12.997 1.10285C13.3075 1.35229 13.6272 1.58922 13.9286 1.8509C14.1605 2.05225 14.4059 2.27956 14.5966 2.49543C14.6914 2.60277 14.7833 2.71937 14.8544 2.83723C14.9172 2.94141 15.0038 3.11122 15.0038 3.30988C15.0038 3.50848 14.9172 3.67838 14.8544 3.78254C14.7834 3.90019 14.6912 4.01619 14.5966 4.12336C14.4059 4.33923 14.1605 4.56752 13.9286 4.76887C13.6944 4.97226 13.4614 5.15895 13.288 5.29426C13.1919 5.36928 13.0916 5.44026 12.997 5.51692C12.7247 5.51692 12.5298 5.72903 12.2958 5.41145C12.1321 5.18912 12.179 4.87598 12.4013 4.71223C12.7002 4.48979 12.9919 4.25737 13.2733 4.01301C13.3507 3.94586 13.4249 3.87662 13.497 3.80988H6.19913C3.78848 3.80988 2.00479 5.53034 2.00479 8.00422C2.0047 8.28016 1.7807 8.50401 1.50479 8.50422C1.2287 8.50422 1.00488 8.28029 1.00479 8.00422C1.00479 4.96775 3.24656 2.80988 6.19913 2.80988H13.4989C13.4264 2.74268 13.3512 2.67341 13.2733 2.60578C13.0565 2.41748 12.8378 2.24241 12.6728 2.1136C12.586 2.04586 12.4794 1.98464 12.4013 1.90656C12.1792 1.74273 12.1321 1.42957 12.2958 1.20735Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_arrow_swap_horizontal_16!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcArrowSwapHorizontal16Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_arrow_swap_horizontal_16,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_arrow_swap_horizontal_20: ImageVector? = null
|
||||
|
||||
val Icons.ic_arrow_swap_horizontal_20: ImageVector
|
||||
get() {
|
||||
if (_ic_arrow_swap_horizontal_20 != null) return _ic_arrow_swap_horizontal_20!!
|
||||
_ic_arrow_swap_horizontal_20 = ImageVector.Builder(
|
||||
name = "ic_arrow_swap_horizontal_20",
|
||||
defaultWidth = 20.dp,
|
||||
defaultHeight = 20.dp,
|
||||
viewportWidth = 20f,
|
||||
viewportHeight = 20f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M17.2486 9.25041C17.6626 9.25059 17.9986 9.58634 17.9986 10.0004C17.9984 13.4943 15.4106 15.9844 12.0142 15.9848H4.38239C4.64562 16.2075 4.91445 16.4234 5.19098 16.6293C5.5247 16.878 5.62195 17.3488 5.36871 17.6928C5.13841 18.0054 4.71159 18.0873 4.38434 17.894L4.31989 17.852C4.00747 17.5396 3.60039 17.2964 3.26617 17.0063C3.00544 16.7799 2.72524 16.5198 2.50446 16.2699C2.39484 16.1459 2.28339 16.0059 2.19586 15.8608C2.13005 15.7516 2.03019 15.5645 2.00641 15.3354L2.00153 15.2348L2.00641 15.1342C2.03017 14.9049 2.13004 14.718 2.19586 14.6088C2.28347 14.4635 2.39475 14.3238 2.50446 14.1996C2.72541 13.9496 3.00522 13.6889 3.26617 13.4623C3.59999 13.1725 4.00686 12.9296 4.31891 12.6176C4.65232 12.3721 5.12302 12.4435 5.36871 12.7768C5.61412 13.1102 5.54289 13.579 5.20953 13.8246C4.96546 14.0687 4.64515 14.2617 4.38141 14.4848H12.0142C14.5978 14.4844 16.4984 12.6503 16.4986 10.0004C16.4986 9.58623 16.8344 9.25041 17.2486 9.25041Z"),
|
||||
)
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M14.6314 2.30705C14.931 1.90064 15.293 2.0191 15.6822 2.14885C16.0261 2.43744 16.3931 2.69754 16.733 2.9926C16.994 3.2192 17.2747 3.47982 17.4957 3.7299C17.6054 3.85404 17.7167 3.99383 17.8043 4.13908C17.8794 4.26384 17.9985 4.49026 17.9986 4.76506C17.9985 5.03992 17.8795 5.26625 17.8043 5.39103C17.7167 5.53626 17.6053 5.67609 17.4957 5.80021C17.2748 6.05019 16.9939 6.31001 16.733 6.53654C16.3358 6.88138 15.9458 7.18139 15.773 7.31193C15.743 7.33459 15.706 7.35553 15.6793 7.38225C15.3458 7.62751 14.877 7.55625 14.6314 7.22307C14.3776 6.87826 14.475 6.40861 14.8091 6.15959C15.0856 5.95362 15.3546 5.7379 15.6177 5.51506H7.9859C5.40232 5.51539 3.5018 7.34953 3.50153 9.99943C3.50153 10.4136 3.16574 10.7494 2.75153 10.7494C2.33741 10.7493 2.00153 10.4136 2.00153 9.99943C2.00181 6.50557 4.58949 4.0154 7.9859 4.01506H15.6177C15.306 3.75105 15.008 3.51895 14.8697 3.41447C14.8435 3.39469 14.8168 3.37557 14.7906 3.35588C14.4572 3.11024 14.3859 2.64052 14.6314 2.30705Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_arrow_swap_horizontal_20!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcArrowSwapHorizontal20Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_arrow_swap_horizontal_20,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_arrow_swap_horizontal_24: ImageVector? = null
|
||||
|
||||
val Icons.ic_arrow_swap_horizontal_24: ImageVector
|
||||
get() {
|
||||
if (_ic_arrow_swap_horizontal_24 != null) return _ic_arrow_swap_horizontal_24!!
|
||||
_ic_arrow_swap_horizontal_24 = ImageVector.Builder(
|
||||
name = "ic_arrow_swap_horizontal_24",
|
||||
defaultWidth = 24.dp,
|
||||
defaultHeight = 24.dp,
|
||||
viewportWidth = 24f,
|
||||
viewportHeight = 24f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M21 11.0045C21.5523 11.0045 22 11.4522 22 12.0045C22 16.3821 18.7551 19.5045 14.5 19.5045H5.21191C5.49969 19.743 5.79278 19.9745 6.0918 20.1988C6.53636 20.5262 6.6328 21.1526 6.30566 21.5972C5.96497 22.0598 5.32136 22.1191 4.87402 21.7857C4.43528 21.4587 4.00784 21.1151 3.59473 20.7564C3.26986 20.4744 2.91892 20.1493 2.6416 19.8355C2.50393 19.6797 2.36275 19.5024 2.25098 19.317C2.15573 19.1589 2 18.8651 2 18.5045C2.00003 18.1439 2.15574 17.85 2.25098 17.692C2.36275 17.5066 2.50394 17.3292 2.6416 17.1734C2.91892 16.8596 3.26988 16.5346 3.59473 16.2525C4.00784 15.8938 4.43528 15.5502 4.87402 15.2232C4.88489 15.2151 4.8976 15.2084 4.90723 15.1988C5.35185 14.8717 5.97725 14.9672 6.30469 15.4117C6.63219 15.8564 6.53744 16.4826 6.09277 16.8101L6.0918 16.8092C5.79136 17.0311 5.4995 17.2661 5.21191 17.5045H14.5C17.6714 17.5045 20 15.2568 20 12.0045C20 11.4522 20.4477 11.0045 21 11.0045Z"),
|
||||
)
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M17.6953 2.41169C18.036 1.94929 18.6787 1.88996 19.126 2.22321C19.5647 2.55021 19.9922 2.89383 20.4053 3.25251C20.7301 3.53456 21.0811 3.85962 21.3584 4.17341C21.4961 4.32922 21.6373 4.50657 21.749 4.69196C21.8443 4.84998 22 5.14386 22 5.50446C22 5.86506 21.8443 6.15891 21.749 6.31696C21.6373 6.50237 21.4961 6.67971 21.3584 6.83552C21.0811 7.14932 20.7301 7.47436 20.4053 7.75642C20.0754 8.04283 19.7486 8.30528 19.5059 8.4947C19.3736 8.59794 19.212 8.69092 19.0928 8.81013C18.6481 9.13731 18.0218 9.04181 17.6943 8.59724C17.3672 8.15256 17.4627 7.52621 17.9072 7.1988C18.2219 7.01 18.5075 6.73711 18.7881 6.50446H9.5C6.32862 6.50446 4.00003 8.75217 4 12.0045C4 12.5567 3.55228 13.0045 3 13.0045C2.44772 13.0045 2 12.5567 2 12.0045C2.00004 7.6269 5.24487 4.50446 9.5 4.50446H18.7881C18.5017 4.26707 18.2111 4.0345 17.9121 3.81306C17.4729 3.48759 17.3691 2.85468 17.6953 2.41169Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_arrow_swap_horizontal_24!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcArrowSwapHorizontal24Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_arrow_swap_horizontal_24,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_arrow_swap_horizontal_28: ImageVector? = null
|
||||
|
||||
val Icons.ic_arrow_swap_horizontal_28: ImageVector
|
||||
get() {
|
||||
if (_ic_arrow_swap_horizontal_28 != null) return _ic_arrow_swap_horizontal_28!!
|
||||
_ic_arrow_swap_horizontal_28 = ImageVector.Builder(
|
||||
name = "ic_arrow_swap_horizontal_28",
|
||||
defaultWidth = 28.dp,
|
||||
defaultHeight = 28.dp,
|
||||
viewportWidth = 28f,
|
||||
viewportHeight = 28f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M24.7474 12.7524C25.4377 12.7525 25.9974 13.3121 25.9974 14.0024C25.997 19.2619 22.0959 23.0158 16.9837 23.0161H6.04327C6.34685 23.2645 6.65476 23.5082 6.97003 23.7417C7.00663 23.7671 7.04005 23.7983 7.07452 23.8266C7.54368 24.2519 7.6241 24.9726 7.24054 25.4936C6.83126 26.049 6.04922 26.167 5.49347 25.7583C4.9236 25.4733 4.39161 24.9068 3.9212 24.4985C3.53236 24.161 3.11138 23.7696 2.77765 23.392C2.61218 23.2048 2.44089 22.9913 2.30499 22.7661C2.20416 22.5989 2.04466 22.3001 2.00616 21.9292L1.99738 21.7661L2.00616 21.603C2.04454 21.2318 2.2041 20.9334 2.30499 20.7661C2.44095 20.5406 2.61202 20.3265 2.77765 20.1391C3.11135 19.7616 3.53239 19.3712 3.9212 19.0337C4.42705 18.5946 4.95059 18.1738 5.48956 17.7758C6.02099 17.3469 6.84799 17.5056 7.24054 18.0385C7.6494 18.5943 7.53135 19.3773 6.97589 19.7866C6.65821 20.0211 6.34807 20.2662 6.0423 20.5161H16.9837C20.7412 20.5159 23.497 17.8553 23.4974 14.0024C23.4974 13.312 24.057 12.7524 24.7474 12.7524Z"),
|
||||
)
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M20.7542 2.51021C21.1635 1.95435 21.9464 1.83538 22.5023 2.24459C22.6445 2.38682 22.8384 2.49824 22.9964 2.62154C23.2868 2.84813 23.6785 3.16239 24.0735 3.50533C24.4625 3.84293 24.8843 4.23318 25.2181 4.6108C25.3836 4.79814 25.5538 5.01237 25.6898 5.23775C25.805 5.42891 25.9983 5.79119 25.9984 6.23775C25.9983 6.68425 25.805 7.04662 25.6898 7.23775C25.5539 7.46296 25.3835 7.67651 25.2181 7.86373C24.8843 8.24139 24.4625 8.63254 24.0735 8.97018C23.4801 9.48529 22.9005 9.93091 22.6429 10.1254L22.5062 10.228C21.9463 10.6178 21.168 10.5271 20.7542 9.96529C20.3449 9.40939 20.4649 8.62559 21.0208 8.21627C21.3376 7.98225 21.6468 7.73745 21.9515 7.48775H11.011C7.2533 7.48792 4.49754 10.1482 4.49738 14.0014C4.49728 14.6915 3.93745 15.2512 3.24738 15.2514C2.55708 15.2514 1.99747 14.6917 1.99738 14.0014C1.99754 8.74159 5.89861 4.98792 11.011 4.98775H21.9525C21.6489 4.73936 21.341 4.49564 21.0257 4.26217C20.4769 3.85506 20.3464 3.06423 20.7542 2.51021Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_arrow_swap_horizontal_28!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcArrowSwapHorizontal28Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_arrow_swap_horizontal_28,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_arrow_swap_horizontal_32: ImageVector? = null
|
||||
|
||||
val Icons.ic_arrow_swap_horizontal_32: ImageVector
|
||||
get() {
|
||||
if (_ic_arrow_swap_horizontal_32 != null) return _ic_arrow_swap_horizontal_32!!
|
||||
_ic_arrow_swap_horizontal_32 = ImageVector.Builder(
|
||||
name = "ic_arrow_swap_horizontal_32",
|
||||
defaultWidth = 32.dp,
|
||||
defaultHeight = 32.dp,
|
||||
viewportWidth = 32f,
|
||||
viewportHeight = 32f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M28.5 14.5053C29.3284 14.5053 30 15.1769 30 16.0053C29.9997 22.1473 25.4424 26.5324 19.4727 26.5326H6.88187C7.20141 26.7917 7.52461 27.047 7.8555 27.2914C7.89862 27.3234 7.93899 27.3599 7.9805 27.394C8.54395 27.9043 8.64018 28.7686 8.17972 29.394C7.69336 30.0542 6.73698 30.1964 6.07816 29.7094C5.45186 29.2447 4.84175 28.7557 4.25296 28.2446C3.80021 27.8515 3.30898 27.3949 2.91898 26.9535C2.72551 26.7346 2.52434 26.4837 2.36429 26.2182C2.24594 26.0218 2.05553 25.6683 2.0098 25.227L2.00003 25.0326L2.0098 24.8373C2.0556 24.396 2.24597 24.0424 2.36429 23.8461C2.52425 23.5808 2.72464 23.3296 2.918 23.1108C3.308 22.6694 3.80023 22.2138 4.25296 21.8207C4.94417 21.2206 5.61892 20.7017 5.91898 20.475C5.97157 20.4353 6.03512 20.3989 6.08206 20.352C6.74897 19.8612 7.68848 20.0037 8.17972 20.6703C8.6709 21.3373 8.52907 22.2766 7.86234 22.768H7.86038C7.85929 22.7688 7.85799 22.771 7.8555 22.7729C7.52453 23.018 7.20082 23.2732 6.88089 23.5326H19.4727C23.8167 23.5324 26.9997 20.4594 27 16.0053C27 15.1769 27.6716 14.5053 28.5 14.5053Z"),
|
||||
)
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M23.8194 2.61467C24.3124 1.9453 25.267 1.8191 25.9307 2.30608C26.5546 2.76822 27.161 3.25619 27.7471 3.76506C28.1997 4.15802 28.6912 4.6139 29.0811 5.0551C29.2744 5.27395 29.4748 5.52513 29.6348 5.79045C29.77 6.01478 29.9999 6.44506 30 6.97698C29.9999 7.50873 29.77 7.93817 29.6348 8.16252C29.4748 8.42796 29.2745 8.67894 29.0811 8.89788C28.6911 9.33928 28.1999 9.79578 27.7471 10.1889C27.2871 10.5883 26.8312 10.9534 26.4932 11.2172C26.3087 11.3612 26.0834 11.4903 25.917 11.6567C25.25 12.1478 24.3106 12.0053 23.8194 11.3383C23.3285 10.6713 23.4709 9.73182 24.1377 9.24065C24.4709 8.99452 24.7964 8.73784 25.1182 8.47698H12.5274C8.18322 8.47717 5.00023 11.5501 5.00003 16.0043C4.99997 16.8327 4.32842 17.5043 3.50003 17.5043C2.67164 17.5043 2.00009 16.8327 2.00003 16.0043C2.00024 9.86217 6.55758 5.47718 12.5274 5.47698H25.1192C24.7992 5.21757 24.4756 4.96241 24.1446 4.71721C23.4921 4.22093 23.3257 3.28503 23.8194 2.61467Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_arrow_swap_horizontal_32!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcArrowSwapHorizontal32Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_arrow_swap_horizontal_32,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_arrow_up_12: ImageVector? = null
|
||||
|
||||
val Icons.ic_arrow_up_12: ImageVector
|
||||
get() {
|
||||
if (_ic_arrow_up_12 != null) return _ic_arrow_up_12!!
|
||||
_ic_arrow_up_12 = ImageVector.Builder(
|
||||
name = "ic_arrow_up_12",
|
||||
defaultWidth = 12.dp,
|
||||
defaultHeight = 12.dp,
|
||||
viewportWidth = 12f,
|
||||
viewportHeight = 12f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M5.5 10.25C5.5 10.5261 5.72386 10.75 6 10.75C6.27614 10.75 6.5 10.5261 6.5 10.25V3.20703L9.64648 6.35352C9.84175 6.54878 10.1583 6.54878 10.3535 6.35352C10.5488 6.15825 10.5488 5.84175 10.3535 5.64648L6.35352 1.64648C6.15825 1.45122 5.84175 1.45122 5.64648 1.64648L1.64648 5.64648C1.45122 5.84175 1.45122 6.15825 1.64648 6.35352C1.84175 6.54878 2.15825 6.54878 2.35352 6.35352L5.5 3.20703V10.25Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_arrow_up_12!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcArrowUp12Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_arrow_up_12,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_arrow_up_16: ImageVector? = null
|
||||
|
||||
val Icons.ic_arrow_up_16: ImageVector
|
||||
get() {
|
||||
if (_ic_arrow_up_16 != null) return _ic_arrow_up_16!!
|
||||
_ic_arrow_up_16 = ImageVector.Builder(
|
||||
name = "ic_arrow_up_16",
|
||||
defaultWidth = 16.dp,
|
||||
defaultHeight = 16.dp,
|
||||
viewportWidth = 16f,
|
||||
viewportHeight = 16f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M7.49966 13.6667C7.49966 13.9427 7.72367 14.1665 7.99966 14.1667C8.27581 14.1667 8.49966 13.9428 8.49966 13.6667V3.87372L12.9801 8.35321C13.1754 8.54847 13.4919 8.54847 13.6872 8.35321C13.8821 8.15792 13.8823 7.84133 13.6872 7.64618L8.35318 2.31317C8.1579 2.11807 7.84136 2.11796 7.64615 2.31317L2.31314 7.64618C2.11793 7.84139 2.11804 8.15793 2.31314 8.35321C2.5084 8.54847 2.82491 8.54847 3.02017 8.35321L7.49966 3.87372V13.6667Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_arrow_up_16!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcArrowUp16Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_arrow_up_16,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_arrow_up_20: ImageVector? = null
|
||||
|
||||
val Icons.ic_arrow_up_20: ImageVector
|
||||
get() {
|
||||
if (_ic_arrow_up_20 != null) return _ic_arrow_up_20!!
|
||||
_ic_arrow_up_20 = ImageVector.Builder(
|
||||
name = "ic_arrow_up_20",
|
||||
defaultWidth = 20.dp,
|
||||
defaultHeight = 20.dp,
|
||||
viewportWidth = 20f,
|
||||
viewportHeight = 20f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M9.25034 17.0833C9.25034 17.4975 9.58612 17.8333 10.0003 17.8333C10.4144 17.8331 10.7503 17.4974 10.7503 17.0833V5.14484L16.1361 10.5306C16.4289 10.8234 16.9037 10.8231 17.1966 10.5306C17.4895 10.2377 17.4895 9.76293 17.1966 9.47003L10.5306 2.80304C10.2378 2.5102 9.76297 2.51031 9.47006 2.80304L2.80307 9.47003C2.51034 9.76294 2.51023 10.2377 2.80307 10.5306C3.09592 10.8233 3.57076 10.8233 3.86362 10.5306L9.25034 5.14386V17.0833Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_arrow_up_20!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcArrowUp20Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_arrow_up_20,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_arrow_up_24: ImageVector? = null
|
||||
|
||||
val Icons.ic_arrow_up_24: ImageVector
|
||||
get() {
|
||||
if (_ic_arrow_up_24 != null) return _ic_arrow_up_24!!
|
||||
_ic_arrow_up_24 = ImageVector.Builder(
|
||||
name = "ic_arrow_up_24",
|
||||
defaultWidth = 24.dp,
|
||||
defaultHeight = 24.dp,
|
||||
viewportWidth = 24f,
|
||||
viewportHeight = 24f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M11 20.5C11 21.0523 11.4477 21.5 12 21.5C12.5523 21.5 13 21.0523 13 20.5V6.41406L19.293 12.707C19.6835 13.0976 20.3165 13.0976 20.707 12.707C21.0976 12.3165 21.0976 11.6835 20.707 11.293L12.707 3.29297C12.3165 2.90244 11.6835 2.90244 11.293 3.29297L3.29297 11.293C2.90245 11.6835 2.90245 12.3165 3.29297 12.707C3.68349 13.0976 4.31651 13.0976 4.70703 12.707L11 6.41406V20.5Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_arrow_up_24!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcArrowUp24Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_arrow_up_24,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_arrow_up_28: ImageVector? = null
|
||||
|
||||
val Icons.ic_arrow_up_28: ImageVector
|
||||
get() {
|
||||
if (_ic_arrow_up_28 != null) return _ic_arrow_up_28!!
|
||||
_ic_arrow_up_28 = ImageVector.Builder(
|
||||
name = "ic_arrow_up_28",
|
||||
defaultWidth = 28.dp,
|
||||
defaultHeight = 28.dp,
|
||||
viewportWidth = 28f,
|
||||
viewportHeight = 28f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M12.7497 23.9167C12.7497 24.6069 13.3095 25.1665 13.9997 25.1667C14.69 25.1667 15.2497 24.607 15.2497 23.9167V7.68427L22.4499 14.8835C22.938 15.3716 23.7293 15.3716 24.2174 14.8835C24.7053 14.3953 24.7055 13.604 24.2174 13.1159L14.8835 3.7829C14.3953 3.29491 13.604 3.2948 13.1159 3.7829L3.78287 13.1159C3.29477 13.604 3.29487 14.3953 3.78287 14.8835C4.27102 15.3716 5.06229 15.3716 5.55045 14.8835L12.7497 7.68427V23.9167Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_arrow_up_28!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcArrowUp28Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_arrow_up_28,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_arrow_up_32: ImageVector? = null
|
||||
|
||||
val Icons.ic_arrow_up_32: ImageVector
|
||||
get() {
|
||||
if (_ic_arrow_up_32 != null) return _ic_arrow_up_32!!
|
||||
_ic_arrow_up_32 = ImageVector.Builder(
|
||||
name = "ic_arrow_up_32",
|
||||
defaultWidth = 32.dp,
|
||||
defaultHeight = 32.dp,
|
||||
viewportWidth = 32f,
|
||||
viewportHeight = 32f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M14.5003 27.3333C14.5003 28.1617 15.1719 28.8333 16.0003 28.8333C16.8286 28.8331 17.5003 28.1616 17.5003 27.3333V8.95538L25.6058 17.0609C26.1915 17.6465 27.1411 17.6463 27.7269 17.0609C28.3127 16.4751 28.3127 15.5255 27.7269 14.9398L17.0609 4.27277C16.4752 3.68703 15.5256 3.68714 14.9398 4.27277L4.2728 14.9398C3.68717 15.5256 3.68706 16.4751 4.2728 17.0609C4.85854 17.6464 5.80815 17.6464 6.39389 17.0609L14.5003 8.95441V27.3333Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_arrow_up_32!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcArrowUp32Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_arrow_up_32,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_loading_spinner_12: ImageVector? = null
|
||||
|
||||
val Icons.ic_loading_spinner_12: ImageVector
|
||||
get() {
|
||||
if (_ic_loading_spinner_12 != null) return _ic_loading_spinner_12!!
|
||||
_ic_loading_spinner_12 = ImageVector.Builder(
|
||||
name = "ic_loading_spinner_12",
|
||||
defaultWidth = 12.dp,
|
||||
defaultHeight = 12.dp,
|
||||
viewportWidth = 12f,
|
||||
viewportHeight = 12f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M6 1C6.98891 1 7.95607 1.29337 8.77832 1.84277C9.60038 2.39217 10.2408 3.17342 10.6191 4.08691C10.9975 5.00049 11.0972 6.00575 10.9043 6.97559C10.7114 7.94547 10.2344 8.83591 9.53516 9.53516C8.83591 10.2344 7.94547 10.7114 6.97559 10.9043C6.00575 11.0972 5.00049 10.9975 4.08691 10.6191C3.17342 10.2408 2.39217 9.60038 1.84277 8.77832C1.29337 7.95607 1 6.98891 1 6C1 5.72386 1.22386 5.5 1.5 5.5C1.77614 5.5 2 5.72386 2 6C2 6.79113 2.2343 7.56486 2.67383 8.22266C3.11335 8.88039 3.73887 9.39258 4.46973 9.69531C5.20054 9.99795 6.00447 10.0772 6.78027 9.92285C7.5562 9.76851 8.26872 9.38754 8.82812 8.82812C9.38754 8.26871 9.76851 7.5562 9.92285 6.78027C10.0772 6.00447 9.99795 5.20054 9.69531 4.46973C9.39258 3.73887 8.88039 3.11335 8.22266 2.67383C7.56486 2.2343 6.79113 2 6 2C5.72386 2 5.5 1.77614 5.5 1.5C5.5 1.22386 5.72386 1 6 1Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_loading_spinner_12!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcLoadingSpinner12Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_loading_spinner_12,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_loading_spinner_16: ImageVector? = null
|
||||
|
||||
val Icons.ic_loading_spinner_16: ImageVector
|
||||
get() {
|
||||
if (_ic_loading_spinner_16 != null) return _ic_loading_spinner_16!!
|
||||
_ic_loading_spinner_16 = ImageVector.Builder(
|
||||
name = "ic_loading_spinner_16",
|
||||
defaultWidth = 16.dp,
|
||||
defaultHeight = 16.dp,
|
||||
viewportWidth = 16f,
|
||||
viewportHeight = 16f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M8 2C9.18663 2.00007 10.3473 2.35246 11.334 3.01172C12.3204 3.67102 13.0899 4.60793 13.5439 5.7041C13.9979 6.80037 14.1172 8.00714 13.8857 9.1709C13.6542 10.3347 13.0823 11.4041 12.2432 12.2432C11.4041 13.0823 10.3347 13.6542 9.1709 13.8857C8.00714 14.1172 6.80037 13.9979 5.7041 13.5439C4.60783 13.0899 3.67005 12.3205 3.01074 11.334C2.35155 10.3474 2.00006 9.18657 2 8C2.00016 7.65496 2.27992 7.375 2.625 7.375C2.96992 7.37518 3.24984 7.65507 3.25 8C3.25006 8.93941 3.52887 9.85856 4.05078 10.6396C4.57273 11.4205 5.31485 12.0292 6.18262 12.3887C7.05043 12.748 8.00552 12.8424 8.92676 12.6592C9.84813 12.4759 10.6951 12.0237 11.3594 11.3594C12.0237 10.6951 12.4759 9.84813 12.6592 8.92676C12.8424 8.00552 12.748 7.05043 12.3887 6.18262C12.0292 5.31484 11.4205 4.57273 10.6396 4.05078C9.85856 3.52887 8.93941 3.25007 8 3.25C7.65508 3.24983 7.37518 2.96992 7.375 2.625C7.375 2.27993 7.65496 2.00017 8 2Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_loading_spinner_16!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcLoadingSpinner16Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_loading_spinner_16,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_loading_spinner_20: ImageVector? = null
|
||||
|
||||
val Icons.ic_loading_spinner_20: ImageVector
|
||||
get() {
|
||||
if (_ic_loading_spinner_20 != null) return _ic_loading_spinner_20!!
|
||||
_ic_loading_spinner_20 = ImageVector.Builder(
|
||||
name = "ic_loading_spinner_20",
|
||||
defaultWidth = 20.dp,
|
||||
defaultHeight = 20.dp,
|
||||
viewportWidth = 20f,
|
||||
viewportHeight = 20f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M10 2C11.5823 2 13.1287 2.46958 14.4443 3.34863C15.7599 4.22764 16.7851 5.47676 17.3906 6.93848C17.9961 8.40021 18.1553 10.0088 17.8467 11.5605C17.538 13.1124 16.776 14.5384 15.6572 15.6572C14.5384 16.776 13.1124 17.538 11.5605 17.8467C10.0088 18.1553 8.40021 17.9961 6.93848 17.3906C5.47676 16.7851 4.22764 15.7599 3.34863 14.4443C2.46958 13.1287 2 11.5823 2 10C2 9.58579 2.33579 9.25 2.75 9.25C3.16421 9.25 3.5 9.58579 3.5 10C3.5 11.2856 3.88147 12.5424 4.5957 13.6113C5.30993 14.6802 6.32505 15.5129 7.5127 16.0049C8.70042 16.4969 10.0077 16.6258 11.2686 16.375C12.5292 16.1241 13.6878 15.5056 14.5967 14.5967C15.5056 13.6878 16.1241 12.5292 16.375 11.2686C16.6258 10.0077 16.4969 8.70041 16.0049 7.5127C15.5129 6.32505 14.6802 5.30993 13.6113 4.5957C12.5424 3.88147 11.2856 3.5 10 3.5C9.58579 3.5 9.25 3.16421 9.25 2.75C9.25 2.33579 9.58579 2 10 2Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_loading_spinner_20!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcLoadingSpinner20Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_loading_spinner_20,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_loading_spinner_24: ImageVector? = null
|
||||
|
||||
val Icons.ic_loading_spinner_24: ImageVector
|
||||
get() {
|
||||
if (_ic_loading_spinner_24 != null) return _ic_loading_spinner_24!!
|
||||
_ic_loading_spinner_24 = ImageVector.Builder(
|
||||
name = "ic_loading_spinner_24",
|
||||
defaultWidth = 24.dp,
|
||||
defaultHeight = 24.dp,
|
||||
viewportWidth = 24f,
|
||||
viewportHeight = 24f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M12 2C13.9778 2 15.9112 2.58673 17.5557 3.68555C19.2001 4.78434 20.4824 6.34567 21.2393 8.17285C21.9961 10.0001 22.1935 12.0114 21.8076 13.9512C21.4217 15.8909 20.4697 17.6728 19.0713 19.0713C17.6728 20.4697 15.8909 21.4217 13.9512 21.8076C12.0114 22.1935 10.0001 21.9961 8.17285 21.2393C6.34567 20.4824 4.78434 19.2001 3.68555 17.5557C2.58673 15.9112 2 13.9778 2 12C2 11.4477 2.44772 11 3 11C3.55228 11 4 11.4477 4 12C4 13.5823 4.46958 15.1287 5.34863 16.4443C6.22764 17.7599 7.47676 18.7851 8.93848 19.3906C10.4002 19.9961 12.0088 20.1553 13.5605 19.8467C15.1124 19.538 16.5384 18.776 17.6572 17.6572C18.776 16.5384 19.538 15.1124 19.8467 13.5605C20.1553 12.0088 19.9961 10.4002 19.3906 8.93848C18.7851 7.47676 17.7599 6.22764 16.4443 5.34863C15.1287 4.46958 13.5823 4 12 4C11.4477 4 11 3.55228 11 3C11 2.44772 11.4477 2 12 2Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_loading_spinner_24!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcLoadingSpinner24Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_loading_spinner_24,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_loading_spinner_28: ImageVector? = null
|
||||
|
||||
val Icons.ic_loading_spinner_28: ImageVector
|
||||
get() {
|
||||
if (_ic_loading_spinner_28 != null) return _ic_loading_spinner_28!!
|
||||
_ic_loading_spinner_28 = ImageVector.Builder(
|
||||
name = "ic_loading_spinner_28",
|
||||
defaultWidth = 28.dp,
|
||||
defaultHeight = 28.dp,
|
||||
viewportWidth = 28f,
|
||||
viewportHeight = 28f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M14 2C16.3734 2 18.6936 2.70388 20.667 4.02246C22.6403 5.34103 24.1787 7.21554 25.0869 9.4082C25.995 11.6007 26.2324 14.0133 25.7695 16.3408C25.3065 18.6686 24.1636 20.8071 22.4854 22.4854C20.8071 24.1636 18.6686 25.3065 16.3408 25.7695C14.0133 26.2324 11.6007 25.995 9.4082 25.0869C7.21555 24.1787 5.34103 22.6403 4.02246 20.667C2.70389 18.6936 2 16.3734 2 14C2 13.3096 2.55965 12.75 3.25 12.75C3.94036 12.75 4.5 13.3096 4.5 14C4.5 15.8789 5.05672 17.7161 6.10059 19.2783C7.14438 20.8404 8.62855 22.0573 10.3643 22.7764C12.1002 23.4954 14.0107 23.6839 15.8535 23.3174C17.6963 22.9508 19.3892 22.0463 20.7178 20.7178C22.0463 19.3892 22.9508 17.6963 23.3174 15.8535C23.6839 14.0107 23.4964 12.1002 22.7773 10.3643C22.0583 8.6284 20.8405 7.14445 19.2783 6.10059C17.7161 5.05671 15.8789 4.5 14 4.5C13.3096 4.5 12.75 3.94036 12.75 3.25C12.75 2.55964 13.3096 2 14 2Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_loading_spinner_28!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcLoadingSpinner28Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_loading_spinner_28,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_loading_spinner_32: ImageVector? = null
|
||||
|
||||
val Icons.ic_loading_spinner_32: ImageVector
|
||||
get() {
|
||||
if (_ic_loading_spinner_32 != null) return _ic_loading_spinner_32!!
|
||||
_ic_loading_spinner_32 = ImageVector.Builder(
|
||||
name = "ic_loading_spinner_32",
|
||||
defaultWidth = 32.dp,
|
||||
defaultHeight = 32.dp,
|
||||
viewportWidth = 32f,
|
||||
viewportHeight = 32f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M16 2C18.7689 2 21.476 2.82103 23.7783 4.35938C26.0805 5.89771 27.875 8.08449 28.9346 10.6426C29.9941 13.2007 30.2716 16.0158 29.7314 18.7314C29.1912 21.4471 27.8573 23.9415 25.8994 25.8994C23.9415 27.8573 21.4471 29.1912 18.7314 29.7314C16.0158 30.2716 13.2007 29.9941 10.6426 28.9346C8.0845 27.875 5.8977 26.0805 4.35938 23.7783C2.82104 21.476 2 18.7689 2 16C2 15.1716 2.67157 14.5 3.5 14.5C4.32843 14.5 5 15.1716 5 16C5 18.1755 5.64487 20.3024 6.85352 22.1113C8.06216 23.9202 9.78015 25.3305 11.79 26.1631C13.7999 26.9956 16.0119 27.2134 18.1455 26.7891C20.2793 26.3646 22.2399 25.3167 23.7783 23.7783C25.3166 22.24 26.3646 20.2801 26.7891 18.1465C27.2135 16.0127 26.9956 13.8 26.1631 11.79C25.3305 9.78015 23.9202 8.06216 22.1113 6.85352C20.3024 5.64487 18.1756 5 16 5C15.1716 5 14.5 4.32843 14.5 3.5C14.5 2.67157 15.1716 2 16 2Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_loading_spinner_32!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcLoadingSpinner32Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_loading_spinner_32,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_sign_equal_12: ImageVector? = null
|
||||
|
||||
val Icons.ic_sign_equal_12: ImageVector
|
||||
get() {
|
||||
if (_ic_sign_equal_12 != null) return _ic_sign_equal_12!!
|
||||
_ic_sign_equal_12 = ImageVector.Builder(
|
||||
name = "ic_sign_equal_12",
|
||||
defaultWidth = 12.dp,
|
||||
defaultHeight = 12.dp,
|
||||
viewportWidth = 12f,
|
||||
viewportHeight = 12f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M9.5 7.5C9.77614 7.5 10 7.72386 10 8C10 8.27614 9.77614 8.5 9.5 8.5H2.5C2.22386 8.5 2 8.27614 2 8C2 7.72386 2.22386 7.5 2.5 7.5H9.5ZM9.5 3.5C9.77614 3.5 10 3.72386 10 4C10 4.27614 9.77614 4.5 9.5 4.5H2.5C2.22386 4.5 2 4.27614 2 4C2 3.72386 2.22386 3.5 2.5 3.5H9.5Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_sign_equal_12!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcSignEqual12Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_sign_equal_12,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_sign_equal_16: ImageVector? = null
|
||||
|
||||
val Icons.ic_sign_equal_16: ImageVector
|
||||
get() {
|
||||
if (_ic_sign_equal_16 != null) return _ic_sign_equal_16!!
|
||||
_ic_sign_equal_16 = ImageVector.Builder(
|
||||
name = "ic_sign_equal_16",
|
||||
defaultWidth = 16.dp,
|
||||
defaultHeight = 16.dp,
|
||||
viewportWidth = 16f,
|
||||
viewportHeight = 16f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M12.5 10C12.7761 10 13 10.2239 13 10.5C13 10.7761 12.7761 11 12.5 11H3.5C3.22386 11 3 10.7761 3 10.5C3 10.2239 3.22386 10 3.5 10H12.5ZM12.5 5C12.7761 5 13 5.22386 13 5.5C13 5.77614 12.7761 6 12.5 6H3.5C3.22386 6 3 5.77614 3 5.5C3 5.22386 3.22386 5 3.5 5H12.5Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_sign_equal_16!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcSignEqual16Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_sign_equal_16,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_sign_equal_20: ImageVector? = null
|
||||
|
||||
val Icons.ic_sign_equal_20: ImageVector
|
||||
get() {
|
||||
if (_ic_sign_equal_20 != null) return _ic_sign_equal_20!!
|
||||
_ic_sign_equal_20 = ImageVector.Builder(
|
||||
name = "ic_sign_equal_20",
|
||||
defaultWidth = 20.dp,
|
||||
defaultHeight = 20.dp,
|
||||
viewportWidth = 20f,
|
||||
viewportHeight = 20f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M16 12.75C16.4142 12.75 16.75 13.0858 16.75 13.5C16.75 13.9142 16.4142 14.25 16 14.25H4C3.58579 14.25 3.25 13.9142 3.25 13.5C3.25 13.0858 3.58579 12.75 4 12.75H16ZM16 5.75C16.4142 5.75 16.75 6.08579 16.75 6.5C16.75 6.91421 16.4142 7.25 16 7.25H4C3.58579 7.25 3.25 6.91421 3.25 6.5C3.25 6.08579 3.58579 5.75 4 5.75H16Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_sign_equal_20!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcSignEqual20Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_sign_equal_20,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_sign_equal_24: ImageVector? = null
|
||||
|
||||
val Icons.ic_sign_equal_24: ImageVector
|
||||
get() {
|
||||
if (_ic_sign_equal_24 != null) return _ic_sign_equal_24!!
|
||||
_ic_sign_equal_24 = ImageVector.Builder(
|
||||
name = "ic_sign_equal_24",
|
||||
defaultWidth = 24.dp,
|
||||
defaultHeight = 24.dp,
|
||||
viewportWidth = 24f,
|
||||
viewportHeight = 24f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M19 15C19.5523 15 20 15.4477 20 16C20 16.5523 19.5523 17 19 17H5C4.44772 17 4 16.5523 4 16C4 15.4477 4.44772 15 5 15H19ZM19 7C19.5523 7 20 7.44772 20 8C20 8.55228 19.5523 9 19 9H5C4.44772 9 4 8.55228 4 8C4 7.44772 4.44772 7 5 7H19Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_sign_equal_24!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcSignEqual24Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_sign_equal_24,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_sign_equal_28: ImageVector? = null
|
||||
|
||||
val Icons.ic_sign_equal_28: ImageVector
|
||||
get() {
|
||||
if (_ic_sign_equal_28 != null) return _ic_sign_equal_28!!
|
||||
_ic_sign_equal_28 = ImageVector.Builder(
|
||||
name = "ic_sign_equal_28",
|
||||
defaultWidth = 28.dp,
|
||||
defaultHeight = 28.dp,
|
||||
viewportWidth = 28f,
|
||||
viewportHeight = 28f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M22 17.25C22.6904 17.25 23.25 17.8096 23.25 18.5C23.25 19.1904 22.6904 19.75 22 19.75H6C5.30964 19.75 4.75 19.1904 4.75 18.5C4.75 17.8096 5.30964 17.25 6 17.25H22ZM22 8.25C22.6904 8.25 23.25 8.80964 23.25 9.5C23.25 10.1904 22.6904 10.75 22 10.75H6C5.30964 10.75 4.75 10.1904 4.75 9.5C4.75 8.80964 5.30964 8.25 6 8.25H22Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_sign_equal_28!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcSignEqual28Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_sign_equal_28,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_sign_equal_32: ImageVector? = null
|
||||
|
||||
val Icons.ic_sign_equal_32: ImageVector
|
||||
get() {
|
||||
if (_ic_sign_equal_32 != null) return _ic_sign_equal_32!!
|
||||
_ic_sign_equal_32 = ImageVector.Builder(
|
||||
name = "ic_sign_equal_32",
|
||||
defaultWidth = 32.dp,
|
||||
defaultHeight = 32.dp,
|
||||
viewportWidth = 32f,
|
||||
viewportHeight = 32f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M25.5 20C26.3284 20 27 20.6716 27 21.5C27 22.3284 26.3284 23 25.5 23H6.5C5.67157 23 5 22.3284 5 21.5C5 20.6716 5.67157 20 6.5 20H25.5ZM25.5 9C26.3284 9 27 9.67157 27 10.5C27 11.3284 26.3284 12 25.5 12H6.5C5.67157 12 5 11.3284 5 10.5C5 9.67157 5.67157 9 6.5 9H25.5Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_sign_equal_32!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcSignEqual32Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_sign_equal_32,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_sign_usd_12: ImageVector? = null
|
||||
|
||||
val Icons.ic_sign_usd_12: ImageVector
|
||||
get() {
|
||||
if (_ic_sign_usd_12 != null) return _ic_sign_usd_12!!
|
||||
_ic_sign_usd_12 = ImageVector.Builder(
|
||||
name = "ic_sign_usd_12",
|
||||
defaultWidth = 12.dp,
|
||||
defaultHeight = 12.dp,
|
||||
viewportWidth = 12f,
|
||||
viewportHeight = 12f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M6.24954 0.5C6.52568 0.5 6.74953 0.72387 6.74954 1V1.55176C7.42689 1.64637 8.0446 1.86753 8.53958 2.1875C9.20731 2.61916 9.70754 3.27502 9.70755 4.07422C9.70747 4.35029 9.48364 4.57422 9.20755 4.57422C8.93161 4.57404 8.70763 4.35019 8.70755 4.07422C8.70754 3.72796 8.49005 3.34633 7.99661 3.02734C7.5082 2.71164 6.80353 2.5 5.99954 2.5C5.19556 2.5 4.49088 2.71164 4.00247 3.02734C3.50903 3.34633 3.29155 3.72796 3.29153 4.07422C3.29155 4.29659 3.33349 4.46597 3.40482 4.59863C3.47494 4.72893 3.58855 4.8519 3.77493 4.96191C4.16757 5.19353 4.8587 5.35156 5.99954 5.35156C7.18836 5.35156 8.1724 5.49931 8.87259 5.89941C9.23277 6.10525 9.52233 6.38077 9.71829 6.73535C9.91304 7.08786 9.99952 7.48949 9.99954 7.92578C9.99954 8.88789 9.47075 9.5592 8.70755 9.96094C8.15754 10.2504 7.47756 10.4084 6.74954 10.4697V11C6.74954 11.2761 6.52568 11.5 6.24954 11.5C5.97361 11.4998 5.74954 11.276 5.74954 11V10.4922C4.80503 10.4557 3.93479 10.2162 3.27005 9.82227C2.55796 9.40028 1.99954 8.74624 1.99954 7.92578C1.99964 7.64972 2.22346 7.42578 2.49954 7.42578C2.77563 7.42578 2.99945 7.64972 2.99954 7.92578C2.99954 8.25079 3.22518 8.63323 3.77982 8.96191C4.32353 9.28411 5.107 9.5 5.99954 9.5C6.92806 9.5 7.71052 9.35574 8.24173 9.07617C8.74508 8.81124 8.99954 8.44501 8.99954 7.92578C8.99952 7.62162 8.94005 7.39388 8.84329 7.21875C8.74761 7.04562 8.59956 6.89505 8.3765 6.76758C7.91001 6.50102 7.14403 6.35156 5.99954 6.35156C4.80735 6.35156 3.89439 6.19405 3.26614 5.82324C2.94235 5.63213 2.69081 5.38245 2.52396 5.07227C2.35836 4.76428 2.29155 4.42445 2.29153 4.07422C2.29155 3.27502 2.79178 2.61916 3.4595 2.1875C4.07394 1.79032 4.87755 1.54733 5.74954 1.50781V1C5.74956 0.724025 5.97362 0.50025 6.24954 0.5Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_sign_usd_12!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcSignUsd12Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_sign_usd_12,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_sign_usd_16: ImageVector? = null
|
||||
|
||||
val Icons.ic_sign_usd_16: ImageVector
|
||||
get() {
|
||||
if (_ic_sign_usd_16 != null) return _ic_sign_usd_16!!
|
||||
_ic_sign_usd_16 = ImageVector.Builder(
|
||||
name = "ic_sign_usd_16",
|
||||
defaultWidth = 16.dp,
|
||||
defaultHeight = 16.dp,
|
||||
viewportWidth = 16f,
|
||||
viewportHeight = 16f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M8.34985 0.500183C8.626 0.500183 8.84985 0.724041 8.84985 1.00018V1.9494C9.83996 2.06353 10.7395 2.37327 11.4465 2.83026C12.3465 3.41205 12.9904 4.27563 12.9905 5.30389C12.9902 5.57981 12.7665 5.80389 12.4905 5.80389C12.2148 5.8035 11.9907 5.57957 11.9905 5.30389C11.9904 4.72855 11.6292 4.13921 10.9036 3.6701C10.1829 3.20439 9.15743 2.89963 7.99927 2.8996C6.84092 2.89965 5.81462 3.20425 5.09399 3.6701C4.36861 4.13917 4.00715 4.72866 4.00708 5.30389C4.00714 5.64045 4.07116 5.91136 4.1897 6.13202C4.30718 6.3505 4.49402 6.54862 4.78247 6.71893C5.37924 7.07105 6.39182 7.29215 7.99927 7.29218C9.6545 7.29219 10.9886 7.49914 11.9221 8.03241C12.3988 8.30481 12.7762 8.66529 13.0305 9.12518C13.2837 9.58331 13.3996 10.1119 13.3997 10.6965C13.3996 11.9549 12.7132 12.8333 11.6965 13.3683C10.912 13.7811 9.92062 13.997 8.84985 14.0695V15.0012C8.84935 15.2769 8.62569 15.5012 8.34985 15.5012C8.07411 15.5011 7.85035 15.2768 7.84985 15.0012V14.0969C6.48072 14.0739 5.22168 13.7381 4.27954 13.1799C3.3143 12.6078 2.599 11.7458 2.59888 10.6965C2.59897 10.4205 2.82293 10.1966 3.09888 10.1965C3.37496 10.1965 3.59879 10.4204 3.59888 10.6965C3.599 11.2505 3.9816 11.8408 4.78931 12.3195C5.58633 12.7917 6.72036 13.0997 7.99927 13.0998C9.31403 13.0998 10.4462 12.8963 11.2307 12.4836C11.9874 12.0853 12.3996 11.5119 12.3997 10.6965C12.3996 10.2442 12.3106 9.89022 12.1555 9.60956C12.0015 9.33094 11.7657 9.09468 11.426 8.90057C10.7262 8.50083 9.61008 8.29219 7.99927 8.29218C6.3405 8.29215 5.10608 8.07156 4.27368 7.58026C3.84786 7.32886 3.52304 7.00402 3.30884 6.60565C3.09606 6.20972 3.00714 5.76838 3.00708 5.30389C3.00715 4.2758 3.6513 3.41205 4.55103 2.83026C5.4218 2.26733 6.5853 1.92658 7.84985 1.90155V1.00018C7.84985 0.724107 8.0738 0.500291 8.34985 0.500183Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_sign_usd_16!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcSignUsd16Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_sign_usd_16,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_sign_usd_20: ImageVector? = null
|
||||
|
||||
val Icons.ic_sign_usd_20: ImageVector
|
||||
get() {
|
||||
if (_ic_sign_usd_20 != null) return _ic_sign_usd_20!!
|
||||
_ic_sign_usd_20 = ImageVector.Builder(
|
||||
name = "ic_sign_usd_20",
|
||||
defaultWidth = 20.dp,
|
||||
defaultHeight = 20.dp,
|
||||
viewportWidth = 20f,
|
||||
viewportHeight = 20f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M10.4081 1.00348C10.8683 1.00348 11.2411 1.37625 11.2411 1.83649V2.80719C12.3279 2.96265 13.3175 3.31918 14.1103 3.8316C15.1888 4.52891 15.9882 5.58131 15.9882 6.85602C15.9879 7.26976 15.6519 7.60563 15.2382 7.60602C14.8241 7.60602 14.4885 7.27 14.4882 6.85602C14.4882 6.26079 14.1135 5.61958 13.2968 5.09137C12.4873 4.56804 11.3233 4.21942 9.99991 4.2193C8.67639 4.2193 7.51269 4.56803 6.70303 5.09137C5.88581 5.61968 5.51163 6.26061 5.51163 6.85602C5.51169 7.22745 5.5823 7.51456 5.70499 7.74274C5.8259 7.9675 6.01936 8.17779 6.33292 8.36285C6.98959 8.75026 8.13378 9.00836 9.99991 9.00836C11.9375 9.00842 13.5296 9.24892 14.6571 9.89313C15.236 10.224 15.7003 10.6652 16.0136 11.232C16.3251 11.7957 16.4637 12.4406 16.4638 13.1441C16.4637 14.6856 15.6185 15.7619 14.3896 16.4088C13.5074 16.873 12.4148 17.1273 11.2411 17.2281V18.1636C11.241 18.6238 10.8683 18.9966 10.4081 18.9966C9.94794 18.9966 9.57519 18.6238 9.5751 18.1636V17.2711C8.04947 17.2094 6.64609 16.8181 5.57608 16.1841C4.42409 15.5014 3.53512 14.4506 3.53506 13.1441C3.53531 12.7301 3.871 12.3941 4.28506 12.3941C4.69899 12.3943 5.03482 12.7302 5.03506 13.1441C5.03512 13.7076 5.42489 14.3513 6.34073 14.8941C7.24034 15.4271 8.53299 15.7808 9.99991 15.7808C11.5206 15.7808 12.8106 15.5441 13.6913 15.0806C14.53 14.639 14.9637 14.021 14.9638 13.1441C14.9637 12.6389 14.8645 12.2552 14.7001 11.9576C14.5372 11.663 14.2861 11.4091 13.913 11.1959C13.136 10.7519 11.8711 10.5084 9.99991 10.5084C8.05697 10.5084 6.58032 10.2499 5.57022 9.65387C5.0509 9.34727 4.64965 8.94802 4.3837 8.45367C4.11961 7.96253 4.01169 7.41927 4.01163 6.85602C4.01163 5.5812 4.80993 4.52891 5.88858 3.8316C6.87612 3.19325 8.16901 2.79688 9.5751 2.73004V1.83649C9.5751 1.37626 9.94789 1.0035 10.4081 1.00348Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_sign_usd_20!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcSignUsd20Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_sign_usd_20,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_sign_usd_24: ImageVector? = null
|
||||
|
||||
val Icons.ic_sign_usd_24: ImageVector
|
||||
get() {
|
||||
if (_ic_sign_usd_24 != null) return _ic_sign_usd_24!!
|
||||
_ic_sign_usd_24 = ImageVector.Builder(
|
||||
name = "ic_sign_usd_24",
|
||||
defaultWidth = 24.dp,
|
||||
defaultHeight = 24.dp,
|
||||
viewportWidth = 24f,
|
||||
viewportHeight = 24f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M12.5 0.999939C13.0523 0.999967 13.5 1.4477 13.5 1.99994V3.10443C14.8543 3.29374 16.0895 3.73518 17.0791 4.37494C18.4146 5.23826 19.416 6.54999 19.4161 8.14838C19.4159 8.70042 18.9681 9.1482 18.4161 9.14838C17.8639 9.14838 17.4162 8.70053 17.4161 8.14838C17.416 7.45585 16.9801 6.69261 15.9932 6.05463C15.0164 5.42322 13.607 4.99994 11.9991 4.99994C10.3911 4.99994 8.98175 5.42322 8.00493 6.05463C7.01805 6.69261 6.5821 7.45585 6.58208 8.14838C6.58211 8.59299 6.66703 8.93094 6.80962 9.19623C6.94984 9.457 7.17592 9.70361 7.54887 9.92377C8.33404 10.3872 9.7168 10.704 11.9991 10.704C14.3767 10.704 16.3448 10.9986 17.7452 11.7988C18.4654 12.2104 19.0447 12.7607 19.4366 13.4697C19.8262 14.1748 19.999 14.9788 19.9991 15.8515C19.9991 17.7759 18.9408 19.1184 17.4141 19.9218C16.3144 20.5005 14.9553 20.8157 13.5 20.9384V21.9999C13.5 22.5522 13.0523 22.9999 12.5 22.9999C11.9478 22.9999 11.5 22.5522 11.5 21.9999V20.9882C9.61042 20.9154 7.86886 20.4334 6.53911 19.6454C5.11504 18.8015 3.99907 17.4923 3.99907 15.8515C3.99926 15.2994 4.4469 14.8515 4.99907 14.8515C5.55124 14.8515 5.99888 15.2994 5.99907 15.8515C5.99907 16.5015 6.44958 17.2674 7.55864 17.9247C8.64607 18.5691 10.214 18.9999 11.9991 18.9999C13.8561 18.9999 15.421 18.7114 16.4834 18.1523C17.4902 17.6224 17.9991 16.89 17.9991 15.8515C17.999 15.2432 17.8801 14.7877 17.6866 14.4374C17.4952 14.0912 17.1991 13.79 16.753 13.5351C15.82 13.002 14.2881 12.704 11.9991 12.704C9.61468 12.704 7.78877 12.388 6.53227 11.6464C5.88451 11.2641 5.38161 10.7641 5.0479 10.1435C4.71679 9.52759 4.58211 8.84875 4.58208 8.14838C4.5821 6.54999 5.58354 5.23826 6.91899 4.37494C8.14813 3.5804 9.75561 3.09054 11.5 3.01166V1.99994C11.5001 1.44768 11.9478 0.999939 12.5 0.999939Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_sign_usd_24!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcSignUsd24Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_sign_usd_24,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_sign_usd_28: ImageVector? = null
|
||||
|
||||
val Icons.ic_sign_usd_28: ImageVector
|
||||
get() {
|
||||
if (_ic_sign_usd_28 != null) return _ic_sign_usd_28!!
|
||||
_ic_sign_usd_28 = ImageVector.Builder(
|
||||
name = "ic_sign_usd_28",
|
||||
defaultWidth = 28.dp,
|
||||
defaultHeight = 28.dp,
|
||||
viewportWidth = 28f,
|
||||
viewportHeight = 28f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M14.5876 1.00452C15.2777 1.0047 15.8374 1.56443 15.8376 2.25452V3.48694C17.4125 3.71559 18.8499 4.23337 20.0066 4.98108C21.5882 6.00358 22.7849 7.56465 22.7849 9.4762C22.7847 10.1664 22.2251 10.7262 21.5349 10.7262C20.8448 10.7259 20.285 10.1663 20.2849 9.4762C20.2849 8.69699 19.7951 7.82152 18.6491 7.08069C17.5158 6.34805 15.875 5.85414 13.9987 5.85413C12.1226 5.85417 10.4817 6.3481 9.34836 7.08069C8.20259 7.82148 7.71262 8.69705 7.71262 9.4762C7.71265 9.98868 7.80915 10.3732 7.96945 10.6715C8.12684 10.9642 8.38265 11.2443 8.81027 11.4967C9.71464 12.0305 11.3222 12.402 13.9987 12.402C16.7945 12.402 19.1225 12.748 20.7849 13.6979C21.6414 14.1873 22.3326 14.8434 22.8005 15.6901C23.2656 16.5317 23.4704 17.489 23.4704 18.524C23.4703 20.8176 22.2069 22.4177 20.3943 23.3717C19.1089 24.0481 17.5276 24.4184 15.8376 24.567V25.7448C15.8376 26.435 15.2778 26.9946 14.5876 26.9948C13.8973 26.9948 13.3376 26.4351 13.3376 25.7448V24.6295C11.1355 24.5341 9.10475 23.9673 7.54758 23.0446C5.86321 22.0463 4.52718 20.4885 4.52707 18.524C4.52719 17.8339 5.08691 17.2742 5.77707 17.274C6.46735 17.274 7.02695 17.8338 7.02707 18.524C7.02718 19.25 7.53132 20.1292 8.82199 20.8942C10.0856 21.643 11.9134 22.1461 13.9987 22.1461C16.1739 22.1461 17.9978 21.8073 19.2302 21.1588C20.3929 20.5468 20.9703 19.7102 20.9704 18.524C20.9704 17.8194 20.832 17.2971 20.612 16.899C20.3948 16.5062 20.0581 16.1622 19.5446 15.8688C18.4665 15.2527 16.6837 14.902 13.9987 14.902C11.1946 14.902 9.03328 14.5314 7.53976 13.65C6.76873 13.1949 6.16753 12.5984 5.76828 11.8561C5.37214 11.1194 5.21265 10.3086 5.21262 9.4762C5.21262 7.56476 6.4094 6.00359 7.99094 4.98108C9.4303 4.05062 11.3048 3.47495 13.3376 3.3717V2.25452C13.3378 1.56431 13.8974 1.00452 14.5876 1.00452Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_sign_usd_28!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcSignUsd28Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_sign_usd_28,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathFillType
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.addPathNodes
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _ic_sign_usd_32: ImageVector? = null
|
||||
|
||||
val Icons.ic_sign_usd_32: ImageVector
|
||||
get() {
|
||||
if (_ic_sign_usd_32 != null) return _ic_sign_usd_32!!
|
||||
_ic_sign_usd_32 = ImageVector.Builder(
|
||||
name = "ic_sign_usd_32",
|
||||
defaultWidth = 32.dp,
|
||||
defaultHeight = 32.dp,
|
||||
viewportWidth = 32f,
|
||||
viewportHeight = 32f,
|
||||
).apply {
|
||||
addPath(
|
||||
fill = SolidColor(Color.Black),
|
||||
pathFillType = PathFillType.NonZero,
|
||||
pathData = addPathNodes("M16.6753 0.997803C17.5017 0.99781 18.1721 1.66846 18.1723 2.49487V3.86011C19.9708 4.12804 21.6136 4.72311 22.9389 5.57983C24.7677 6.76212 26.1604 8.57309 26.1606 10.7976C26.1606 11.6241 25.491 12.2945 24.6645 12.2947C23.8379 12.2946 23.1674 11.6242 23.1674 10.7976C23.1672 9.92877 22.6208 8.93841 21.3139 8.09351C20.0217 7.25819 18.1461 6.69312 15.9985 6.69312C13.8511 6.69316 11.9762 7.25828 10.6841 8.09351C9.37706 8.93843 8.82981 9.92874 8.82956 10.7976C8.82956 11.3796 8.94077 11.8116 9.1196 12.1443C9.29478 12.4701 9.57954 12.7847 10.063 13.0701C11.0888 13.6755 12.924 14.1032 15.9985 14.1033C19.2159 14.1033 21.9062 14.5002 23.8315 15.6003C24.8243 16.1677 25.6274 16.9297 26.1714 17.9138C26.712 18.8921 26.9487 20.0039 26.9487 21.2019C26.9486 23.8654 25.48 25.7229 23.3803 26.8279C21.9073 27.6031 20.1008 28.0292 18.1723 28.2039V29.5046C18.1721 30.3311 17.5018 31.0007 16.6753 31.0007C15.8488 31.0007 15.1784 30.3311 15.1782 29.5046V28.2791C12.6602 28.1615 10.3378 27.5086 8.55124 26.45C6.60512 25.2966 5.04844 23.4901 5.04831 21.2019C5.04842 20.3754 5.71888 19.7049 6.54538 19.7048C7.37193 19.7048 8.04234 20.3754 8.04245 21.2019C8.04258 22.0072 8.60283 23.0008 10.0776 23.8748C11.5199 24.7294 13.6096 25.3064 15.9985 25.3064C18.4952 25.3064 20.5809 24.9178 21.9858 24.1785C23.3074 23.4829 23.9554 22.5395 23.9555 21.2019C23.9555 20.3994 23.7983 19.8092 23.5512 19.3621C23.3075 18.9211 22.9285 18.5327 22.3462 18.2C21.1204 17.4996 19.0831 17.0964 15.9985 17.0964C12.7711 17.0964 10.2728 16.67 8.54147 15.6482C7.64675 15.12 6.94765 14.4266 6.48288 13.5623C6.02181 12.7047 5.8364 11.7623 5.8364 10.7976C5.83665 8.57302 7.23021 6.76211 9.05905 5.57983C10.7104 4.5124 12.8539 3.84952 15.1782 3.72241V2.49487C15.1784 1.66846 15.8488 0.997803 16.6753 0.997803Z"),
|
||||
)
|
||||
}.build()
|
||||
return _ic_sign_usd_32!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun IcSignUsd32Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.ic_sign_usd_32,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated.icons
|
||||
|
||||
/**
|
||||
* Auto-generated namespace for design-system icons.
|
||||
* Each icon is provided as an extension property on this object.
|
||||
*/
|
||||
object Icons
|
||||
|
|
@ -8,6 +8,8 @@ import org.joda.time.DateTimeZone
|
|||
import org.joda.time.LocalDate
|
||||
import org.joda.time.format.DateTimeFormatter
|
||||
|
||||
const val SECONDS_IN_HOUR = 3600
|
||||
|
||||
/**
|
||||
* If [this] timestamp is today or yesterday, returns relative date,
|
||||
* otherwise returns formatting date.
|
||||
|
|
|
|||
340
core/ui/token-gen/build-icons.mjs
Normal file
340
core/ui/token-gen/build-icons.mjs
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
import crypto from 'crypto';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
// ── Paths ──────────────────────────────────────────────────────────────────────
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const iconsDir = path.join(__dirname, '..', 'ds-tokens', 'icons');
|
||||
const outputDir = path.join(
|
||||
__dirname, '..', 'src', 'main', 'java', 'com', 'tangem', 'core', 'ui',
|
||||
'res', 'generated', 'icons',
|
||||
);
|
||||
|
||||
const PACKAGE = 'com.tangem.core.ui.res.generated.icons';
|
||||
|
||||
// Source SVGs use #0F0F0F as a "tint placeholder" — rewrite to Color.Black so
|
||||
// Icon(tint = …) at the call site can re-color the icon.
|
||||
const TINT_PLACEHOLDERS = new Set(['#0f0f0f', '#0F0F0F']);
|
||||
|
||||
// ── Helpers ────────────────────────────────────────────────────────────────────
|
||||
|
||||
function* walkSvgs(dir) {
|
||||
if (!fs.existsSync(dir)) return;
|
||||
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
const full = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) yield* walkSvgs(full);
|
||||
else if (entry.name.endsWith('.svg')) yield full;
|
||||
}
|
||||
}
|
||||
|
||||
/** Find an attribute value in a snippet of XML. */
|
||||
function attr(snippet, name) {
|
||||
const m = snippet.match(new RegExp(`\\b${name}="([^"]*)"`));
|
||||
return m ? m[1] : null;
|
||||
}
|
||||
|
||||
function capitalize(s) {
|
||||
return s.charAt(0).toUpperCase() + s.slice(1);
|
||||
}
|
||||
|
||||
/** Parse an SVG file into a normalized icon descriptor. */
|
||||
function parseSvg(filePath) {
|
||||
const src = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
const svgOpen = src.match(/<svg\b[^>]*>/);
|
||||
if (!svgOpen) throw new Error('No <svg> root element');
|
||||
const svgEl = svgOpen[0];
|
||||
|
||||
// Viewport / default size
|
||||
const viewBox = attr(svgEl, 'viewBox');
|
||||
let viewportW, viewportH;
|
||||
if (viewBox) {
|
||||
const parts = viewBox.split(/\s+/).map(Number);
|
||||
viewportW = parts[2];
|
||||
viewportH = parts[3];
|
||||
}
|
||||
const defaultW = parseFloat(attr(svgEl, 'width')) || viewportW;
|
||||
const defaultH = parseFloat(attr(svgEl, 'height')) || viewportH;
|
||||
viewportW = viewportW ?? defaultW;
|
||||
viewportH = viewportH ?? defaultH;
|
||||
|
||||
if (!viewportW || !viewportH) {
|
||||
throw new Error('Missing viewBox/width/height');
|
||||
}
|
||||
|
||||
// Group transforms aren't supported (would need matrix decomposition).
|
||||
if (/<g\b[^>]*\btransform=/.test(src)) {
|
||||
throw new Error('<g transform="…"> is not supported by the current generator');
|
||||
}
|
||||
|
||||
// <path .../> elements
|
||||
const paths = [];
|
||||
const pathRe = /<path\b([^>]*?)\/?>/g;
|
||||
let m;
|
||||
while ((m = pathRe.exec(src)) !== null) {
|
||||
const a = m[1];
|
||||
paths.push({
|
||||
d: attr(a, 'd'),
|
||||
fill: attr(a, 'fill'),
|
||||
fillRule: attr(a, 'fill-rule'),
|
||||
fillOpacity: attr(a, 'fill-opacity'),
|
||||
stroke: attr(a, 'stroke'),
|
||||
strokeWidth: attr(a, 'stroke-width'),
|
||||
strokeLinecap: attr(a, 'stroke-linecap'),
|
||||
strokeLinejoin: attr(a, 'stroke-linejoin'),
|
||||
opacity: attr(a, 'opacity'),
|
||||
});
|
||||
}
|
||||
|
||||
if (paths.length === 0) throw new Error('No <path> elements found');
|
||||
for (const p of paths) {
|
||||
if (!p.d) throw new Error('A <path> is missing the "d" attribute');
|
||||
}
|
||||
|
||||
return { viewportW, viewportH, defaultW, defaultH, paths };
|
||||
}
|
||||
|
||||
/**
|
||||
* ic_arrow_down_24_regular.svg →
|
||||
* { propName: 'ic_arrow_down_24', fileName: 'IcArrowDown24' }
|
||||
*/
|
||||
function deriveNames(svgFile) {
|
||||
const base = path.basename(svgFile, '.svg').replace(/_regular$/, '');
|
||||
const fileName = base
|
||||
.split('_')
|
||||
.map(part => capitalize(part))
|
||||
.join('');
|
||||
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(base)) {
|
||||
throw new Error(`Icon name "${base}" is not a valid Kotlin identifier`);
|
||||
}
|
||||
return { propName: base, fileName };
|
||||
}
|
||||
|
||||
/** Convert an SVG color string into a Compose Color expression, or null to skip. */
|
||||
function svgColorToKotlin(value) {
|
||||
if (!value || value === 'none') return null;
|
||||
if (TINT_PLACEHOLDERS.has(value.toLowerCase())) return 'Color.Black';
|
||||
|
||||
const hex6 = value.match(/^#([0-9a-fA-F]{6})$/);
|
||||
if (hex6) return `Color(0xFF${hex6[1].toUpperCase()})`;
|
||||
|
||||
const hex3 = value.match(/^#([0-9a-fA-F]{3})$/);
|
||||
if (hex3) {
|
||||
const [r, g, b] = hex3[1].toUpperCase().split('');
|
||||
return `Color(0xFF${r}${r}${g}${g}${b}${b})`;
|
||||
}
|
||||
|
||||
const hex8 = value.match(/^#([0-9a-fA-F]{8})$/);
|
||||
if (hex8) return `Color(0x${hex8[1].toUpperCase()})`;
|
||||
|
||||
const rgba = value.match(/^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d.]+)\s*\)$/);
|
||||
if (rgba) {
|
||||
const r = (+rgba[1]).toString(16).padStart(2, '0').toUpperCase();
|
||||
const g = (+rgba[2]).toString(16).padStart(2, '0').toUpperCase();
|
||||
const b = (+rgba[3]).toString(16).padStart(2, '0').toUpperCase();
|
||||
const a = Math.round(parseFloat(rgba[4]) * 255).toString(16).padStart(2, '0').toUpperCase();
|
||||
return `Color(0x${a}${r}${g}${b})`;
|
||||
}
|
||||
|
||||
if (value === 'black') return 'Color.Black';
|
||||
if (value === 'white') return 'Color.White';
|
||||
if (value === 'transparent') return 'Color.Transparent';
|
||||
|
||||
throw new Error(`Unsupported SVG color: "${value}"`);
|
||||
}
|
||||
|
||||
function renderPath(p, indent) {
|
||||
const pad = ' '.repeat(indent);
|
||||
const pad1 = ' '.repeat(indent + 1);
|
||||
const args = [];
|
||||
|
||||
// If a path has no fill at all and has stroke, leave fill out. Otherwise default to tintable black.
|
||||
const hasStroke = !!p.stroke && p.stroke !== 'none';
|
||||
const fillSpecified = p.fill != null;
|
||||
let fillKt = svgColorToKotlin(p.fill);
|
||||
if (!fillSpecified && !hasStroke) fillKt = 'Color.Black';
|
||||
if (fillKt) args.push(`fill = SolidColor(${fillKt})`);
|
||||
|
||||
if (p.fillOpacity != null) {
|
||||
args.push(`fillAlpha = ${parseFloat(p.fillOpacity)}f`);
|
||||
} else if (p.opacity != null && fillKt) {
|
||||
args.push(`fillAlpha = ${parseFloat(p.opacity)}f`);
|
||||
}
|
||||
|
||||
const strokeKt = svgColorToKotlin(p.stroke);
|
||||
if (strokeKt) args.push(`stroke = SolidColor(${strokeKt})`);
|
||||
if (p.strokeWidth != null) args.push(`strokeLineWidth = ${parseFloat(p.strokeWidth)}f`);
|
||||
if (p.strokeLinecap) args.push(`strokeLineCap = StrokeCap.${capitalize(p.strokeLinecap)}`);
|
||||
if (p.strokeLinejoin) args.push(`strokeLineJoin = StrokeJoin.${capitalize(p.strokeLinejoin)}`);
|
||||
|
||||
args.push(`pathFillType = PathFillType.${p.fillRule === 'evenodd' ? 'EvenOdd' : 'NonZero'}`);
|
||||
args.push(`pathData = addPathNodes(${JSON.stringify(p.d)})`);
|
||||
|
||||
const lines = [`${pad}addPath(`];
|
||||
for (const arg of args) lines.push(`${pad1}${arg},`);
|
||||
lines.push(`${pad})`);
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
function renderIconFile({ propName, fileName }, icon) {
|
||||
const usesStroke = icon.paths.some(p => p.stroke && p.stroke !== 'none');
|
||||
|
||||
const imports = [
|
||||
'androidx.compose.material3.Icon',
|
||||
'androidx.compose.runtime.Composable',
|
||||
'androidx.compose.ui.graphics.Color',
|
||||
'androidx.compose.ui.graphics.PathFillType',
|
||||
'androidx.compose.ui.graphics.SolidColor',
|
||||
'androidx.compose.ui.graphics.vector.ImageVector',
|
||||
'androidx.compose.ui.graphics.vector.addPathNodes',
|
||||
'androidx.compose.ui.tooling.preview.Preview',
|
||||
'androidx.compose.ui.unit.dp',
|
||||
];
|
||||
if (usesStroke) {
|
||||
imports.push('androidx.compose.ui.graphics.StrokeCap');
|
||||
imports.push('androidx.compose.ui.graphics.StrokeJoin');
|
||||
}
|
||||
imports.sort();
|
||||
|
||||
const pathBlocks = icon.paths.map(p => renderPath(p, 2)).join('\n');
|
||||
|
||||
return `@file:Suppress("all")
|
||||
|
||||
package ${PACKAGE}
|
||||
|
||||
${imports.map(i => `import ${i}`).join('\n')}
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
|
||||
private var _${propName}: ImageVector? = null
|
||||
|
||||
val Icons.${propName}: ImageVector
|
||||
get() {
|
||||
if (_${propName} != null) return _${propName}!!
|
||||
_${propName} = ImageVector.Builder(
|
||||
name = ${JSON.stringify(propName)},
|
||||
defaultWidth = ${icon.defaultW}.dp,
|
||||
defaultHeight = ${icon.defaultH}.dp,
|
||||
viewportWidth = ${icon.viewportW}f,
|
||||
viewportHeight = ${icon.viewportH}f,
|
||||
).apply {
|
||||
${pathBlocks.replace(/^/gm, ' ')}
|
||||
}.build()
|
||||
return _${propName}!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun ${fileName}Preview() {
|
||||
Icon(
|
||||
imageVector = Icons.${propName},
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
const ICONS_NAMESPACE = `@file:Suppress("all")
|
||||
|
||||
package ${PACKAGE}
|
||||
|
||||
/**
|
||||
* Auto-generated namespace for design-system icons.
|
||||
* Each icon is provided as an extension property on this object.
|
||||
*/
|
||||
object Icons
|
||||
`;
|
||||
|
||||
// ── Hash gate ──────────────────────────────────────────────────────────────────
|
||||
|
||||
function computeIconsHash() {
|
||||
const files = [...walkSvgs(iconsDir)];
|
||||
files.sort((a, b) => {
|
||||
const ra = path.relative(iconsDir, a).split(path.sep).join('/');
|
||||
const rb = path.relative(iconsDir, b).split(path.sep).join('/');
|
||||
return ra.localeCompare(rb);
|
||||
});
|
||||
const hash = crypto.createHash('sha256');
|
||||
for (const file of files) {
|
||||
hash.update(path.relative(iconsDir, file).split(path.sep).join('/'));
|
||||
hash.update('\0');
|
||||
hash.update(fs.readFileSync(file));
|
||||
hash.update('\0');
|
||||
}
|
||||
return hash.digest('hex');
|
||||
}
|
||||
|
||||
// ── Main ───────────────────────────────────────────────────────────────────────
|
||||
|
||||
export async function buildIcons() {
|
||||
console.log('\nBuilding icon vectors...');
|
||||
|
||||
const newHash = computeIconsHash();
|
||||
const hashFile = path.join(outputDir, '.icons-hash');
|
||||
if (fs.existsSync(hashFile)) {
|
||||
const prev = fs.readFileSync(hashFile, 'utf8').trim();
|
||||
if (prev === newHash) {
|
||||
console.log(` ✓ icons unchanged (${newHash.substring(0, 12)}…); skipping`);
|
||||
return { hash: newHash };
|
||||
}
|
||||
}
|
||||
|
||||
fs.mkdirSync(outputDir, { recursive: true });
|
||||
|
||||
// Parse every SVG up-front so we fail fast on errors before writing anything.
|
||||
const icons = [];
|
||||
for (const svgFile of walkSvgs(iconsDir)) {
|
||||
const names = deriveNames(svgFile);
|
||||
let parsed;
|
||||
try {
|
||||
parsed = parseSvg(svgFile);
|
||||
} catch (e) {
|
||||
throw new Error(`${path.relative(iconsDir, svgFile)}: ${e.message}`);
|
||||
}
|
||||
icons.push({ names, parsed });
|
||||
}
|
||||
|
||||
// Detect property-name collisions early.
|
||||
const seen = new Map();
|
||||
for (const { names } of icons) {
|
||||
if (seen.has(names.propName)) {
|
||||
throw new Error(
|
||||
`Duplicate icon property "${names.propName}" (file collision: ` +
|
||||
`${seen.get(names.propName)}.kt vs ${names.fileName}.kt)`,
|
||||
);
|
||||
}
|
||||
seen.set(names.propName, names.fileName);
|
||||
}
|
||||
|
||||
// Write namespace + per-icon files.
|
||||
const expectedFiles = new Set(['Icons.kt', '.icons-hash']);
|
||||
fs.writeFileSync(path.join(outputDir, 'Icons.kt'), ICONS_NAMESPACE);
|
||||
|
||||
for (const { names, parsed } of icons) {
|
||||
const file = `${names.fileName}.kt`;
|
||||
expectedFiles.add(file);
|
||||
fs.writeFileSync(path.join(outputDir, file), renderIconFile(names, parsed));
|
||||
}
|
||||
|
||||
// Cleanup stale generated files (icons that no longer have a source SVG).
|
||||
let removed = 0;
|
||||
for (const entry of fs.readdirSync(outputDir)) {
|
||||
if (!expectedFiles.has(entry) && entry.endsWith('.kt')) {
|
||||
fs.unlinkSync(path.join(outputDir, entry));
|
||||
removed++;
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(hashFile, newHash + '\n');
|
||||
const removedNote = removed > 0 ? `, removed ${removed} stale` : '';
|
||||
console.log(` ✓ ${icons.length} icon(s) (${newHash.substring(0, 12)}…${removedNote})`);
|
||||
return { hash: newHash };
|
||||
}
|
||||
|
||||
// Run directly when executed as `node build-icons.mjs`.
|
||||
if (process.argv[1] && fileURLToPath(import.meta.url) === path.resolve(process.argv[1])) {
|
||||
await buildIcons();
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import crypto from 'crypto';
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { buildIcons } from './build-icons.mjs';
|
||||
|
||||
// ── Paths ──────────────────────────────────────────────────────────────────────
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
|
@ -908,8 +909,19 @@ function computeTokensHash() {
|
|||
return hash.digest('hex');
|
||||
}
|
||||
|
||||
const tokensHash = computeTokensHash();
|
||||
// ── Build icons ───────────────────────────────────────────────────────────────
|
||||
// Run before writing .tokens-hash so the icons hash can be folded in — Gradle
|
||||
// then has a single hash that invalidates on any ds-tokens change (tokens or icons).
|
||||
const { hash: iconsHash } = await buildIcons();
|
||||
|
||||
const tokensInputHash = computeTokensHash();
|
||||
const tokensHash = crypto
|
||||
.createHash('sha256')
|
||||
.update(tokensInputHash)
|
||||
.update('\0')
|
||||
.update(iconsHash)
|
||||
.digest('hex');
|
||||
fs.writeFileSync(path.join(outputDir, '.tokens-hash'), tokensHash + '\n');
|
||||
console.log(` ✓ .tokens-hash (${tokensHash.substring(0, 12)}…)`);
|
||||
console.log(`\n ✓ .tokens-hash (${tokensHash.substring(0, 12)}…)`);
|
||||
|
||||
console.log(`\nDone! Output: ${outputDir}`);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue