Updated on 2026-08-14

This commit is contained in:
Tangem 2022-08-04 13:57:19 +03:00
commit 43387c838d
83 changed files with 2213 additions and 1178 deletions

@ -1 +1 @@
Subproject commit bf673f7f88ed561cd8827447c4886f80f30b7e23
Subproject commit f33f020823031f1c532cf5a9d5cf3fbecadcf050

View file

@ -6,8 +6,14 @@ 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.details.ui.walletconnect.dialogs.ApproveWcSessionDialog
import com.tangem.tap.features.details.ui.walletconnect.dialogs.BnbTransactionDialog
import com.tangem.tap.features.details.ui.walletconnect.dialogs.ClipboardOrScanQrDialog
import com.tangem.tap.features.details.ui.walletconnect.dialogs.PersonalSignDialog
import com.tangem.tap.features.details.ui.walletconnect.dialogs.TransactionDialog
import com.tangem.tap.features.onboarding.AddressInfoBottomSheetDialog
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
import com.tangem.tap.features.onboarding.products.twins.ui.dialog.CreateWalletInterruptDialog
@ -17,7 +23,12 @@ import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.BackupInPro
import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.ConfirmDiscardingBackupDialog
import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.UnfinishedBackupFoundDialog
import com.tangem.tap.features.wallet.redux.models.WalletDialog
import com.tangem.tap.features.wallet.ui.dialogs.*
import com.tangem.tap.features.wallet.ui.dialogs.AmountToSendBottomSheetDialog
import com.tangem.tap.features.wallet.ui.dialogs.ChooseTradeActionBottomSheetDialog
import com.tangem.tap.features.wallet.ui.dialogs.RussianCardholdersWarningBottomSheetDialog
import com.tangem.tap.features.wallet.ui.dialogs.ScanFailsDialog
import com.tangem.tap.features.wallet.ui.dialogs.SignedHashesWarningDialog
import com.tangem.tap.features.wallet.ui.dialogs.SimpleOkDialog
import com.tangem.tap.features.wallet.ui.wallet.CurrencySelectionDialog
import com.tangem.tap.store
import com.tangem.wallet.R
@ -139,6 +150,18 @@ class DialogManager : StoreSubscriber<GlobalState> {
)
is WalletDialog.RussianCardholdersWarningDialog ->
RussianCardholdersWarningBottomSheetDialog(context)
is DetailsDialog.ConfirmDisablingSaving -> {
val messageRes = when (state.dialog.setting) {
PrivacySetting.SAVE_CARDS -> R.string.app_settings_off_saved_wallet_alert_message
PrivacySetting.SAVE_ACCESS_CODE -> R.string.app_settings_off_saved_access_code_alert_message
}
SimpleCancelableAlertDialog.create(
titleRes = R.string.common_warning,
messageRes = messageRes,
context = context,
primaryButtonAction = state.dialog.onOk
)
}
else -> null
}
dialog?.show()

View file

@ -0,0 +1,71 @@
package com.tangem.tap.common.compose
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.sp
import com.tangem.wallet.R
object TangemTypography {
val body1 = TextStyle(
fontFamily = FontFamily(Font(R.font.roboto)),
fontSize = 16.0.sp,
letterSpacing = 0.5.sp,
lineHeight = 24.0.sp,
)
val body2 = TextStyle(
fontFamily = FontFamily(Font(R.font.roboto)),
fontSize = 14.0.sp,
letterSpacing = 0.25.sp,
lineHeight = 20.0.sp,
)
val button = TextStyle(
fontFamily = FontFamily(Font(R.font.roboto_medium)),
fontSize = 14.0.sp,
letterSpacing = 0.10000000149011612.sp,
lineHeight = 20.0.sp,
)
val caption = TextStyle(
fontFamily = FontFamily(Font(R.font.roboto)),
fontSize = 12.0.sp,
letterSpacing = 0.4000000059604645.sp,
lineHeight = 16.0.sp,
)
val headline1 = TextStyle(
fontFamily = FontFamily(Font(R.font.roboto)),
fontSize = 34.0.sp,
letterSpacing = 0.0.sp,
lineHeight = 44.0.sp,
)
val headline2 = TextStyle(
fontFamily = FontFamily(Font(R.font.roboto_medium)),
fontSize = 24.0.sp,
letterSpacing = 0.18000000715255737.sp,
lineHeight = 32.0.sp,
)
val headline3 = TextStyle(
fontFamily = FontFamily(Font(R.font.roboto_medium)),
fontSize = 20.0.sp,
letterSpacing = 0.15000000596046448.sp,
lineHeight = 24.0.sp,
)
val overline = TextStyle(
fontFamily = FontFamily(Font(R.font.roboto_medium)),
fontSize = 10.0.sp,
letterSpacing = 1.5.sp,
lineHeight = 16.0.sp,
)
val subtitle1 = TextStyle(
fontFamily = FontFamily(Font(R.font.roboto_medium)),
fontSize = 16.0.sp,
letterSpacing = 0.15000000596046448.sp,
lineHeight = 24.0.sp,
)
val subtitle2 = TextStyle(
fontFamily = FontFamily(Font(R.font.roboto_medium)),
fontSize = 14.0.sp,
letterSpacing = 0.10000000149011612.sp,
lineHeight = 24.0.sp,
)
}

View file

@ -7,9 +7,10 @@ import androidx.fragment.app.FragmentManager
import com.tangem.common.extensions.VoidCallback
import com.tangem.tap.common.redux.navigation.AppScreen
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.cardsettings.CardSettingsFragment
import com.tangem.tap.features.details.ui.details.DetailsFragment
import com.tangem.tap.features.details.ui.resetcard.ResetCardFragment
import com.tangem.tap.features.details.ui.securitymode.SecurityModeFragment
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
@ -92,8 +93,10 @@ private fun fragmentFactory(screen: AppScreen): Fragment {
AppScreen.Wallet -> WalletFragment()
AppScreen.Send -> SendFragment()
AppScreen.Details -> DetailsFragment()
AppScreen.DetailsConfirm -> DetailsConfirmFragment()
AppScreen.DetailsSecurity -> DetailsSecurityFragment()
AppScreen.DetailsSecurity -> SecurityModeFragment()
AppScreen.CardSettings -> CardSettingsFragment()
AppScreen.AppSettings -> CardSettingsFragment()
AppScreen.ResetToFactory -> ResetCardFragment()
AppScreen.Disclaimer -> DisclaimerFragment()
AppScreen.AddTokens -> AddTokensFragment()
AppScreen.AddCustomToken -> AddCustomTokenFragment()

View file

@ -1,5 +1,6 @@
package com.tangem.tap.common.redux.navigation
import android.net.Uri
import androidx.fragment.app.FragmentActivity
import org.rekotlin.Action
import java.lang.ref.WeakReference
@ -15,6 +16,8 @@ sealed class NavigationAction : Action {
data class OpenUrl(val url: String) : NavigationAction()
data class OpenDocument(val url: Uri) : NavigationAction()
data class Share(val data: String) : NavigationAction()
data class ActivityCreated(val activity: WeakReference<FragmentActivity>) : NavigationAction()

View file

@ -1,5 +1,6 @@
package com.tangem.tap.common.redux.navigation
import android.content.Intent
import com.tangem.tap.common.CustomTabsManager
import com.tangem.tap.common.extensions.openFragment
import com.tangem.tap.common.extensions.popBackTo
@ -32,6 +33,11 @@ val navigationMiddleware: Middleware<AppState> = { dispatch, state ->
CustomTabsManager().openUrl(action.url, it)
}
}
is NavigationAction.OpenDocument -> {
val intent = Intent(Intent.ACTION_VIEW)
intent.data = action.url
navState?.activity?.get()?.startActivity(intent)
}
is NavigationAction.Share -> {
navState?.activity?.get()?.let {
it.shareText(action.data)

View file

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

View file

@ -19,6 +19,7 @@ import com.tangem.common.extensions.ByteArrayKey
import com.tangem.common.hdWallet.DerivationPath
import com.tangem.domain.common.ScanResponse
import com.tangem.operations.CommandResponse
import com.tangem.operations.ScanTask
import com.tangem.operations.derivation.DerivationTaskResponse
import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask
import com.tangem.operations.pins.CheckUserCodesCommand
@ -144,6 +145,12 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
initialMessage = Message(context.getString(R.string.initial_message_tap_header)))
}
suspend fun scanCard(): CompletionResult<Card> {
return runTaskAsyncReturnOnMain(
ScanTask(),
initialMessage = Message(context.getString(R.string.initial_message_tap_header)))
}
suspend fun <T : CommandResponse> runTaskAsync(
runnable: CardSessionRunnable<T>, cardId: String? = null, initialMessage: Message? = null,
): CompletionResult<T> =

View file

@ -6,8 +6,8 @@ import com.tangem.common.card.EllipticCurve
import com.tangem.common.card.FirmwareVersion
import com.tangem.common.extensions.toHexString
import com.tangem.common.services.Result
import com.tangem.domain.common.TapWorkarounds
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
import com.tangem.domain.common.TapWorkarounds.isTangemNote
import com.tangem.domain.common.TwinCardNumber
import com.tangem.domain.common.getTwinCardNumber
import com.tangem.domain.common.isTangemTwin
@ -15,7 +15,6 @@ import com.tangem.operations.attestation.CardVerifyAndGetInfo
import com.tangem.operations.attestation.OnlineCardVerifier
import com.tangem.tap.features.wallet.redux.Artwork
val Card.remainingSignatures: Int?
get() = this.getSingleWallet()?.remainingSignatures
@ -24,7 +23,7 @@ val Card.isWalletDataSupported: Boolean
val Card.isMultiwalletAllowed: Boolean
get() {
return !isTangemTwin() && !isStart2Coin && !TapWorkarounds.isTangemNote(this)
return !isTangemTwin() && !isStart2Coin && !isTangemNote()
&& (firmwareVersion >= FirmwareVersion.MultiWalletAvailable ||
getSingleWallet()?.curve == EllipticCurve.Secp256k1)
}

View file

@ -14,10 +14,14 @@ import com.tangem.common.extensions.guard
import com.tangem.common.extensions.toHexString
import com.tangem.common.extensions.toMapKey
import com.tangem.common.hdWallet.DerivationPath
import com.tangem.domain.common.*
import com.tangem.domain.common.ProductType
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.TapWorkarounds.isExcluded
import com.tangem.domain.common.TapWorkarounds.isNotSupportedInThatRelease
import com.tangem.domain.common.TapWorkarounds.isTangemNote
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
import com.tangem.domain.common.TwinsHelper
import com.tangem.domain.common.isTangemTwins
import com.tangem.operations.PreflightReadMode
import com.tangem.operations.PreflightReadTask
import com.tangem.operations.ScanTask
@ -56,7 +60,7 @@ class ScanProductTask(
}
val commandProcessor = when {
TapWorkarounds.isTangemNote(card) -> ScanNoteProcessor()
card.isTangemNote() -> ScanNoteProcessor()
card.isTangemTwins() -> ScanTwinProcessor()
else -> ScanWalletProcessor(currenciesRepository, additionalBlockchainsToDerive)
}

View file

@ -3,12 +3,8 @@ package com.tangem.tap.features.details.redux
import com.tangem.blockchain.common.Wallet
import com.tangem.common.card.Card
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.TwinCardNumber
import com.tangem.operations.pins.CheckUserCodesResponse
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.common.redux.NotificationAction
import com.tangem.tap.domain.termsOfUse.CardTou
import com.tangem.wallet.R
import org.rekotlin.Action
sealed class DetailsAction : Action {
@ -20,31 +16,23 @@ sealed class DetailsAction : Action {
) : DetailsAction()
object ShowDisclaimer : DetailsAction()
data class ReCreateTwinsWallet(val number: TwinCardNumber) : DetailsAction()
object ReCreateTwinsWallet : DetailsAction()
sealed class ResetToFactory : DetailsAction() {
object Check : ResetToFactory()
object Proceed : ResetToFactory() {
object NotAllowedByCard : ResetToFactory(), NotificationAction {
override val messageResource = R.string.error_purge_prohibited
}
object NotEmpty : ResetToFactory(), NotificationAction {
override val messageResource = R.string.details_notification_erase_wallet_not_possible
}
}
object Confirm : ResetToFactory()
object Cancel : ResetToFactory()
object Proceed : ResetToFactory()
data class Confirm(val confirmed: Boolean) : ResetToFactory()
object Failure : ResetToFactory()
object Success : ResetToFactory()
}
object CreateBackup : DetailsAction()
object ScanCard : DetailsAction()
data class PrepareCardSettingsData(val card: Card) : DetailsAction()
object ResetCardSettingsData : DetailsAction()
sealed class ManageSecurity : DetailsAction() {
data class CheckCurrentSecurityOption(val card: Card) : ManageSecurity()
data class SetCurrentOption(val userCodes: CheckUserCodesResponse) : ManageSecurity()
object OpenSecurity : ManageSecurity()
data class SelectOption(val option: SecurityOption) : ManageSecurity()
object SaveChanges : ManageSecurity() {
@ -52,11 +40,15 @@ sealed class DetailsAction : Action {
object Failure : ManageSecurity()
}
data class ConfirmSelection(val option: SecurityOption) : ManageSecurity() {
object AlreadySet : ManageSecurity(), NotificationAction {
override val messageResource = R.string.details_notification_security_option_already_active
}
}
object ChangeAccessCode : ManageSecurity()
}
sealed class AppSettings : DetailsAction() {
data class SwitchPrivacySetting(val allow: Boolean, val setting: PrivacySetting) :
AppSettings()
data class ConfirmSwitchingSetting(val allow: Boolean, val setting: PrivacySetting) :
AppSettings()
}
data class ChangeAppCurrency(val fiatCurrency: FiatCurrency) : DetailsAction()

View file

@ -1,11 +1,11 @@
package com.tangem.tap.features.details.redux
import com.tangem.common.CompletionResult
import com.tangem.common.card.FirmwareVersion
import com.tangem.common.core.TangemSdkError
import com.tangem.operations.pins.CheckUserCodesResponse
import com.tangem.domain.common.isTangemTwins
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 +28,33 @@ 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.AppSettings -> managePrivacyMiddleware.handle(action)
is DetailsAction.ShowDisclaimer -> {
store.dispatch(DisclaimerAction.ShowAcceptedDisclaimer)
store.dispatch(NavigationAction.NavigateTo(AppScreen.Disclaimer))
val uri = store.state.detailsState.cardTermsOfUseUrl
if (uri != null) {
store.dispatch(NavigationAction.OpenDocument(uri))
} else {
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 +65,24 @@ 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,
),
)
}
}
DetailsAction.ScanCard -> {
scope.launch {
when (val result = tangemSdkManager.scanCard()) {
is CompletionResult.Success -> {
val card = result.data
store.dispatchOnMain(DetailsAction.PrepareCardSettingsData(card))
}
is CompletionResult.Failure -> {
}
}
}
}
}
@ -69,22 +95,11 @@ class DetailsMiddleware {
fun handle(action: DetailsAction.ResetToFactory) {
when (action) {
is DetailsAction.ResetToFactory.Proceed -> {
when (store.state.detailsState.eraseWalletState) {
EraseWalletState.Allowed ->
store.dispatch(NavigationAction.NavigateTo(AppScreen.DetailsConfirm))
EraseWalletState.NotAllowedByCard ->
store.dispatch(DetailsAction.ResetToFactory.Proceed.NotAllowedByCard)
EraseWalletState.NotEmpty ->
store.dispatch(DetailsAction.ResetToFactory.Proceed.NotEmpty)
else -> { /* no-op */
}
val card = store.state.detailsState.cardSettingsState?.card ?: return
if (card.isTangemTwins()) {
store.dispatch(DetailsAction.ReCreateTwinsWallet)
return
}
}
is DetailsAction.ResetToFactory.Cancel -> {
store.dispatch(NavigationAction.PopBackTo())
}
is DetailsAction.ResetToFactory.Confirm -> {
val card = store.state.detailsState.scanResponse?.card ?: return
scope.launch {
val result = tangemSdkManager.resetToFactorySettings(card)
withContext(Dispatchers.Main) {
@ -98,7 +113,7 @@ class DetailsMiddleware {
store.state.globalState.analyticsHandlers?.logCardSdkError(
error,
Analytics.ActionToLog.PurgeWallet,
card = store.state.detailsState.scanResponse?.card
card = store.state.detailsState.scanResponse?.card,
)
}
}
@ -115,44 +130,13 @@ class DetailsMiddleware {
class ManageSecurityMiddleware {
fun handle(action: DetailsAction.ManageSecurity) {
when (action) {
is DetailsAction.ManageSecurity.CheckCurrentSecurityOption -> {
if (action.card.firmwareVersion >= FirmwareVersion.IsAccessCodeStatusAvailable) {
// for a card that meets this condition, we can get these statuses from it
val simulatedResponse = CheckUserCodesResponse(
action.card.isAccessCodeSet, action.card.isPasscodeSet ?: false
)
store.dispatch(DetailsAction.ManageSecurity.SetCurrentOption(simulatedResponse))
store.dispatch(DetailsAction.ManageSecurity.OpenSecurity)
} else {
scope.launch {
when (val response = tangemSdkManager.checkUserCodes(action.card.cardId)) {
is CompletionResult.Success -> {
store.dispatchOnMain(DetailsAction.ManageSecurity.SetCurrentOption(response.data))
store.dispatchOnMain(DetailsAction.ManageSecurity.OpenSecurity)
}
is CompletionResult.Failure -> {
}
}
}
}
}
is DetailsAction.ManageSecurity.OpenSecurity -> {
store.dispatch(NavigationAction.NavigateTo(AppScreen.DetailsSecurity))
}
is DetailsAction.ManageSecurity.ConfirmSelection -> {
if (action.option != store.state.detailsState.securityScreenState?.currentOption) {
if (action.option == SecurityOption.LongTap) {
store.dispatch(DetailsAction.ManageSecurity.SaveChanges)
} else {
store.dispatch(NavigationAction.NavigateTo(AppScreen.DetailsConfirm))
}
} else {
store.dispatch(DetailsAction.ManageSecurity.ConfirmSelection.AlreadySet)
}
}
is DetailsAction.ManageSecurity.SaveChanges -> {
val cardId = store.state.detailsState.scanResponse?.card?.cardId
val selectedOption = store.state.detailsState.securityScreenState?.selectedOption
val selectedOption =
store.state.detailsState.cardSettingsState?.manageSecurityState?.selectedOption
scope.launch {
val result = when (selectedOption) {
SecurityOption.LongTap -> tangemSdkManager.setLongTap(cardId)
@ -166,9 +150,7 @@ class DetailsMiddleware {
selectedOption?.let {
store.dispatch(GlobalAction.UpdateSecurityOptions(it))
}
if (selectedOption != SecurityOption.LongTap) {
store.dispatch(NavigationAction.PopBackTo())
}
store.dispatch(NavigationAction.PopBackTo())
store.dispatch(DetailsAction.ManageSecurity.SaveChanges.Success)
}
is CompletionResult.Failure -> {
@ -178,9 +160,9 @@ class DetailsMiddleware {
actionToLog = Analytics.ActionToLog.ChangeSecOptions,
parameters = mapOf(
AnalyticsParam.NEW_SECURITY_OPTION to
(selectedOption?.name ?: "")
(selectedOption?.name ?: ""),
),
card = store.state.detailsState.scanResponse?.card
card = store.state.detailsState.scanResponse?.card,
)
}
store.dispatch(DetailsAction.ManageSecurity.SaveChanges.Failure)
@ -191,9 +173,37 @@ class DetailsMiddleware {
}
}
}
is DetailsAction.ManageSecurity.ChangeAccessCode -> {
val card = store.state.detailsState.cardSettingsState?.card ?: return
scope.launch {
tangemSdkManager.setAccessCode(card.cardId)
}
}
else -> { /* no-op */
}
}
}
}
}
class ManagePrivacyMiddleware {
fun handle(action: DetailsAction.AppSettings) {
when (action) {
is DetailsAction.AppSettings.ConfirmSwitchingSetting -> {
// TODO()
}
is DetailsAction.AppSettings.SwitchPrivacySetting -> {
if (action.allow) {
store.dispatch(
DetailsAction.AppSettings.ConfirmSwitchingSetting(
action.allow,
action.setting,
),
)
} else {
store.dispatchDialogShow(DetailsDialog.ConfirmDisablingSaving(action.setting))
}
}
}
}
}
}

View file

@ -1,16 +1,15 @@
package com.tangem.tap.features.details.redux
import com.tangem.common.card.Card
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
import com.tangem.domain.common.TapWorkarounds.isTangemNote
import com.tangem.domain.common.isTangemTwin
import com.tangem.tap.common.redux.AppState
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 {
@ -24,14 +23,21 @@ private fun internalReduce(action: Action, state: AppState): DetailsState {
val detailsState = state.detailsState
return when (action) {
is DetailsAction.PrepareScreen -> {
handlePrepareScreen(action, detailsState)
handlePrepareScreen(action)
}
is DetailsAction.PrepareCardSettingsData -> {
handlePrepareCardSettingsScreen(action.card, detailsState)
}
is DetailsAction.ResetCardSettingsData -> detailsState.copy(cardSettingsState = null)
is DetailsAction.ResetToFactory -> {
handleEraseWallet(action, detailsState)
}
is DetailsAction.ManageSecurity -> {
handleSecurityAction(action, detailsState)
}
is DetailsAction.AppSettings -> {
handlePrivacyAction(action, detailsState)
}
is DetailsAction.ChangeAppCurrency ->
detailsState.copy(appCurrency = action.fiatCurrency)
@ -41,49 +47,69 @@ private fun internalReduce(action: Action, state: AppState): DetailsState {
private fun handlePrepareScreen(
action: DetailsAction.PrepareScreen,
state: DetailsState,
): DetailsState {
return DetailsState(
scanResponse = action.scanResponse,
wallets = action.wallets,
cardInfo = action.scanResponse.card.toCardInfo(),
cardTermsOfUseUrl = action.cardTou.getUrl(action.scanResponse.card),
createBackupAllowed = action.scanResponse.card.backupStatus == Card.BackupStatus.NoBackup,
appCurrency = store.state.globalState.appCurrency
appCurrency = store.state.globalState.appCurrency,
)
}
private fun handlePrepareCardSettingsScreen(card: Card, state: DetailsState): DetailsState {
val cardSettingsState = CardSettingsState(
cardInfo = card.toCardInfo(),
manageSecurityState = prepareSecurityOptions(card),
card = card,
resetCardAllowed = isResetToFactoryAllowedByCard(card),
)
return state.copy(cardSettingsState = cardSettingsState)
}
private fun prepareSecurityOptions(card: Card): ManageSecurityState {
val securityOption = when {
card.isAccessCodeSet -> {
SecurityOption.AccessCode
}
card.isPasscodeSet == true -> {
SecurityOption.PassCode
}
else -> {
SecurityOption.LongTap
}
}
val allowedSecurityOptions = when {
card.isStart2Coin || card.isTangemNote() -> {
EnumSet.of(SecurityOption.LongTap)
}
card.settings.isBackupAllowed -> {
EnumSet.of(securityOption)
}
else -> prepareAllowedSecurityOptions(card, securityOption)
}
return ManageSecurityState(
currentOption = securityOption,
allowedOptions = allowedSecurityOptions,
selectedOption = securityOption,
)
}
private fun isResetToFactoryAllowedByCard(card: Card): Boolean {
val notAllowedByAnyWallet = card.wallets.any { it.settings.isPermanent }
val notAllowedByCard = notAllowedByAnyWallet ||
(card.isWalletDataSupported && (!card.isTangemNote() && !card.settings.isBackupAllowed))
return !notAllowedByCard
}
private fun handleEraseWallet(
action: DetailsAction.ResetToFactory,
state: DetailsState,
): DetailsState {
return when (action) {
DetailsAction.ResetToFactory.Check -> {
val card = state.scanResponse?.card
val notAllowedByAnyWallet = card?.wallets?.any { it.settings.isPermanent } ?: false
val notAllowedByCard = notAllowedByAnyWallet ||
(card?.isWalletDataSupported == true &&
(!state.scanResponse.isTangemNote() && !state.scanResponse.supportsBackup()))
val notEmpty = state.wallets.any { it.hasSendableAmountsOrPendingTransactions() }
val eraseWalletState = when {
notAllowedByCard -> EraseWalletState.NotAllowedByCard
notEmpty -> EraseWalletState.NotEmpty
else -> EraseWalletState.Allowed
}
state.copy(eraseWalletState = eraseWalletState)
}
DetailsAction.ResetToFactory.Proceed -> {
if (state.eraseWalletState == EraseWalletState.Allowed) {
state.copy(confirmScreenState = ConfirmScreenState.EraseWallet)
} else {
state
}
}
DetailsAction.ResetToFactory.Cancel -> state.copy(eraseWalletState = null)
DetailsAction.ResetToFactory.Failure -> state.copy(eraseWalletState = null)
DetailsAction.ResetToFactory.Success -> state.copy(eraseWalletState = null)
is DetailsAction.ResetToFactory.Confirm ->
state.copy(cardSettingsState = state.cardSettingsState?.copy(resetConfirmed = action.confirmed))
else -> state
}
}
@ -92,68 +118,47 @@ private fun handleSecurityAction(
action: DetailsAction.ManageSecurity, state: DetailsState,
): DetailsState {
return when (action) {
is DetailsAction.ManageSecurity.SetCurrentOption -> {
val securityOption = when {
action.userCodes.isAccessCodeSet -> {
SecurityOption.AccessCode
}
action.userCodes.isPasscodeSet -> {
SecurityOption.PassCode
}
else -> {
SecurityOption.LongTap
}
}
state.copy(securityScreenState = SecurityScreenState(currentOption = securityOption))
}
is DetailsAction.ManageSecurity.OpenSecurity -> {
val allowedSecurityOptions = when {
state.scanResponse?.card?.isStart2Coin == true ||
state.scanResponse?.isTangemNote() == true -> {
EnumSet.of(SecurityOption.LongTap)
}
state.scanResponse?.supportsBackup() == true -> {
EnumSet.of(state.securityScreenState?.currentOption)
}
else -> prepareAllowedSecurityOptions(
state.scanResponse?.card, state.securityScreenState?.currentOption
)
}
state.copy(securityScreenState = state.securityScreenState?.copy(
allowedOptions = allowedSecurityOptions,
selectedOption = state.securityScreenState.currentOption
))
}
is DetailsAction.ManageSecurity.SelectOption -> {
state.copy(securityScreenState = state.securityScreenState?.copy(
selectedOption = action.option
))
}
is DetailsAction.ManageSecurity.ConfirmSelection -> {
val confirmScreenState = when (action.option) {
SecurityOption.LongTap -> ConfirmScreenState.LongTap
SecurityOption.PassCode -> ConfirmScreenState.PassCode
SecurityOption.AccessCode -> ConfirmScreenState.AccessCode
}
state.copy(confirmScreenState = confirmScreenState)
val manageSecurityState = state.cardSettingsState?.manageSecurityState?.copy(
selectedOption = action.option,
)
state.copy(cardSettingsState = state.cardSettingsState?.copy(manageSecurityState = manageSecurityState))
}
is DetailsAction.ManageSecurity.SaveChanges.Success -> {
// Setting options to show only LongTap from now on for non-twins
val manageSecurityState = state.cardSettingsState?.manageSecurityState?.copy(
currentOption = state.cardSettingsState.manageSecurityState.selectedOption,
allowedOptions = state.scanResponse?.card?.let {
prepareAllowedSecurityOptions(
it, state.cardSettingsState.manageSecurityState.selectedOption,
)
} ?: EnumSet.of(SecurityOption.LongTap),
)
state.copy(
securityScreenState = state.securityScreenState?.copy(
currentOption = state.securityScreenState.selectedOption,
allowedOptions = state.scanResponse?.card?.let {
prepareAllowedSecurityOptions(
it, state.securityScreenState.selectedOption
)
} ?: EnumSet.of(SecurityOption.LongTap)
))
cardSettingsState = state.cardSettingsState?.copy(
manageSecurityState = manageSecurityState,
),
)
}
else -> state
}
}
private fun handlePrivacyAction(
action: DetailsAction.AppSettings, state: DetailsState,
): DetailsState {
return when (action) {
is DetailsAction.AppSettings.ConfirmSwitchingSetting -> {
when (action.setting) {
PrivacySetting.SAVE_CARDS -> state.copy(saveCards = action.allow)
PrivacySetting.SAVE_ACCESS_CODE -> state.copy(savePasswords = action.allow)
}
}
is DetailsAction.AppSettings.SwitchPrivacySetting -> state
}
}
private fun prepareAllowedSecurityOptions(
card: Card?, currentSecurityOption: SecurityOption?,
): EnumSet<SecurityOption> {
@ -171,7 +176,6 @@ private fun prepareAllowedSecurityOptions(
return allowedSecurityOptions
}
private fun Card.toCardInfo(): CardInfo {
val cardId = this.cardId.chunked(4).joinToString(separator = " ")
val issuer = this.issuer.name

View file

@ -2,9 +2,11 @@ package com.tangem.tap.features.details.redux
import android.net.Uri
import com.tangem.blockchain.common.Wallet
import com.tangem.common.card.Card
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
@ -14,13 +16,13 @@ import kotlin.properties.ReadOnlyProperty
data class DetailsState(
val scanResponse: ScanResponse? = null,
val wallets: List<Wallet> = emptyList(),
val cardInfo: CardInfo? = null,
val eraseWalletState: EraseWalletState? = null,
val confirmScreenState: ConfirmScreenState? = null,
val securityScreenState: SecurityScreenState? = null,
val cardSettingsState: CardSettingsState? = null,
val cardTermsOfUseUrl: Uri? = null,
val privacyPolicyUrl: String? = 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,
@ -39,13 +41,31 @@ data class CardInfo(
val signedHashes: Int,
)
enum class EraseWalletState { Allowed, NotAllowedByCard, NotEmpty }
enum class ConfirmScreenState { EraseWallet, LongTap, AccessCode, PassCode }
data class SecurityScreenState(
data class CardSettingsState(
val cardInfo: CardInfo,
val card: Card,
val manageSecurityState: ManageSecurityState?,
val resetCardAllowed: Boolean,
val resetConfirmed: Boolean = false,
)
data class ManageSecurityState(
val currentOption: SecurityOption = SecurityOption.LongTap,
val selectedOption: SecurityOption = currentOption,
val allowedOptions: EnumSet<SecurityOption> = EnumSet.allOf(SecurityOption::class.java),
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.AppSettings.ConfirmSwitchingSetting(false, setting)) }
}
}
enum class PrivacySetting {
SAVE_CARDS, SAVE_ACCESS_CODE
}

View file

@ -1,88 +0,0 @@
package com.tangem.tap.features.details.ui
import android.os.Bundle
import android.view.View
import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.Fragment
import androidx.transition.TransitionInflater
import by.kirich1409.viewbindingdelegate.viewBinding
import com.tangem.tap.common.extensions.getDrawable
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.features.details.redux.ConfirmScreenState
import com.tangem.tap.features.details.redux.DetailsAction
import com.tangem.tap.features.details.redux.DetailsState
import com.tangem.tap.store
import com.tangem.wallet.R
import com.tangem.wallet.databinding.FragmentDetailsConfirmBinding
import org.rekotlin.StoreSubscriber
class DetailsConfirmFragment : Fragment(R.layout.fragment_details_confirm),
StoreSubscriber<DetailsState> {
private val binding: FragmentDetailsConfirmBinding by viewBinding(FragmentDetailsConfirmBinding::bind)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
store.dispatch(NavigationAction.PopBackTo())
}
})
val inflater = TransitionInflater.from(requireContext())
enterTransition = inflater.inflateTransition(R.transition.slide_right)
exitTransition = inflater.inflateTransition(R.transition.fade)
}
override fun onStart() {
super.onStart()
store.subscribe(this) { state ->
state.skipRepeats { oldState, newState ->
oldState.detailsState == newState.detailsState
}.select { it.detailsState }
}
}
override fun onStop() {
super.onStop()
store.unsubscribe(this)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.toolbar.setNavigationOnClickListener {
store.dispatch(NavigationAction.PopBackTo())
}
}
override fun newState(state: DetailsState) {
if (activity == null || view == null) return
setState(state)
}
private fun setState(state: DetailsState) = with(binding) {
when (state.confirmScreenState) {
ConfirmScreenState.EraseWallet -> {
toolbar.title = getString(R.string.details_row_title_reset_factory_settings)
tvWarningDescription.text = getString(R.string.details_row_title_reset_factory_settings_warning)
btnConfirm.text = getString(R.string.details_row_title_reset_factory_settings)
btnConfirm.setCompoundDrawablesRelativeWithIntrinsicBounds(
null, null, getDrawable(R.drawable.ic_send), null
)
btnConfirm.setOnClickListener { store.dispatch(DetailsAction.ResetToFactory.Confirm) }
}
ConfirmScreenState.LongTap, ConfirmScreenState.AccessCode,
ConfirmScreenState.PassCode -> {
toolbar.title = getString(R.string.details_manage_security_title)
tvWarningDescription.text = getString(R.string.details_security_management_warning)
btnConfirm.text = getString(R.string.common_save_changes)
btnConfirm.setCompoundDrawablesRelativeWithIntrinsicBounds(
null, null, getDrawable(R.drawable.ic_save), null
)
btnConfirm.setOnClickListener { store.dispatch(DetailsAction.ManageSecurity.SaveChanges) }
}
}
}
}

View file

@ -1,153 +0,0 @@
package com.tangem.tap.features.details.ui
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.Fragment
import androidx.transition.TransitionInflater
import by.kirich1409.viewbindingdelegate.viewBinding
import com.tangem.domain.common.getTwinCardIdForUser
import com.tangem.tap.common.extensions.show
import com.tangem.tap.common.feedback.FeedbackEmail
import com.tangem.tap.common.feedback.SupportInfo
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.common.redux.navigation.AppScreen
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.wallet.redux.WalletAction
import com.tangem.tap.store
import com.tangem.wallet.R
import com.tangem.wallet.databinding.FragmentDetailsBinding
import org.rekotlin.StoreSubscriber
class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber<DetailsState> {
private val binding: FragmentDetailsBinding by viewBinding(FragmentDetailsBinding::bind)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
store.dispatch(NavigationAction.PopBackTo())
}
})
val inflater = TransitionInflater.from(requireContext())
enterTransition = inflater.inflateTransition(R.transition.slide_right)
exitTransition = inflater.inflateTransition(R.transition.fade)
}
override fun onStart() {
super.onStart()
store.subscribe(this) { state ->
state.skipRepeats { oldState, newState ->
oldState.detailsState == newState.detailsState
}.select { it.detailsState }
}
}
override fun onStop() {
super.onStop()
store.unsubscribe(this)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.toolbar.setNavigationOnClickListener {
store.dispatch(NavigationAction.PopBackTo())
}
}
override fun newState(state: DetailsState) {
if (activity == null || view == null) return
setState(state)
}
private fun setState(state: DetailsState) = with (binding) {
if (state.cardInfo != null) {
val cardId = if (state.isTangemTwins) {
state.scanResponse?.card?.getTwinCardIdForUser()
} else {
state.cardInfo.cardId
}
tvCardId.text = cardId
tvIssuer.text = state.cardInfo.issuer
tvSignedHashes.text = getString(
R.string.details_row_subtitle_signed_hashes_format,
state.cardInfo.signedHashes.toString()
)
}
tvSignedHashes.show(!state.isTangemTwins)
tvSignedHashesTitle.show(!state.isTangemTwins)
tvDisclaimer.setOnClickListener { store.dispatch(DetailsAction.ShowDisclaimer) }
tvCardTou.show(state.cardTermsOfUseUrl != null)
tvCardTou.setOnClickListener {
val intent = Intent(Intent.ACTION_VIEW)
intent.data = state.cardTermsOfUseUrl
startActivity(intent)
}
if (state.isTangemTwins) {
tvResetToFactory.show()
tvResetToFactory.text = getText(R.string.details_row_title_twins_recreate)
tvResetToFactory.setOnClickListener {
store.dispatch(DetailsAction.ReCreateTwinsWallet(state.twinCardsState.cardNumber!!))
}
} else {
tvResetToFactory.show()
tvResetToFactory.text = getText(R.string.details_row_title_reset_factory_settings)
tvResetToFactory.setOnClickListener {
store.dispatch(DetailsAction.ResetToFactory.Check)
store.dispatch(DetailsAction.ResetToFactory.Proceed)
}
}
tvCreateBackup.show(state.createBackupAllowed)
tvCreateBackup.setOnClickListener {
store.dispatch(DetailsAction.CreateBackup)
}
tvAppCurrency.show(state.scanResponse?.card?.isMultiwalletAllowed != true)
tvAppCurrencyTitle.show(state.scanResponse?.card?.isMultiwalletAllowed != true)
tvAppCurrency.text = state.appCurrency.code
tvAppCurrency.setOnClickListener {
store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency)
}
tvSendFeedback.setOnClickListener {
store.dispatch(GlobalAction.SendEmail(FeedbackEmail()))
}
tvWalletConnect.show(state.scanResponse?.card?.isMultiwalletAllowed == true)
tvWalletConnect.setOnClickListener {
store.dispatch(NavigationAction.NavigateTo(AppScreen.WalletConnectSessions))
}
tvSupport.setOnClickListener {
store.dispatch(GlobalAction.OpenChat(SupportInfo()))
}
llManageSecurity.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 { tvSecurity.text = getString(it) }
}
}

View file

@ -1,147 +0,0 @@
package com.tangem.tap.features.details.ui
import android.os.Bundle
import android.view.View
import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.Fragment
import androidx.transition.TransitionInflater
import by.kirich1409.viewbindingdelegate.viewBinding
import com.tangem.common.card.Card
import com.tangem.tap.common.extensions.show
import com.tangem.tap.common.redux.navigation.NavigationAction
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.store
import com.tangem.wallet.R
import com.tangem.wallet.databinding.FragmentDetailsSecurityBinding
import org.rekotlin.StoreSubscriber
import java.util.*
class DetailsSecurityFragment : Fragment(R.layout.fragment_details_security),
StoreSubscriber<DetailsState> {
private val binding: FragmentDetailsSecurityBinding by viewBinding(
FragmentDetailsSecurityBinding::bind
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
store.dispatch(NavigationAction.PopBackTo())
}
})
val inflater = TransitionInflater.from(requireContext())
enterTransition = inflater.inflateTransition(R.transition.slide_right)
exitTransition = inflater.inflateTransition(R.transition.fade)
}
override fun onStart() {
super.onStart()
store.subscribe(this) { state ->
state.skipRepeats { oldState, newState ->
oldState.detailsState == newState.detailsState
}.select { it.detailsState }
}
}
override fun onStop() {
super.onStop()
store.unsubscribe(this)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.toolbar.setNavigationOnClickListener {
store.dispatch(NavigationAction.PopBackTo())
}
setOnClickListeners()
}
private fun setOnClickListeners() {
binding.btnSaveChanges.setOnClickListener {
store.state.detailsState.securityScreenState?.selectedOption?.let {
store.dispatch(DetailsAction.ManageSecurity.ConfirmSelection(it))
}
}
}
override fun newState(state: DetailsState) {
if (activity == null || view == null) return
selectSecurityOption(state.securityScreenState?.selectedOption)
for (option in SecurityOption.values()) {
setupOption(
option,
state.securityScreenState?.allowedOptions
?: EnumSet.noneOf(SecurityOption::class.java)
)
}
binding.tvAccessCodeUnavailableDisclaimer.show(
state.scanResponse?.card?.backupStatus == Card.BackupStatus.NoBackup
)
}
private fun selectSecurityOption(securityOption: SecurityOption?) = with(binding) {
radiobuttonLongTap.isChecked =
securityOption == SecurityOption.LongTap && radiobuttonLongTap.isEnabled
radiobuttonPasscode.isChecked =
securityOption == SecurityOption.PassCode && radiobuttonPasscode.isEnabled
radiobuttonAccessCode.isChecked =
securityOption == SecurityOption.AccessCode && radiobuttonAccessCode.isEnabled
}
private fun setupOption(option: SecurityOption, allowedOptions: EnumSet<SecurityOption>) {
when (option) {
SecurityOption.LongTap -> { enableLongTap(allowedOptions.contains(option)) }
SecurityOption.PassCode -> { enablePasscode(allowedOptions.contains(option)) }
SecurityOption.AccessCode -> { enableAccessCode(allowedOptions.contains(option)) }
}
}
private fun enableLongTap(enable: Boolean) = with(binding) {
groupLongTap.show(enable)
val alpha = if (enable) 1f else 0.5f
tvLongTapDescription.alpha = alpha
tvLongTapTitle.alpha = alpha
radiobuttonLongTap.alpha = alpha
radiobuttonLongTap.isEnabled = enable
vLongTap.isClickable = enable
if (enable) {
vLongTap.setOnClickListener {
store.dispatch(DetailsAction.ManageSecurity.SelectOption(SecurityOption.LongTap))
}
}
}
private fun enablePasscode(enable: Boolean) = with(binding) {
groupPasscode.show(enable)
val alpha = if (enable) 1f else 0.5f
tvPasscodeDescription.alpha = alpha
tvPasscodeTitle.alpha = alpha
radiobuttonPasscode.alpha = alpha
radiobuttonPasscode.isEnabled = enable
vPasscode.isClickable = enable
if (enable) {
vPasscode.setOnClickListener {
store.dispatch(DetailsAction.ManageSecurity.SelectOption(SecurityOption.PassCode))
}
}
}
private fun enableAccessCode(enable: Boolean) = with(binding) {
groupAccessCode.show(enable)
val alpha = if (enable) 1f else 0.5f
tvAccessCodeDescription.alpha = alpha
tvAccessCodeTitle.alpha = alpha
radiobuttonAccessCode.alpha = alpha
radiobuttonAccessCode.isEnabled = enable
vAccessCode.isClickable = enable
if (enable) {
vAccessCode.setOnClickListener {
store.dispatch(DetailsAction.ManageSecurity.SelectOption(SecurityOption.AccessCode))
}
}
}
}

View file

@ -0,0 +1,3 @@
package com.tangem.tap.features.details.ui.appsettings
class AppSettingsFragment

View file

@ -0,0 +1,9 @@
package com.tangem.tap.features.details.ui.appsettings
import androidx.compose.runtime.Composable
@Composable
fun AppSettingsScreen(
) {
}

View file

@ -0,0 +1,73 @@
package com.tangem.tap.features.details.ui.cardsettings
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.Fragment
import androidx.transition.TransitionInflater
import com.google.accompanist.appcompattheme.AppCompatTheme
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.features.details.redux.DetailsAction
import com.tangem.tap.features.details.redux.DetailsState
import com.tangem.tap.store
import org.rekotlin.StoreSubscriber
class CardSettingsFragment : Fragment(), StoreSubscriber<DetailsState> {
private val viewModel = CardSettingsViewModel(store)
private var screenState: MutableState<CardSettingsScreenState> =
mutableStateOf(viewModel.updateState(store.state.detailsState.cardSettingsState))
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val inflater = TransitionInflater.from(requireContext())
enterTransition = inflater.inflateTransition(android.R.transition.fade)
exitTransition = inflater.inflateTransition(android.R.transition.fade)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
return ComposeView(requireContext()).apply {
setContent {
isTransitionGroup = true
AppCompatTheme {
CardSettingsScreen(
state = screenState.value,
onBackPressed = {
store.dispatch(DetailsAction.ResetCardSettingsData)
store.dispatch(NavigationAction.PopBackTo())
},
)
}
}
}
}
override fun onStart() {
super.onStart()
store.subscribe(this) { state ->
state.skipRepeats { oldState, newState ->
oldState.detailsState == newState.detailsState
}.select { it.detailsState }
}
}
override fun onStop() {
super.onStop()
store.unsubscribe(this)
}
override fun newState(state: DetailsState) {
if (activity == null || view == null) return
screenState.value = viewModel.updateState(state.cardSettingsState)
}
}

View file

@ -0,0 +1,169 @@
package com.tangem.tap.features.details.ui.cardsettings
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.colorResource
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.tap.common.compose.TangemTypography
import com.tangem.tap.features.details.ui.common.DetailsMainButton
import com.tangem.tap.features.details.ui.common.SettingsScreensScaffold
import com.tangem.wallet.R
@Composable
fun CardSettingsScreen(
state: CardSettingsScreenState,
onBackPressed: () -> Unit,
modifier: Modifier = Modifier,
) {
SettingsScreensScaffold(
content =
if (state.cardDetails == null) {
{ CardSettingsReadCard(state.onScanCardClick, modifier = modifier) }
} else {
{ CardSettings(state = state, modifier = modifier) }
},
titleRes = R.string.card_settings_title,
onBackClick = onBackPressed,
)
}
@Composable
fun CardSettingsReadCard(
onScanCardClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.fillMaxSize(),
verticalArrangement = Arrangement.SpaceBetween,
) {
Box(
modifier = modifier
.fillMaxWidth(),
) {
Image(
modifier = modifier
.fillMaxWidth()
.padding(start = 80.dp, end = 80.dp, top = 70.dp)
.rotate(-15f),
painter = painterResource(id = R.drawable.card_placeholder_secondary),
contentDescription = "",
contentScale = ContentScale.FillWidth,
)
Image(
modifier = modifier
.fillMaxWidth()
.padding(start = 60.dp, end = 60.dp)
.rotate(-1f),
painter = painterResource(id = R.drawable.card_placeholder_black),
contentDescription = "",
contentScale = ContentScale.FillWidth,
)
}
Column(
modifier = modifier
.fillMaxWidth()
.padding(start = 16.dp, end = 16.dp, bottom = 32.dp),
) {
Text(
text = stringResource(id = R.string.scan_card_settings_title),
color = colorResource(id = R.color.text_primary_1),
style = TangemTypography.headline3,
)
Spacer(modifier = modifier.size(20.dp))
Text(
text = stringResource(id = R.string.scan_card_settings_message),
color = colorResource(id = R.color.text_secondary),
style = TangemTypography.body1,
)
Spacer(modifier = modifier.size(29.dp))
DetailsMainButton(
title = stringResource(id = R.string.scan_card_settings_button),
onClick = onScanCardClick,
modifier = modifier,
)
}
}
}
@Composable
fun CardSettings(
state: CardSettingsScreenState,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.fillMaxWidth(),
) {
state.cardDetails?.map {
val paddingBottom = when (it) {
is CardInfo.CardId, is CardInfo.Issuer -> 12.dp
is CardInfo.SignedHashes -> 14.dp
is CardInfo.SecurityMode -> 16.dp
is CardInfo.ChangeAccessCode -> 16.dp
is CardInfo.ResetToFactorySettings -> 28.dp
}
val paddingTop = when (it) {
is CardInfo.CardId -> 0.dp
is CardInfo.Issuer -> 12.dp
is CardInfo.SignedHashes -> 12.dp
is CardInfo.SecurityMode -> 14.dp
is CardInfo.ChangeAccessCode -> 16.dp
is CardInfo.ResetToFactorySettings -> 16.dp
}
Column(
modifier = modifier
.fillMaxWidth()
.clickable(
enabled = it.clickable,
onClick = { state.onElementClick(it) },
)
.padding(start = 20.dp, end = 20.dp, bottom = paddingBottom, top = paddingTop),
) {
val titleColor = if (it.clickable) R.color.text_primary_1 else R.color.text_tertiary
val subtitleColor = if (it.clickable) R.color.text_secondary else R.color.text_tertiary
Text(
text = it.titleRes.resolveReference(),
color = colorResource(id = titleColor),
style = TangemTypography.subtitle1,
)
Spacer(modifier = modifier.size(4.dp))
Text(
text = it.subtitle.resolveReference(),
color = colorResource(id = subtitleColor),
style = TangemTypography.body2,
)
}
}
}
}
@Composable
@Preview
fun CardSettingsPreview() {
CardSettingsScreen(state = CardSettingsScreenState(onScanCardClick = {}) {}, {})
}

View file

@ -0,0 +1,74 @@
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.tap.features.details.redux.SecurityOption
import com.tangem.tap.features.details.ui.securitymode.toTitleRes
import com.tangem.wallet.R
data class CardSettingsScreenState(
val cardDetails: List<CardInfo>? = null,
val onScanCardClick: () -> Unit,
val onElementClick: (CardInfo) -> Unit,
)
sealed class CardInfo(
val titleRes: TextReference, val subtitle: TextReference, val clickable: Boolean = false,
) {
class CardId(subtitle: String) : CardInfo(
titleRes = TextReference.Res(R.string.details_row_title_cid),
subtitle = TextReference
.Str(subtitle),
)
class Issuer(subtitle: String) : CardInfo(
titleRes = TextReference.Res(R.string.details_row_title_issuer),
subtitle = TextReference
.Str(subtitle),
)
class SignedHashes(hashes: String) : CardInfo(
titleRes = TextReference.Res(R.string.details_row_title_signed_hashes),
subtitle = TextReference.Res(R.string.details_row_subtitle_signed_hashes_format, hashes),
)
class SecurityMode(
securityOption: SecurityOption,
clickable: Boolean,
) : CardInfo(
titleRes = TextReference.Res(R.string.card_settings_security_mode),
subtitle = TextReference.Res(securityOption.toTitleRes()),
clickable = clickable,
)
object ChangeAccessCode : CardInfo(
titleRes = TextReference.Res(R.string.card_settings_change_access_code),
subtitle = TextReference.Res(R.string.card_settings_change_access_code_footer),
clickable = true,
)
object ResetToFactorySettings : CardInfo(
titleRes = TextReference.Res(R.string.card_settings_reset_card_to_factory),
subtitle = TextReference.Res(R.string.card_settings_reset_card_to_factory_footer),
clickable = true,
)
}
sealed interface TextReference {
class Res(@StringRes val id: Int, val formatArgs: List<Any> = emptyList()) : TextReference {
constructor(@StringRes id: Int, vararg formatArgs: Any) : this(id, formatArgs.toList())
}
class Str(val value: String) : TextReference
}
@Composable
@ReadOnlyComposable
fun TextReference.resolveReference(): String {
return when (this) {
is TextReference.Res -> stringResource(this.id, *this.formatArgs.toTypedArray())
is TextReference.Str -> this.value
}
}

View file

@ -0,0 +1,75 @@
package com.tangem.tap.features.details.ui.cardsettings
import com.tangem.domain.common.getTwinCardIdForUser
import com.tangem.domain.common.isTangemTwins
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.features.details.redux.CardSettingsState
import com.tangem.tap.features.details.redux.DetailsAction
import org.rekotlin.Store
class CardSettingsViewModel(private val store: Store<AppState>) {
fun updateState(state: CardSettingsState?): CardSettingsScreenState {
return if (state?.manageSecurityState == null) {
CardSettingsScreenState(
cardDetails = null,
onElementClick = {},
onScanCardClick = {
store.dispatch(DetailsAction.ScanCard)
},
)
} else {
val cardId = if (state.card.isTangemTwins()) {
state.card.getTwinCardIdForUser()
} else {
state.cardInfo.cardId
}
val cardDetails: MutableList<CardInfo> = mutableListOf(
CardInfo.CardId(cardId),
CardInfo.Issuer(state.cardInfo.issuer),
)
if (!state.card.isTangemTwins()) {
cardDetails.add(CardInfo.SignedHashes(state.cardInfo.signedHashes.toString()))
}
cardDetails.add(
CardInfo.SecurityMode(
securityOption = state.manageSecurityState.currentOption,
clickable = state.manageSecurityState.allowedOptions.size > 1,
),
)
if (state.card.backupStatus?.isActive == true && state.card.isAccessCodeSet) {
cardDetails.add(CardInfo.ChangeAccessCode)
}
if (state.resetCardAllowed) {
cardDetails.add(CardInfo.ResetToFactorySettings)
}
CardSettingsScreenState(
cardDetails = cardDetails,
onScanCardClick = { },
onElementClick = {
handleClickingItem(it)
},
)
}
}
private fun handleClickingItem(item: CardInfo) {
when (item) {
is CardInfo.ChangeAccessCode -> {
store.dispatch(DetailsAction.ManageSecurity.ChangeAccessCode)
}
is CardInfo.ResetToFactorySettings -> {
store.dispatch(NavigationAction.NavigateTo(AppScreen.ResetToFactory))
}
is CardInfo.SecurityMode -> {
store.dispatch(DetailsAction.ManageSecurity.OpenSecurity)
}
else -> {}
}
}
}

View file

@ -0,0 +1,112 @@
package com.tangem.tap.features.details.ui.common
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.tangem.tap.common.compose.TangemTypography
import com.tangem.wallet.R
@Composable
fun SettingsScreensScaffold(
content: @Composable () -> Unit,
background: @Composable (() -> Unit)? = null,
titleRes: Int,
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
) {
BackHandler(true, onBackClick)
Scaffold(
topBar = { EmptyTopBarWithNavigation(onBackClick = onBackClick) },
modifier = modifier.systemBarsPadding(),
backgroundColor = colorResource(id = R.color.background_primary),
) {
Box(modifier = modifier.fillMaxSize()) {
background?.invoke()
Column(
modifier = modifier.fillMaxWidth(),
) {
Text(
text = stringResource(id = titleRes),
modifier = modifier.padding(start = 20.dp, end = 20.dp, bottom = 52.dp),
style = TangemTypography.headline1,
color = colorResource(id = R.color.text_primary_1),
)
content()
}
}
}
}
@Composable
fun EmptyTopBarWithNavigation(
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
) {
TopAppBar(
title = { },
navigationIcon =
{
IconButton(onClick = onBackClick) {
Icon(
painterResource(id = R.drawable.ic_back), "",
tint = colorResource(id = R.color.icon_primary_1),
)
}
},
backgroundColor = colorResource(id = R.color.background_primary),
elevation = 0.dp,
)
}
@Composable
fun DetailsMainButton(
title: String,
enabled: Boolean = true,
onClick: (() -> Unit),
modifier: Modifier = Modifier,
) {
Button(
onClick = onClick,
modifier = modifier
.fillMaxWidth()
.height(48.dp),
shape = RoundedCornerShape(12.dp),
enabled = enabled,
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(R.color.button_primary),
contentColor = colorResource(R.color.text_primary_2),
disabledBackgroundColor = colorResource(R.color.button_disabled),
disabledContentColor = colorResource(R.color.text_disabled),
),
) {
Text(text = title)
Spacer(modifier = modifier.size(8.dp))
Icon(painter = painterResource(id = R.drawable.ic_tangem), contentDescription = "")
}
}

View file

@ -0,0 +1,69 @@
package com.tangem.tap.features.details.ui.details
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.Fragment
import androidx.transition.TransitionInflater
import com.google.accompanist.appcompattheme.AppCompatTheme
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.features.details.redux.DetailsState
import com.tangem.tap.store
import org.rekotlin.StoreSubscriber
class DetailsFragment : Fragment(), StoreSubscriber<DetailsState> {
private val detailsViewModel = DetailsViewModel(store)
private var detailsScreenState: MutableState<DetailsScreenState> =
mutableStateOf(detailsViewModel.updateState(store.state.detailsState))
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val inflater = TransitionInflater.from(requireContext())
enterTransition = inflater.inflateTransition(android.R.transition.fade)
exitTransition = inflater.inflateTransition(android.R.transition.fade)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
return ComposeView(requireContext()).apply {
setContent {
isTransitionGroup = true
AppCompatTheme {
DetailsScreen(
state = detailsScreenState.value,
onBackPressed = { store.dispatch(NavigationAction.PopBackTo()) },
)
}
}
}
}
override fun onStart() {
super.onStart()
store.subscribe(this) { state ->
state.skipRepeats { oldState, newState ->
oldState.detailsState == newState.detailsState
}.select { it.detailsState }
}
}
override fun onStop() {
super.onStop()
store.unsubscribe(this)
}
override fun newState(state: DetailsState) {
if (activity == null || view == null) return
detailsScreenState.value = detailsViewModel.updateState(state)
}
}

View file

@ -0,0 +1,184 @@
package com.tangem.tap.features.details.ui.details
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.material.Icon
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.colorResource
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.tap.common.compose.TangemTypography
import com.tangem.tap.features.details.ui.common.SettingsScreensScaffold
import com.tangem.wallet.R
@Composable
fun DetailsScreen(
state: DetailsScreenState,
onBackPressed: () -> Unit,
modifier: Modifier = Modifier,
) {
SettingsScreensScaffold(
content = {
Content(state = state, modifier = modifier)
},
titleRes = R.string.details_title,
onBackClick = onBackPressed,
)
}
@Composable
fun Content(
state: DetailsScreenState,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.fillMaxWidth()
.padding(bottom = 40.dp),
) {
state.elements.map {
if (it == SettingsElement.WalletConnect) {
WalletConnectDetailsItem(
onItemsClick = state.onItemsClick, modifier = modifier,
)
} else {
DetailsItem(
item = it, onItemsClick = state.onItemsClick,
modifier = modifier,
)
}
}
Spacer(modifier = Modifier.weight(1f))
TangemSocialAccounts(state.tangemLinks, state.onSocialNetworkClick)
Spacer(modifier = Modifier.size(12.dp))
Text(
text = "${stringResource(id = state.appNameRes)} ${state.tangemVersion}",
style = TangemTypography.caption,
color = colorResource(id = R.color.text_tertiary),
modifier = modifier.padding(start = 16.dp, end = 16.dp),
)
}
}
@Composable
fun WalletConnectDetailsItem(
onItemsClick: (SettingsElement) -> Unit,
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier
.height(84.dp)
.fillMaxWidth()
.clickable { onItemsClick(SettingsElement.WalletConnect) },
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterResource(id = R.drawable.ic_walletconnect),
contentDescription = stringResource(id = R.string.wallet_connect_title),
modifier = modifier.padding(start = 20.dp, end = 20.dp),
tint = colorResource(id = R.color.all_colors_azure),
)
Column(
modifier = modifier.height(56.dp),
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.Center,
) {
Text(
text = stringResource(id = R.string.wallet_connect_title),
modifier = modifier.padding(end = 20.dp, bottom = 4.dp),
style = TangemTypography.headline3,
color = colorResource(id = R.color.text_primary_1),
)
Text(
text = stringResource(id = R.string.wallet_connect_subtitle),
modifier = modifier.padding(end = 20.dp, bottom = 4.dp),
style = TangemTypography.body1,
color = colorResource(id = R.color.text_secondary),
)
}
}
}
@Composable
fun DetailsItem(
item: SettingsElement,
onItemsClick: (SettingsElement) -> Unit,
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier
.height(56.dp)
.fillMaxWidth()
.clickable { onItemsClick(item) },
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterResource(id = item.iconRes),
contentDescription = stringResource(id = item.titleRes),
modifier = modifier.padding(start = 20.dp, end = 20.dp),
tint = colorResource(id = R.color.icon_secondary),
)
Text(
text = stringResource(id = item.titleRes),
modifier = modifier.padding(end = 20.dp),
style = TangemTypography.subtitle1,
color = colorResource(id = R.color.text_primary_1),
)
}
}
@Composable
fun TangemSocialAccounts(
links: List<TangemLink>,
onSocialNetworkClick: (String) -> Unit,
modifier: Modifier = Modifier,
) {
LazyRow(
modifier = modifier.padding(start = 8.dp, end = 8.dp),
) {
items(links) {
Icon(
painter = painterResource(id = it.iconRes),
contentDescription = "",
modifier = modifier
.padding(8.dp)
.clickable { onSocialNetworkClick(it.url) },
tint = colorResource(id = R.color.icon_informative),
)
}
}
}
@Composable
@Preview
fun Preview() {
DetailsScreen(
state = DetailsScreenState(
elements = SettingsElement.values().toList(),
tangemLinks = TangemSocialAccounts.accountsEn,
tangemVersion = "Tangem 2.14.12 (343)",
onItemsClick = {}, onSocialNetworkClick = {},
),
onBackPressed = {},
)
}

View file

@ -0,0 +1,54 @@
package com.tangem.tap.features.details.ui.details
import com.tangem.wallet.R
data class DetailsScreenState(
val elements: List<SettingsElement>,
val tangemLinks: List<TangemLink>,
val tangemVersion: String,
val onItemsClick: (SettingsElement) -> Unit,
val onSocialNetworkClick: (String) -> Unit,
) {
val appNameRes: Int = R.string.app_name
}
enum class SettingsElement(
val iconRes: Int,
val titleRes: Int,
) {
WalletConnect(R.drawable.ic_walletconnect, R.string.wallet_connect_title),
Chat(R.drawable.ic_chat, R.string.details_ask_a_question),
SendFeedback(R.drawable.ic_comment, R.string.details_row_title_send_feedback),
CardSettings(R.drawable.ic_card_settings, R.string.card_settings_title),
AppSettings(R.drawable.ic_settings, R.string.app_settings_title),
LinkMoreCards(R.drawable.ic_more_cards, R.string.details_row_title_create_backup),
TermsOfService(R.drawable.ic_text, R.string.disclaimer_title),
PrivacyPolicy(R.drawable.ic_lock, R.string.details_row_privacy_policy),
;
}
data class TangemLink(
val iconRes: Int,
val url: String,
)
object TangemSocialAccounts {
val accountsEn: List<TangemLink> = listOf(
TangemLink(R.drawable.ic_telegram, "https://t.me/TangemCards"),
TangemLink(R.drawable.ic_twitter, "https://twitter.com/tangem"),
TangemLink(R.drawable.ic_facebook, "https://m.facebook.com/TangemCards/"),
TangemLink(R.drawable.ic_instagram, "https://instagram.com/tangemcards"),
TangemLink(R.drawable.ic_github, "https://github.com/tangem"),
TangemLink(R.drawable.ic_youtube, "https://youtube.com/channel/UCFGwLS7yggzVkP6ozte0m1w"),
TangemLink(R.drawable.ic_linkedin, "https://www.linkedin.com/company/tangem"),
)
val accountsRu: List<TangemLink> = listOf(
TangemLink(R.drawable.ic_telegram, "https://t.me/tangem_ru"),
TangemLink(R.drawable.ic_twitter, "https://twitter.com/tangem"),
TangemLink(R.drawable.ic_facebook, "https://m.facebook.com/TangemCards/"),
TangemLink(R.drawable.ic_instagram, "https://instagram.com/tangemcards"),
TangemLink(R.drawable.ic_github, "https://github.com/tangem"),
TangemLink(R.drawable.ic_youtube, "https://youtube.com/channel/UCFGwLS7yggzVkP6ozte0m1w"),
TangemLink(R.drawable.ic_linkedin, "https://www.linkedin.com/company/tangem"),
)
}

View file

@ -0,0 +1,91 @@
package com.tangem.tap.features.details.ui.details
import com.tangem.tap.common.feedback.FeedbackEmail
import com.tangem.tap.common.feedback.SupportInfo
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.common.redux.navigation.AppScreen
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.home.LocaleRegionProvider
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
import com.tangem.wallet.BuildConfig
import org.rekotlin.Store
class DetailsViewModel(private val store: Store<AppState>) {
fun updateState(state: DetailsState): DetailsScreenState {
val settings = SettingsElement.values().mapNotNull {
when (it) {
SettingsElement.WalletConnect -> {
if (state.scanResponse?.card?.isMultiwalletAllowed == true) it else null
}
SettingsElement.LinkMoreCards -> {
if (state.createBackupAllowed) it else null
}
SettingsElement.PrivacyPolicy -> {
if (state.privacyPolicyUrl != null) it else null
}
else -> it
}
}
return DetailsScreenState(
settings,
tangemLinks = getSocialLinks(),
tangemVersion = getTangemAppVersion(),
onItemsClick = { handleClickingSettingsItem(it) },
onSocialNetworkClick = { handleSocialNetworkClick(it) },
)
}
private fun handleSocialNetworkClick(url: String) {
store.dispatch(NavigationAction.OpenUrl(url))
}
private fun handleClickingSettingsItem(item: SettingsElement) {
when (item) {
SettingsElement.WalletConnect -> {
store.dispatch(NavigationAction.NavigateTo(AppScreen.WalletConnectSessions))
}
SettingsElement.Chat -> {
store.dispatch(GlobalAction.OpenChat(SupportInfo()))
}
SettingsElement.SendFeedback -> {
store.dispatch(GlobalAction.SendEmail(FeedbackEmail()))
}
SettingsElement.CardSettings -> {
store.dispatch(NavigationAction.NavigateTo(AppScreen.CardSettings))
}
SettingsElement.AppSettings -> {
store.dispatch(NavigationAction.NavigateTo(AppScreen.AppSettings)) //TODO: To be available later
}
SettingsElement.LinkMoreCards -> {
store.dispatch(DetailsAction.CreateBackup)
}
SettingsElement.TermsOfService -> {
store.dispatch(DetailsAction.ShowDisclaimer)
}
SettingsElement.PrivacyPolicy -> {
// TODO: To be available later
}
}
}
private fun getSocialLinks(): List<TangemLink> {
val locale = LocaleRegionProvider().getRegion()
return if (locale.lowercase() == RUSSIA_COUNTRY_CODE) {
TangemSocialAccounts.accountsRu
} else {
TangemSocialAccounts.accountsEn
}
}
private fun getTangemAppVersion(): String {
val versionCode: Int = BuildConfig.VERSION_CODE
val versionName: String = BuildConfig.VERSION_NAME
return "$versionName ($versionCode)"
}
}

View file

@ -0,0 +1,69 @@
package com.tangem.tap.features.details.ui.resetcard
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.Fragment
import androidx.transition.TransitionInflater
import com.google.accompanist.appcompattheme.AppCompatTheme
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.features.details.redux.DetailsState
import com.tangem.tap.store
import org.rekotlin.StoreSubscriber
class ResetCardFragment : Fragment(), StoreSubscriber<DetailsState> {
private val viewModel = ResetCardViewModel(store)
private var screenState: MutableState<ResetCardScreenState> =
mutableStateOf(viewModel.updateState(store.state.detailsState.cardSettingsState))
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val inflater = TransitionInflater.from(requireContext())
enterTransition = inflater.inflateTransition(android.R.transition.fade)
exitTransition = inflater.inflateTransition(android.R.transition.fade)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
return ComposeView(requireContext()).apply {
setContent {
isTransitionGroup = true
AppCompatTheme {
ResetCardScreen(
state = screenState.value,
onBackPressed = { store.dispatch(NavigationAction.PopBackTo()) },
)
}
}
}
}
override fun onStart() {
super.onStart()
store.subscribe(this) { state ->
state.skipRepeats { oldState, newState ->
oldState.detailsState == newState.detailsState
}.select { it.detailsState }
}
}
override fun onStop() {
super.onStop()
store.unsubscribe(this)
}
override fun newState(state: DetailsState) {
if (activity == null || view == null) return
screenState.value = viewModel.updateState(state.cardSettingsState)
}
}

View file

@ -0,0 +1,126 @@
package com.tangem.tap.features.details.ui.resetcard
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.Icon
import androidx.compose.material.IconToggleButton
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.colorResource
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.tap.common.compose.TangemTypography
import com.tangem.tap.features.details.ui.common.DetailsMainButton
import com.tangem.tap.features.details.ui.common.SettingsScreensScaffold
import com.tangem.wallet.R
@Composable
fun ResetCardScreen(
state: ResetCardScreenState,
onBackPressed: () -> Unit,
modifier: Modifier = Modifier,
) {
SettingsScreensScaffold(
content = { ResetCardView(state = state, modifier = modifier) },
background =
{ Image(painter = painterResource(id = R.drawable.ic_reset_background), contentDescription = "") },
titleRes = R.string.reset_card_to_factory_navigation_title,
onBackClick = onBackPressed,
)
}
@Composable
fun ResetCardView(
state: ResetCardScreenState,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.fillMaxSize(),
verticalArrangement = Arrangement.Bottom,
) {
Text(
text = stringResource(id = R.string.common_attention),
modifier = modifier.padding(start = 20.dp, end = 20.dp),
style = TangemTypography.headline3,
color = colorResource(id = R.color.text_primary_1),
)
Spacer(modifier = modifier.size(24.dp))
Text(
text = stringResource(id = R.string.reset_card_to_factory_message),
modifier = modifier.padding(start = 20.dp, end = 20.dp),
style = TangemTypography.body1,
color = colorResource(id = R.color.text_secondary),
)
Spacer(modifier = modifier.size(44.dp))
Row(
modifier = modifier
.fillMaxWidth()
.padding(end = 20.dp),
) {
IconToggleButton(
checked = state.accepted,
onCheckedChange = state.onAcceptWarningToggleClick,
modifier = modifier.padding(start = 20.dp, end = 20.dp),
) {
Icon(
painter = painterResource(
if (state.accepted) {
R.drawable.ic_accepted
} else {
R.drawable.ic_unticked
},
),
contentDescription = null,
tint = if (state.accepted) {
colorResource(id = R.color.icon_accent)
} else {
colorResource(id = R.color.icon_secondary)
},
)
}
Text(
text = stringResource(id = R.string.reset_card_to_factory_warning_message),
style = TangemTypography.body2,
color = colorResource(id = R.color.text_secondary),
)
}
Spacer(modifier = modifier.size(32.dp))
Box(
modifier = modifier
.padding(start = 16.dp, end = 16.dp, bottom = 32.dp),
) {
DetailsMainButton(
title = stringResource(id = R.string.reset_card_to_factory_button_title),
onClick = state.onResetButtonClick,
enabled = state.resetButtonEnabled,
)
}
}
}
@Composable
@Preview
fun ResetCardScreenPreview(
) {
ResetCardScreen(state = ResetCardScreenState(onAcceptWarningToggleClick = {}, accepted = true) {}, {})
}

View file

@ -0,0 +1,10 @@
package com.tangem.tap.features.details.ui.resetcard
data class ResetCardScreenState(
val accepted: Boolean = false,
val onAcceptWarningToggleClick: (Boolean) -> Unit,
val onResetButtonClick: () -> Unit,
) {
val resetButtonEnabled: Boolean
get() = accepted
}

View file

@ -0,0 +1,17 @@
package com.tangem.tap.features.details.ui.resetcard
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.features.details.redux.CardSettingsState
import com.tangem.tap.features.details.redux.DetailsAction
import org.rekotlin.Store
class ResetCardViewModel(private val store: Store<AppState>) {
fun updateState(state: CardSettingsState?): ResetCardScreenState {
return ResetCardScreenState(
accepted = state?.resetConfirmed ?: false,
onAcceptWarningToggleClick = { store.dispatch(DetailsAction.ResetToFactory.Confirm(it)) },
onResetButtonClick = { store.dispatch(DetailsAction.ResetToFactory.Proceed) },
)
}
}

View file

@ -0,0 +1,69 @@
package com.tangem.tap.features.details.ui.securitymode
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.Fragment
import androidx.transition.TransitionInflater
import com.google.accompanist.appcompattheme.AppCompatTheme
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.features.details.redux.DetailsState
import com.tangem.tap.store
import org.rekotlin.StoreSubscriber
class SecurityModeFragment : Fragment(), StoreSubscriber<DetailsState> {
private val viewModel = SecurityModeViewModel(store)
private var screenState: MutableState<SecurityModeScreenState> =
mutableStateOf(viewModel.updateState(store.state.detailsState.cardSettingsState?.manageSecurityState))
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val inflater = TransitionInflater.from(requireContext())
enterTransition = inflater.inflateTransition(android.R.transition.fade)
exitTransition = inflater.inflateTransition(android.R.transition.fade)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
return ComposeView(requireContext()).apply {
setContent {
isTransitionGroup = true
AppCompatTheme {
SecurityModeScreen(
state = screenState.value,
onBackPressed = { store.dispatch(NavigationAction.PopBackTo()) },
)
}
}
}
}
override fun onStart() {
super.onStart()
store.subscribe(this) { state ->
state.skipRepeats { oldState, newState ->
oldState.detailsState == newState.detailsState
}.select { it.detailsState }
}
}
override fun onStop() {
super.onStop()
store.unsubscribe(this)
}
override fun newState(state: DetailsState) {
if (activity == null || view == null) return
screenState.value = viewModel.updateState(state.cardSettingsState?.manageSecurityState)
}
}

View file

@ -0,0 +1,125 @@
package com.tangem.tap.features.details.ui.securitymode
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.selection.selectable
import androidx.compose.material.RadioButton
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.tap.common.compose.TangemTypography
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.SettingsScreensScaffold
import com.tangem.wallet.R
@Composable
fun SecurityModeScreen(
state: SecurityModeScreenState,
onBackPressed: () -> Unit,
modifier: Modifier = Modifier,
) {
SettingsScreensScaffold(
content = { SecurityModeOptions(state = state, modifier = modifier) },
titleRes = R.string.card_settings_security_mode,
onBackClick = onBackPressed,
)
}
@Composable
fun SecurityModeOptions(
state: SecurityModeScreenState,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.fillMaxSize()
.padding(bottom = 28.dp),
verticalArrangement = Arrangement.SpaceBetween,
) {
state.availableOptions.map {
SecurityOption(option = it, state = state, modifier = modifier)
}
Spacer(modifier = Modifier.weight(1f))
DetailsMainButton(
title = stringResource(id = R.string.common_save_changes),
enabled = state.isSaveChangesEnabled,
onClick = state.onSaveChangesClicked,
modifier = modifier
.padding(start = 20.dp, end = 20.dp),
)
}
}
@Composable
fun SecurityOption(
option: SecurityOption, state: SecurityModeScreenState,
modifier: Modifier,
) {
val selected = option == state.selectedSecurityMode
val title = option.toTitleRes()
val subtitle = when (option) {
SecurityOption.LongTap -> R.string.details_manage_security_long_tap_description
SecurityOption.PassCode -> R.string.details_manage_security_passcode_description
SecurityOption.AccessCode -> R.string.details_manage_security_access_code_description
}
Row(
modifier = modifier
.fillMaxWidth()
.selectable(
selected = selected, onClick = { state.onNewModeSelected(option) },
)
.padding(start = 20.dp, end = 20.dp, bottom = 32.dp),
) {
RadioButton(
selected = selected, onClick = null,
modifier = modifier.padding(end = 20.dp),
)
Column {
Text(
text = stringResource(id = title),
style = TangemTypography.subtitle1,
color = colorResource(id = R.color.text_primary_1),
)
Spacer(modifier = modifier.size(4.dp))
Text(
text = stringResource(id = subtitle),
style = TangemTypography.body2,
color = colorResource(id = R.color.text_secondary),
)
}
}
}
@Preview
@Composable
fun SecurityModeScreenPreview() {
SecurityModeScreen(
state = SecurityModeScreenState(
availableOptions = SecurityOption.values().toList(),
selectedSecurityMode = SecurityOption.LongTap,
isSaveChangesEnabled = false,
onNewModeSelected = {},
onSaveChangesClicked = {},
),
onBackPressed = {},
)
}

View file

@ -0,0 +1,20 @@
package com.tangem.tap.features.details.ui.securitymode
import com.tangem.tap.features.details.redux.SecurityOption
import com.tangem.wallet.R
data class SecurityModeScreenState(
val availableOptions: List<SecurityOption>,
val selectedSecurityMode: SecurityOption,
val isSaveChangesEnabled: Boolean,
val onNewModeSelected: (SecurityOption) -> Unit,
val onSaveChangesClicked: () -> Unit,
)
fun SecurityOption.toTitleRes(): Int {
return when (this) {
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
}
}

View file

@ -0,0 +1,27 @@
package com.tangem.tap.features.details.ui.securitymode
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.features.details.redux.DetailsAction
import com.tangem.tap.features.details.redux.ManageSecurityState
import com.tangem.tap.features.details.redux.SecurityOption
import org.rekotlin.Store
class SecurityModeViewModel(val store: Store<AppState>) {
fun updateState(state: ManageSecurityState?): SecurityModeScreenState {
if (state == null) return SecurityModeScreenState(
availableOptions = emptyList(),
selectedSecurityMode = SecurityOption.LongTap,
isSaveChangesEnabled = false,
onNewModeSelected = {},
onSaveChangesClicked = {},
)
return SecurityModeScreenState(
availableOptions = state.allowedOptions.toList(),
selectedSecurityMode = state.selectedOption,
isSaveChangesEnabled = state.selectedOption != state.currentOption,
onNewModeSelected = { store.dispatch(DetailsAction.ManageSecurity.SelectOption(it)) },
onSaveChangesClicked = { store.dispatch(DetailsAction.ManageSecurity.SaveChanges) },
)
}
}

View file

@ -0,0 +1,21 @@
package com.tangem.tap.features.details.ui.walletconnect
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@Composable
fun WalletConnectScreen(
modifier: Modifier = Modifier,
) {
}
//data class WalletConnectScreenState(
// sessions: WcSessionScreenState
//)
//
//data class WcSessionScreenState(
// val icon: Bitmap,
//
//)

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="20dp"
android:viewportHeight="20" android:viewportWidth="20"
android:width="20dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#1ACE80" android:fillType="evenOdd" android:pathData="M10,0C4.48,0 0,4.48 0,10C0,15.52 4.48,20 10,20C15.52,20 20,15.52 20,10C20,4.48 15.52,0 10,0ZM8,15L3,10L4.41,8.59L8,12.17L15.59,4.58L17,6L8,15Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M11,15H13V17H11V15ZM11,7H13V13H11V7ZM12,2C6.47,2 2,6.5 2,12C2,14.652 3.054,17.196 4.929,19.071C5.858,20 6.96,20.736 8.173,21.239C9.386,21.741 10.687,22 12,22C14.652,22 17.196,20.946 19.071,19.071C20.946,17.196 22,14.652 22,12C22,10.687 21.741,9.386 21.239,8.173C20.736,6.96 20,5.858 19.071,4.929C18.142,4 17.04,3.264 15.827,2.761C14.614,2.259 13.313,2 12,2ZM12,20C9.878,20 7.843,19.157 6.343,17.657C4.843,16.157 4,14.122 4,12C4,9.878 4.843,7.843 6.343,6.343C7.843,4.843 9.878,4 12,4C14.122,4 16.157,4.843 17.657,6.343C19.157,7.843 20,9.878 20,12C20,14.122 19.157,16.157 17.657,17.657C16.157,19.157 14.122,20 12,20Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4C9.11,4 6.6,5.64 5.35,8.04C2.34,8.36 0,10.91 0,14C0,15.591 0.632,17.117 1.757,18.243C2.883,19.368 4.409,20 6,20H19C19.657,20 20.307,19.871 20.913,19.619C21.52,19.368 22.071,19 22.535,18.535C23,18.071 23.368,17.52 23.619,16.913C23.871,16.307 24,15.657 24,15C24,12.36 21.95,10.22 19.35,10.04ZM19,18H6C4.939,18 3.922,17.579 3.172,16.828C2.421,16.078 2,15.061 2,14C2,11.95 3.53,10.24 5.56,10.03L6.63,9.92L7.13,8.97C8.08,7.14 9.94,6 12,6C14.62,6 16.88,7.86 17.39,10.43L17.69,11.93L19.22,12.04C20.78,12.14 22,13.45 22,15C22,15.796 21.684,16.559 21.121,17.121C20.559,17.684 19.796,18 19,18ZM8,13H10.55V16H13.45V13H16L12,9L8,13Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:fillType="evenOdd" android:pathData="M4,4H20C21.1,4 22,4.89 22,6V13.4C21.41,12.93 20.74,12.56 20,12.32V12H4V18H11.53C11.5,18.17 11.5,18.33 11.5,18.5C11.5,19 11.57,19.5 11.68,20H4C2.9,20 2,19.11 2,18V6C2,4.89 2.89,4 4,4ZM4,8H20V6H4V8ZM16.856,19.614C17.16,19.909 17.572,20.075 18.001,20.075C18.431,20.075 18.842,19.909 19.146,19.614C19.45,19.318 19.62,18.918 19.62,18.5C19.62,18.082 19.45,17.682 19.146,17.386C18.842,17.091 18.431,16.925 18.001,16.925C17.572,16.925 17.16,17.091 16.856,17.386C16.552,17.682 16.382,18.082 16.382,18.5C16.382,18.918 16.552,19.318 16.856,19.614ZM21.471,18.5C21.471,18.649 21.457,18.792 21.438,18.937L22.414,19.684C22.502,19.751 22.525,19.872 22.47,19.972L21.545,21.528C21.489,21.628 21.364,21.663 21.263,21.628L20.111,21.173C19.87,21.353 19.62,21.501 19.329,21.618L19.158,22.811C19.139,22.919 19.042,23 18.926,23H17.076C16.96,23 16.863,22.919 16.844,22.811L16.673,21.618C16.382,21.506 16.132,21.353 15.892,21.173L14.74,21.628C14.638,21.663 14.513,21.628 14.457,21.528L13.532,19.972C13.472,19.872 13.5,19.751 13.588,19.684L14.564,18.937C14.545,18.792 14.531,18.649 14.531,18.5C14.531,18.351 14.545,18.203 14.564,18.05L13.588,17.316C13.5,17.249 13.472,17.128 13.532,17.028L14.457,15.472C14.513,15.373 14.638,15.332 14.74,15.373L15.892,15.823C16.132,15.647 16.382,15.494 16.673,15.382L16.844,14.189C16.863,14.081 16.96,14 17.076,14H18.926C19.042,14 19.139,14.081 19.158,14.189L19.329,15.382C19.62,15.494 19.87,15.647 20.111,15.823L21.263,15.373C21.364,15.332 21.489,15.373 21.545,15.472L22.47,17.028C22.525,17.128 22.502,17.249 22.414,17.316L21.438,18.05C21.457,18.203 21.471,18.351 21.471,18.5Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:fillType="evenOdd" android:pathData="M7,3C5.895,3 5,3.895 5,5V15C5,16.105 5.895,17 7,17H21C22.105,17 23,16.105 23,15V5C23,3.895 22.105,3 21,3H17.205C16.61,3 16.143,3.406 15.991,3.906C15.833,4.424 15.349,5.5 14,5.5C12.651,5.5 12.167,4.424 12.009,3.906C11.857,3.406 11.391,3 10.795,3H7ZM7,5L10.286,5C10.697,5.936 11.724,7.5 14,7.5C16.276,7.5 17.303,5.936 17.714,5H21V15H7V5ZM18,19H3V8H1V19C1,19.53 1.21,20.04 1.59,20.41C1.96,20.79 2.47,21 3,21H18V19Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M9,22C8.735,22 8.48,21.895 8.293,21.707C8.105,21.52 8,21.265 8,21V18H4C3.47,18 2.961,17.789 2.586,17.414C2.211,17.039 2,16.53 2,16V4C2,2.89 2.9,2 4,2H20C20.53,2 21.039,2.211 21.414,2.586C21.789,2.961 22,3.47 22,4V16C22,16.53 21.789,17.039 21.414,17.414C21.039,17.789 20.53,18 20,18H13.9L10.2,21.71C10,21.9 9.75,22 9.5,22H9ZM10,16V19.08L13.08,16H20V4H4V16H10ZM6,7H18V9H6V7ZM6,11H15V13H6V11Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z"/>
</vector>

View file

@ -1,10 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M9,22C8.4,22 8,21.6 8,21V18H4C2.9,18 2,17.1 2,16V4C2,2.9 2.9,2 4,2H20C21.1,2 22,2.9 22,4V16C22,17.1 21.1,18 20,18H13.9L10.2,21.7C10,21.9 9.8,22 9.5,22H9ZM10,16V19.1L13.1,16H20V4H4V16H10ZM16.3,6L14.9,9H17V13H13V8.8L14.3,6H16.3ZM10.3,6L8.9,9H11V13H7V8.8L8.3,6H10.3Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#B0B0B0" android:pathData="M12,1.935C6.442,1.935 1.935,6.465 1.935,12.052C1.935,17.124 5.653,21.312 10.495,22.043V14.733H8.005V12.074H10.495V10.304C10.495,7.375 11.915,6.089 14.337,6.089C15.497,6.089 16.111,6.176 16.402,6.215V8.536H14.749C13.721,8.536 13.362,9.516 13.362,10.62V12.074H16.375L15.967,14.733H13.362V22.065C18.274,21.395 22.065,17.173 22.065,12.052C22.065,6.465 17.558,1.935 12,1.935Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M6,13H18V11H6M3,6V8H21V6M10,18H14V16H10V18Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#B0B0B0" android:pathData="M12,2.4C6.698,2.4 2.4,6.698 2.4,12C2.4,16.498 5.498,20.262 9.674,21.304C9.629,21.174 9.6,21.024 9.6,20.838V19.197C9.21,19.197 8.558,19.197 8.394,19.197C7.737,19.197 7.153,18.914 6.87,18.39C6.555,17.806 6.501,16.914 5.722,16.369C5.49,16.187 5.666,15.98 5.933,16.008C6.425,16.147 6.833,16.485 7.217,16.986C7.599,17.487 7.779,17.601 8.494,17.601C8.84,17.601 9.358,17.581 9.846,17.504C10.109,16.838 10.562,16.224 11.117,15.934C7.92,15.606 6.394,14.015 6.394,11.856C6.394,10.926 6.79,10.027 7.463,9.27C7.242,8.518 6.965,6.984 7.548,6.4C8.986,6.4 9.856,7.333 10.065,7.585C10.782,7.339 11.569,7.2 12.396,7.2C13.225,7.2 14.015,7.339 14.734,7.586C14.94,7.336 15.81,6.4 17.252,6.4C17.838,6.985 17.557,8.525 17.334,9.275C18.002,10.031 18.396,10.928 18.396,11.856C18.396,14.014 16.873,15.603 13.681,15.934C14.559,16.392 15.2,17.68 15.2,18.65V20.838C15.2,20.921 15.182,20.981 15.172,21.052C18.913,19.741 21.6,16.189 21.6,12C21.6,6.698 17.302,2.4 12,2.4Z"/>
</vector>

View file

@ -0,0 +1,10 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<group>
<clip-path android:pathData="M2.4,2.4h19.2v19.2h-19.2z"/>
<path android:fillColor="#B0B0B0" android:pathData="M21.581,8.045C21.536,7.025 21.371,6.323 21.135,5.716C20.891,5.07 20.516,4.493 20.025,4.013C19.545,3.525 18.963,3.146 18.326,2.906C17.714,2.67 17.017,2.505 15.997,2.46C14.969,2.411 14.642,2.4 12.036,2.4C9.429,2.4 9.103,2.411 8.079,2.456C7.058,2.501 6.357,2.666 5.749,2.903C5.104,3.146 4.527,3.521 4.047,4.013C3.559,4.493 3.18,5.074 2.94,5.712C2.704,6.323 2.539,7.021 2.494,8.041C2.445,9.069 2.434,9.395 2.434,12.002C2.434,14.609 2.445,14.935 2.49,15.959C2.535,16.979 2.7,17.68 2.936,18.288C3.18,18.933 3.559,19.511 4.047,19.991C4.527,20.479 5.108,20.857 5.746,21.097C6.357,21.334 7.055,21.499 8.075,21.544C9.099,21.589 9.425,21.6 12.032,21.6C14.639,21.6 14.965,21.589 15.989,21.544C17.009,21.499 17.711,21.334 18.318,21.097C19.608,20.598 20.629,19.578 21.128,18.288C21.364,17.677 21.529,16.979 21.574,15.959C21.619,14.935 21.63,14.609 21.63,12.002C21.63,9.395 21.626,9.069 21.581,8.045ZM19.852,15.884C19.811,16.822 19.653,17.328 19.522,17.666C19.199,18.502 18.536,19.166 17.699,19.488C17.362,19.62 16.852,19.777 15.918,19.818C14.905,19.864 14.601,19.875 12.039,19.875C9.478,19.875 9.17,19.864 8.161,19.818C7.223,19.777 6.717,19.62 6.38,19.488C5.963,19.334 5.584,19.091 5.277,18.772C4.958,18.461 4.714,18.086 4.56,17.669C4.429,17.332 4.272,16.822 4.23,15.888C4.185,14.875 4.174,14.571 4.174,12.009C4.174,9.448 4.185,9.14 4.23,8.131C4.272,7.193 4.429,6.687 4.56,6.35C4.714,5.933 4.958,5.554 5.281,5.247C5.592,4.928 5.967,4.684 6.383,4.53C6.721,4.399 7.231,4.242 8.165,4.2C9.178,4.155 9.481,4.144 12.043,4.144C14.609,4.144 14.912,4.155 15.922,4.2C16.859,4.242 17.365,4.399 17.703,4.53C18.119,4.684 18.498,4.928 18.806,5.247C19.125,5.558 19.368,5.933 19.522,6.35C19.653,6.687 19.811,7.197 19.852,8.131C19.897,9.144 19.909,9.448 19.909,12.009C19.909,14.571 19.897,14.871 19.852,15.884Z"/>
<path android:fillColor="#B0B0B0" android:pathData="M12.036,7.07C9.313,7.07 7.103,9.279 7.103,12.002C7.103,14.725 9.313,16.934 12.036,16.934C14.759,16.934 16.968,14.725 16.968,12.002C16.968,9.279 14.759,7.07 12.036,7.07ZM12.036,15.201C10.269,15.201 8.836,13.768 8.836,12.002C8.836,10.235 10.269,8.802 12.036,8.802C13.802,8.802 15.235,10.235 15.235,12.002C15.235,13.768 13.802,15.201 12.036,15.201Z"/>
<path android:fillColor="#B0B0B0" android:pathData="M18.315,6.875C18.315,7.511 17.799,8.026 17.163,8.026C16.527,8.026 16.011,7.511 16.011,6.875C16.011,6.239 16.527,5.723 17.163,5.723C17.799,5.723 18.315,6.239 18.315,6.875Z"/>
</group>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#B0B0B0" android:pathData="M19.2,3.2H4.8C3.916,3.2 3.2,3.916 3.2,4.8V19.2C3.2,20.084 3.916,20.8 4.8,20.8H19.2C20.084,20.8 20.8,20.084 20.8,19.2V4.8C20.8,3.916 20.084,3.2 19.2,3.2ZM8.763,17.6H6.403V10.006H8.763V17.6ZM7.559,8.921C6.798,8.921 6.183,8.304 6.183,7.545C6.183,6.785 6.799,6.169 7.559,6.169C8.318,6.169 8.934,6.786 8.934,7.545C8.934,8.304 8.318,8.921 7.559,8.921ZM17.603,17.6H15.245V13.907C15.245,13.026 15.229,11.894 14.018,11.894C12.79,11.894 12.602,12.853 12.602,13.843V17.6H10.243V10.006H12.507V11.044H12.539C12.854,10.447 13.624,9.817 14.772,9.817C17.162,9.817 17.603,11.39 17.603,13.435V17.6Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M12,17C10.89,17 10,16.1 10,15C10,13.89 10.89,13 12,13C12.53,13 13.039,13.211 13.414,13.586C13.789,13.961 14,14.47 14,15C14,15.53 13.789,16.039 13.414,16.414C13.039,16.789 12.53,17 12,17ZM18,20V10H6V20H18ZM18,8C18.53,8 19.039,8.211 19.414,8.586C19.789,8.961 20,9.47 20,10V20C20,20.53 19.789,21.039 19.414,21.414C19.039,21.789 18.53,22 18,22H6C4.89,22 4,21.1 4,20V10C4,8.89 4.89,8 6,8H7V6C7,4.674 7.527,3.402 8.464,2.464C9.402,1.527 10.674,1 12,1C12.657,1 13.307,1.129 13.913,1.381C14.52,1.632 15.071,2 15.535,2.464C16,2.929 16.368,3.48 16.619,4.087C16.871,4.693 17,5.343 17,6V8H18ZM12,3C11.204,3 10.441,3.316 9.879,3.879C9.316,4.441 9,5.204 9,6V8H15V6C15,5.204 14.684,4.441 14.121,3.879C13.559,3.316 12.796,3 12,3Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M12,16C12.53,16 13.039,16.211 13.414,16.586C13.789,16.961 14,17.47 14,18C14,18.53 13.789,19.039 13.414,19.414C13.039,19.789 12.53,20 12,20C11.47,20 10.961,19.789 10.586,19.414C10.211,19.039 10,18.53 10,18C10,17.47 10.211,16.961 10.586,16.586C10.961,16.211 11.47,16 12,16ZM12,10C12.53,10 13.039,10.211 13.414,10.586C13.789,10.961 14,11.47 14,12C14,12.53 13.789,13.039 13.414,13.414C13.039,13.789 12.53,14 12,14C11.47,14 10.961,13.789 10.586,13.414C10.211,13.039 10,12.53 10,12C10,11.47 10.211,10.961 10.586,10.586C10.961,10.211 11.47,10 12,10ZM12,4C12.53,4 13.039,4.211 13.414,4.586C13.789,4.961 14,5.47 14,6C14,6.53 13.789,7.039 13.414,7.414C13.039,7.789 12.53,8 12,8C11.47,8 10.961,7.789 10.586,7.414C10.211,7.039 10,6.53 10,6C10,5.47 10.211,4.961 10.586,4.586C10.961,4.211 11.47,4 12,4Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:fillType="evenOdd" android:pathData="M21,11V16H7V11H21ZM21,8V6H7V8H21ZM22.41,4.59C22.04,4.21 21.53,4 21,4H7C5.89,4 5,4.89 5,6V16C5,17.1 5.89,18 7,18H21C21.53,18 22.04,17.79 22.41,17.41C22.79,17.04 23,16.53 23,16V6C23,5.47 22.79,4.96 22.41,4.59ZM18,20H3V9H1V20C1,20.53 1.21,21.04 1.59,21.41C1.96,21.79 2.47,22 3,22H18V20Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M12.63,2C18.16,2 22.64,6.5 22.64,12C22.64,17.5 18.16,22 12.63,22C9.12,22 6.05,20.18 4.26,17.43L5.84,16.18C7.25,18.47 9.76,20 12.64,20C14.762,20 16.797,19.157 18.297,17.657C19.797,16.157 20.64,14.122 20.64,12C20.64,9.878 19.797,7.843 18.297,6.343C16.797,4.843 14.762,4 12.64,4C8.56,4 5.2,7.06 4.71,11H7.47L3.73,14.73L0,11H2.69C3.19,5.95 7.45,2 12.63,2ZM15.59,10.24C16.09,10.25 16.5,10.65 16.5,11.16V15.77C16.5,16.27 16.09,16.69 15.58,16.69H10.05C9.54,16.69 9.13,16.27 9.13,15.77V11.16C9.13,10.65 9.54,10.25 10.04,10.24V9.23C10.04,7.7 11.29,6.46 12.81,6.46C14.34,6.46 15.59,7.7 15.59,9.23V10.24ZM12.81,7.86C12.06,7.86 11.44,8.47 11.44,9.23V10.24H14.19V9.23C14.19,8.47 13.57,7.86 12.81,7.86Z"/>
</vector>

View file

@ -0,0 +1,24 @@
<vector android:autoMirrored="true" android:height="344dp"
android:viewportHeight="344" android:viewportWidth="233"
android:width="233dp" xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillAlpha="0.3" android:pathData="M49,-262L49,-262A184,184 0,0 1,233 -78L233,160A184,184 0,0 1,49 344L49,344A184,184 0,0 1,-135 160L-135,-78A184,184 0,0 1,49 -262z">
<aapt:attr name="android:fillColor">
<gradient android:centerX="149.32" android:centerY="383.08"
android:gradientRadius="337.25" android:type="radial">
<item android:color="#FFFF9900" android:offset="0"/>
<item android:color="#00FF9900" android:offset="1"/>
</gradient>
</aapt:attr>
</path>
<path android:fillAlpha="0.5" android:pathData="M49,-182L49,-182A150,150 0,0 1,199 -32L199,160A150,150 0,0 1,49 310L49,310A150,150 0,0 1,-101 160L-101,-32A150,150 0,0 1,49 -182z">
<aapt:attr name="android:fillColor">
<gradient android:centerX="73" android:centerY="498"
android:gradientRadius="371.06" android:type="radial">
<item android:color="#FFDA1717" android:offset="0"/>
<item android:color="#03DA1717" android:offset="1"/>
<item android:color="#00FF0000" android:offset="1"/>
</gradient>
</aapt:attr>
</path>
<path android:fillColor="#DE1010" android:fillType="evenOdd" android:pathData="M72.88,249.79C72.88,253.27 70.53,255.96 66.66,255.96H31.34C27.47,255.96 25.12,253.27 25.12,249.79C25.12,248.71 25.39,247.62 26.01,246.6L43.69,215.79C44.85,213.71 46.9,212.67 49,212.67C51.1,212.67 53.12,213.71 54.31,215.79L71.99,246.6C72.56,247.6 72.88,248.71 72.88,249.79ZM49.02,240.74C47.84,240.74 47.18,240.06 47.15,238.85L46.86,226.45C46.84,225.24 47.72,224.38 49,224.38C50.23,224.38 51.19,225.27 51.16,226.48L50.82,238.85C50.8,240.08 50.14,240.74 49.02,240.74ZM49.02,248.37C47.66,248.37 46.47,247.28 46.47,245.93C46.47,244.57 47.63,243.47 49.02,243.47C50.39,243.47 51.55,244.54 51.55,245.93C51.55,247.3 50.37,248.37 49.02,248.37Z"/>
</vector>

View file

@ -1,16 +1,8 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="21dp"
android:viewportWidth="24"
android:viewportHeight="21"
>
<path
android:pathData="M17.7908,9.0129C16.9896,6.7531 15.3666,4.9247 13.1993,3.8873C11.032,2.8498 8.5873,2.7163 6.3275,3.5175L6.2762,3.538C6.1734,3.5791 6.081,3.651 6.0399,3.764C5.9886,3.8667 5.9886,3.99 6.0296,4.0927C6.1221,4.329 6.3789,4.442 6.6254,4.3598C8.6695,3.6408 10.8676,3.764 12.809,4.6988C14.7606,5.6335 16.2295,7.277 16.9485,9.3108C17.2566,10.1839 17.4107,11.0878 17.4107,12.002C17.4107,12.9161 17.2566,13.8201 16.9485,14.6932C16.2295,16.7372 14.7606,18.3704 12.809,19.3052C10.8574,20.2399 8.6592,20.3632 6.6151,19.6441C6.3789,19.562 6.1221,19.6749 6.0296,19.9112C5.9886,20.0242 5.9886,20.1372 6.0399,20.2399C6.0913,20.3426 6.1734,20.4248 6.2864,20.4659L6.3378,20.4864C7.3136,20.8254 8.3202,21 9.3269,21C10.6519,21 11.977,20.7021 13.2096,20.1166C15.3769,19.0792 17.0101,17.2611 17.801,14.991C18.14,14.0255 18.3146,13.0189 18.3146,12.0122C18.3044,10.9851 18.1297,9.9784 17.7908,9.0129Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M7.1702,17.0252C7.1183,17.1498 7.1287,17.2848 7.1806,17.4095C7.2326,17.5341 7.3365,17.6172 7.4715,17.6588C8.0532,17.8457 8.6556,17.9392 9.2581,17.9392C9.9644,17.9392 10.6707,17.8146 11.3251,17.5549C12.7689,17.0044 13.9115,15.9137 14.5347,14.5011C14.8671,13.7532 15.0333,12.9742 15.0333,12.1744V12.0082C15.0126,11.2499 14.8464,10.502 14.5347,9.7957C13.9011,8.383 12.7689,7.3028 11.3251,6.7419C10.0787,6.2641 8.6972,6.2329 7.4299,6.6484C7.3157,6.6899 7.2118,6.773 7.1599,6.8873C7.1079,7.0016 7.1079,7.1262 7.1495,7.2405C7.2326,7.4586 7.4819,7.5729 7.7104,7.5001C8.7803,7.147 9.954,7.1677 11.0031,7.5729C12.2184,8.0403 13.1844,8.9543 13.7142,10.1489C13.9946,10.7721 14.1296,11.4265 14.14,12.1017V12.1328C14.14,12.8184 13.9946,13.4831 13.7142,14.1167C13.1844,15.3113 12.2184,16.2253 11.0031,16.6928C9.9436,17.0979 8.7699,17.1186 7.6896,16.7551C7.4819,16.7135 7.243,16.8174 7.1702,17.0252Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M9.9148,13.5778C9.6136,13.692 9.2812,13.7128 8.9592,13.6297C8.7619,13.5778 8.5437,13.6816 8.471,13.879V13.8894C8.4191,14.014 8.4295,14.1594 8.5022,14.2841C8.5645,14.4087 8.6892,14.5022 8.8346,14.5334C9.0112,14.5749 9.1774,14.5853 9.3539,14.5853C9.6552,14.5853 9.9564,14.5334 10.2472,14.4191C11.2029,14.0556 11.8469,13.1207 11.8469,12.0924C11.8469,11.0641 11.2029,10.1396 10.2472,9.7657C9.7694,9.5787 9.2501,9.5476 8.7411,9.6722C8.6268,9.7034 8.523,9.7761 8.471,9.8903C8.4191,9.9942 8.4087,10.1188 8.4503,10.2331L8.4607,10.2539C8.5437,10.472 8.7723,10.5863 9.0008,10.5447C9.302,10.472 9.624,10.4928 9.9148,10.607C10.5277,10.8356 10.9328,11.438 10.9328,12.0924C10.9328,12.7468 10.5277,13.3492 9.9148,13.5778Z"
android:fillColor="#ffffff"/>
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<group>
<clip-path android:pathData="M0,0h24v24h-24z"/>
<path android:fillColor="#000000" android:pathData="M2,4H6V2H2C1.47,2 0.961,2.211 0.586,2.586C0.211,2.961 0,3.47 0,4L0,8H2V4ZM22,2H18V4H22V8H24V4C24,3.47 23.789,2.961 23.414,2.586C23.039,2.211 22.53,2 22,2ZM2,16H0V20C0,20.53 0.211,21.039 0.586,21.414C0.961,21.789 1.47,22 2,22H6V20H2V16ZM22,20H18V22H22C22.53,22 23.039,21.789 23.414,21.414C23.789,21.039 24,20.53 24,20V16H22V20ZM4,8V16C4,16.53 4.211,17.039 4.586,17.414C4.961,17.789 5.47,18 6,18H18C18.53,18 19.039,17.789 19.414,17.414C19.789,17.039 20,16.53 20,16V8C20,7.47 19.789,6.961 19.414,6.586C19.039,6.211 18.53,6 18,6H6C5.47,6 4.961,6.211 4.586,6.586C4.211,6.961 4,7.47 4,8ZM6,16V12H18V16H6ZM18,8V10H6V8H18Z"/>
</group>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M21,11C21,16.55 17.16,21.74 12,23C6.84,21.74 3,16.55 3,11V5L12,1L21,5V11ZM12,21C15.75,20 19,15.54 19,11.22V6.3L12,3.18L5,6.3V11.22C5,15.54 8.25,20 12,21ZM14.8,11V9.5C14.8,8.1 13.4,7 12,7C10.6,7 9.2,8.1 9.2,9.5V11C8.6,11 8,11.6 8,12.2V15.7C8,16.4 8.6,17 9.2,17H14.7C15.4,17 16,16.4 16,15.8V12.3C16,11.6 15.4,11 14.8,11ZM13.5,11H10.5V9.5C10.5,8.7 11.2,8.2 12,8.2C12.8,8.2 13.5,8.7 13.5,9.5V11Z"/>
</vector>

View file

@ -1,10 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M12,8C13.061,8 14.078,8.421 14.828,9.172C15.578,9.922 16,10.939 16,12C16,13.061 15.578,14.078 14.828,14.828C14.078,15.579 13.061,16 12,16C10.939,16 9.922,15.579 9.172,14.828C8.421,14.078 8,13.061 8,12C8,10.939 8.421,9.922 9.172,9.172C9.922,8.421 10.939,8 12,8ZM12,10C11.469,10 10.961,10.211 10.586,10.586C10.211,10.961 10,11.47 10,12C10,12.53 10.211,13.039 10.586,13.414C10.961,13.789 11.469,14 12,14C12.53,14 13.039,13.789 13.414,13.414C13.789,13.039 14,12.53 14,12C14,11.47 13.789,10.961 13.414,10.586C13.039,10.211 12.53,10 12,10ZM10,22C9.75,22 9.54,21.82 9.5,21.58L9.13,18.93C8.5,18.68 7.96,18.34 7.44,17.94L4.95,18.95C4.73,19.03 4.46,18.95 4.34,18.73L2.34,15.27C2.21,15.05 2.27,14.78 2.46,14.63L4.57,12.97L4.5,12L4.57,11L2.46,9.37C2.27,9.22 2.21,8.95 2.34,8.73L4.34,5.27C4.46,5.05 4.73,4.96 4.95,5.05L7.44,6.05C7.96,5.66 8.5,5.32 9.13,5.07L9.5,2.42C9.54,2.18 9.75,2 10,2H14C14.25,2 14.46,2.18 14.5,2.42L14.87,5.07C15.5,5.32 16.04,5.66 16.56,6.05L19.05,5.05C19.27,4.96 19.54,5.05 19.66,5.27L21.66,8.73C21.79,8.95 21.73,9.22 21.54,9.37L19.43,11L19.5,12L19.43,13L21.54,14.63C21.73,14.78 21.79,15.05 21.66,15.27L19.66,18.73C19.54,18.95 19.27,19.04 19.05,18.95L16.56,17.95C16.04,18.34 15.5,18.68 14.87,18.93L14.5,21.58C14.46,21.82 14.25,22 14,22H10ZM11.25,4L10.88,6.61C9.68,6.86 8.62,7.5 7.85,8.39L5.44,7.35L4.69,8.65L6.8,10.2C6.4,11.37 6.4,12.64 6.8,13.8L4.68,15.36L5.43,16.66L7.86,15.62C8.63,16.5 9.68,17.14 10.87,17.38L11.24,20H12.76L13.13,17.39C14.32,17.14 15.37,16.5 16.14,15.62L18.57,16.66L19.32,15.36L17.2,13.81C17.6,12.64 17.6,11.37 17.2,10.2L19.31,8.65L18.56,7.35L16.15,8.39C15.38,7.5 14.32,6.86 13.12,6.62L12.75,4H11.25Z"/>
</vector>

View file

@ -0,0 +1,7 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M4,3.9C4,3.403 4.421,3 4.941,3H19.059C19.579,3 20,3.403 20,3.9V8.4H4V3.9Z"/>
<path android:fillColor="#000000" android:pathData="M4,12H9.647V21H4.941C4.421,21 4,20.597 4,20.1V12Z"/>
<path android:fillColor="#000000" android:pathData="M20,12H14.353V21H19.059C19.579,21 20,20.597 20,20.1V12Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#B0B0B0" android:pathData="M20.239,19.288C20.597,18.212 22.282,7.49 22.489,5.377C22.552,4.736 22.344,4.312 21.94,4.122C21.449,3.892 20.721,4.006 19.878,4.304C18.721,4.711 3.932,10.838 3.077,11.193C2.268,11.53 1.5,11.895 1.5,12.427C1.5,12.8 1.728,13.01 2.353,13.228C3.003,13.454 4.642,13.939 5.61,14.199C6.542,14.45 7.602,14.232 8.196,13.871C8.826,13.489 16.101,8.74 16.622,8.324C17.144,7.908 17.56,8.44 17.134,8.858C16.707,9.274 11.715,14.002 11.056,14.657C10.256,15.453 10.823,16.276 11.36,16.606C11.973,16.983 16.376,19.865 17.041,20.328C17.705,20.79 18.376,21 18.993,21C19.609,20.999 19.932,20.206 20.239,19.288Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M6,2C5.47,2 4.961,2.211 4.586,2.586C4.211,2.961 4,3.47 4,4V20C4,20.53 4.211,21.039 4.586,21.414C4.961,21.789 5.47,22 6,22H18C18.53,22 19.039,21.789 19.414,21.414C19.789,21.039 20,20.53 20,20V8L14,2H6ZM6,4H13V9H18V20H6V4ZM8,12V14H16V12H8ZM8,16V18H13V16H8Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M6,19C6,19.53 6.211,20.039 6.586,20.414C6.961,20.789 7.47,21 8,21H16C16.53,21 17.039,20.789 17.414,20.414C17.789,20.039 18,19.53 18,19V7H6V19ZM8,9H16V19H8V9ZM15.5,4L14.5,3H9.5L8.5,4H5V6H19V4H15.5Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#B0B0B0" android:pathData="M22.4,5.55C21.634,5.89 20.812,6.118 19.949,6.222C20.83,5.694 21.506,4.858 21.825,3.861C21.001,4.35 20.087,4.705 19.114,4.897C18.336,4.067 17.227,3.549 16,3.549C13.643,3.549 11.733,5.46 11.733,7.816C11.733,8.15 11.771,8.477 11.843,8.788C8.297,8.61 5.153,6.911 3.047,4.329C2.681,4.959 2.47,5.692 2.47,6.475C2.47,7.955 3.223,9.262 4.368,10.026C3.669,10.004 3.01,9.812 2.435,9.493C2.435,9.511 2.435,9.528 2.435,9.546C2.435,11.614 3.906,13.339 5.858,13.73C5.501,13.828 5.123,13.88 4.734,13.88C4.459,13.88 4.191,13.853 3.931,13.804C4.474,15.499 6.05,16.733 7.918,16.768C6.458,17.913 4.618,18.595 2.618,18.595C2.274,18.595 1.934,18.575 1.599,18.535C3.488,19.746 5.73,20.452 8.141,20.452C15.99,20.452 20.282,13.95 20.282,8.31C20.282,8.126 20.278,7.942 20.27,7.758C21.104,7.156 21.828,6.405 22.4,5.55Z"/>
</vector>

View file

@ -0,0 +1,8 @@
<vector android:autoMirrored="true" android:height="20dp"
android:viewportHeight="20" android:viewportWidth="20"
android:width="20dp" xmlns:android="http://schemas.android.com/apk/res/android">
<group>
<clip-path android:fillType="evenOdd" android:pathData="M0,10C0,4.48 4.48,0 10,0C15.52,0 20,4.48 20,10C20,15.52 15.52,20 10,20C4.48,20 0,15.52 0,10ZM2,10C2,14.42 5.58,18 10,18C14.42,18 18,14.42 18,10C18,5.58 14.42,2 10,2C5.58,2 2,5.58 2,10Z"/>
<path android:fillColor="#656565" android:pathData="M-2,-2h24v24h-24z"/>
</group>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#007AFF" android:pathData="M4.915,7.735C8.827,4.088 15.173,4.088 19.085,7.735L19.555,8.171C19.753,8.353 19.753,8.648 19.555,8.831L17.946,10.333C17.847,10.421 17.692,10.421 17.593,10.333L16.943,9.726C14.213,7.181 9.787,7.181 7.057,9.726L6.364,10.374C6.265,10.462 6.11,10.462 6.011,10.374L4.395,8.878C4.197,8.695 4.197,8.401 4.395,8.218L4.915,7.735ZM22.415,10.84L23.851,12.177C24.049,12.359 24.049,12.654 23.851,12.837L17.382,18.863C17.184,19.046 16.869,19.046 16.677,18.863L12.09,14.586C12.04,14.539 11.96,14.539 11.91,14.586L7.323,18.863C7.125,19.046 6.809,19.046 6.617,18.863L0.149,12.837C-0.05,12.654 -0.05,12.359 0.149,12.177L1.585,10.84C1.783,10.657 2.099,10.657 2.29,10.84L6.877,15.116C6.927,15.163 7.007,15.163 7.057,15.116L11.644,10.84C11.842,10.657 12.158,10.657 12.35,10.84L16.937,15.116C16.986,15.163 17.067,15.163 17.116,15.116L21.703,10.84C21.902,10.657 22.217,10.657 22.415,10.84Z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#B0B0B0" android:pathData="M21.985,6.96C21.79,5.904 20.863,5.136 19.79,4.896C18.18,4.56 15.205,4.32 11.986,4.32C8.767,4.32 5.743,4.56 4.133,4.896C3.06,5.136 2.134,5.856 1.939,6.96C1.743,8.16 1.548,9.84 1.548,12C1.548,14.16 1.743,15.84 1.987,17.04C2.182,18.096 3.109,18.864 4.182,19.104C5.889,19.44 8.816,19.68 12.035,19.68C15.254,19.68 18.18,19.44 19.888,19.104C20.961,18.864 21.887,18.144 22.082,17.04C22.277,15.84 22.521,14.112 22.57,12C22.472,9.84 22.229,8.16 21.985,6.96ZM9.352,15.36V8.64L15.303,12L9.352,15.36Z"/>
</vector>

Binary file not shown.

Binary file not shown.

View file

@ -1,323 +0,0 @@
<?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/details_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_card_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="4dp"
android:text="@string/details_section_title_card"
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_card_title" />
<TextView
android:id="@+id/tv_card_id_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/details_row_title_cid"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_card_title" />
<TextView
android:id="@+id/tv_card_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:textColor="@color/darkGray1"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_card_title"
tools:text="0000 0000 0000 0000" />
<TextView
android:id="@+id/tv_issuer_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/details_row_title_issuer"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_card_id_title" />
<TextView
android:id="@+id/tv_issuer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:textColor="@color/darkGray1"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_card_id"
tools:text="Tangem" />
<TextView
android:id="@+id/tv_signed_hashes_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/details_row_title_signed_hashes"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_issuer_title" />
<TextView
android:id="@+id/tv_signed_hashes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:textColor="@color/darkGray1"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_issuer"
tools:text="48 hashes" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/ll_manage_security"
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_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>
<TextView
android:id="@+id/tv_create_backup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/details_row_title_create_backup"
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/ll_manage_security" />
<TextView
android:id="@+id/tv_reset_to_factory"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/details_row_title_reset_factory_settings"
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_create_backup" />
<TextView
android:id="@+id/tv_settings_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="22dp"
android:paddingBottom="4dp"
android:text="@string/details_section_title_app"
android:textAllCaps="true"
android:textColor="@color/colorSecondary"
android:textSize="13sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_reset_to_factory" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/separatorGrey2"
app:layout_constraintTop_toBottomOf="@id/tv_settings_title" />
<TextView
android:id="@+id/tv_app_currency"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:drawablePadding="15dp"
android:textColor="@color/darkGray1"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:drawableTint="@color/darkGray1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_settings_title"
tools:text="USD" />
<TextView
android:id="@+id/tv_app_currency_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/details_row_title_currency"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_settings_title" />
<TextView
android:id="@+id/tv_disclaimer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/disclaimer_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_app_currency_title" />
<TextView
android:id="@+id/tv_card_tou"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="15dp"
android:paddingTop="7dp"
android:paddingBottom="10dp"
android:text="@string/details_row_title_card_tou"
android:textColor="@color/darkGray6"
android:textSize="16sp"
android:visibility="gone"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:drawableTint="@color/darkGray1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_disclaimer" />
<TextView
android:id="@+id/tv_send_feedback"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/details_row_title_send_feedback"
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_card_tou" />
<TextView
android:id="@+id/tv_wallet_connect"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/wallet_connect"
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_send_feedback" />
<TextView
android:id="@+id/tv_support"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/details_ask_a_question"
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_wallet_connect" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -1,229 +0,0 @@
<?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"
android:id="@+id/coordinator_details_confirm"
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/details_manage_security_title" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_details_confirm"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="16dp"
android:layout_marginBottom="33dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.Group
android:id="@+id/group_long_tap"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="tv_long_tap_title, radiobutton_long_tap, tv_long_tap_description, v_long_tap" />
<TextView
android:id="@+id/tv_long_tap_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp"
android:text="@string/details_manage_security_long_tap"
android:textSize="16sp"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.radiobutton.MaterialRadioButton
android:id="@+id/radiobutton_long_tap"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_long_tap_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="60dp"
android:paddingBottom="8dp"
android:text="@string/details_manage_security_long_tap_description"
android:textColor="@color/darkGray1"
android:textSize="13sp"
app:layout_constraintTop_toBottomOf="@id/tv_long_tap_title" />
<View
android:id="@+id/v_long_tap"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
app:layout_constraintBottom_toBottomOf="@id/tv_long_tap_description"
app:layout_constraintTop_toTopOf="@id/tv_long_tap_title" />
<androidx.constraintlayout.widget.Group
android:id="@+id/group_passcode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="tv_passcode_title, radiobutton_passcode, tv_passcode_description, v_passcode" />
<TextView
android:id="@+id/tv_passcode_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp"
android:text="@string/details_manage_security_passcode"
android:textSize="16sp"
app:layout_constraintTop_toBottomOf="@id/v_long_tap" />
<com.google.android.material.radiobutton.MaterialRadioButton
android:id="@+id/radiobutton_passcode"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/v_passcode" />
<TextView
android:id="@+id/tv_passcode_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="60dp"
android:paddingBottom="8dp"
android:text="@string/details_manage_security_passcode_description"
android:textColor="@color/darkGray1"
android:textSize="13sp"
app:layout_constraintTop_toBottomOf="@id/tv_passcode_title" />
<View
android:id="@+id/v_passcode"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
app:layout_constraintBottom_toBottomOf="@id/tv_passcode_description"
app:layout_constraintTop_toTopOf="@id/tv_passcode_title" />
<androidx.constraintlayout.widget.Group
android:id="@+id/group_access_code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="tv_access_code_title, radiobutton_access_code, tv_access_code_description, v_access_code" />
<TextView
android:id="@+id/tv_access_code_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp"
android:text="@string/details_manage_security_access_code"
android:textSize="16sp"
app:layout_constraintTop_toBottomOf="@id/v_passcode" />
<com.google.android.material.radiobutton.MaterialRadioButton
android:id="@+id/radiobutton_access_code"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/v_access_code" />
<TextView
android:id="@+id/tv_access_code_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="60dp"
android:paddingBottom="8dp"
android:text="@string/details_manage_security_access_code_description"
android:textColor="@color/darkGray1"
android:textSize="13sp"
app:layout_constraintTop_toBottomOf="@id/tv_access_code_title" />
<View
android:id="@+id/v_access_code"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
app:layout_constraintBottom_toBottomOf="@id/tv_access_code_description"
app:layout_constraintTop_toTopOf="@id/tv_access_code_title" />
<TextView
android:id="@+id/tv_access_code_unavailable_disclaimer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/tv_access_code_description"
android:text="@string/details_manage_security_access_code_disclaimer"
android:textColor="@color/darkGray1"
android:textSize="16sp"
android:textAlignment="textStart"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:visibility="gone"
/>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintGuide_percent="0.37" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_save_changes"
style="@style/TapBlackButton"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginStart="7dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="16dp"
android:text="@string/common_continue"
app:icon="@drawable/ic_save"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/guideline" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -61,4 +61,36 @@
<string name="wallet_connect_network_not_found_format">%s network not found. Please, add it first and try again.</string>
<string name="wallet_connect_scanner_error_unsupported_network">This network is not supported. Please select another network.</string>
<string name="wallet_currency_subtitle">%s network</string>
<string name="card_settings_title">Card Settings</string>
<string name="card_settings_security_mode">Security Mode</string>
<string name="card_settings_security_mode_footer">Selected application protection method</string>
<string name="card_settings_change_access_code">Change access code</string>
<string name="card_settings_change_access_code_footer">Access code will be changed on this card only</string>
<string name="scan_card_settings_title">Get your card ready!</string>
<string name="scan_card_settings_message">Scan the card to change its settings. The changes will impact only the card youve scanned and will not affect other cards tied to your wallet.</string>
<string name="scan_card_settings_button">Scan Card</string>
<string name="app_settings_title">App settings</string>
<string name="app_settings_warning_title">Enable biometric authentication</string>
<string name="app_settings_warning_subtitle">Go to settings to enable biometric authentication in the Tangem app</string>
<string name="app_settings_saved_wallet">Keep the wallet in the app</string>
<string name="app_settings_saved_wallet_footer">Enable to link all the wallets to Tangem app. Biometric authentication will be required for unlocking the app. Transaction signing requires tapping your Tangem card.</string>
<string name="app_settings_saved_access_codes">Save Access Code</string>
<string name="app_settings_saved_access_codes_footer">Biometric authentication will be requested instead of the access code for interactions with your card.</string>
<string name="app_settings_off_saved_wallet_alert_message">Removing the saved card deletes all the saved wallets and their access codes.</string>
<string name="app_settings_off_saved_access_code_alert_message">This will delete all the saved wallet access codes. Any further operation with the wallet will require submitting the access code.</string>
<string name="wallet_connect_title">WalletConnect</string>
<string name="wallet_connect_subtitle">Connect to Dapps</string>
<string name="details_row_title_create_backup">Link More Cards</string>
<string name="details_row_title_create_backup_footer">You can synchronize up to three cards into one wallet. It can only be done once.</string>
<string name="details_row_privacy_policy">Privacy policy</string>
<string name="reset_card_to_factory_navigation_title">Reset to factory settings</string>
<string name="reset_card_to_factory_message">This action will completely remove the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code.</string>
<string name="reset_card_to_factory_warning_message">I understand that after performing this action, I will no longer have access to the current wallet</string>
<string name="reset_card_to_factory_button_title">Reset the card</string>
<string name="card_settings_reset_card_to_factory">Reset to Factory Settings</string>
<string name="card_settings_reset_card_to_factory_footer">Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code.</string>
</resources>

View file

@ -61,4 +61,36 @@
<string name="wallet_connect_network_not_found_format">%s network not found. Please, add it first and try again.</string>
<string name="wallet_connect_scanner_error_unsupported_network">This network is not supported. Please select another network.</string>
<string name="wallet_currency_subtitle">%s network</string>
<string name="card_settings_title">Card Settings</string>
<string name="card_settings_security_mode">Security Mode</string>
<string name="card_settings_security_mode_footer">Selected application protection method</string>
<string name="card_settings_change_access_code">Change access code</string>
<string name="card_settings_change_access_code_footer">Access code will be changed on this card only</string>
<string name="scan_card_settings_title">Get your card ready!</string>
<string name="scan_card_settings_message">Scan the card to change its settings. The changes will impact only the card youve scanned and will not affect other cards tied to your wallet.</string>
<string name="scan_card_settings_button">Scan Card</string>
<string name="app_settings_title">App settings</string>
<string name="app_settings_warning_title">Enable biometric authentication</string>
<string name="app_settings_warning_subtitle">Go to settings to enable biometric authentication in the Tangem app</string>
<string name="app_settings_saved_wallet">Keep the wallet in the app</string>
<string name="app_settings_saved_wallet_footer">Enable to link all the wallets to Tangem app. Biometric authentication will be required for unlocking the app. Transaction signing requires tapping your Tangem card.</string>
<string name="app_settings_saved_access_codes">Save Access Code</string>
<string name="app_settings_saved_access_codes_footer">Biometric authentication will be requested instead of the access code for interactions with your card.</string>
<string name="app_settings_off_saved_wallet_alert_message">Removing the saved card deletes all the saved wallets and their access codes.</string>
<string name="app_settings_off_saved_access_code_alert_message">This will delete all the saved wallet access codes. Any further operation with the wallet will require submitting the access code.</string>
<string name="wallet_connect_title">WalletConnect</string>
<string name="wallet_connect_subtitle">Connect to Dapps</string>
<string name="details_row_title_create_backup">Link More Cards</string>
<string name="details_row_title_create_backup_footer">You can synchronize up to three cards into one wallet. It can only be done once.</string>
<string name="details_row_privacy_policy">Privacy policy</string>
<string name="reset_card_to_factory_navigation_title">Reset to factory settings</string>
<string name="reset_card_to_factory_message">This action will completely remove the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code.</string>
<string name="reset_card_to_factory_warning_message">I understand that after performing this action, I will no longer have access to the current wallet</string>
<string name="reset_card_to_factory_button_title">Reset the card</string>
<string name="card_settings_reset_card_to_factory">Reset to Factory Settings</string>
<string name="card_settings_reset_card_to_factory_footer">Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code.</string>
</resources>

View file

@ -62,4 +62,36 @@
<string name="wallet_connect_scanner_error_unsupported_network">This network is not supported. Please select another network.</string>
<string name="wallet_currency_subtitle">%s network</string>
<string name="card_settings_title">Card Settings</string>
<string name="card_settings_security_mode">Security Mode</string>
<string name="card_settings_security_mode_footer">Selected application protection method</string>
<string name="card_settings_change_access_code">Change access code</string>
<string name="card_settings_change_access_code_footer">Access code will be changed on this card only</string>
<string name="scan_card_settings_title">Get your card ready!</string>
<string name="scan_card_settings_message">Scan the card to change its settings. The changes will impact only the card youve scanned and will not affect other cards tied to your wallet.</string>
<string name="scan_card_settings_button">Scan Card</string>
<string name="app_settings_title">App settings</string>
<string name="app_settings_warning_title">Enable biometric authentication</string>
<string name="app_settings_warning_subtitle">Go to settings to enable biometric authentication in the Tangem app</string>
<string name="app_settings_saved_wallet">Keep the wallet in the app</string>
<string name="app_settings_saved_wallet_footer">Enable to link all the wallets to Tangem app. Biometric authentication will be required for unlocking the app. Transaction signing requires tapping your Tangem card.</string>
<string name="app_settings_saved_access_codes">Save Access Code</string>
<string name="app_settings_saved_access_codes_footer">Biometric authentication will be requested instead of the access code for interactions with your card.</string>
<string name="app_settings_off_saved_wallet_alert_message">Removing the saved card deletes all the saved wallets and their access codes.</string>
<string name="app_settings_off_saved_access_code_alert_message">This will delete all the saved wallet access codes. Any further operation with the wallet will require submitting the access code.</string>
<string name="wallet_connect_title">WalletConnect</string>
<string name="wallet_connect_subtitle">Connect to Dapps</string>
<string name="details_row_title_create_backup">Link More Cards</string>
<string name="details_row_title_create_backup_footer">You can synchronize up to three cards into one wallet. It can only be done once.</string>
<string name="details_row_privacy_policy">Privacy policy</string>
<string name="reset_card_to_factory_navigation_title">Reset to factory settings</string>
<string name="reset_card_to_factory_message">This action will completely remove the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code.</string>
<string name="reset_card_to_factory_warning_message">I understand that after performing this action, I will no longer have access to the current wallet</string>
<string name="reset_card_to_factory_button_title">Reset the card</string>
<string name="card_settings_reset_card_to_factory">Reset to Factory Settings</string>
<string name="card_settings_reset_card_to_factory_footer">Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code.</string>
</resources>

View file

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--<color name="background_action">#C9C9C9</color>-->
<!--<color name="background_plain">#000000</color>-->
<!--<color name="background_primary">#1E1E1E</color>-->
<!--<color name="background_secondary">#000000</color>-->
<!--<color name="button_disabled">#1E1E1E</color>-->
<!--<color name="button_positive">#1ACE80</color>-->
<!--<color name="button_positive_disabled">#06311F</color>-->
<!--<color name="button_primary">#F5F5F5</color>-->
<!--<color name="button_secondary">#303030</color>-->
<!--<color name="control_checked">#1ACE80</color>-->
<!--<color name="control_key">#F5F5F5</color>-->
<!--<color name="control_unchecked">#3B3B3B</color>-->
<!--<color name="field_focused">#3B3B3B</color>-->
<!--<color name="field_primary">#303030</color>-->
<!--<color name="icon_accent">#1ACE80</color>-->
<!--<color name="icon_attention">#FFB71B</color>-->
<!--<color name="icon_inactive">#3B3B3B</color>-->
<!--<color name="icon_informative">#656565</color>-->
<!--<color name="icon_primary_1">#FFFFFF</color>-->
<!--<color name="icon_primary_2">#1E1E1E</color>-->
<!--<color name="icon_secondary">#919191</color>-->
<!--<color name="icon_warning">#DE1010</color>-->
<!--<color name="stroke_primary">#303030</color>-->
<!--<color name="stroke_secondary">#66919191</color>-->
<!--<color name="stroke_transparency">#1E1E1E</color>-->
<!--<color name="text_accent">#1ACE80</color>-->
<!--<color name="text_attention">#FFB71B</color>-->
<!--<color name="text_constant_white">#FFFFFF</color>-->
<!--<color name="text_disabled">#494949</color>-->
<!--<color name="text_primary_1">#FFFFFF</color>-->
<!--<color name="text_primary_2">#1E1E1E</color>-->
<!--<color name="text_secondary">#B0B0B0</color>-->
<!--<color name="text_tertiary">#919191</color>-->
<!--<color name="text_warning">#DE1010</color>-->
</resources>

View file

@ -307,7 +307,6 @@
<string name="details_backup_status_format_active">Активный. Количество резервных карт: %d</string>
<string name="details_backup_status_format_linked">Связано. Количество резервных карт: %d</string>
<string name="details_backup_status_no_backup">Нет резервной копии</string>
<string name="details_row_title_create_backup">Создать резервную копию</string>
<string name="welcome_interrupted_backup_alert_message">У Вас есть прерванное резервное копирование. Хотите возобновить?</string>
<string name="welcome_interrupted_backup_alert_resume">Да, возобновить</string>
<string name="welcome_interrupted_backup_alert_discard">Отказаться</string>
@ -323,7 +322,6 @@
<string name="onboarding_subtitle_scan_backup_card_format">Подготовьте резервную карту с номером %s</string>
<string name="onboarding_subtitle_scan_primary_card_format">Подготовьте основную карту с номером %s</string>
<string name="details_row_title_reset_factory_settings">Сброс до заводских настроек</string>
<string name="details_row_title_reset_factory_settings_warning">Это действие необратимо. Если после сброса карты кто-то отправит на нее средства, то Вы не сможете их вывести.</string>
<string name="details_manage_security_access_code_disclaimer">Код доступа доступен только для карт с резервной копией</string>
<string name="solana_rent_warning">Сеть Solana взымает арендную плату в размере %s каждые 2 дня. Аккаунты, которые не могут позволить себе арендную плату, удаляются из сети. Пополните свой счет более чем на %s, чтобы использовать его бесплатно.</string>
<string name="token_symbol_address_format">%1s (%2s)</string>

View file

@ -76,7 +76,38 @@
<string name="russian_bank_card_warning_subtitle">У вас есть карта банка другой страны или платежной системы UnionPay?</string>
<string name="common_yes">Да</string>
<string name="details_ask_a_question">Задать вопрос</string>
<string name="details_ask_a_question">Чат</string>
<string name="chat_bot_name">Tangem Bot</string>
<string name="card_settings_title">Настройки карты</string>
<string name="card_settings_security_mode">Тип безопасности</string>
<string name="card_settings_security_mode_footer">Выбранный способ защиты приложения</string>
<string name="card_settings_change_access_code">Смена кода доступа</string>
<string name="card_settings_change_access_code_footer">Код доступа будет изменен только на данной карте</string>
<string name="scan_card_settings_title">Приготовьте свою карту</string>
<string name="scan_card_settings_message">Отсканируйте карту, чтобы изменить ее настройки. Изменения затронут только ту карту, которую вы отсканировали, и не повлияют на другие карты, привязанные к вашему кошельку.</string>
<string name="scan_card_settings_button">Сканировать</string>
<string name="app_settings_title">Настройки приложения</string>
<string name="app_settings_warning_title">Включите биометрическую аутентификацию</string>
<string name="app_settings_warning_subtitle">Перейдите в настройки, чтобы включить биометрическую аутентификацию в приложении Tangem</string>
<string name="app_settings_saved_wallet">Cохранение кошелька</string>
<string name="app_settings_saved_wallet_footer">Если эта опция включена, кошельки всех отсканированных карт будут привязываться к приложению и при открытии приложения будет необходимо пройти биометрическую аутентификацию. Подпись транзакций все так же потребует карту.</string>
<string name="app_settings_saved_access_codes">Сохранение кода доступа</string>
<string name="app_settings_saved_access_codes_footer">Если эта опция включена, пароли от карты будут хранится на телефоне в зашифрованном виде и при работе с картой вместо пароля будет запрашиваться биометрическая аутентификация</string>
<string name="app_settings_off_saved_wallet_alert_message">При отключении функции сохранения кошелька все ранее сохраненные кошельки будут удалены.</string>
<string name="app_settings_off_saved_access_code_alert_message">Все сохраненные коды доступа будут удалены. Вам потребуется вводить код доступа при работе с кошельком.</string>
<string name="wallet_connect_title">WalletConnect</string>
<string name="wallet_connect_subtitle">Подключение к Dapps</string>
<string name="details_row_title_create_backup">Добавить еще карты</string>
<string name="details_row_title_create_backup_footer">Вы можете объеденить до трех карт в одним кошельке. Это можно сделать только один раз.</string>
<string name="details_row_privacy_policy">Privacy policy</string>
<string name="reset_card_to_factory_navigation_title">Сброс к заводским настройкам</string>
<string name="reset_card_to_factory_message">Это действие приведет к полному удалению кошелька на этой карте. Кошелек невозможно будет восстановить или использовать данную карту для восстановления кода доступа</string>
<string name="reset_card_to_factory_warning_message">Я понимаю, что после выполнения этого действия у меня больше не будет доступа к текущему кошельку</string>
<string name="reset_card_to_factory_button_title">Сбросить карту</string>
<string name="card_settings_reset_card_to_factory">Сброс к заводским настройкам</string>
<string name="card_settings_reset_card_to_factory_footer">Сброс к заводским настройкам приведет к полному удалению кошелька с выбранной карты. Вы не сможете восстановить текущий кошелек или использовать эту карту для восстановления кода доступа.</string>
</resources>

View file

@ -64,4 +64,82 @@
<color name="warning_critical">#CA0F03</color>
<color name="gray_button">#EFEFF0</color>
<color name="all_colors_amaranth">#DE1010</color>
<color name="all_colors_azure">#007AFF</color>
<color name="all_colors_black">#000000</color>
<color name="all_colors_cobalt">#0029FF</color>
<color name="all_colors_dark_1">#919191</color>
<color name="all_colors_dark_2">#656565</color>
<color name="all_colors_dark_3">#494949</color>
<color name="all_colors_dark_4">#3B3B3B</color>
<color name="all_colors_dark_5">#303030</color>
<color name="all_colors_dark_6">#1E1E1E</color>
<color name="all_colors_dark_green">#06311F</color>
<color name="all_colors_flamingo">#ED7979</color>
<color name="all_colors_light_1">#F5F5F5</color>
<color name="all_colors_light_2">#EBEBEB</color>
<color name="all_colors_light_3">#D3D3D3</color>
<color name="all_colors_light_4">#C9C9C9</color>
<color name="all_colors_light_5">#B0B0B0</color>
<color name="all_colors_magic_mint">#A3EBCC</color>
<color name="all_colors_meadow">#1ACE80</color>
<color name="all_colors_tangerine">#FFB71B</color>
<color name="all_colors_white">#FFFFFF</color>
<color name="background_action">#000000</color>
<color name="background_plain">#FFFFFF</color>
<color name="background_primary">#FFFFFF</color>
<color name="background_secondary">#F5F5F5</color>
<color name="button_disabled">#EBEBEB</color>
<color name="button_positive">#1ACE80</color>
<color name="button_positive_disabled">#A3EBCC</color>
<color name="button_primary">#1E1E1E</color>
<color name="button_secondary">#EBEBEB</color>
<color name="control_checked">#1ACE80</color>
<color name="control_key">#FFFFFF</color>
<color name="control_unchecked">#EBEBEB</color>
<color name="field_focused">#EBEBEB</color>
<color name="field_primary">#F5F5F5</color>
<color name="icon_accent">#1ACE80</color>
<color name="icon_attention">#FFB71B</color>
<color name="icon_inactive">#C9C9C9</color>
<color name="icon_informative">#B0B0B0</color>
<color name="icon_primary_1">#000000</color>
<color name="icon_primary_2">#FFFFFF</color>
<color name="icon_secondary">#656565</color>
<color name="icon_warning">#DE1010</color>
<color name="stroke_primary">#EBEBEB</color>
<color name="stroke_secondary">#663B3B3B</color>
<color name="stroke_transparency">#FFFFFF</color>
<color name="text_accent">#1ACE80</color>
<color name="text_attention">#FFB71B</color>
<color name="text_constant_white">#FFFFFF</color>
<color name="text_disabled">#C9C9C9</color>
<color name="text_primary_1">#1E1E1E</color>
<color name="text_primary_2">#FFFFFF</color>
<color name="text_secondary">#656565</color>
<color name="text_tertiary">#919191</color>
<color name="text_warning">#DE1010</color>
</resources>

View file

@ -77,7 +77,39 @@
<string name="common_yes">Yes</string>
<string name="common_no">No</string>
<string name="details_ask_a_question">Ask a question</string>
<string name="details_ask_a_question">Chat</string>
<string name="chat_bot_name">Tangem Bot</string>
<string name="card_settings_title">Card Settings</string>
<string name="card_settings_security_mode">Security Mode</string>
<string name="card_settings_security_mode_footer">Selected application protection method</string>
<string name="card_settings_change_access_code">Change access code</string>
<string name="card_settings_change_access_code_footer">Access code will be changed on this card only</string>
<string name="scan_card_settings_title">Get your card ready!</string>
<string name="scan_card_settings_message">Scan the card to change its settings. The changes will impact only the card youve scanned and will not affect other cards tied to your wallet.</string>
<string name="scan_card_settings_button">Scan Card</string>
<string name="app_settings_title">App settings</string>
<string name="app_settings_warning_title">Enable biometric authentication</string>
<string name="app_settings_warning_subtitle">Go to settings to enable biometric authentication in the Tangem app</string>
<string name="app_settings_saved_wallet">Keep the wallet in the app</string>
<string name="app_settings_saved_wallet_footer">Enable to link all the wallets to Tangem app. Biometric authentication will be required for unlocking the app. Transaction signing requires tapping your Tangem card.</string>
<string name="app_settings_saved_access_codes">Save Access Code</string>
<string name="app_settings_saved_access_codes_footer">Biometric authentication will be requested instead of the access code for interactions with your card.</string>
<string name="app_settings_off_saved_wallet_alert_message">Removing the saved card deletes all the saved wallets and their access codes.</string>
<string name="app_settings_off_saved_access_code_alert_message">This will delete all the saved wallet access codes. Any further operation with the wallet will require submitting the access code.</string>
<string name="wallet_connect_title">WalletConnect</string>
<string name="wallet_connect_subtitle">Connect to Dapps</string>
<string name="details_row_title_create_backup">Link More Cards</string>
<string name="details_row_title_create_backup_footer">You can synchronize up to three cards into one wallet. It can only be done once.</string>
<string name="details_row_privacy_policy">Privacy policy</string>
<string name="reset_card_to_factory_navigation_title">Reset to factory settings</string>
<string name="reset_card_to_factory_message">This action will completely remove the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code.</string>
<string name="reset_card_to_factory_warning_message">I understand that after performing this action, I will no longer have access to the current wallet</string>
<string name="reset_card_to_factory_button_title">Reset the card</string>
<string name="card_settings_reset_card_to_factory">Reset to Factory Settings</string>
<string name="card_settings_reset_card_to_factory_footer">Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code.</string>
</resources>

View file

@ -131,7 +131,7 @@
<string name="warning_low_signatures_format" translatable="false">There are only %s signatures available on this card. You must withdraw all of your funds.</string>
//Wallet Connect
<string name="wallet_connect" translatable="false">Wallet Connect</string>
<string name="wallet_connect" translatable="false">WalletConnect</string>
<string name="wallet_connect_sessions_title" translatable="false">Wallet Connect Sessions</string>
<string name="wallet_connect_session_opened" translatable="false">WalletConnect session opened with %s</string>
<string name="wallet_connect_no_sessions_title" translatable="false">Ooops. No Sessions.</string>
@ -283,7 +283,6 @@
<string name="details_backup_status_format_active" translatable="false">Active. Backup cards count: %d</string>
<string name="details_backup_status_format_linked" translatable="false">Linked. Backup cards count: %d</string>
<string name="details_backup_status_no_backup" translatable="false">No backup</string>
<string name="details_row_title_create_backup" translatable="false">Create backup</string>
<string name="welcome_interrupted_backup_alert_message" translatable="false">You have an interrupted backup. Do you want to resume?</string>
<string name="welcome_interrupted_backup_alert_resume" translatable="false">Yes, resume</string>
<string name="welcome_interrupted_backup_alert_discard" translatable="false">Discard</string>
@ -299,7 +298,6 @@
<string name="onboarding_subtitle_scan_backup_card_format" translatable="false">Prepare the backup card with number %s</string>
<string name="onboarding_subtitle_scan_primary_card_format" translatable="false">Prepare the primary card with number %s</string>
<string name="details_row_title_reset_factory_settings" translatable="false">Reset to factory settings</string>
<string name="details_row_title_reset_factory_settings_warning" translatable="false">This action is irreversible. If, after resetting the card, someone sends funds to it, then you will not be able to withdraw them.</string>
<string name="details_manage_security_access_code_disclaimer" translatable="false">Access code is available only for cards with a backup.</string>

View file

@ -42,8 +42,7 @@ object TapWorkarounds {
return false
}
@Deprecated("Use ScanResponse.isTangemNote")
fun isTangemNote(card: Card): Boolean = tangemNoteBatches.contains(card.batchId)
fun Card.isTangemNote(): Boolean = tangemNoteBatches.contains(batchId)
fun isTangemWalletBatch(card: Card): Boolean = tangemWalletBatches.contains(card.batchId)