Updated on 2026-08-14

This commit is contained in:
Tangem 2024-12-16 18:07:48 +03:00
commit 8232cc6e18
255 changed files with 2657 additions and 2338 deletions

View file

@ -18,7 +18,6 @@ import androidx.compose.ui.focus.focusRequester
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.datasource.CollectionPreviewParameterProvider
@ -27,8 +26,9 @@ import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.SpacerW
import com.tangem.core.ui.event.EventEffect
import com.tangem.core.ui.event.consumedEvent
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.tap.features.details.ui.appcurrency.AppCurrencySelectorState.Currency
import com.tangem.wallet.R
import kotlinx.collections.immutable.ImmutableList
@ -114,7 +114,7 @@ private fun TopBar(
is AppCurrencySelectorState.Loading,
is AppCurrencySelectorState.Default,
-> Text(
text = stringResource(id = R.string.details_row_title_currency),
text = stringResourceSafe(id = R.string.details_row_title_currency),
style = TangemTheme.typography.subtitle1,
)
}
@ -163,7 +163,7 @@ private fun SearchBar(onInputChange: (String) -> Unit, modifier: Modifier = Modi
singleLine = true,
textStyle = TangemTheme.typography.subtitle2,
placeholder = {
Text(text = stringResource(id = R.string.common_search))
Text(text = stringResourceSafe(id = R.string.common_search))
},
colors = SearchBarColors,
)

View file

@ -2,13 +2,13 @@ package com.tangem.tap.features.details.ui.appsettings.components
import android.content.res.Configuration
import androidx.compose.runtime.Composable
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
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.res.TangemThemePreview
import com.tangem.tap.features.details.ui.appsettings.AppSettingsDialogsFactory
import com.tangem.tap.features.details.ui.appsettings.AppSettingsScreenState.Dialog
@ -26,7 +26,7 @@ internal fun SettingsAlertDialog(dialog: Dialog.Alert) {
onClick = dialog.onConfirm,
),
dismissButton = DialogButtonUM(
title = stringResource(id = R.string.common_cancel),
title = stringResourceSafe(id = R.string.common_cancel),
onClick = dialog.onDismiss,
),
onDismissDialog = dialog.onDismiss,

View file

@ -2,13 +2,13 @@ package com.tangem.tap.features.details.ui.appsettings.components
import android.content.res.Configuration
import androidx.compose.runtime.Composable
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
import com.tangem.core.ui.components.DialogButtonUM
import com.tangem.core.ui.components.SelectorDialog
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.tap.features.details.ui.appsettings.AppSettingsDialogsFactory
import com.tangem.tap.features.details.ui.appsettings.AppSettingsScreenState.Dialog
@ -22,7 +22,7 @@ internal fun SettingsSelectorDialog(dialog: Dialog.Selector) {
selectedItemIndex = dialog.selectedItemIndex,
items = dialog.items.map { it.resolveReference() }.toImmutableList(),
confirmButton = DialogButtonUM(
title = stringResource(R.string.common_cancel),
title = stringResourceSafe(R.string.common_cancel),
onClick = dialog.onDismiss,
),
onSelect = dialog.onSelect,

View file

@ -14,8 +14,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.tap.features.details.ui.common.DetailsMainButton
@ -88,13 +88,13 @@ private fun CardSettingsReadCard(onScanCardClick: () -> Unit) {
),
) {
Text(
text = stringResource(id = R.string.scan_card_settings_title),
text = stringResourceSafe(id = R.string.scan_card_settings_title),
color = TangemTheme.colors.text.primary1,
style = TangemTheme.typography.h3,
)
Spacer(modifier = Modifier.size(TangemTheme.dimens.size20))
Text(
text = stringResource(id = R.string.scan_card_settings_message),
text = stringResourceSafe(id = R.string.scan_card_settings_message),
color = TangemTheme.colors.text.secondary,
style = TangemTheme.typography.body1,
modifier = Modifier
@ -103,7 +103,7 @@ private fun CardSettingsReadCard(onScanCardClick: () -> Unit) {
)
Spacer(modifier = Modifier.size(TangemTheme.dimens.size32))
DetailsMainButton(
title = stringResource(id = R.string.scan_card_settings_button),
title = stringResourceSafe(id = R.string.scan_card_settings_button),
onClick = onScanCardClick,
)
}

View file

@ -3,7 +3,7 @@ package com.tangem.tap.features.details.ui.cardsettings
import androidx.annotation.StringRes
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.res.stringResource
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.tap.features.details.redux.SecurityOption
import com.tangem.tap.features.details.ui.securitymode.toTitleRes
import com.tangem.wallet.R
@ -77,7 +77,7 @@ internal sealed interface TextReference {
@ReadOnlyComposable
internal fun TextReference.resolveReference(): String {
return when (this) {
is TextReference.Res -> stringResource(this.id, *this.formatArgs.toTypedArray())
is TextReference.Res -> stringResourceSafe(this.id, *this.formatArgs.toTypedArray())
is TextReference.Str -> this.value
}
}

View file

@ -5,7 +5,7 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.tap.features.details.ui.common.DetailsMainButton
import com.tangem.tap.features.details.ui.common.DetailsRadioButtonElement
@ -36,14 +36,14 @@ fun AccessCodeRecoveryOptions(state: AccessCodeRecoveryScreenState) {
)
DetailsRadioButtonElement(
title = stringResource(id = R.string.common_enabled),
subtitle = stringResource(id = R.string.card_settings_access_code_recovery_enabled_description),
title = stringResourceSafe(id = R.string.common_enabled),
subtitle = stringResourceSafe(id = R.string.card_settings_access_code_recovery_enabled_description),
selected = state.enabledSelection,
onClick = { state.onOptionClick(true) },
)
DetailsRadioButtonElement(
title = stringResource(id = R.string.common_disabled),
subtitle = stringResource(id = R.string.card_settings_access_code_recovery_disabled_description),
title = stringResourceSafe(id = R.string.common_disabled),
subtitle = stringResourceSafe(id = R.string.card_settings_access_code_recovery_disabled_description),
selected = !state.enabledSelection,
onClick = { state.onOptionClick(false) },
)
@ -51,7 +51,7 @@ fun AccessCodeRecoveryOptions(state: AccessCodeRecoveryScreenState) {
Spacer(modifier = Modifier.weight(1f))
DetailsMainButton(
title = stringResource(id = R.string.common_save_changes),
title = stringResourceSafe(id = R.string.common_save_changes),
enabled = state.isSaveChangesEnabled,
onClick = { state.onSaveChangesClick() },
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing20),

View file

@ -10,9 +10,9 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
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.utils.WindowInsetsZero
import com.tangem.wallet.R
@ -64,7 +64,7 @@ internal fun SettingsScreensScaffold(
) {
if (titleRes != null) {
Text(
text = stringResource(id = titleRes),
text = stringResourceSafe(id = titleRes),
modifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing20)
.padding(bottom = TangemTheme.dimens.spacing36),
@ -82,7 +82,7 @@ internal fun SettingsScreensScaffold(
@Composable
internal fun ScreenTitle(titleRes: Int, modifier: Modifier = Modifier) {
Text(
text = stringResource(id = titleRes),
text = stringResourceSafe(id = titleRes),
modifier = modifier.padding(start = 20.dp, end = 20.dp),
style = TangemTheme.typography.h1,
color = TangemTheme.colors.text.primary1,

View file

@ -10,9 +10,9 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
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.*
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.tap.features.details.ui.cardsettings.TextReference
@ -71,7 +71,7 @@ private fun ResetCardView(state: ResetCardScreenState) {
@Composable
private fun Title() {
Text(
text = stringResource(id = R.string.card_settings_reset_card_to_factory),
text = stringResourceSafe(id = R.string.card_settings_reset_card_to_factory),
style = TangemTheme.typography.h1,
color = TangemTheme.colors.text.primary1,
)
@ -89,7 +89,7 @@ private fun AlertImage() {
@Composable
private fun Subtitle() {
Text(
text = stringResource(id = R.string.common_attention),
text = stringResourceSafe(id = R.string.common_attention),
style = TangemTheme.typography.h3,
color = TangemTheme.colors.text.primary1,
)
@ -179,7 +179,7 @@ private fun ColumnScope.DynamicSpacer(scrollState: ScrollState) {
@Composable
private fun ResetButton(enabled: Boolean, onResetButtonClick: () -> Unit) {
DetailsMainButton(
title = stringResource(id = R.string.reset_card_to_factory_button_title),
title = stringResourceSafe(id = R.string.reset_card_to_factory_button_title),
onClick = onResetButtonClick,
enabled = enabled,
)
@ -188,14 +188,14 @@ private fun ResetButton(enabled: Boolean, onResetButtonClick: () -> Unit) {
@Composable
private fun CommonResetDialog(dialog: ResetCardScreenState.Dialog) {
BasicDialog(
title = stringResource(dialog.titleResId),
message = stringResource(dialog.messageResId),
title = stringResourceSafe(dialog.titleResId),
message = stringResourceSafe(dialog.messageResId),
dismissButton = DialogButtonUM(
title = stringResource(id = R.string.common_cancel),
title = stringResourceSafe(id = R.string.common_cancel),
onClick = dialog.onDismiss,
),
confirmButton = DialogButtonUM(
title = stringResource(id = R.string.card_settings_action_sheet_reset),
title = stringResourceSafe(id = R.string.card_settings_action_sheet_reset),
warning = true,
onClick = dialog.onConfirmClick,
),
@ -206,10 +206,10 @@ private fun CommonResetDialog(dialog: ResetCardScreenState.Dialog) {
@Composable
private fun CompletedResetDialog(dialog: ResetCardDialog) {
BasicDialog(
title = stringResource(id = dialog.titleResId),
message = stringResource(id = dialog.messageResId),
title = stringResourceSafe(id = dialog.titleResId),
message = stringResourceSafe(id = dialog.messageResId),
confirmButton = DialogButtonUM(
title = stringResource(id = R.string.common_ok),
title = stringResourceSafe(id = R.string.common_ok),
onClick = dialog.onConfirmClick,
),
onDismissDialog = {},

View file

@ -5,9 +5,9 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.tap.features.details.redux.SecurityOption
import com.tangem.tap.features.details.ui.common.DetailsMainButton
import com.tangem.tap.features.details.ui.common.DetailsRadioButtonElement
@ -47,7 +47,7 @@ private fun SecurityModeOptions(state: SecurityModeScreenState) {
Spacer(modifier = Modifier.weight(1f))
DetailsMainButton(
title = stringResource(id = R.string.common_save_changes),
title = stringResourceSafe(id = R.string.common_save_changes),
enabled = state.isSaveChangesEnabled,
onClick = state.onSaveChangesClicked,
modifier = Modifier.padding(start = 20.dp, end = 20.dp),
@ -68,8 +68,8 @@ private fun SecurityOption(option: SecurityOption, state: SecurityModeScreenStat
}
DetailsRadioButtonElement(
title = stringResource(id = title),
subtitle = stringResource(id = subtitle),
title = stringResourceSafe(id = title),
subtitle = stringResourceSafe(id = subtitle),
selected = selected,
onClick = { state.onNewModeSelected(option) },
)
@ -80,7 +80,7 @@ private fun SecurityOption(option: SecurityOption, state: SecurityModeScreenStat
private fun SecurityModeScreenPreview() {
SecurityModeScreen(
state = SecurityModeScreenState(
availableOptions = SecurityOption.values().toList(),
availableOptions = SecurityOption.entries,
selectedSecurityMode = SecurityOption.LongTap,
isSaveChangesEnabled = false,
onNewModeSelected = {},

View file

@ -13,10 +13,10 @@ import androidx.compose.ui.graphics.ColorFilter
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 androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.analytics.Analytics
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.tap.common.analytics.events.Settings
import com.tangem.tap.common.extensions.getFromClipboard
@ -96,7 +96,7 @@ private fun EmptyScreen(state: WalletConnectScreenState) {
)
Spacer(modifier = Modifier.size(24.dp))
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.tertiary,
)

View file

@ -2,20 +2,23 @@ package com.tangem.tap.features.home.compose.content
import androidx.annotation.DrawableRes
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
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 androidx.compose.ui.unit.dp
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.stringResourceSafe
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.tap.features.home.compose.StoriesBottomImageAnimation
@ -27,8 +30,8 @@ fun StoriesRevolutionaryWallet() {
SplitContent(
topContent = {
TopContent(
titleText = stringResource(id = R.string.story_awe_title),
subtitleText = stringResource(id = R.string.story_awe_description),
titleText = stringResourceSafe(id = R.string.story_awe_title),
subtitleText = stringResourceSafe(id = R.string.story_awe_description),
)
},
bottomContent = {
@ -46,8 +49,8 @@ fun StoriesUltraSecureBackup(isPaused: Boolean, stepDuration: Int) {
SplitContent(
topContent = {
TopContent(
titleText = stringResource(id = R.string.story_backup_title),
subtitleText = stringResource(id = R.string.story_backup_description),
titleText = stringResourceSafe(id = R.string.story_backup_title),
subtitleText = stringResourceSafe(id = R.string.story_backup_description),
)
},
bottomContent = {
@ -65,8 +68,8 @@ fun StoriesCurrencies(isPaused: Boolean, stepDuration: Int) {
SplitContent(
topContent = {
TopContent(
titleText = stringResource(id = R.string.story_currencies_title),
subtitleText = stringResource(id = R.string.story_currencies_description),
titleText = stringResourceSafe(id = R.string.story_currencies_title),
subtitleText = stringResourceSafe(id = R.string.story_currencies_description),
)
},
bottomContent = {
@ -81,8 +84,8 @@ fun StoriesWeb3(isPaused: Boolean, stepDuration: Int) {
SplitContent(
topContent = {
TopContent(
titleText = stringResource(id = R.string.story_web3_title),
subtitleText = stringResource(id = R.string.story_web3_description),
titleText = stringResourceSafe(id = R.string.story_web3_title),
subtitleText = stringResourceSafe(id = R.string.story_web3_description),
)
},
bottomContent = {
@ -97,8 +100,8 @@ fun StoriesWalletForEveryone(stepDuration: Int) {
SplitContent(
topContent = {
TopContent(
titleText = stringResource(id = R.string.story_finish_title),
subtitleText = stringResource(id = R.string.story_finish_description),
titleText = stringResourceSafe(id = R.string.story_finish_title),
subtitleText = stringResourceSafe(id = R.string.story_finish_description),
)
},
bottomContent = {

View file

@ -16,13 +16,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.sp
import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.tap.features.home.compose.StoriesTextAnimation
@ -66,7 +66,7 @@ fun FirstStoriesContent(isPaused: Boolean, duration: Int) {
) { modifier ->
Text(
modifier = modifier,
text = stringResource(R.string.story_meet_title),
text = stringResourceSafe(R.string.story_meet_title),
style = style,
color = TangemColorPalette.White,
textAlign = TextAlign.Center,

View file

@ -9,12 +9,12 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.testTag
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
import com.tangem.core.ui.components.SpacerW12
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
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.test.TestTags
@ -52,7 +52,7 @@ internal fun HomeButtons(
private fun ScanCardButton(showProgress: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) {
StoriesButton(
modifier = modifier,
text = stringResource(id = R.string.home_button_scan),
text = stringResourceSafe(id = R.string.home_button_scan),
useDarkerColors = false,
icon = TangemButtonIconPosition.End(iconResId = R.drawable.ic_tangem_24),
onClick = onClick,
@ -64,7 +64,7 @@ private fun ScanCardButton(showProgress: Boolean, onClick: () -> Unit, modifier:
private fun OrderCardButton(onClick: () -> Unit, modifier: Modifier = Modifier) {
StoriesButton(
modifier = modifier,
text = stringResource(id = R.string.home_button_order),
text = stringResourceSafe(id = R.string.home_button_order),
useDarkerColors = true,
onClick = onClick,
)

View file

@ -7,9 +7,9 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.wallet.R
@ -18,7 +18,7 @@ import com.tangem.wallet.R
internal fun SearchCurrenciesButton(onClick: () -> Unit, modifier: Modifier = Modifier) {
StoriesButton(
modifier = modifier,
text = stringResource(id = R.string.common_search_tokens),
text = stringResourceSafe(id = R.string.common_search_tokens),
icon = TangemButtonIconPosition.Start(R.drawable.ic_search_24),
showProgress = false,
useDarkerColors = true,

View file

@ -1,23 +0,0 @@
package com.tangem.tap.features.home.data
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.models.GeoResponse
import com.tangem.tap.features.home.domain.HomeRepository
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.withContext
/**
* Implementation of repository for Home feature
*
* @property tangemTechApi API for server requests
* @property dispatchers coroutine dispatcher provider
*/
class HomeRepositoryImpl(
private val tangemTechApi: TangemTechApi,
private val dispatchers: CoroutineDispatcherProvider,
) : HomeRepository {
override suspend fun getUserCountryCode(): GeoResponse = withContext(dispatchers.io) {
tangemTechApi.getUserCountryCode()
}
}

View file

@ -1,10 +0,0 @@
package com.tangem.tap.features.home.domain
import com.tangem.datasource.api.tangemTech.models.GeoResponse
/** Repository for Home feature */
interface HomeRepository {
/** Get user's country code */
suspend fun getUserCountryCode(): GeoResponse
}

View file

@ -1,12 +0,0 @@
package com.tangem.tap.features.home.featuretoggles
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
import javax.inject.Inject
class HomeFeatureToggles @Inject constructor(
private val featureTogglesManager: FeatureTogglesManager,
) {
val isMigrateUserCountryCodeEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled(name = "MIGRATE_USER_COUNTRY_CODE_ENABLED")
}

View file

@ -53,7 +53,6 @@ private fun handleHomeAction(action: Action) {
store.dispatch(GlobalAction.RestoreAppCurrency)
store.dispatch(GlobalAction.ExchangeManager.Init)
store.dispatch(GlobalAction.FetchUserCountry)
}
is HomeAction.ReadCard -> {
action.scope.launch {

View file

@ -18,7 +18,6 @@ import com.tangem.domain.settings.usercountry.FetchUserCountryUseCase
import com.tangem.domain.staking.FetchStakingTokensUseCase
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.tap.common.extensions.setContext
import com.tangem.tap.features.home.featuretoggles.HomeFeatureToggles
import com.tangem.tap.features.main.model.MainScreenState
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.hilt.android.lifecycle.HiltViewModel
@ -41,7 +40,6 @@ internal class MainViewModel @Inject constructor(
private val dispatchers: CoroutineDispatcherProvider,
private val fetchStakingTokensUseCase: FetchStakingTokensUseCase,
private val apiConfigsManager: ApiConfigsManager,
homeFeatureToggles: HomeFeatureToggles,
private val fetchUserCountryUseCase: FetchUserCountryUseCase,
getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
) : ViewModel(), MainIntents {
@ -63,11 +61,9 @@ internal class MainViewModel @Inject constructor(
viewModelScope.launch(dispatchers.main) { incrementAppLaunchCounterUseCase() }
if (homeFeatureToggles.isMigrateUserCountryCodeEnabled) {
viewModelScope.launch {
fetchUserCountryUseCase().onLeft {
Timber.e("Unable to fetch the user country code $it")
}
viewModelScope.launch {
fetchUserCountryUseCase().onLeft {
Timber.e("Unable to fetch the user country code $it")
}
}

View file

@ -22,11 +22,9 @@ import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Onboarding
import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.redux.AppDialog
import com.tangem.tap.common.redux.global.GlobalState
import com.tangem.tap.features.demo.DemoHelper
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletAction
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupStartedSource
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletAction
import com.tangem.tap.features.saveWallet.redux.SaveWalletAction
import com.tangem.tap.mainScope
import com.tangem.tap.proxy.redux.DaggerGraphState
@ -50,7 +48,7 @@ object OnboardingHelper {
if (!response.twinsIsTwinned()) {
true
} else {
onboardingManager.isActivationInProgress(cardId) ?: false
onboardingManager.isActivationInProgress(cardId)
}
}
@ -62,7 +60,7 @@ object OnboardingHelper {
emptyWallets || activationInProgress || isNoBackup
}
response.card.wallets.isNotEmpty() -> onboardingManager.isActivationInProgress(cardId) ?: false
response.card.wallets.isNotEmpty() -> onboardingManager.isActivationInProgress(cardId)
else -> true
}
}
@ -70,7 +68,7 @@ object OnboardingHelper {
fun whereToNavigate(scanResponse: ScanResponse): AppRoute {
val newOnboardingSupportTypes = scanResponse.productType == ProductType.Wallet2 ||
scanResponse.productType == ProductType.Ring ||
scanResponse.productType == ProductType.Wallet
scanResponse.productType == ProductType.Wallet // AppRoute.OnboardingOther is also supported
if (store.inject(DaggerGraphState::onboardingV2FeatureToggles).isOnboardingV2Enabled &&
newOnboardingSupportTypes
) {
@ -222,7 +220,7 @@ object OnboardingHelper {
}
}
fun handleTopUpAction(walletManager: WalletManager, scanResponse: ScanResponse, globalState: GlobalState) {
fun handleTopUpAction(walletManager: WalletManager, scanResponse: ScanResponse) {
val blockchain = walletManager.wallet.blockchain
val excludedBlockchains = store.inject(DaggerGraphState::excludedBlockchains)
@ -238,17 +236,10 @@ object OnboardingHelper {
Analytics.send(Onboarding.Topup.ButtonBuyCrypto(currencyType))
scope.launch {
val homeFeatureToggles = store.inject(DaggerGraphState::homeFeatureToggles)
val getUserCountryCodeUseCase = store.inject(DaggerGraphState::getUserCountryUseCase)
val isRussia = getUserCountryCodeUseCase().isRight { it is UserCountry.Russia }
val onrampFeatureToggles = store.inject(DaggerGraphState::onrampFeatureToggles)
val isRussia = if (homeFeatureToggles.isMigrateUserCountryCodeEnabled) {
val getUserCountryCodeUseCase = store.inject(DaggerGraphState::getUserCountryUseCase)
getUserCountryCodeUseCase().isRight { it is UserCountry.Russia }
} else {
globalState.userCountryCode == RUSSIA_COUNTRY_CODE
}
if (isRussia && !onrampFeatureToggles.isFeatureEnabled) {
val dialogData = AppDialog.RussianCardholdersWarningDialog.Data(topUpUrl)
store.dispatchDialogShow(AppDialog.RussianCardholdersWarningDialog(dialogData))

View file

@ -176,7 +176,6 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch
OnboardingHelper.handleTopUpAction(
walletManager = walletManager,
scanResponse = scanResponse,
globalState = globalState,
)
}
is OnboardingNoteAction.Done -> {

View file

@ -299,7 +299,6 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
OnboardingHelper.handleTopUpAction(
walletManager = walletManager,
scanResponse = onboardingManager?.scanResponse ?: return,
globalState = globalState,
)
}
TwinCardsAction.Done -> {

View file

@ -5,11 +5,11 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
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.R
import com.tangem.core.ui.components.BasicDialog
import com.tangem.core.ui.components.DialogButtonUM
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.tap.features.saveWallet.ui.models.EnrollBiometricsDialog
@ -17,10 +17,10 @@ import com.tangem.tap.features.saveWallet.ui.models.EnrollBiometricsDialog
@Composable
fun EnrollBiometricsDialogContent(dialog: EnrollBiometricsDialog) {
BasicDialog(
title = stringResource(R.string.save_user_wallet_agreement_enroll_biometrics_title),
message = stringResource(R.string.save_user_wallet_agreement_enroll_biometrics_description),
title = stringResourceSafe(R.string.save_user_wallet_agreement_enroll_biometrics_title),
message = stringResourceSafe(R.string.save_user_wallet_agreement_enroll_biometrics_description),
confirmButton = DialogButtonUM(
title = stringResource(R.string.common_enable),
title = stringResourceSafe(R.string.common_enable),
onClick = dialog.onEnroll,
),
dismissButton = DialogButtonUM(

View file

@ -11,11 +11,11 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.painter.Painter
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.*
import com.tangem.core.ui.components.atoms.Hand
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.wallet.R
@ -63,7 +63,7 @@ private fun Header(onCloseClick: () -> Unit) {
modifier = Modifier.size(TangemTheme.dimens.size24),
painter = painterResource(id = R.drawable.ic_close_24),
tint = TangemTheme.colors.icon.secondary,
contentDescription = stringResource(id = R.string.common_cancel),
contentDescription = stringResourceSafe(id = R.string.common_cancel),
)
}
SpacerW8()
@ -85,7 +85,7 @@ private fun Title(modifier: Modifier = Modifier) {
contentDescription = null,
)
Text(
text = stringResource(id = R.string.save_user_wallet_agreement_header_biometrics),
text = stringResourceSafe(id = R.string.save_user_wallet_agreement_header_biometrics),
style = TangemTheme.typography.h2,
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.Center,
@ -102,13 +102,13 @@ private fun Description(modifier: Modifier = Modifier) {
) {
DescriptionItem(
iconPainter = painterResource(id = R.drawable.ic_face_recognition_24),
title = stringResource(id = R.string.save_user_wallet_agreement_access_title),
description = stringResource(id = R.string.save_user_wallet_agreement_access_description),
title = stringResourceSafe(id = R.string.save_user_wallet_agreement_access_title),
description = stringResourceSafe(id = R.string.save_user_wallet_agreement_access_description),
)
DescriptionItem(
iconPainter = painterResource(id = R.drawable.ic_lock_24),
title = stringResource(id = R.string.save_user_wallet_agreement_code_title),
description = stringResource(id = R.string.save_user_wallet_agreement_code_description_biometrics),
title = stringResourceSafe(id = R.string.save_user_wallet_agreement_code_title),
description = stringResourceSafe(id = R.string.save_user_wallet_agreement_code_description_biometrics),
)
}
}
@ -125,12 +125,12 @@ private fun Footer(showProgress: Boolean, onSaveWalletClick: () -> Unit) {
PrimaryButton(
modifier = Modifier.fillMaxWidth(),
showProgress = showProgress,
text = stringResource(id = R.string.save_user_wallet_agreement_allow_biometrics),
text = stringResourceSafe(id = R.string.save_user_wallet_agreement_allow_biometrics),
onClick = onSaveWalletClick,
)
Text(
modifier = Modifier.fillMaxWidth(fraction = .7f),
text = stringResource(R.string.save_user_wallet_agreement_notice),
text = stringResourceSafe(R.string.save_user_wallet_agreement_notice),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
textAlign = TextAlign.Center,

View file

@ -17,7 +17,6 @@ import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.redux.AppDialog
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.features.demo.DemoHelper
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager
import com.tangem.tap.network.exchangeServices.buyErc20TestnetTokens
import com.tangem.tap.proxy.redux.DaggerGraphState
@ -26,7 +25,6 @@ import com.tangem.tap.store
import kotlinx.coroutines.launch
import org.rekotlin.Middleware
@Suppress("LargeClass")
@Deprecated("Will be removed soon")
object TradeCryptoMiddleware {
@ -41,25 +39,24 @@ object TradeCryptoMiddleware {
}
}
@Suppress("LongMethod", "CyclomaticComplexMethod")
private fun handle(state: () -> AppState?, action: TradeCryptoAction) {
if (DemoHelper.tryHandle(state, action)) return
when (action) {
is TradeCryptoAction.FinishSelling -> openReceiptUrl(action.transactionId)
is TradeCryptoAction.Buy -> proceedBuyAction(state, action)
is TradeCryptoAction.Buy -> proceedBuyAction(action)
is TradeCryptoAction.Sell -> proceedSellAction(action)
is TradeCryptoAction.SendToken -> handleNewSendToken(action = action)
is TradeCryptoAction.SendCoin -> handleNewSendCoin(action = action)
}
}
private fun proceedBuyAction(state: () -> AppState?, action: TradeCryptoAction.Buy) {
private fun proceedBuyAction(action: TradeCryptoAction.Buy) {
val isOnrampEnabled = store.inject(DaggerGraphState::onrampFeatureToggles).isFeatureEnabled
if (isOnrampEnabled) {
proceedWithOnramp(action.userWallet.walletId, action.cryptoCurrencyStatus.currency, action.source)
} else {
proceedWithLegacyBuyAction(state, action)
proceedWithLegacyBuyAction(action)
}
}
@ -75,7 +72,7 @@ object TradeCryptoMiddleware {
}
}
private fun proceedWithLegacyBuyAction(state: () -> AppState?, action: TradeCryptoAction.Buy) {
private fun proceedWithLegacyBuyAction(action: TradeCryptoAction.Buy) {
val networkAddress = action.cryptoCurrencyStatus.value.networkAddress
?.defaultAddress
?.let(NetworkAddress.Address::value)
@ -94,15 +91,10 @@ object TradeCryptoMiddleware {
)
scope.launch {
val homeFeatureToggles = store.inject(DaggerGraphState::homeFeatureToggles)
val getUserCountryCodeUseCase = store.inject(DaggerGraphState::getUserCountryUseCase)
val onrampFeatureToggles = store.inject(DaggerGraphState::onrampFeatureToggles)
val isRussia = if (homeFeatureToggles.isMigrateUserCountryCodeEnabled) {
val getUserCountryCodeUseCase = store.inject(DaggerGraphState::getUserCountryUseCase)
getUserCountryCodeUseCase().isRight { it is UserCountry.Russia }
} else {
state()?.globalState?.userCountryCode == RUSSIA_COUNTRY_CODE
}
val isRussia = getUserCountryCodeUseCase().isRight { it is UserCountry.Russia }
if (action.checkUserLocation && isRussia && !onrampFeatureToggles.isFeatureEnabled) {
val dialogData = topUrl?.let {

View file

@ -130,6 +130,5 @@ internal class WelcomeViewModel @Inject constructor(
private fun initGlobalState() {
store.dispatch(GlobalAction.RestoreAppCurrency)
store.dispatch(GlobalAction.ExchangeManager.Init)
store.dispatch(GlobalAction.FetchUserCountry)
}
}

View file

@ -4,10 +4,10 @@ import android.content.res.Configuration
import androidx.compose.foundation.layout.Column
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.BasicDialog
import com.tangem.core.ui.components.DialogButtonUM
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.tap.features.welcome.ui.model.WarningModel
import com.tangem.wallet.R
@ -18,8 +18,8 @@ internal fun WarningDialog(warning: WarningModel?) {
null -> Unit
is WarningModel.BiometricsLockoutWarning -> {
BasicDialog(
title = stringResource(id = R.string.biometric_lockout_warning_title),
message = stringResource(
title = stringResourceSafe(id = R.string.biometric_lockout_warning_title),
message = stringResourceSafe(
id = if (warning.isPermanent) {
R.string.biometric_lockout_permanent_warning_description
} else {
@ -28,30 +28,30 @@ internal fun WarningDialog(warning: WarningModel?) {
),
onDismissDialog = warning.onDismiss,
confirmButton = DialogButtonUM(
title = stringResource(id = R.string.common_ok),
title = stringResourceSafe(id = R.string.common_ok),
onClick = warning.onDismiss,
),
)
}
is WarningModel.KeyInvalidatedWarning -> {
BasicDialog(
title = stringResource(id = R.string.common_attention),
message = stringResource(id = R.string.key_invalidated_warning_description),
title = stringResourceSafe(id = R.string.common_attention),
message = stringResourceSafe(id = R.string.key_invalidated_warning_description),
onDismissDialog = warning.onDismiss,
confirmButton = DialogButtonUM(
title = stringResource(id = R.string.common_ok),
title = stringResourceSafe(id = R.string.common_ok),
onClick = warning.onDismiss,
),
)
}
is WarningModel.BiometricsDisabledWarning -> {
BasicDialog(
title = stringResource(id = R.string.common_warning),
message = stringResource(id = R.string.biometric_unavailable_warning),
title = stringResourceSafe(id = R.string.common_warning),
message = stringResourceSafe(id = R.string.biometric_unavailable_warning),
onDismissDialog = warning.onDismiss,
isDismissable = false,
confirmButton = DialogButtonUM(
title = stringResource(id = R.string.common_ok),
title = stringResourceSafe(id = R.string.common_ok),
onClick = warning.onDismiss,
),
)

View file

@ -9,10 +9,10 @@ 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.*
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.wallet.R
@ -38,7 +38,7 @@ internal fun WelcomeScreenContent(
modifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing16)
.fillMaxWidth(),
text = stringResource(R.string.welcome_unlock_title),
text = stringResourceSafe(R.string.welcome_unlock_title),
style = TangemTheme.typography.h2,
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.Center,
@ -48,9 +48,9 @@ internal fun WelcomeScreenContent(
modifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing44)
.fillMaxWidth(),
text = stringResource(
text = stringResourceSafe(
id = R.string.welcome_unlock_description,
stringResource(id = R.string.common_biometric_authentication),
stringResourceSafe(id = R.string.common_biometric_authentication),
),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.secondary,
@ -61,9 +61,9 @@ internal fun WelcomeScreenContent(
modifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing16)
.fillMaxWidth(),
text = stringResource(
text = stringResourceSafe(
id = R.string.welcome_unlock,
stringResource(id = R.string.common_biometrics),
stringResourceSafe(id = R.string.common_biometrics),
),
showProgress = showUnlockProgress,
onClick = onUnlockClick,
@ -73,7 +73,7 @@ internal fun WelcomeScreenContent(
modifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing16)
.fillMaxWidth(),
text = stringResource(R.string.welcome_unlock_card),
text = stringResourceSafe(R.string.welcome_unlock_card),
showProgress = showScanCardProgress,
iconResId = R.drawable.ic_tangem_24,
onClick = onScanCardClick,