Updated on 2026-08-14

This commit is contained in:
Tangem 2022-07-06 18:07:27 +04:00
parent 7a202ea6dc
commit a0e31b3412
18 changed files with 448 additions and 53 deletions

View file

@ -6,6 +6,8 @@ import com.tangem.tap.common.redux.AppDialog
import com.tangem.tap.common.redux.global.GlobalState
import com.tangem.tap.common.ui.SimpleAlertDialog
import com.tangem.tap.common.ui.SimpleCancelableAlertDialog
import com.tangem.tap.features.details.redux.DetailsDialog
import com.tangem.tap.features.details.redux.PrivacySetting
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectDialog
import com.tangem.tap.features.details.ui.walletconnect.dialogs.*
import com.tangem.tap.features.onboarding.AddressInfoBottomSheetDialog
@ -131,6 +133,18 @@ class DialogManager : StoreSubscriber<GlobalState> {
primaryButtonRes = state.dialog.primaryButtonRes,
primaryButtonAction = state.dialog.onOk
)
is DetailsDialog.ConfirmDisablingSaving -> {
val messageRes = when (state.dialog.setting) {
PrivacySetting.SAVE_CARDS -> R.string.security_and_privacy_save_card_disable_warning
PrivacySetting.SAVE_ACCESS_CODE -> R.string.security_and_privacy_save_password_disable_warning
}
SimpleCancelableAlertDialog.create(
titleRes = R.string.common_warning,
messageRes = messageRes,
context = context,
primaryButtonAction = state.dialog.onOk
)
}
else -> null
}
dialog?.show()

View file

@ -10,6 +10,8 @@ import com.tangem.tap.common.redux.navigation.FragmentShareTransition
import com.tangem.tap.features.details.ui.DetailsConfirmFragment
import com.tangem.tap.features.details.ui.DetailsFragment
import com.tangem.tap.features.details.ui.DetailsSecurityFragment
import com.tangem.tap.features.details.ui.securityprivacy.ChangeAccessCodeFragment
import com.tangem.tap.features.details.ui.securityprivacy.SecurityAndPrivacyFragment
import com.tangem.tap.features.details.ui.walletconnect.QrScanFragment
import com.tangem.tap.features.details.ui.walletconnect.WalletConnectSessionsFragment
import com.tangem.tap.features.disclaimer.ui.DisclaimerFragment
@ -90,6 +92,8 @@ private fun fragmentFactory(screen: AppScreen): Fragment {
AppScreen.Details -> DetailsFragment()
AppScreen.DetailsConfirm -> DetailsConfirmFragment()
AppScreen.DetailsSecurity -> DetailsSecurityFragment()
AppScreen.SecurityAndPrivacy -> SecurityAndPrivacyFragment()
AppScreen.ChangeAccessCode -> ChangeAccessCodeFragment()
AppScreen.Disclaimer -> DisclaimerFragment()
AppScreen.AddTokens -> AddTokensFragment()
AppScreen.AddCustomToken -> AddCustomTokenFragment()

View file

@ -16,7 +16,7 @@ enum class AppScreen {
OnboardingNote, OnboardingWallet, OnboardingTwins, OnboardingOther,
Wallet, WalletDetails,
Send,
Details, DetailsConfirm, DetailsSecurity,
Details, DetailsConfirm, DetailsSecurity, SecurityAndPrivacy, ChangeAccessCode,
AddTokens, AddCustomToken,
WalletConnectSessions,
QrScan

View file

@ -59,5 +59,13 @@ sealed class DetailsAction : Action {
}
}
sealed class ManagePrivacy : DetailsAction() {
data class SwitchPrivacySetting(val allow: Boolean, val setting: PrivacySetting) :
ManagePrivacy()
data class ConfirmSwitchingSetting(val allow: Boolean, val setting: PrivacySetting) :
ManagePrivacy()
}
data class ChangeAppCurrency(val fiatCurrency: FiatCurrency) : DetailsAction()
}

View file

@ -6,6 +6,7 @@ import com.tangem.common.core.TangemSdkError
import com.tangem.operations.pins.CheckUserCodesResponse
import com.tangem.tap.common.analytics.Analytics
import com.tangem.tap.common.analytics.AnalyticsParam
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.extensions.dispatchNotification
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.redux.AppState
@ -28,24 +29,28 @@ import org.rekotlin.Middleware
class DetailsMiddleware {
private val eraseWalletMiddleware = EraseWalletMiddleware()
private val manageSecurityMiddleware = ManageSecurityMiddleware()
private val managePrivacyMiddleware = ManagePrivacyMiddleware()
val detailsMiddleware: Middleware<AppState> = { _, _ ->
{ next ->
{ action ->
when (action) {
is DetailsAction.ResetToFactory -> eraseWalletMiddleware.handle(action)
is DetailsAction.ManageSecurity -> manageSecurityMiddleware.handle(action)
is DetailsAction.ManagePrivacy -> managePrivacyMiddleware.handle(action)
is DetailsAction.ShowDisclaimer -> {
store.dispatch(DisclaimerAction.ShowAcceptedDisclaimer)
store.dispatch(NavigationAction.NavigateTo(AppScreen.Disclaimer))
}
is DetailsAction.ReCreateTwinsWallet -> {
val wallet = store.state.walletState.walletManagers.map { it.wallet }.firstOrNull()
val wallet =
store.state.walletState.walletManagers.map { it.wallet }.firstOrNull()
if (wallet == null) {
store.dispatch(TwinCardsAction.SetMode(CreateTwinWalletMode.RecreateWallet))
store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingTwins))
} else {
if (wallet.hasSendableAmountsOrPendingTransactions()) {
val walletIsNotEmpty = store.state.globalState.resources.strings.walletIsNotEmpty
val walletIsNotEmpty =
store.state.globalState.resources.strings.walletIsNotEmpty
store.dispatchNotification(walletIsNotEmpty)
} else {
store.dispatch(TwinCardsAction.SetMode(CreateTwinWalletMode.RecreateWallet))
@ -56,7 +61,12 @@ class DetailsMiddleware {
is DetailsAction.CreateBackup -> {
store.state.detailsState.scanResponse?.let {
store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingWallet))
store.dispatch(GlobalAction.Onboarding.Start(it, fromHomeScreen = false))
store.dispatch(
GlobalAction.Onboarding.Start(
it,
fromHomeScreen = false
)
)
}
}
}
@ -121,13 +131,22 @@ class DetailsMiddleware {
val simulatedResponse = CheckUserCodesResponse(
action.card.isAccessCodeSet, action.card.isPasscodeSet ?: false
)
store.dispatch(DetailsAction.ManageSecurity.SetCurrentOption(simulatedResponse))
store.dispatch(
DetailsAction.ManageSecurity.SetCurrentOption(
simulatedResponse
)
)
store.dispatch(DetailsAction.ManageSecurity.OpenSecurity)
} else {
scope.launch {
when (val response = tangemSdkManager.checkUserCodes(action.card.cardId)) {
when (val response =
tangemSdkManager.checkUserCodes(action.card.cardId)) {
is CompletionResult.Success -> {
store.dispatchOnMain(DetailsAction.ManageSecurity.SetCurrentOption(response.data))
store.dispatchOnMain(
DetailsAction.ManageSecurity.SetCurrentOption(
response.data
)
)
store.dispatchOnMain(DetailsAction.ManageSecurity.OpenSecurity)
}
is CompletionResult.Failure -> {
@ -152,7 +171,8 @@ class DetailsMiddleware {
}
is DetailsAction.ManageSecurity.SaveChanges -> {
val cardId = store.state.detailsState.scanResponse?.card?.cardId
val selectedOption = store.state.detailsState.securityScreenState?.selectedOption
val selectedOption =
store.state.detailsState.securityScreenState?.selectedOption
scope.launch {
val result = when (selectedOption) {
SecurityOption.LongTap -> tangemSdkManager.setLongTap(cardId)
@ -196,4 +216,26 @@ class DetailsMiddleware {
}
}
}
}
class ManagePrivacyMiddleware {
fun handle(action: DetailsAction.ManagePrivacy) {
when (action) {
is DetailsAction.ManagePrivacy.ConfirmSwitchingSetting -> {
// TODO()
}
is DetailsAction.ManagePrivacy.SwitchPrivacySetting -> {
if (action.allow) {
store.dispatch(
DetailsAction.ManagePrivacy.ConfirmSwitchingSetting(
action.allow,
action.setting
)
)
} else {
store.dispatchDialogShow(DetailsDialog.ConfirmDisablingSaving(action.setting))
}
}
}
}
}
}

View file

@ -9,8 +9,8 @@ import com.tangem.tap.domain.extensions.isWalletDataSupported
import com.tangem.tap.domain.extensions.signedHashesCount
import com.tangem.tap.features.wallet.models.hasSendableAmountsOrPendingTransactions
import com.tangem.tap.store
import java.util.EnumSet
import org.rekotlin.Action
import java.util.*
class DetailsReducer {
companion object {
@ -32,6 +32,9 @@ private fun internalReduce(action: Action, state: AppState): DetailsState {
is DetailsAction.ManageSecurity -> {
handleSecurityAction(action, detailsState)
}
is DetailsAction.ManagePrivacy -> {
handlePrivacyAction(action, detailsState)
}
is DetailsAction.ChangeAppCurrency ->
detailsState.copy(appCurrency = action.fiatCurrency)
@ -154,6 +157,20 @@ private fun handleSecurityAction(
}
}
private fun handlePrivacyAction(
action: DetailsAction.ManagePrivacy, state: DetailsState,
): DetailsState {
return when (action) {
is DetailsAction.ManagePrivacy.ConfirmSwitchingSetting -> {
when (action.setting) {
PrivacySetting.SAVE_CARDS -> state.copy(saveCards = action.allow)
PrivacySetting.SAVE_ACCESS_CODE -> state.copy(savePasswords = action.allow)
}
}
is DetailsAction.ManagePrivacy.SwitchPrivacySetting -> state
}
}
private fun prepareAllowedSecurityOptions(
card: Card?, currentSecurityOption: SecurityOption?,
): EnumSet<SecurityOption> {

View file

@ -5,6 +5,7 @@ import com.tangem.blockchain.common.Wallet
import com.tangem.domain.common.ScanResponse
import com.tangem.tap.common.entities.Button
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.common.redux.StateDialog
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState
import com.tangem.tap.store
import org.rekotlin.StateType
@ -20,7 +21,9 @@ data class DetailsState(
val securityScreenState: SecurityScreenState? = null,
val cardTermsOfUseUrl: Uri? = null,
val createBackupAllowed: Boolean = false,
val appCurrency: FiatCurrency = FiatCurrency.Default
val appCurrency: FiatCurrency = FiatCurrency.Default,
val saveCards: Boolean = true,
val savePasswords: Boolean = true
) : StateType {
// if you do not delegate - the application crashes on startup,
@ -48,4 +51,16 @@ data class SecurityScreenState(
val buttonProceed: Button = Button(true),
)
enum class SecurityOption { LongTap, PassCode, AccessCode }
enum class SecurityOption { LongTap, PassCode, AccessCode }
sealed interface DetailsDialog : StateDialog {
data class ConfirmDisablingSaving(val setting: PrivacySetting) : DetailsDialog {
val onOk: () -> Unit =
{ store.dispatch(DetailsAction.ManagePrivacy.ConfirmSwitchingSetting(false, setting)) }
}
}
enum class PrivacySetting {
SAVE_CARDS, SAVE_ACCESS_CODE
}

View file

@ -15,7 +15,6 @@ import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.domain.extensions.isMultiwalletAllowed
import com.tangem.tap.features.details.redux.DetailsAction
import com.tangem.tap.features.details.redux.DetailsState
import com.tangem.tap.features.details.redux.SecurityOption
import com.tangem.tap.features.feedback.FeedbackEmail
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.store
@ -132,17 +131,10 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber<Det
store.dispatch(NavigationAction.NavigateTo(AppScreen.WalletConnectSessions))
}
llManageSecurity.setOnClickListener {
store.dispatch(DetailsAction.ManageSecurity.CheckCurrentSecurityOption(state.scanResponse!!.card))
tvSecurityAndPrivacy.setOnClickListener {
store.dispatch(NavigationAction.NavigateTo(AppScreen.SecurityAndPrivacy))
}
val currentSecurity = when (state.securityScreenState?.currentOption) {
SecurityOption.LongTap -> R.string.details_manage_security_long_tap
SecurityOption.PassCode -> R.string.details_manage_security_passcode
SecurityOption.AccessCode -> R.string.details_manage_security_access_code
null -> null
}
currentSecurity?.let { tvSecurity.text = getString(it) }
}
}

View file

@ -0,0 +1,26 @@
package com.tangem.tap.features.details.ui.securityprivacy
import com.tangem.tap.features.BaseStoreFragment
import com.tangem.tap.features.details.redux.DetailsState
import com.tangem.tap.store
import com.tangem.wallet.R
import org.rekotlin.StoreSubscriber
class ChangeAccessCodeFragment : BaseStoreFragment(R.layout.view_compose_fragment),
StoreSubscriber<DetailsState> {
override fun newState(state: DetailsState) {
}
override fun subscribeToStore() {
store.subscribe(this) { state ->
state.skipRepeats { oldState, newState ->
oldState.detailsState == newState.detailsState
}.select { it.detailsState }
}
storeSubscribersList.add(this)
}
}

View file

@ -0,0 +1,86 @@
package com.tangem.tap.features.details.ui.securityprivacy
import android.os.Bundle
import android.view.View
import by.kirich1409.viewbindingdelegate.viewBinding
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.features.BaseStoreFragment
import com.tangem.tap.features.details.redux.DetailsAction
import com.tangem.tap.features.details.redux.DetailsState
import com.tangem.tap.features.details.redux.PrivacySetting
import com.tangem.tap.features.details.redux.SecurityOption
import com.tangem.tap.store
import com.tangem.wallet.R
import com.tangem.wallet.databinding.FragmentDetailsSecurityPrivacyBinding
import org.rekotlin.StoreSubscriber
class SecurityAndPrivacyFragment : BaseStoreFragment(R.layout.fragment_details_security_privacy),
StoreSubscriber<DetailsState> {
private val binding: FragmentDetailsSecurityPrivacyBinding
by viewBinding(FragmentDetailsSecurityPrivacyBinding::bind)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
with(binding) {
tvAccessCode.setOnClickListener {
store.dispatch(NavigationAction.NavigateTo(AppScreen.ChangeAccessCode))
}
switchSaveCards.setOnCheckedChangeListener { _, isChecked ->
store.dispatch(
DetailsAction.ManagePrivacy.SwitchPrivacySetting(
isChecked,
PrivacySetting.SAVE_CARDS
)
)
}
switchSavePasswords.setOnCheckedChangeListener { _, isChecked ->
store.dispatch(
DetailsAction.ManagePrivacy.SwitchPrivacySetting(
isChecked,
PrivacySetting.SAVE_ACCESS_CODE
)
)
}
}
}
override fun newState(state: DetailsState) {
with(binding) {
llAccessManagement.setOnClickListener {
store.dispatch(
DetailsAction.ManageSecurity.CheckCurrentSecurityOption(
state.scanResponse!!.card
)
)
}
val currentSecurity = when (state.securityScreenState?.currentOption) {
SecurityOption.LongTap -> R.string.details_manage_security_long_tap
SecurityOption.PassCode -> R.string.details_manage_security_passcode
SecurityOption.AccessCode -> R.string.details_manage_security_access_code
null -> null
}
currentSecurity?.let { tvAccessManagement.text = getString(it) }
switchSaveCards.isChecked = state.saveCards
switchSavePasswords.isChecked = state.savePasswords
}
}
override fun subscribeToStore() {
store.subscribe(this) { state ->
state.skipRepeats { oldState, newState ->
oldState.detailsState == newState.detailsState
}.select { it.detailsState }
}
storeSubscribersList.add(this)
}
}

View file

@ -133,39 +133,20 @@
app:layout_constraintTop_toBottomOf="@id/tv_issuer"
tools:text="48 hashes" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/ll_manage_security"
<TextView
android:id="@+id/tv_security_and_privacy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:drawablePadding="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
app:layout_constraintTop_toBottomOf="@+id/tv_signed_hashes_title">
<TextView
android:id="@+id/tv_security_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/details_row_title_manage_security"
android:textColor="@color/darkGray6"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_security"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawablePadding="15dp"
android:gravity="end"
android:maxLines="2"
android:textColor="@color/darkGray1"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:drawableTint="@color/darkGray1"
tools:text="Long Tap" />
</androidx.appcompat.widget.LinearLayoutCompat>
android:text="@string/security_and_privacy_title"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:drawableTint="@color/darkGray1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_signed_hashes_title"/>
<TextView
android:id="@+id/tv_create_backup"
@ -180,7 +161,7 @@
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:drawableTint="@color/darkGray1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/ll_manage_security" />
app:layout_constraintTop_toBottomOf="@id/tv_security_and_privacy" />
<TextView
android:id="@+id/tv_reset_to_factory"

View file

@ -21,7 +21,7 @@
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="@drawable/ic_baseline_arrow_back_24"
app:title="@string/details_manage_security_title" />
app:title="@string/security_and_privacy_access_method_title" />
</com.google.android.material.appbar.AppBarLayout>

View file

@ -0,0 +1,164 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/coordinator_wallet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/backgroundLightGray"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar"
style="@style/Widget.MaterialComponents.Toolbar.Surface"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/backgroundLightGray"
android:fitsSystemWindows="true"
app:liftOnScroll="true">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="@drawable/ic_baseline_arrow_back_24"
app:title="@string/security_and_privacy_title" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/sv_wallet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="35dp"
android:fillViewport="true"
android:overScrollMode="never"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_wallet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="33dp">
<TextView
android:id="@+id/tv_security_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="4dp"
android:text="@string/security_and_privacy_security"
android:textAllCaps="true"
android:textColor="@color/colorSecondary"
android:textSize="13sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/separatorGrey2"
app:layout_constraintTop_toBottomOf="@id/tv_security_title" />
<TextView
android:id="@+id/tv_access_code"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/security_and_privacy_change_password"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:drawableTint="@color/darkGray1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_security_title" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/ll_access_management"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingTop="7dp"
android:paddingBottom="7dp"
app:layout_constraintTop_toBottomOf="@+id/tv_access_code">
<TextView
android:id="@+id/tv_access_management_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/security_and_privacy_access_method"
android:textColor="@color/darkGray6"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_access_management"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawablePadding="15dp"
android:gravity="end"
android:maxLines="2"
android:textColor="@color/darkGray1"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:drawableTint="@color/darkGray1"
tools:text="Long Tap" />
</androidx.appcompat.widget.LinearLayoutCompat>
<TextView
android:id="@+id/tv_privacy_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="22dp"
android:paddingBottom="4dp"
android:text="@string/security_and_privacy_privacy"
android:textAllCaps="true"
android:textColor="@color/colorSecondary"
android:textSize="13sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/ll_access_management" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/separatorGrey2"
app:layout_constraintTop_toBottomOf="@id/tv_privacy_title" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/switch_save_cards"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/security_and_privacy_save_card_switch"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_privacy_title" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/switch_save_passwords"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/security_and_privacy_save_password_switch"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/switch_save_cards" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -60,4 +60,13 @@
<string name="wallet_connect_network_not_found_format">%s network not found. Please, add it first and try again.</string>
<string name="wallet_currency_subtitle">%s network</string>
<string name="security_and_privacy_title">Security &amp; Privacy</string>
<string name="security_and_privacy_security">Security</string>
<string name="security_and_privacy_privacy">Privacy</string>
<string name="security_and_privacy_change_password">Change access code</string>
<string name="security_and_privacy_access_method">Change access method</string>
<string name="security_and_privacy_access_method_title">Change Access Method</string>
<string name="security_and_privacy_save_card_switch">Save cards</string>
<string name="security_and_privacy_save_password_switch">Save passwords</string>
</resources>

View file

@ -60,4 +60,13 @@
<string name="wallet_connect_network_not_found_format">%s network not found. Please, add it first and try again.</string>
<string name="wallet_currency_subtitle">%s network</string>
<string name="security_and_privacy_title">Security &amp; Privacy</string>
<string name="security_and_privacy_security">Security</string>
<string name="security_and_privacy_privacy">Privacy</string>
<string name="security_and_privacy_change_password">Change access code</string>
<string name="security_and_privacy_access_method">Change access method</string>
<string name="security_and_privacy_access_method_title">Change Access Method</string>
<string name="security_and_privacy_save_card_switch">Save cards</string>
<string name="security_and_privacy_save_password_switch">Save passwords</string>
</resources>

View file

@ -60,4 +60,13 @@
<string name="wallet_connect_network_not_found_format">%s network not found. Please, add it first and try again.</string>
<string name="wallet_currency_subtitle">%s network</string>
<string name="security_and_privacy_title">Security &amp; Privacy</string>
<string name="security_and_privacy_security">Security</string>
<string name="security_and_privacy_privacy">Privacy</string>
<string name="security_and_privacy_change_password">Change access code</string>
<string name="security_and_privacy_access_method">Change access method</string>
<string name="security_and_privacy_access_method_title">Change Access Method</string>
<string name="security_and_privacy_save_card_switch">Save cards</string>
<string name="security_and_privacy_save_password_switch">Save passwords</string>
</resources>

View file

@ -68,4 +68,13 @@
<string name="main_no_backup_warning_title">Бэкап кошелька не был произведен</string>
<string name="main_no_backup_warning_subtitle">Чтобы защитить свои активы, мы советуем вам выполнить эту процедуру</string>
<string name="security_and_privacy_title">Безопасность и приватность</string>
<string name="security_and_privacy_security">Безопасность</string>
<string name="security_and_privacy_privacy">Приватность</string>
<string name="security_and_privacy_change_password">Изменить код доступа</string>
<string name="security_and_privacy_access_method">Изменить защиту доступа</string>
<string name="security_and_privacy_access_method_title">Изменить защиту доступа</string>
<string name="security_and_privacy_save_card_switch">Сохранять карты</string>
<string name="security_and_privacy_save_password_switch">Сохранять пароли</string>
</resources>

View file

@ -70,4 +70,14 @@
<string name="main_no_backup_warning_subtitle">To protect your assets, we advise you to carry out this procedure</string>
<string name="wallet_hide_token" translatable="false">Remove token</string>
<string name="security_and_privacy_title">Security &amp; Privacy</string>
<string name="security_and_privacy_security">Security</string>
<string name="security_and_privacy_privacy">Privacy</string>
<string name="security_and_privacy_change_password">Change access code</string>
<string name="security_and_privacy_access_method">Change access method</string>
<string name="security_and_privacy_access_method_title">Change Access Method</string>
<string name="security_and_privacy_save_card_switch">Save cards</string>
<string name="security_and_privacy_save_password_switch">Save passwords</string>
<string name="security_and_privacy_save_card_disable_warning">При отключении данной опции все сохраненные карты и пароли будут сброшены, все данные удалены. Для входа в приложение понадобится прикладывать карту.</string>
<string name="security_and_privacy_save_password_disable_warning">Все сохраненные пароли от карт будут удалены. Для проведения операций с картой вам необходимо будет вводить пароль.</string>
</resources>