Updated on 2026-08-14

This commit is contained in:
Tangem 2024-12-24 17:36:59 +03:00
commit fbb99bcda0
317 changed files with 3800 additions and 2894 deletions

View file

@ -56,7 +56,7 @@ dependencies {
implementation(projects.core.deepLinks.global)
implementation(projects.core.decompose)
implementation(projects.core.datasource)
implementation(projects.core.res)
implementation(projects.libs.crypto)
implementation(projects.libs.blockchainSdk)

View file

@ -33,15 +33,9 @@ internal object WalletScreenPreviewData {
private val textContentTokensState = WalletTokensListState.ContentState.Content(
items = persistentListOf(
TokensListItemUM.NetworkGroupTitle(
id = 1,
name = stringReference("Bitcoin"),
),
TokensListItemUM.GroupTitle(id = 1, text = stringReference("Network Bitcoin")),
TokensListItemUM.Token(state = tokenItemState),
TokensListItemUM.NetworkGroupTitle(
id = 2,
name = stringReference("Ethereum"),
),
TokensListItemUM.GroupTitle(id = 2, text = stringReference("Network Ethereum")),
TokensListItemUM.Token(
state = tokenItemState.copy(
id = "2",

View file

@ -20,7 +20,6 @@ import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
@ -32,9 +31,10 @@ import com.tangem.core.ui.components.SecondaryButton
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
import com.tangem.core.ui.components.buttons.actions.RoundedActionButton
import com.tangem.core.ui.components.token.TokenItem
import com.tangem.core.ui.components.tokenlist.internal.DraggableNetworkTitleItem
import com.tangem.core.ui.components.tokenlist.internal.DraggableGroupTitleItem
import com.tangem.core.ui.event.EventEffect
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.reordarable.ReorderableItem
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
@ -176,10 +176,10 @@ private fun LazyItemScope.DraggableItem(
val modifierWithBackground = itemModifier.background(color = TangemTheme.colors.background.primary)
when (item) {
is DraggableItem.GroupHeader -> DraggableNetworkTitleItem(
modifier = modifierWithBackground,
networkName = item.networkName,
is DraggableItem.GroupHeader -> DraggableGroupTitleItem(
state = item.groupTitle,
reorderableTokenListState = reorderableState,
modifier = modifierWithBackground,
)
is DraggableItem.Token -> TokenItem(
modifier = modifierWithBackground,
@ -232,7 +232,7 @@ private fun TopBar(
contentAlignment = Alignment.CenterStart,
) {
Text(
text = stringResource(id = R.string.organize_tokens_title),
text = stringResourceSafe(id = R.string.organize_tokens_title),
style = TangemTheme.typography.subtitle1,
color = TangemTheme.colors.text.primary1,
maxLines = 1,
@ -287,12 +287,12 @@ private fun Actions(config: OrganizeTokensState.ActionsConfig, modifier: Modifie
) {
SecondaryButton(
modifier = Modifier.weight(1f),
text = stringResource(id = R.string.common_cancel),
text = stringResourceSafe(id = R.string.common_cancel),
onClick = config.onCancelClick,
)
PrimaryButton(
modifier = Modifier.weight(1f),
text = stringResource(id = R.string.common_apply),
text = stringResourceSafe(id = R.string.common_apply),
onClick = config.onApplyClick,
showProgress = config.showApplyProgress,
enabled = config.canApply,

View file

@ -2,6 +2,10 @@ package com.tangem.feature.wallet.presentation.organizetokens.model
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.components.token.state.TokenItemState
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem.RoundingMode
/**
@ -30,7 +34,16 @@ internal sealed class DraggableItem {
val networkName: String,
override val roundingMode: RoundingMode = RoundingMode.None,
override val showShadow: Boolean = false,
) : DraggableItem()
) : DraggableItem() {
val groupTitle = TokensListItemUM.GroupTitle(
id = id,
text = resourceReference(
id = R.string.wallet_network_group_title,
formatArgs = wrappedList(networkName),
),
)
}
/**
* Item for token.

View file

@ -12,7 +12,7 @@ internal sealed class WalletEvent {
data class ShowAlert(val state: WalletAlertState) : WalletEvent()
data class CopyAddress(val address: String) : WalletEvent()
data object CopyAddress : WalletEvent()
data class RateApp(val onDismissClick: () -> Unit) : WalletEvent()

View file

@ -3,7 +3,8 @@ package com.tangem.feature.wallet.presentation.wallet.state.model
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.components.token.state.TokenItemState
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.feature.wallet.impl.R
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
@ -30,7 +31,13 @@ internal sealed class WalletTokensListState {
data object Locked : ContentState() {
override val items = persistentListOf(
TokensListItemUM.NetworkGroupTitle(id = 42, name = TextReference.Res(id = R.string.main_tokens)),
TokensListItemUM.GroupTitle(
id = 42,
text = resourceReference(
id = R.string.wallet_network_group_title,
formatArgs = wrappedList(resourceReference(id = R.string.main_tokens)),
),
),
TokensListItemUM.Token(state = TokenItemState.Locked(id = "Locked#1")),
)
override val organizeTokensButtonConfig = null

View file

@ -2,7 +2,8 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers.convert
import com.tangem.common.ui.tokens.TokenItemStateConverter
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
@ -10,6 +11,7 @@ import com.tangem.domain.tokens.model.NetworkGroup
import com.tangem.domain.tokens.model.TokenList
import com.tangem.domain.tokens.model.TotalFiatBalance
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents
import com.tangem.utils.converter.Converter
@ -60,9 +62,12 @@ internal class TokenListStateConverter(
}
private fun MutableList<TokensListItemUM>.addGroup(group: NetworkGroup): List<TokensListItemUM> {
val groupTitle = TokensListItemUM.NetworkGroupTitle(
val groupTitle = TokensListItemUM.GroupTitle(
id = group.network.hashCode(),
name = stringReference(group.network.name),
text = resourceReference(
id = R.string.wallet_network_group_title,
formatArgs = wrappedList(group.network.name),
),
)
add(groupTitle)

View file

@ -1,13 +1,13 @@
package com.tangem.feature.wallet.presentation.wallet.ui
import androidx.compose.runtime.*
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.TextFieldValue
import com.tangem.core.ui.components.AdditionalTextInputDialogUM
import com.tangem.core.ui.components.BasicDialog
import com.tangem.core.ui.components.DialogButtonUM
import com.tangem.core.ui.components.TextInputDialog
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAlertState
@ -35,7 +35,7 @@ private fun BasicAlert(state: WalletAlertState.Basic, onDismiss: () -> Unit) {
},
)
dismissButton = DialogButtonUM(
title = stringResource(id = R.string.common_cancel),
title = stringResourceSafe(id = R.string.common_cancel),
onClick = onDismiss,
)
} else {
@ -75,7 +75,7 @@ private fun TextInputAlert(state: WalletAlertState.TextInput, onDismiss: () -> U
onDismissDialog = onDismiss,
onValueChange = { value = it },
title = state.title.resolveReference(),
dismissButton = DialogButtonUM(title = stringResource(id = R.string.common_cancel), onClick = onDismiss),
dismissButton = DialogButtonUM(title = stringResourceSafe(id = R.string.common_cancel), onClick = onDismiss),
textFieldParams = AdditionalTextInputDialogUM(
label = state.label.resolveReference(),
isError = state.errorTextProvider(value.text) != null,

View file

@ -5,9 +5,8 @@ import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.AnnotatedString
import com.tangem.core.res.getStringSafe
import com.tangem.core.ui.event.EventEffect
import com.tangem.core.ui.event.StateEvent
import com.tangem.core.ui.extensions.resolveReference
@ -32,7 +31,6 @@ internal fun WalletEventEffect(
val coroutineScope = rememberCoroutineScope()
val context = LocalContext.current
val resources = LocalContext.current.resources
val clipboardManager = LocalClipboardManager.current
EventEffect(
event = event,
onTrigger = { value ->
@ -46,9 +44,8 @@ internal fun WalletEventEffect(
snackbarHostState.showSnackbar(message = value.text.resolveReference(resources))
}
is WalletEvent.CopyAddress -> {
clipboardManager.setText(AnnotatedString(value.address))
snackbarHostState.showSnackbar(
message = resources.getString(R.string.wallet_notification_address_copied),
message = resources.getStringSafe(R.string.wallet_notification_address_copied),
duration = SnackbarDuration.Short,
)
}

View file

@ -33,7 +33,6 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@ -61,6 +60,7 @@ import com.tangem.core.ui.components.snackbar.CopiedTextSnackbar
import com.tangem.core.ui.components.snackbar.TangemSnackbar
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.core.ui.event.StateEvent
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.pullToRefresh.PullToRefreshConfig
import com.tangem.core.ui.res.LocalMainBottomSheetColor
import com.tangem.core.ui.res.LocalWindowSize
@ -513,7 +513,7 @@ internal fun MarketsHint(isVisible: Boolean, modifier: Modifier = Modifier) {
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = stringResource(R.string.markets_hint),
text = stringResourceSafe(R.string.markets_hint),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
textAlign = TextAlign.Center,
@ -561,12 +561,12 @@ private fun MarketsTooltipContent(modifier: Modifier = Modifier) {
horizontalAlignment = Alignment.Start,
) {
Text(
text = stringResource(id = R.string.markets_tooltip_title),
text = stringResourceSafe(id = R.string.markets_tooltip_title),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.primary1,
)
Text(
text = stringResource(id = R.string.markets_tooltip_message),
text = stringResourceSafe(id = R.string.markets_tooltip_message),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.secondary,
)

View file

@ -10,7 +10,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.SecondaryButton
@ -19,6 +18,7 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.showcase.ShowcaseContent
import com.tangem.core.ui.components.showcase.model.ShowcaseItemModel
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.core.ui.utils.requestPushPermission
@ -76,7 +76,7 @@ private fun PushNotificationsSheetContent(content: PushNotificationsBottomSheetC
),
) {
SecondaryButton(
text = stringResource(R.string.common_later),
text = stringResourceSafe(R.string.common_later),
onClick = {
content.onNeverRequest()
onDismiss()
@ -84,7 +84,7 @@ private fun PushNotificationsSheetContent(content: PushNotificationsBottomSheetC
modifier = Modifier.weight(1f),
)
PrimaryButton(
text = stringResource(R.string.common_allow),
text = stringResourceSafe(R.string.common_allow),
onClick = {
isClicked.value = true
content.onRequest()

View file

@ -30,7 +30,6 @@ import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
@ -48,6 +47,7 @@ import com.tangem.core.ui.components.ResizableText
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.stringResourceSafe
import com.tangem.core.ui.res.TangemDimens
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
@ -252,7 +252,7 @@ private fun ManageWalletContextMenu(
@Composable
private fun MenuItem(@StringRes textResId: Int, imageVector: ImageVector, onClick: () -> Unit) {
DropdownMenuItem(
text = { Text(text = stringResource(id = textResId), style = TangemTheme.typography.subtitle2) },
text = { Text(text = stringResourceSafe(id = textResId), style = TangemTheme.typography.subtitle2) },
modifier = Modifier.background(color = TangemTheme.colors.background.secondary),
trailingIcon = { Icon(imageVector = imageVector, contentDescription = null) },
onClick = onClick,

View file

@ -11,11 +11,11 @@ import androidx.compose.material3.Text
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 com.tangem.core.ui.components.tokenlist.TokenListItem
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState
@ -91,7 +91,7 @@ private fun LazyListScope.nonContentItem(modifier: Modifier = Modifier) {
)
Text(
text = stringResource(id = R.string.main_empty_tokens_list_message),
text = stringResourceSafe(id = R.string.main_empty_tokens_list_message),
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing48),
color = TangemTheme.colors.text.tertiary,
textAlign = TextAlign.Center,

View file

@ -7,6 +7,7 @@ import com.tangem.common.ui.tokens.getUnavailabilityReasonText
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent
import com.tangem.core.navigation.share.ShareManager
import com.tangem.core.ui.clipboard.ClipboardManager
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.core.ui.components.bottomsheets.chooseaddress.ChooseAddressBottomSheetConfig
@ -113,6 +114,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
private val reduxStateHolder: ReduxStateHolder,
private val vibratorHapticManager: VibratorHapticManager,
private val clipboardManager: ClipboardManager,
private val shareManager: ShareManager,
private val appRouter: AppRouter,
private val rampStateManager: RampStateManager,
private val getUserCountryUseCase: GetUserCountryUseCase,
@ -167,7 +169,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
val defaultAddress = addresses.firstOrNull()?.value ?: return null
vibratorHapticManager.performOneTime(TangemHapticEffect.OneTime.Click)
clipboardManager.setText(text = defaultAddress)
clipboardManager.setText(text = defaultAddress, isSensitive = true)
analyticsEventHandler.send(TokenReceiveAnalyticsEvent.ButtonCopyAddress(cryptoCurrency.symbol))
return resourceReference(R.string.wallet_notification_address_copied)
}
@ -184,9 +186,11 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
showMemoDisclaimer = currency.network.transactionExtrasType != Network.TransactionExtrasType.NONE,
onCopyClick = {
analyticsEventHandler.send(TokenReceiveAnalyticsEvent.ButtonCopyAddress(currency.symbol))
clipboardManager.setText(text = it, isSensitive = true)
},
onShareClick = {
analyticsEventHandler.send(TokenReceiveAnalyticsEvent.ButtonShareAddress(currency.symbol))
shareManager.shareText(text = it)
},
)
}
@ -200,12 +204,11 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
walletManagersFacade.getDefaultAddress(
userWalletId = stateHolder.getSelectedWalletId(),
network = cryptoCurrencyStatus.currency.network,
)?.let {
)?.let { address ->
stateHolder.update(CloseBottomSheetTransformer(userWalletId = stateHolder.getSelectedWalletId()))
walletEventSender.send(
event = WalletEvent.CopyAddress(address = it),
)
clipboardManager.setText(text = address, isSensitive = true)
walletEventSender.send(event = WalletEvent.CopyAddress)
}
}
}