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

@ -18,13 +18,13 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.components.appbar.TangemTopAppBar
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
import com.tangem.core.ui.components.block.BlockItem
import com.tangem.core.ui.components.snackbar.TangemSnackbarHost
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.LocalSnackbarHostState
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
@ -86,7 +86,7 @@ private fun Content(
item {
Text(
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16),
text = stringResource(R.string.details_title),
text = stringResourceSafe(R.string.details_title),
style = TangemTheme.typography.h1,
color = TangemTheme.colors.text.primary1,
)
@ -127,7 +127,9 @@ private fun Block(
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.Top,
) {
val itemModifier = Modifier.fillMaxWidth().testTag(TestTags.DETAILS_SCREEN_ITEM)
val itemModifier = Modifier
.fillMaxWidth()
.testTag(TestTags.DETAILS_SCREEN_ITEM)
when (model) {
is DetailsItemUM.Basic -> {

View file

@ -7,8 +7,8 @@ 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 com.tangem.core.ui.components.block.BlockCard
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.details.impl.R
@ -37,12 +37,12 @@ internal fun WalletConnectBlock(onClick: () -> Unit, modifier: Modifier = Modifi
verticalArrangement = Arrangement.SpaceAround,
) {
Text(
text = stringResource(id = R.string.wallet_connect_title),
text = stringResourceSafe(id = R.string.wallet_connect_title),
style = TangemTheme.typography.subtitle1,
color = TangemTheme.colors.text.primary1,
)
Text(
text = stringResource(id = R.string.wallet_connect_subtitle),
text = stringResourceSafe(id = R.string.wallet_connect_subtitle),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.secondary,
)

View file

@ -1,6 +1,5 @@
package com.tangem.features.details.utils
import androidx.compose.ui.res.stringResource
import arrow.core.Either
import arrow.core.raise.Raise
import arrow.core.raise.ensureNotNull
@ -13,10 +12,7 @@ import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.navigation.popTo
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.components.SimpleOkDialog
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.isNullOrEmpty
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.message.ContentMessage
import com.tangem.core.ui.message.SnackbarMessage
import com.tangem.domain.card.ScanCardProcessor
@ -107,7 +103,7 @@ internal class UserWalletSaver @Inject constructor(
messageSender.send(
message = ContentMessage { onDismiss ->
SimpleOkDialog(
message = stringResource(id = R.string.user_wallet_list_error_wallet_already_saved),
message = stringResourceSafe(id = R.string.user_wallet_list_error_wallet_already_saved),
onDismissDialog = onDismiss,
)
},

View file

@ -16,7 +16,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.isGranted
@ -31,6 +30,7 @@ import com.tangem.core.ui.components.appbar.TangemTopAppBar
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
import com.tangem.core.ui.components.buttons.common.TangemButtonColors
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
@ -153,7 +153,7 @@ private fun BoxScope.DisclaimerButton(onAccept: (Boolean) -> Unit) {
rememberPermissionState(permission = permission).status.isGranted
} ?: true
PrimaryButton(
text = stringResource(id = R.string.common_accept),
text = stringResourceSafe(id = R.string.common_accept),
onClick = { onAccept(!isPermissionGranted) },
colors = TangemButtonColors(
backgroundColor = TangemColorPalette.Light4,

View file

@ -1,6 +1,5 @@
package com.tangem.features.managetokens.model
import androidx.compose.ui.res.stringResource
import arrow.core.getOrElse
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.decompose.di.ComponentScoped
@ -10,6 +9,7 @@ import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.components.SimpleOkDialog
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.message.ContentMessage
import com.tangem.domain.card.DerivePublicKeysUseCase
import com.tangem.domain.card.HasMissedDerivationsUseCase
@ -231,7 +231,7 @@ internal class CustomTokenFormModel @Inject constructor(
private fun showErrorDialog() {
val dialog = ContentMessage { onDismiss ->
SimpleOkDialog(
message = stringResource(R.string.common_unknown_error),
message = stringResourceSafe(R.string.common_unknown_error),
onDismissDialog = onDismiss,
)
}

View file

@ -16,7 +16,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.platform.LocalDensity
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.PreviewParameterProvider
@ -33,6 +32,7 @@ import com.tangem.core.ui.components.keyboardAsState
import com.tangem.core.ui.components.notifications.Notification
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.TangemThemePreview
import com.tangem.features.managetokens.component.preview.PreviewCustomTokenFormComponent
@ -89,7 +89,7 @@ internal fun CustomTokenFormContent(model: CustomTokenFormUM, modifier: Modifier
.align(Alignment.BottomCenter)
.padding(bottom = TangemTheme.dimens.spacing16 + bottomBarHeight)
.fillMaxWidth(),
text = stringResource(id = R.string.custom_token_add_token),
text = stringResourceSafe(id = R.string.custom_token_add_token),
colors = TangemButtonsDefaults.primaryButtonColors,
enabled = model.canAddToken,
showProgress = model.isValidating,

View file

@ -17,7 +17,6 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
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.PreviewParameterProvider
@ -28,6 +27,7 @@ import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.components.rows.ChainRow
import com.tangem.core.ui.components.rows.model.ChainRowUM
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.domain.tokens.model.Network
@ -137,7 +137,7 @@ private fun Header(header: CustomTokenSelectorUM.HeaderUM, modifier: Modifier =
modifier = Modifier
.padding(top = TangemTheme.dimens.spacing12)
.padding(horizontal = TangemTheme.dimens.spacing12),
text = stringResource(R.string.add_custom_token_choose_network),
text = stringResourceSafe(R.string.add_custom_token_choose_network),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
)
@ -189,13 +189,14 @@ private fun CustomDerivationButton(
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
) {
Text(
text = stringResource(id = R.string.custom_token_custom_derivation),
text = stringResourceSafe(id = R.string.custom_token_custom_derivation),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.secondary,
)
Text(
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12),
text = enteredDerivationPath ?: stringResource(id = R.string.custom_token_custom_derivation_title),
text = enteredDerivationPath
?: stringResourceSafe(id = R.string.custom_token_custom_derivation_title),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.primary1,
)

View file

@ -23,7 +23,6 @@ import androidx.compose.ui.draw.rotate
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
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.PreviewParameterProvider
@ -55,6 +54,7 @@ import com.tangem.core.ui.components.snackbar.TangemSnackbarHost
import com.tangem.core.ui.event.EventEffect
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.haptic.TangemHapticEffect
import com.tangem.core.ui.res.LocalHapticManager
import com.tangem.core.ui.res.LocalSnackbarHostState
@ -165,7 +165,7 @@ private fun SaveChangesButton(
label = "save_button_visibility",
) {
TangemButton(
text = stringResource(id = R.string.common_save),
text = stringResourceSafe(id = R.string.common_save),
icon = if (showIcon) {
TangemButtonIconPosition.End(R.drawable.ic_tangem_24)
} else {
@ -277,7 +277,7 @@ private fun SearchNothingFoundText(modifier: Modifier = Modifier) {
contentAlignment = Alignment.Center,
) {
Text(
text = stringResource(R.string.markets_search_token_no_result_title),
text = stringResourceSafe(R.string.markets_search_token_no_result_title),
style = TangemTheme.typography.caption1,
color = TangemTheme.colors.text.tertiary,
)

View file

@ -9,7 +9,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
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
@ -20,6 +19,7 @@ import com.tangem.core.ui.components.SecondaryButton
import com.tangem.core.ui.components.fields.SearchBar
import com.tangem.core.ui.components.snackbar.TangemSnackbarHost
import com.tangem.core.ui.event.EventEffect
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.LocalSnackbarHostState
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
@ -102,7 +102,7 @@ private fun FloatingActionButton(config: OnboardingManageTokensUM.ActionButtonCo
is OnboardingManageTokensUM.ActionButtonConfig.Continue -> ContinueButton(config = config, modifier = modifier)
is OnboardingManageTokensUM.ActionButtonConfig.Later -> SecondaryButton(
modifier = modifier,
text = stringResource(id = R.string.common_later),
text = stringResourceSafe(id = R.string.common_later),
showProgress = config.showProgress,
onClick = config.onClick,
)
@ -117,7 +117,7 @@ private fun ContinueButton(
if (config.showTangemIcon) {
PrimaryButtonIconEnd(
modifier = modifier,
text = stringResource(id = R.string.common_continue),
text = stringResourceSafe(id = R.string.common_continue),
iconResId = R.drawable.ic_tangem_24,
showProgress = config.showProgress,
onClick = config.onClick,
@ -125,7 +125,7 @@ private fun ContinueButton(
} else {
PrimaryButton(
modifier = modifier,
text = stringResource(id = R.string.common_continue),
text = stringResourceSafe(id = R.string.common_continue),
showProgress = config.showProgress,
onClick = config.onClick,
)

View file

@ -4,8 +4,8 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.managetokens.impl.R
@ -13,7 +13,7 @@ import com.tangem.features.managetokens.impl.R
internal fun AddCustomTokenDescription(modifier: Modifier = Modifier) {
Text(
modifier = modifier.fillMaxWidth(fraction = 0.7f),
text = stringResource(id = R.string.custom_token_subtitle),
text = stringResourceSafe(id = R.string.custom_token_subtitle),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.secondary,
textAlign = TextAlign.Center,

View file

@ -1,11 +1,11 @@
package com.tangem.features.managetokens.ui.dialog
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.tangem.core.ui.components.BasicDialog
import com.tangem.core.ui.components.DialogButtonUM
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.features.managetokens.impl.R
@Composable
@ -14,7 +14,7 @@ internal fun CurrencyUnsupportedDialog(title: TextReference, message: TextRefere
title = title.resolveReference(),
message = message.resolveReference(),
confirmButton = DialogButtonUM(
title = stringResource(R.string.common_ok),
title = stringResourceSafe(R.string.common_ok),
onClick = onDismiss,
),
onDismissDialog = onDismiss,

View file

@ -4,7 +4,6 @@ import android.content.res.Configuration
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberUpdatedState
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.PreviewParameterProvider
@ -12,6 +11,7 @@ import com.tangem.core.ui.components.AdditionalTextInputDialogUM
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.core.ui.res.TangemThemePreview
import com.tangem.features.managetokens.component.CustomTokenDerivationInputComponent
import com.tangem.features.managetokens.component.preview.PreviewCustomTokenDerivationInputComponent
@ -23,21 +23,21 @@ internal fun CustomDerivationInputDialog(model: CustomDerivationInputUM, onDismi
val value by rememberUpdatedState(newValue = model.value)
TextInputDialog(
title = stringResource(id = R.string.custom_token_custom_derivation_title),
title = stringResourceSafe(id = R.string.custom_token_custom_derivation_title),
fieldValue = value,
confirmButton = DialogButtonUM(
title = stringResource(id = R.string.common_ok),
title = stringResourceSafe(id = R.string.common_ok),
enabled = model.isConfirmEnabled,
onClick = model.onConfirm,
),
dismissButton = DialogButtonUM(
title = stringResource(id = R.string.common_cancel),
title = stringResourceSafe(id = R.string.common_cancel),
onClick = onDismiss,
),
onDismissDialog = onDismiss,
onValueChange = model.updateValue,
textFieldParams = AdditionalTextInputDialogUM(
label = model.error?.resolveReference() ?: stringResource(id = R.string.custom_token_derivation_path),
label = model.error?.resolveReference() ?: stringResourceSafe(id = R.string.custom_token_derivation_path),
isError = model.error != null,
),
)

View file

@ -1,9 +1,9 @@
package com.tangem.features.managetokens.ui.dialog
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.tangem.core.ui.components.BasicDialog
import com.tangem.core.ui.components.DialogButtonUM
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
import com.tangem.domain.tokens.model.Network
import com.tangem.features.managetokens.impl.R
@ -11,18 +11,18 @@ import com.tangem.features.managetokens.impl.R
@Composable
internal fun HasLinkedTokensWarning(currency: ManagedCryptoCurrency, network: Network, onDismiss: () -> Unit) {
BasicDialog(
title = stringResource(
title = stringResourceSafe(
R.string.token_details_unable_hide_alert_title,
currency.name,
),
message = stringResource(
message = stringResourceSafe(
R.string.token_details_unable_hide_alert_message,
currency.name,
currency.symbol,
network.name,
),
confirmButton = DialogButtonUM(
title = stringResource(R.string.common_ok),
title = stringResourceSafe(R.string.common_ok),
onClick = onDismiss,
),
onDismissDialog = onDismiss,

View file

@ -1,27 +1,27 @@
package com.tangem.features.managetokens.ui.dialog
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.tangem.core.ui.components.BasicDialog
import com.tangem.core.ui.components.DialogButtonUM
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
import com.tangem.features.managetokens.impl.R
@Composable
internal fun HideTokenWarning(currency: ManagedCryptoCurrency, onConfirm: () -> Unit, onDismiss: () -> Unit) {
BasicDialog(
title = stringResource(
title = stringResourceSafe(
R.string.token_details_hide_alert_title,
currency.name,
),
message = stringResource(R.string.token_details_hide_alert_message),
message = stringResourceSafe(R.string.token_details_hide_alert_message),
confirmButton = DialogButtonUM(
title = stringResource(R.string.token_details_hide_alert_hide),
title = stringResourceSafe(R.string.token_details_hide_alert_hide),
warning = true,
onClick = onConfirm,
),
dismissButton = DialogButtonUM(
title = stringResource(R.string.common_cancel),
title = stringResourceSafe(R.string.common_cancel),
onClick = onDismiss,
),
onDismissDialog = onDismiss,

View file

@ -152,7 +152,7 @@ internal class ManageTokensUiManager(
private fun copyContractAddress(source: ManagedCryptoCurrency.SourceNetwork) {
if (source is ManagedCryptoCurrency.SourceNetwork.Default) {
clipboardManager.setText(text = source.contractAddress)
clipboardManager.setText(text = source.contractAddress, isSensitive = false)
showSnackbarMessage(resourceReference(R.string.contract_address_copied_message))
}
}

View file

@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle
@ -15,6 +14,7 @@ import com.tangem.core.ui.components.TextShimmer
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.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.utils.PreviewShimmerContainer
@ -34,7 +34,12 @@ internal fun Description(
append(description.resolveReference())
}
withStyle(SpanStyle(color = TangemTheme.colors.text.accent)) {
append(" " + stringResource(R.string.common_read_more).replace(' ', StringsSigns.NON_BREAKING_SPACE))
append(
" " + stringResourceSafe(R.string.common_read_more).replace(
' ',
StringsSigns.NON_BREAKING_SPACE,
),
)
}
}

View file

@ -10,7 +10,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
@ -27,10 +26,7 @@ import com.tangem.core.ui.components.buttons.SmallButtonConfig
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.components.token.TokenItem
import com.tangem.core.ui.components.token.state.TokenItemState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.markets.details.impl.ui.state.ExchangesBottomSheetContent
@ -92,7 +88,7 @@ internal fun ExchangesBottomSheet(config: TangemBottomSheetConfig) {
@Composable
private fun Title(@StringRes textResId: Int, onBackClick: () -> Unit) {
TangemTopAppBar(
title = stringResource(id = textResId),
title = stringResourceSafe(id = textResId),
startButton = TopAppBarButtonUM.Back(onBackClicked = onBackClick),
)
}
@ -128,7 +124,7 @@ private fun Error(content: ExchangesBottomSheetContent.Error, modifier: Modifier
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = stringResource(id = content.message),
text = stringResourceSafe(id = content.message),
color = TangemTheme.colors.text.tertiary,
textAlign = TextAlign.Center,
style = TangemTheme.typography.caption1,

View file

@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.*
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@ -16,6 +15,7 @@ import com.tangem.core.ui.components.block.information.InformationBlock
import com.tangem.core.ui.components.buttons.chip.Chip
import com.tangem.core.ui.components.inputrow.inner.DividerContainer
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.TangemThemePreview
import com.tangem.core.ui.utils.PreviewShimmerContainer
@ -31,7 +31,7 @@ internal fun LinksBlock(state: LinksUM, modifier: Modifier = Modifier) {
contentHorizontalPadding = 0.dp,
title = {
Text(
text = stringResource(id = R.string.markets_token_details_links),
text = stringResourceSafe(id = R.string.markets_token_details_links),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
maxLines = 1,
@ -41,22 +41,22 @@ internal fun LinksBlock(state: LinksUM, modifier: Modifier = Modifier) {
content = {
Column {
SubBlock(
title = stringResource(id = R.string.markets_token_details_official_links),
title = stringResourceSafe(id = R.string.markets_token_details_official_links),
links = state.officialLinks,
onLinkClick = state.onLinkClick,
)
SubBlock(
title = stringResource(id = R.string.markets_token_details_social),
title = stringResourceSafe(id = R.string.markets_token_details_social),
links = state.social,
onLinkClick = state.onLinkClick,
)
SubBlock(
title = stringResource(id = R.string.markets_token_details_repository),
title = stringResourceSafe(id = R.string.markets_token_details_repository),
links = state.repository,
onLinkClick = state.onLinkClick,
)
SubBlock(
title = stringResource(id = R.string.markets_token_details_blockchain_site),
title = stringResourceSafe(id = R.string.markets_token_details_blockchain_site),
links = state.blockchainSite,
onLinkClick = state.onLinkClick,
lastBlock = true,

View file

@ -1,11 +1,12 @@
package com.tangem.features.markets.details.impl.ui.components
import android.content.res.Configuration
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.components.TextButton
@ -14,6 +15,7 @@ import com.tangem.core.ui.components.block.information.GridItems
import com.tangem.core.ui.components.block.information.InformationBlock
import com.tangem.core.ui.components.buttons.common.TangemButtonsDefaults
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.PreviewShimmerContainer
@ -33,7 +35,7 @@ internal fun MetricsBlock(state: MetricsUM, modifier: Modifier = Modifier) {
modifier = modifier,
title = {
Text(
text = stringResource(id = R.string.markets_token_details_metrics),
text = stringResourceSafe(id = R.string.markets_token_details_metrics),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
maxLines = 1,

View file

@ -2,14 +2,12 @@ package com.tangem.features.markets.details.impl.ui.components
import android.content.res.Configuration
import androidx.compose.foundation.layout.*
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
@ -21,13 +19,14 @@ import com.tangem.core.ui.components.block.information.InformationBlock
import com.tangem.core.ui.components.buttons.segmentedbutton.SegmentedButtons
import com.tangem.core.ui.components.progressbar.LinearProgressIndicator
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemAnimations
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.utils.PreviewShimmerContainer
import com.tangem.domain.markets.PriceChangeInterval
import com.tangem.features.markets.details.impl.ui.state.PricePerformanceUM
import com.tangem.features.markets.details.impl.ui.getText
import com.tangem.features.markets.details.impl.ui.state.PricePerformanceUM
import com.tangem.features.markets.impl.R
import kotlinx.collections.immutable.persistentListOf
@ -39,7 +38,7 @@ internal fun PricePerformanceBlock(state: PricePerformanceUM, modifier: Modifier
modifier = modifier,
title = {
Text(
text = stringResource(id = R.string.markets_token_details_price_performance),
text = stringResourceSafe(id = R.string.markets_token_details_price_performance),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
maxLines = 1,
@ -106,13 +105,13 @@ private fun Content(state: PricePerformanceUM.Value, modifier: Modifier = Modifi
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text(
text = stringResource(R.string.markets_token_details_low),
text = stringResourceSafe(R.string.markets_token_details_low),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
)
SpacerW8()
Text(
text = stringResource(R.string.markets_token_details_high),
text = stringResourceSafe(R.string.markets_token_details_high),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
)

View file

@ -130,7 +130,7 @@ internal class TokenActionsHandler @AssistedInject constructor(
.toImmutableList()
val defaultAddress = addresses.firstOrNull()?.value ?: return
clipboardManager.setText(text = defaultAddress)
clipboardManager.setText(text = defaultAddress, isSensitive = true)
uiMessageSender.send(SnackbarMessage(resourceReference(R.string.wallet_notification_address_copied)))
}

View file

@ -17,7 +17,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.layout.onGloballyPositioned
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
@ -37,6 +36,7 @@ import com.tangem.core.ui.components.currency.icon.CoinIcon
import com.tangem.core.ui.components.rows.ArrowRow
import com.tangem.core.ui.components.rows.BlockchainRow
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.haptic.TangemHapticEffect
import com.tangem.core.ui.res.LocalHapticManager
import com.tangem.core.ui.res.TangemTheme
@ -154,7 +154,7 @@ private fun ContinueButton(
)
.navigationBarsPadding()
.fillMaxWidth(),
text = stringResource(R.string.common_continue),
text = stringResourceSafe(R.string.common_continue),
icon = if (enabled && isTangemIconVisible) {
TangemButtonIconPosition.End(R.drawable.ic_tangem_24)
} else {
@ -178,7 +178,7 @@ private fun NetworkSelection(state: SelectNetworkUM, modifier: Modifier = Modifi
modifier = modifier,
title = {
Text(
text = stringResource(R.string.markets_select_network),
text = stringResourceSafe(R.string.markets_select_network),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
)
@ -279,7 +279,7 @@ private fun ScanWalletWarning(modifier: Modifier = Modifier) {
contentDescription = null,
)
Text(
text = stringResource(R.string.markets_generate_addresses_notification),
text = stringResourceSafe(R.string.markets_generate_addresses_notification),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
)

View file

@ -10,7 +10,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.key
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.util.fastForEachIndexed
@ -24,6 +23,7 @@ import com.tangem.core.ui.components.buttons.SecondarySmallButton
import com.tangem.core.ui.components.buttons.SmallButtonConfig
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
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.markets.impl.R
@ -68,7 +68,7 @@ internal fun MyPortfolio(state: MyPortfolioUM, modifier: Modifier = Modifier) {
@Composable
private fun Title() {
Text(
text = stringResource(R.string.markets_common_my_portfolio),
text = stringResourceSafe(R.string.markets_common_my_portfolio),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
)
@ -150,7 +150,7 @@ fun UnavailableAssetForWallet(modifier: Modifier = Modifier) {
private fun UnavailableContent(@StringRes textId: Int, modifier: Modifier = Modifier) {
Text(
modifier = modifier,
text = stringResource(textId),
text = stringResourceSafe(textId),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,
)
@ -163,14 +163,14 @@ private fun AddFirstTokenContent(state: MyPortfolioUM.AddFirstToken, modifier: M
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
) {
Text(
text = stringResource(R.string.markets_add_to_my_portfolio_description),
text = stringResourceSafe(R.string.markets_add_to_my_portfolio_description),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,
)
PrimaryButton(
modifier = Modifier.fillMaxWidth(),
text = stringResource(R.string.markets_add_to_portfolio_button),
text = stringResourceSafe(R.string.markets_add_to_portfolio_button),
onClick = state.onAddClick,
)
}

View file

@ -1,12 +1,12 @@
package com.tangem.features.markets.portfolio.impl.ui
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.tangem.core.ui.components.BasicDialog
import com.tangem.core.ui.components.DialogButtonUM
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.features.markets.impl.R
@Composable
@ -19,7 +19,7 @@ internal fun WarningDialog(
title = title.resolveReference(),
message = message.resolveReference(),
confirmButton = DialogButtonUM(
title = stringResource(R.string.common_ok),
title = stringResourceSafe(R.string.common_ok),
onClick = onDismiss,
),
onDismissDialog = onDismiss,

View file

@ -9,7 +9,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.common.ui.charts.MarketChartMini
@ -21,6 +20,7 @@ import com.tangem.core.ui.components.TextShimmer
import com.tangem.core.ui.components.block.BlockCard
import com.tangem.core.ui.components.marketprice.PriceChangeInPercent
import com.tangem.core.ui.components.marketprice.PriceChangeType
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.markets.details.impl.model.formatter.toChartType
@ -75,7 +75,7 @@ private fun LeftSide(
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4),
) {
Text(
text = stringResource(id = R.string.wallet_marketplace_block_title, symbol),
text = stringResourceSafe(id = R.string.wallet_marketplace_block_title, symbol),
color = TangemTheme.colors.text.tertiary,
style = TangemTheme.typography.subtitle2,
)
@ -99,7 +99,7 @@ private fun LeftSide(
)
Text(
modifier = Modifier.alignByBaseline(),
text = stringResource(id = R.string.wallet_marketprice_block_update_time),
text = stringResourceSafe(id = R.string.wallet_marketprice_block_update_time),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,
)

View file

@ -15,7 +15,6 @@ import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
@ -33,6 +32,7 @@ import com.tangem.core.ui.components.keyboardAsState
import com.tangem.core.ui.event.consumedEvent
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.LocalMainBottomSheetColor
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
@ -149,9 +149,9 @@ private fun Title(isInSearchMode: Boolean, modifier: Modifier = Modifier) {
Text(
modifier = modifier,
text = if (isInSearchMode) {
stringResource(id = R.string.markets_search_result_title)
stringResourceSafe(id = R.string.markets_search_result_title)
} else {
stringResource(id = R.string.markets_common_title)
stringResourceSafe(id = R.string.markets_common_title)
},
style = TangemTheme.typography.h3,
color = TangemTheme.colors.text.primary1,

View file

@ -10,12 +10,12 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import com.tangem.core.ui.components.buttons.SecondarySmallButton
import com.tangem.core.ui.components.buttons.SmallButtonConfig
import com.tangem.core.ui.components.list.InfiniteListHandler
import com.tangem.core.ui.event.EventEffect
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.markets.impl.R
import com.tangem.features.markets.tokenlist.impl.ui.state.ListUM
@ -160,7 +160,7 @@ private fun ShowTokensUnder100kItem(onShowTokensClick: () -> Unit, modifier: Mod
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = stringResource(R.string.markets_search_see_tokens_under_100k),
text = stringResourceSafe(R.string.markets_search_see_tokens_under_100k),
style = TangemTheme.typography.caption1,
color = TangemTheme.colors.text.tertiary,
)
@ -180,7 +180,7 @@ private fun SearchNothingFoundText(modifier: Modifier = Modifier) {
contentAlignment = Alignment.Center,
) {
Text(
text = stringResource(R.string.markets_search_token_no_result_title),
text = stringResourceSafe(R.string.markets_search_token_no_result_title),
style = TangemTheme.typography.caption1,
color = TangemTheme.colors.text.tertiary,
)

View file

@ -7,11 +7,11 @@ 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.tooling.preview.Preview
import com.tangem.core.ui.components.buttons.SecondarySmallButton
import com.tangem.core.ui.components.buttons.SmallButtonConfig
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.markets.impl.R
@ -24,7 +24,7 @@ internal fun UnableToLoadData(onRetryClick: () -> Unit, modifier: Modifier = Mod
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = stringResource(R.string.markets_loading_error_title),
text = stringResourceSafe(R.string.markets_loading_error_title),
style = TangemTheme.typography.caption1,
color = TangemTheme.colors.text.tertiary,
)

View file

@ -8,8 +8,8 @@ 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.res.stringResource
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.dp
import com.airbnb.lottie.compose.LottieAnimation
@ -17,6 +17,7 @@ import com.airbnb.lottie.compose.LottieCompositionSpec
import com.airbnb.lottie.compose.animateLottieCompositionAsState
import com.airbnb.lottie.compose.rememberLottieComposition
import com.tangem.core.ui.components.*
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.onboarding.v2.impl.R
@ -49,16 +50,17 @@ internal fun OnboardingDone(onContinueClick: () -> Unit, modifier: Modifier = Mo
SpacerH32()
Text(
modifier = Modifier.padding(horizontal = 32.dp),
text = stringResource(R.string.onboarding_done_header),
text = stringResourceSafe(R.string.onboarding_done_header),
style = TangemTheme.typography.h2,
color = TangemTheme.colors.text.primary1,
)
SpacerH12()
Text(
modifier = Modifier.padding(horizontal = 32.dp),
text = stringResource(R.string.onboarding_subtitle_success_tangem_wallet_onboarding),
text = stringResourceSafe(R.string.onboarding_subtitle_success_tangem_wallet_onboarding),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.secondary,
textAlign = TextAlign.Center,
)
SpacerH(72.dp)
}
@ -69,7 +71,7 @@ internal fun OnboardingDone(onContinueClick: () -> Unit, modifier: Modifier = Mo
.padding(horizontal = 16.dp)
.padding(bottom = 16.dp)
.navigationBarsPadding(),
text = stringResource(R.string.onboarding_button_continue_wallet),
text = stringResourceSafe(R.string.onboarding_button_continue_wallet),
onClick = onContinueClick,
)
}

View file

@ -33,6 +33,7 @@ import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.MultiWall
import com.tangem.features.onboarding.v2.multiwallet.impl.child.chooseoption.Wallet1ChooseOptionComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.MultiWalletCreateWalletComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.MultiWalletFinalizeComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.scanprimary.Wallet1ScanPrimaryComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.MultiWalletSeedPhraseComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletModel
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletState
@ -59,6 +60,7 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
CreateWallet -> WalletArtworksState.Folded
ChooseBackupOption -> WalletArtworksState.Fan
SeedPhrase -> WalletArtworksState.Folded
ScanPrimary -> WalletArtworksState.Folded
AddBackupDevice -> WalletArtworksState.Unfold(WalletArtworksState.Unfold.Step.First)
Finalize -> WalletArtworksState.Stack()
Done -> error("Done state should not be used as starting state")
@ -93,11 +95,14 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
)
val backButtonClickFlow = MutableSharedFlow<Unit>()
override val innerNavigation: InnerNavigation = object : InnerNavigation {
override val state = innerNavigationStateFlow
override fun pop(onComplete: (Boolean) -> Unit) {
if (childStack.active.configuration == SeedPhrase) {
val config = childStack.active.configuration
if (config == SeedPhrase || config == Finalize) {
componentScope.launch { backButtonClickFlow.emit(Unit) }
} else {
model.onBack()
@ -152,6 +157,11 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
backButtonClickFlow = backButtonClickFlow,
onBack = { stackNavigation.pop() },
)
ScanPrimary -> Wallet1ScanPrimaryComponent(
context = childContext,
params = childParams,
onDone = { handleNavigationEvent(AddBackupDevice) },
)
AddBackupDevice -> MultiWalletBackupComponent(
context = childContext,
params = childParams,
@ -160,6 +170,8 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
Finalize -> MultiWalletFinalizeComponent(
context = childContext,
params = childParams,
backButtonClickFlow = backButtonClickFlow,
onBack = { model.onBack() },
onEvent = ::handleFinalizeComponentEvent,
)
Done -> error("Unexpected Done state")

View file

@ -1,5 +1,6 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.accesscode.model
import androidx.compose.runtime.Stable
import androidx.compose.ui.text.input.TextFieldValue
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.decompose.di.ComponentScoped
@ -20,6 +21,7 @@ import javax.inject.Inject
private const val MINIMUM_ACCESS_CODE_LENGTH = 4
@Stable
@ComponentScoped
internal class MultiWalletAccessCodeModel @Inject constructor(
paramsContainer: ParamsContainer,

View file

@ -4,12 +4,12 @@ import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemAnimations
import com.tangem.features.onboarding.v2.impl.R
import com.tangem.features.onboarding.v2.multiwallet.impl.child.accesscode.ui.state.MultiWalletAccessCodeUM
@ -65,9 +65,9 @@ private fun Content(state: MultiWalletAccessCodeUM, modifier: Modifier = Modifie
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
.imePadding(),
text = if (state.step == ConfirmAccessCode) {
stringResource(R.string.common_confirm)
stringResourceSafe(R.string.common_confirm)
} else {
stringResource(R.string.common_continue)
stringResourceSafe(R.string.common_continue)
},
onClick = state.onContinue,
)

View file

@ -1,6 +1,9 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.accesscode.ui
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
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.runtime.LaunchedEffect
@ -9,12 +12,12 @@ 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.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.OutlineTextFieldWithIcon
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.onboarding.v2.impl.R
@ -35,17 +38,17 @@ internal fun MultiWalletAccessCodeEnter(
) {
Text(
text = if (reEnterAccessCodeState) {
stringResource(R.string.onboarding_access_code_repeat_code_title)
stringResourceSafe(R.string.onboarding_access_code_repeat_code_title)
} else {
stringResource(R.string.onboarding_access_code_intro_title)
stringResourceSafe(R.string.onboarding_access_code_intro_title)
},
style = TangemTheme.typography.subtitle1,
)
Text(
text = if (reEnterAccessCodeState) {
stringResource(R.string.onboarding_access_code_repeat_code_hint)
stringResourceSafe(R.string.onboarding_access_code_repeat_code_hint)
} else {
stringResource(R.string.onboarding_access_code_hint)
stringResourceSafe(R.string.onboarding_access_code_hint)
},
style = TangemTheme.typography.body1,
)
@ -73,7 +76,7 @@ internal fun MultiWalletAccessCodeEnter(
} 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.atLeast4CharError,
visualTransformation = if (state.accessCodeHidden) {
PasswordVisualTransformation()
@ -82,9 +85,9 @@ internal fun MultiWalletAccessCodeEnter(
},
caption = when {
state.codesNotMatchError && reEnterAccessCodeState ->
stringResource(R.string.onboarding_access_codes_doesnt_match)
stringResourceSafe(R.string.onboarding_access_codes_doesnt_match)
state.atLeast4CharError && !reEnterAccessCodeState ->
stringResource(R.string.onboarding_access_code_too_short)
stringResourceSafe(R.string.onboarding_access_code_too_short)
else -> null
},
)

View file

@ -8,12 +8,12 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.components.SpacerW
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.onboarding.v2.impl.R
@ -26,7 +26,7 @@ internal fun MultiWalletAccessCodeIntro(modifier: Modifier = Modifier) {
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
Text(
text = stringResource(R.string.onboarding_access_code_intro_title),
text = stringResourceSafe(R.string.onboarding_access_code_intro_title),
style = TangemTheme.typography.h2,
)
Icon(
@ -41,18 +41,18 @@ internal fun MultiWalletAccessCodeIntro(modifier: Modifier = Modifier) {
verticalArrangement = Arrangement.spacedBy(24.dp),
) {
DescriptionItem(
title = stringResource(R.string.onboarding_access_code_feature_1_title),
body = stringResource(R.string.onboarding_access_code_feature_1_description),
title = stringResourceSafe(R.string.onboarding_access_code_feature_1_title),
body = stringResourceSafe(R.string.onboarding_access_code_feature_1_description),
iconRes = R.drawable.ic_feature_1,
)
DescriptionItem(
title = stringResource(R.string.onboarding_access_code_feature_2_title),
body = stringResource(R.string.onboarding_access_code_feature_2_description),
title = stringResourceSafe(R.string.onboarding_access_code_feature_2_title),
body = stringResourceSafe(R.string.onboarding_access_code_feature_2_description),
iconRes = R.drawable.ic_feature_2,
)
DescriptionItem(
title = stringResource(R.string.onboarding_access_code_feature_3_title),
body = stringResource(R.string.onboarding_access_code_feature_3_description),
title = stringResourceSafe(R.string.onboarding_access_code_feature_3_title),
body = stringResourceSafe(R.string.onboarding_access_code_feature_3_description),
iconRes = R.drawable.ic_feature_3,
)
}

View file

@ -8,8 +8,8 @@ import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.features.onboarding.v2.impl.R
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.model.MultiWalletBackupModel
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.ui.MultiWalletBackup
import kotlinx.coroutines.flow.update

View file

@ -1,5 +1,6 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.model
import androidx.compose.runtime.Stable
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemSdkError
@ -28,6 +29,7 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject
@Stable
@ComponentScoped
class MultiWalletBackupModel @Inject constructor(
paramsContainer: ParamsContainer,
@ -82,15 +84,16 @@ class MultiWalletBackupModel @Inject constructor(
}
private fun startBackupWallet() {
if (state.value.numberOfBackupCards == 0) {
if (state.value.numberOfBackupCards == 0 && scanResponse.primaryCard != null) {
backupService.discardSavedBackup()
}
val primaryCard = scanResponse.primaryCard
val primaryCard = scanResponse.primaryCard
if (primaryCard != null) {
backupService.setPrimaryCard(primaryCard)
addBackupCardWithService()
}
addBackupCardWithService()
}
private fun setNumberOfBackupCards(number: Int) {

View file

@ -1,17 +1,22 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.ui
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
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
import com.tangem.core.ui.components.*
import com.tangem.core.ui.components.BasicDialog
import com.tangem.core.ui.components.DialogButtonUM
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.SecondaryButtonIconEnd
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.TangemThemePreview
import com.tangem.features.onboarding.v2.impl.R
@ -55,7 +60,8 @@ private fun ColumnScope.Content(state: MultiWalletBackupUM) {
Column(
Modifier
.fillMaxWidth()
.padding(start = 32.dp, end = 32.dp, bottom = 74.dp)
.verticalScroll(rememberScrollState())
.padding(start = 32.dp, end = 32.dp, bottom = 16.dp)
.weight(1f),
horizontalAlignment = Alignment.CenterHorizontally,
) {
@ -83,7 +89,7 @@ private fun ColumnScope.Content(state: MultiWalletBackupUM) {
iconResId = R.drawable.ic_tangem_24,
enabled = state.addBackupButtonEnabled,
showProgress = state.addBackupButtonLoading,
text = stringResource(R.string.onboarding_button_add_backup_card),
text = stringResourceSafe(R.string.onboarding_button_add_backup_card),
onClick = state.onAddBackupClick,
)
@ -91,7 +97,7 @@ private fun ColumnScope.Content(state: MultiWalletBackupUM) {
modifier = Modifier
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
.fillMaxWidth(),
text = stringResource(R.string.onboarding_button_finalize_backup),
text = stringResourceSafe(R.string.onboarding_button_finalize_backup),
enabled = state.finalizeButtonEnabled,
onClick = state.onFinalizeButtonClick,
)

View file

@ -32,7 +32,7 @@ class Wallet1ChooseOptionComponent(
}
params.parentParams.titleProvider.changeTitle(
text = resourceReference(R.string.onboarding_create_wallet_header),
text = resourceReference(R.string.onboarding_getting_started),
)
componentScope.launch {
@ -45,6 +45,7 @@ class Wallet1ChooseOptionComponent(
@Composable
override fun Content(modifier: Modifier) {
Wallet1ChooseOption(
canSkipBackup = model.canSkipBackup,
onBackupClick = {
onNextStep(OnboardingMultiWalletState.Step.AddBackupDevice)
},

View file

@ -1,10 +1,12 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.chooseoption.model
import androidx.compose.runtime.Stable
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.decompose.di.ComponentScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.domain.card.repository.CardRepository
import com.tangem.domain.common.TapWorkarounds.canSkipBackup
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.builder.UserWalletBuilder
import com.tangem.domain.wallets.models.UserWallet
@ -18,6 +20,7 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject
@Stable
@ComponentScoped
internal class Wallet1ChooseOptionModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider,
@ -36,6 +39,8 @@ internal class Wallet1ChooseOptionModel @Inject constructor(
analyticsHandler.send(OnboardingEvent.Backup.ScreenOpened)
}
val canSkipBackup = params.multiWalletState.value.currentScanResponse.card.canSkipBackup
fun onSkipClick() {
if (skipClicked) return
skipClicked = true

View file

@ -1,20 +1,29 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.chooseoption.ui
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
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
import com.tangem.core.ui.components.PrimaryButtonIconEnd
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.SecondaryButton
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.onboarding.v2.impl.R
@Composable
fun Wallet1ChooseOption(onSkipClick: () -> Unit, onBackupClick: () -> Unit, modifier: Modifier = Modifier) {
fun Wallet1ChooseOption(
canSkipBackup: Boolean,
onSkipClick: () -> Unit,
onBackupClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.fillMaxSize()
@ -26,12 +35,13 @@ fun Wallet1ChooseOption(onSkipClick: () -> Unit, onBackupClick: () -> Unit, modi
Column(
Modifier
.fillMaxWidth()
.padding(start = 32.dp, end = 32.dp, bottom = 24.dp)
.verticalScroll(rememberScrollState())
.padding(start = 32.dp, end = 32.dp, bottom = 16.dp)
.weight(1f),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = stringResource(R.string.onboarding_create_wallet_header),
text = stringResourceSafe(R.string.onboarding_wallet_info_title_first),
style = TangemTheme.typography.h2,
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.Center,
@ -39,7 +49,7 @@ fun Wallet1ChooseOption(onSkipClick: () -> Unit, onBackupClick: () -> Unit, modi
)
Text(
text = stringResource(R.string.onboarding_create_wallet_body),
text = stringResourceSafe(R.string.onboarding_wallet_info_subtitle_first),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.secondary,
textAlign = TextAlign.Center,
@ -47,21 +57,35 @@ fun Wallet1ChooseOption(onSkipClick: () -> Unit, onBackupClick: () -> Unit, modi
)
}
PrimaryButtonIconEnd(
PrimaryButton(
modifier = Modifier
.padding(start = 16.dp, end = 16.dp, bottom = 12.dp)
.fillMaxWidth(),
iconResId = R.drawable.ic_tangem_24,
text = stringResource(R.string.onboarding_button_backup_now),
text = stringResourceSafe(R.string.onboarding_button_backup_now),
onClick = onBackupClick,
)
SecondaryButton(
modifier = Modifier
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
.fillMaxWidth(),
text = stringResource(R.string.onboarding_button_skip_backup),
onClick = onSkipClick,
if (canSkipBackup) {
SecondaryButton(
modifier = Modifier
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
.fillMaxWidth(),
text = stringResourceSafe(R.string.onboarding_button_skip_backup),
onClick = onSkipClick,
)
}
}
}
@Preview(showBackground = true)
@Composable
private fun Preview() {
TangemThemePreview {
Wallet1ChooseOption(
canSkipBackup = true,
onSkipClick = {},
onBackupClick = {},
modifier = Modifier.fillMaxSize(),
)
}
}

View file

@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.arkivanov.essenty.lifecycle.doOnStart
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.extensions.resourceReference
@ -25,17 +26,19 @@ internal class MultiWalletCreateWalletComponent(
private val model: MultiWalletCreateWalletModel = getOrCreateModel(params)
init {
params.innerNavigation.update {
it.copy(
stackSize = 2,
stackMaxSize = 8,
lifecycle.doOnStart {
params.innerNavigation.update {
it.copy(
stackSize = 2,
stackMaxSize = 8,
)
}
params.parentParams.titleProvider.changeTitle(
text = resourceReference(R.string.onboarding_create_wallet_header),
)
}
params.parentParams.titleProvider.changeTitle(
text = resourceReference(R.string.onboarding_create_wallet_header),
)
componentScope.launch {
model.onDone.collect(onNextStep)
}

View file

@ -1,5 +1,6 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.model
import androidx.compose.runtime.Stable
import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemSdkError
import com.tangem.core.analytics.api.AnalyticsEventHandler
@ -11,12 +12,17 @@ import com.tangem.domain.card.repository.CardRepository
import com.tangem.domain.feedback.GetCardInfoUseCase
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
import com.tangem.domain.feedback.models.FeedbackEmailType
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.builder.UserWalletBuilder
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
import com.tangem.domain.wallets.usecase.SaveWalletUseCase
import com.tangem.features.onboarding.v2.impl.R
import com.tangem.features.onboarding.v2.multiwallet.impl.analytics.OnboardingEvent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.ui.state.MultiWalletCreateWalletUM
import com.tangem.features.onboarding.v2.multiwallet.impl.common.ui.resetCardDialog
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletState
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletState.Step
import com.tangem.sdk.api.TangemSdkManager
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableSharedFlow
@ -27,6 +33,7 @@ import kotlinx.coroutines.launch
import javax.inject.Inject
@Suppress("LongParameterList")
@Stable
@ComponentScoped
internal class MultiWalletCreateWalletModel @Inject constructor(
paramsContainer: ParamsContainer,
@ -36,6 +43,8 @@ internal class MultiWalletCreateWalletModel @Inject constructor(
private val getCardInfoUseCase: GetCardInfoUseCase,
private val cardRepository: CardRepository,
private val analyticsHandler: AnalyticsEventHandler,
private val generateWalletNameUseCase: GenerateWalletNameUseCase,
private val saveWalletUseCase: SaveWalletUseCase,
) : Model() {
private val params = paramsContainer.require<MultiWalletChildParams>()
@ -61,7 +70,7 @@ internal class MultiWalletCreateWalletModel @Inject constructor(
showOtherOptionsButton = params.parentParams.withSeedPhraseFlow,
onOtherOptionsClick = {
modelScope.launch {
onDone.emit(OnboardingMultiWalletState.Step.SeedPhrase)
onDone.emit(Step.SeedPhrase)
}
},
dialog = null,
@ -69,7 +78,7 @@ internal class MultiWalletCreateWalletModel @Inject constructor(
)
val uiState: StateFlow<MultiWalletCreateWalletUM> = _uiState
val onDone = MutableSharedFlow<OnboardingMultiWalletState.Step>()
val onDone = MutableSharedFlow<Step>()
init {
analyticsHandler.send(OnboardingEvent.CreateWallet.ScreenOpened)
@ -96,13 +105,14 @@ internal class MultiWalletCreateWalletModel @Inject constructor(
cardRepository.startCardActivation(cardId = result.data.card.cardId)
if (params.parentParams.withSeedPhraseFlow) {
onDone.emit(OnboardingMultiWalletState.Step.AddBackupDevice)
} else {
onDone.emit(OnboardingMultiWalletState.Step.ChooseBackupOption)
}
analyticsHandler.send(OnboardingEvent.CreateWallet.WalletCreatedSuccessfully())
val cardDoesNotSupportBackup = result.data.card.settings.isBackupAllowed.not()
when {
cardDoesNotSupportBackup -> createWalletAndNavigateBackWithDone()
params.parentParams.withSeedPhraseFlow -> onDone.emit(Step.AddBackupDevice)
else -> onDone.emit(Step.ChooseBackupOption)
}
}
is CompletionResult.Failure -> {
@ -115,6 +125,32 @@ internal class MultiWalletCreateWalletModel @Inject constructor(
}
}
private fun createWalletAndNavigateBackWithDone() {
modelScope.launch {
val scanResponse = params.multiWalletState.value.currentScanResponse
val userWallet = createUserWallet(scanResponse)
saveWalletUseCase(userWallet, canOverride = true)
.onRight {
cardRepository.finishCardActivation(scanResponse.card.cardId)
// save user wallet for manage tokens screen
params.multiWalletState.update {
it.copy(resultUserWallet = userWallet)
}
onDone.emit(Step.Done)
}
}
}
private suspend fun createUserWallet(scanResponse: ScanResponse): UserWallet {
return requireNotNull(
value = UserWalletBuilder(scanResponse, generateWalletNameUseCase).build(),
lazyMessage = { "User wallet not created" },
)
}
private fun handleActivationError() {
_uiState.update { state ->
state.copy(

View file

@ -1,11 +1,12 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.ui
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
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
@ -15,6 +16,7 @@ import com.tangem.core.ui.components.PrimaryButtonIconEnd
import com.tangem.core.ui.components.SecondaryButton
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.TangemThemePreview
import com.tangem.features.onboarding.v2.impl.R
@ -48,7 +50,8 @@ internal fun MultiWalletCreateWallet(state: MultiWalletCreateWalletUM, modifier:
Column(
Modifier
.fillMaxWidth()
.padding(start = 32.dp, end = 32.dp, bottom = 24.dp)
.verticalScroll(rememberScrollState())
.padding(start = 32.dp, end = 32.dp, bottom = 16.dp)
.weight(1f),
horizontalAlignment = Alignment.CenterHorizontally,
) {
@ -74,7 +77,7 @@ internal fun MultiWalletCreateWallet(state: MultiWalletCreateWalletUM, modifier:
.padding(start = 16.dp, end = 16.dp, bottom = 12.dp)
.fillMaxWidth(),
iconResId = R.drawable.ic_tangem_24,
text = stringResource(R.string.onboarding_create_wallet_button_create_wallet),
text = stringResourceSafe(R.string.onboarding_create_wallet_button_create_wallet),
onClick = state.onCreateWalletClick,
)
@ -83,7 +86,7 @@ internal fun MultiWalletCreateWallet(state: MultiWalletCreateWalletUM, modifier:
modifier = Modifier
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
.fillMaxWidth(),
text = stringResource(R.string.onboarding_create_wallet_options_button_options),
text = stringResourceSafe(R.string.onboarding_create_wallet_options_button_options),
onClick = state.onOtherOptionsClick,
)
}

View file

@ -1,5 +1,6 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize
import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
@ -12,6 +13,7 @@ import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChild
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.model.MultiWalletFinalizeModel
import com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.ui.MultiWalletFinalize
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
@ -19,6 +21,8 @@ import kotlinx.coroutines.launch
internal class MultiWalletFinalizeComponent(
context: AppComponentContext,
params: MultiWalletChildParams,
backButtonClickFlow: SharedFlow<Unit>,
onBack: () -> Unit,
onEvent: (Event) -> Unit,
) : AppComponentContext by context, MultiWalletChildComponent {
@ -40,12 +44,21 @@ internal class MultiWalletFinalizeComponent(
onEvent(it)
}
}
componentScope.launch {
backButtonClickFlow.collect { model.onBack() }
}
componentScope.launch {
model.onBackFlow.collect { onBack() }
}
}
@Composable
override fun Content(modifier: Modifier) {
val state by model.uiState.collectAsStateWithLifecycle()
BackHandler { model.onBack() }
MultiWalletFinalize(
state = state,
modifier = modifier,

View file

@ -1,5 +1,6 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.model
import androidx.compose.runtime.Stable
import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemSdkError
import com.tangem.core.decompose.di.ComponentScoped
@ -29,14 +30,12 @@ import com.tangem.sdk.api.BackupServiceHolder
import com.tangem.sdk.api.TangemSdkManager
import com.tangem.utils.StringsSigns
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import javax.inject.Inject
@Suppress("LongParameterList")
@Stable
@ComponentScoped
internal class MultiWalletFinalizeModel @Inject constructor(
paramsContainer: ParamsContainer,
@ -59,6 +58,7 @@ internal class MultiWalletFinalizeModel @Inject constructor(
private var walletHasBackupError = false
val uiState = _uiState.asStateFlow()
val onBackFlow = MutableSharedFlow<Unit>()
val onEvent = MutableSharedFlow<MultiWalletFinalizeComponent.Event>()
@ -72,6 +72,12 @@ internal class MultiWalletFinalizeModel @Inject constructor(
}
}
fun onBack() {
if (uiState.value.scanPrimary) {
modelScope.launch { onBackFlow.emit(Unit) }
}
}
private fun getInitialState(): MultiWalletFinalizeUM {
val backupService = backupServiceHolder.backupService.get() ?: return MultiWalletFinalizeUM()
val initialStep = getInitialStep()
@ -193,18 +199,24 @@ internal class MultiWalletFinalizeModel @Inject constructor(
private fun finishBackup() {
modelScope.launch {
val scanResponse = params.multiWalletState.value.currentScanResponse
val userWallet = createUserWallet(scanResponse)
when (params.parentParams.mode) {
val userWalletCreated = createUserWallet(scanResponse)
val userWallet = when (params.parentParams.mode) {
OnboardingMultiWalletComponent.Mode.Onboarding -> {
userWalletsListManager.save(
userWallet = userWallet.copy(
userWallet = userWalletCreated.copy(
scanResponse = scanResponse.updateScanResponseAfterBackup(),
),
canOverride = true,
)
userWalletCreated
}
OnboardingMultiWalletComponent.Mode.AddBackup -> {
val userWallet = userWalletsListManager.userWallets.first()
.firstOrNull { it.scanResponse.primaryCard?.cardId == scanResponse.primaryCard?.cardId }
?: userWalletCreated
userWalletsListManager.update(
userWalletId = userWallet.walletId,
update = { wallet ->
@ -213,6 +225,8 @@ internal class MultiWalletFinalizeModel @Inject constructor(
)
},
)
userWallet
}
}

View file

@ -1,15 +1,17 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.ui
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
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
import com.tangem.core.ui.components.PrimaryButtonIconEnd
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.onboarding.v2.impl.R
@ -27,13 +29,14 @@ internal fun MultiWalletFinalize(state: MultiWalletFinalizeUM, modifier: Modifie
Column(
Modifier
.fillMaxWidth()
.padding(start = 32.dp, end = 32.dp, bottom = 74.dp)
.padding(start = 32.dp, end = 32.dp, bottom = 16.dp)
.verticalScroll(rememberScrollState())
.weight(1f),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
modifier = Modifier.padding(top = 16.dp),
text = stringResource(
text = stringResourceSafe(
when {
state.scanPrimary && state.isRing -> R.string.common_origin_ring
state.scanPrimary && state.isRing.not() -> R.string.common_origin_card
@ -49,9 +52,9 @@ internal fun MultiWalletFinalize(state: MultiWalletFinalizeUM, modifier: Modifie
Text(
modifier = Modifier.padding(top = 12.dp),
text = if (state.isRing) {
stringResource(R.string.onboarding_subtitle_scan_ring)
stringResourceSafe(R.string.onboarding_subtitle_scan_ring)
} else {
stringResource(
stringResourceSafe(
R.string.onboarding_subtitle_scan_backup_card_format,
state.cardNumber,
)
@ -66,7 +69,7 @@ internal fun MultiWalletFinalize(state: MultiWalletFinalizeUM, modifier: Modifie
modifier = Modifier
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
.fillMaxWidth(),
text = stringResource(
text = stringResourceSafe(
if (state.isRing) R.string.onboarding_button_backup_ring else R.string.onboarding_button_backup_origin,
),
iconResId = R.drawable.ic_tangem_24,

View file

@ -0,0 +1,46 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.scanprimary
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.features.onboarding.v2.impl.R
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.features.onboarding.v2.multiwallet.impl.child.scanprimary.model.Wallet1ScanPrimaryModel
import com.tangem.features.onboarding.v2.multiwallet.impl.child.scanprimary.ui.Wallet1ScanPrimary
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
internal class Wallet1ScanPrimaryComponent(
context: AppComponentContext,
params: MultiWalletChildParams,
onDone: () -> Unit,
) : AppComponentContext by context, ComposableContentComponent {
private val model: Wallet1ScanPrimaryModel = getOrCreateModel(params)
init {
params.innerNavigation.update {
it.copy(
stackSize = 4,
stackMaxSize = 8,
)
}
params.parentParams.titleProvider.changeTitle(
text = resourceReference(R.string.onboarding_navbar_title_creating_backup),
)
componentScope.launch { model.onDone.collect { onDone() } }
}
@Composable
override fun Content(modifier: Modifier) {
Wallet1ScanPrimary(
isRing = model.isRing,
onScanPrimaryClick = model::onScanPrimaryClick,
)
}
}

View file

@ -0,0 +1,43 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.scanprimary.model
import androidx.compose.runtime.Stable
import com.tangem.common.CompletionResult
import com.tangem.core.decompose.di.ComponentScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.features.onboarding.v2.impl.R
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.sdk.api.BackupServiceHolder
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch
import javax.inject.Inject
@Stable
@ComponentScoped
internal class Wallet1ScanPrimaryModel @Inject constructor(
paramsContainer: ParamsContainer,
override val dispatchers: CoroutineDispatcherProvider,
private val backupServiceHolder: BackupServiceHolder,
) : Model() {
private val params = paramsContainer.require<MultiWalletChildParams>()
private val scanResponse = params.multiWalletState.value.currentScanResponse
val isRing = scanResponse.cardTypesResolver.isRing()
val onDone = MutableSharedFlow<Unit>()
fun onScanPrimaryClick() {
val backupService = backupServiceHolder.backupService.get() ?: return
val iconScanRes = R.drawable.img_hand_scan_ring.takeIf { isRing }
backupService.readPrimaryCard(iconScanRes = iconScanRes, cardId = scanResponse.card.cardId) { result ->
when (result) {
is CompletionResult.Success -> {
modelScope.launch { onDone.emit(Unit) }
}
is CompletionResult.Failure -> Unit
}
}
}
}

View file

@ -0,0 +1,74 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.scanprimary.ui
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.PrimaryButtonIconEnd
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.onboarding.v2.impl.R
@Composable
internal fun Wallet1ScanPrimary(isRing: Boolean, onScanPrimaryClick: () -> Unit, modifier: Modifier = Modifier) {
Column(
modifier = modifier
.fillMaxSize()
.navigationBarsPadding(),
verticalArrangement = Arrangement.Bottom,
) {
Column(
Modifier
.fillMaxWidth()
.padding(start = 32.dp, end = 32.dp, bottom = 16.dp)
.verticalScroll(rememberScrollState())
.weight(1f),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
modifier = Modifier.padding(top = 16.dp),
text = stringResourceSafe(R.string.onboarding_title_scan_origin_card),
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.Center,
style = TangemTheme.typography.h2,
)
Text(
modifier = Modifier.padding(top = 12.dp),
text = stringResourceSafe(R.string.onboarding_subtitle_scan_primary),
color = TangemTheme.colors.text.secondary,
textAlign = TextAlign.Center,
style = TangemTheme.typography.body1,
)
}
PrimaryButtonIconEnd(
modifier = Modifier
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
.fillMaxWidth(),
text = stringResourceSafe(
if (isRing) R.string.onboarding_button_backup_ring else R.string.onboarding_button_backup_origin,
),
iconResId = R.drawable.ic_tangem_24,
onClick = onScanPrimaryClick,
)
}
}
@Preview
@Composable
private fun Preview() {
TangemThemePreview {
Wallet1ScanPrimary(
isRing = true,
onScanPrimaryClick = {},
)
}
}

View file

@ -1,5 +1,6 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model
import androidx.compose.runtime.Stable
import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemSdkError
import com.tangem.core.analytics.api.AnalyticsEventHandler
@ -33,6 +34,7 @@ import javax.inject.Inject
// | DON'T FIXME !!! MODIFY WITH CAUTION !!! |
// =============================================
@Suppress("LongParameterList")
@Stable
@ComponentScoped
internal class MultiWalletSeedPhraseModel @Inject constructor(
paramsContainer: ParamsContainer,

View file

@ -4,6 +4,7 @@ import android.net.Uri
import com.tangem.utils.SupportedLanguages
import java.util.Locale
// TODO: [REDACTED_JIRA]
internal fun seedPhraseLearnMoreUrl(): String {
val language = Locale.getDefault().language

View file

@ -1,6 +1,7 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui
import androidx.compose.animation.*
import com.tangem.core.ui.extensions.stringResourceSafe
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyRow
@ -14,7 +15,6 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@ -55,49 +55,52 @@ internal fun MultiWalletSeedPhraseImport(state: MultiWalletSeedPhraseUM.Import,
Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState()),
.imePadding(),
) {
Text(
text = stringResource(id = R.string.onboarding_seed_import_message),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.secondary,
textAlign = TextAlign.Center,
modifier = Modifier
.padding(start = 36.dp, end = 36.dp, top = 24.dp, bottom = 16.dp)
.fillMaxWidth(),
)
PhraseBlock(
state = state,
modifier = Modifier.padding(horizontal = 16.dp),
)
OutlineTextFieldWithIcon(
modifier = modifier
.padding(horizontal = 16.dp)
.fillMaxWidth(),
value = state.passPhrase,
onValueChange = state.passPhraseChange,
iconResId = R.drawable.ic_information_24,
iconColor = TangemTheme.colors.icon.informative,
label = stringResource(id = R.string.common_passphrase),
placeholder = stringResource(id = R.string.send_optional_field),
onIconClick = state.onPassphraseInfoClick,
)
Box(Modifier.weight(1f)) {
PrimaryButtonIconEnd(
Column(
Modifier
.verticalScroll(rememberScrollState())
.weight(1f),
) {
Text(
text = stringResourceSafe(id = R.string.onboarding_seed_import_message),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.secondary,
textAlign = TextAlign.Center,
modifier = Modifier
.align(Alignment.BottomStart)
.padding(16.dp)
.padding(start = 36.dp, end = 36.dp, top = 24.dp, bottom = 16.dp)
.fillMaxWidth(),
text = stringResource(id = R.string.common_import),
iconResId = R.drawable.ic_tangem_24,
enabled = state.createWalletEnabled,
showProgress = state.createWalletProgress,
onClick = state.createWalletClick,
)
PhraseBlock(
state = state,
modifier = Modifier.padding(horizontal = 16.dp),
)
OutlineTextFieldWithIcon(
modifier = modifier
.padding(horizontal = 16.dp)
.fillMaxWidth(),
value = state.passPhrase,
onValueChange = state.passPhraseChange,
iconResId = R.drawable.ic_information_24,
iconColor = TangemTheme.colors.icon.informative,
label = stringResourceSafe(id = R.string.common_passphrase),
placeholder = stringResourceSafe(id = R.string.send_optional_field),
onIconClick = state.onPassphraseInfoClick,
)
}
PrimaryButtonIconEnd(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
text = stringResourceSafe(id = R.string.common_import),
iconResId = R.drawable.ic_tangem_24,
enabled = state.createWalletEnabled,
showProgress = state.createWalletProgress,
onClick = state.createWalletClick,
)
}
val keyboard by keyboardAsState()

View file

@ -10,7 +10,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.style.LineBreak
import androidx.compose.ui.text.style.TextAlign
@ -19,6 +18,7 @@ import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.SecondaryButton
import com.tangem.core.ui.components.SpacerH32
import com.tangem.core.ui.components.SpacerW8
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.onboarding.v2.impl.R
@ -51,7 +51,7 @@ internal fun MultiWalletSeedPhraseStart(state: MultiWalletSeedPhraseUM.Start, mo
Text(
modifier = Modifier
.padding(horizontal = TangemTheme.dimens.size12, vertical = TangemTheme.dimens.size4),
text = stringResource(id = R.string.onboarding_seed_phrase_intro_legacy),
text = stringResourceSafe(id = R.string.onboarding_seed_phrase_intro_legacy),
color = TangemTheme.colors.text.warning,
style = TangemTheme.typography.body1,
)
@ -71,12 +71,12 @@ private fun BodyContent(state: MultiWalletSeedPhraseUM.Start, modifier: Modifier
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
Text(
text = stringResource(id = R.string.onboarding_seed_intro_title),
text = stringResourceSafe(id = R.string.onboarding_seed_intro_title),
style = TangemTheme.typography.h2,
color = TangemTheme.colors.text.primary1,
)
Text(
text = stringResource(id = R.string.onboarding_seed_intro_message),
text = stringResourceSafe(id = R.string.onboarding_seed_intro_message),
style = TangemTheme.typography.body1
.copy(lineBreak = LineBreak.Paragraph),
color = TangemTheme.colors.text.secondary,
@ -119,7 +119,7 @@ private fun ReadMoreBlock(state: MultiWalletSeedPhraseUM.Start, modifier: Modifi
Text(
modifier = Modifier.align(Alignment.CenterVertically),
style = TangemTheme.typography.button,
text = stringResource(id = R.string.onboarding_seed_button_read_more),
text = stringResourceSafe(id = R.string.onboarding_seed_button_read_more),
)
}
}
@ -135,13 +135,13 @@ private fun Buttons(state: MultiWalletSeedPhraseUM.Start, modifier: Modifier = M
) {
SecondaryButton(
modifier = Modifier.fillMaxWidth(),
text = stringResource(id = R.string.onboarding_seed_intro_button_generate),
text = stringResourceSafe(id = R.string.onboarding_seed_intro_button_generate),
onClick = state.onGenerateSeedPhraseClicked,
)
SecondaryButton(
modifier = Modifier
.fillMaxWidth(),
text = stringResource(id = R.string.onboarding_seed_intro_button_import),
text = stringResourceSafe(id = R.string.onboarding_seed_intro_button_import),
onClick = state.onImportSeedPhraseClicked,
)
}

View file

@ -8,14 +8,14 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.pluralStringResource
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.LayoutDirection
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.buttons.segmentedbutton.SegmentedButtons
import com.tangem.core.ui.extensions.pluralStringResourceSafe
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.onboarding.v2.impl.R
@ -31,26 +31,32 @@ internal fun MultiWalletSeedPhraseWords(
modifier: Modifier = Modifier,
) {
Column(modifier.fillMaxSize()) {
SegmentSeedBlock(
modifier = Modifier.padding(vertical = 20.dp),
state = state,
)
TitleBlock(state)
SeedPhraseGridBlock(
mnemonicGridItems = state.words,
Column(
modifier = Modifier
.weight(1f)
.fillMaxWidth()
.padding(top = 20.dp, bottom = 32.dp),
)
.verticalScroll(rememberScrollState())
.imePadding()
.weight(1f),
) {
SegmentSeedBlock(
modifier = Modifier.padding(vertical = 20.dp),
state = state,
)
TitleBlock(state)
SeedPhraseGridBlock(
mnemonicGridItems = state.words,
modifier = Modifier
.fillMaxWidth()
.padding(top = 20.dp, bottom = 32.dp),
)
}
PrimaryButton(
modifier = Modifier
.fillMaxWidth()
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp),
text = stringResource(id = R.string.common_continue),
text = stringResourceSafe(id = R.string.common_continue),
onClick = state.onContinueClick,
)
}
@ -70,7 +76,7 @@ private fun SegmentSeedBlock(state: MultiWalletSeedPhraseUM.GenerateSeedPhrase,
},
) {
Text(
text = pluralStringResource(
text = pluralStringResourceSafe(
id = R.plurals.onboarding_seed_generate_words_count,
count = if (it == 0) 12 else 24,
if (it == 0) 12 else 24,
@ -95,14 +101,14 @@ private fun TitleBlock(state: MultiWalletSeedPhraseUM.GenerateSeedPhrase, modifi
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
Text(
text = stringResource(id = R.string.onboarding_seed_generate_title),
text = stringResourceSafe(id = R.string.onboarding_seed_generate_title),
style = TangemTheme.typography.h2,
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth(),
)
Text(
text = pluralStringResource(
text = pluralStringResourceSafe(
id = R.plurals.onboarding_seed_generate_message_words_count,
count = if (state.words24OptionSelected.not()) 12 else 24,
if (state.words24OptionSelected.not()) 12 else 24,
@ -118,8 +124,7 @@ private fun TitleBlock(state: MultiWalletSeedPhraseUM.GenerateSeedPhrase, modifi
@Composable
private fun SeedPhraseGridBlock(mnemonicGridItems: ImmutableList<MnemonicGridItem>, modifier: Modifier = Modifier) {
VerticalGrid(
modifier = modifier
.verticalScroll(rememberScrollState()),
modifier = modifier,
items = mnemonicGridItems,
) { item ->
Row(

View file

@ -5,9 +5,7 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
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.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@ -18,6 +16,7 @@ import com.tangem.core.ui.components.DialogButtonUM
import com.tangem.core.ui.components.OutlineTextField
import com.tangem.core.ui.components.PrimaryButtonIconEnd
import com.tangem.core.ui.extensions.resolveReference
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.onboarding.v2.multiwallet.impl.child.seedphrase.ui.state.MultiWalletSeedPhraseUM
@ -48,48 +47,50 @@ internal fun MultiWalletSeedPhraseWordsCheck(
Column(
modifier = modifier
.fillMaxSize()
.verticalScroll(rememberScrollState()),
.imePadding(),
) {
Text(
text = stringResource(R.string.onboarding_seed_user_validation_title),
style = TangemTheme.typography.h2,
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.Center,
modifier = Modifier
.padding(top = 48.dp, start = 36.dp, end = 36.dp, bottom = 16.dp)
.fillMaxWidth(),
)
Text(
text = stringResource(R.string.onboarding_seed_user_validation_message),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.secondary,
textAlign = TextAlign.Center,
modifier = Modifier
.padding(horizontal = 36.dp)
.fillMaxWidth(),
)
Fields(
state = state,
modifier = Modifier
.padding(vertical = 30.dp, horizontal = 16.dp),
)
Box(
Modifier.weight(1f),
Column(
Modifier
.verticalScroll(rememberScrollState())
.weight(1f),
) {
PrimaryButtonIconEnd(
Text(
text = stringResourceSafe(R.string.onboarding_seed_user_validation_title),
style = TangemTheme.typography.h2,
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.Center,
modifier = Modifier
.align(Alignment.BottomStart)
.padding(16.dp)
.padding(top = 48.dp, start = 36.dp, end = 36.dp, bottom = 16.dp)
.fillMaxWidth(),
text = stringResource(id = R.string.onboarding_create_wallet_button_create_wallet),
iconResId = R.drawable.ic_tangem_24,
enabled = state.createWalletButtonEnabled,
showProgress = state.createWalletButtonProgress,
onClick = state.onCreateWalletButtonClick,
)
Text(
text = stringResourceSafe(R.string.onboarding_seed_user_validation_message),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.secondary,
textAlign = TextAlign.Center,
modifier = Modifier
.padding(horizontal = 36.dp)
.fillMaxWidth(),
)
Fields(
state = state,
modifier = Modifier
.padding(vertical = 30.dp, horizontal = 16.dp),
)
}
PrimaryButtonIconEnd(
modifier = Modifier
.padding(16.dp)
.imePadding()
.fillMaxWidth(),
text = stringResourceSafe(id = R.string.onboarding_create_wallet_button_create_wallet),
iconResId = R.drawable.ic_tangem_24,
enabled = state.createWalletButtonEnabled,
showProgress = state.createWalletButtonProgress,
onClick = state.onCreateWalletButtonClick,
)
}
}

View file

@ -11,13 +11,13 @@ 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
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
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.onboarding.v2.impl.R
@ -50,7 +50,7 @@ fun PassphraseInfoBottomSheetContent(onDismiss: () -> Unit) {
)
Text(
text = stringResource(id = R.string.common_passphrase),
text = stringResourceSafe(id = R.string.common_passphrase),
modifier = Modifier
.padding(top = TangemTheme.dimens.size40)
.align(Alignment.CenterHorizontally),
@ -59,7 +59,7 @@ fun PassphraseInfoBottomSheetContent(onDismiss: () -> Unit) {
)
Text(
text = stringResource(id = R.string.onboarding_bottom_sheet_passphrase_description),
text = stringResourceSafe(id = R.string.onboarding_bottom_sheet_passphrase_description),
modifier = Modifier
.padding(top = TangemTheme.dimens.size16)
.padding(horizontal = TangemTheme.dimens.size24)
@ -75,7 +75,7 @@ fun PassphraseInfoBottomSheetContent(onDismiss: () -> Unit) {
.padding(top = TangemTheme.dimens.size40)
.padding(bottom = TangemTheme.dimens.size32)
.fillMaxWidth(),
text = stringResource(id = R.string.common_ok),
text = stringResourceSafe(id = R.string.common_ok),
onClick = onDismiss,
)
}

View file

@ -9,6 +9,7 @@ import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.model.Mul
import com.tangem.features.onboarding.v2.multiwallet.impl.child.chooseoption.model.Wallet1ChooseOptionModel
import com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.model.MultiWalletCreateWalletModel
import com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.model.MultiWalletFinalizeModel
import com.tangem.features.onboarding.v2.multiwallet.impl.child.scanprimary.model.Wallet1ScanPrimaryModel
import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model.MultiWalletSeedPhraseModel
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletModel
import dagger.Binds
@ -66,4 +67,9 @@ internal interface ModelModule {
@IntoMap
@ClassKey(Wallet1ChooseOptionModel::class)
fun provideModel7(model: Wallet1ChooseOptionModel): Model
@Binds
@IntoMap
@ClassKey(Wallet1ScanPrimaryModel::class)
fun provideModel8(model: Wallet1ScanPrimaryModel): Model
}

View file

@ -103,11 +103,19 @@ internal class OnboardingMultiWalletModel @Inject constructor(
}
private fun getInitialStep(): OnboardingMultiWalletState.Step {
val card = params.scanResponse.card
val scanResponse = params.scanResponse
val card = scanResponse.card
val backupService = backupServiceHolder.backupService.get()!!
return when {
// interrupted backup
backupService.hasIncompletedBackup -> OnboardingMultiWalletState.Step.Finalize
// Add backup button
// Wallet1 without backup and userwallet's scanResponse doesn't contain primary card.
card.wallets.isNotEmpty() && card.backupStatus == CardDTO.BackupStatus.NoBackup &&
scanResponse.primaryCard == null -> OnboardingMultiWalletState.Step.ScanPrimary
card.wallets.isNotEmpty() && card.backupStatus == CardDTO.BackupStatus.NoBackup ->
OnboardingMultiWalletState.Step.AddBackupDevice
card.wallets.isNotEmpty() && card.backupStatus?.isActive == true ->

View file

@ -17,6 +17,8 @@ data class OnboardingMultiWalletState(
/**
* Wallet1
* ScanPrimary -> |
* |
* CreateWallet -> ChooseBackupOption -> AddBackupDevice -> Finalize -> [Done]
* |
* -> [Done]
@ -27,7 +29,7 @@ data class OnboardingMultiWalletState(
* -> AddBackupDevice -> Finalize -> [Done]
*/
enum class Step {
CreateWallet, ChooseBackupOption, SeedPhrase, AddBackupDevice, Finalize, Done
CreateWallet, ChooseBackupOption, SeedPhrase, ScanPrimary, AddBackupDevice, Finalize, Done
}
@JvmInline

View file

@ -7,7 +7,9 @@ import com.tangem.features.onboarding.v2.impl.R
fun screenTitleByStep(step: OnboardingMultiWalletState.Step): TextReference = when (step) {
OnboardingMultiWalletState.Step.CreateWallet ->
resourceReference(R.string.onboarding_create_wallet_header)
OnboardingMultiWalletState.Step.AddBackupDevice ->
OnboardingMultiWalletState.Step.ScanPrimary,
OnboardingMultiWalletState.Step.AddBackupDevice,
->
resourceReference(R.string.onboarding_navbar_title_creating_backup)
OnboardingMultiWalletState.Step.Finalize ->
resourceReference(R.string.onboarding_button_finalize_backup)

View file

@ -49,9 +49,9 @@ internal fun OnboardingMultiWallet(
url2 = state.artwork2Url,
url3 = state.artwork3Url,
modifier = Modifier
.weight(.56f)
.padding(horizontal = 34.dp)
.padding(top = 20.dp)
.weight(.4f)
.fillMaxWidth(),
state = artworksState,
)

View file

@ -16,7 +16,7 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
@Suppress("UnusedPrivateMember")
class DefaultOnboardingVisaComponent @AssistedInject constructor(
internal class DefaultOnboardingVisaComponent @AssistedInject constructor(
@Assisted appComponentContext: AppComponentContext,
@Assisted private val params: OnboardingVisaComponent.Params,
) : OnboardingVisaComponent, AppComponentContext by appComponentContext {

View file

@ -9,7 +9,7 @@ import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.features.onboarding.v2.visa.impl.child.accesscode.model.OnboardingVisaAccessCodeModel
import kotlinx.coroutines.flow.SharedFlow
class OnboardingVisaAccessCodeComponent(
internal class OnboardingVisaAccessCodeComponent(
appComponentContext: AppComponentContext,
private val params: Params,
) : ComposableContentComponent, AppComponentContext by appComponentContext {

View file

@ -10,7 +10,7 @@ import javax.inject.Inject
@Stable
@ComponentScoped
class OnboardingVisaAccessCodeModel @Inject constructor(
internal class OnboardingVisaAccessCodeModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider,
private val paramsContainer: ParamsContainer,
) : Model() {

View file

@ -0,0 +1,167 @@
package com.tangem.features.onboarding.v2.visa.impl.child.accesscode.ui
import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
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
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.common.ui.navigationButtons.NavigationButton
import com.tangem.common.ui.navigationButtons.NavigationPrimaryButton
import com.tangem.core.ui.components.OutlineTextFieldWithIcon
import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.components.SpacerH16
import com.tangem.core.ui.components.SpacerH32
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.res.TangemAnimations
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.onboarding.v2.impl.R
import com.tangem.features.onboarding.v2.visa.impl.child.accesscode.ui.state.OnboardingVisaAccessCodeUM
import kotlinx.coroutines.delay
@Composable
internal fun OnboardingVisaAccessCode(state: OnboardingVisaAccessCodeUM, modifier: Modifier = Modifier) {
Column(
modifier
.fillMaxSize()
.navigationBarsPadding(),
) {
AnimatedContent(
modifier = Modifier
.padding(top = 48.dp)
.weight(1f),
targetState = state.step,
transitionSpec = TangemAnimations.AnimatedContent
.slide { initial, target -> initial.ordinal < target.ordinal },
) { step ->
Content(
state = state,
reEnterAccessCodeState = step == OnboardingVisaAccessCodeUM.Step.ReEnter,
)
}
SpacerH(20.dp)
NavigationPrimaryButton(
modifier = Modifier
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
.imePadding(),
primaryButton = NavigationButton(
textReference = when (state.step) {
OnboardingVisaAccessCodeUM.Step.Enter -> resourceReference(R.string.common_continue)
OnboardingVisaAccessCodeUM.Step.ReEnter ->
resourceReference(R.string.onboarding_create_wallet_button_create_wallet)
},
onClick = state.onContinue,
iconRes = R.drawable.ic_tangem_24,
isIconVisible = state.step == OnboardingVisaAccessCodeUM.Step.ReEnter,
),
)
}
}
@Suppress("LongMethod")
@Composable
private fun Content(
state: OnboardingVisaAccessCodeUM,
reEnterAccessCodeState: Boolean,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
modifier = Modifier
.padding(horizontal = 32.dp),
text = if (reEnterAccessCodeState) {
"Re-enter your access code" // TODO
} else {
"Create access code" // TODO
},
style = TangemTheme.typography.h2,
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.Center,
)
SpacerH16()
// TODO
Text(
modifier = Modifier
.padding(horizontal = 32.dp),
text = "The access code will be used manage your payment account and protect it from unauthorized access",
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.secondary,
textAlign = TextAlign.Center,
)
SpacerH32()
val focusRequester = remember { FocusRequester() }
OutlineTextFieldWithIcon(
modifier = modifier
.padding(horizontal = 16.dp)
.focusRequester(focusRequester)
.fillMaxWidth(),
iconResId = if (state.accessCodeHidden) {
R.drawable.ic_eye_outline_24
} else {
R.drawable.ic_eye_off_outline_24
},
iconColor = TangemTheme.colors.icon.primary1,
onIconClick = state.onAccessCodeHideClick,
value = if (reEnterAccessCodeState) {
state.accessCodeSecond
} else {
state.accessCodeFirst
},
onValueChange = if (reEnterAccessCodeState) {
state.onAccessCodeSecondChange
} else {
state.onAccessCodeFirstChange
},
label = stringResource(id = R.string.onboarding_wallet_info_title_third),
isError = state.codesNotMatchError || state.atLeast4CharError,
visualTransformation = if (state.accessCodeHidden) {
PasswordVisualTransformation()
} else {
VisualTransformation.None
},
caption = when {
state.codesNotMatchError && reEnterAccessCodeState ->
stringResource(R.string.onboarding_access_codes_doesnt_match)
state.atLeast4CharError && !reEnterAccessCodeState ->
stringResource(R.string.onboarding_access_code_too_short)
else -> null
},
)
LaunchedEffect(Unit) {
delay(timeMillis = 200)
focusRequester.requestFocus()
}
}
}
@Preview(showBackground = true)
@Composable
private fun Preview() {
TangemThemePreview {
OnboardingVisaAccessCode(
state = OnboardingVisaAccessCodeUM(),
)
}
}

View file

@ -0,0 +1,20 @@
package com.tangem.features.onboarding.v2.visa.impl.child.accesscode.ui.state
import androidx.compose.ui.text.input.TextFieldValue
data class OnboardingVisaAccessCodeUM(
val step: Step = Step.Enter,
val accessCodeFirst: TextFieldValue = TextFieldValue(""),
val accessCodeSecond: TextFieldValue = TextFieldValue(""),
val codesNotMatchError: Boolean = false,
val atLeast4CharError: Boolean = false,
val accessCodeHidden: Boolean = true,
val onAccessCodeFirstChange: (TextFieldValue) -> Unit = {},
val onAccessCodeSecondChange: (TextFieldValue) -> Unit = {},
val onContinue: () -> Unit = {},
val onAccessCodeHideClick: () -> Unit = {},
) {
enum class Step {
Enter, ReEnter
}
}

View file

@ -6,8 +6,10 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.ui.OnboardingVisaWelcome
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.ui.state.OnboardingVisaWelcomeUM
class OnboardingVisaWelcomeComponent(
internal class OnboardingVisaWelcomeComponent(
appComponentContext: AppComponentContext,
private val params: Params,
) : ComposableContentComponent, AppComponentContext by appComponentContext {
@ -15,9 +17,15 @@ class OnboardingVisaWelcomeComponent(
@Composable
override fun Content(modifier: Modifier) {
BackHandler(onBack = remember(this) { { params.onBack() } })
OnboardingVisaWelcome(
modifier = modifier,
state = OnboardingVisaWelcomeUM(),
)
}
data class Params(
val onBack: () -> Unit,
val startActivation: () -> Unit,
)
}

View file

@ -0,0 +1,124 @@
package com.tangem.features.onboarding.v2.visa.impl.child.welcome.ui
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.PrimaryButtonIconEnd
import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.components.SpacerH12
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.onboarding.v2.impl.R
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.ui.state.OnboardingVisaWelcomeUM
@Composable
internal fun OnboardingVisaWelcome(state: OnboardingVisaWelcomeUM, modifier: Modifier = Modifier) {
Column(
modifier = modifier
.fillMaxSize()
.navigationBarsPadding(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Column(
Modifier
.padding(
top = 20.dp,
bottom = 32.dp,
start = 32.dp,
end = 32.dp,
)
.fillMaxSize()
.weight(1f),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Artwork()
SpacerH(50.dp)
Text(
text = when (state.mode) {
OnboardingVisaWelcomeUM.Mode.Hello -> "Hello, ${state.userName}!"
OnboardingVisaWelcomeUM.Mode.WelcomeBack -> "Welcome back, ${state.userName}!"
},
style = TangemTheme.typography.h2,
color = TangemTheme.colors.text.primary1,
)
SpacerH12()
Text(
text = when (state.mode) {
OnboardingVisaWelcomeUM.Mode.Hello -> "bla bla bla //TODO"
OnboardingVisaWelcomeUM.Mode.WelcomeBack -> "bla bla bla? //TODO"
},
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.secondary,
)
}
when (state.mode) {
OnboardingVisaWelcomeUM.Mode.Hello -> {
PrimaryButton(
modifier = Modifier
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
.fillMaxWidth(),
text = "Start Activation",
onClick = state.onContinueClick,
)
}
OnboardingVisaWelcomeUM.Mode.WelcomeBack -> {
PrimaryButtonIconEnd(
modifier = Modifier
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
.fillMaxWidth(),
text = "Start Activation",
iconResId = R.drawable.ic_tangem_24,
onClick = state.onContinueClick,
)
}
}
}
}
@Composable
fun Artwork(modifier: Modifier = Modifier) {
Box(modifier) {
val circleColor = TangemTheme.colors.background.secondary
Canvas(
modifier = Modifier
.align(Alignment.Center)
.size(254.dp)
.fillMaxSize(),
) {
drawCircle(
color = circleColor,
radius = size.width / 2,
center = center,
)
}
AsyncImage(
model = R.drawable.img_card_visa,
contentDescription = null,
modifier = Modifier
.align(Alignment.Center)
.size(128.dp), // Adjust the size as needed
)
}
}
@Preview(showBackground = true)
@Composable
private fun Preview() {
TangemThemePreview {
OnboardingVisaWelcome(state = OnboardingVisaWelcomeUM())
}
}

View file

@ -0,0 +1,11 @@
package com.tangem.features.onboarding.v2.visa.impl.child.welcome.ui.state
internal data class OnboardingVisaWelcomeUM(
val mode: Mode = Mode.Hello,
val userName: String = "",
val onContinueClick: () -> Unit = {},
) {
enum class Mode {
Hello, WelcomeBack
}
}

View file

@ -13,10 +13,10 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import com.tangem.core.ui.components.SecondaryButton
import com.tangem.core.ui.components.SpacerH32
import com.tangem.core.ui.components.SpacerW8
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.onboarding.R
import com.tangem.feature.onboarding.presentation.wallet2.model.AboutState
@ -56,7 +56,7 @@ fun AboutSeedPhraseScreen(state: AboutState, modifier: Modifier = Modifier) {
SecondaryButton(
modifier = Modifier
.fillMaxWidth(),
text = stringResource(id = R.string.onboarding_seed_intro_button_generate),
text = stringResourceSafe(id = R.string.onboarding_seed_intro_button_generate),
enabled = state.buttonGenerateSeedPhrase.enabled,
showProgress = state.buttonGenerateSeedPhrase.showProgress,
onClick = state.buttonGenerateSeedPhrase.onClick,
@ -66,7 +66,7 @@ fun AboutSeedPhraseScreen(state: AboutState, modifier: Modifier = Modifier) {
SecondaryButton(
modifier = Modifier
.fillMaxWidth(),
text = stringResource(id = R.string.onboarding_seed_intro_button_import),
text = stringResourceSafe(id = R.string.onboarding_seed_intro_button_import),
enabled = state.buttonImportSeedPhrase.enabled,
showProgress = state.buttonImportSeedPhrase.showProgress,
onClick = state.buttonImportSeedPhrase.onClick,
@ -105,7 +105,7 @@ private fun EditIconBlock() {
horizontal = TangemTheme.dimens.size12,
vertical = TangemTheme.dimens.size4,
),
text = stringResource(id = R.string.onboarding_seed_phrase_intro_legacy),
text = stringResourceSafe(id = R.string.onboarding_seed_phrase_intro_legacy),
color = TangemTheme.colors.text.warning,
style = TangemTheme.typography.body1,
)
@ -143,7 +143,7 @@ private fun ReadMoreBlock(state: AboutState) {
)
SpacerW8()
Text(
text = stringResource(id = R.string.onboarding_seed_button_read_more),
text = stringResourceSafe(id = R.string.onboarding_seed_button_read_more),
color = TangemTheme.colors.text.primary1,
)
}

View file

@ -4,10 +4,10 @@ import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.tangem.core.ui.R
import com.tangem.core.ui.components.OutlineTextField
import com.tangem.core.ui.components.PrimaryButtonIconEnd
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.onboarding.presentation.wallet2.model.CheckSeedPhraseState
import com.tangem.feature.onboarding.presentation.wallet2.ui.components.Description
@ -29,7 +29,6 @@ fun CheckSeedPhraseScreen(state: CheckSeedPhraseState, modifier: Modifier = Modi
.weight(1f)
.fillMaxWidth(),
) {
item {
OnboardingDescriptionBlock(
modifier = Modifier
@ -59,7 +58,7 @@ fun CheckSeedPhraseScreen(state: CheckSeedPhraseState, modifier: Modifier = Modi
PrimaryButtonIconEnd(
modifier = Modifier
.fillMaxWidth(),
text = stringResource(id = R.string.onboarding_create_wallet_button_create_wallet),
text = stringResourceSafe(id = R.string.onboarding_create_wallet_button_create_wallet),
iconResId = R.drawable.ic_tangem_24,
enabled = state.buttonCreateWallet.enabled,
showProgress = state.buttonCreateWallet.showProgress,

View file

@ -14,7 +14,6 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
@ -22,8 +21,9 @@ import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameter
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import com.tangem.core.ui.components.*
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.feature.onboarding.R
import com.tangem.feature.onboarding.presentation.wallet2.model.ButtonState
import com.tangem.feature.onboarding.presentation.wallet2.model.ImportSeedPhraseState
@ -49,7 +49,7 @@ fun ImportSeedPhraseScreen(state: ImportSeedPhraseState, modifier: Modifier = Mo
OnboardingDescriptionBlock(
modifier = Modifier.padding(top = TangemTheme.dimens.size16),
) {
DescriptionSubTitleText(text = stringResource(id = R.string.onboarding_seed_import_message))
DescriptionSubTitleText(text = stringResourceSafe(id = R.string.onboarding_seed_import_message))
}
PhraseBlock(
modifier = Modifier
@ -70,7 +70,7 @@ fun ImportSeedPhraseScreen(state: ImportSeedPhraseState, modifier: Modifier = Mo
PrimaryButtonIconEnd(
modifier = Modifier
.fillMaxWidth(),
text = stringResource(id = R.string.common_import),
text = stringResourceSafe(id = R.string.common_import),
iconResId = R.drawable.ic_tangem_24,
enabled = state.buttonCreateWallet.enabled,
showProgress = state.buttonCreateWallet.showProgress,
@ -108,8 +108,8 @@ private fun PassphraseBlock(
onValueChange = passphraseField.onTextFieldValueChanged,
iconResId = R.drawable.ic_information_24,
iconColor = TangemTheme.colors.icon.informative,
label = stringResource(id = R.string.common_passphrase),
placeholder = stringResource(id = R.string.send_optional_field),
label = stringResourceSafe(id = R.string.common_passphrase),
placeholder = stringResourceSafe(id = R.string.send_optional_field),
onIconClick = onPassphraseInfoClick,
)
}

View file

@ -8,11 +8,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import coil.compose.SubcomposeAsyncImage
import coil.request.ImageRequest
import com.tangem.core.ui.components.PrimaryButtonIconEnd
import com.tangem.core.ui.components.SecondaryButton
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.onboarding.R
import com.tangem.feature.onboarding.presentation.wallet2.model.IntroState
@ -49,7 +49,7 @@ fun IntroScreen(state: IntroState, modifier: Modifier = Modifier) {
PrimaryButtonIconEnd(
modifier = Modifier
.fillMaxWidth(),
text = stringResource(id = R.string.onboarding_create_wallet_button_create_wallet),
text = stringResourceSafe(id = R.string.onboarding_create_wallet_button_create_wallet),
iconResId = R.drawable.ic_tangem_24,
enabled = state.buttonCreateWallet.enabled,
showProgress = state.buttonCreateWallet.showProgress,
@ -60,7 +60,7 @@ fun IntroScreen(state: IntroState, modifier: Modifier = Modifier) {
SecondaryButton(
modifier = Modifier
.fillMaxWidth(),
text = stringResource(id = R.string.onboarding_create_wallet_options_button_options),
text = stringResourceSafe(id = R.string.onboarding_create_wallet_options_button_options),
enabled = state.buttonOtherOptions.enabled,
showProgress = state.buttonOtherOptions.showProgress,
onClick = state.buttonOtherOptions.onClick,

View file

@ -11,12 +11,12 @@ 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
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.feature.onboarding.R
@ -50,7 +50,7 @@ fun PassphraseInfoBottomSheetContent(content: ShowPassphraseInfoBottomSheetConte
)
Text(
text = stringResource(id = R.string.common_passphrase),
text = stringResourceSafe(id = R.string.common_passphrase),
modifier = Modifier
.padding(top = TangemTheme.dimens.size40)
.align(Alignment.CenterHorizontally),
@ -59,7 +59,7 @@ fun PassphraseInfoBottomSheetContent(content: ShowPassphraseInfoBottomSheetConte
)
Text(
text = stringResource(id = R.string.onboarding_bottom_sheet_passphrase_description),
text = stringResourceSafe(id = R.string.onboarding_bottom_sheet_passphrase_description),
modifier = Modifier
.padding(top = TangemTheme.dimens.size16)
.padding(horizontal = TangemTheme.dimens.size24)
@ -75,7 +75,7 @@ fun PassphraseInfoBottomSheetContent(content: ShowPassphraseInfoBottomSheetConte
.padding(top = TangemTheme.dimens.size40)
.padding(bottom = TangemTheme.dimens.size32)
.fillMaxWidth(),
text = stringResource(id = R.string.common_ok),
text = stringResourceSafe(id = R.string.common_ok),
onClick = content.onOkClick,
)
}

View file

@ -9,13 +9,13 @@ import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.pluralStringResource
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
import com.tangem.core.ui.components.SpacerH16
import com.tangem.core.ui.components.buttons.segmentedbutton.SegmentedButtons
import com.tangem.core.ui.extensions.pluralStringResourceSafe
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.feature.onboarding.R
@ -60,7 +60,7 @@ fun YourSeedPhraseScreen(state: YourSeedPhraseState, modifier: Modifier = Modifi
firstActionContent = {
PrimaryButton(
modifier = Modifier.fillMaxWidth(),
text = stringResource(id = R.string.common_continue),
text = stringResourceSafe(id = R.string.common_continue),
onClick = state.buttonContinue.onClick,
)
},
@ -77,10 +77,10 @@ private fun TitleBlock(state: SegmentSeedState) {
.fillMaxWidth(),
) {
Column {
DescriptionTitleText(text = stringResource(id = R.string.onboarding_seed_generate_title))
DescriptionTitleText(text = stringResourceSafe(id = R.string.onboarding_seed_generate_title))
SpacerH16()
DescriptionSubTitleText(
text = pluralStringResource(
text = pluralStringResourceSafe(
id = R.plurals.onboarding_seed_generate_message_words_count,
count = state.selectedSeedType.count,
state.selectedSeedType.count,
@ -101,7 +101,7 @@ private fun SegmentSeedBlock(state: SegmentSeedState, modifier: Modifier = Modif
},
) {
Text(
text = pluralStringResource(
text = pluralStringResourceSafe(
id = R.plurals.onboarding_seed_generate_words_count,
count = it.count,
it.count,

View file

@ -8,10 +8,10 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.sp
import com.tangem.core.ui.components.SpacerH16
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
/**
@ -31,9 +31,9 @@ fun OnboardingDescriptionBlock(modifier: Modifier = Modifier, content: @Composab
@Composable
fun Description(@StringRes titleRes: Int, @StringRes subTitleRes: Int) {
Column {
DescriptionTitleText(text = stringResource(id = titleRes))
DescriptionTitleText(text = stringResourceSafe(id = titleRes))
SpacerH16()
DescriptionSubTitleText(text = stringResource(id = subTitleRes))
DescriptionSubTitleText(text = stringResourceSafe(id = subTitleRes))
}
}

View file

@ -8,7 +8,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
@ -23,6 +22,7 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
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.TangemThemePreview
import com.tangem.features.onramp.confirmresidency.ConfirmResidencyComponent
@ -55,7 +55,7 @@ internal fun ConfirmResidencyBottomSheetContent(model: ConfirmResidencyUM, modif
modifier = Modifier
.fillMaxWidth()
.padding(top = TangemTheme.dimens.spacing10),
text = stringResource(id = R.string.onramp_residency_bottomsheet_title),
text = stringResourceSafe(id = R.string.onramp_residency_bottomsheet_title),
style = TangemTheme.typography.subtitle1,
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.Center,
@ -114,7 +114,7 @@ private fun CountryContent(name: String, flagUrl: String, isCountrySupported: Bo
if (!isCountrySupported) {
Text(
modifier = Modifier.padding(top = TangemTheme.dimens.spacing6),
text = stringResource(id = R.string.onramp_residency_bottomsheet_country_not_supported),
text = stringResourceSafe(id = R.string.onramp_residency_bottomsheet_country_not_supported),
color = TangemTheme.colors.text.warning,
style = TangemTheme.typography.body2,
)

View file

@ -1,7 +1,6 @@
package com.tangem.features.onramp.main.model
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.res.stringResource
import com.arkivanov.decompose.router.slot.SlotNavigation
import com.arkivanov.decompose.router.slot.activate
import com.tangem.common.ui.alerts.models.AlertDemoModeUM
@ -14,6 +13,7 @@ import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.components.BasicDialog
import com.tangem.core.ui.components.DialogButtonUM
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.message.ContentMessage
import com.tangem.domain.demo.IsDemoCardUseCase
import com.tangem.domain.onramp.*
@ -358,7 +358,7 @@ internal class OnrampMainComponentModel @Inject constructor(
)
val dismissButton = DialogButtonUM(
title = stringResource(id = R.string.common_cancel),
title = stringResourceSafe(id = R.string.common_cancel),
onClick = onDismiss,
)

View file

@ -13,11 +13,11 @@ 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.res.stringResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle
import com.tangem.core.ui.extensions.appendSpace
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.OnrampProviderBlockUM
@ -47,7 +47,7 @@ private fun OnrampProviderBlock(state: OnrampProviderBlockUM.Content, modifier:
Column(modifier = Modifier.weight(1F)) {
Text(
text = buildAnnotatedString {
append(stringResource(id = R.string.onramp_pay_with))
append(stringResourceSafe(id = R.string.onramp_pay_with))
appendSpace()
withStyle(
style = SpanStyle(
@ -63,7 +63,7 @@ private fun OnrampProviderBlock(state: OnrampProviderBlockUM.Content, modifier:
)
Text(
text = buildAnnotatedString {
append(stringResource(id = R.string.onramp_via))
append(stringResourceSafe(id = R.string.onramp_via))
appendSpace()
append(state.providerName)
},
@ -87,7 +87,7 @@ private fun OnrampProviderBlock(state: OnrampProviderBlockUM.Content, modifier:
horizontal = TangemTheme.dimens.spacing6,
vertical = TangemTheme.dimens.spacing1,
),
text = stringResource(id = R.string.express_provider_best_rate),
text = stringResourceSafe(id = R.string.express_provider_best_rate),
style = TangemTheme.typography.caption1,
color = TangemTheme.colors.text.primary2,
)
@ -105,7 +105,7 @@ private fun OnrampProviderLoading(modifier: Modifier = Modifier) {
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
) {
Text(
text = stringResource(id = R.string.express_provider),
text = stringResourceSafe(id = R.string.express_provider),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
)
@ -119,7 +119,7 @@ private fun OnrampProviderLoading(modifier: Modifier = Modifier) {
modifier = Modifier.size(TangemTheme.dimens.size16),
)
Text(
text = stringResource(id = R.string.express_fetch_best_rates),
text = stringResourceSafe(id = R.string.express_fetch_best_rates),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,
)

View file

@ -16,7 +16,6 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@ -33,6 +32,7 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
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.domain.onramp.model.OnrampPaymentMethod
@ -61,7 +61,7 @@ internal fun SelectProviderBottomSheetContent(state: SelectPaymentAndProviderUM,
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = stringResource(id = R.string.onramp_choose_provider_title_hint),
text = stringResourceSafe(id = R.string.onramp_choose_provider_title_hint),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.secondary,
textAlign = TextAlign.Center,
@ -102,7 +102,7 @@ private fun PaymentMethodBlock(
PaymentMethodIcon(imageUrl = state.imageUrl)
Column(modifier = Modifier.weight(1F)) {
Text(
text = stringResource(id = R.string.onramp_pay_with),
text = stringResourceSafe(id = R.string.onramp_pay_with),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,
)
@ -193,7 +193,7 @@ private fun AvailableProviderItem(state: ProviderListItemUM.Available.Content, m
when {
state.isBestRate -> {
Text(
text = stringResource(R.string.express_provider_best_rate),
text = stringResourceSafe(R.string.express_provider_best_rate),
style = TangemTheme.typography.caption1,
color = TangemTheme.colors.text.constantWhite,
modifier = Modifier
@ -278,7 +278,7 @@ private fun OnrampMoreProviders() {
.padding(top = 16.dp),
)
Text(
text = stringResource(R.string.express_more_providers_soon),
text = stringResourceSafe(R.string.express_more_providers_soon),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.icon.informative,
modifier = Modifier

View file

@ -1,6 +1,5 @@
package com.tangem.features.onramp.redirect.model
import androidx.compose.ui.res.stringResource
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
@ -10,10 +9,7 @@ import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.components.BasicDialog
import com.tangem.core.ui.components.DialogButtonUM
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
import com.tangem.core.ui.extensions.combinedReference
import com.tangem.core.ui.extensions.resourceReference
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.message.ContentMessage
import com.tangem.domain.onramp.GetOnrampRedirectUrlUseCase
import com.tangem.domain.onramp.model.error.OnrampError
@ -88,9 +84,9 @@ internal class OnrampRedirectModel @Inject constructor(
)
val contentMessage = ContentMessage { onDismiss ->
BasicDialog(
message = stringResource(id = R.string.common_unknown_error),
message = stringResourceSafe(id = R.string.common_unknown_error),
confirmButton = DialogButtonUM(
title = stringResource(id = R.string.common_ok),
title = stringResourceSafe(id = R.string.common_ok),
onClick = {
params.onBack()
onDismiss()

View file

@ -12,7 +12,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import coil.compose.AsyncImage
import com.tangem.core.ui.components.CircleShimmer
@ -24,6 +23,7 @@ import com.tangem.core.ui.components.buttons.SecondarySmallButton
import com.tangem.core.ui.components.buttons.SmallButtonConfig
import com.tangem.core.ui.components.fields.SearchBar
import com.tangem.core.ui.extensions.resourceReference
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.selectcountry.entity.CountryItemState
@ -67,7 +67,7 @@ private fun LazyListScope.countryListError(state: CountryListUM.Error) {
verticalArrangement = Arrangement.Center,
) {
Text(
text = stringResource(id = R.string.markets_loading_error_title),
text = stringResourceSafe(id = R.string.markets_loading_error_title),
style = TangemTheme.typography.caption1,
color = TangemTheme.colors.text.tertiary,
)
@ -185,7 +185,7 @@ private fun UnavailableCountryItem(state: CountryItemState.WithContent.Unavailab
color = TangemTheme.colors.text.disabled,
)
Text(
text = stringResource(R.string.onramp_country_unavailable),
text = stringResourceSafe(R.string.onramp_country_unavailable),
maxLines = 1,
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,

View file

@ -11,7 +11,6 @@ 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.res.stringResource
import androidx.compose.ui.util.fastForEach
import coil.compose.AsyncImage
import com.tangem.core.ui.components.CircleShimmer
@ -24,6 +23,7 @@ import com.tangem.core.ui.components.buttons.SmallButtonConfig
import com.tangem.core.ui.components.fields.SearchBar
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.resourceReference
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.selectcurrency.entity.CurrenciesListUM
@ -67,7 +67,7 @@ private fun LazyListScope.currencyListError(state: CurrenciesListUM.Error) {
verticalArrangement = Arrangement.Center,
) {
Text(
text = stringResource(id = R.string.markets_loading_error_title),
text = stringResourceSafe(id = R.string.markets_loading_error_title),
style = TangemTheme.typography.caption1,
color = TangemTheme.colors.text.tertiary,
)

View file

@ -1,6 +1,5 @@
package com.tangem.features.onramp.selecttoken.model
import androidx.compose.ui.res.stringResource
import arrow.core.getOrElse
import com.tangem.common.routing.AppRouter
import com.tangem.common.ui.alerts.models.AlertDemoModeUM
@ -14,6 +13,7 @@ import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.components.BasicDialog
import com.tangem.core.ui.components.DialogButtonUM
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.message.ContentMessage
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
@ -141,7 +141,7 @@ internal class OnrampOperationModel @Inject constructor(
)
val dismissButton = DialogButtonUM(
title = stringResource(id = R.string.common_cancel),
title = stringResourceSafe(id = R.string.common_cancel),
onClick = onDismiss,
)

View file

@ -10,9 +10,9 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.utils.rememberHideKeyboardNestedScrollConnection
import com.tangem.features.onramp.impl.R
@ -39,7 +39,7 @@ internal fun OnrampSelectToken(
stickyHeader(key = "header") {
AppBarWithBackButton(
onBackClick = state.onBackClick,
text = stringResource(id = state.titleResId),
text = stringResourceSafe(id = state.titleResId),
iconRes = R.drawable.ic_close_24,
containerColor = TangemTheme.colors.background.secondary,
)

View file

@ -13,11 +13,11 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.util.fastForEach
import coil.compose.AsyncImage
import com.tangem.core.ui.components.SpacerWMax
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.utils.WindowInsetsZero
import com.tangem.features.onramp.impl.R
@ -35,7 +35,7 @@ internal fun OnrampSettingsContent(state: OnrampSettingsUM, modifier: Modifier =
AppBarWithBackButton(
modifier = Modifier.statusBarsPadding(),
onBackClick = state.onBack,
text = stringResource(id = R.string.onramp_settings_title),
text = stringResourceSafe(id = R.string.onramp_settings_title),
iconRes = R.drawable.ic_close_24,
)
},
@ -81,7 +81,7 @@ private fun ResidenceSection(state: OnrampSettingsItemUM.Residence, modifier: Mo
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = stringResource(id = R.string.onramp_settings_residence),
text = stringResourceSafe(id = R.string.onramp_settings_residence),
color = TangemTheme.colors.text.tertiary,
style = TangemTheme.typography.subtitle2,
)
@ -103,7 +103,7 @@ private fun ResidenceSection(state: OnrampSettingsItemUM.Residence, modifier: Mo
)
}
Text(
text = stringResource(id = R.string.onramp_settings_residence_description),
text = stringResourceSafe(id = R.string.onramp_settings_residence_description),
color = TangemTheme.colors.text.tertiary,
style = TangemTheme.typography.caption2,
)

View file

@ -12,7 +12,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
@ -27,10 +26,7 @@ import com.tangem.core.ui.components.appbar.TangemTopAppBar
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
import com.tangem.core.ui.components.containers.FooterContainer
import com.tangem.core.ui.components.transactions.TransactionDoneTitle
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.resourceReference
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.core.ui.utils.DateTimeFormatters
@ -73,7 +69,7 @@ private fun Content(state: OnrampSuccessComponentUM.Content, onBackClick: () ->
},
bottomBar = {
PrimaryButton(
text = stringResource(R.string.common_close),
text = stringResourceSafe(R.string.common_close),
onClick = onBackClick,
modifier = Modifier
.fillMaxWidth()
@ -171,7 +167,7 @@ private fun AmountProviderBlock(providerName: TextReference, providerImageUrl: S
horizontalArrangement = Arrangement.spacedBy(6.dp),
) {
Text(
text = stringResource(R.string.common_with),
text = stringResourceSafe(R.string.common_with),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,
)

View file

@ -14,7 +14,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
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
@ -25,10 +24,7 @@ import com.tangem.core.ui.components.marketprice.PriceChangeType
import com.tangem.core.ui.components.rows.NetworkTitle
import com.tangem.core.ui.components.token.TokenItem
import com.tangem.core.ui.components.token.state.TokenItemState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.utils.dashedBorder
@ -98,7 +94,7 @@ private fun RemoveButton(state: ExchangeCardUM.RemoveButtonUM?) {
state ?: return@AnimatedVisibility
Text(
text = stringResource(id = R.string.manage_tokens_remove),
text = stringResourceSafe(id = R.string.manage_tokens_remove),
modifier = Modifier.clickable(
indication = ripple(bounded = false),
interactionSource = remember { MutableInteractionSource() },

View file

@ -13,9 +13,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.utils.rememberHideKeyboardNestedScrollConnection
import com.tangem.features.onramp.impl.R
@ -59,7 +59,7 @@ internal fun SwapSelectTokens(
stickyHeader(key = "header") {
AppBarWithBackButton(
onBackClick = state.onBackClick,
text = stringResource(id = R.string.common_swap),
text = stringResourceSafe(id = R.string.common_swap),
iconRes = R.drawable.ic_close_24,
containerColor = TangemTheme.colors.background.secondary,
)

View file

@ -25,6 +25,8 @@ import com.tangem.feature.qrscanning.viewmodel.QrScanningViewModel
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import timber.log.Timber
import java.io.IOException
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import javax.inject.Inject
@ -62,8 +64,15 @@ internal class QrScanningFragment : ComposeFragment() {
private val galleryLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) {
val selectedImage = it ?: Uri.EMPTY
if (selectedImage != Uri.EMPTY) {
val image = InputImage.fromFilePath(requireContext(), selectedImage)
analyzer.analyze(image)
val mimeType = requireContext().contentResolver.getType(selectedImage)
if (mimeType.isImageMimeType()) {
try {
val image = InputImage.fromFilePath(requireContext(), selectedImage)
analyzer.analyze(image)
} catch (e: IOException) {
Timber.e(e, "Unable to get image $selectedImage from gallery")
}
}
}
}
@ -80,7 +89,7 @@ internal class QrScanningFragment : ComposeFragment() {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.launchGalleryEvent
.collect {
galleryLauncher.launch(it.imageFilter)
galleryLauncher.launch(GALLERY_IMAGE_FILTER)
delay(timeMillis = 2000)
}
}
@ -137,8 +146,13 @@ internal class QrScanningFragment : ComposeFragment() {
}
}
private fun String?.isImageMimeType() = this?.startsWith(prefix = "$IMAGE_MIME_TYPE/") == true
companion object {
private const val IMAGE_MIME_TYPE = "image"
private const val GALLERY_IMAGE_FILTER = "$IMAGE_MIME_TYPE/*"
fun create() = QrScanningFragment()
}
}

View file

@ -3,6 +3,7 @@ package com.tangem.feature.qrscanning.presentation
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
data class CameraDeniedBottomSheetConfig(
val onSettingsClick: () -> Unit,
val onGalleryClick: () -> Unit,
val onCancelClick: () -> Unit,
) : TangemBottomSheetConfigContent

View file

@ -1,9 +1,6 @@
package com.tangem.feature.qrscanning.presentation
import android.content.Intent
import android.content.res.Configuration
import android.net.Uri
import android.provider.Settings
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
@ -11,13 +8,11 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.content.ContextCompat
import com.tangem.core.ui.components.SimpleSettingsRow
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.feature.qrscanning.impl.R
@ -36,26 +31,19 @@ fun CameraDeniedBottomSheet(config: TangemBottomSheetConfig) {
@Composable
private fun CameraDeniedBottomSheet(content: CameraDeniedBottomSheetConfig) {
val context = LocalContext.current
Column {
SimpleSettingsRow(
title = stringResource(id = R.string.qr_scanner_camera_denied_settings_button),
title = stringResourceSafe(id = R.string.qr_scanner_camera_denied_settings_button),
icon = R.drawable.ic_settings_24,
onItemsClick = {
val intent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", context.packageName, null),
)
ContextCompat.startActivity(context, intent, null)
},
onItemsClick = content.onSettingsClick,
)
SimpleSettingsRow(
title = stringResource(id = R.string.qr_scanner_camera_denied_gallery_button),
title = stringResourceSafe(id = R.string.qr_scanner_camera_denied_gallery_button),
icon = R.drawable.ic_gallery_24,
onItemsClick = content.onGalleryClick,
)
SimpleSettingsRow(
title = stringResource(id = R.string.common_close),
title = stringResourceSafe(id = R.string.common_close),
icon = R.drawable.ic_close_24,
onItemsClick = content.onCancelClick,
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing16),
@ -75,12 +63,12 @@ private fun CameraDeniedBottomSheetHeader(modifier: Modifier = Modifier) {
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4),
) {
Text(
text = stringResource(id = R.string.qr_scanner_camera_denied_title),
text = stringResourceSafe(id = R.string.qr_scanner_camera_denied_title),
style = TangemTheme.typography.subtitle1,
color = TangemTheme.colors.text.primary1,
)
Text(
text = stringResource(id = R.string.qr_scanner_camera_denied_text),
text = stringResourceSafe(id = R.string.qr_scanner_camera_denied_text),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.secondary,
)
@ -98,6 +86,7 @@ private fun Preview_CameraDeniedBottomSheet() {
isShow = true,
onDismissRequest = {},
content = CameraDeniedBottomSheetConfig(
onSettingsClick = {},
onCancelClick = {},
onGalleryClick = {},
),

View file

@ -15,6 +15,7 @@ internal class ShowCameraDeniedBottomSheetTransformer(
isShow = true,
onDismissRequest = clickIntents::onBackClick,
content = CameraDeniedBottomSheetConfig(
onSettingsClick = clickIntents::onSettingsClick,
onCancelClick = clickIntents::onBackClick,
onGalleryClick = clickIntents::onGalleryClicked,
),

View file

@ -1,5 +1,6 @@
package com.tangem.feature.qrscanning.viewmodel
import com.tangem.core.navigation.settings.SettingsManager
import com.tangem.domain.qrscanning.usecases.EmitQrScannedEventUseCase
import com.tangem.feature.qrscanning.presentation.QrScanningStateController
import com.tangem.feature.qrscanning.presentation.transformers.DismissBottomSheetTransformer
@ -11,32 +12,30 @@ import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.launch
import javax.inject.Inject
interface QrScanningClickIntents {
internal interface QrScanningClickIntents {
val launchGallery: SharedFlow<GalleryRequest>
val launchGallery: SharedFlow<Unit>
fun onBackClick()
fun onQrScanned(qrCode: String)
fun onGalleryClicked()
}
@JvmInline
value class GalleryRequest(
val imageFilter: String,
)
fun onSettingsClick()
}
@ViewModelScoped
internal class QrScanningClickIntentsImplementor @Inject constructor(
private val stateHolder: QrScanningStateController,
private val emitQrScannedEventUseCase: EmitQrScannedEventUseCase,
private val settingsManager: SettingsManager,
private val dispatcher: CoroutineDispatcherProvider,
) : BaseQrScanningClickIntents(), QrScanningClickIntents {
private var isScanned = false
override val launchGallery = MutableSharedFlow<GalleryRequest>(
override val launchGallery = MutableSharedFlow<Unit>(
extraBufferCapacity = 1,
onBufferOverflow = BufferOverflow.DROP_LATEST,
)
@ -56,13 +55,13 @@ internal class QrScanningClickIntentsImplementor @Inject constructor(
}
override fun onGalleryClicked() {
launchGallery.tryEmit(GalleryRequest(imageFilter = GALLERY_IMAGE_FILTER))
launchGallery.tryEmit(Unit)
if (stateHolder.value.bottomSheetConfig != null) {
stateHolder.update(DismissBottomSheetTransformer())
}
}
companion object {
private const val GALLERY_IMAGE_FILTER = "image/*"
override fun onSettingsClick() {
settingsManager.openSettings()
}
}

View file

@ -31,7 +31,7 @@ internal class QrScanningViewModel @Inject constructor(
private val network: String? = savedStateHandle[AppRoute.QrScanning.NETWORK_KEY]
val uiState: StateFlow<QrScanningState> = stateHolder.uiState
val launchGalleryEvent: SharedFlow<GalleryRequest> = clickIntents.launchGallery
val launchGalleryEvent: SharedFlow<Unit> = clickIntents.launchGallery
init {
// samsung for some reason disables reader mode, and then it works unstable

View file

@ -14,6 +14,7 @@ dependencies {
/** Core modules */
implementation(projects.core.analytics)
implementation(projects.core.analytics.models)
implementation(projects.core.navigation)
implementation(projects.core.res)
implementation(projects.core.utils)
implementation(projects.core.ui)
@ -37,7 +38,6 @@ dependencies {
/** Other libraries */
implementation(deps.compose.shimmer)
implementation(deps.compose.accompanist.webView)
implementation(deps.compose.accompanist.systemUiController)
/** DI */

View file

@ -50,6 +50,6 @@ internal data class ReferralStateHolder(
data class Analytics(
val onAgreementClicked: () -> Unit,
val onCopyClicked: () -> Unit,
val onShareClicked: () -> Unit,
val onShareClicked: (String) -> Unit,
)
}

View file

@ -1,66 +0,0 @@
package com.tangem.feature.referral.ui
import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.google.accompanist.web.WebView
import com.google.accompanist.web.rememberWebViewState
import com.tangem.core.ui.components.appbar.TangemTopAppBar
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.webview.applySafeSettings
import com.tangem.feature.referral.presentation.R
/**
* Bottom sheet content with referral program terms of use
*
* @param url link to the html page
* @param bottomBarHeight bottom insets
*/
@Composable
internal fun AgreementBottomSheetContent(url: String, bottomBarHeight: Dp) {
Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState()),
) {
TangemTopAppBar(title = stringResource(id = R.string.details_referral_title))
AgreementHtmlView(url = url)
Spacer(modifier = Modifier.height(bottomBarHeight))
}
}
@Composable
private fun AgreementHtmlView(url: String) {
val state = rememberWebViewState(url)
val isInPreviewMode = LocalInspectionMode.current
WebView(
state = state,
modifier = Modifier.background(TangemTheme.colors.background.primary),
captureBackPresses = false,
onCreated = {
if (!isInPreviewMode) it.applySafeSettings()
},
)
}
@Preview
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun Preview_AgreementBottomSheet() {
TangemThemePreview {
AgreementBottomSheetContent(url = "https://tangem.com/en/", 50.dp)
}
}

View file

@ -9,20 +9,20 @@ import androidx.compose.foundation.layout.padding
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.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.feature.referral.presentation.R
@Composable
internal fun AgreementText(@StringRes firstPartResId: Int, onClick: () -> Unit) {
val agreementText = annotatedAgreementString(firstPart = stringResource(firstPartResId))
val agreementText = annotatedAgreementString(firstPart = stringResourceSafe(firstPartResId))
ClickableText(
text = agreementText,
modifier = Modifier
@ -46,10 +46,10 @@ private fun annotatedAgreementString(firstPart: String): AnnotatedString {
append("$firstPart ")
}
withStyle(SpanStyle(color = TangemTheme.colors.text.accent)) {
append(stringResource(id = R.string.common_terms_and_conditions))
append(stringResourceSafe(id = R.string.common_terms_and_conditions))
}
withStyle(SpanStyle(color = TangemTheme.colors.text.tertiary)) {
append(" ${stringResource(id = R.string.referral_tos_suffix)}")
append(" ${stringResourceSafe(id = R.string.referral_tos_suffix)}")
}
}
}

View file

@ -7,9 +7,9 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.components.PrimaryButtonIconEnd
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.feature.referral.presentation.R
@ -23,7 +23,7 @@ internal fun NonParticipateBottomBlock(onAgreementClick: () -> Unit, onParticipa
)
PrimaryButtonIconEnd(
text = stringResource(id = R.string.referral_button_participate),
text = stringResourceSafe(id = R.string.referral_button_participate),
iconResId = R.drawable.ic_tangem_24,
onClick = onParticipateClick,
modifier = Modifier

Some files were not shown because too many files have changed in this diff Show more