Updated on 2026-08-14

This commit is contained in:
Tangem 2026-04-28 14:11:23 +03:00
commit 0470e1f010
1144 changed files with 48463 additions and 11166 deletions

View file

@ -13,7 +13,7 @@ object SupportedLanguages {
const val CHINESE = "zh"
const val SPANISH = "es"
val supportedLangugeCodes = listOf(
val supportedLanguageCodes = listOf(
ENGLISH,
RUSSIAN,
GERMAN,
@ -25,10 +25,17 @@ object SupportedLanguages {
SPANISH,
)
/**
* Returns the ISO 639-1 code of the device's current language when it belongs to
* [supportedLanguageCodes], otherwise falls back to [ENGLISH].
*
* Intended for callers that need a plain two-letter language code (e.g. URL path segments
* like `tangem.com/{en|ru}/...`).
*/
fun getCurrentSupportedLanguageCode(): String {
val locale = Locale.getDefault()
return if (supportedLangugeCodes.contains(locale.language)) {
return if (supportedLanguageCodes.contains(locale.language)) {
locale.language
} else {
ENGLISH

View file

@ -1,28 +0,0 @@
package com.tangem.utils
import java.util.Locale
@Deprecated("Use TangemBlogUrlBuilder from common module")
object TangemBlogUrlBuilder {
private const val RU_LOCALE = "ru"
private const val EN_LOCALE = "en"
private const val TANGEM_MAIN = "https://tangem.com/"
val FEE_BLOG_LINK: String
get(): String {
val locale = if (Locale.getDefault().language == RU_LOCALE) RU_LOCALE else EN_LOCALE
return buildString {
append(TANGEM_MAIN)
append(locale)
append("/blog/post/what-is-a-transaction-fee-and-why-do-we-need-it/")
}
}
const val RESOURCE_TO_LEARN_ABOUT_APPROVING_IN_SWAP = "https://tangem.com/en/blog/post/give-revoke-permission/"
const val YIELD_SUPPLY_HOW_IT_WORKS_URL = "https://tangem.com/en/blog/post/yield-mode"
const val YIELD_SUPPLY_TOS_URL = "https://aave.com/terms-of-service"
const val YIELD_SUPPLY_PRIVACY_URL = "https://aave.com/privacy-policy"
}

View file

@ -0,0 +1,32 @@
package com.tangem.utils.annotations
/**
* Marks code that should be removed when the specified feature toggle is cleaned up
* by the `/cleanup-feature-toggles` skill.
*
* @property toggleName the name of the feature toggle (e.g., "GASLESS_APPROVAL_ENABLED")
* @property description optional description of what should be done during cleanup
*
[REDACTED_AUTHOR]
*/
@Target(
AnnotationTarget.CLASS,
AnnotationTarget.ANNOTATION_CLASS,
AnnotationTarget.PROPERTY,
AnnotationTarget.FIELD,
AnnotationTarget.LOCAL_VARIABLE,
AnnotationTarget.VALUE_PARAMETER,
AnnotationTarget.CONSTRUCTOR,
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.TYPE,
AnnotationTarget.EXPRESSION,
AnnotationTarget.FILE,
AnnotationTarget.TYPEALIAS,
)
@Retention(AnnotationRetention.SOURCE)
annotation class RemoveWithToggle(
val toggleName: String,
val description: String = "",
)

View file

@ -1,11 +1,44 @@
package com.tangem.utils.info
/**
* Runtime information about the host application and device.
*
* Consumed by API layers to populate request headers and bodies (see
* `RequestHeader.AppVersionPlatformHeaders` and push-notification registration) and by feature
* code that needs to branch on platform / vendor.
*/
interface AppInfoProvider {
/** Platform identifier, e.g. `"Android"`. */
val platform: String
/** Human-readable device name in the form `"$MANUFACTURER $MODEL"`, e.g. `"Google Pixel 8"`. */
val device: String
/** OS release string, e.g. `"14"` on Android 14. Corresponds to `Build.VERSION.RELEASE`. */
val osVersion: String
/**
* Android API level of the running system, e.g. `34` on Android 14. Corresponds to
* `Build.VERSION.SDK_INT`. Use this (not [osVersion]) when branching by framework capability.
*/
val sdkVersion: Int
/** Current locale as a BCP 47 language tag (e.g. `"en-US"`, `"zh-CN"`). */
val language: String
/** IANA time-zone id of the device's current time zone, e.g. `"Europe/Moscow"`, `"UTC"`. */
val timezone: String
/** User-visible app version string (e.g. `"5.36.4"`), matching `BuildConfig.VERSION_NAME`. */
val appVersion: String
/** Monotonically-increasing internal build number, matching `BuildConfig.VERSION_CODE`. */
val appVersionCode: Int
/**
* `true` if the device manufacturer or brand is Huawei. Used to gate features that depend on
* Google Play Services (HMS-only devices cannot rely on FCM, Play Billing, etc.).
*/
val isHuaweiDevice: Boolean
}

View file

@ -1,8 +0,0 @@
package com.tangem.utils.version
interface AppVersionProvider {
val versionName: String
val versionCode: Int
}

View file

@ -0,0 +1,94 @@
package com.tangem.utils
import com.google.common.truth.Truth
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import java.util.Locale
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class SupportedLanguagesTest {
private lateinit var originalLocale: Locale
@BeforeEach
fun setUp() {
originalLocale = Locale.getDefault()
}
@AfterEach
fun tearDown() {
Locale.setDefault(originalLocale)
}
@Test
fun `getCurrentSupportedLanguageCode returns primary language when locale is supported`() {
// Arrange
Locale.setDefault(Locale("en", "US"))
// Act
val actual = SupportedLanguages.getCurrentSupportedLanguageCode()
// Assert
Truth.assertThat(actual).isEqualTo("en")
}
@Test
fun `getCurrentSupportedLanguageCode drops region for supported language`() {
// Arrange
Locale.setDefault(Locale("zh", "CN"))
// Act
val actual = SupportedLanguages.getCurrentSupportedLanguageCode()
// Assert
Truth.assertThat(actual).isEqualTo("zh")
}
@Test
fun `getCurrentSupportedLanguageCode returns ENGLISH when locale is not supported`() {
// Arrange — pt (Portuguese) is not in supportedLanguageCodes
Locale.setDefault(Locale("pt", "BR"))
// Act
val actual = SupportedLanguages.getCurrentSupportedLanguageCode()
// Assert
Truth.assertThat(actual).isEqualTo(SupportedLanguages.ENGLISH)
}
@Test
fun `getCurrentSupportedLanguageCode returns ENGLISH for empty language`() {
// Arrange
Locale.setDefault(Locale("", ""))
// Act
val actual = SupportedLanguages.getCurrentSupportedLanguageCode()
// Assert
Truth.assertThat(actual).isEqualTo(SupportedLanguages.ENGLISH)
}
@Test
fun `getCurrentSupportedLanguageCode supports every code in supportedLanguageCodes`() {
SupportedLanguages.supportedLanguageCodes.forEach { code ->
// Arrange
Locale.setDefault(Locale(code))
// Act
val actual = SupportedLanguages.getCurrentSupportedLanguageCode()
// Assert
Truth.assertThat(actual).isEqualTo(code)
}
}
@Test
fun `supportedLanguageCodes contains the expected nine ISO 639-1 codes`() {
// Assert
Truth.assertThat(SupportedLanguages.supportedLanguageCodes)
.containsExactly("en", "ru", "de", "fr", "it", "ja", "uk", "zh", "es")
.inOrder()
}
}