Updated on 2026-08-14
This commit is contained in:
parent
f5cd710825
commit
d68da48f0f
69 changed files with 2452 additions and 144 deletions
|
|
@ -72,13 +72,14 @@ dependencies {
|
|||
implementation 'androidx.fragment:fragment-ktx:1.3.6'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
|
||||
implementation 'com.google.android.material:material:1.4.0'
|
||||
implementation "androidx.core:core-ktx:1.6.0"
|
||||
implementation 'com.google.android.play:core:1.10.2'
|
||||
implementation 'com.google.android.play:core-ktx:1.8.1'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||
|
||||
implementation 'com.tangem:blockchain:develop-48'
|
||||
implementation 'com.tangem.tangem-sdk-kotlin:core:develop-95'
|
||||
implementation 'com.tangem.tangem-sdk-kotlin:android:develop-95'
|
||||
implementation 'com.tangem:blockchain:develop-49'
|
||||
implementation 'com.tangem.tangem-sdk-kotlin:core:CSK-206_backup-98'
|
||||
implementation 'com.tangem.tangem-sdk-kotlin:android:CSK-206_backup-98'
|
||||
|
||||
// WebView
|
||||
implementation "androidx.browser:browser:1.3.0"
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import android.view.View
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tangem.TangemSdk
|
||||
import com.tangem.operations.backup.BackupService
|
||||
import com.tangem.tangem_sdk_new.extensions.init
|
||||
import com.tangem.tap.common.DialogManager
|
||||
import com.tangem.tap.common.IntentHandler
|
||||
|
|
@ -32,6 +33,7 @@ import kotlin.coroutines.CoroutineContext
|
|||
|
||||
lateinit var tangemSdk: TangemSdk
|
||||
lateinit var tangemSdkManager: TangemSdkManager
|
||||
lateinit var backupService: BackupService
|
||||
var notificationsHandler: NotificationsHandler? = null
|
||||
|
||||
private val coroutineContext: CoroutineContext
|
||||
|
|
@ -67,6 +69,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler {
|
|||
|
||||
tangemSdk = TangemSdk.init(this, TangemSdkManager.config)
|
||||
tangemSdkManager = TangemSdkManager(tangemSdk, this)
|
||||
backupService = BackupService.init(tangemSdk, this)
|
||||
|
||||
store.dispatch(GlobalAction.SetResources(getAndroidResources()))
|
||||
store.dispatch(WalletConnectAction.RestoreSessions)
|
||||
|
|
@ -94,7 +97,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler {
|
|||
val backStackIsEmpty = supportFragmentManager.backStackEntryCount == 0
|
||||
val isScannedBefore = store.state.globalState.scanResponse != null
|
||||
val isOnboardingServiceActive = store.state.globalState.onboardingManager != null
|
||||
if (backStackIsEmpty || (!isOnboardingServiceActive && !isScannedBefore)) {
|
||||
if (backStackIsEmpty && (!isOnboardingServiceActive && !isScannedBefore)) {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Home))
|
||||
}
|
||||
intentHandler.handleIntent(intent)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@ import com.tangem.tap.features.details.ui.walletconnect.dialogs.*
|
|||
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
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupDialog
|
||||
import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.BackupInProgressDialog
|
||||
import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.BuyMoreBackupCardsDialog
|
||||
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.ui.dialogs.ScanFailsDialog
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
|
|
@ -74,6 +79,10 @@ class DialogManager : StoreSubscriber<GlobalState> {
|
|||
TransactionDialog.create(state.dialog.dialogData, context)
|
||||
is WalletConnectDialog.PersonalSign ->
|
||||
PersonalSignDialog.create(state.dialog.data, context)
|
||||
is BackupDialog.BuyMoreBackupCards -> BuyMoreBackupCardsDialog.create(context)
|
||||
is BackupDialog.BackupInProgress -> BackupInProgressDialog.create(context)
|
||||
is BackupDialog.UnfinishedBackupFound -> UnfinishedBackupFoundDialog.create(context)
|
||||
is BackupDialog.ConfirmDiscardingBackup -> ConfirmDiscardingBackupDialog.create(context)
|
||||
else -> null
|
||||
}
|
||||
dialog?.show()
|
||||
|
|
|
|||
|
|
@ -72,9 +72,37 @@ object TangemSdk {
|
|||
is TangemSdkError.WalletCannotBeCreated -> TangemSdkError.WalletCannotBeCreated()
|
||||
is TangemSdkError.UnsupportedCurve -> TangemSdkError.UnsupportedCurve()
|
||||
is TangemSdkError.UnsupportedWalletConfig -> TangemSdkError.UnsupportedWalletConfig()
|
||||
is TangemSdkError.CryptoUtilsError -> TangemSdkError.CryptoUtilsError()
|
||||
is TangemSdkError.CryptoUtilsError -> TangemSdkError.CryptoUtilsError(error.customMessage)
|
||||
is TangemSdkError.NetworkError -> TangemSdkError.NetworkError(error.customMessage)
|
||||
is TangemSdkError.ExceptionError -> TangemSdkError.ExceptionError(error.throwable)
|
||||
is TangemSdkError.TooMuchBackupCards -> TangemSdkError.TooMuchBackupCards()
|
||||
is TangemSdkError.BackupCardRequired -> TangemSdkError.BackupCardRequired()
|
||||
is TangemSdkError.CertificateSignatureRequired -> TangemSdkError.CertificateSignatureRequired()
|
||||
is TangemSdkError.AccessCodeOrPasscodeRequired -> TangemSdkError.AccessCodeOrPasscodeRequired()
|
||||
is TangemSdkError.ResetPinNoCardsToReset -> TangemSdkError.ResetPinNoCardsToReset()
|
||||
is TangemSdkError.ResetPinWrongCard -> TangemSdkError.ResetPinWrongCard()
|
||||
is TangemSdkError.BackupFailedCardNotLinked -> TangemSdkError.BackupFailedCardNotLinked()
|
||||
is TangemSdkError.BackupNotAllowed -> TangemSdkError.BackupNotAllowed()
|
||||
is TangemSdkError.BackupCardAlreadyAdded -> TangemSdkError.BackupCardAlreadyAdded()
|
||||
is TangemSdkError.MissingPrimaryCard -> TangemSdkError.MissingPrimaryCard()
|
||||
is TangemSdkError.MissingPrimaryAttestSignature -> TangemSdkError.MissingPrimaryAttestSignature()
|
||||
is TangemSdkError.NoBackupDataForCard -> TangemSdkError.NoBackupDataForCard()
|
||||
is TangemSdkError.BackupFailedEmptyWallets -> TangemSdkError.BackupFailedEmptyWallets()
|
||||
is TangemSdkError.BackupFailedNotEmptyWallets -> TangemSdkError.BackupFailedNotEmptyWallets()
|
||||
is TangemSdkError.NoActiveBackup -> TangemSdkError.NoActiveBackup()
|
||||
is TangemSdkError.ResetBackupFailedHasBackupedWallets -> TangemSdkError.ResetBackupFailedHasBackupedWallets()
|
||||
is TangemSdkError.BackupServiceInvalidState -> TangemSdkError.BackupServiceInvalidState()
|
||||
is TangemSdkError.NoBackupCardForIndex -> TangemSdkError.NoBackupCardForIndex()
|
||||
is TangemSdkError.EmptyBackupCards -> TangemSdkError.EmptyBackupCards()
|
||||
is TangemSdkError.BackupFailedWrongIssuer -> TangemSdkError.BackupFailedWrongIssuer()
|
||||
is TangemSdkError.BackupFailedHDWalletSettings -> TangemSdkError.BackupFailedHDWalletSettings()
|
||||
is TangemSdkError.BackupFailedNotEnoughCurves -> TangemSdkError.BackupFailedNotEnoughCurves()
|
||||
is TangemSdkError.BackupFailedNotEnoughWallets -> TangemSdkError.BackupFailedNotEnoughWallets()
|
||||
is TangemSdkError.FileSettingsUnsupported -> TangemSdkError.FileSettingsUnsupported()
|
||||
is TangemSdkError.FilesIsEmpty -> TangemSdkError.FilesIsEmpty()
|
||||
is TangemSdkError.FilesDisabled -> TangemSdkError.FilesDisabled()
|
||||
is TangemSdkError.HDWalletDisabled -> TangemSdkError.HDWalletDisabled()
|
||||
is TangemSdkError.WrongInteractionMode -> TangemSdkError.WrongInteractionMode()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import com.tangem.tap.features.home.HomeFragment
|
|||
import com.tangem.tap.features.onboarding.products.note.OnboardingNoteFragment
|
||||
import com.tangem.tap.features.onboarding.products.otherCards.OnboardingOtherCardsFragment
|
||||
import com.tangem.tap.features.onboarding.products.twins.ui.TwinsCardsFragment
|
||||
import com.tangem.tap.features.onboarding.products.wallet.OnboardingWalletFragment
|
||||
import com.tangem.tap.features.onboarding.products.wallet.ui.OnboardingWalletFragment
|
||||
import com.tangem.tap.features.send.ui.SendFragment
|
||||
import com.tangem.tap.features.tokens.ui.AddTokensFragment
|
||||
import com.tangem.tap.features.wallet.ui.WalletDetailsFragment
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOt
|
|||
import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsState
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsMiddleware
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupMiddleware
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletMiddleware
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletState
|
||||
import com.tangem.tap.features.send.redux.middlewares.SendMiddleware
|
||||
|
|
@ -60,7 +61,8 @@ data class AppState(
|
|||
DetailsMiddleware().detailsMiddleware,
|
||||
DisclaimerMiddleware().disclaimerMiddleware,
|
||||
TokensMiddleware().tokensMiddleware,
|
||||
WalletConnectMiddleware().walletConnectMiddleware
|
||||
WalletConnectMiddleware().walletConnectMiddleware,
|
||||
BackupMiddleware().backupMiddleware
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ sealed class GlobalAction : Action {
|
|||
object HideDialog : GlobalAction()
|
||||
|
||||
sealed class Onboarding {
|
||||
data class Start(val scanResponse: ScanResponse) : GlobalAction()
|
||||
data class Start(val scanResponse: ScanResponse, val fromHomeScreen: Boolean = true) : GlobalAction()
|
||||
object Stop : GlobalAction()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@ import com.tangem.operations.CommandResponse
|
|||
import com.tangem.operations.pins.CheckUserCodesCommand
|
||||
import com.tangem.operations.pins.CheckUserCodesResponse
|
||||
import com.tangem.operations.pins.SetUserCodeCommand
|
||||
import com.tangem.operations.wallet.PurgeWalletCommand
|
||||
import com.tangem.tap.common.analytics.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.AnalyticsHandler
|
||||
import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler
|
||||
import com.tangem.tap.domain.tasks.CreateWalletAndRescanTask
|
||||
import com.tangem.tap.domain.tasks.product.ResetToFactorySettingsTask
|
||||
import com.tangem.tap.domain.tasks.product.ScanProductTask
|
||||
import com.tangem.tap.domain.tasks.product.ScanResponse
|
||||
import com.tangem.wallet.R
|
||||
|
|
@ -66,11 +66,11 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
|
|||
initialMessage = Message(context.getString(R.string.initial_message_create_wallet_body)))
|
||||
}
|
||||
|
||||
suspend fun eraseWallet(card: Card): CompletionResult<SuccessResponse> {
|
||||
suspend fun resetToFactorySettings(card: Card): CompletionResult<Card> {
|
||||
return runTaskAsyncReturnOnMain(
|
||||
PurgeWalletCommand(card.wallets.first().publicKey),
|
||||
ResetToFactorySettingsTask(),
|
||||
card.cardId,
|
||||
initialMessage = Message(context.getString(R.string.initial_message_purge_wallet_body)))
|
||||
initialMessage = Message(context.getString(R.string.details_row_title_reset_factory_settings)))
|
||||
}
|
||||
|
||||
suspend fun setPasscode(cardId: String?): CompletionResult<SuccessResponse> {
|
||||
|
|
|
|||
|
|
@ -29,8 +29,7 @@ object TapWorkarounds {
|
|||
}
|
||||
|
||||
fun Card.isNotSupportedInThatRelease():Boolean {
|
||||
return tangemWalletBatches.contains(batchId)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@Deprecated("Use ScanResponse.isTangemNote")
|
||||
|
|
|
|||
|
|
@ -30,7 +30,9 @@ class CreateProductWalletAndRescanTask(
|
|||
}
|
||||
CreateProductWalletTask(card, type).run(session) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> PreflightReadTask(PreflightReadMode.FullCardRead).run(session, callback)
|
||||
is CompletionResult.Success -> PreflightReadTask(PreflightReadMode.FullCardRead).run(
|
||||
session,
|
||||
callback)
|
||||
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
|
||||
}
|
||||
}
|
||||
|
|
@ -42,7 +44,10 @@ private class CreateProductWalletTask(
|
|||
private val type: ProductType,
|
||||
) : CardSessionRunnable<CreateWalletResponse> {
|
||||
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<CreateWalletResponse>) -> Unit) {
|
||||
override fun run(
|
||||
session: CardSession,
|
||||
callback: (result: CompletionResult<CreateWalletResponse>) -> Unit,
|
||||
) {
|
||||
val commandProcessor = when (type) {
|
||||
ProductType.Note -> CreateWalletTangemNote()
|
||||
ProductType.Twins -> throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet")
|
||||
|
|
@ -57,7 +62,7 @@ private class CreateWalletTangemNote : ProductCommandProcessor<CreateWalletRespo
|
|||
override fun proceed(
|
||||
card: Card,
|
||||
session: CardSession,
|
||||
callback: (result: CompletionResult<CreateWalletResponse>) -> Unit
|
||||
callback: (result: CompletionResult<CreateWalletResponse>) -> Unit,
|
||||
) {
|
||||
if (card.supportedCurves.isEmpty()) {
|
||||
callback(CompletionResult.Failure(TangemSdkError.CardError()))
|
||||
|
|
@ -89,9 +94,17 @@ private class CreateWalletTangemWallet : ProductCommandProcessor<CreateWalletRes
|
|||
override fun proceed(
|
||||
card: Card,
|
||||
session: CardSession,
|
||||
callback: (result: CompletionResult<CreateWalletResponse>) -> Unit
|
||||
callback: (result: CompletionResult<CreateWalletResponse>) -> Unit,
|
||||
) {
|
||||
//TODO:
|
||||
val supportedCurves = setOf(EllipticCurve.Secp256k1, EllipticCurve.Ed25519)
|
||||
val curves = card.getCurvesForNonCreatedWallets().intersect(supportedCurves).toList()
|
||||
CreateProductWalletsTask(curves).run(session) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success ->
|
||||
callback(CompletionResult.Success(result.data.createWalletResponses[0]))
|
||||
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -100,7 +113,7 @@ private class CreateWalletOtherCards : ProductCommandProcessor<CreateWalletRespo
|
|||
override fun proceed(
|
||||
card: Card,
|
||||
session: CardSession,
|
||||
callback: (result: CompletionResult<CreateWalletResponse>) -> Unit
|
||||
callback: (result: CompletionResult<CreateWalletResponse>) -> Unit,
|
||||
) {
|
||||
val firmwareVersion = card.firmwareVersion
|
||||
val task = if (firmwareVersion < FirmwareVersion.MultiWalletAvailable) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
package com.tangem.tap.domain.tasks.product
|
||||
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.common.core.CardSession
|
||||
import com.tangem.common.core.CardSessionRunnable
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.operations.backup.ResetBackupCommand
|
||||
import com.tangem.operations.wallet.PurgeWalletCommand
|
||||
|
||||
class ResetToFactorySettingsTask() : CardSessionRunnable<Card> {
|
||||
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<Card>) -> Unit) {
|
||||
deleteWallets(session, callback)
|
||||
}
|
||||
|
||||
private fun deleteWallets(
|
||||
session: CardSession,
|
||||
callback: (result: CompletionResult<Card>) -> Unit,
|
||||
) {
|
||||
|
||||
val wallet = session.environment.card?.wallets?.lastOrNull().guard {
|
||||
resetBackup(session, callback)
|
||||
return
|
||||
}
|
||||
|
||||
PurgeWalletCommand(wallet.publicKey).run(session) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
deleteWallets(session, callback)
|
||||
}
|
||||
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun resetBackup(
|
||||
session: CardSession,
|
||||
callback: (result: CompletionResult<Card>) -> Unit,
|
||||
) {
|
||||
|
||||
val backupStatus = session.environment.card?.backupStatus
|
||||
if (backupStatus == null && backupStatus == Card.BackupStatus.NoBackup) {
|
||||
callback(CompletionResult.Success(session.environment.card!!))
|
||||
return
|
||||
}
|
||||
|
||||
ResetBackupCommand().run(session) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
callback(CompletionResult.Success(session.environment.card!!))
|
||||
}
|
||||
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -68,7 +68,7 @@ class CurrenciesRepository(val context: Application) {
|
|||
}
|
||||
|
||||
return try {
|
||||
tokensAdapter.fromJson(json)!!.map { it.toToken() }
|
||||
tokensAdapter.fromJson(json)!!.map { it.toToken() }.distinct()
|
||||
} catch (exception: Exception) {
|
||||
try {
|
||||
obsoleteTokensAdapter.fromJson(json)!!.map { it.toToken() }
|
||||
|
|
@ -86,7 +86,7 @@ class CurrenciesRepository(val context: Application) {
|
|||
private fun loadSavedBlockchains(cardId: String): List<Blockchain> {
|
||||
return try {
|
||||
val json = context.readFileText(getFileNameForBlockchains(cardId))
|
||||
blockchainsAdapter.fromJson(json) ?: emptyList()
|
||||
blockchainsAdapter.fromJson(json)?.distinct() ?: emptyList()
|
||||
} catch (exception: Exception) {
|
||||
emptyList()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,24 +25,26 @@ sealed class DetailsAction : Action {
|
|||
object ShowDisclaimer : DetailsAction()
|
||||
data class ReCreateTwinsWallet(val number: TwinCardNumber) : DetailsAction()
|
||||
|
||||
sealed class EraseWallet : DetailsAction() {
|
||||
object Check : EraseWallet()
|
||||
object Proceed : EraseWallet() {
|
||||
object NotAllowedByCard : EraseWallet(), NotificationAction {
|
||||
sealed class ResetToFactory : DetailsAction() {
|
||||
object Check : ResetToFactory()
|
||||
object Proceed : ResetToFactory() {
|
||||
object NotAllowedByCard : ResetToFactory(), NotificationAction {
|
||||
override val messageResource = R.string.error_purge_prohibited
|
||||
}
|
||||
|
||||
object NotEmpty : EraseWallet(), NotificationAction {
|
||||
object NotEmpty : ResetToFactory(), NotificationAction {
|
||||
override val messageResource = R.string.details_notification_erase_wallet_not_possible
|
||||
}
|
||||
}
|
||||
|
||||
object Confirm : EraseWallet()
|
||||
object Cancel : EraseWallet()
|
||||
object Failure : EraseWallet()
|
||||
object Success : EraseWallet()
|
||||
object Confirm : ResetToFactory()
|
||||
object Cancel : ResetToFactory()
|
||||
object Failure : ResetToFactory()
|
||||
object Success : ResetToFactory()
|
||||
}
|
||||
|
||||
object CreateBackup : DetailsAction()
|
||||
|
||||
sealed class AppCurrencyAction : DetailsAction() {
|
||||
data class SetCurrencies(val currencies: List<FiatCurrency>) : AppCurrencyAction()
|
||||
object ChooseAppCurrency : AppCurrencyAction()
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class DetailsMiddleware {
|
|||
{ action ->
|
||||
when (action) {
|
||||
is DetailsAction.PrepareScreen -> prepareData()
|
||||
is DetailsAction.EraseWallet -> eraseWalletMiddleware.handle(action)
|
||||
is DetailsAction.ResetToFactory -> eraseWalletMiddleware.handle(action)
|
||||
is DetailsAction.AppCurrencyAction -> appCurrencyMiddleware.handle(action)
|
||||
is DetailsAction.ManageSecurity -> manageSecurityMiddleware.handle(action)
|
||||
is DetailsAction.ShowDisclaimer -> {
|
||||
|
|
@ -58,6 +58,12 @@ class DetailsMiddleware {
|
|||
}
|
||||
}
|
||||
}
|
||||
is DetailsAction.CreateBackup -> {
|
||||
store.state.detailsState.scanResponse?.let {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingWallet))
|
||||
store.dispatch(GlobalAction.Onboarding.Start(it, fromHomeScreen = false))
|
||||
}
|
||||
}
|
||||
}
|
||||
next(action)
|
||||
}
|
||||
|
|
@ -86,25 +92,25 @@ class DetailsMiddleware {
|
|||
}
|
||||
|
||||
class EraseWalletMiddleware() {
|
||||
fun handle(action: DetailsAction.EraseWallet) {
|
||||
fun handle(action: DetailsAction.ResetToFactory) {
|
||||
when (action) {
|
||||
is DetailsAction.EraseWallet.Proceed -> {
|
||||
is DetailsAction.ResetToFactory.Proceed -> {
|
||||
when (store.state.detailsState.eraseWalletState) {
|
||||
EraseWalletState.Allowed ->
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.DetailsConfirm))
|
||||
EraseWalletState.NotAllowedByCard ->
|
||||
store.dispatch(DetailsAction.EraseWallet.Proceed.NotAllowedByCard)
|
||||
store.dispatch(DetailsAction.ResetToFactory.Proceed.NotAllowedByCard)
|
||||
EraseWalletState.NotEmpty ->
|
||||
store.dispatch(DetailsAction.EraseWallet.Proceed.NotEmpty)
|
||||
store.dispatch(DetailsAction.ResetToFactory.Proceed.NotEmpty)
|
||||
}
|
||||
}
|
||||
is DetailsAction.EraseWallet.Cancel -> {
|
||||
is DetailsAction.ResetToFactory.Cancel -> {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
}
|
||||
is DetailsAction.EraseWallet.Confirm -> {
|
||||
is DetailsAction.ResetToFactory.Confirm -> {
|
||||
val card = store.state.detailsState.scanResponse?.card ?: return
|
||||
scope.launch {
|
||||
val result = tangemSdkManager.eraseWallet(card)
|
||||
val result = tangemSdkManager.resetToFactorySettings(card)
|
||||
withContext(Dispatchers.Main) {
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ private fun internalReduce(action: Action, state: AppState): DetailsState {
|
|||
is DetailsAction.PrepareScreen -> {
|
||||
handlePrepareScreen(action, detailsState)
|
||||
}
|
||||
is DetailsAction.EraseWallet -> {
|
||||
is DetailsAction.ResetToFactory -> {
|
||||
handleEraseWallet(action, detailsState)
|
||||
}
|
||||
is DetailsAction.AppCurrencyAction -> {
|
||||
|
|
@ -39,23 +39,34 @@ private fun internalReduce(action: Action, state: AppState): DetailsState {
|
|||
}
|
||||
}
|
||||
|
||||
private fun handlePrepareScreen(action: DetailsAction.PrepareScreen, state: DetailsState): DetailsState {
|
||||
private fun handlePrepareScreen(
|
||||
action: DetailsAction.PrepareScreen,
|
||||
state: DetailsState,
|
||||
): DetailsState {
|
||||
val backupIsActive = action.scanResponse.card.backupStatus?.isActive ?: false
|
||||
|
||||
return DetailsState(
|
||||
scanResponse = action.scanResponse,
|
||||
wallets = action.wallets,
|
||||
cardInfo = action.scanResponse.card.toCardInfo(),
|
||||
appCurrencyState = AppCurrencyState(action.fiatCurrencyName),
|
||||
cardTermsOfUseUrl = action.cardTou.getUrl(action.scanResponse.card)
|
||||
cardTermsOfUseUrl = action.cardTou.getUrl(action.scanResponse.card),
|
||||
createBackupAllowed = action.scanResponse.isTangemWallet() && !backupIsActive,
|
||||
)
|
||||
}
|
||||
|
||||
private fun handleEraseWallet(action: DetailsAction.EraseWallet, state: DetailsState): DetailsState {
|
||||
private fun handleEraseWallet(
|
||||
action: DetailsAction.ResetToFactory,
|
||||
state: DetailsState,
|
||||
): DetailsState {
|
||||
return when (action) {
|
||||
DetailsAction.EraseWallet.Check -> {
|
||||
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())
|
||||
(card?.isWalletDataSupported == true &&
|
||||
(!state.scanResponse.isTangemNote() && !state.scanResponse.isTangemWallet()))
|
||||
|
||||
val notEmpty = state.wallets.any {
|
||||
it.hasPendingTransactions() || it.amounts.toSendableAmounts().isNotEmpty()
|
||||
}
|
||||
|
|
@ -66,22 +77,22 @@ private fun handleEraseWallet(action: DetailsAction.EraseWallet, state: DetailsS
|
|||
}
|
||||
state.copy(eraseWalletState = eraseWalletState)
|
||||
}
|
||||
DetailsAction.EraseWallet.Proceed -> {
|
||||
DetailsAction.ResetToFactory.Proceed -> {
|
||||
if (state.eraseWalletState == EraseWalletState.Allowed) {
|
||||
state.copy(confirmScreenState = ConfirmScreenState.EraseWallet)
|
||||
} else {
|
||||
state
|
||||
}
|
||||
}
|
||||
DetailsAction.EraseWallet.Cancel -> state.copy(eraseWalletState = null)
|
||||
DetailsAction.EraseWallet.Failure -> state.copy(eraseWalletState = null)
|
||||
DetailsAction.EraseWallet.Success -> state.copy(eraseWalletState = null)
|
||||
DetailsAction.ResetToFactory.Cancel -> state.copy(eraseWalletState = null)
|
||||
DetailsAction.ResetToFactory.Failure -> state.copy(eraseWalletState = null)
|
||||
DetailsAction.ResetToFactory.Success -> state.copy(eraseWalletState = null)
|
||||
else -> state
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleAppCurrencyAction(
|
||||
action: DetailsAction.AppCurrencyAction, state: DetailsState
|
||||
action: DetailsAction.AppCurrencyAction, state: DetailsState,
|
||||
): DetailsState {
|
||||
return when (action) {
|
||||
is DetailsAction.AppCurrencyAction.SetCurrencies -> {
|
||||
|
|
@ -105,7 +116,7 @@ private fun handleAppCurrencyAction(
|
|||
}
|
||||
|
||||
private fun handleSecurityAction(
|
||||
action: DetailsAction.ManageSecurity, state: DetailsState
|
||||
action: DetailsAction.ManageSecurity, state: DetailsState,
|
||||
): DetailsState {
|
||||
return when (action) {
|
||||
is DetailsAction.ManageSecurity.SetCurrentOption -> {
|
||||
|
|
@ -123,18 +134,18 @@ private fun handleSecurityAction(
|
|||
state.copy(securityScreenState = SecurityScreenState(currentOption = securityOption))
|
||||
}
|
||||
is DetailsAction.ManageSecurity.OpenSecurity -> {
|
||||
if (state.scanResponse?.card?.isStart2Coin == true ||
|
||||
state.scanResponse?.isTangemNote() == true
|
||||
) {
|
||||
return state.copy(securityScreenState = state.securityScreenState?.copy(
|
||||
allowedOptions = EnumSet.of(SecurityOption.LongTap),
|
||||
selectedOption = state.securityScreenState.currentOption
|
||||
))
|
||||
val allowedSecurityOptions = when {
|
||||
state.scanResponse?.card?.isStart2Coin == true ||
|
||||
state.scanResponse?.isTangemNote() == true -> {
|
||||
EnumSet.of(SecurityOption.LongTap)
|
||||
}
|
||||
state.scanResponse?.isTangemWallet() == true -> {
|
||||
EnumSet.of(state.securityScreenState?.currentOption)
|
||||
}
|
||||
else -> prepareAllowedSecurityOptions(
|
||||
state.scanResponse?.card, state.securityScreenState?.currentOption
|
||||
)
|
||||
}
|
||||
|
||||
val allowedSecurityOptions = prepareAllowedSecurityOptions(
|
||||
state.scanResponse?.card, state.securityScreenState?.currentOption
|
||||
)
|
||||
state.copy(securityScreenState = state.securityScreenState?.copy(
|
||||
allowedOptions = allowedSecurityOptions,
|
||||
selectedOption = state.securityScreenState.currentOption
|
||||
|
|
@ -171,7 +182,7 @@ private fun handleSecurityAction(
|
|||
}
|
||||
|
||||
private fun prepareAllowedSecurityOptions(
|
||||
card: Card?, currentSecurityOption: SecurityOption?
|
||||
card: Card?, currentSecurityOption: SecurityOption?,
|
||||
): EnumSet<SecurityOption> {
|
||||
val prohibitDefaultPin = card?.settings?.isResettingUserCodesAllowed != true
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ data class DetailsState(
|
|||
val confirmScreenState: ConfirmScreenState? = null,
|
||||
val securityScreenState: SecurityScreenState? = null,
|
||||
val cardTermsOfUseUrl: Uri? = null,
|
||||
val createBackupAllowed: Boolean = false,
|
||||
) : StateType {
|
||||
|
||||
// if you do not delegate - the application crashes on startup,
|
||||
|
|
|
|||
|
|
@ -58,13 +58,13 @@ class DetailsConfirmFragment : Fragment(R.layout.fragment_details_confirm),
|
|||
|
||||
when (state.confirmScreenState) {
|
||||
ConfirmScreenState.EraseWallet -> {
|
||||
toolbar.title = getString(R.string.details_row_title_erase_wallet)
|
||||
tv_warning_description.text = getString(R.string.details_erase_wallet_warning)
|
||||
btn_confirm.text = getString(R.string.details_row_title_erase_wallet)
|
||||
toolbar.title = getString(R.string.details_row_title_reset_factory_settings)
|
||||
tv_warning_description.text = getString(R.string.details_row_title_reset_factory_settings_warning)
|
||||
btn_confirm.text = getString(R.string.details_row_title_reset_factory_settings)
|
||||
btn_confirm.setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||
null, null, getDrawable(R.drawable.ic_send), null
|
||||
)
|
||||
btn_confirm.setOnClickListener { store.dispatch(DetailsAction.EraseWallet.Confirm) }
|
||||
btn_confirm.setOnClickListener { store.dispatch(DetailsAction.ResetToFactory.Confirm) }
|
||||
}
|
||||
ConfirmScreenState.LongTap, ConfirmScreenState.AccessCode,
|
||||
ConfirmScreenState.PassCode -> {
|
||||
|
|
|
|||
|
|
@ -89,20 +89,24 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber<Det
|
|||
}
|
||||
|
||||
if (state.isTangemTwins) {
|
||||
tv_erase_wallet.show()
|
||||
tv_erase_wallet.text = getText(R.string.details_row_title_twins_recreate)
|
||||
tv_erase_wallet.setOnClickListener {
|
||||
tv_reset_to_factory.show()
|
||||
tv_reset_to_factory.text = getText(R.string.details_row_title_twins_recreate)
|
||||
tv_reset_to_factory.setOnClickListener {
|
||||
store.dispatch(DetailsAction.ReCreateTwinsWallet(state.twinCardsState.cardNumber!!))
|
||||
}
|
||||
} else {
|
||||
tv_erase_wallet.show()
|
||||
tv_erase_wallet.text = getText(R.string.details_row_title_erase_wallet)
|
||||
tv_erase_wallet.setOnClickListener {
|
||||
store.dispatch(DetailsAction.EraseWallet.Check)
|
||||
store.dispatch(DetailsAction.EraseWallet.Proceed)
|
||||
tv_reset_to_factory.show()
|
||||
tv_reset_to_factory.text = getText(R.string.details_row_title_reset_factory_settings)
|
||||
tv_reset_to_factory.setOnClickListener {
|
||||
store.dispatch(DetailsAction.ResetToFactory.Check)
|
||||
store.dispatch(DetailsAction.ResetToFactory.Proceed)
|
||||
}
|
||||
}
|
||||
|
||||
tv_create_backup.show(state.createBackupAllowed)
|
||||
tv_create_backup.setOnClickListener {
|
||||
store.dispatch(DetailsAction.CreateBackup)
|
||||
}
|
||||
|
||||
tv_app_currency.text = state.appCurrencyState.fiatCurrencyName
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import com.tangem.tap.domain.DELAY_SDK_DIALOG_CLOSE
|
|||
import com.tangem.tap.features.onboarding.OnboardingHelper
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction
|
||||
import com.tangem.tap.features.send.redux.states.ButtonState
|
||||
import com.tangem.tap.preferencesStorage
|
||||
import com.tangem.tap.scope
|
||||
|
|
@ -39,6 +40,7 @@ private val homeMiddleware: Middleware<AppState> = { dispatch, state ->
|
|||
store.dispatch(GlobalAction.RestoreAppCurrency)
|
||||
store.dispatch(GlobalAction.GetMoonPayStatus)
|
||||
store.dispatch(HomeAction.SetTermsOfUseState(preferencesStorage.wasDisclaimerAccepted()))
|
||||
store.dispatch(BackupAction.CheckForUnfinishedBackup)
|
||||
}
|
||||
is HomeAction.ShouldScanCardOnResume -> {
|
||||
if (action.shouldScanCard) {
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.transition.TransitionInflater
|
||||
import com.tangem.tap.features.BaseStoreFragment
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class OnboardingWalletFragment : BaseStoreFragment(R.layout.fragment_onboarding_wallet), StoreSubscriber<OnboardingWalletState> {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val inflater = TransitionInflater.from(requireContext())
|
||||
enterTransition = inflater.inflateTransition(R.transition.fade)
|
||||
exitTransition = inflater.inflateTransition(R.transition.fade)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
}
|
||||
|
||||
override fun subscribeToStore() {
|
||||
store.subscribe(this) { state ->
|
||||
state.skipRepeats { oldState, newState ->
|
||||
oldState.onboardingWalletState == newState.onboardingWalletState
|
||||
}.select { it.onboardingWalletState }
|
||||
}
|
||||
storeSubscribersList.add(this)
|
||||
}
|
||||
|
||||
override fun newState(state: OnboardingWalletState) {
|
||||
if (activity == null) return
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +1,65 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.redux
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import com.tangem.tap.features.wallet.redux.Artwork
|
||||
import org.rekotlin.Action
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
sealed class OnboardingWalletAction : Action {
|
||||
object Init : OnboardingWalletAction()
|
||||
object GetToCreateWalletStep : OnboardingWalletAction()
|
||||
object CreateWallet : OnboardingWalletAction()
|
||||
object TopUp : OnboardingWalletAction()
|
||||
object Done : OnboardingWalletAction()
|
||||
object FinishOnboarding : OnboardingWalletAction()
|
||||
|
||||
object ProceedBackup : OnboardingWalletAction()
|
||||
|
||||
sealed class Backup : Action {
|
||||
object LoadArtwork : OnboardingWalletAction()
|
||||
class SetArtworkUrl(val artwork: Artwork) : OnboardingWalletAction()
|
||||
|
||||
object OnBackPressed : OnboardingWalletAction()
|
||||
}
|
||||
|
||||
sealed class BackupAction : Action {
|
||||
|
||||
object DetermineBackupStep : BackupAction()
|
||||
object IntroduceBackup : BackupAction()
|
||||
object StartBackup : BackupAction()
|
||||
object DismissBackup : BackupAction()
|
||||
object ScanPrimaryCard : BackupAction()
|
||||
|
||||
object CheckForUnfinishedBackup : BackupAction()
|
||||
|
||||
object StartAddingBackupCards : BackupAction()
|
||||
object AddBackupCard : BackupAction() {
|
||||
object Success : BackupAction()
|
||||
}
|
||||
|
||||
data class LoadBackupCardArtwork(
|
||||
val cardId: CardId,
|
||||
val cardPublicKey: ByteArray,
|
||||
) : BackupAction() {
|
||||
data class Success(val cardId: CardId, val artwork: Bitmap)
|
||||
}
|
||||
|
||||
object GoToShop : BackupAction()
|
||||
object FinishAddingBackupCards : BackupAction()
|
||||
|
||||
object ShowAccessCodeInfoScreen : BackupAction()
|
||||
object ShowEnterAccessCodeScreen : BackupAction()
|
||||
data class CheckAccessCode(val accessCode: String) : BackupAction()
|
||||
data class SetAccessCodeError(val error: AccessCodeError?) : BackupAction()
|
||||
data class SaveFirstAccessCode(val accessCode: String) : BackupAction()
|
||||
object ShowReenterAccessCodeScreen : BackupAction()
|
||||
data class SaveAccessCodeConfirmation(val accessCodeConfirmation: String) : BackupAction()
|
||||
|
||||
data class PrepareToWriteBackupCard(val cardNumber: Int) : BackupAction()
|
||||
data class WriteBackupCard(val cardNumber: Int) : BackupAction()
|
||||
|
||||
object PrepareToWritePrimaryCard : BackupAction()
|
||||
object WritePrimaryCard: BackupAction()
|
||||
|
||||
object FinishBackup : BackupAction()
|
||||
object DiscardBackup : BackupAction()
|
||||
object ResumeBackup : BackupAction()
|
||||
|
||||
}
|
||||
|
|
@ -1,6 +1,22 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.redux
|
||||
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.operations.backup.BackupService
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.dispatchOpenUrl
|
||||
import com.tangem.tap.common.extensions.withMainContext
|
||||
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.hasWallets
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.features.home.redux.HomeMiddleware
|
||||
import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteAction
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Action
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
class OnboardingWalletMiddleware {
|
||||
|
|
@ -12,7 +28,215 @@ class OnboardingWalletMiddleware {
|
|||
private val onboardingWalletMiddleware: Middleware<AppState> = { dispatch, state ->
|
||||
{ next ->
|
||||
{ action ->
|
||||
handleWalletAction(action)
|
||||
next(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleWalletAction(action: Action) {
|
||||
if (action !is OnboardingWalletAction) return
|
||||
val globalState = store.state.globalState
|
||||
val onboardingManager = globalState.onboardingManager
|
||||
|
||||
val scanResponse = onboardingManager?.scanResponse
|
||||
val card = scanResponse?.card
|
||||
|
||||
val walletState = store.state.onboardingWalletState
|
||||
|
||||
when (action) {
|
||||
OnboardingWalletAction.Init -> {
|
||||
val action = when {
|
||||
card == null -> {
|
||||
OnboardingWalletAction.ProceedBackup
|
||||
}
|
||||
card.hasWallets() && card.backupStatus == Card.BackupStatus.NoBackup ->
|
||||
OnboardingWalletAction.ProceedBackup
|
||||
card.hasWallets() && card.backupStatus?.isActive == true ->
|
||||
BackupAction.FinishBackup
|
||||
else -> OnboardingWalletAction.GetToCreateWalletStep
|
||||
}
|
||||
store.dispatch(action)
|
||||
}
|
||||
is OnboardingNoteAction.LoadCardArtwork -> {
|
||||
// scope.launch {
|
||||
// val artwork = onboardingManager.loadArtwork()
|
||||
// store.dispatchOnMain(OnboardingWalletAction.SetArtworkUrl(artwork))
|
||||
// }
|
||||
}
|
||||
is OnboardingWalletAction.CreateWallet -> {
|
||||
scope.launch {
|
||||
scanResponse ?: return@launch
|
||||
val result = tangemSdkManager.createProductWallet(scanResponse)
|
||||
withMainContext {
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
val updatedResponse = scanResponse.copy(card = result.data)
|
||||
onboardingManager.scanResponse = updatedResponse
|
||||
onboardingManager.activationStarted(updatedResponse.card.cardId)
|
||||
store.dispatch(OnboardingWalletAction.ProceedBackup)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
OnboardingWalletAction.FinishOnboarding -> {
|
||||
store.dispatch(GlobalAction.Onboarding.Stop)
|
||||
|
||||
(listOf(walletState.backupState.primaryCardId) +
|
||||
walletState.backupState.backupCardIds + scanResponse?.card?.cardId)
|
||||
.distinct().filterNotNull()
|
||||
.forEach { cardId ->
|
||||
preferencesStorage.usedCardsPrefStorage.activationFinished(cardId)
|
||||
}
|
||||
|
||||
if (scanResponse == null) {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatch(HomeAction.ReadCard)
|
||||
} else {
|
||||
scope.launch { globalState.tapWalletManager.onCardScanned(scanResponse) }
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Wallet))
|
||||
}
|
||||
}
|
||||
OnboardingWalletAction.ProceedBackup -> {
|
||||
val newAction = when (val backupState = backupService.currentState) {
|
||||
BackupService.State.Preparing -> BackupAction.IntroduceBackup
|
||||
BackupService.State.FinalizingPrimaryCard -> BackupAction.PrepareToWritePrimaryCard
|
||||
is BackupService.State.FinalizingBackupCard ->
|
||||
BackupAction.PrepareToWriteBackupCard(backupState.index)
|
||||
BackupService.State.Finished -> BackupAction.FinishBackup
|
||||
}
|
||||
store.dispatch(newAction)
|
||||
}
|
||||
OnboardingWalletAction.OnBackPressed -> {
|
||||
if (walletState.backupState.backupStep is BackupStep.WriteBackupCard ||
|
||||
walletState.backupState.backupStep is BackupStep.WritePrimaryCard) {
|
||||
store.dispatch(GlobalAction.ShowDialog(BackupDialog.BackupInProgress))
|
||||
} else {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BackupMiddleware {
|
||||
val backupMiddleware: Middleware<AppState> = { dispatch, state ->
|
||||
{ next ->
|
||||
{ action ->
|
||||
val backupState = state()?.onboardingWalletState?.backupState
|
||||
when (action) {
|
||||
is BackupAction.StartBackup -> {
|
||||
backupService.discardSavedBackup()
|
||||
}
|
||||
is BackupAction.ScanPrimaryCard -> {
|
||||
backupService.readPrimaryCard { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
store.dispatchOnMain(BackupAction.StartAddingBackupCards)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is BackupAction.AddBackupCard -> {
|
||||
backupService.addBackupCard { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
store.dispatchOnMain(BackupAction.AddBackupCard.Success)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is BackupAction.GoToShop -> {
|
||||
store.dispatchOpenUrl(HomeMiddleware.CARD_SHOP_URI)
|
||||
}
|
||||
is BackupAction.FinishAddingBackupCards -> {
|
||||
if (backupService.addedBackupCardsCount == 1) {
|
||||
store.dispatchOnMain(GlobalAction.ShowDialog(BackupDialog.BuyMoreBackupCards))
|
||||
}
|
||||
if (backupService.addedBackupCardsCount == 2) {
|
||||
store.dispatchOnMain(BackupAction.ShowAccessCodeInfoScreen)
|
||||
}
|
||||
}
|
||||
is BackupAction.CheckAccessCode -> {
|
||||
if (action.accessCode.length < 4) {
|
||||
store.dispatch(BackupAction.SetAccessCodeError(
|
||||
AccessCodeError.CodeTooShort
|
||||
))
|
||||
} else {
|
||||
store.dispatch(BackupAction.SaveFirstAccessCode(action.accessCode))
|
||||
}
|
||||
}
|
||||
is BackupAction.SaveAccessCodeConfirmation -> {
|
||||
if (action.accessCodeConfirmation == backupState?.accessCode) {
|
||||
backupService.setAccessCode(action.accessCodeConfirmation)
|
||||
store.dispatch(BackupAction.PrepareToWritePrimaryCard)
|
||||
} else {
|
||||
store.dispatch(BackupAction.SetAccessCodeError(
|
||||
AccessCodeError.CodesDoNotMatch
|
||||
))
|
||||
}
|
||||
}
|
||||
is BackupAction.WritePrimaryCard -> {
|
||||
backupService.proceedBackup { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
store.dispatchOnMain(
|
||||
BackupAction.PrepareToWriteBackupCard(1)
|
||||
)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is BackupAction.WriteBackupCard -> {
|
||||
backupService.proceedBackup { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
if (backupService.currentState == BackupService.State.Finished) {
|
||||
store.dispatchOnMain(BackupAction.FinishBackup)
|
||||
} else {
|
||||
store.dispatchOnMain(
|
||||
BackupAction.PrepareToWriteBackupCard(action.cardNumber + 1)
|
||||
)
|
||||
}
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is BackupAction.FinishBackup -> {
|
||||
// store.dispatch(OnboardingWalletAction.Done)
|
||||
}
|
||||
is BackupAction.DiscardBackup -> {
|
||||
backupService.discardSavedBackup()
|
||||
}
|
||||
is BackupAction.CheckForUnfinishedBackup -> {
|
||||
if (backupService.hasIncompletedBackup) {
|
||||
store.dispatch(GlobalAction.ShowDialog(BackupDialog.UnfinishedBackupFound))
|
||||
}
|
||||
}
|
||||
is BackupAction.ResumeBackup -> {
|
||||
store.dispatch(OnboardingWalletAction.ProceedBackup)
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingWallet))
|
||||
}
|
||||
is BackupAction.DismissBackup -> {
|
||||
store.dispatch(BackupAction.FinishBackup)
|
||||
}
|
||||
}
|
||||
|
||||
next(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +1,126 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.redux
|
||||
|
||||
import com.tangem.tap.backupService
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import org.rekotlin.Action
|
||||
|
||||
class OnboardingWalletReducer {
|
||||
companion object {
|
||||
fun reduce(action: Action, state: AppState): OnboardingWalletState = internalReduce(action, state)
|
||||
fun reduce(action: Action, state: AppState): OnboardingWalletState =
|
||||
internalReduce(action, state)
|
||||
}
|
||||
}
|
||||
|
||||
private fun internalReduce(action: Action, appState: AppState): OnboardingWalletState {
|
||||
var state = appState.onboardingWalletState
|
||||
|
||||
when (action) {
|
||||
val state = appState.onboardingWalletState
|
||||
|
||||
return when (action) {
|
||||
is BackupAction -> state.copy(backupState = BackupReducer.reduce(action, state.backupState))
|
||||
is GlobalAction.Onboarding.Start -> OnboardingWalletState(
|
||||
backupState = state.backupState.copy(canSkipBackup = action.fromHomeScreen)
|
||||
)
|
||||
is OnboardingWalletAction.GetToCreateWalletStep ->
|
||||
OnboardingWalletState(step = OnboardingWalletStep.CreateWallet)
|
||||
is OnboardingWalletAction.ProceedBackup -> state.copy(step = OnboardingWalletStep.Backup)
|
||||
is OnboardingWalletAction.SetArtworkUrl -> {
|
||||
state.copy(artwork = action.artwork)
|
||||
}
|
||||
is OnboardingWalletAction.Done -> state.copy(step = OnboardingWalletStep.Done)
|
||||
else -> state
|
||||
}
|
||||
}
|
||||
|
||||
return state
|
||||
|
||||
class BackupReducer {
|
||||
companion object {
|
||||
fun reduce(
|
||||
action: BackupAction, state: BackupState,
|
||||
): BackupState {
|
||||
|
||||
return when (action) {
|
||||
BackupAction.IntroduceBackup -> state.copy(backupStep = BackupStep.InitBackup)
|
||||
|
||||
BackupAction.StartBackup -> state.copy(backupStep = BackupStep.ScanOriginCard)
|
||||
|
||||
BackupAction.StartAddingBackupCards -> {
|
||||
state.copy(backupStep = BackupStep.AddBackupCards)
|
||||
}
|
||||
BackupAction.AddBackupCard.Success -> {
|
||||
state.copy(backupCardsNumber = state.backupCardsNumber + 1)
|
||||
}
|
||||
BackupAction.FinishAddingBackupCards -> {
|
||||
state
|
||||
}
|
||||
BackupAction.ShowAccessCodeInfoScreen -> {
|
||||
state.copy(backupStep = BackupStep.SetAccessCode)
|
||||
}
|
||||
BackupAction.ShowEnterAccessCodeScreen -> {
|
||||
state.copy(backupStep = BackupStep.EnterAccessCode)
|
||||
}
|
||||
is BackupAction.SaveFirstAccessCode -> {
|
||||
state.copy(
|
||||
backupStep = BackupStep.ReenterAccessCode,
|
||||
accessCode = action.accessCode
|
||||
)
|
||||
}
|
||||
is BackupAction.SetAccessCodeError -> {
|
||||
state.copy(
|
||||
accessCodeError = action.error
|
||||
)
|
||||
}
|
||||
is BackupAction.PrepareToWritePrimaryCard -> {
|
||||
if (state.primaryCardId == null) {
|
||||
state.copy(
|
||||
primaryCardId = backupService.primaryCardId,
|
||||
backupCardIds = backupService.backupCardIds,
|
||||
backupCardsNumber = backupService.backupCardIds.size,
|
||||
backupStep = BackupStep.WritePrimaryCard
|
||||
)
|
||||
} else {
|
||||
state.copy(
|
||||
backupStep = BackupStep.WritePrimaryCard
|
||||
)
|
||||
}
|
||||
}
|
||||
is BackupAction.PrepareToWriteBackupCard -> {
|
||||
if (state.primaryCardId == null) {
|
||||
state.copy(
|
||||
primaryCardId = backupService.primaryCardId,
|
||||
backupCardIds = backupService.backupCardIds,
|
||||
backupCardsNumber = backupService.backupCardIds.size,
|
||||
backupStep = BackupStep.WriteBackupCard(action.cardNumber)
|
||||
)
|
||||
} else {
|
||||
state.copy(
|
||||
backupStep = BackupStep.WriteBackupCard(action.cardNumber)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is BackupAction.FinishBackup -> {
|
||||
state.copy(
|
||||
backupStep = BackupStep.Finished
|
||||
)
|
||||
}
|
||||
|
||||
BackupAction.WritePrimaryCard -> state
|
||||
is BackupAction.WriteBackupCard -> state
|
||||
is BackupAction.SaveAccessCodeConfirmation -> state
|
||||
BackupAction.ScanPrimaryCard -> state
|
||||
BackupAction.ShowEnterAccessCodeScreen -> state
|
||||
BackupAction.ShowReenterAccessCodeScreen -> state
|
||||
BackupAction.AddBackupCard -> state
|
||||
BackupAction.DismissBackup -> state
|
||||
is BackupAction.LoadBackupCardArtwork -> state
|
||||
is BackupAction.CheckAccessCode -> state
|
||||
BackupAction.GoToShop -> state
|
||||
BackupAction.DetermineBackupStep -> state
|
||||
BackupAction.CheckForUnfinishedBackup -> state
|
||||
BackupAction.DiscardBackup -> state
|
||||
BackupAction.ResumeBackup -> state
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,81 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.redux
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import com.tangem.tap.common.redux.StateDialog
|
||||
import com.tangem.tap.features.wallet.redux.Artwork
|
||||
import org.rekotlin.StateType
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
data class OnboardingWalletState(
|
||||
val any: String? = null
|
||||
) : StateType
|
||||
val step: OnboardingWalletStep = OnboardingWalletStep.None,
|
||||
val backupState: BackupState = BackupState(),
|
||||
val artwork: Artwork? = null,
|
||||
val showConfetti: Boolean = false,
|
||||
) : StateType {
|
||||
|
||||
fun getProgressStep(): Int {
|
||||
return when {
|
||||
step == OnboardingWalletStep.CreateWallet -> {
|
||||
1
|
||||
}
|
||||
step == OnboardingWalletStep.Backup -> {
|
||||
when (backupState.backupStep) {
|
||||
BackupStep.InitBackup -> 2
|
||||
BackupStep.ScanOriginCard -> 3
|
||||
|
||||
BackupStep.AddBackupCards -> 4
|
||||
BackupStep.EnterAccessCode -> 4
|
||||
BackupStep.ReenterAccessCode -> 4
|
||||
BackupStep.SetAccessCode -> 4
|
||||
BackupStep.WritePrimaryCard, is BackupStep.WriteBackupCard -> 5
|
||||
BackupStep.Finished -> 6
|
||||
}
|
||||
}
|
||||
step == OnboardingWalletStep.Done -> 6
|
||||
else -> 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class OnboardingWalletStep {
|
||||
None, CreateWallet, TopUpWallet, Backup, Done
|
||||
None, CreateWallet, Backup, Done
|
||||
}
|
||||
|
||||
data class BackupState(
|
||||
val primaryCardId: String? = null,
|
||||
val backupCardsNumber: Int = 0,
|
||||
val backupCardIds: List<CardId> = emptyList(),
|
||||
val backupCardsArtworks: Map<CardId, Bitmap> = emptyMap(),
|
||||
val accessCode: String = "",
|
||||
val accessCodeError: AccessCodeError? = null,
|
||||
val backupStep: BackupStep = BackupStep.InitBackup,
|
||||
val maxBackupCards: Int = 2,
|
||||
val canSkipBackup: Boolean = true
|
||||
)
|
||||
|
||||
enum class AccessCodeError {
|
||||
CodeTooShort, CodesDoNotMatch
|
||||
}
|
||||
|
||||
typealias CardId = String
|
||||
|
||||
sealed class BackupStep {
|
||||
object InitBackup : BackupStep()
|
||||
object ScanOriginCard : BackupStep()
|
||||
object AddBackupCards : BackupStep()
|
||||
object SetAccessCode : BackupStep()
|
||||
object EnterAccessCode : BackupStep()
|
||||
object ReenterAccessCode : BackupStep()
|
||||
object WritePrimaryCard : BackupStep()
|
||||
data class WriteBackupCard(val cardNumber: Int) : BackupStep()
|
||||
object Finished : BackupStep()
|
||||
}
|
||||
|
||||
sealed class BackupDialog: StateDialog {
|
||||
object BuyMoreBackupCards : StateDialog
|
||||
object BackupInProgress : StateDialog
|
||||
object UnfinishedBackupFound : StateDialog
|
||||
object ConfirmDiscardingBackup : StateDialog
|
||||
}
|
||||
|
|
@ -0,0 +1,234 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.ui
|
||||
|
||||
import android.animation.AnimatorSet
|
||||
import android.animation.ObjectAnimator
|
||||
import android.animation.PropertyValuesHolder
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.core.animation.doOnEnd
|
||||
import com.tangem.tap.common.leapfrogWidget.LeapView
|
||||
import com.tangem.tap.common.leapfrogWidget.LeapViewState
|
||||
import com.tangem.tap.common.leapfrogWidget.LeapfrogWidget
|
||||
|
||||
class BackupCardsWidget(
|
||||
val leapfrogWidget: LeapfrogWidget,
|
||||
val getTopOfAnchorViewForActivateState: () -> Float,
|
||||
) {
|
||||
|
||||
fun toWelcome(animate: Boolean = true, onEnd: () -> Unit = {}) {
|
||||
val animator = createAnimator(animate, onEnd)
|
||||
animator.playTogether(
|
||||
createAnimator(BackupCardType.ORIGIN, createWelcomeProperties(BackupCardType.ORIGIN)),
|
||||
createAnimator(BackupCardType.FIRST_BACKUP, createWelcomeProperties(BackupCardType.FIRST_BACKUP)),
|
||||
createAnimator(BackupCardType.SECOND_BACKUP, createWelcomeProperties(BackupCardType.SECOND_BACKUP))
|
||||
)
|
||||
leapfrogWidget.fold { animator.start() }
|
||||
}
|
||||
|
||||
fun toFolded(animate: Boolean = true, onEnd: () -> Unit = {}) {
|
||||
val animator = createAnimator(animate, onEnd)
|
||||
animator.playTogether(
|
||||
createAnimator(BackupCardType.ORIGIN, createLeapfrogProperties(BackupCardType.ORIGIN)),
|
||||
createAnimator(BackupCardType.FIRST_BACKUP, createLeapfrogProperties(BackupCardType.FIRST_BACKUP)),
|
||||
createAnimator(BackupCardType.SECOND_BACKUP, createLeapfrogProperties(BackupCardType.SECOND_BACKUP))
|
||||
)
|
||||
leapfrogWidget.fold { animator.start() }
|
||||
}
|
||||
|
||||
fun toFan(animate: Boolean = true, onEnd: () -> Unit = {}) {
|
||||
val animator = createAnimator(animate, onEnd)
|
||||
animator.playTogether(
|
||||
createAnimator(BackupCardType.ORIGIN, createFanProperties(BackupCardType.ORIGIN)),
|
||||
createAnimator(BackupCardType.FIRST_BACKUP, createFanProperties(BackupCardType.FIRST_BACKUP)),
|
||||
createAnimator(BackupCardType.SECOND_BACKUP, createFanProperties(BackupCardType.SECOND_BACKUP))
|
||||
)
|
||||
leapfrogWidget.fold { animator.start() }
|
||||
}
|
||||
|
||||
fun toLeapfrog(animate: Boolean = true, onEnd: () -> Unit = {}) {
|
||||
val animator = createAnimator(animate, onEnd)
|
||||
animator.playTogether(
|
||||
createAnimator(BackupCardType.ORIGIN, createLeapfrogProperties(BackupCardType.ORIGIN)),
|
||||
createAnimator(BackupCardType.FIRST_BACKUP, createLeapfrogProperties(BackupCardType.FIRST_BACKUP)),
|
||||
createAnimator(BackupCardType.SECOND_BACKUP, createLeapfrogProperties(BackupCardType.SECOND_BACKUP))
|
||||
)
|
||||
leapfrogWidget.fold {
|
||||
animator.doOnEnd {
|
||||
leapfrogWidget.initViews()
|
||||
leapfrogWidget.unfold()
|
||||
}
|
||||
animator.start()
|
||||
}
|
||||
}
|
||||
//
|
||||
// fun toActivate(animate: Boolean = true, onEnd: () -> Unit = {}) {
|
||||
// val animator = createAnimator(animate, onEnd)
|
||||
// animator.playTogether(
|
||||
// createAnimator(TwinCardNumber.First, createActivateProperties(TwinCardNumber.First)),
|
||||
// createAnimator(TwinCardNumber.Second, createActivateProperties(TwinCardNumber.Second))
|
||||
// )
|
||||
// animator.start()
|
||||
// }
|
||||
|
||||
private fun createAnimator(animate: Boolean, onEnd: () -> Unit): AnimatorSet {
|
||||
return AnimatorSet().apply {
|
||||
duration = if (animate) 400 else 0
|
||||
doOnEnd { onEnd() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun createAnimator(
|
||||
cardType: BackupCardType,
|
||||
properties: CardProperties,
|
||||
): ObjectAnimator {
|
||||
val view = getLeapViewByCardNumber(cardType).view
|
||||
val animator = ObjectAnimator.ofPropertyValuesHolder(view,
|
||||
*properties.createValuesHolders().toTypedArray())
|
||||
view.elevation = properties.elevation
|
||||
return animator
|
||||
}
|
||||
|
||||
private fun createWelcomeProperties(cardType: BackupCardType): CardProperties {
|
||||
return when (cardType) {
|
||||
BackupCardType.ORIGIN -> CardProperties(
|
||||
xTranslation = 440f,
|
||||
yTranslation = 0f,
|
||||
rotation = 75f,
|
||||
elevation = 2f,
|
||||
scale = .9f,
|
||||
)
|
||||
BackupCardType.FIRST_BACKUP -> CardProperties(
|
||||
xTranslation = 10f,
|
||||
yTranslation = -100f,
|
||||
rotation = 100f,
|
||||
elevation = 1f,
|
||||
scale = .9f,
|
||||
)
|
||||
BackupCardType.SECOND_BACKUP -> CardProperties(
|
||||
xTranslation = -440f,
|
||||
yTranslation = -100f,
|
||||
rotation = 70f,
|
||||
elevation = 0f,
|
||||
scale = .9f,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createFanProperties(cardType: BackupCardType): CardProperties {
|
||||
return when (cardType) {
|
||||
BackupCardType.ORIGIN -> CardProperties(
|
||||
xTranslation = 0f,
|
||||
yTranslation = 0f,
|
||||
rotation = 5f,
|
||||
elevation = 2f,
|
||||
scale = 1f,
|
||||
)
|
||||
BackupCardType.FIRST_BACKUP -> CardProperties(
|
||||
xTranslation = 0f,
|
||||
yTranslation = -80f,
|
||||
rotation = -5f,
|
||||
elevation = 1f,
|
||||
scale = 0.9f,
|
||||
)
|
||||
BackupCardType.SECOND_BACKUP -> CardProperties(
|
||||
xTranslation = 10f,
|
||||
yTranslation = -170f,
|
||||
rotation = -20f,
|
||||
elevation = 0f,
|
||||
scale = 0.8f,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createLeapfrogProperties(cardType: BackupCardType): CardProperties {
|
||||
return when (cardType) {
|
||||
BackupCardType.ORIGIN -> CardProperties(
|
||||
xTranslation = 0f,
|
||||
yTranslation = 0f,
|
||||
rotation = 0f,
|
||||
elevation = 2f,
|
||||
scale = 1f,
|
||||
)
|
||||
BackupCardType.FIRST_BACKUP -> CardProperties(
|
||||
xTranslation = 0f,
|
||||
yTranslation = 0f,
|
||||
rotation = 0f,
|
||||
elevation = 1f,
|
||||
scale = 0.9f,
|
||||
)
|
||||
BackupCardType.SECOND_BACKUP -> CardProperties(
|
||||
xTranslation = 0f,
|
||||
yTranslation = 0f,
|
||||
rotation = 0f,
|
||||
elevation = 0f,
|
||||
scale = 0.8f,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createActivateProperties(cardType: BackupCardType): CardProperties {
|
||||
val topOfAnchorView = getTopOfAnchorViewForActivateState()
|
||||
val twinProperties = CardProperties.from(getLeapViewByCardNumber(cardType).state)
|
||||
return twinProperties.copy(
|
||||
xTranslation = twinProperties.xTranslation,
|
||||
yTranslation = twinProperties.yTranslation - topOfAnchorView,
|
||||
rotation = 0f,
|
||||
scale = twinProperties.scale - 0.4f,
|
||||
)
|
||||
}
|
||||
|
||||
private fun getLeapViewByCardNumber(cardType: BackupCardType): LeapView {
|
||||
return when (cardType) {
|
||||
BackupCardType.ORIGIN -> leapfrogWidget.getViewByPosition(0)
|
||||
BackupCardType.FIRST_BACKUP -> leapfrogWidget.getViewByPosition(1)
|
||||
BackupCardType.SECOND_BACKUP -> leapfrogWidget.getViewByPosition(2)
|
||||
}
|
||||
}
|
||||
|
||||
fun getOriginCardView(): ImageView {
|
||||
return getLeapViewByCardNumber(BackupCardType.ORIGIN).view as ImageView
|
||||
}
|
||||
|
||||
fun getFirstBackupCardView(): ImageView {
|
||||
return getLeapViewByCardNumber(BackupCardType.FIRST_BACKUP).view as ImageView
|
||||
}
|
||||
|
||||
fun getSecondBackupCardView(): ImageView {
|
||||
return getLeapViewByCardNumber(BackupCardType.SECOND_BACKUP).view as ImageView
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum class BackupCardType { ORIGIN, FIRST_BACKUP, SECOND_BACKUP }
|
||||
|
||||
|
||||
private data class CardProperties(
|
||||
val xTranslation: Float = 0f,
|
||||
val yTranslation: Float = 0f,
|
||||
val rotation: Float = 0f,
|
||||
val elevation: Float = 0f,
|
||||
val scale: Float = 1.1f,
|
||||
) {
|
||||
|
||||
fun createValuesHolders(): List<PropertyValuesHolder> {
|
||||
return listOf(
|
||||
PropertyValuesHolder.ofFloat(View.TRANSLATION_X, xTranslation),
|
||||
PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, yTranslation),
|
||||
PropertyValuesHolder.ofFloat(View.ROTATION, rotation),
|
||||
PropertyValuesHolder.ofFloat(View.SCALE_X, scale),
|
||||
PropertyValuesHolder.ofFloat(View.SCALE_Y, scale),
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun from(leapViewState: LeapViewState): CardProperties {
|
||||
val leapViewProperties = leapViewState.properties
|
||||
|
||||
return CardProperties(
|
||||
yTranslation = leapViewProperties.yTranslation,
|
||||
elevation = leapViewProperties.elevationEnd,
|
||||
scale = leapViewProperties.scale,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.ui
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.tangem.tap.common.extensions.getString
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.item_backup_info_adapter.view.*
|
||||
|
||||
class BackupInfoAdapter : RecyclerView.Adapter<BackupInfoViewHolder>() {
|
||||
|
||||
private val data = backupInfoSnippets
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BackupInfoViewHolder =
|
||||
BackupInfoViewHolder(LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_backup_info_adapter, parent, false))
|
||||
|
||||
override fun getItemCount(): Int = data.size
|
||||
|
||||
override fun onBindViewHolder(holder: BackupInfoViewHolder, position: Int) =
|
||||
holder.itemView.run {
|
||||
tv_header.text = getString(data[position].header)
|
||||
tv_body.text = getString(data[position].body)
|
||||
}
|
||||
}
|
||||
|
||||
private class BackupInfo(
|
||||
@StringRes val header: Int,
|
||||
@StringRes val body: Int,
|
||||
)
|
||||
|
||||
private val backupInfoSnippets = listOf(
|
||||
BackupInfo(
|
||||
R.string.onboarding_wallet_info_title_first,
|
||||
R.string.onboarding_wallet_info_subtitle_first
|
||||
),
|
||||
BackupInfo(
|
||||
R.string.onboarding_wallet_info_title_second,
|
||||
R.string.onboarding_wallet_info_subtitle_second
|
||||
),
|
||||
BackupInfo(
|
||||
R.string.onboarding_wallet_info_title_third,
|
||||
R.string.onboarding_wallet_info_subtitle_third
|
||||
),
|
||||
BackupInfo(
|
||||
R.string.onboarding_wallet_info_title_fourth,
|
||||
R.string.onboarding_wallet_info_subtitle_fourth
|
||||
),
|
||||
|
||||
)
|
||||
|
||||
class BackupInfoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
|
||||
|
|
@ -0,0 +1,384 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.*
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.transition.TransitionInflater
|
||||
import androidx.transition.TransitionManager
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import com.tangem.common.CardIdFormatter
|
||||
import com.tangem.common.core.CardIdDisplayFormat
|
||||
import com.tangem.tap.common.extensions.addOnBackPressedDispatcher
|
||||
import com.tangem.tap.common.extensions.dispatchOpenUrl
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.leapfrogWidget.LeapfrogWidget
|
||||
import com.tangem.tap.common.postUi
|
||||
import com.tangem.tap.features.home.redux.HomeMiddleware
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.*
|
||||
import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.AccessCodeDialog
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_onboarding_wallet.*
|
||||
import kotlinx.android.synthetic.main.fragment_onboarding_wallet.toolbar
|
||||
import kotlinx.android.synthetic.main.fragment_wallet_details.*
|
||||
import kotlinx.android.synthetic.main.layout_onboarding_buttons_add_cards.*
|
||||
import kotlinx.android.synthetic.main.layout_onboarding_buttons_common.*
|
||||
import kotlinx.android.synthetic.main.view_confetti.*
|
||||
import kotlinx.android.synthetic.main.view_onboarding_progress.*
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
||||
StoreSubscriber<OnboardingWalletState> {
|
||||
|
||||
private var accessCodeDialog: AccessCodeDialog? = null
|
||||
private lateinit var cardsWidget: BackupCardsWidget
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
postponeEnterTransition()
|
||||
setHasOptionsMenu(true)
|
||||
|
||||
|
||||
activity?.addOnBackPressedDispatcher {
|
||||
store.dispatch(OnboardingWalletAction.OnBackPressed)
|
||||
}
|
||||
|
||||
val inflater = TransitionInflater.from(requireContext())
|
||||
enterTransition = inflater.inflateTransition(R.transition.fade)
|
||||
exitTransition = inflater.inflateTransition(R.transition.fade)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val leapfrog = LeapfrogWidget(fl_cards_container)
|
||||
cardsWidget = BackupCardsWidget(leapfrog) { 200f }
|
||||
startPostponedEnterTransition()
|
||||
|
||||
view_pager_backup_info.adapter = BackupInfoAdapter()
|
||||
TabLayoutMediator(tab_layout_backup_info, view_pager_backup_info) { tab, position ->
|
||||
//Some implementation
|
||||
}.attach()
|
||||
|
||||
(activity as? AppCompatActivity)?.setSupportActionBar(toolbar)
|
||||
|
||||
store.dispatch(OnboardingWalletAction.Init)
|
||||
toolbar.setNavigationOnClickListener { activity?.onBackPressed() }
|
||||
|
||||
// store.dispatch(OnboardingWalletAction.LoadArtwork)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
store.subscribe(this) { state ->
|
||||
state.skipRepeats { oldState, newState ->
|
||||
oldState.onboardingWalletState == newState.onboardingWalletState
|
||||
}.select { it.onboardingWalletState }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
store.unsubscribe(this)
|
||||
}
|
||||
|
||||
override fun newState(state: OnboardingWalletState) {
|
||||
if (activity == null) return
|
||||
|
||||
requireActivity().invalidateOptionsMenu()
|
||||
|
||||
state.artwork?.artwork?.let { imv_front_card.setImageBitmap(it) }
|
||||
pb_state.max = 6
|
||||
pb_state.progress = state.getProgressStep()
|
||||
|
||||
when (state.step) {
|
||||
OnboardingWalletStep.None -> {
|
||||
}
|
||||
OnboardingWalletStep.CreateWallet -> setupCreateWalletState()
|
||||
OnboardingWalletStep.Backup -> setBackupState(state.backupState)
|
||||
OnboardingWalletStep.Done -> {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupCreateWalletState() {
|
||||
btn_main_action.setText(R.string.onboarding_create_wallet_button_create_wallet)
|
||||
btn_main_action.setOnClickListener { store.dispatch(OnboardingWalletAction.CreateWallet) }
|
||||
btn_alternative_action.hide()
|
||||
|
||||
toolbar.title = getText(R.string.onboarding_getting_started)
|
||||
|
||||
tv_header.setText(R.string.onboarding_create_wallet_header)
|
||||
tv_body.setText(R.string.onboarding_create_wallet_body)
|
||||
|
||||
cardsWidget.toFolded()
|
||||
startPostponedEnterTransition()
|
||||
}
|
||||
|
||||
|
||||
private fun setBackupState(state: BackupState) {
|
||||
when (state.backupStep) {
|
||||
BackupStep.InitBackup -> showBackupIntro(state)
|
||||
BackupStep.ScanOriginCard -> showScanOriginCard(state)
|
||||
BackupStep.AddBackupCards -> showAddBackupCards(state)
|
||||
BackupStep.SetAccessCode -> showSetAccessCode()
|
||||
BackupStep.EnterAccessCode -> showEnterAccessCode(state)
|
||||
BackupStep.ReenterAccessCode -> showReenterAccessCode(state)
|
||||
is BackupStep.WritePrimaryCard -> showWritePrimaryCard(state)
|
||||
is BackupStep.WriteBackupCard -> showWriteBackupCard(state)
|
||||
BackupStep.Finished -> showSuccess(state)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showBackupIntro(state: BackupState) {
|
||||
imv_first_backup_card.show()
|
||||
imv_second_backup_card.show()
|
||||
|
||||
cardsWidget.toWelcome()
|
||||
|
||||
tv_header.hide()
|
||||
tv_body.hide()
|
||||
view_pager_backup_info.show()
|
||||
tab_layout_backup_info.show()
|
||||
|
||||
btn_main_action.text = getText(R.string.onboarding_button_backup_now)
|
||||
btn_alternative_action.text = getText(R.string.onboarding_button_skip_backup)
|
||||
btn_alternative_action.show(state.canSkipBackup)
|
||||
btn_main_action.setOnClickListener { store.dispatch(BackupAction.StartBackup) }
|
||||
btn_alternative_action.setOnClickListener { store.dispatch(BackupAction.DismissBackup) }
|
||||
startPostponedEnterTransition()
|
||||
}
|
||||
|
||||
private fun showScanOriginCard(state: BackupState) {
|
||||
|
||||
toolbar.title = getText(R.string.onboarding_navbar_title_creating_backup)
|
||||
|
||||
cardsWidget.toFolded()
|
||||
|
||||
tv_header.show()
|
||||
tv_body.show()
|
||||
view_pager_backup_info.hide()
|
||||
tab_layout_backup_info.hide()
|
||||
|
||||
imv_first_backup_card.show()
|
||||
imv_second_backup_card.show()
|
||||
|
||||
tv_header.text = getText(R.string.onboarding_title_scan_origin_card)
|
||||
tv_body.text = getString(
|
||||
R.string.onboarding_subtitle_scan_origin_card,
|
||||
)
|
||||
|
||||
btn_main_action.text = getString(R.string.onboarding_button_scan_origin_card)
|
||||
btn_alternative_action.hide()
|
||||
btn_main_action.setOnClickListener { store.dispatch(BackupAction.ScanPrimaryCard) }
|
||||
}
|
||||
|
||||
private fun showAddBackupCards(state: BackupState) {
|
||||
imv_first_backup_card.show()
|
||||
imv_second_backup_card.show()
|
||||
|
||||
layout_buttons_add_cards.show()
|
||||
layout_buttons_common.hide()
|
||||
if (state.backupCardsNumber < state.maxBackupCards) {
|
||||
btn_add_card.text = getText(R.string.onboarding_button_add_backup_card)
|
||||
btn_add_card.setOnClickListener { store.dispatch(BackupAction.AddBackupCard) }
|
||||
} else {
|
||||
btn_add_card.text = "You hit the maximum"
|
||||
btn_add_card.isEnabled = false
|
||||
}
|
||||
|
||||
when (state.backupCardsNumber) {
|
||||
0 -> {
|
||||
cardsWidget.toFan()
|
||||
tv_header.text = getText(R.string.onboarding_title_no_backup_cards)
|
||||
tv_body.text = getText(R.string.onboarding_subtitle_no_backup_cards)
|
||||
cardsWidget.getFirstBackupCardView().alpha = 0.6f
|
||||
cardsWidget.getSecondBackupCardView().alpha = 0.2f
|
||||
}
|
||||
1 -> {
|
||||
tv_header.text = getText(R.string.onboarding_title_one_backup_card)
|
||||
tv_body.text = getText(R.string.onboarding_subtitle_one_backup_card)
|
||||
|
||||
cardsWidget.getFirstBackupCardView().animate().alpha(1f).setDuration(400)
|
||||
cardsWidget.getSecondBackupCardView().alpha = 0.2f
|
||||
}
|
||||
2 -> {
|
||||
tv_header.text = getText(R.string.onboarding_title_two_backup_cards)
|
||||
tv_body.text = getText(R.string.onboarding_subtitle_two_backup_cards)
|
||||
cardsWidget.getFirstBackupCardView().alpha = 1f
|
||||
cardsWidget.getSecondBackupCardView().animate().alpha(1f).setDuration(400)
|
||||
}
|
||||
}
|
||||
|
||||
btn_continue.text = getText(R.string.onboarding_button_finalize_backup)
|
||||
btn_continue.setOnClickListener { store.dispatch(BackupAction.FinishAddingBackupCards) }
|
||||
btn_continue.isEnabled = state.backupCardsNumber != 0
|
||||
}
|
||||
|
||||
private fun showSetAccessCode() {
|
||||
accessCodeDialog = AccessCodeDialog(requireContext()).apply {
|
||||
dismissWithAnimation = true
|
||||
create()
|
||||
setOnCancelListener {
|
||||
|
||||
}
|
||||
show()
|
||||
showInfoScreen()
|
||||
val view =
|
||||
delegate.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
|
||||
(view?.parent as? ViewGroup)?.let { TransitionManager.beginDelayedTransition(it) }
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
|
||||
view?.let { it.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT }
|
||||
}
|
||||
}
|
||||
|
||||
private fun showEnterAccessCode(state: BackupState) {
|
||||
accessCodeDialog?.showEnterAccessCode()
|
||||
accessCodeDialog?.showError(state.accessCodeError)
|
||||
postUi(2000) { store.dispatch(BackupAction.SetAccessCodeError(null)) }
|
||||
|
||||
}
|
||||
|
||||
private fun showReenterAccessCode(state: BackupState) {
|
||||
accessCodeDialog?.showReenterAccessCode()
|
||||
accessCodeDialog?.showError(state.accessCodeError)
|
||||
postUi(2000) { store.dispatch(BackupAction.SetAccessCodeError(null)) }
|
||||
|
||||
}
|
||||
|
||||
private fun showWritePrimaryCard(state: BackupState) {
|
||||
accessCodeDialog?.dismiss()
|
||||
|
||||
prepareViewForFinalizeStep()
|
||||
cardsWidget.getSecondBackupCardView().show(state.backupCardsNumber == 2)
|
||||
|
||||
cardsWidget.toLeapfrog() {
|
||||
cardsWidget.getFirstBackupCardView().alpha = 0.6f
|
||||
cardsWidget.getSecondBackupCardView().alpha = 0.2f
|
||||
}
|
||||
|
||||
val cardIdFormatter = CardIdFormatter(CardIdDisplayFormat.LastMasked(4))
|
||||
tv_header.text = getText(R.string.onboarding_title_prepare_origin)
|
||||
tv_body.text = getString(
|
||||
R.string.onboarding_subtitle_scan_primary_card_format,
|
||||
state.primaryCardId?.let { cardIdFormatter.getFormattedCardId(it) }
|
||||
)
|
||||
btn_main_action.text = getText(R.string.onboarding_button_backup_origin)
|
||||
btn_main_action.setOnClickListener { store.dispatch(BackupAction.WritePrimaryCard) }
|
||||
|
||||
}
|
||||
|
||||
private fun prepareViewForFinalizeStep() {
|
||||
layout_buttons_add_cards.hide()
|
||||
layout_buttons_common.show()
|
||||
|
||||
imv_first_backup_card.show()
|
||||
imv_second_backup_card.show()
|
||||
|
||||
toolbar.title = getText(R.string.onboarding_button_finalize_backup)
|
||||
|
||||
imv_card_background.hide()
|
||||
|
||||
cardsWidget.toLeapfrog()
|
||||
|
||||
// imv_front_card.alpha = 1f
|
||||
// imv_first_backup_card.alpha = 1f
|
||||
// imv_second_backup_card.alpha = 1f
|
||||
|
||||
btn_alternative_action.hide()
|
||||
}
|
||||
|
||||
private fun showWriteBackupCard(state: BackupState) {
|
||||
prepareViewForFinalizeStep()
|
||||
|
||||
cardsWidget.getSecondBackupCardView().show(state.backupCardsNumber == 2)
|
||||
|
||||
val cardNumber = (state.backupStep as? BackupStep.WriteBackupCard)?.cardNumber ?: 1
|
||||
when (cardNumber) {
|
||||
1 -> cardsWidget.leapfrogWidget.leap() {
|
||||
cardsWidget.getOriginCardView().alpha = 0.4f
|
||||
cardsWidget.getFirstBackupCardView().alpha = 0.2f
|
||||
cardsWidget.getSecondBackupCardView().alpha = 1f
|
||||
}
|
||||
2 -> cardsWidget.leapfrogWidget.leap() {
|
||||
cardsWidget.getOriginCardView().alpha = 0.4f
|
||||
cardsWidget.getFirstBackupCardView().alpha = 0.2f
|
||||
cardsWidget.getSecondBackupCardView().alpha = 1f
|
||||
}
|
||||
}
|
||||
|
||||
val cardIdFormatter = CardIdFormatter(CardIdDisplayFormat.LastMasked(4))
|
||||
tv_header.text =
|
||||
getString(R.string.onboarding_title_backup_card_format, cardNumber)
|
||||
tv_body.text = getString(
|
||||
R.string.onboarding_subtitle_scan_primary_card_format,
|
||||
cardIdFormatter.getFormattedCardId(state.backupCardIds[cardNumber - 1])
|
||||
)
|
||||
btn_main_action.text = getString(
|
||||
R.string.onboarding_button_backup_card_format,
|
||||
cardNumber
|
||||
)
|
||||
|
||||
btn_main_action.setOnClickListener { store.dispatch(BackupAction.WriteBackupCard(cardNumber)) }
|
||||
}
|
||||
|
||||
private fun showSuccess(state: BackupState) {
|
||||
tv_header.text = getText(R.string.onboarding_done_header)
|
||||
val text = when (state.backupCardsNumber) {
|
||||
1 -> getText(R.string.onboarding_subtitle_success_backup_one_card)
|
||||
2 -> getText(R.string.onboarding_subtitle_success_backup)
|
||||
else -> getText(R.string.onboarding_subtitle_success_tangem_wallet_onboarding)
|
||||
}
|
||||
|
||||
tv_header.show()
|
||||
tv_body.show()
|
||||
view_pager_backup_info.hide()
|
||||
tab_layout_backup_info.hide()
|
||||
|
||||
tv_body.text = text
|
||||
btn_main_action.text = getText(R.string.common_continue)
|
||||
btn_alternative_action.hide()
|
||||
btn_main_action.setOnClickListener {
|
||||
lav_confetti.cancelAnimation()
|
||||
lav_confetti.hide()
|
||||
store.dispatch(OnboardingWalletAction.FinishOnboarding)
|
||||
}
|
||||
|
||||
cardsWidget.leapfrogWidget.fold {
|
||||
fl_cards_container?.hide()
|
||||
imv_card_background?.hide()
|
||||
lav_confetti?.show()
|
||||
lav_confetti?.playAnimation()
|
||||
imv_success?.alpha = 0f
|
||||
imv_success?.show()
|
||||
|
||||
imv_success?.animate()
|
||||
?.alpha(1f)
|
||||
?.setDuration(400)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.shop_menu -> {
|
||||
store.dispatchOpenUrl(HomeMiddleware.CARD_SHOP_URI)
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.shop, menu)
|
||||
|
||||
val backupStep = store.state.onboardingWalletState.backupState.backupStep
|
||||
val shopMenuShouldBeVisible =
|
||||
backupStep == BackupStep.ScanOriginCard || backupStep == BackupStep.AddBackupCards
|
||||
menu.getItem(0).isVisible = shopMenuShouldBeVisible
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.ui.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.AccessCodeError
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.layout_backup_access_code.*
|
||||
import kotlinx.android.synthetic.main.layout_backup_access_code_info.*
|
||||
import kotlinx.android.synthetic.main.layout_backup_access_code_submit.*
|
||||
|
||||
class AccessCodeDialog(context: Context) : BottomSheetDialog(context) {
|
||||
|
||||
|
||||
init {
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
val dialogView = LayoutInflater.from(context).inflate(R.layout.layout_backup_access_code, null)
|
||||
setContentView(dialogView)
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
|
||||
override fun setContentView(view: View) {
|
||||
super.setContentView(view)
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
|
||||
|
||||
fun showInfoScreen() {
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
layout_backup_access_code_info.show()
|
||||
layout_backup_access_code_submit.hide()
|
||||
btn_access_code_create.setOnClickListener {
|
||||
store.dispatch(BackupAction.ShowEnterAccessCodeScreen)
|
||||
}
|
||||
}
|
||||
|
||||
fun showEnterAccessCode() {
|
||||
layout_backup_access_code_info.hide()
|
||||
layout_backup_access_code_submit.show()
|
||||
btn_access_code_submit.text = context.getText(R.string.common_continue)
|
||||
btn_access_code_submit.setOnClickListener {
|
||||
store.dispatch(BackupAction.CheckAccessCode(et_access_code.text.toString()))
|
||||
}
|
||||
}
|
||||
|
||||
fun showReenterAccessCode() {
|
||||
layout_backup_access_code_info.hide()
|
||||
layout_backup_access_code_submit.show()
|
||||
et_access_code.setText("")
|
||||
btn_access_code_submit.text = context.getText(R.string.common_submit)
|
||||
btn_access_code_submit.setOnClickListener {
|
||||
store.dispatch(BackupAction.SaveAccessCodeConfirmation(et_access_code.text.toString()))
|
||||
}
|
||||
}
|
||||
|
||||
fun showError(error: AccessCodeError?) {
|
||||
when (error) {
|
||||
AccessCodeError.CodeTooShort ->
|
||||
til_access_code.error = context.getString(R.string.onboarding_access_code_too_short)
|
||||
AccessCodeError.CodesDoNotMatch ->
|
||||
til_access_code.error = context.getString(R.string.onboarding_access_codes_doesnt_match)
|
||||
null -> til_access_code.error = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.ui.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
|
||||
class BackupInProgressDialog {
|
||||
companion object {
|
||||
fun create(context: Context): AlertDialog {
|
||||
return AlertDialog.Builder(context).apply {
|
||||
setTitle(R.string.alert_title)
|
||||
setMessage(R.string.onboarding_backup_exit_warning)
|
||||
setPositiveButton(R.string.warning_button_ok) { _, _ ->
|
||||
store.dispatch(GlobalAction.HideDialog)
|
||||
}
|
||||
setOnDismissListener {
|
||||
store.dispatch(GlobalAction.HideDialog)
|
||||
}
|
||||
}.create()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.ui.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
|
||||
class BuyMoreBackupCardsDialog {
|
||||
companion object {
|
||||
fun create(context: Context): AlertDialog {
|
||||
return AlertDialog.Builder(context).apply {
|
||||
setTitle(R.string.alert_title)
|
||||
setMessage(R.string.onboarding_alert_message_not_max_backup_cards_added)
|
||||
setPositiveButton(R.string.common_continue) { _, _ ->
|
||||
store.dispatch(BackupAction.ShowAccessCodeInfoScreen)
|
||||
}
|
||||
setNegativeButton(R.string.onboarding_button_buy_more_cards) { _, _ ->
|
||||
store.dispatch(BackupAction.GoToShop)
|
||||
}
|
||||
setOnDismissListener {
|
||||
store.dispatch(GlobalAction.HideDialog)
|
||||
}
|
||||
}.create()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.ui.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
|
||||
class ConfirmDiscardingBackupDialog {
|
||||
companion object {
|
||||
fun create(context: Context): AlertDialog {
|
||||
return AlertDialog.Builder(context).apply {
|
||||
setTitle(R.string.welcome_interrupted_backup_discard_title)
|
||||
setMessage(R.string.welcome_interrupted_backup_discard_message)
|
||||
setPositiveButton(R.string.welcome_interrupted_backup_discard_resume) { _, _ ->
|
||||
store.dispatch(BackupAction.ResumeBackup)
|
||||
}
|
||||
setNegativeButton(R.string.welcome_interrupted_backup_discard_discard) { _, _ ->
|
||||
store.dispatch(BackupAction.DiscardBackup)
|
||||
}
|
||||
setOnDismissListener {
|
||||
store.dispatch(GlobalAction.HideDialog)
|
||||
}
|
||||
setCancelable(false)
|
||||
}.create()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.ui.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupDialog
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
|
||||
class UnfinishedBackupFoundDialog {
|
||||
companion object {
|
||||
fun create(context: Context): AlertDialog {
|
||||
return AlertDialog.Builder(context).apply {
|
||||
setTitle(R.string.alert_title)
|
||||
setMessage(R.string.welcome_interrupted_backup_alert_message)
|
||||
setPositiveButton(R.string.welcome_interrupted_backup_alert_resume) { _, _ ->
|
||||
store.dispatch(GlobalAction.HideDialog)
|
||||
store.dispatch(BackupAction.ResumeBackup)
|
||||
}
|
||||
setNegativeButton(R.string.welcome_interrupted_backup_alert_discard) { _, _ ->
|
||||
store.dispatch(GlobalAction.HideDialog)
|
||||
store.dispatch(GlobalAction.ShowDialog(BackupDialog.ConfirmDiscardingBackup))
|
||||
}
|
||||
setCancelable(false)
|
||||
}.create()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.tap.features.onboarding.service
|
||||
|
||||
//class OnboardingWalletService(
|
||||
// override val fromScreen: AppScreen,
|
||||
// override var scanResponse: ScanResponse,
|
||||
// cardInfoStorage: UsedCardsPrefStorage,
|
||||
// walletManagerFactory: WalletManagerFactory,
|
||||
//) : ProductOnboardingService(cardInfoStorage, walletManagerFactory) {
|
||||
//
|
||||
// override fun navigateToScreen(): AppScreen {
|
||||
// return AppScreen.OnboardingWallet
|
||||
// }
|
||||
//}
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.features.wallet.ui.wallet
|
|||
|
||||
import android.app.Dialog
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.redux.StateDialog
|
||||
|
|
@ -49,8 +50,22 @@ class MultiWalletView : WalletView {
|
|||
btn_scan_multiwallet?.show()
|
||||
rv_multiwallet.show()
|
||||
btn_add_token.show()
|
||||
setupWalletCardNumber(fragment)
|
||||
}
|
||||
|
||||
private fun setupWalletCardNumber(fragment: WalletFragment) = with(fragment) {
|
||||
val card = store.state.globalState.scanResponse?.card
|
||||
if (card?.backupStatus?.isActive == true) {
|
||||
val cardCount = (card.backupStatus as Card.BackupStatus.Active).cardCount + 1
|
||||
tv_twin_card_number.show()
|
||||
tv_twin_card_number.text =
|
||||
getString(R.string.wallet_twins_chip_format, 1, cardCount)
|
||||
} else {
|
||||
tv_twin_card_number.hide()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun setupButtons(fragment: WalletFragment) = with(fragment) {
|
||||
btn_scan_multiwallet?.setOnClickListener { store.dispatch(WalletAction.Scan) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,11 +96,11 @@ class SingleWalletView : WalletView {
|
|||
twinCardsState?.cardNumber?.let { cardNumber ->
|
||||
tv_twin_card_number.show()
|
||||
val number = when (cardNumber) {
|
||||
TwinCardNumber.First -> "1"
|
||||
TwinCardNumber.Second -> "2"
|
||||
TwinCardNumber.First -> 1
|
||||
TwinCardNumber.Second -> 2
|
||||
}
|
||||
tv_twin_card_number.text =
|
||||
this.getString(R.string.wallet_twins_chip_format, number)
|
||||
this.getString(R.string.wallet_twins_chip_format, number, 2)
|
||||
}
|
||||
if (twinCardsState?.cardNumber == null) {
|
||||
tv_twin_card_number.hide()
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class UsedCardsPrefStorage(
|
|||
}
|
||||
|
||||
fun activationIsStarted(cardId: String): Boolean {
|
||||
return findCardInfo(cardId)?.isActivationStarted ?: false
|
||||
return findCardInfo(cardId)?.isActivationStarted ?: true
|
||||
}
|
||||
|
||||
fun activationFinished(cardId: String) {
|
||||
|
|
|
|||
5
app/src/main/res/color/selector_btn_gray_text_color.xml
Normal file
5
app/src/main/res/color/selector_btn_gray_text_color.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="#ABABAB" android:state_enabled="false" />
|
||||
<item android:color="#060606" />
|
||||
</selector>
|
||||
7
app/src/main/res/color/selector_edit_text.xml
Normal file
7
app/src/main/res/color/selector_edit_text.xml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="#1ACE80" android:state_focused="true"/>
|
||||
<item android:color="#1ACE80" android:state_hovered="true"/>
|
||||
<item android:color="#E0E0E0" android:state_enabled="false"/>
|
||||
<item android:color="#E0E0E0"/> <!-- unfocused -->
|
||||
</selector>
|
||||
BIN
app/src/main/res/drawable-hdpi/card_placeholder_new.png
Normal file
BIN
app/src/main/res/drawable-hdpi/card_placeholder_new.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 119 KiB |
BIN
app/src/main/res/drawable-ldpi/card_placeholder_new.png
Normal file
BIN
app/src/main/res/drawable-ldpi/card_placeholder_new.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
BIN
app/src/main/res/drawable-mdpi/card_placeholder_new.png
Normal file
BIN
app/src/main/res/drawable-mdpi/card_placeholder_new.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
BIN
app/src/main/res/drawable-xhdpi/card_placeholder_new.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/card_placeholder_new.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 236 KiB |
BIN
app/src/main/res/drawable-xxhdpi/card_placeholder_new.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/card_placeholder_new.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 499 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/card_placeholder_new.png
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/card_placeholder_new.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 837 KiB |
24
app/src/main/res/drawable/ic_access_code.xml
Normal file
24
app/src/main/res/drawable/ic_access_code.xml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="119dp"
|
||||
android:height="119dp"
|
||||
android:viewportWidth="119"
|
||||
android:viewportHeight="119">
|
||||
<path
|
||||
android:pathData="M111.664,30.74H7.336C3.291,30.74 0,34.03 0,38.075V60.431C0,64.476 3.291,67.767 7.336,67.767H72.541C73.506,67.767 74.288,66.985 74.288,66.021C74.288,65.056 73.506,64.274 72.541,64.274H7.336C5.217,64.274 3.493,62.55 3.493,60.431V38.075C3.493,35.957 5.217,34.233 7.336,34.233H111.664C113.783,34.233 115.507,35.957 115.507,38.075V54.842C115.507,55.807 116.289,56.589 117.253,56.589C118.218,56.589 119,55.807 119,54.842V38.075C119,34.03 115.709,30.74 111.664,30.74Z"
|
||||
android:fillColor="#060606"/>
|
||||
<path
|
||||
android:pathData="M111.548,58.972V56.706C111.548,48.552 104.914,41.918 96.76,41.918C88.606,41.918 81.973,48.552 81.973,56.706V58.972C79.809,59.703 78.247,61.751 78.247,64.158V82.788C78.247,85.805 80.702,88.26 83.719,88.26H109.801C112.819,88.26 115.274,85.805 115.274,82.788V64.158C115.274,61.751 113.711,59.703 111.548,58.972ZM96.76,45.411C102.988,45.411 108.055,50.478 108.055,56.706V58.685H85.466V56.706C85.466,50.478 90.533,45.411 96.76,45.411ZM111.781,82.788C111.781,83.879 110.893,84.767 109.801,84.767H83.719C82.628,84.767 81.74,83.879 81.74,82.788V64.158C81.74,63.066 82.628,62.178 83.719,62.178H109.801C110.893,62.178 111.781,63.066 111.781,64.158V82.788Z"
|
||||
android:fillColor="#060606"/>
|
||||
<path
|
||||
android:pathData="M28.343,44.654C27.861,43.819 26.793,43.533 25.957,44.015L22.123,46.228V41.801C22.123,40.837 21.341,40.055 20.377,40.055C19.412,40.055 18.63,40.837 18.63,41.801V46.228L14.796,44.015C13.961,43.532 12.893,43.819 12.411,44.654C11.928,45.489 12.215,46.558 13.05,47.04L16.884,49.253L13.05,51.467C12.215,51.949 11.928,53.017 12.411,53.853C12.734,54.413 13.321,54.726 13.925,54.726C14.221,54.726 14.521,54.651 14.796,54.492L18.63,52.278V56.706C18.63,57.67 19.412,58.452 20.377,58.452C21.341,58.452 22.123,57.67 22.123,56.706V52.278L25.957,54.492C26.232,54.651 26.533,54.726 26.829,54.726C27.433,54.726 28.02,54.413 28.343,53.853C28.825,53.017 28.539,51.949 27.704,51.467L23.87,49.253L27.704,47.04C28.539,46.558 28.825,45.489 28.343,44.654Z"
|
||||
android:fillColor="#060606"/>
|
||||
<path
|
||||
android:pathData="M50.699,44.654C50.217,43.819 49.149,43.533 48.313,44.015L44.48,46.228V41.801C44.48,40.837 43.698,40.055 42.733,40.055C41.768,40.055 40.986,40.837 40.986,41.801V46.228L37.153,44.015C36.317,43.532 35.249,43.819 34.767,44.654C34.285,45.489 34.571,46.558 35.406,47.04L39.24,49.253L35.406,51.467C34.571,51.949 34.285,53.017 34.767,53.853C35.09,54.413 35.677,54.726 36.281,54.726C36.577,54.726 36.877,54.651 37.153,54.492L40.986,52.278V56.706C40.986,57.67 41.768,58.452 42.733,58.452C43.698,58.452 44.48,57.67 44.48,56.706V52.278L48.313,54.492C48.588,54.651 48.889,54.726 49.185,54.726C49.789,54.726 50.376,54.413 50.699,53.853C51.181,53.017 50.895,51.949 50.06,51.467L46.226,49.253L50.06,47.04C50.895,46.558 51.181,45.489 50.699,44.654Z"
|
||||
android:fillColor="#060606"/>
|
||||
<path
|
||||
android:pathData="M73.055,44.654C72.573,43.819 71.505,43.533 70.67,44.015L66.836,46.228V41.801C66.836,40.837 66.054,40.055 65.089,40.055C64.125,40.055 63.343,40.837 63.343,41.801V46.228L59.509,44.015C58.673,43.532 57.605,43.819 57.123,44.654C56.641,45.489 56.927,46.558 57.762,47.04L61.596,49.253L57.762,51.467C56.927,51.949 56.641,53.017 57.123,53.853C57.446,54.413 58.034,54.726 58.637,54.726C58.933,54.726 59.234,54.651 59.509,54.492L63.343,52.278V56.706C63.343,57.67 64.125,58.452 65.089,58.452C66.054,58.452 66.836,57.67 66.836,56.706V52.278L70.67,54.492C70.945,54.651 71.245,54.726 71.541,54.726C72.145,54.726 72.732,54.413 73.055,53.853C73.538,53.017 73.252,51.949 72.416,51.467L68.582,49.253L72.416,47.04C73.252,46.558 73.538,45.489 73.055,44.654Z"
|
||||
android:fillColor="#060606"/>
|
||||
<path
|
||||
android:pathData="M96.76,66.137C93.743,66.137 91.288,68.592 91.288,71.61C91.288,74.017 92.85,76.064 95.014,76.795V79.062C95.014,80.026 95.796,80.808 96.76,80.808C97.725,80.808 98.507,80.026 98.507,79.062V76.795C100.67,76.064 102.233,74.017 102.233,71.61C102.233,68.592 99.778,66.137 96.76,66.137ZM96.76,73.589C95.669,73.589 94.781,72.701 94.781,71.61C94.781,70.518 95.669,69.63 96.76,69.63C97.852,69.63 98.74,70.518 98.74,71.61C98.74,72.701 97.852,73.589 96.76,73.589Z"
|
||||
android:fillColor="#060606"/>
|
||||
</vector>
|
||||
15
app/src/main/res/drawable/ic_dot.xml
Normal file
15
app/src/main/res/drawable/ic_dot.xml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape
|
||||
android:innerRadius="0dp"
|
||||
android:shape="ring"
|
||||
android:thickness="4.5dp"
|
||||
android:useLevel="false">
|
||||
<solid
|
||||
android:color="#80686868"
|
||||
android:fillAlpha="0.5"
|
||||
/>
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
11
app/src/main/res/drawable/ic_dot_not_selected.xml
Normal file
11
app/src/main/res/drawable/ic_dot_not_selected.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="4.5dp"
|
||||
android:height="4.5dp"
|
||||
android:viewportWidth="7"
|
||||
android:viewportHeight="7">
|
||||
<path
|
||||
android:pathData="M3.5,7C5.433,7 7,5.433 7,3.5C7,1.567 5.433,0 3.5,0C1.567,0 0,1.567 0,3.5C0,5.433 1.567,7 3.5,7Z"
|
||||
android:fillColor="#686868"
|
||||
android:fillAlpha="0.5"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
22
app/src/main/res/drawable/ic_feature_1.xml
Normal file
22
app/src/main/res/drawable/ic_feature_1.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="25dp"
|
||||
android:height="25dp"
|
||||
android:viewportWidth="25"
|
||||
android:viewportHeight="25">
|
||||
<path
|
||||
android:pathData="M3,11H11C12.6569,11 14,12.3431 14,14V22C14,23.6569 12.6569,25 11,25H3C1.3432,25 0,23.6569 0,22V14C0,12.3431 1.3432,11 3,11Z"
|
||||
android:fillColor="#1ACE80"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M18.7143,11H23.2857C24.2325,11 25,11.7675 25,12.7143V17.2857C25,18.2325 24.2325,19 23.2857,19H18.7143C17.7675,19 17,18.2325 17,17.2857V12.7143C17,11.7675 17.7675,11 18.7143,11Z"
|
||||
android:strokeAlpha="0.15"
|
||||
android:fillColor="#1ACE80"
|
||||
android:fillType="evenOdd"
|
||||
android:fillAlpha="0.15"/>
|
||||
<path
|
||||
android:pathData="M7.7143,0H19.2857C20.2325,0 21,0.7675 21,1.7143V6.2857C21,7.2325 20.2325,8 19.2857,8H7.7143C6.7675,8 6,7.2325 6,6.2857V1.7143C6,0.7675 6.7675,0 7.7143,0Z"
|
||||
android:strokeAlpha="0.5"
|
||||
android:fillColor="#1ACE80"
|
||||
android:fillType="evenOdd"
|
||||
android:fillAlpha="0.5"/>
|
||||
</vector>
|
||||
22
app/src/main/res/drawable/ic_feature_2.xml
Normal file
22
app/src/main/res/drawable/ic_feature_2.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="25dp"
|
||||
android:height="25dp"
|
||||
android:viewportWidth="25"
|
||||
android:viewportHeight="25">
|
||||
<path
|
||||
android:pathData="M18,25C21.866,25 25,21.866 25,18C25,14.134 21.866,11 18,11C14.134,11 11,14.134 11,18C11,21.866 14.134,25 18,25Z"
|
||||
android:fillColor="#1ACE80"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M9,10C11.7614,10 14,7.7614 14,5C14,2.2386 11.7614,0 9,0C6.2386,0 4,2.2386 4,5C4,7.7614 6.2386,10 9,10Z"
|
||||
android:strokeAlpha="0.5"
|
||||
android:fillColor="#1ACE80"
|
||||
android:fillType="evenOdd"
|
||||
android:fillAlpha="0.5"/>
|
||||
<path
|
||||
android:pathData="M4,21C6.2091,21 8,19.2091 8,17C8,14.7909 6.2091,13 4,13C1.7909,13 0,14.7909 0,17C0,19.2091 1.7909,21 4,21Z"
|
||||
android:strokeAlpha="0.15"
|
||||
android:fillColor="#1ACE80"
|
||||
android:fillType="evenOdd"
|
||||
android:fillAlpha="0.15"/>
|
||||
</vector>
|
||||
22
app/src/main/res/drawable/ic_feature_3.xml
Normal file
22
app/src/main/res/drawable/ic_feature_3.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="26dp"
|
||||
android:height="22dp"
|
||||
android:viewportWidth="26"
|
||||
android:viewportHeight="22">
|
||||
<path
|
||||
android:pathData="M19.3989,4.1971L13.3558,4.1971C12.3137,4.1512 11.3955,4.9319 11.3048,5.9408C11.2723,6.3027 11.3515,6.6613 11.5324,6.9712L14.7623,12.5027C15.2667,13.3667 16.4185,13.6429 17.3349,13.1197C17.6423,12.9442 17.8966,12.6917 18.0696,12.3902L21.041,6.9712C21.5566,6.0725 21.1048,4.9181 20.1946,4.4571C19.9583,4.3374 19.6695,4.209 19.3989,4.1971Z"
|
||||
android:strokeAlpha="0.5"
|
||||
android:fillColor="#1ACE80"
|
||||
android:fillType="evenOdd"
|
||||
android:fillAlpha="0.5"/>
|
||||
<path
|
||||
android:pathData="M20.1304,14.9339L17.4396,19.051C16.9906,19.738 17.1702,20.6677 17.8409,21.1276C18.0815,21.2926 18.3644,21.3806 18.6539,21.3806H23.8216C24.6287,21.3806 25.2829,20.7105 25.2829,19.8837C25.2829,19.6064 25.2077,19.3345 25.0657,19.0984L22.5889,14.9813C22.1655,14.2775 21.2652,14.0586 20.5781,14.4923C20.3997,14.6049 20.247,14.7555 20.1304,14.9339Z"
|
||||
android:strokeAlpha="0.15"
|
||||
android:fillColor="#1ACE80"
|
||||
android:fillType="evenOdd"
|
||||
android:fillAlpha="0.15"/>
|
||||
<path
|
||||
android:pathData="M5.1416,10.4031L0.4325,17.4279C-0.3532,18.6 -0.0387,20.1864 1.1349,20.9711C1.5559,21.2526 2.051,21.4029 2.5576,21.4029H11.6011C13.0135,21.4029 14.1585,20.2594 14.1585,18.8488C14.1585,18.3756 14.0269,17.9117 13.7783,17.5089L9.4439,10.4841C8.7029,9.2832 7.1275,8.9096 5.925,9.6496C5.6128,9.8417 5.3456,10.0987 5.1416,10.4031Z"
|
||||
android:fillColor="#1ACE80"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
12
app/src/main/res/drawable/ic_hide_password.xml
Normal file
12
app/src/main/res/drawable/ic_hide_password.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,18.1876C11.4712,18.1865 10.9435,18.1373 10.4236,18.0405C10.2623,18.0147 10.1155,17.9323 10.0094,17.8081C9.9033,17.6839 9.845,17.526 9.8447,17.3626C9.8464,17.2619 9.8699,17.1627 9.9136,17.0719C9.9572,16.9811 10.02,16.9008 10.0976,16.8366C10.1751,16.7723 10.2657,16.7256 10.3631,16.6996C10.4604,16.6737 10.5622,16.669 10.6615,16.6861C11.1028,16.7692 11.5509,16.8115 12,16.8126C16.0728,16.8126 19.61,13.2465 20.7224,12.0001C19.9811,11.1704 19.1666,10.4092 18.2886,9.7259C18.2172,9.6706 18.1574,9.6017 18.1125,9.5233C18.0677,9.4449 18.0388,9.3584 18.0274,9.2688C18.0044,9.0879 18.0542,8.9052 18.1659,8.761C18.2776,8.6167 18.442,8.5228 18.6229,8.4998C18.7125,8.4884 18.8035,8.4947 18.8906,8.5185C18.9778,8.5422 19.0594,8.5829 19.1308,8.6382C20.2501,9.5006 21.2685,10.4866 22.1668,11.5773C22.2615,11.6983 22.313,11.8475 22.313,12.0011C22.313,12.1548 22.2615,12.304 22.1668,12.425C21.9819,12.6594 17.5853,18.1876 12,18.1876Z"
|
||||
android:fillColor="#A4A4A4"/>
|
||||
<path
|
||||
android:pathData="M19.3608,4.6384C19.2319,4.5095 19.0571,4.4371 18.8748,4.4371C18.6925,4.4371 18.5176,4.5095 18.3887,4.6384L16.2024,6.8247C15.3747,6.4258 14.4989,6.1356 13.5968,5.9612C13.0702,5.8622 12.5356,5.8122 11.9998,5.812C6.4145,5.812 2.0179,11.3402 1.8337,11.5753C1.739,11.6963 1.6875,11.8455 1.6875,11.9991C1.6875,12.1528 1.739,12.302 1.8337,12.423C2.7311,13.5128 3.7486,14.4978 4.8669,15.3593C5.396,15.7739 5.9503,16.1553 6.5266,16.5012L4.6387,18.3884C4.573,18.4518 4.5207,18.5277 4.4846,18.6116C4.4486,18.6955 4.4296,18.7857 4.4288,18.877C4.428,18.9682 4.4454,19.0588 4.48,19.1433C4.5146,19.2278 4.5656,19.3045 4.6302,19.3691C4.6947,19.4336 4.7715,19.4847 4.856,19.5192C4.9405,19.5538 5.031,19.5712 5.1223,19.5704C5.2136,19.5696 5.3038,19.5507 5.3877,19.5146C5.4715,19.4786 5.5474,19.4262 5.6108,19.3606L19.3608,5.6105C19.4897,5.4816 19.5621,5.3068 19.5621,5.1245C19.5621,4.9422 19.4897,4.7674 19.3608,4.6384ZM5.7112,14.2744C4.8332,13.5908 4.0186,12.8294 3.2774,11.9995C4.3898,10.7537 7.927,7.187 11.9998,7.187C12.4521,7.1873 12.9034,7.2297 13.3479,7.3135C13.9703,7.4319 14.5783,7.6163 15.1616,7.8635L13.8952,9.1299C13.2342,8.6931 12.4427,8.4981 11.6544,8.5778C10.8662,8.6575 10.1297,9.007 9.5695,9.5672C9.0093,10.1274 8.6598,10.8639 8.5801,11.6521C8.5004,12.4403 8.6954,13.2319 9.1322,13.8929L7.531,15.4968C6.8943,15.1361 6.2859,14.7274 5.7112,14.2744ZM10.1435,12.8822C10.0095,12.6071 9.939,12.3055 9.9373,11.9995C9.9374,11.4541 10.1528,10.9308 10.5368,10.5434C10.8428,10.2523 11.229,10.0594 11.6455,9.9896C12.0621,9.9198 12.49,9.9761 12.8743,10.1515L10.1435,12.8822Z"
|
||||
android:fillColor="#A4A4A4"/>
|
||||
</vector>
|
||||
12
app/src/main/res/drawable/ic_selected_dot.xml
Normal file
12
app/src/main/res/drawable/ic_selected_dot.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape
|
||||
android:innerRadius="0dp"
|
||||
android:shape="ring"
|
||||
android:thickness="4.5dp"
|
||||
android:useLevel="false">
|
||||
<solid android:color="#060606"/>
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
12
app/src/main/res/drawable/ic_show_password.xml
Normal file
12
app/src/main/res/drawable/ic_show_password.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12.0003,18.1875C6.4136,18.1875 2.0185,12.6593 1.8342,12.4242C1.7393,12.3032 1.6877,12.1538 1.6877,12C1.6877,11.8462 1.7393,11.6968 1.8342,11.5758C2.0185,11.3407 6.4136,5.8125 12.0003,5.8125C17.5869,5.8125 21.9821,11.3407 22.1663,11.5758C22.2612,11.6968 22.3128,11.8462 22.3128,12C22.3128,12.1538 22.2612,12.3032 22.1663,12.4242C21.9821,12.6593 17.5869,18.1875 12.0003,18.1875ZM3.278,12C4.391,13.2471 7.9268,16.8125 12.0003,16.8125C16.0737,16.8125 19.6095,13.2471 20.7226,12C19.6095,10.7529 16.0737,7.1875 12.0003,7.1875C7.9268,7.1875 4.391,10.7529 3.278,12Z"
|
||||
android:fillColor="#A4A4A4"/>
|
||||
<path
|
||||
android:pathData="M12,15.4375C11.3201,15.4375 10.6555,15.2359 10.0902,14.8582C9.5249,14.4804 9.0843,13.9436 8.8242,13.3155C8.564,12.6873 8.4959,11.9962 8.6285,11.3294C8.7612,10.6626 9.0886,10.0501 9.5693,9.5693C10.0501,9.0886 10.6626,8.7612 11.3294,8.6285C11.9962,8.4959 12.6873,8.564 13.3155,8.8242C13.9436,9.0843 14.4804,9.5249 14.8582,10.0902C15.2359,10.6555 15.4375,11.3201 15.4375,12C15.4364,12.9113 15.0739,13.785 14.4295,14.4295C13.785,15.0739 12.9113,15.4364 12,15.4375ZM12,9.9375C11.5921,9.9375 11.1933,10.0585 10.8541,10.2851C10.515,10.5117 10.2506,10.8338 10.0945,11.2107C9.9384,11.5876 9.8975,12.0023 9.9771,12.4024C10.0567,12.8025 10.2531,13.17 10.5416,13.4584C10.83,13.7468 11.1975,13.9433 11.5976,14.0229C11.9977,14.1024 12.4124,14.0616 12.7893,13.9055C13.1661,13.7494 13.4883,13.485 13.7149,13.1459C13.9415,12.8067 14.0625,12.4079 14.0625,12C14.0625,11.453 13.8452,10.9284 13.4584,10.5416C13.0716,10.1548 12.547,9.9375 12,9.9375Z"
|
||||
android:fillColor="#A4A4A4"/>
|
||||
</vector>
|
||||
5
app/src/main/res/drawable/selector_password_toggle.xml
Normal file
5
app/src/main/res/drawable/selector_password_toggle.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/ic_hide_password" android:state_checked="true"/>
|
||||
<item android:drawable="@drawable/ic_show_password"/>
|
||||
</selector>
|
||||
8
app/src/main/res/drawable/selector_tabs_dots.xml
Normal file
8
app/src/main/res/drawable/selector_tabs_dots.xml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:drawable="@drawable/ic_selected_dot"
|
||||
android:state_selected="true"/>
|
||||
|
||||
<item android:drawable="@drawable/ic_dot"/>
|
||||
</selector>
|
||||
|
|
@ -160,15 +160,14 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_signed_hashes" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_erase_wallet"
|
||||
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_erase_wallet"
|
||||
android:text="@string/details_row_title_create_backup"
|
||||
android:textColor="@color/darkGray6"
|
||||
android:textSize="16sp"
|
||||
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
|
||||
|
|
@ -176,6 +175,21 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_security_title" />
|
||||
|
||||
<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"
|
||||
|
|
@ -187,7 +201,7 @@
|
|||
android:textColor="@color/colorSecondary"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_erase_wallet" />
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_reset_to_factory" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,225 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<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_details_confirm"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/backgroundLightGray"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/app_bar"
|
||||
style="@style/ThemeOverlay.MyTheme.Toolbar.AccentColorMenu"
|
||||
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/onboarding_getting_started"
|
||||
app:menu="@menu/shop"/>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/onboarding_main_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<include
|
||||
layout="@layout/view_onboarding_progress"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/imv_card_background"
|
||||
android:layout_width="236dp"
|
||||
android:layout_height="236dp"
|
||||
android:layout_gravity="center"
|
||||
android:adjustViewBounds="true"
|
||||
android:background="@drawable/shape_circle"
|
||||
android:backgroundTint="@color/lightGray0"
|
||||
android:elevation="0dp"
|
||||
android:scaleType="fitCenter"
|
||||
app:layout_constraintStart_toStartOf="@id/fl_cards_container"
|
||||
app:layout_constraintEnd_toEndOf="@id/fl_cards_container"
|
||||
app:layout_constraintTop_toTopOf="@id/fl_cards_container"
|
||||
app:layout_constraintBottom_toBottomOf="@id/fl_cards_container"
|
||||
android:layout_marginBottom="16dp"
|
||||
/>
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fl_cards_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="16dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/guideline2"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.495"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/pb_state">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/imv_second_backup_card"
|
||||
android:layout_width="296dp"
|
||||
android:layout_height="186dp"
|
||||
android:scaleType="fitXY"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/card_placeholder_black"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/imv_first_backup_card"
|
||||
android:layout_width="296dp"
|
||||
android:layout_height="186dp"
|
||||
android:scaleType="fitXY"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/card_placeholder_black"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/imv_front_card"
|
||||
android:layout_width="296dp"
|
||||
android:layout_height="186dp"
|
||||
android:scaleType="fitXY"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/card_placeholder_black"
|
||||
android:transitionName="imv_front_card"
|
||||
/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/imv_success"
|
||||
android:layout_width="142dp"
|
||||
android:layout_height="142dp"
|
||||
android:src="@drawable/ic_activation_success"
|
||||
app:layout_constraintBottom_toTopOf="@id/guideline2"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.495"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/pb_state"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/ll_header_body_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="72dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline2">
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_header"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
tools:text="Header"
|
||||
android:textColor="#060606"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.504"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline2" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_body"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="64dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="64dp"
|
||||
tools:text="Body"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#686868"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_header" />
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/view_pager_backup_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintHorizontal_bias="0.504"
|
||||
app:layout_constraintBottom_toTopOf="@id/layout_buttons_common"
|
||||
app:flow_verticalBias="0"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline2"
|
||||
android:layout_marginBottom="12dp"/>
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tab_layout_backup_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/backgroundLightGray"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/view_pager_backup_info"
|
||||
app:layout_constraintBottom_toTopOf="@id/layout_buttons_common"
|
||||
app:tabBackground="@drawable/selector_tabs_dots"
|
||||
app:tabIndicator="@null"
|
||||
app:tabPaddingStart="8dp"
|
||||
app:tabPaddingEnd="8dp"
|
||||
app:tabGravity="center"/>
|
||||
|
||||
<include
|
||||
android:id="@+id/layout_buttons_common"
|
||||
layout="@layout/layout_onboarding_buttons_common"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
||||
/>
|
||||
|
||||
<include
|
||||
android:id="@+id/layout_buttons_add_cards"
|
||||
layout="@layout/layout_onboarding_buttons_add_cards"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guideline2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintGuide_percent="0.60"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<include
|
||||
layout="@layout/view_confetti"
|
||||
android:visibility="gone" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
36
app/src/main/res/layout/item_backup_info_adapter.xml
Normal file
36
app/src/main/res/layout/item_backup_info_adapter.xml
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_header"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:text="Header"
|
||||
android:textColor="#060606"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.504"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_body"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="64dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="64dp"
|
||||
android:text="Body"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#686868"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_header" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
44
app/src/main/res/layout/layout_backup_access_code.xml
Normal file
44
app/src/main/res/layout/layout_backup_access_code.xml
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/access_code_title"
|
||||
style="@style/heading"
|
||||
android:textStyle="bold"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="100dp"
|
||||
android:text="@string/onboarding_access_code_intro_title"
|
||||
android:textAlignment="center"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<include
|
||||
android:id="@+id/layout_backup_access_code_info"
|
||||
layout="@layout/layout_backup_access_code_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/access_code_title" />
|
||||
|
||||
<include
|
||||
android:id="@+id/layout_backup_access_code_submit"
|
||||
layout="@layout/layout_backup_access_code_submit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/access_code_title" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</FrameLayout>
|
||||
132
app/src/main/res/layout/layout_backup_access_code_info.xml
Normal file
132
app/src/main/res/layout/layout_backup_access_code_info.xml
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_access_code_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="25dp"
|
||||
android:src="@drawable/ic_access_code"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:layout_marginTop="20dp"
|
||||
android:id="@+id/tv_feature_1_title"
|
||||
style="@style/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/onboarding_access_code_feature_1_title"
|
||||
android:textAlignment="center"
|
||||
app:layout_constraintStart_toStartOf="@id/tv_feature_1_description"
|
||||
app:layout_constraintTop_toBottomOf="@id/iv_access_code_icon" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_feature_1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="46dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:src="@drawable/ic_feature_1"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_feature_1_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_feature_1_description"
|
||||
style="@style/description"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="46dp"
|
||||
android:text="@string/onboarding_access_code_feature_1_description"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/iv_feature_1"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_feature_1_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_feature_2_title"
|
||||
style="@style/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="30dp"
|
||||
android:text="@string/onboarding_access_code_feature_2_title"
|
||||
android:textAlignment="center"
|
||||
app:layout_constraintStart_toStartOf="@id/tv_feature_1_description"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_feature_1_description" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_feature_2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="46dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:src="@drawable/ic_feature_2"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_feature_2_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_feature_2_description"
|
||||
style="@style/description"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="46dp"
|
||||
android:text="@string/onboarding_access_code_feature_2_description"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/iv_feature_2"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_feature_2_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_feature_3_title"
|
||||
style="@style/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="30dp"
|
||||
android:text="@string/onboarding_access_code_feature_3_title"
|
||||
android:textAlignment="center"
|
||||
app:layout_constraintStart_toStartOf="@id/tv_feature_3_description"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_feature_2_description" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_feature_3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="46dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:src="@drawable/ic_feature_3"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_feature_3_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_feature_3_description"
|
||||
style="@style/description"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="46dp"
|
||||
android:text="@string/onboarding_access_code_feature_3_description"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/iv_feature_3"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_feature_3_title" />
|
||||
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_access_code_create"
|
||||
style="@style/TapButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="78dp"
|
||||
android:layout_marginEnd="78dp"
|
||||
android:layout_marginBottom="92dp"
|
||||
android:text="@string/common_create"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
60
app/src/main/res/layout/layout_backup_access_code_submit.xml
Normal file
60
app/src/main/res/layout/layout_backup_access_code_submit.xml
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_access_code_enter_description"
|
||||
style="DescriptionBig"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="14dp"
|
||||
android:paddingStart="32dp"
|
||||
android:paddingEnd="32dp"
|
||||
android:textAlignment="center"
|
||||
android:text="@string/onboarding_access_code_hint"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/til_access_code"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="44dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="40dp"
|
||||
android:hint="Access code"
|
||||
app:boxStrokeColor="@color/selector_edit_text"
|
||||
app:boxStrokeWidth="1dp"
|
||||
app:endIconDrawable="@drawable/selector_password_toggle"
|
||||
app:endIconMode="password_toggle"
|
||||
app:hintTextColor="@color/accent"
|
||||
android:theme="@style/EditTextThemeOverlay"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_access_code_enter_description">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_access_code"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textVisiblePassword"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_access_code_submit"
|
||||
style="@style/TapButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="78dp"
|
||||
android:layout_marginEnd="78dp"
|
||||
android:layout_marginBottom="92dp"
|
||||
android:text="@string/common_create"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_add_card"
|
||||
style="@style/OnboardingButton"
|
||||
android:backgroundTint="@color/gray_button"
|
||||
android:textColor="@color/selector_btn_gray_text_color"
|
||||
android:elevation="0dp"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="92dp"
|
||||
tools:text="+ Add backup card"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@id/btn_continue"
|
||||
app:layout_constraintStart_toStartOf="@id/btn_continue" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_continue"
|
||||
style="@style/OnboardingButton"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="32dp"
|
||||
tools:text="Main Action"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
33
app/src/main/res/layout/layout_onboarding_buttons_common.xml
Normal file
33
app/src/main/res/layout/layout_onboarding_buttons_common.xml
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_main_action"
|
||||
style="@style/OnboardingButton"
|
||||
android:layout_width="204dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="92dp"
|
||||
tools:text="Main Action"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_alternative_action"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:textSize="16sp"
|
||||
android:layout_width="204dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="32dp"
|
||||
tools:text="Alternative action"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/tapButtonColorBlack"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -19,4 +19,10 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/card_placeholder_black" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:tint="@color/warning"
|
||||
android:src="@drawable/card_placeholder_black" />
|
||||
|
||||
</FrameLayout>
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge>
|
||||
|
||||
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/pb_state"
|
||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||
|
|
|
|||
8
app/src/main/res/menu/shop.xml
Normal file
8
app/src/main/res/menu/shop.xml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/shop_menu"
|
||||
android:title="@string/home_button_shop"
|
||||
app:showAsAction="always" />
|
||||
</menu>
|
||||
|
|
@ -55,4 +55,7 @@
|
|||
<color name="warning_warning">#FFB71B</color>
|
||||
<color name="warning_critical">#CA0F03</color>
|
||||
|
||||
<color name="gray_button">#EFEFF0</color>
|
||||
|
||||
<color name="menu_accent_color">#18C077</color>
|
||||
</resources>
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
<string name="twins_onboarding_subtitle" translatable="false">One wallet. Two cards.</string>
|
||||
<string name="twins_onboarding_description_format" translatable="false">This one that you are holding in your hands and the other one with number #%s.</string>
|
||||
|
||||
<string name="wallet_twins_chip_format" translatable="false">Card %s of 2</string>
|
||||
<string name="wallet_twins_chip_format" translatable="false">Card %1d of %2d</string>
|
||||
|
||||
<string name="details_row_title_twins_recreate" translatable="false">Re-create twin wallet</string>
|
||||
<string name="details_row_title_card_tou" translatable="false">Card terms of use</string>
|
||||
|
|
@ -208,4 +208,89 @@
|
|||
|
||||
<string name="warning_button_ok" translatable="false">Ok, Got it!</string>
|
||||
|
||||
<string name="onboarding_success" translatable="false">Success!</string>
|
||||
<string name="onboarding_getting_started" translatable="false">Getting started</string>
|
||||
|
||||
<string name="onboarding_button_backup_now" translatable="false">Backup now</string>
|
||||
<string name="onboarding_button_get_backup_card" translatable="false">Get a backup card</string>
|
||||
<string name="onboarding_button_skip_backup" translatable="false">Skip for later</string>
|
||||
<string name="onboarding_button_finalize_backup" translatable="false">Finalize the backup process</string>
|
||||
<string name="onboarding_button_add_backup_card" translatable="false">+ Add backup card</string>
|
||||
<string name="onboarding_button_backup_card_format" translatable="false">Scan the card #%d</string>
|
||||
<string name="onboarding_button_scan_origin_card" translatable="false">Scan primary card</string>
|
||||
<string name="onboarding_button_buy_more_cards" translatable="false">Buy more cards</string>
|
||||
|
||||
<string name="onboarding_title_backup_card" translatable="false">Backup your wallet</string>
|
||||
<string name="onboarding_title_no_backup_cards" translatable="false">No backup cards</string>
|
||||
<string name="onboarding_title_scan_origin_card" translatable="false">Prepare your card</string>
|
||||
<string name="onboarding_title_one_backup_card" translatable="false">One backup card added</string>
|
||||
<string name="onboarding_title_two_backup_cards" translatable="false">Two backup cards added</string>
|
||||
<string name="onboarding_title_backup_card_format" translatable="false">Backup card #%d</string>
|
||||
|
||||
<string name="onboarding_subtitle_backup_card" translatable="false">You can backup your keys up to two other blank wallet cards</string>
|
||||
<string name="onboarding_subtitle_no_backup_cards" translatable="false">To start the backup process add up to two cards</string>
|
||||
<string name="onboarding_subtitle_scan_origin_card_format" translatable="false">Prepare the primary card with number %s</string>
|
||||
<string name="onboarding_subtitle_scan_origin_card" translatable="false">Prepare the primary card</string>
|
||||
<string name="onboarding_subtitle_one_backup_card" translatable="false">You can add one more card or finalize the backup process</string>
|
||||
<string name="onboarding_subtitle_two_backup_cards" translatable="false">Max number of cards added. Finalize the backup process</string>
|
||||
<string name="onboarding_subtitle_backup_warning" translatable="false">If the process of backup gets interrupted in any way you’ll have to start over</string>
|
||||
|
||||
<string name="onboarding_alert_message_not_max_backup_cards_added" translatable="false">You’ve added one backup card. When backup process is finished you can’t add more backup cards. If you have one more card, add it in backup, otherwise you can buy it in shop. Do you like to continue backup process?</string>
|
||||
|
||||
<string name="onboarding_access_code_intro_title" translatable="false">Create Access Code</string>
|
||||
<string name="onboarding_access_code_repeat_code_title" translatable="false">Re-enter your Access Code</string>
|
||||
<string name="onboarding_access_code_feature_1_title" translatable="false">Protect</string>
|
||||
<string name="onboarding_access_code_feature_2_title" translatable="false">Personalize</string>
|
||||
<string name="onboarding_access_code_feature_3_title" translatable="false">Restore</string>
|
||||
<string name="onboarding_access_code_feature_1_description" translatable="false">You have to setup a single access code to protect all yor wallets.</string>
|
||||
<string name="onboarding_access_code_feature_2_description" translatable="false">You can set an individual access code on each card later.</string>
|
||||
<string name="onboarding_access_code_feature_3_description" translatable="false">The access code can be restored with a linked card, don’t keep all cards at one place.</string>
|
||||
<string name="onboarding_access_code_hint" translatable="false">Choose any word, phrase, or number you want as your access code.</string>
|
||||
<string name="onboarding_access_code_too_short" translatable="false">Access code must be at least 4 characters long</string>
|
||||
<string name="onboarding_access_codes_doesnt_match" translatable="false">Entered access code didn\'t match initial access code</string>
|
||||
|
||||
<string name="common_create" translatable="false">Create</string>
|
||||
<string name="common_submit" translatable="false">Submit</string>
|
||||
<string name="onboarding_subtitle_success_backup" translatable="false">You have created 2 backup cards, and now these cards are ready for use.</string>
|
||||
<string name="onboarding_navbar_title_creating_backup" translatable="false">Creating a backup</string>
|
||||
<string name="onboarding_backup_exit_warning" translatable="false">The backup process is partly complete. You can’t exit it now.</string>
|
||||
|
||||
<string name="onboarding_wallet_info_title_first" translatable="false">Backup wallet</string>
|
||||
<string name="onboarding_wallet_info_title_second" translatable="false">Identical cards</string>
|
||||
<string name="onboarding_wallet_info_title_third" translatable="false">Access code</string>
|
||||
<string name="onboarding_wallet_info_title_fourth" translatable="false">Access code restore</string>
|
||||
|
||||
<string name="onboarding_wallet_info_subtitle_first" translatable="false">You can backup your keys up to two other blank Tangem Wallet cards.</string>
|
||||
<string name="onboarding_wallet_info_subtitle_second" translatable="false">All the backup cards can be used as full-functoinal with the identical keys.</string>
|
||||
<string name="onboarding_wallet_info_subtitle_third" translatable="false">You will be able to set an access code to protect your wallets.</string>
|
||||
<string name="onboarding_wallet_info_subtitle_fourth" translatable="false">Access code can be restored with one of backup cards.</string>
|
||||
|
||||
<string name="onboarding_subtitle_success_tangem_wallet_onboarding" translatable="false">Your Tangem Wallet card is configured and ready for use.</string>
|
||||
<string name="onboarding_subtitle_success_backup_one_card" translatable="false">You have created 1 backup card, and now this card are ready for use.</string>
|
||||
<string name="common_origin_card" translatable="false">Primary Card</string>
|
||||
<string name="onboarding_alert_i_understand" translatable="false">I understand</string>
|
||||
|
||||
<string name="details_row_title_backup_status" translatable="false">Backup status</string>
|
||||
<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>
|
||||
<string name="welcome_interrupted_backup_discard_title" translatable="false">This is an irreversible action</string>
|
||||
<string name="welcome_interrupted_backup_discard_message" translatable="false">If you will discard the backup now, then you will have to reset the cards to factory settings to start over again</string>
|
||||
<string name="welcome_interrupted_backup_discard_resume" translatable="false">Resume backup</string>
|
||||
<string name="welcome_interrupted_backup_discard_discard" translatable="false">Discard</string>
|
||||
<string name="onboarding_title_prepare_origin" translatable="false">Primary card</string>
|
||||
<string name="onboarding_button_backup_origin" translatable="false">Scan the primary card</string>
|
||||
<string name="onboarding_button_continue_wallet" translatable="false">Continue to my wallet</string>
|
||||
<string name="card_label_number_format" translatable="false">Card %1s of %2s</string>
|
||||
<string name="send_title_currency_format" translatable="false">Sending %s</string>
|
||||
<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>
|
||||
|
||||
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:windowActionBarOverlay">true</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<item name="actionMenuTextColor">@color/menu_accent_color</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="AppTheme" parent="BaseAppTheme" />
|
||||
|
|
@ -28,11 +30,20 @@
|
|||
<item name="actionMenuTextColor">@color/menu_item_color</item>
|
||||
</style>
|
||||
|
||||
<style name="ThemeOverlay.MyTheme.Toolbar.AccentColorMenu" parent="ThemeOverlay.MaterialComponents.Toolbar.Surface">
|
||||
<item name="actionMenuTextColor">@color/accent</item>
|
||||
</style>
|
||||
|
||||
<!-- EditText -->
|
||||
<style name="StyledEditText" parent="TextAppearance.MaterialComponents.Body1">
|
||||
<item name="colorControlNormal">#e34b1c</item>
|
||||
</style>
|
||||
|
||||
<style name="EditTextThemeOverlay" parent="ThemeOverlay.AppCompat">
|
||||
<item name="colorAccent">@color/accent</item>
|
||||
<item name="colorPrimary">@color/accent</item>
|
||||
</style>
|
||||
|
||||
<style name="BaseTapButton">
|
||||
<item name="android:insetTop">0dp</item>
|
||||
<item name="android:insetBottom">0dp</item>
|
||||
|
|
@ -54,7 +65,8 @@
|
|||
</style>
|
||||
|
||||
<style name="OnboardingButton" parent="BaseTapButton">
|
||||
<item name="android:layout_width">204dp</item>
|
||||
<item name="android:minWidth">204dp</item>
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">48dp</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:fontFamily">sans-serif-medium</item>
|
||||
|
|
@ -107,6 +119,34 @@
|
|||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:lineSpacingExtra">4sp</item>
|
||||
</style>
|
||||
<style name="heading">
|
||||
<item name="android:textSize">24sp</item>
|
||||
<item name="android:textColor">#060606</item>
|
||||
</style>
|
||||
|
||||
<style name="title">
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:textColor">#060606</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
</style>
|
||||
|
||||
<style name="description">
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textColor">#686868</item>
|
||||
</style>
|
||||
|
||||
<style name="DescriptionBig">
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:textColor">#686868</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="DialogStyle" parent="Theme.Design.Light.BottomSheetDialog">
|
||||
<item name="android:windowIsFloating">false</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowSoftInputMode">adjustResize</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
||||
<!-- android:fontFamily="sans-serif" // roboto regular -->
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue