Updated on 2026-08-14
This commit is contained in:
parent
1a0eaa779a
commit
654b2ff948
17 changed files with 103 additions and 36 deletions
|
|
@ -15,7 +15,6 @@ import androidx.compose.ui.draw.rotate
|
|||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
|
@ -30,10 +29,7 @@ import com.tangem.core.ui.components.TextShimmer
|
|||
import com.tangem.core.ui.components.block.BlockCard
|
||||
import com.tangem.core.ui.components.block.TangemBlockCardColors
|
||||
import com.tangem.core.ui.components.text.applyBladeBrush
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
@ -218,7 +214,7 @@ fun getBalanceValueAndFlickerState(balance: UserWalletItemUM.Balance): Pair<Stri
|
|||
is UserWalletItemUM.Balance.Failed -> DASH_SIGN to false
|
||||
is UserWalletItemUM.Balance.Hidden -> THREE_STARS to false
|
||||
is UserWalletItemUM.Balance.Loading -> null to false
|
||||
is UserWalletItemUM.Balance.Locked -> stringResource(R.string.common_locked) to false
|
||||
is UserWalletItemUM.Balance.Locked -> stringResourceSafe(R.string.common_locked) to false
|
||||
is UserWalletItemUM.Balance.Loaded -> balance.value to balance.isFlickering
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.datasource.local.nft.converter
|
||||
|
||||
import android.content.res.Resources
|
||||
import com.tangem.core.res.getStringSafe
|
||||
import com.tangem.datasource.R
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.network.Network
|
||||
|
|
@ -48,12 +49,12 @@ class NFTSdkCollectionConverter(
|
|||
is NFTCollection.Identifier.EVM ->
|
||||
name.toCollectionName()
|
||||
is NFTCollection.Identifier.TON -> if (collectionId.contractAddress == null) {
|
||||
resources.getString(R.string.nft_no_collection)
|
||||
resources.getStringSafe(R.string.nft_no_collection)
|
||||
} else {
|
||||
name.toCollectionName()
|
||||
}
|
||||
is NFTCollection.Identifier.Solana -> if (collectionId.collectionAddress == null) {
|
||||
resources.getString(R.string.nft_no_collection)
|
||||
resources.getStringSafe(R.string.nft_no_collection)
|
||||
} else {
|
||||
name.toCollectionName()
|
||||
}
|
||||
|
|
@ -61,7 +62,7 @@ class NFTSdkCollectionConverter(
|
|||
}
|
||||
|
||||
private fun String?.toCollectionName() = if (this.isNullOrEmpty()) {
|
||||
resources.getString(R.string.nft_untitled_collection)
|
||||
resources.getStringSafe(R.string.nft_untitled_collection)
|
||||
} else {
|
||||
this
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.components.PrimaryButton
|
||||
|
|
@ -40,14 +39,14 @@ internal fun NFTCollectionsEmpty(state: NFTCollectionsUM.Empty, modifier: Modifi
|
|||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(top = TangemTheme.dimens.spacing24),
|
||||
text = stringResource(R.string.nft_collections_empty_title),
|
||||
text = stringResourceSafe(R.string.nft_collections_empty_title),
|
||||
style = TangemTheme.typography.h3,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(top = TangemTheme.dimens.spacing8),
|
||||
text = stringResource(R.string.nft_collections_empty_description),
|
||||
text = stringResourceSafe(R.string.nft_collections_empty_description),
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
textAlign = TextAlign.Center,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -43,7 +42,8 @@ internal fun OnboardingNoteCreateWallet(state: OnboardingNoteCreateWalletUM, mod
|
|||
state = WalletArtworksState.Folded,
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier.weight(1 - ALL_STEPS_TOP_CONTAINER_WEIGHT)
|
||||
modifier = Modifier
|
||||
.weight(1 - ALL_STEPS_TOP_CONTAINER_WEIGHT)
|
||||
.fillMaxWidth()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(horizontal = 32.dp),
|
||||
|
|
@ -51,7 +51,7 @@ internal fun OnboardingNoteCreateWallet(state: OnboardingNoteCreateWalletUM, mod
|
|||
) {
|
||||
SpacerHMax()
|
||||
Text(
|
||||
text = stringResource(R.string.onboarding_create_wallet_header),
|
||||
text = stringResourceSafe(R.string.onboarding_create_wallet_header),
|
||||
style = TangemTheme.typography.h2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Center,
|
||||
|
|
@ -59,7 +59,7 @@ internal fun OnboardingNoteCreateWallet(state: OnboardingNoteCreateWalletUM, mod
|
|||
)
|
||||
SpacerH16()
|
||||
Text(
|
||||
text = stringResource(R.string.onboarding_create_wallet_body),
|
||||
text = stringResourceSafe(R.string.onboarding_create_wallet_body),
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
textAlign = TextAlign.Center,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
|
|
@ -134,7 +133,7 @@ private fun Content(
|
|||
} else {
|
||||
state.onAccessCodeFirstChange
|
||||
},
|
||||
label = stringResource(id = R.string.onboarding_wallet_info_title_third),
|
||||
label = stringResourceSafe(id = R.string.onboarding_wallet_info_title_third),
|
||||
isError = state.codesNotMatchError || state.atLeastMinCharsError,
|
||||
visualTransformation = if (state.accessCodeHidden) {
|
||||
PasswordVisualTransformation()
|
||||
|
|
@ -143,9 +142,9 @@ private fun Content(
|
|||
},
|
||||
caption = when {
|
||||
state.codesNotMatchError && reEnterAccessCodeState ->
|
||||
stringResource(R.string.onboarding_access_codes_doesnt_match)
|
||||
stringResourceSafe(R.string.onboarding_access_codes_doesnt_match)
|
||||
state.atLeastMinCharsError && !reEnterAccessCodeState ->
|
||||
stringResource(R.string.onboarding_access_code_too_short)
|
||||
stringResourceSafe(R.string.onboarding_access_code_too_short)
|
||||
else -> null
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ import androidx.compose.foundation.layout.*
|
|||
import androidx.compose.foundation.text.ClickableText
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.PrimaryButton
|
||||
import com.tangem.core.ui.extensions.appendColored
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.onramp.impl.R
|
||||
import com.tangem.features.onramp.main.entity.OnrampMainComponentUM
|
||||
|
|
@ -35,7 +35,7 @@ internal fun OnrampButtonComponent(state: OnrampMainComponentUM) {
|
|||
OnrampTosText(providerState)
|
||||
PrimaryButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResource(id = R.string.common_buy),
|
||||
text = stringResourceSafe(id = R.string.common_buy),
|
||||
onClick = state.buyButtonConfig.onClick,
|
||||
enabled = state.buyButtonConfig.enabled,
|
||||
)
|
||||
|
|
@ -44,9 +44,9 @@ internal fun OnrampButtonComponent(state: OnrampMainComponentUM) {
|
|||
|
||||
@Composable
|
||||
private fun OnrampTosText(provider: OnrampProviderBlockUM.Content?) {
|
||||
val termsOfUse = stringResource(R.string.common_terms_of_use)
|
||||
val privacyPolicy = stringResource(R.string.common_privacy_policy)
|
||||
val tosText = stringResource(R.string.onramp_legal, termsOfUse, privacyPolicy)
|
||||
val termsOfUse = stringResourceSafe(R.string.common_terms_of_use)
|
||||
val privacyPolicy = stringResourceSafe(R.string.common_privacy_policy)
|
||||
val tosText = stringResourceSafe(R.string.onramp_legal, termsOfUse, privacyPolicy)
|
||||
|
||||
val clickableAnnotation = buildAnnotatedString {
|
||||
append(tosText.substringBefore(termsOfUse))
|
||||
|
|
|
|||
|
|
@ -10,19 +10,19 @@ import androidx.compose.material3.Icon
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Devices
|
||||
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 com.tangem.core.ui.extensions.resourceReference
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.tooling.preview.Devices
|
||||
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 com.tangem.core.ui.components.divider.DividerWithPadding
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.walletconnect.impl.R
|
||||
|
|
@ -75,7 +75,7 @@ internal fun WcEstimatedWalletChangesItem(item: WcEstimatedWalletChangesUM, modi
|
|||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(if (isExpanded) R.string.common_show_less else R.string.common_show_more),
|
||||
text = stringResourceSafe(if (isExpanded) R.string.common_show_less else R.string.common_show_more),
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -191,6 +191,7 @@ firebase-perf = { module = "com.google.firebase:firebase-perf" }
|
|||
# region Detekt
|
||||
detekt-compose = { module = "ru.kode:detekt-rules-compose", version.ref = "detektComposeRules" }
|
||||
detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }
|
||||
detekt-api = { module = "io.gitlab.arturbosch.detekt:detekt-api", version.ref = "detekt" }
|
||||
# endregion Detekt
|
||||
|
||||
# region Test
|
||||
|
|
|
|||
|
|
@ -22,13 +22,19 @@ private fun DetektExtension.configure(project: Project) {
|
|||
ignoreFailures = false
|
||||
autoCorrect = true
|
||||
buildUponDefaultConfig = true
|
||||
config.setFrom(project.rootProject.files("tangem-android-tools/detekt-config.yml"))
|
||||
config.setFrom(
|
||||
project.rootProject.files(
|
||||
"tangem-android-tools/detekt-config.yml",
|
||||
"plugins/detekt-rules/app-detekt-config.yml"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun Project.configureDetektPlugins() {
|
||||
listOf(
|
||||
listOfNotNull(
|
||||
findLibrary(alias = "detekt-formatting"),
|
||||
findLibrary(alias = "detekt-compose"),
|
||||
findProject(":plugins:detekt-rules"),
|
||||
).forEach {
|
||||
dependencies.add(CONFIGURATION_DETEKT_PLUGINS, it)
|
||||
}
|
||||
|
|
|
|||
1
plugins/detekt-rules/.gitignore
vendored
Normal file
1
plugins/detekt-rules/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
3
plugins/detekt-rules/app-detekt-config.yml
Normal file
3
plugins/detekt-rules/app-detekt-config.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
tangem-rules:
|
||||
UnsafeStringResourceUsage:
|
||||
active: true
|
||||
7
plugins/detekt-rules/build.gradle.kts
Normal file
7
plugins/detekt-rules/build.gradle.kts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
plugins {
|
||||
alias(deps.plugins.kotlin.jvm)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(deps.detekt.api)
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.detekt
|
||||
|
||||
import com.tangem.detekt.rules.UnsafeStringResourceUsage
|
||||
import io.gitlab.arturbosch.detekt.api.Config
|
||||
import io.gitlab.arturbosch.detekt.api.RuleSet
|
||||
import io.gitlab.arturbosch.detekt.api.RuleSetProvider
|
||||
|
||||
class TangemRuleSetProvider : RuleSetProvider {
|
||||
|
||||
override val ruleSetId: String = "tangem-rules"
|
||||
|
||||
override fun instance(config: Config): RuleSet {
|
||||
return RuleSet(
|
||||
id = ruleSetId,
|
||||
rules = listOf(
|
||||
UnsafeStringResourceUsage(config),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package com.tangem.detekt.rules
|
||||
|
||||
import io.gitlab.arturbosch.detekt.api.*
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
|
||||
class UnsafeStringResourceUsage(config: Config) : Rule(config) {
|
||||
|
||||
override val issue: Issue = Issue(
|
||||
id = "UnsafeStringResourceUsage",
|
||||
severity = Severity.Security,
|
||||
description = "Avoid using stringResource directly in the code.",
|
||||
debt = Debt.FIVE_MINS,
|
||||
)
|
||||
|
||||
val unsafeFunctionNames = listOf("stringResource", "pluralStringResource")
|
||||
|
||||
override fun visitCallExpression(expression: KtCallExpression) {
|
||||
super.visitCallExpression(expression)
|
||||
|
||||
val functionName = expression.calleeExpression?.text
|
||||
if (functionName in unsafeFunctionNames) {
|
||||
report(
|
||||
CodeSmell(
|
||||
issue = issue,
|
||||
entity = Entity.from(expression),
|
||||
message = "Usage of `$functionName` is unsafe. Use the version of the function with the `Safe` " +
|
||||
"suffix. For example, `${functionName}Safe`."
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
com.tangem.detekt.TangemRuleSetProvider
|
||||
|
|
@ -134,6 +134,7 @@ dependencyResolutionManagement {
|
|||
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
|
||||
|
||||
include(":app")
|
||||
include(":plugins:detekt-rules")
|
||||
|
||||
// region Core modules
|
||||
include(":core:analytics")
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 4eb84b4150ab0b03400707a6f121d4fd313e3cef
|
||||
Subproject commit 53e359bc2ead37feeb9e70d7004c91cde07ccf9b
|
||||
Loading…
Add table
Add a link
Reference in a new issue