Updated on 2026-08-14
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
|
@ -187,13 +187,18 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
override fun onDestroy() {
|
||||
store.dispatch(NavigationAction.ActivityDestroyed(WeakReference(this)))
|
||||
intentProcessor.removeAll()
|
||||
cardSdkLifecycleObserver.onDestroy()
|
||||
cardSdkLifecycleObserver.onDestroy(this)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private fun initIntentHandlers() {
|
||||
val hasSavedWalletsProvider = { store.state.globalState.userWalletsListManager?.hasUserWallets == true }
|
||||
intentProcessor.addHandler(BackgroundScanIntentHandler(hasSavedWalletsProvider))
|
||||
intentProcessor.addHandler(
|
||||
BackgroundScanIntentHandler(
|
||||
hasSavedWalletsProvider,
|
||||
lifecycleScope,
|
||||
),
|
||||
)
|
||||
intentProcessor.addHandler(WalletConnectLinkIntentHandler())
|
||||
intentProcessor.addHandler(BuyCurrencyIntentHandler())
|
||||
intentProcessor.addHandler(SellCurrencyIntentHandler())
|
||||
|
|
@ -246,7 +251,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
*/
|
||||
cardSdkLifecycleObserver.onCreate(context = this)
|
||||
|
||||
scope.launch {
|
||||
lifecycleScope.launch {
|
||||
intentProcessor.handleIntent(intent)
|
||||
}
|
||||
}
|
||||
|
|
@ -318,8 +323,11 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
if (store.state.globalState.userWalletsListManager?.hasUserWallets == true) {
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Welcome))
|
||||
store.dispatchOnMain(WelcomeAction.SetInitialIntent(intentWhichStartedActivity))
|
||||
scope.launch {
|
||||
val handler = BackgroundScanIntentHandler(hasSavedUserWalletsProvider = { true })
|
||||
lifecycleScope.launch {
|
||||
val handler = BackgroundScanIntentHandler(
|
||||
hasSavedUserWalletsProvider = { true },
|
||||
lifecycleCoroutineScope = lifecycleScope,
|
||||
)
|
||||
val isBackgroundScanHandled = handler.handleIntent(intentWhichStartedActivity)
|
||||
val hasNotIncompletedBackup = !backupService.hasIncompletedBackup
|
||||
if (!isBackgroundScanHandled && hasNotIncompletedBackup) {
|
||||
|
|
@ -328,7 +336,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
}
|
||||
} else {
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Home))
|
||||
scope.launch {
|
||||
lifecycleScope.launch {
|
||||
intentProcessor.handleIntent(intentWhichStartedActivity)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ import com.tangem.domain.common.LogConfig
|
|||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.legacy.WalletManagersRepository
|
||||
import com.tangem.feature.learn2earn.domain.api.Learn2earnInteractor
|
||||
import com.tangem.features.tokendetails.featuretoggles.TokenDetailsFeatureToggles
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import com.tangem.tap.common.analytics.AnalyticsFactory
|
||||
|
|
@ -153,8 +152,8 @@ class TapApplication : Application(), ImageLoaderFactory {
|
|||
@Inject
|
||||
lateinit var walletConnectSessionsRepository: WalletConnectSessionsRepository
|
||||
|
||||
@Inject
|
||||
lateinit var learn2earnInteractor: Learn2earnInteractor
|
||||
// @Inject
|
||||
// lateinit var learn2earnInteractor: Learn2earnInteractor
|
||||
|
||||
@Inject
|
||||
lateinit var tokenDetailsFeatureToggles: TokenDetailsFeatureToggles
|
||||
|
|
@ -247,7 +246,7 @@ class TapApplication : Application(), ImageLoaderFactory {
|
|||
// [REDACTED_JIRA]
|
||||
runBlocking {
|
||||
featureTogglesManager.init()
|
||||
learn2earnInteractor.init()
|
||||
// learn2earnInteractor.init()
|
||||
}
|
||||
|
||||
initTopUpController()
|
||||
|
|
|
|||
|
|
@ -45,6 +45,16 @@ sealed class Onboarding(
|
|||
event = "Backup Finished",
|
||||
params = mapOf("Cards count" to "$cardsCount"),
|
||||
)
|
||||
|
||||
object ResetCancelEvent : Backup(
|
||||
event = "Reset Card Notification",
|
||||
params = mapOf("Option" to "Cancel"),
|
||||
)
|
||||
|
||||
object ResetPerformEvent : Backup(
|
||||
event = "Reset Card Notification",
|
||||
params = mapOf("Option" to "Reset"),
|
||||
)
|
||||
}
|
||||
|
||||
sealed class Topup(
|
||||
|
|
|
|||
|
|
@ -2,10 +2,13 @@ package com.tangem.tap.common.redux.global
|
|||
|
||||
import com.tangem.domain.redux.domainStore
|
||||
import com.tangem.domain.redux.global.DomainGlobalAction
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.features.onboarding.OnboardingManager
|
||||
import com.tangem.tap.preferencesStorage
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.utils.extensions.replaceBy
|
||||
import org.rekotlin.Action
|
||||
|
||||
|
|
@ -82,9 +85,12 @@ fun globalReducer(action: Action, state: AppState, appStateHolder: AppStateHolde
|
|||
}
|
||||
is GlobalAction.SetIfCardVerifiedOnline ->
|
||||
globalState.copy(cardVerifiedOnline = action.verified)
|
||||
is GlobalAction.FetchUserCountry.Success -> globalState.copy(
|
||||
userCountryCode = action.countryCode,
|
||||
)
|
||||
is GlobalAction.FetchUserCountry.Success -> {
|
||||
store.dispatchOnMain(HomeAction.UpdateCountryCode(action.countryCode))
|
||||
globalState.copy(
|
||||
userCountryCode = action.countryCode,
|
||||
)
|
||||
}
|
||||
is GlobalAction.UpdateUserWalletsListManager -> {
|
||||
appStateHolder.userWalletsListManager = action.manager
|
||||
globalState.copy(
|
||||
|
|
|
|||
|
|
@ -134,9 +134,12 @@ class TangemSdkManager(private val cardSdkConfigRepository: CardSdkConfigReposit
|
|||
return runTaskAsyncReturnOnMain(DeriveMultipleWalletPublicKeysTask(derivations), cardId)
|
||||
}
|
||||
|
||||
suspend fun resetToFactorySettings(cardId: String): CompletionResult<CardDTO> {
|
||||
suspend fun resetToFactorySettings(
|
||||
cardId: String,
|
||||
allowsRequestAccessCodeFromRepository: Boolean,
|
||||
): CompletionResult<CardDTO> {
|
||||
return runTaskAsyncReturnOnMain(
|
||||
runnable = ResetToFactorySettingsTask(),
|
||||
runnable = ResetToFactorySettingsTask(allowsRequestAccessCodeFromRepository),
|
||||
cardId = cardId,
|
||||
initialMessage = Message(resources.getString(R.string.card_settings_reset_card_to_factory)),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -151,7 +151,9 @@ private class CreateWalletTangemWallet(
|
|||
) {
|
||||
val config = CardConfig.createConfig(card)
|
||||
val walletsOnCard = card.wallets.map { it.curve }.toSet()
|
||||
val curves = card.supportedCurves.intersect(config.mandatoryCurves.toSet()).subtract(walletsOnCard).toList()
|
||||
val curves = config.mandatoryCurves.toSet()
|
||||
.intersect(card.supportedCurves.toSet())
|
||||
.subtract(walletsOnCard).toList()
|
||||
|
||||
if (curves.isEmpty()) {
|
||||
val createWalletResponses = card.wallets.map { wallet ->
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ import com.tangem.common.extensions.guard
|
|||
import com.tangem.operations.backup.ResetBackupCommand
|
||||
import com.tangem.operations.wallet.PurgeWalletCommand
|
||||
|
||||
class ResetToFactorySettingsTask : CardSessionRunnable<Card> {
|
||||
class ResetToFactorySettingsTask(
|
||||
override val allowsRequestAccessCodeFromRepository: Boolean,
|
||||
) : CardSessionRunnable<Card> {
|
||||
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<Card>) -> Unit) {
|
||||
deleteWallets(session, callback)
|
||||
|
|
|
|||
|
|
@ -249,7 +249,10 @@ private class ScanWalletProcessor(
|
|||
derivationStyleProvider: DerivationStyleProvider,
|
||||
): List<BlockchainNetwork> {
|
||||
val userTokensRepository = userTokensRepository ?: return emptyList()
|
||||
val blockchainsToDerive = userTokensRepository.loadBlockchainsToDerive(card)
|
||||
val blockchainsToDerive = userTokensRepository.loadBlockchainsToDerive(
|
||||
card,
|
||||
derivationStyleProvider.getDerivationStyle(),
|
||||
)
|
||||
.toMutableList()
|
||||
.ifEmpty { getDefaultBlockchains(derivationStyleProvider) }
|
||||
|
||||
|
|
|
|||
|
|
@ -28,18 +28,23 @@ class UserTokensRepository(
|
|||
private val networkConnectionManager: NetworkConnectionManager,
|
||||
) {
|
||||
|
||||
suspend fun getUserTokens(card: CardDTO): List<Currency> = withContext(dispatchers.io) {
|
||||
val userWalletId = getUserWalletId(card) ?: return@withContext emptyList()
|
||||
suspend fun getUserTokens(card: CardDTO, derivationStyle: DerivationStyle?): List<Currency> =
|
||||
withContext(dispatchers.io) {
|
||||
val userWalletId = getUserWalletId(card) ?: return@withContext emptyList()
|
||||
|
||||
if (DemoHelper.isDemoCardId(card.cardId)) {
|
||||
return@withContext loadTokensOffline(userWalletId = userWalletId).ifEmpty(::loadDemoCurrencies)
|
||||
if (DemoHelper.isDemoCardId(card.cardId)) {
|
||||
return@withContext loadTokensOffline(userWalletId = userWalletId).ifEmpty {
|
||||
loadDemoCurrencies(
|
||||
derivationStyle,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (!networkConnectionManager.isOnline) return@withContext loadTokensOffline(userWalletId = userWalletId)
|
||||
|
||||
return@withContext remoteGetUserTokens(userWalletId = userWalletId)
|
||||
}
|
||||
|
||||
if (!networkConnectionManager.isOnline) return@withContext loadTokensOffline(userWalletId = userWalletId)
|
||||
|
||||
return@withContext remoteGetUserTokens(userWalletId = userWalletId)
|
||||
}
|
||||
|
||||
suspend fun saveUserTokens(card: CardDTO, tokens: List<Currency>) = withContext(dispatchers.io) {
|
||||
val userWalletId = getUserWalletId(card) ?: return@withContext
|
||||
val userTokens = tokens.toUserTokensResponse()
|
||||
|
|
@ -48,28 +53,29 @@ class UserTokensRepository(
|
|||
}
|
||||
|
||||
// FIXME: Move to data layer
|
||||
suspend fun loadBlockchainsToDerive(card: CardDTO): List<BlockchainNetwork> = withContext(dispatchers.io) {
|
||||
val userWalletId = getUserWalletId(card) ?: return@withContext emptyList()
|
||||
val blockchainNetworks = loadTokensOffline(userWalletId = userWalletId).toBlockchainNetworks()
|
||||
suspend fun loadBlockchainsToDerive(card: CardDTO, derivationStyle: DerivationStyle?): List<BlockchainNetwork> =
|
||||
withContext(dispatchers.io) {
|
||||
val userWalletId = getUserWalletId(card) ?: return@withContext emptyList()
|
||||
val blockchainNetworks = loadTokensOffline(userWalletId = userWalletId).toBlockchainNetworks()
|
||||
|
||||
if (DemoHelper.isDemoCardId(card.cardId)) {
|
||||
return@withContext blockchainNetworks.ifEmpty(loadDemoCurrencies()::toBlockchainNetworks)
|
||||
if (DemoHelper.isDemoCardId(card.cardId)) {
|
||||
return@withContext blockchainNetworks.ifEmpty(loadDemoCurrencies(derivationStyle)::toBlockchainNetworks)
|
||||
}
|
||||
|
||||
return@withContext blockchainNetworks
|
||||
}
|
||||
|
||||
return@withContext blockchainNetworks
|
||||
}
|
||||
|
||||
private fun loadTokensOffline(userWalletId: String): List<Currency> {
|
||||
return storageService.getUserTokens(userWalletId = userWalletId) ?: emptyList()
|
||||
}
|
||||
|
||||
// FIXME: Move to user wallet config
|
||||
private fun loadDemoCurrencies(): List<Currency> {
|
||||
private fun loadDemoCurrencies(derivationStyle: DerivationStyle?): List<Currency> {
|
||||
return DemoHelper.config.demoBlockchains
|
||||
.map { blockchain ->
|
||||
BlockchainNetwork(
|
||||
blockchain = blockchain,
|
||||
derivationPath = blockchain.derivationPath(DerivationStyle.LEGACY)?.rawPath,
|
||||
derivationPath = blockchain.derivationPath(derivationStyle)?.rawPath,
|
||||
tokens = emptyList(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.tap.domain.walletStores.implementation
|
|||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.address.AddressType
|
||||
import com.tangem.common.*
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.wallets.legacy.WalletManagersRepository
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
@ -126,8 +127,9 @@ internal class DefaultWalletStoresManager(
|
|||
|
||||
private suspend fun fetchMultiWallets(userWallet: UserWallet): CompletionResult<Unit> {
|
||||
val scanResponse = userWallet.scanResponse
|
||||
val derivationStyle = scanResponse.derivationStyleProvider.getDerivationStyle()
|
||||
val userTokens = withContext(Dispatchers.IO) {
|
||||
userTokensRepository.getUserTokens(scanResponse.card)
|
||||
userTokensRepository.getUserTokens(scanResponse.card, derivationStyle)
|
||||
}
|
||||
val userWalletId = userWallet.walletId
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.HDWalletError
|
||||
|
|
@ -212,13 +213,21 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
return listOf(defaultNetwork) + Blockchain.values()
|
||||
.filter { blockchain ->
|
||||
scanResponse?.card?.supportedBlockchains(scanResponse.cardTypesResolver)
|
||||
?.contains(blockchain) == true &&
|
||||
blockchain.derivationPath(derivationStyle)?.rawPath?.isNotEmpty() == true
|
||||
?.contains(blockchain) == true && isDerivationPathNotEmpty(derivationStyle, blockchain)
|
||||
}
|
||||
.sortedBy(Blockchain::fullName)
|
||||
.map(::createNetworkSelectorItem)
|
||||
}
|
||||
|
||||
private fun isDerivationPathNotEmpty(derivationStyle: DerivationStyle?, blockchain: Blockchain): Boolean {
|
||||
// derivationStyle is null for cards without HD wallets, always return true
|
||||
return if (derivationStyle != null) {
|
||||
blockchain.derivationPath(derivationStyle)?.rawPath?.isNotEmpty() == true
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun createTokenNameInputField(): AddCustomTokenInputField.TokenName {
|
||||
return AddCustomTokenInputField.TokenName(
|
||||
value = "",
|
||||
|
|
@ -288,7 +297,12 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
}
|
||||
.sortedBy(Blockchain::fullName)
|
||||
.mapNotNull {
|
||||
val derivationPath = it.derivationPath(derivationStyle)?.rawPath
|
||||
val derivationPath = if (derivationStyle != null) {
|
||||
it.derivationPath(derivationStyle)?.rawPath
|
||||
} else {
|
||||
// derivationStyle is null for cards without HDWallet, use DerivationStyle.V1
|
||||
it.derivationPath(DerivationStyle.V1)?.rawPath
|
||||
}
|
||||
if (derivationPath?.isNotEmpty() == true) {
|
||||
createDerivationPathSelectorAdditionalItem(
|
||||
blockchain = it,
|
||||
|
|
@ -628,6 +642,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
if (blockchain == null) return null
|
||||
|
||||
val derivationStyle = reduxStateHolder.scanResponse?.derivationStyleProvider?.getDerivationStyle()
|
||||
?: DerivationStyle.V1
|
||||
|
||||
val derivationNetwork = if (blockchain == Blockchain.Unknown) {
|
||||
uiState.form.networkSelectorField.selectedItem.blockchain
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ class DetailsMiddleware {
|
|||
scope.launch {
|
||||
val userWalletId = UserWalletIdBuilder.card(card).build()
|
||||
|
||||
tangemSdkManager.resetToFactorySettings(card.cardId)
|
||||
tangemSdkManager.resetToFactorySettings(card.cardId, true)
|
||||
.flatMap { userWalletsListManager.delete(listOfNotNull(userWalletId)) }
|
||||
.flatMap { tangemSdkManager.deleteSavedUserCodes(setOf(card.cardId)) }
|
||||
.doOnSuccess {
|
||||
|
|
|
|||
|
|
@ -12,20 +12,19 @@ import androidx.compose.ui.platform.ComposeView
|
|||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.tokens.TokensAction
|
||||
import com.tangem.feature.learn2earn.presentation.Learn2earnViewModel
|
||||
import com.tangem.tap.common.analytics.events.IntroductionProcess
|
||||
import com.tangem.tap.features.home.compose.StoriesScreen
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.features.home.redux.HomeState
|
||||
import com.tangem.tap.features.home.redux.Stories
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
@AndroidEntryPoint
|
||||
|
|
@ -33,7 +32,7 @@ class HomeFragment : Fragment(), StoreSubscriber<HomeState> {
|
|||
|
||||
private var homeState: MutableState<HomeState> = mutableStateOf(store.state.homeState)
|
||||
|
||||
private val learn2earnViewModel by activityViewModels<Learn2earnViewModel>()
|
||||
// private val learn2earnViewModel by activityViewModels<Learn2earnViewModel>()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
|
@ -43,10 +42,10 @@ class HomeFragment : Fragment(), StoreSubscriber<HomeState> {
|
|||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
// sync adding story before screen creation
|
||||
if (learn2earnViewModel.uiState.storyScreenState.isVisible) {
|
||||
store.dispatch(HomeAction.InsertStory(position = 0, Stories.OneInchPromo))
|
||||
homeState.value = store.state.homeState
|
||||
}
|
||||
// if (learn2earnViewModel.uiState.storyScreenState.isVisible) {
|
||||
// store.dispatch(HomeAction.InsertStory(position = 0, Stories.OneInchPromo))
|
||||
// homeState.value = store.state.homeState
|
||||
// }
|
||||
return ComposeView(inflater.context).apply {
|
||||
setContent {
|
||||
TangemTheme {
|
||||
|
|
@ -91,10 +90,14 @@ class HomeFragment : Fragment(), StoreSubscriber<HomeState> {
|
|||
private fun ScreenContent() {
|
||||
StoriesScreen(
|
||||
homeState = homeState,
|
||||
onLearn2earnClick = learn2earnViewModel.uiState.storyScreenState.onClick,
|
||||
onLearn2earnClick = {}, // learn2earnViewModel.uiState.storyScreenState.onClick,
|
||||
onScanButtonClick = {
|
||||
Analytics.send(IntroductionProcess.ButtonScanCard())
|
||||
store.dispatch(HomeAction.ReadCard())
|
||||
lifecycleScope.launch {
|
||||
store.dispatch(
|
||||
HomeAction.ReadCard(lifecycleCoroutineScope = lifecycleScope),
|
||||
)
|
||||
}
|
||||
},
|
||||
onShopButtonClick = {
|
||||
Analytics.send(IntroductionProcess.ButtonBuyCards())
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
|||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.learn2earn.presentation.ui.Learn2earnStoriesScreen
|
||||
import com.tangem.tap.features.home.compose.content.*
|
||||
|
|
@ -169,15 +170,27 @@ private fun StoriesScreenContent(config: StoriesScreenContentConfig, modifier: M
|
|||
.height(17.dp)
|
||||
.alpha(if (hideContent) 0f else 1f)
|
||||
.align(Alignment.Start),
|
||||
colorFilter = if (config.currentStory.isDarkBackground) null else ColorFilter.tint(Color.Black),
|
||||
colorFilter = if (config.currentStory.isDarkBackground) {
|
||||
null
|
||||
} else {
|
||||
ColorFilter.tint(TangemColorPalette.Dark6)
|
||||
},
|
||||
)
|
||||
when (config.currentStory) {
|
||||
Stories.OneInchPromo -> Learn2earnStoriesScreen(config.onLearn2earnClick)
|
||||
Stories.TangemIntro -> FirstStoriesContent(isPaused, currentStoryDuration) {
|
||||
Stories.TangemIntro -> FirstStoriesContent(
|
||||
isPaused = isPaused,
|
||||
duration = currentStoryDuration,
|
||||
isNewWalletAvailable = config.currentStory.isNewWalletAvailable,
|
||||
) {
|
||||
hideContent = it
|
||||
}
|
||||
Stories.RevolutionaryWallet -> StoriesRevolutionaryWallet(currentStoryDuration)
|
||||
Stories.UltraSecureBackup -> StoriesUltraSecureBackup(isPaused, currentStoryDuration)
|
||||
is Stories.UltraSecureBackup -> StoriesUltraSecureBackup(
|
||||
isPaused = isPaused,
|
||||
stepDuration = currentStoryDuration,
|
||||
isNewWalletAvailable = config.currentStory.isNewWalletAvailable,
|
||||
)
|
||||
Stories.Currencies -> StoriesCurrencies(isPaused, currentStoryDuration)
|
||||
Stories.Web3 -> StoriesWeb3(isPaused, currentStoryDuration)
|
||||
Stories.WalletForEveryone -> StoriesWalletForEveryone(currentStoryDuration)
|
||||
|
|
|
|||
|
|
@ -2,13 +2,12 @@ package com.tangem.tap.features.home.compose.content
|
|||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
|
@ -56,7 +55,7 @@ fun StoriesRevolutionaryWallet(stepDuration: Int) {
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun StoriesUltraSecureBackup(isPaused: Boolean, stepDuration: Int) {
|
||||
fun StoriesUltraSecureBackup(isPaused: Boolean, stepDuration: Int, isNewWalletAvailable: MutableState<Boolean>) {
|
||||
val subtitleText = buildAnnotatedString {
|
||||
append(stringResource(id = R.string.story_backup_description_1))
|
||||
append(" ")
|
||||
|
|
@ -75,7 +74,11 @@ fun StoriesUltraSecureBackup(isPaused: Boolean, stepDuration: Int) {
|
|||
)
|
||||
},
|
||||
bottomContent = {
|
||||
FloatingCardsContent(isPaused, stepDuration)
|
||||
FloatingCardsContent(
|
||||
isPaused = isPaused,
|
||||
stepDuration = stepDuration,
|
||||
isNewWalletAvailable = isNewWalletAvailable,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -230,7 +233,13 @@ private fun RevolutionaryWalletPreview() {
|
|||
@Preview
|
||||
@Composable
|
||||
private fun UltraSecureBackupPreview() {
|
||||
StoriesUltraSecureBackup(false, 6000)
|
||||
StoriesUltraSecureBackup(
|
||||
false,
|
||||
6000,
|
||||
remember {
|
||||
mutableStateOf(true)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
|
|
|
|||
|
|
@ -32,7 +32,12 @@ import com.tangem.wallet.R
|
|||
|
||||
@Suppress("LongMethod", "ComplexMethod", "MagicNumber")
|
||||
@Composable
|
||||
fun FirstStoriesContent(isPaused: Boolean, duration: Int, onHideContent: (Boolean) -> Unit) {
|
||||
fun FirstStoriesContent(
|
||||
isPaused: Boolean,
|
||||
duration: Int,
|
||||
isNewWalletAvailable: MutableState<Boolean>,
|
||||
onHideContent: (Boolean) -> Unit,
|
||||
) {
|
||||
val bottomInsetsPx = WindowInsets.navigationBars.getBottom(LocalDensity.current)
|
||||
|
||||
val screenState = remember { mutableStateOf(StartingScreenState.INIT) }
|
||||
|
|
@ -115,13 +120,18 @@ fun FirstStoriesContent(isPaused: Boolean, duration: Int, onHideContent: (Boolea
|
|||
.weight(1.2f)
|
||||
.wrapContentSize(),
|
||||
) {
|
||||
val painter = if (isNewWalletAvailable.value) {
|
||||
painterResource(id = R.drawable.img_meet_tangem2)
|
||||
} else {
|
||||
painterResource(id = R.drawable.img_meet_tangem)
|
||||
}
|
||||
StoriesBottomImageAnimation(
|
||||
totalDuration = duration,
|
||||
firstStepDuration = 400,
|
||||
) { modifier ->
|
||||
Image(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
painter = painterResource(id = R.drawable.img_meet_tangem),
|
||||
painter = painter,
|
||||
contentDescription = "Tangem Wallet card",
|
||||
)
|
||||
}
|
||||
|
|
@ -178,5 +188,11 @@ private fun MutableState<StartingScreenState>.isMeetTangemDisplaying(): Boolean
|
|||
@Preview
|
||||
@Composable
|
||||
private fun FirstStoriesPreview() {
|
||||
FirstStoriesContent(false, 8000) {}
|
||||
FirstStoriesContent(
|
||||
false,
|
||||
8000,
|
||||
remember {
|
||||
mutableStateOf(false)
|
||||
},
|
||||
) {}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import androidx.compose.foundation.Image
|
|||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
|
|
@ -21,9 +22,13 @@ import com.tangem.wallet.R
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
fun FloatingCardsContent(isPaused: Boolean, stepDuration: Int) {
|
||||
fun FloatingCardsContent(isPaused: Boolean, stepDuration: Int, isNewWalletAvailable: MutableState<Boolean>) {
|
||||
val bottomInsetsPx = WindowInsets.navigationBars.getBottom(LocalDensity.current)
|
||||
val imageBitmap = asImageBitmap(R.drawable.img_card_placeholder_wallet_2)
|
||||
val imageBitmap = if (isNewWalletAvailable.value) {
|
||||
asImageBitmap(R.drawable.img_card_placeholder_wallet_2)
|
||||
} else {
|
||||
asImageBitmap(R.drawable.card_placeholder_wallet)
|
||||
}
|
||||
val cards = listOf(
|
||||
FloatingCard.first(),
|
||||
FloatingCard.second(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.features.home.redux
|
||||
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Basic
|
||||
|
|
@ -13,12 +14,22 @@ sealed class HomeAction : Action {
|
|||
|
||||
data class InsertStory(val position: Int, val story: Stories) : HomeAction()
|
||||
|
||||
/**
|
||||
* Action for scanning card
|
||||
*
|
||||
* @property analyticsEvent analytics event
|
||||
* @property lifecycleCoroutineScope lifecycle scope. It will be canceled when lifecycle-aware component is
|
||||
* destroyed.
|
||||
*/
|
||||
data class ReadCard(
|
||||
val analyticsEvent: AnalyticsEvent? = Basic.CardWasScanned(AnalyticsParam.ScannedFrom.Introduction),
|
||||
val lifecycleCoroutineScope: LifecycleCoroutineScope,
|
||||
) : HomeAction()
|
||||
|
||||
data class ScanInProgress(val scanInProgress: Boolean) : HomeAction()
|
||||
data class GoToShop(val userCountryCode: String?) : HomeAction()
|
||||
|
||||
data class UpdateCountryCode(val userCountryCode: String) : HomeAction()
|
||||
|
||||
data class ChangeScanCardButtonState(val state: IndeterminateProgressButton) : HomeAction()
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.features.home.redux
|
||||
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import com.tangem.common.doOnFailure
|
||||
import com.tangem.common.doOnResult
|
||||
import com.tangem.common.doOnSuccess
|
||||
|
|
@ -62,7 +63,7 @@ private fun handleHomeAction(action: Action) {
|
|||
store.dispatch(GlobalAction.FetchUserCountry)
|
||||
}
|
||||
is HomeAction.ReadCard -> {
|
||||
readCard(action.analyticsEvent)
|
||||
readCard(action.analyticsEvent, action.lifecycleCoroutineScope)
|
||||
}
|
||||
is HomeAction.GoToShop -> {
|
||||
Analytics.send(Shop.ScreenOpened())
|
||||
|
|
@ -77,32 +78,34 @@ private fun handleHomeAction(action: Action) {
|
|||
}
|
||||
}
|
||||
|
||||
private fun readCard(analyticsEvent: AnalyticsEvent?) = scope.launch {
|
||||
delay(timeMillis = 200)
|
||||
store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy(
|
||||
isBiometricsRequestPolicy = preferencesStorage.shouldSaveAccessCodes,
|
||||
)
|
||||
private fun readCard(analyticsEvent: AnalyticsEvent?, lifecycleCoroutineScope: LifecycleCoroutineScope) {
|
||||
lifecycleCoroutineScope.launch {
|
||||
delay(timeMillis = 200)
|
||||
store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy(
|
||||
isBiometricsRequestPolicy = preferencesStorage.shouldSaveAccessCodes,
|
||||
)
|
||||
|
||||
store.state.daggerGraphState.get(DaggerGraphState::scanCardProcessor).scan(
|
||||
analyticsEvent = analyticsEvent,
|
||||
onProgressStateChange = { showProgress ->
|
||||
if (showProgress) {
|
||||
changeButtonState(ButtonState.PROGRESS)
|
||||
} else {
|
||||
store.state.daggerGraphState.get(DaggerGraphState::scanCardProcessor).scan(
|
||||
analyticsEvent = analyticsEvent,
|
||||
onProgressStateChange = { showProgress ->
|
||||
if (showProgress) {
|
||||
changeButtonState(ButtonState.PROGRESS)
|
||||
} else {
|
||||
changeButtonState(ButtonState.ENABLED)
|
||||
}
|
||||
},
|
||||
onScanStateChange = { scanInProgress ->
|
||||
store.dispatch(HomeAction.ScanInProgress(scanInProgress))
|
||||
},
|
||||
onFailure = {
|
||||
Timber.e(it, "Unable to scan card")
|
||||
changeButtonState(ButtonState.ENABLED)
|
||||
}
|
||||
},
|
||||
onScanStateChange = { scanInProgress ->
|
||||
store.dispatch(HomeAction.ScanInProgress(scanInProgress))
|
||||
},
|
||||
onFailure = {
|
||||
Timber.e(it, "Unable to scan card")
|
||||
changeButtonState(ButtonState.ENABLED)
|
||||
},
|
||||
onSuccess = { scanResponse ->
|
||||
proceedWithScanResponse(scanResponse)
|
||||
},
|
||||
)
|
||||
},
|
||||
onSuccess = { scanResponse ->
|
||||
proceedWithScanResponse(scanResponse)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithScanResponse(scanResponse: ScanResponse) = scope.launch {
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ object HomeReducer {
|
|||
fun reduce(action: Action, state: AppState): HomeState = internalReduce(action, state)
|
||||
}
|
||||
|
||||
private fun internalReduce(action: Action, state: AppState): HomeState {
|
||||
if (action !is HomeAction) return state.homeState
|
||||
private fun internalReduce(action: Action, appState: AppState): HomeState {
|
||||
if (action !is HomeAction) return appState.homeState
|
||||
|
||||
var state = state.homeState
|
||||
var state = appState.homeState
|
||||
when (action) {
|
||||
is HomeAction.InsertStory -> {
|
||||
state = state.copy(
|
||||
|
|
@ -25,6 +25,9 @@ private fun internalReduce(action: Action, state: AppState): HomeState {
|
|||
is HomeAction.ChangeScanCardButtonState -> {
|
||||
state = state.copy(btnScanState = action.state)
|
||||
}
|
||||
is HomeAction.UpdateCountryCode -> {
|
||||
state.onCountryCodeUpdate(state, action.userCountryCode)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
package com.tangem.tap.features.home.redux
|
||||
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import com.tangem.tap.common.entities.IndeterminateProgressButton
|
||||
import com.tangem.tap.features.send.redux.states.ButtonState
|
||||
import com.tangem.tap.features.wallet.redux.ProgressState
|
||||
import org.rekotlin.StateType
|
||||
import java.util.Locale
|
||||
|
||||
data class HomeState(
|
||||
val scanInProgress: Boolean = false,
|
||||
|
|
@ -19,7 +22,16 @@ data class HomeState(
|
|||
|
||||
fun stepOf(story: Stories): Int = stories.indexOf(story)
|
||||
|
||||
fun onCountryCodeUpdate(homeState: HomeState, countryCode: String) {
|
||||
val isNewWalletAvailable = !(countryCode == RUSSIA_COUNTRY_CODE || countryCode == BELARUS_COUNTRY_CODE)
|
||||
homeState.stories.forEach {
|
||||
it.isNewWalletAvailable.value = isNewWalletAvailable
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val RUSSIA_COUNTRY_CODE = "ru"
|
||||
private const val BELARUS_COUNTRY_CODE = "by"
|
||||
fun initDefaultStories(): List<Stories> = listOf(
|
||||
Stories.TangemIntro,
|
||||
Stories.RevolutionaryWallet,
|
||||
|
|
@ -28,12 +40,18 @@ data class HomeState(
|
|||
Stories.Web3,
|
||||
Stories.WalletForEveryone,
|
||||
)
|
||||
|
||||
fun isNewWalletAvailableInit(): Boolean {
|
||||
val locale = Locale.getDefault().language
|
||||
return !(locale == RUSSIA_COUNTRY_CODE || locale == BELARUS_COUNTRY_CODE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class Stories(
|
||||
val isDarkBackground: Boolean,
|
||||
val duration: Int,
|
||||
val isNewWalletAvailable: MutableState<Boolean> = mutableStateOf(HomeState.isNewWalletAvailableInit()),
|
||||
) {
|
||||
object OneInchPromo : Stories(true, duration = 8000)
|
||||
object TangemIntro : Stories(true, duration = 8000)
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ import android.content.Intent
|
|||
import android.nfc.NfcAdapter
|
||||
import android.nfc.Tag
|
||||
import android.os.Build
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.features.intentHandler.IntentHandler
|
||||
import com.tangem.tap.features.welcome.redux.WelcomeAction
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -18,6 +18,7 @@ import kotlinx.coroutines.launch
|
|||
*/
|
||||
class BackgroundScanIntentHandler(
|
||||
private val hasSavedUserWalletsProvider: () -> Boolean,
|
||||
private val lifecycleCoroutineScope: LifecycleCoroutineScope,
|
||||
) : IntentHandler {
|
||||
|
||||
private val nfcActions = arrayOf(
|
||||
|
|
@ -40,12 +41,12 @@ class BackgroundScanIntentHandler(
|
|||
intent.action = null
|
||||
if (hasSavedUserWalletsProvider.invoke()) {
|
||||
// TODO: Remove delay after [REDACTED_JIRA]
|
||||
scope.launch {
|
||||
lifecycleCoroutineScope.launch {
|
||||
delay(timeMillis = 200)
|
||||
store.dispatchWithMain(WelcomeAction.ProceedWithCard)
|
||||
store.dispatchWithMain(WelcomeAction.ProceedWithCard(lifecycleCoroutineScope))
|
||||
}
|
||||
} else {
|
||||
store.dispatchWithMain(HomeAction.ReadCard())
|
||||
store.dispatchWithMain(HomeAction.ReadCard(lifecycleCoroutineScope = lifecycleCoroutineScope))
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.redux
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.feature.onboarding.data.model.CreateWalletResponse
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.analytics.SeedPhraseSource
|
||||
|
|
@ -12,11 +13,12 @@ sealed class OnboardingWalletAction : Action {
|
|||
object GetToCreateWalletStep : OnboardingWalletAction()
|
||||
object CreateWallet : OnboardingWalletAction()
|
||||
data class WalletWasCreated(
|
||||
val shouldSendAnalyticsEvent: Boolean,
|
||||
val result: CompletionResult<CreateProductWalletTaskResponse>,
|
||||
) : OnboardingWalletAction()
|
||||
|
||||
object Done : OnboardingWalletAction()
|
||||
object FinishOnboarding : OnboardingWalletAction()
|
||||
data class FinishOnboarding(val lifecycleCoroutineScope: LifecycleCoroutineScope) : OnboardingWalletAction()
|
||||
|
||||
object ResumeBackup : OnboardingWalletAction()
|
||||
|
||||
|
|
|
|||
|
|
@ -104,14 +104,16 @@ private fun handleWalletAction(action: Action) {
|
|||
scanResponse ?: return
|
||||
scope.launch {
|
||||
val result = tangemSdkManager.createProductWallet(scanResponse)
|
||||
store.dispatchOnMain(OnboardingWalletAction.WalletWasCreated(result))
|
||||
store.dispatchOnMain(OnboardingWalletAction.WalletWasCreated(true, result))
|
||||
}
|
||||
}
|
||||
is OnboardingWalletAction.WalletWasCreated -> {
|
||||
scanResponse ?: return
|
||||
when (val result = action.result) {
|
||||
is CompletionResult.Success -> {
|
||||
Analytics.send(Onboarding.CreateWallet.WalletCreatedSuccessfully())
|
||||
if (action.shouldSendAnalyticsEvent) {
|
||||
Analytics.send(Onboarding.CreateWallet.WalletCreatedSuccessfully())
|
||||
}
|
||||
// here we must use updated scanResponse after createWallet & derivation
|
||||
val updatedResponse = globalState.onboardingState.onboardingManager.scanResponse.copy(
|
||||
card = result.data.card,
|
||||
|
|
@ -144,12 +146,12 @@ private fun handleWalletAction(action: Action) {
|
|||
is CompletionResult.Failure -> Unit
|
||||
}
|
||||
}
|
||||
OnboardingWalletAction.FinishOnboarding -> {
|
||||
is OnboardingWalletAction.FinishOnboarding -> {
|
||||
store.dispatch(GlobalAction.Onboarding.Stop)
|
||||
|
||||
if (scanResponse == null) {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatch(HomeAction.ReadCard())
|
||||
store.dispatch(HomeAction.ReadCard(lifecycleCoroutineScope = action.lifecycleCoroutineScope))
|
||||
} else {
|
||||
val backupState = store.state.onboardingWalletState.backupState
|
||||
val updatedScanResponse = updateScanResponseAfterBackup(scanResponse, backupState)
|
||||
|
|
@ -268,7 +270,8 @@ private fun handleWallet2Action(action: OnboardingWallet2Action) {
|
|||
CompletionResult.Failure(mediateResult.error)
|
||||
}
|
||||
}
|
||||
store.dispatchOnMain(OnboardingWalletAction.WalletWasCreated(result))
|
||||
// do not send analytics event for wallet2 flow, cause its already sent
|
||||
store.dispatchOnMain(OnboardingWalletAction.WalletWasCreated(false, result))
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
|
|
@ -457,7 +460,7 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction)
|
|||
}
|
||||
|
||||
is BackupAction.ResetBackupCard -> {
|
||||
scope.launch { tangemSdkManager.resetToFactorySettings(action.cardId) }
|
||||
scope.launch { tangemSdkManager.resetToFactorySettings(action.cardId, false) }
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import android.widget.ImageView
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.MenuProvider
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.transition.TransitionInflater
|
||||
import androidx.transition.TransitionManager
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
|
|
@ -21,6 +22,7 @@ import com.tangem.common.CardIdFormatter
|
|||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.CardIdDisplayFormat
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.feature.onboarding.data.model.CreateWalletResponse
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.analytics.SeedPhraseSource
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseMediator
|
||||
|
|
@ -64,6 +66,7 @@ class OnboardingWalletFragment :
|
|||
private val seedPhraseViewModel by viewModels<SeedPhraseViewModel>()
|
||||
|
||||
private lateinit var cardsWidget: WalletCardsWidget
|
||||
private var seedPhraseRouter: SeedPhraseRouter? = null
|
||||
private var accessCodeDialog: AccessCodeDialog? = null
|
||||
|
||||
private lateinit var animator: BackupAnimator
|
||||
|
|
@ -77,7 +80,9 @@ class OnboardingWalletFragment :
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
seedPhraseViewModel.setRouter(makeSeedPhraseRouter())
|
||||
val newSeedPhraseRouter = makeSeedPhraseRouter()
|
||||
seedPhraseRouter = newSeedPhraseRouter
|
||||
seedPhraseViewModel.setRouter(newSeedPhraseRouter)
|
||||
seedPhraseViewModel.setMediator(makeSeedPhraseMediator())
|
||||
}
|
||||
|
||||
|
|
@ -172,6 +177,12 @@ class OnboardingWalletFragment :
|
|||
when {
|
||||
state.wallet2State != null -> {
|
||||
seedPhraseStateHandler.newState(this, state, seedPhraseViewModel)
|
||||
state.cardArtworkUri?.let {
|
||||
seedPhraseViewModel.setCardArtworkUri(it.toString())
|
||||
loadImageIntoImageView(it, binding.imvFrontCard)
|
||||
loadImageIntoImageView(it, binding.imvFirstBackupCard)
|
||||
loadImageIntoImageView(it, binding.imvSecondBackupCard)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
loadImageIntoImageView(state.cardArtworkUri, binding.imvFrontCard)
|
||||
|
|
@ -195,7 +206,6 @@ class OnboardingWalletFragment :
|
|||
OnboardingWalletStep.CreateWallet -> setupCreateWalletState()
|
||||
OnboardingWalletStep.Backup -> setBackupState(
|
||||
state = state.backupState,
|
||||
isWallet2 = state.wallet2State != null,
|
||||
)
|
||||
|
||||
else -> {}
|
||||
|
|
@ -220,9 +230,9 @@ class OnboardingWalletFragment :
|
|||
animator.setupCreateWalletState()
|
||||
}
|
||||
|
||||
private fun setBackupState(state: BackupState, isWallet2: Boolean) {
|
||||
private fun setBackupState(state: BackupState) {
|
||||
when (state.backupStep) {
|
||||
BackupStep.InitBackup -> showBackupIntro(state, isWallet2)
|
||||
BackupStep.InitBackup -> showBackupIntro(state)
|
||||
BackupStep.ScanOriginCard -> showScanOriginCard()
|
||||
BackupStep.AddBackupCards -> showAddBackupCards(state)
|
||||
BackupStep.SetAccessCode -> showSetAccessCode()
|
||||
|
|
@ -234,7 +244,7 @@ class OnboardingWalletFragment :
|
|||
}
|
||||
}
|
||||
|
||||
private fun showBackupIntro(state: BackupState, isWallet2: Boolean) = with(binding) {
|
||||
private fun showBackupIntro(state: BackupState) = with(binding) {
|
||||
imvFirstBackupCard.show()
|
||||
imvSecondBackupCard.show()
|
||||
|
||||
|
|
@ -250,7 +260,7 @@ class OnboardingWalletFragment :
|
|||
|
||||
btnWalletAlternativeAction.text = getText(R.string.onboarding_button_skip_backup)
|
||||
btnWalletAlternativeAction.setOnClickListener { store.dispatch(BackupAction.SkipBackup) }
|
||||
btnWalletAlternativeAction.show(state.canSkipBackup && !isWallet2)
|
||||
btnWalletAlternativeAction.show(state.canSkipBackup)
|
||||
}
|
||||
animator.showBackupIntro(state)
|
||||
}
|
||||
|
|
@ -419,7 +429,9 @@ class OnboardingWalletFragment :
|
|||
layoutButtonsCommon.btnWalletAlternativeAction.hide()
|
||||
layoutButtonsCommon.btnWalletMainAction.setOnClickListener {
|
||||
showConfetti(false)
|
||||
store.dispatch(OnboardingWalletAction.FinishOnboarding)
|
||||
lifecycleScope.launch {
|
||||
store.dispatch(OnboardingWalletAction.FinishOnboarding(lifecycleCoroutineScope = lifecycleScope))
|
||||
}
|
||||
}
|
||||
|
||||
animator.showSuccess {
|
||||
|
|
@ -443,6 +455,19 @@ class OnboardingWalletFragment :
|
|||
}
|
||||
|
||||
override fun handleOnBackPressed() {
|
||||
// workaround to use right navigation back for toolbar back btn on seed phrase flow
|
||||
val isWallet2 =
|
||||
store.state.globalState.onboardingState.onboardingManager?.scanResponse?.cardTypesResolver?.isWallet2()
|
||||
?: false
|
||||
val seedPhraseRouter = seedPhraseRouter
|
||||
if (seedPhraseRouter != null && isWallet2) {
|
||||
seedPhraseRouter.navigateBack()
|
||||
} else {
|
||||
legacyOnBackHandler()
|
||||
}
|
||||
}
|
||||
|
||||
private fun legacyOnBackHandler() {
|
||||
store.dispatch(OnboardingWalletAction.OnBackPressed)
|
||||
}
|
||||
|
||||
|
|
@ -453,7 +478,7 @@ class OnboardingWalletFragment :
|
|||
}
|
||||
|
||||
private fun makeSeedPhraseRouter(): SeedPhraseRouter = SeedPhraseRouter(
|
||||
onBack = ::handleOnBackPressed,
|
||||
onBack = ::legacyOnBackHandler,
|
||||
onOpenChat = {
|
||||
store.dispatch(GlobalAction.OpenChat(SupportInfo()))
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ package com.tangem.tap.features.onboarding.products.wallet.ui.dialogs
|
|||
|
||||
import android.content.Context
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.tap.common.analytics.events.Onboarding
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction
|
||||
import com.tangem.tap.store
|
||||
|
|
@ -13,9 +15,10 @@ object ResetBackupCardDialog {
|
|||
setTitle(R.string.common_attention)
|
||||
setMessage(R.string.onboarding_linking_error_card_with_wallets)
|
||||
setPositiveButton(R.string.common_cancel) { _, _ ->
|
||||
/* no-op */
|
||||
Analytics.send(Onboarding.Backup.ResetCancelEvent)
|
||||
}
|
||||
setNegativeButton(R.string.card_settings_action_sheet_reset) { _, _ ->
|
||||
Analytics.send(Onboarding.Backup.ResetPerformEvent)
|
||||
store.dispatch(BackupAction.ResetBackupCard(cardId))
|
||||
}
|
||||
setOnDismissListener {
|
||||
|
|
|
|||
|
|
@ -155,6 +155,13 @@ sealed class SendAction : SendScreenAction {
|
|||
val onOk: () -> Unit,
|
||||
) : Dialog()
|
||||
|
||||
data class ChiaWarningDialog(
|
||||
val blockchainName: String,
|
||||
val maxOutputs: Int,
|
||||
val maxAmount: BigDecimal,
|
||||
val onOk: () -> Unit,
|
||||
) : Dialog()
|
||||
|
||||
sealed class SendTransactionFails : Dialog() {
|
||||
data class CardSdkError(val error: TangemSdkError) : Dialog()
|
||||
data class BlockchainSdkError(val error: com.tangem.blockchain.common.BlockchainSdkError) : Dialog()
|
||||
|
|
|
|||
|
|
@ -307,6 +307,19 @@ private fun sendTransaction(
|
|||
),
|
||||
)
|
||||
}
|
||||
is BlockchainSdkError.Chia.UtxoAmountError -> {
|
||||
dispatch(
|
||||
SendAction.Dialog.ChiaWarningDialog(
|
||||
blockchainName = Blockchain.Chia.fullName,
|
||||
maxOutputs = error.maxOutputs,
|
||||
maxAmount = error.maxAmount,
|
||||
onOk = {
|
||||
dispatch(AmountAction.SetAmount(error.maxAmount, isUserInput = false))
|
||||
dispatch(AmountActionUi.CheckAmountToSend)
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
when {
|
||||
error.customMessage.contains(DemoTransactionSender.ID) -> {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ private class SendReducer : SendInternalReducer {
|
|||
}
|
||||
is SendAction.Dialog.TezosWarningDialog -> sendState.copy(dialog = action)
|
||||
is SendAction.Dialog.KaspaWarningDialog -> sendState.copy(dialog = action)
|
||||
is SendAction.Dialog.ChiaWarningDialog -> sendState.copy(dialog = action)
|
||||
is SendAction.Dialog.SendTransactionFails.CardSdkError -> sendState.copy(dialog = action)
|
||||
is SendAction.Dialog.SendTransactionFails.BlockchainSdkError -> sendState.copy(dialog = action)
|
||||
is SendAction.Dialog.RequestFeeError -> sendState.copy(dialog = action)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
package com.tangem.tap.features.send.ui.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.tangem.tap.features.send.redux.SendAction
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
|
||||
// TODO: [REDACTED_JIRA]
|
||||
object ChiaWarningDialog {
|
||||
|
||||
fun create(context: Context, dialog: SendAction.Dialog.ChiaWarningDialog): AlertDialog {
|
||||
return AlertDialog.Builder(context).apply {
|
||||
setTitle(R.string.common_warning)
|
||||
setMessage(
|
||||
context.getString(
|
||||
R.string.common_utxo_validate_withdrawal_message_warning,
|
||||
dialog.blockchainName,
|
||||
dialog.maxOutputs,
|
||||
dialog.maxAmount.toPlainString(),
|
||||
),
|
||||
)
|
||||
setPositiveButton(R.string.common_ok) { _, _ ->
|
||||
dialog.onOk()
|
||||
}
|
||||
setOnDismissListener {
|
||||
store.dispatch(SendAction.Dialog.Hide)
|
||||
}
|
||||
}
|
||||
.create()
|
||||
}
|
||||
}
|
||||
|
|
@ -18,10 +18,7 @@ import com.tangem.tap.features.send.redux.SendAction
|
|||
import com.tangem.tap.features.send.redux.states.*
|
||||
import com.tangem.tap.features.send.ui.FeeUiHelper
|
||||
import com.tangem.tap.features.send.ui.SendFragment
|
||||
import com.tangem.tap.features.send.ui.dialogs.KaspaWarningDialog
|
||||
import com.tangem.tap.features.send.ui.dialogs.RequestFeeErrorDialog
|
||||
import com.tangem.tap.features.send.ui.dialogs.SendTransactionFailsDialog
|
||||
import com.tangem.tap.features.send.ui.dialogs.TezosWarningDialog
|
||||
import com.tangem.tap.features.send.ui.dialogs.*
|
||||
import com.tangem.tap.features.wallet.redux.ProgressState
|
||||
import com.tangem.tap.features.wallet.redux.utils.ROUGH_SIGN
|
||||
import com.tangem.tap.features.wallet.redux.utils.UNKNOWN_AMOUNT_SIGN
|
||||
|
|
@ -124,6 +121,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("ComplexMethod")
|
||||
private fun handleSendScreen(fg: SendFragment, state: SendState) = with(fg.binding) {
|
||||
when (state.dialog) {
|
||||
is SendAction.Dialog.TezosWarningDialog -> {
|
||||
|
|
@ -138,6 +136,12 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
dialog?.show()
|
||||
}
|
||||
}
|
||||
is SendAction.Dialog.ChiaWarningDialog -> {
|
||||
if (dialog == null) {
|
||||
dialog = ChiaWarningDialog.create(fg.requireContext(), state.dialog)
|
||||
dialog?.show()
|
||||
}
|
||||
}
|
||||
is SendAction.Dialog.SendTransactionFails.CardSdkError -> {
|
||||
if (dialog == null) {
|
||||
dialog = SendTransactionFailsDialog.create(fg.requireContext(), state.dialog)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.features.wallet.redux
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.address.AddressType
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
|
@ -73,7 +74,10 @@ sealed class WalletAction : Action {
|
|||
class CheckRemainingSignatures(val remainingSignatures: Int?) : Warnings()
|
||||
}
|
||||
|
||||
data class Scan(val onScanSuccessEvent: AnalyticsEvent?) : WalletAction()
|
||||
data class Scan(
|
||||
val onScanSuccessEvent: AnalyticsEvent?,
|
||||
val lifecycleScope: LifecycleCoroutineScope,
|
||||
) : WalletAction()
|
||||
|
||||
data class Send(val amount: Amount? = null) : WalletAction()
|
||||
|
||||
|
|
@ -109,7 +113,7 @@ sealed class WalletAction : Action {
|
|||
data class ExploreAddress(val exploreUrl: String, val context: Context) : WalletAction()
|
||||
|
||||
object CreateWallet : WalletAction()
|
||||
object ChangeWallet : WalletAction()
|
||||
data class ChangeWallet(val lifecycleScope: LifecycleCoroutineScope) : WalletAction()
|
||||
object ShowSaveWalletIfNeeded : WalletAction()
|
||||
|
||||
sealed class TradeCryptoAction : WalletAction() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.features.wallet.redux.middlewares
|
||||
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
|
|
@ -115,9 +116,9 @@ class WalletMiddleware {
|
|||
}
|
||||
is WalletAction.Scan -> {
|
||||
store.dispatch(NavigationAction.PopBackTo(AppScreen.Home))
|
||||
scope.launch {
|
||||
action.lifecycleScope.launch {
|
||||
delay(timeMillis = 700)
|
||||
store.dispatchOnMain(HomeAction.ReadCard(action.onScanSuccessEvent))
|
||||
store.dispatchOnMain(HomeAction.ReadCard(action.onScanSuccessEvent, action.lifecycleScope))
|
||||
}
|
||||
}
|
||||
is WalletAction.LoadData,
|
||||
|
|
@ -226,7 +227,7 @@ class WalletMiddleware {
|
|||
showSaveWalletIfNeeded()
|
||||
}
|
||||
is WalletAction.ChangeWallet -> {
|
||||
changeWallet(walletState)
|
||||
changeWallet(walletState, action.lifecycleScope)
|
||||
}
|
||||
is WalletAction.UserWalletChanged -> Unit
|
||||
is WalletAction.WalletStoresChanged -> {
|
||||
|
|
@ -379,7 +380,7 @@ class WalletMiddleware {
|
|||
}
|
||||
}
|
||||
|
||||
private fun changeWallet(state: WalletState) {
|
||||
private fun changeWallet(state: WalletState, lifecycleScope: LifecycleCoroutineScope) {
|
||||
when {
|
||||
state.canSaveUserWallets -> {
|
||||
Analytics.send(MainScreen.ButtonMyWallets())
|
||||
|
|
@ -387,7 +388,12 @@ class WalletMiddleware {
|
|||
}
|
||||
else -> {
|
||||
Analytics.send(MainScreen.ButtonScanCard())
|
||||
store.dispatch(WalletAction.Scan(Basic.CardWasScanned(AnalyticsParam.ScannedFrom.Main)))
|
||||
store.dispatch(
|
||||
WalletAction.Scan(
|
||||
onScanSuccessEvent = Basic.CardWasScanned(AnalyticsParam.ScannedFrom.Main),
|
||||
lifecycleScope = lifecycleScope,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,7 @@ import android.view.View
|
|||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.flowWithLifecycle
|
||||
|
|
@ -26,16 +24,12 @@ import com.tangem.core.analytics.Analytics
|
|||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.core.ui.extensions.setStatusBarColor
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.utils.OneTouchClickListener
|
||||
import com.tangem.datasource.connection.NetworkConnectionManager
|
||||
import com.tangem.feature.learn2earn.presentation.Learn2earnViewModel
|
||||
import com.tangem.feature.learn2earn.presentation.ui.Learn2earnMainPageScreen
|
||||
import com.tangem.feature.swap.api.SwapFeatureToggleManager
|
||||
import com.tangem.feature.swap.domain.SwapInteractor
|
||||
import com.tangem.tap.MainActivity
|
||||
import com.tangem.tap.common.analytics.events.Portfolio
|
||||
import com.tangem.tap.common.extensions.beginDelayedTransition
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.recyclerView.SpaceItemDecoration
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
|
|
@ -78,7 +72,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), SafeStoreSubscriber<W
|
|||
|
||||
private var walletView: WalletView = MultiWalletView()
|
||||
|
||||
private val learn2earnViewModel by activityViewModels<Learn2earnViewModel>()
|
||||
// private val learn2earnViewModel by activityViewModels<Learn2earnViewModel>()
|
||||
private val viewModel by viewModels<WalletViewModel>()
|
||||
|
||||
private val totalBalanceWatcher = modelWatcher {
|
||||
|
|
@ -108,7 +102,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), SafeStoreSubscriber<W
|
|||
val inflater = TransitionInflater.from(requireContext())
|
||||
enterTransition = inflater.inflateTransition(R.transition.slide_right)
|
||||
exitTransition = inflater.inflateTransition(R.transition.fade)
|
||||
learn2earnViewModel.onMainScreenCreated()
|
||||
// learn2earnViewModel.onMainScreenCreated()
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
|
|
@ -140,7 +134,11 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), SafeStoreSubscriber<W
|
|||
(activity as? AppCompatActivity)?.setSupportActionBar(binding.toolbar)
|
||||
|
||||
binding.toolbar.setNavigationOnClickListener(
|
||||
OneTouchClickListener { store.dispatch(WalletAction.ChangeWallet) },
|
||||
OneTouchClickListener {
|
||||
lifecycleScope.launch {
|
||||
store.dispatch(WalletAction.ChangeWallet(lifecycleScope))
|
||||
}
|
||||
},
|
||||
)
|
||||
setupWarningsRecyclerView()
|
||||
walletView.changeWalletView(this, binding)
|
||||
|
|
@ -207,27 +205,27 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), SafeStoreSubscriber<W
|
|||
if (state.canSaveUserWallets) R.drawable.ic_wallet_24 else R.drawable.ic_tap_card_24,
|
||||
)
|
||||
|
||||
showLearn2earnView()
|
||||
// showLearn2earnView()
|
||||
}
|
||||
|
||||
private fun showLearn2earnView() {
|
||||
val isShowing = learn2earnViewModel.uiState.mainScreenState.isVisible
|
||||
if (!isShowing) return
|
||||
|
||||
binding.composeLearnToEarnContainer.show(true) { binding.llWarnings.beginDelayedTransition() }
|
||||
binding.composeLearnToEarnContainer.apply {
|
||||
setViewCompositionStrategy(
|
||||
strategy = ViewCompositionStrategy.DisposeOnLifecycleDestroyed(
|
||||
lifecycle = this@WalletFragment.lifecycle,
|
||||
),
|
||||
)
|
||||
setContent {
|
||||
TangemTheme {
|
||||
Learn2earnMainPageScreen(learn2earnViewModel.uiState)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// private fun showLearn2earnView() {
|
||||
// val isShowing = learn2earnViewModel.uiState.mainScreenState.isVisible
|
||||
// if (!isShowing) return
|
||||
//
|
||||
// binding.composeLearnToEarnContainer.show(true) { binding.llWarnings.beginDelayedTransition() }
|
||||
// binding.composeLearnToEarnContainer.apply {
|
||||
// setViewCompositionStrategy(
|
||||
// strategy = ViewCompositionStrategy.DisposeOnLifecycleDestroyed(
|
||||
// lifecycle = [REDACTED_EMAIL],
|
||||
// ),
|
||||
// )
|
||||
// setContent {
|
||||
// TangemTheme {
|
||||
// Learn2earnMainPageScreen(learn2earnViewModel.uiState)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
private fun setupPullToRefreshLayout(state: WalletState) {
|
||||
setupErrorPullToRefreshState(state)
|
||||
|
|
@ -267,7 +265,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), SafeStoreSubscriber<W
|
|||
private fun refreshWalletData() {
|
||||
Analytics.send(Portfolio.Refreshed())
|
||||
store.dispatch(WalletAction.LoadData.Refresh)
|
||||
learn2earnViewModel.onMainScreenRefreshed()
|
||||
// learn2earnViewModel.onMainScreenRefreshed()
|
||||
}
|
||||
|
||||
private fun showWarningsIfPresent(warnings: List<WarningMessage>) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.features.welcome.redux
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import com.tangem.common.core.TangemError
|
||||
import org.rekotlin.Action
|
||||
|
||||
|
|
@ -10,7 +11,7 @@ internal sealed interface WelcomeAction : Action {
|
|||
data class Error(val error: TangemError) : WelcomeAction
|
||||
}
|
||||
|
||||
object ProceedWithCard : WelcomeAction {
|
||||
data class ProceedWithCard(val lifecycleCoroutineScope: LifecycleCoroutineScope) : WelcomeAction {
|
||||
object Success : WelcomeAction
|
||||
data class Error(val error: TangemError) : WelcomeAction
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.features.welcome.redux
|
||||
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.doOnFailure
|
||||
import com.tangem.common.doOnResult
|
||||
|
|
@ -40,7 +41,7 @@ internal class WelcomeMiddleware {
|
|||
private fun handleAction(action: WelcomeAction, state: WelcomeState) {
|
||||
when (action) {
|
||||
is WelcomeAction.ProceedWithBiometrics -> proceedWithBiometrics(state)
|
||||
is WelcomeAction.ProceedWithCard -> proceedWithCard(state)
|
||||
is WelcomeAction.ProceedWithCard -> proceedWithCard(state, action.lifecycleCoroutineScope)
|
||||
is WelcomeAction.ClearUserWallets -> disableUserWalletsSaving()
|
||||
else -> Unit
|
||||
}
|
||||
|
|
@ -77,25 +78,27 @@ internal class WelcomeMiddleware {
|
|||
}
|
||||
}
|
||||
|
||||
private fun proceedWithCard(state: WelcomeState) = scope.launch {
|
||||
scanCardInternal { scanResponse ->
|
||||
val userWallet = UserWalletBuilder(scanResponse).build() ?: return@scanCardInternal
|
||||
private fun proceedWithCard(state: WelcomeState, lifecycleCoroutineScope: LifecycleCoroutineScope) {
|
||||
lifecycleCoroutineScope.launch {
|
||||
scanCardInternal { scanResponse ->
|
||||
val userWallet = UserWalletBuilder(scanResponse).build() ?: return@scanCardInternal
|
||||
|
||||
userWalletsListManager.save(userWallet, canOverride = true)
|
||||
.doOnFailure { error ->
|
||||
Timber.e(error, "Unable to save user wallet")
|
||||
store.dispatchOnMain(WelcomeAction.ProceedWithCard.Error(error))
|
||||
}
|
||||
.doOnSuccess {
|
||||
store.dispatchOnMain(SignInAction.SetSignInType(Basic.SignedIn.SignInType.Card))
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Wallet))
|
||||
store.dispatchOnMain(WelcomeAction.ProceedWithCard.Success)
|
||||
store.onUserWalletSelected(userWallet = userWallet)
|
||||
|
||||
state.intent?.let {
|
||||
WalletConnectLinkIntentHandler().handleIntent(it)
|
||||
userWalletsListManager.save(userWallet, canOverride = true)
|
||||
.doOnFailure { error ->
|
||||
Timber.e(error, "Unable to save user wallet")
|
||||
store.dispatchOnMain(WelcomeAction.ProceedWithCard.Error(error))
|
||||
}
|
||||
}
|
||||
.doOnSuccess {
|
||||
store.dispatchOnMain(SignInAction.SetSignInType(Basic.SignedIn.SignInType.Card))
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Wallet))
|
||||
store.dispatchOnMain(WelcomeAction.ProceedWithCard.Success)
|
||||
store.onUserWalletSelected(userWallet = userWallet)
|
||||
|
||||
state.intent?.let {
|
||||
WalletConnectLinkIntentHandler().handleIntent(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.ui.components.SystemBarsEffect
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
|
@ -65,7 +66,7 @@ internal class WelcomeFragment : ComposeFragment() {
|
|||
showUnlockProgress = state.showUnlockWithBiometricsProgress,
|
||||
showScanCardProgress = state.showUnlockWithCardProgress,
|
||||
onUnlockClick = viewModel::unlockWallets,
|
||||
onScanCardClick = viewModel::scanCard,
|
||||
onScanCardClick = { viewModel.scanCard(lifecycleCoroutineScope = lifecycleScope) },
|
||||
)
|
||||
|
||||
SnackbarHost(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.features.welcome.ui
|
||||
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.core.analytics.Analytics
|
||||
|
|
@ -30,9 +31,9 @@ internal class WelcomeViewModel : ViewModel(), StoreSubscriber<WelcomeState> {
|
|||
store.dispatch(WelcomeAction.ProceedWithBiometrics)
|
||||
}
|
||||
|
||||
fun scanCard() {
|
||||
fun scanCard(lifecycleCoroutineScope: LifecycleCoroutineScope) {
|
||||
Analytics.send(SignIn.ButtonCardSignIn())
|
||||
store.dispatch(WelcomeAction.ProceedWithCard)
|
||||
store.dispatch(WelcomeAction.ProceedWithCard(lifecycleCoroutineScope))
|
||||
}
|
||||
|
||||
fun closeError() {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class UserWalletManagerImpl(
|
|||
val userTokensRepository =
|
||||
requireNotNull(appStateHolder.userTokensRepository) { "userTokensRepository is null" }
|
||||
return if (card != null) {
|
||||
userTokensRepository.getUserTokens(card)
|
||||
userTokensRepository.getUserTokens(card, null) // refactor in [REDACTED_JIRA]
|
||||
.filter {
|
||||
val checkCustom = if (isExcludeCustom) {
|
||||
!it.isCustomCurrency(null)
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 164 KiB |
BIN
app/src/main/res/drawable-hdpi/img_meet_tangem2.webp
Normal file
|
After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 85 KiB |
BIN
app/src/main/res/drawable-mdpi/img_meet_tangem2.webp
Normal file
|
After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 222 KiB After Width: | Height: | Size: 266 KiB |
BIN
app/src/main/res/drawable-xhdpi/img_meet_tangem2.webp
Normal file
|
After Width: | Height: | Size: 222 KiB |
|
Before Width: | Height: | Size: 484 KiB After Width: | Height: | Size: 512 KiB |
BIN
app/src/main/res/drawable-xxhdpi/img_meet_tangem2.webp
Normal file
|
After Width: | Height: | Size: 484 KiB |
|
Before Width: | Height: | Size: 818 KiB After Width: | Height: | Size: 818 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/meet_tangem.webp
Normal file
|
After Width: | Height: | Size: 819 KiB |
21
app/src/main/res/drawable/ic_launcher_foreground.xml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="146"
|
||||
android:viewportHeight="146">
|
||||
<group
|
||||
android:scaleX="0.33"
|
||||
android:scaleY="0.33"
|
||||
android:translateX="48.91"
|
||||
android:translateY="48.91">
|
||||
<path
|
||||
android:fillColor="#1E1E1E"
|
||||
android:pathData="M103.72,0H42.28C32.59,0 27.75,0 24.05,1.89C20.79,3.55 18.14,6.19 16.49,9.45C14.6,13.15 14.6,17.99 14.6,27.68V37.96H131.4V27.68C131.4,17.99 131.4,13.15 129.51,9.45C127.85,6.19 125.21,3.54 121.96,1.89C118.25,0 113.41,0 103.72,0Z" />
|
||||
<path
|
||||
android:fillColor="#1E1E1E"
|
||||
android:pathData="M92.46,70.08H131.4V118.32C131.4,128.01 131.4,132.85 129.51,136.55C127.85,139.81 125.21,142.46 121.95,144.11C118.25,146 113.4,146 103.71,146H92.47L92.46,70.08Z" />
|
||||
<path
|
||||
android:fillColor="#1E1E1E"
|
||||
android:pathData="M14.6,70.08H53.53V146H42.28C32.59,146 27.75,146 24.05,144.11C20.79,142.46 18.15,139.81 16.49,136.55C14.6,132.85 14.6,128.01 14.6,118.32V70.08Z" />
|
||||
</group>
|
||||
</vector>
|
||||
|
|
@ -1,33 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="44dp"
|
||||
android:height="13dp"
|
||||
android:viewportWidth="44"
|
||||
android:viewportHeight="13">
|
||||
<path
|
||||
android:pathData="M5.3925,5.4421L5.3925,9.8495L7.366,9.8495C7.4425,9.8487 7.5156,9.8187 7.5697,9.766C7.6238,9.7133 7.6545,9.6421 7.6554,9.5676L7.6554,5.4421L5.3925,5.4421Z"
|
||||
android:fillColor="@android:color/white"/>
|
||||
<path
|
||||
android:pathData="M0.9796,9.5676C0.9805,9.6421 1.0112,9.7133 1.0653,9.766C1.1194,9.8187 1.1925,9.8487 1.2691,9.8495L3.2425,9.8495L3.2425,5.4421L0.9796,5.4421L0.9796,9.5676Z"
|
||||
android:fillColor="@android:color/white"/>
|
||||
<path
|
||||
android:pathData="M7.6554,3.182L7.6554,1.2109C7.6554,1.1343 7.6255,1.0607 7.5721,1.0065C7.5187,0.9523 7.4463,0.9219 7.3708,0.9219L1.2644,0.9219C1.1889,0.9219 1.1166,0.9523 1.0632,1.0065C1.0098,1.0607 0.9798,1.1343 0.9798,1.2109L0.9798,3.182L7.6554,3.182Z"
|
||||
android:fillColor="@android:color/white"/>
|
||||
<path
|
||||
android:pathData="M18.2145,3.8623C17.8055,3.6911 17.3623,3.6145 16.9187,3.6383C16.3325,3.6367 15.7479,3.7001 15.1759,3.8271L15.1759,4.8288C15.6319,4.775 16.0903,4.744 16.5494,4.736C16.7956,4.7249 17.0421,4.7487 17.2816,4.8064C17.3582,4.8291 17.4278,4.8702 17.4843,4.9261C17.5409,4.9819 17.5826,5.0507 17.6055,5.1264C17.6777,5.3956 17.7082,5.674 17.6961,5.9521L17.6961,6.2466C17.1551,6.2178 16.7243,6.2018 16.4295,6.2018C16.1151,6.1865 15.8016,6.2469 15.516,6.3778C15.2912,6.5041 15.1233,6.71 15.0463,6.9539C14.9395,7.3099 14.8914,7.6805 14.9038,8.0516C14.864,8.5294 14.9773,9.0075 15.2277,9.4182C15.3603,9.5688 15.5273,9.686 15.7149,9.76C15.9025,9.8341 16.1054,9.8628 16.3065,9.8439C16.543,9.8439 17.2783,9.8246 17.6023,9.4022C17.6559,9.335 17.7015,9.262 17.7383,9.1846L17.7739,9.7479L18.966,9.7479L18.966,6.0226C18.9834,5.5406 18.93,5.0588 18.8073,4.592C18.7638,4.437 18.6888,4.2923 18.5869,4.1669C18.485,4.0414 18.3583,3.9378 18.2145,3.8623ZM17.6832,7.4595C17.7167,7.7981 17.6586,8.1394 17.5148,8.4485C17.4445,8.5375 17.3484,8.6034 17.2394,8.6373C17.1162,8.6717 16.9885,8.6879 16.8604,8.6853C16.6603,8.7107 16.458,8.6579 16.2968,8.5381C16.1883,8.3545 16.1428,8.1412 16.1671,7.93C16.16,7.7598 16.1775,7.5896 16.219,7.4244C16.2316,7.3765 16.2543,7.3319 16.2855,7.2933C16.3168,7.2547 16.3559,7.223 16.4004,7.2003C16.5227,7.1521 16.6544,7.1312 16.7859,7.1395L17.6832,7.1395L17.6832,7.4595Z"
|
||||
android:fillColor="@android:color/white"/>
|
||||
<path
|
||||
android:pathData="M28.5312,4.2026C28.5065,4.1598 28.4792,4.1187 28.4495,4.0794C28.0566,3.5603 27.1199,3.6382 27.1199,3.6382C26.8105,3.6281 26.5062,3.7214 26.2524,3.9042C25.996,4.1515 25.8305,4.4827 25.784,4.8417C25.5997,6.0976 25.5997,7.3749 25.784,8.6308C25.8287,8.9857 25.9895,9.3142 26.2398,9.5619C26.5131,9.765 26.8468,9.8626 27.1828,9.8376C27.1828,9.8376 27.2016,9.8376 27.2141,9.8376C27.2141,9.8376 28.0597,9.9057 28.4714,9.471C28.4795,9.826 28.4564,10.1811 28.4023,10.5318C28.3884,10.6253 28.3525,10.7138 28.2977,10.7896C28.2429,10.8654 28.1709,10.9262 28.088,10.9666C27.8262,11.0582 27.5499,11.0967 27.2739,11.0801L25.9757,11.0574L25.9757,12.0728C26.2149,12.1187 26.4562,12.1523 26.6987,12.1734C26.9973,12.2025 27.2802,12.2155 27.5505,12.2155C28.0537,12.2535 28.5569,12.1409 28.9996,11.8911C29.1544,11.7808 29.2862,11.6396 29.3872,11.4757C29.4881,11.3119 29.5562,11.1288 29.5873,10.9373C29.688,10.3136 29.7311,9.6814 29.7162,9.0493L29.7162,3.7323L28.5595,3.7323L28.5312,4.2026ZM28.3866,8.141C28.3673,8.3042 28.2886,8.4537 28.1666,8.5594C28.0239,8.6484 27.8583,8.6904 27.6919,8.6795C27.5059,8.6952 27.3195,8.6558 27.1544,8.5659C27.0258,8.4343 26.9514,8.2564 26.947,8.0695C26.8758,7.1909 26.8758,6.3076 26.947,5.4289C26.9515,5.2481 27.0236,5.076 27.1482,4.9488C27.3164,4.8621 27.5046,4.8251 27.6919,4.8417C27.8692,4.827 28.0458,4.8763 28.1917,4.9812C28.3215,5.1224 28.3994,5.306 28.4117,5.5003C28.4593,5.9169 28.4782,6.3364 28.4683,6.7558C28.4839,7.2191 28.4565,7.683 28.3866,8.141Z"
|
||||
android:fillColor="@android:color/white"/>
|
||||
<path
|
||||
android:pathData="M34.5404,3.8346C34.1306,3.5968 33.6597,3.4902 33.1893,3.5287C32.7005,3.494 32.2126,3.6073 31.787,3.8541C31.4771,4.0813 31.2687,4.4243 31.2075,4.8078C31.1063,5.4337 31.0634,6.0679 31.0794,6.7021C31.0627,7.3375 31.1078,7.9731 31.2139,8.5996C31.2467,8.7891 31.3169,8.9698 31.4204,9.1309C31.5238,9.2921 31.6583,9.4302 31.8158,9.5369C32.2648,9.7724 32.7686,9.8782 33.2726,9.8428C33.5935,9.8421 33.9141,9.8236 34.2331,9.7875C34.4977,9.7629 34.7599,9.7172 35.0175,9.6509L35.0175,8.6321C34.4284,8.6939 33.9449,8.7265 33.5671,8.7265C33.2881,8.7431 33.0084,8.709 32.7411,8.6256C32.6588,8.5899 32.5865,8.5342 32.5306,8.4632C32.4748,8.3922 32.4371,8.3082 32.421,8.2187C32.3635,7.8595 32.3399,7.4955 32.3505,7.1317L35.1456,7.1317L35.1456,6.689C35.1609,6.0364 35.1277,5.3836 35.0463,4.7362C35.0005,4.3798 34.8188,4.0561 34.5404,3.8346ZM33.9321,6.1683L32.3505,6.1683C32.3503,5.8308 32.3728,5.4937 32.4178,5.1593C32.424,5.0798 32.4465,5.0024 32.484,4.9324C32.5216,4.8623 32.5732,4.801 32.6355,4.7524C32.9642,4.6181 33.3312,4.6181 33.66,4.7524C33.7208,4.8026 33.7708,4.8649 33.8072,4.9354C33.8435,5.0059 33.8654,5.0832 33.8713,5.1626C33.9211,5.4953 33.9414,5.8319 33.9321,6.1683Z"
|
||||
android:fillColor="@android:color/white"/>
|
||||
<path
|
||||
android:pathData="M43.0589,4.5379C43.0049,4.2729 42.8609,4.0339 42.6507,3.8605C42.3989,3.6963 42.0997,3.6177 41.7986,3.6369C41.7986,3.6369 41.7693,3.6369 41.7499,3.6369C41.7499,3.6369 40.7779,3.5826 40.3761,4.0746C40.3324,4.13 40.2934,4.1887 40.2595,4.2503C40.1947,4.0846 40.0821,3.9413 39.9355,3.8382C39.6825,3.693 39.3918,3.624 39.0996,3.64C39.0996,3.64 38.1275,3.5826 37.7258,4.0778C37.6809,4.1323 37.6418,4.1912 37.6091,4.2535L37.5767,3.7359L36.3941,3.7359L36.3941,9.7365L37.6901,9.7365L37.6901,6.6084C37.6834,6.233 37.6975,5.8576 37.7323,5.4837C37.7406,5.2996 37.81,5.1233 37.9299,4.982C38.0732,4.866 38.2573,4.8109 38.4418,4.8286C38.6058,4.8156 38.7704,4.8465 38.9181,4.9181C38.9727,4.9699 39.0163,5.0319 39.0463,5.1004C39.0764,5.169 39.0923,5.2428 39.0931,5.3175C39.1272,5.6872 39.1412,6.0583 39.1351,6.4295L39.1351,9.7365L40.4312,9.7365L40.4312,6.6084C40.4312,6.0876 40.4312,5.7137 40.4701,5.4837C40.4788,5.2985 40.5507,5.1217 40.6742,4.982C40.8206,4.8672 41.0063,4.8123 41.1926,4.8286C41.3577,4.8157 41.5233,4.8466 41.6721,4.9181C41.7262,4.9702 41.7692,5.0323 41.7986,5.1008C41.8281,5.1694 41.8435,5.2431 41.8439,5.3175C41.8797,5.6871 41.8937,6.0583 41.886,6.4295L41.886,9.7365L43.182,9.7365L43.182,5.784C43.1892,5.3654 43.148,4.9473 43.0589,4.5379Z"
|
||||
android:fillColor="@android:color/white"/>
|
||||
<path
|
||||
android:pathData="M23.9733,3.8677C23.7029,3.6964 23.3827,3.6156 23.0609,3.6376C23.0609,3.6376 23.0346,3.6376 23.0215,3.6376C23.0215,3.6376 22.0369,3.5865 21.6332,4.0755C21.6044,4.11 21.5781,4.1462 21.5544,4.1842L21.5249,3.7335L20.3269,3.7335L20.3269,9.7365L21.6398,9.7365L21.6398,6.6071C21.6328,6.2337 21.647,5.8602 21.6824,5.4883C21.6921,5.3027 21.7662,5.1258 21.8925,4.9865C22.0509,4.8661 22.2504,4.809 22.4504,4.8267C22.625,4.8143 22.8,4.8451 22.9592,4.9162C23.0182,4.9673 23.0659,5.0297 23.0992,5.0995C23.1325,5.1694 23.1507,5.2452 23.1528,5.3221C23.1903,5.6896 23.2057,6.0589 23.1988,6.4281L23.1988,9.7365L24.5116,9.7365L24.5116,5.84C24.5219,5.4113 24.4856,4.9827 24.4032,4.5614C24.3496,4.2876 24.1971,4.0415 23.9733,3.8677Z"
|
||||
android:fillColor="@android:color/white"/>
|
||||
<path
|
||||
android:pathData="M13.3195,1.9385L11.99,1.9385L11.99,3.6595L11.1628,3.6595L11.1628,4.7597L11.99,4.7597L11.99,9.7361L13.3195,9.7361L13.3195,4.7597L14.3309,4.7597L14.3309,3.6595L13.3195,3.6595L13.3195,1.9385Z"
|
||||
android:fillColor="@android:color/white"/>
|
||||
android:width="51dp"
|
||||
android:height="11dp"
|
||||
android:viewportWidth="74"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M2.924,0H9.413C10.436,0 10.948,0 11.339,0.199C11.683,0.374 11.962,0.654 12.137,0.998C12.337,1.389 12.337,1.9 12.337,2.924V2.924V4.009H0V2.924C0,1.9 0,1.389 0.199,0.998C0.374,0.654 0.654,0.375 0.998,0.199C1.389,0 1.9,0 2.924,0ZM12.337,7.402H8.224L8.225,7.971V15.421H9.413H9.413C10.436,15.421 10.948,15.421 11.339,15.221C11.683,15.047 11.962,14.767 12.137,14.423C12.337,14.032 12.337,13.52 12.337,12.497V7.402ZM4.111,7.402H0V12.497C0,13.52 0,14.032 0.199,14.423C0.375,14.767 0.654,15.047 0.998,15.221C1.389,15.421 1.9,15.421 2.924,15.421H2.924H4.111V7.402ZM22.85,12.479C21.201,12.479 20.346,11.591 20.346,10.022V5.488H19.236V4.046H20.346V2.223H22.264V4.046H24.087V5.488H22.264V9.848C22.264,10.577 22.612,10.91 23.215,10.91C23.595,10.91 23.881,10.862 24.15,10.751V12.273C23.849,12.384 23.437,12.479 22.85,12.479ZM28.298,11.116C29.471,11.116 30.343,10.498 30.343,9.436V8.611H29.36C27.901,8.611 26.966,8.944 26.966,9.959C26.966,10.656 27.347,11.116 28.298,11.116ZM27.838,12.495C26.316,12.495 25.064,11.766 25.064,10.038C25.064,8.104 26.934,7.406 29.312,7.406H30.343V6.978C30.343,5.869 29.962,5.314 28.837,5.314C27.838,5.314 27.347,5.789 27.251,6.614H25.397C25.555,4.68 27.093,3.871 28.948,3.871C30.802,3.871 32.261,4.632 32.261,6.899V12.337H30.374V11.322C29.835,12.035 29.106,12.495 27.838,12.495ZM33.841,4.046V12.337H35.759V7.454C35.759,6.138 36.631,5.472 37.709,5.472C38.85,5.472 39.358,6.043 39.358,7.295V12.337H41.276V7.121C41.276,4.838 40.103,3.871 38.438,3.871C37.075,3.871 36.155,4.553 35.759,5.361V4.046H33.841ZM46.72,10.529C48.051,10.529 49.018,9.578 49.018,7.993V7.882C49.018,6.313 48.162,5.377 46.783,5.377C45.356,5.377 44.532,6.408 44.532,7.914V8.041C44.532,9.578 45.483,10.529 46.72,10.529ZM46.656,15.38C44.056,15.38 42.883,14.207 42.661,12.622H44.595C44.754,13.446 45.388,13.922 46.64,13.922C48.13,13.922 48.955,13.177 48.955,11.687V10.466C48.495,11.259 47.465,12.004 46.244,12.004C44.167,12.004 42.566,10.45 42.566,8.056V7.945C42.566,5.615 44.151,3.871 46.292,3.871C47.655,3.871 48.479,4.49 48.955,5.314V4.046H50.873V11.718C50.857,14.16 49.224,15.38 46.656,15.38ZM52.249,8.278C52.249,10.894 54.009,12.495 56.45,12.495C58.574,12.495 59.985,11.544 60.255,9.8H58.4C58.257,10.609 57.655,11.068 56.498,11.068C55.071,11.068 54.278,10.181 54.215,8.611H60.286V8.056C60.286,5.092 58.431,3.871 56.371,3.871C54.009,3.871 52.249,5.583 52.249,8.151V8.278ZM58.384,7.327H54.246C54.437,6.043 55.213,5.266 56.371,5.266C57.56,5.266 58.289,5.9 58.384,7.327ZM61.651,12.337V4.046H63.569V5.314C63.965,4.537 64.869,3.871 66.089,3.871C67.167,3.871 68.023,4.331 68.436,5.361C69.07,4.331 70.211,3.871 71.241,3.871C72.763,3.871 74,4.807 74,7.089V12.337H72.081V7.216C72.081,5.996 71.558,5.472 70.607,5.472C69.656,5.472 68.784,6.107 68.784,7.375V12.337H66.866V7.216C66.866,5.996 66.327,5.472 65.392,5.472C64.441,5.472 63.569,6.107 63.569,7.375V12.337H61.651Z" />
|
||||
</vector>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="96dp"
|
||||
android:height="96dp"
|
||||
android:viewportWidth="96"
|
||||
android:viewportHeight="96">
|
||||
android:viewportWidth="98"
|
||||
android:viewportHeight="98">
|
||||
<path
|
||||
android:fillColor="#1E1E1E"
|
||||
android:pathData="M56.27,47.27V78H69.56C70.07,78 70.57,77.8 70.93,77.43C71.3,77.07 71.5,76.57 71.5,76.06V47.27H56.27Z" />
|
||||
android:pathData="M59.285,24.464H38.715C35.469,24.464 33.848,24.464 32.607,25.095C31.517,25.652 30.629,26.536 30.076,27.626C29.444,28.867 29.444,30.488 29.444,33.734V37.175H68.555V33.734C68.555,30.488 68.555,28.867 67.924,27.626C67.367,26.536 66.483,25.648 65.393,25.095C64.152,24.464 62.531,24.464 59.285,24.464Z" />
|
||||
<path
|
||||
android:fillColor="#1E1E1E"
|
||||
android:pathData="M25.5,76.06C25.5,76.57 25.71,77.07 26.07,77.43C26.43,77.8 26.93,78 27.44,78H40.73V47.27H25.5V76.06Z" />
|
||||
android:pathData="M55.516,47.93H68.554V64.082C68.554,67.328 68.554,68.949 67.923,70.19C67.366,71.28 66.482,72.168 65.392,72.721C64.151,73.353 62.53,73.353 59.284,73.353H55.52L55.516,47.93Z" />
|
||||
<path
|
||||
android:fillColor="#1E1E1E"
|
||||
android:pathData="M71.5,32.2V18.94C71.5,18.43 71.29,17.93 70.93,17.57C70.56,17.2 70.07,17 69.55,17H27.45C26.94,17 26.44,17.2 26.07,17.57C25.71,17.93 25.5,18.43 25.5,18.94V32.2H71.5Z" />
|
||||
android:pathData="M29.444,47.93H42.479V73.353H38.715C35.469,73.353 33.848,73.353 32.607,72.721C31.517,72.168 30.633,71.28 30.076,70.19C29.444,68.949 29.444,67.328 29.444,64.082V47.93Z" />
|
||||
</vector>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="96dp"
|
||||
android:height="96dp"
|
||||
android:viewportWidth="96"
|
||||
android:viewportHeight="96">
|
||||
android:viewportWidth="450"
|
||||
android:viewportHeight="450">
|
||||
<path
|
||||
android:pathData="M56.271,47.274V78H69.557C70.073,78 70.567,77.795 70.931,77.431C71.295,77.066 71.5,76.572 71.5,76.056V47.274H56.271Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M284.96,82H165.04C146.12,82 136.67,82 129.44,85.68C123.08,88.93 117.91,94.08 114.68,100.44C111,107.67 111,117.12 111,136.04V156.1H339V136.04C339,117.12 339,107.67 335.32,100.44C332.07,94.08 326.92,88.91 320.56,85.68C313.33,82 303.88,82 284.96,82Z" />
|
||||
<path
|
||||
android:pathData="M25.5,76.056C25.5,76.572 25.705,77.066 26.069,77.431C26.433,77.795 26.927,78 27.443,78H40.729V47.274H25.5V76.056Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M262.99,218.8H338.99V312.96C338.99,331.88 338.99,341.33 335.31,348.56C332.07,354.92 326.91,360.09 320.56,363.32C313.32,367 303.87,367 284.95,367H263.01L262.99,218.8Z" />
|
||||
<path
|
||||
android:pathData="M71.5,32.204V18.94C71.5,18.425 71.294,17.932 70.928,17.568C70.562,17.204 70.065,17 69.547,17H27.453C26.935,17 26.438,17.204 26.072,17.568C25.706,17.932 25.5,18.425 25.5,18.94V32.204H71.5Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M111,218.8H186.99V367H165.04C146.12,367 136.67,367 129.44,363.32C123.08,360.09 117.93,354.92 114.68,348.56C111,341.33 111,331.88 111,312.96V218.8Z" />
|
||||
</vector>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_wallet_main_action"
|
||||
style="@style/TapPrimaryIconButton"
|
||||
android:layout_width="204dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/home_bottom_fl_scan_card_container_margin_bottom"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
|
@ -20,7 +19,6 @@
|
|||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_wallet_alternative_action"
|
||||
style="@style/TapTextButton"
|
||||
android:layout_width="204dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/home_bottom_btn_alternative_action_margin_bottom"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@mipmap/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@mipmap/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
|
Before Width: | Height: | Size: 984 B After Width: | Height: | Size: 542 B |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_background.webp
Normal file
|
After Width: | Height: | Size: 44 B |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 604 B After Width: | Height: | Size: 422 B |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_background.webp
Normal file
|
After Width: | Height: | Size: 44 B |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 716 B |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_background.webp
Normal file
|
After Width: | Height: | Size: 46 B |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1,012 B |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp
Normal file
|
After Width: | Height: | Size: 52 B |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 54 B After Width: | Height: | Size: 52 B |
|
Before Width: | Height: | Size: 484 B |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
7
app/src/main/res/values-v29/styles.xml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="AppTheme" parent="BaseAppTheme">
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
@ -68,10 +68,11 @@
|
|||
<item name="cornerRadius">14dp</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:fontFamily">@font/roboto_regular</item>
|
||||
<item name="android:letterSpacing">0</item>
|
||||
<item name="android:fontFamily">@font/roboto_medium</item>
|
||||
<item name="android:letterSpacing">0.01</item>
|
||||
<item name="fontWeight">500</item>
|
||||
<item name="lineHeight">16sp</item>
|
||||
<item name="iconPadding">4dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TapPrimaryButton" parent="BaseTapButton">
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@
|
|||
<string name="address_type_default">По умолчанию</string>
|
||||
<string name="address_type_legacy">Устаревший</string>
|
||||
<string name="common_fee_error">Не удалось получить комиссию</string>
|
||||
<string name="common_utxo_validate_withdrawal_message_warning">Из-за ограничений %1$s в одну транзакцию может поместиться только %2$d UTXO. Это означает, что вы можете отправить только %3$s или меньше. Вам нужно уменьшить сумму.</string>
|
||||
<string name="eth_gas_required_exceeds_allowance">Недостаточно средств для совершения транзакции. Пожалуйста, пополните свой аккаунт.</string>
|
||||
<string name="generic_error_code">Произошла ошибка. Код: %s.</string>
|
||||
<string name="kaspa_withdrawal_message_warning">Из-за ограничений Kaspa в одну транзакцию может поместиться только %1$d UTXO. Это означает, что вы можете отправить только %2$s или меньше. Вам нужно уменьшить сумму.</string>
|
||||
<string name="no_account_generic">Пополните счет на %1$s+ %2$s, чтобы создать аккаунт</string>
|
||||
<string name="no_account_polkadot">Аккаунт получателя не активирован. Отправьте %s или более для активации аккаунта.</string>
|
||||
|
|
|
|||
|
|
@ -577,5 +577,5 @@
|
|||
<string name="welcome_unlock">Войти с %s</string>
|
||||
<string name="welcome_unlock_card">Сканировать карту</string>
|
||||
<string name="welcome_unlock_description">Используйте %s или отсканируйте карту для входа в приложение</string>
|
||||
<string name="welcome_unlock_title">C возвращением!</string>
|
||||
<string name="welcome_unlock_title">С возвращением!</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -80,7 +80,6 @@
|
|||
<string name="common_origin_card">主卡片</string>
|
||||
<string name="common_reject">拒絕</string>
|
||||
<string name="common_rename">重新命名</string>
|
||||
<string name="common_reset">重置</string>
|
||||
<string name="common_save_changes">保存設置</string>
|
||||
<string name="common_search">搜索</string>
|
||||
<string name="common_search_tokens">搜尋代幣</string>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@
|
|||
<string name="address_type_default">Default</string>
|
||||
<string name="address_type_legacy">Legacy</string>
|
||||
<string name="common_fee_error">Failed to get fee</string>
|
||||
<string name="common_utxo_validate_withdrawal_message_warning">Due to %1$s limitations only %2$d UTXOs can fit in a single transaction. This means you can only send %3$s or less. You need to reduce the amount.</string>
|
||||
<string name="eth_gas_required_exceeds_allowance">Not enough funds for the transaction. Please top up your account.</string>
|
||||
<string name="generic_error_code">An error occurred. Code: %s.</string>
|
||||
<string name="kaspa_withdrawal_message_warning">Due to Kaspa limitations only %1$d UTXOs can fit in a single transaction. This means you can only send %2$s or less. You need to reduce the amount.</string>
|
||||
<string name="no_account_generic">Load %1$s+ %2$s to create account</string>
|
||||
<string name="no_account_polkadot">Destination account is not active. Send %s or more to activate the account.</string>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,20 @@
|
|||
package com.tangem.core.ui.components.buttons.common
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.requiredSizeIn
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.SpacerW
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
|
|
@ -30,67 +38,77 @@ fun TangemButton(
|
|||
elevation = elevation,
|
||||
shape = size.toShape(),
|
||||
colors = colors,
|
||||
contentPadding = if (showProgress) ButtonDefaults.ContentPadding else size.toContentPadding(icon = icon),
|
||||
contentPadding = size.toContentPadding(icon = icon),
|
||||
) {
|
||||
ButtonContent(
|
||||
text = text,
|
||||
textStyle = textStyle,
|
||||
ButtonContentContainer(
|
||||
buttonIcon = icon,
|
||||
colors = colors,
|
||||
iconPadding = size.toIconPadding(),
|
||||
showProgress = showProgress,
|
||||
enabled = enabled,
|
||||
size = size,
|
||||
progressIndicator = {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.buttonContentSize(textStyle),
|
||||
color = colors.contentColor(enabled = enabled).value,
|
||||
strokeWidth = TangemTheme.dimens.size4,
|
||||
)
|
||||
},
|
||||
text = {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
text = text,
|
||||
style = textStyle,
|
||||
color = colors.contentColor(enabled = enabled).value,
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
},
|
||||
icon = { iconResId ->
|
||||
Icon(
|
||||
modifier = Modifier.buttonContentSize(textStyle),
|
||||
painter = painterResource(id = iconResId),
|
||||
tint = colors.contentColor(enabled = enabled).value,
|
||||
contentDescription = null,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
private fun ButtonContent(
|
||||
text: String,
|
||||
textStyle: TextStyle,
|
||||
private inline fun RowScope.ButtonContentContainer(
|
||||
buttonIcon: TangemButtonIconPosition,
|
||||
colors: ButtonColors,
|
||||
size: TangemButtonSize,
|
||||
enabled: Boolean,
|
||||
iconPadding: Dp,
|
||||
showProgress: Boolean,
|
||||
progressIndicator: @Composable RowScope.() -> Unit,
|
||||
text: @Composable RowScope.() -> Unit,
|
||||
icon: @Composable RowScope.(Int) -> Unit,
|
||||
) {
|
||||
val icon = @Composable { iconResId: Int ->
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size20),
|
||||
painter = painterResource(id = iconResId),
|
||||
tint = colors.contentColor(enabled = enabled).value,
|
||||
contentDescription = null,
|
||||
)
|
||||
if (showProgress) {
|
||||
progressIndicator()
|
||||
} else {
|
||||
if (buttonIcon is TangemButtonIconPosition.Start) {
|
||||
icon(buttonIcon.iconResId)
|
||||
SpacerW(width = iconPadding)
|
||||
}
|
||||
text()
|
||||
if (buttonIcon is TangemButtonIconPosition.End) {
|
||||
SpacerW(width = iconPadding)
|
||||
icon(buttonIcon.iconResId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Modifier.buttonContentSize(buttonTextStyle: TextStyle): Modifier = composed {
|
||||
val minContentElementSize = TangemTheme.dimens.size20
|
||||
val maxContentElementSize = remember(key1 = buttonTextStyle.lineHeight) {
|
||||
buttonTextStyle.lineHeight.value.dp + 4.dp
|
||||
}
|
||||
|
||||
if (showProgress) {
|
||||
Box(modifier = Modifier.wrapContentSize()) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(TangemTheme.dimens.size24),
|
||||
color = colors.contentColor(enabled = enabled).value,
|
||||
strokeWidth = TangemTheme.dimens.size4,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(size.toIconPadding()),
|
||||
) {
|
||||
if (buttonIcon is TangemButtonIconPosition.Start) {
|
||||
icon(buttonIcon.iconResId)
|
||||
}
|
||||
Text(
|
||||
text = text,
|
||||
style = textStyle,
|
||||
color = colors.contentColor(enabled = enabled).value,
|
||||
maxLines = 1,
|
||||
)
|
||||
if (buttonIcon is TangemButtonIconPosition.End) {
|
||||
icon(buttonIcon.iconResId)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.requiredSizeIn(
|
||||
minWidth = minContentElementSize,
|
||||
minHeight = minContentElementSize,
|
||||
maxWidth = maxContentElementSize,
|
||||
maxHeight = maxContentElementSize,
|
||||
)
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ internal fun TangemButtonSize.toShape(): Shape = when (this) {
|
|||
@Composable
|
||||
@ReadOnlyComposable
|
||||
internal fun TangemButtonSize.toIconPadding(): Dp = when (this) {
|
||||
TangemButtonSize.Default -> TangemTheme.dimens.spacing8
|
||||
TangemButtonSize.Default -> TangemTheme.dimens.spacing4
|
||||
TangemButtonSize.Text -> TangemTheme.dimens.spacing8
|
||||
TangemButtonSize.Selector -> 0.dp
|
||||
TangemButtonSize.Action,
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@
|
|||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M4,3.9C4,3.403 4.421,3 4.941,3H19.059C19.579,3 20,3.403 20,3.9V8.4H4V3.9Z" />
|
||||
android:pathData="M15.682,3.25H8.318C7.157,3.25 6.576,3.25 6.132,3.476C5.742,3.675 5.424,3.992 5.226,4.382C5,4.826 5,5.407 5,6.568V7.8H19V6.568C19,5.407 19,4.826 18.774,4.382C18.575,3.992 18.258,3.674 17.868,3.476C17.424,3.25 16.844,3.25 15.682,3.25Z"
|
||||
android:fillColor="#1E1E1E"/>
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M4,12H9.647V21H4.941C4.421,21 4,20.597 4,20.1V12Z" />
|
||||
android:pathData="M14.333,11.65H19V17.432C19,18.594 19,19.174 18.773,19.618C18.574,20.008 18.258,20.326 17.868,20.524C17.423,20.75 16.843,20.75 15.681,20.75H14.334L14.333,11.65Z"
|
||||
android:fillColor="#1E1E1E"/>
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M20,12H14.353V21H19.059C19.579,21 20,20.597 20,20.1V12Z" />
|
||||
android:pathData="M5,11.65H9.666V20.75H8.318C7.157,20.75 6.576,20.75 6.132,20.524C5.742,20.326 5.425,20.008 5.226,19.618C5,19.174 5,18.594 5,17.432V11.65Z"
|
||||
android:fillColor="#1E1E1E"/>
|
||||
</vector>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,6 @@ interface CardSdkLifecycleObserver {
|
|||
/** Callback of creating activity [context] */
|
||||
fun onCreate(context: Context)
|
||||
|
||||
/** Callback of destroying activity */
|
||||
fun onDestroy()
|
||||
/** Callback of destroying activity [context] */
|
||||
fun onDestroy(context: Context)
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import com.tangem.common.CardFilter
|
|||
import com.tangem.common.card.FirmwareVersion
|
||||
import com.tangem.common.core.Config
|
||||
import com.tangem.sdk.extensions.initWithBiometrics
|
||||
import java.lang.ref.WeakReference
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
|
@ -23,14 +24,22 @@ internal class DefaultCardSdkProvider @Inject constructor() : CardSdkProvider, C
|
|||
|
||||
private var _sdk: TangemSdk? = null
|
||||
|
||||
/** Weak reference of context that uses to create [TangemSdk] */
|
||||
private var contextRef: WeakReference<Context> = WeakReference(null)
|
||||
|
||||
override fun onCreate(context: Context) {
|
||||
if (_sdk == null) {
|
||||
_sdk = TangemSdk.initWithBiometrics(activity = context as FragmentActivity, config = config)
|
||||
}
|
||||
contextRef = WeakReference(context)
|
||||
_sdk = TangemSdk.initWithBiometrics(activity = context as FragmentActivity, config = config)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
_sdk = null
|
||||
override fun onDestroy(context: Context) {
|
||||
/*
|
||||
|
||||
|
||||
*/
|
||||
if (contextRef.get() == context) {
|
||||
_sdk = null
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
|
|
|||
|
|
@ -399,6 +399,12 @@ class DemoConfig {
|
|||
"AB02000000048063",
|
||||
"AB02000000023736",
|
||||
"AB02000000058187",
|
||||
|
||||
// Wallet 2
|
||||
"AF04000000012006",
|
||||
"AF04000000012014",
|
||||
"AF04000000012022",
|
||||
"AF04000000012030",
|
||||
)
|
||||
|
||||
@Suppress("ClassOrdering")
|
||||
|
|
@ -406,6 +412,7 @@ class DemoConfig {
|
|||
"FB20000000000186", // Note ETH
|
||||
"FB10000000000196", // Note BTC
|
||||
"FB30000000000176", // Wallet
|
||||
"FB04000000000152", // Wallet 2
|
||||
)
|
||||
|
||||
@Suppress("ClassOrdering")
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.domain.common
|
|||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.common.card.FirmwareVersion
|
||||
import com.tangem.domain.demo.DemoConfig
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import java.util.*
|
||||
|
||||
|
|
@ -13,6 +14,7 @@ object TapWorkarounds {
|
|||
private const val TEST_CARD_BATCH = "99FF"
|
||||
private const val TEST_CARD_ID_STARTS_WITH = "FF99"
|
||||
private val backupRequiredFirmwareVersion = FirmwareVersion(major = 6, minor = 21)
|
||||
private val demoConfig = DemoConfig()
|
||||
|
||||
val CardDTO.isTangemTwins: Boolean
|
||||
get() = TwinsHelper.getTwinCardNumber(cardId) != null
|
||||
|
|
@ -25,7 +27,7 @@ object TapWorkarounds {
|
|||
|
||||
// for cards 6.21 and higher backup is not skippable
|
||||
val CardDTO.canSkipBackup: Boolean
|
||||
get() = this.firmwareVersion < backupRequiredFirmwareVersion
|
||||
get() = this.firmwareVersion < backupRequiredFirmwareVersion || demoConfig.isDemoCardId(cardId)
|
||||
|
||||
val CardDTO.useOldStyleDerivation: Boolean
|
||||
get() = batchId == "AC01" || batchId == "AC02" || batchId == "CB95"
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ object Wallet2CardConfig : CardConfig {
|
|||
get() = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bip0340,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
EllipticCurve.Bip0340,
|
||||
EllipticCurve.Ed25519Slip0010,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ sealed class CryptoCurrency : Serializable {
|
|||
require(name.isNotBlank()) { "Crypto currency name must not be blank" }
|
||||
require(symbol.isNotBlank()) { "Crypto currency symbol must not be blank" }
|
||||
require(iconUrl?.isNotBlank() ?: true) { "Crypto currency icon URL must not be blank" }
|
||||
require(decimals > 0) { "Crypto currency decimal must not be less then zero, but it is: $decimals" }
|
||||
require(decimals >= 0) { "Crypto currency decimal must not be less then zero, but it is: $decimals" }
|
||||
require(derivationPath?.isNotBlank() ?: true) { "Crypto currency derivation path must not be blank" }
|
||||
}
|
||||
}
|
||||
|
|
@ -23,10 +23,18 @@ sealed class SeedPhraseEvents(
|
|||
}
|
||||
}
|
||||
|
||||
object OnboardingSeedButtonOtherOptions : AnalyticsEvent(
|
||||
category = "Onboarding / Create Wallet",
|
||||
event = "Button - Other Options",
|
||||
)
|
||||
sealed class CreateWalletEvents(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
) : AnalyticsEvent(ONBOARDING_CREATE_WALLET, event, params) {
|
||||
|
||||
object OnboardingSeedButtonCreateWallet : CreateWalletEvents("Button - Create Wallet")
|
||||
|
||||
object OnboardingSeedButtonOtherOptions : CreateWalletEvents("Button - Other Options")
|
||||
companion object {
|
||||
const val ONBOARDING_CREATE_WALLET = "Onboarding / Create Wallet"
|
||||
}
|
||||
}
|
||||
|
||||
enum class SeedPhraseSource {
|
||||
IMPORTED, GENERATED
|
||||
|
|
|
|||
|
|
@ -79,6 +79,13 @@ class StateBuilder(
|
|||
onBackClick = uiActions.menuNavigateBackClick,
|
||||
)
|
||||
|
||||
fun setCardArtwork(uiState: OnboardingSeedPhraseState, cardArtwork: String): OnboardingSeedPhraseState =
|
||||
uiState.copy(
|
||||
introState = uiState.introState.copy(
|
||||
cardImageUrl = cardArtwork,
|
||||
),
|
||||
)
|
||||
|
||||
fun generateMnemonicComponents(uiState: OnboardingSeedPhraseState): OnboardingSeedPhraseState {
|
||||
return uiState.copy(
|
||||
aboutState = uiState.aboutState.copy(
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@ class SeedPhraseRouter(
|
|||
fun navigateBack() {
|
||||
_currentScreen.value = when (_currentScreen.value) {
|
||||
SeedPhraseScreen.CheckSeedPhrase -> SeedPhraseScreen.YourSeedPhrase
|
||||
SeedPhraseScreen.Intro,
|
||||
SeedPhraseScreen.AboutSeedPhrase,
|
||||
SeedPhraseScreen.YourSeedPhrase,
|
||||
SeedPhraseScreen.AboutSeedPhrase -> SeedPhraseScreen.Intro
|
||||
SeedPhraseScreen.ImportSeedPhrase,
|
||||
-> {
|
||||
SeedPhraseScreen.YourSeedPhrase,
|
||||
-> SeedPhraseScreen.AboutSeedPhrase
|
||||
SeedPhraseScreen.Intro -> {
|
||||
onBack.invoke()
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import com.tangem.data.common.locale.LocaleProvider
|
|||
import com.tangem.feature.onboarding.data.model.CreateWalletResponse
|
||||
import com.tangem.feature.onboarding.domain.SeedPhraseError
|
||||
import com.tangem.feature.onboarding.domain.SeedPhraseInteractor
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.analytics.OnboardingSeedButtonOtherOptions
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.analytics.CreateWalletEvents
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.analytics.SeedPhraseEvents
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.analytics.SeedPhraseSource
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.model.*
|
||||
|
|
@ -88,10 +88,11 @@ class SeedPhraseViewModel @Inject constructor(
|
|||
router.currentScreen.onEach { screen ->
|
||||
when (screen) {
|
||||
SeedPhraseScreen.Intro -> {
|
||||
analyticsEventHandler.send(SeedPhraseEvents.IntroScreenOpened)
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
SeedPhraseScreen.AboutSeedPhrase -> {
|
||||
analyticsEventHandler.send(SeedPhraseEvents.IntroScreenOpened)
|
||||
mediator.allowScreenshots(true)
|
||||
}
|
||||
|
||||
|
|
@ -116,6 +117,12 @@ class SeedPhraseViewModel @Inject constructor(
|
|||
this.mediator = mediator
|
||||
}
|
||||
|
||||
fun setCardArtworkUri(cardArtworkUri: String) {
|
||||
if (uiState.introState.cardImageUrl != cardArtworkUri) {
|
||||
uiState = uiBuilder.setCardArtwork(uiState, cardArtworkUri)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createUiActions(): UiActions = UiActions(
|
||||
introActions = IntroUiAction(
|
||||
buttonCreateWalletClick = ::buttonCreateWalletClick,
|
||||
|
|
@ -265,6 +272,7 @@ class SeedPhraseViewModel @Inject constructor(
|
|||
// region ButtonClickHandlers
|
||||
private fun buttonCreateWalletClick() {
|
||||
viewModelScope.launch(dispatchers.io) {
|
||||
analyticsEventHandler.send(CreateWalletEvents.OnboardingSeedButtonCreateWallet)
|
||||
mediator.createWallet(::handleWalletCreationResult)
|
||||
}
|
||||
}
|
||||
|
|
@ -299,7 +307,7 @@ class SeedPhraseViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun buttonOtherOptionsClick() {
|
||||
analyticsEventHandler.send(OnboardingSeedButtonOtherOptions)
|
||||
analyticsEventHandler.send(CreateWalletEvents.OnboardingSeedButtonOtherOptions)
|
||||
router.openScreen(SeedPhraseScreen.AboutSeedPhrase)
|
||||
}
|
||||
|
||||
|
|
@ -368,7 +376,6 @@ class SeedPhraseViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun buttonContinueClick() {
|
||||
analyticsEventHandler.send(SeedPhraseEvents.CheckingScreenOpened)
|
||||
router.openScreen(SeedPhraseScreen.CheckSeedPhrase)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -80,9 +80,9 @@ okHttp-prettyLogging = "3.1.0"
|
|||
# endregion Other libraries
|
||||
|
||||
# region Tangem
|
||||
tangemBlockchainSdk = "develop-340"
|
||||
tangemBlockchainSdk = "release-app_4.11-344"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "develop-293"
|
||||
tangemCardSdk = "release-app_4.11-294"
|
||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds
|
||||
# endregion Tangem
|
||||
|
||||
|
|
|
|||