Updated on 2026-08-14
This commit is contained in:
parent
f5cd710825
commit
d68da48f0f
69 changed files with 2452 additions and 144 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue