Updated on 2026-08-14

This commit is contained in:
Tangem 2023-10-18 17:31:46 +03:00
parent 28b5abc134
commit 38e3891680
189 changed files with 1845 additions and 1522 deletions

View file

@ -32,12 +32,12 @@ import com.tangem.domain.card.ScanCardProcessor
import com.tangem.domain.common.LogConfig
import com.tangem.domain.settings.repositories.AppRatingRepository
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.legacy.WalletManagersRepository
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles
import com.tangem.features.tokendetails.featuretoggles.TokenDetailsFeatureToggles
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
import com.tangem.tap.common.analytics.AnalyticsFactory
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
@ -172,9 +172,6 @@ internal class TapApplication : Application(), ImageLoaderFactory {
// @Inject
// lateinit var learn2earnInteractor: Learn2earnInteractor
@Inject
lateinit var tokenDetailsFeatureToggles: TokenDetailsFeatureToggles
@Inject
lateinit var manageTokensFeatureToggles: ManageTokensFeatureToggles
@ -190,6 +187,9 @@ internal class TapApplication : Application(), ImageLoaderFactory {
@Inject
lateinit var walletManagersFacade: WalletManagersFacade
@Inject
lateinit var networksRepository: NetworksRepository
@Inject
lateinit var currenciesRepository: CurrenciesRepository
@ -296,12 +296,12 @@ internal class TapApplication : Application(), ImageLoaderFactory {
walletFeatureToggles = walletFeatureToggles,
walletConnectRepository = walletConnect2Repository,
walletConnectSessionsRepository = walletConnectSessionsRepository,
tokenDetailsFeatureToggles = tokenDetailsFeatureToggles,
manageTokensFeatureToggles = manageTokensFeatureToggles,
scanCardProcessor = scanCardProcessor,
appCurrencyRepository = appCurrencyRepository,
walletManagersFacade = walletManagersFacade,
appStateHolder = appStateHolder,
networksRepository = networksRepository,
currenciesRepository = currenciesRepository,
appThemeModeRepository = appThemeModeRepository,
balanceHidingRepository = balanceHidingRepository,

View file

@ -0,0 +1,13 @@
package com.tangem.tap.common.analytics
import com.tangem.core.analytics.Analytics
import com.tangem.domain.analytics.ChangeCardAnalyticsContextUseCase
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.common.extensions.setContext
internal class DefaultChangeCardAnalyticsContextUseCase : ChangeCardAnalyticsContextUseCase {
override fun invoke(scanResponse: ScanResponse) {
Analytics.setContext(scanResponse)
}
}

View file

@ -133,9 +133,9 @@ sealed class AnalyticsParam {
}
sealed class WalletCreationType(val value: String) {
object PrivateKey : WalletCreationType("Private key")
object NewSeed : WalletCreationType("New seed")
object SeedImport : WalletCreationType("Seed import")
object PrivateKey : WalletCreationType(value = "Private Key")
object NewSeed : WalletCreationType(value = "New Seed")
object SeedImport : WalletCreationType(value = "Seed Import")
}
companion object Key {
@ -152,7 +152,8 @@ sealed class AnalyticsParam {
const val ERROR_DESCRIPTION = "Error Description"
const val ERROR_CODE = "Error Code"
const val ERROR_KEY = "Error Key"
const val CREATION_TYPE = "Creation type"
const val CREATION_TYPE = "Creation Type"
const val SEED_PHRASE_LENGTH = "Seed Phrase Length"
const val DAPP_NAME = "DApp Name"
const val DAPP_URL = "DApp Url"
const val METHOD_NAME = "Method Name"

View file

@ -32,14 +32,18 @@ sealed class Basic(
batch: String,
signInType: SignInType,
walletsCount: String,
hasBackup: Boolean?,
) : Basic(
event = "Signed in",
params = mapOf(
AnalyticsParam.CURRENCY to currency.value,
AnalyticsParam.BATCH to batch,
"Sign in type" to signInType.name,
"Wallets Count" to walletsCount,
),
params = buildMap {
put(AnalyticsParam.CURRENCY, currency.value)
put(AnalyticsParam.BATCH, batch)
put("Sign in type", signInType.name)
put("Wallets Count", walletsCount)
if (hasBackup != null) {
put("Backuped", if (hasBackup) "Yes" else "No")
}
},
) {
enum class SignInType {
Card, Biometric

View file

@ -23,9 +23,14 @@ sealed class Onboarding(
class ButtonCreateWallet : CreateWallet("Button - Create Wallet")
class WalletCreatedSuccessfully(
creationType: AnalyticsParam.WalletCreationType = AnalyticsParam.WalletCreationType.PrivateKey,
seedPhraseLength: Int? = null,
) : CreateWallet(
event = "Wallet Created Successfully",
params = mapOf(AnalyticsParam.CREATION_TYPE to creationType.value),
params = buildMap {
put(AnalyticsParam.CREATION_TYPE, creationType.value)
if (seedPhraseLength != null) put(AnalyticsParam.SEED_PHRASE_LENGTH, seedPhraseLength.toString())
},
)
}

View file

@ -22,6 +22,7 @@ sealed class Settings(
class ButtonAppSettings : Settings(event = "Button - App Settings")
class ButtonCreateBackup : Settings(event = "Button - Create Backup")
class ButtonWalletConnect : Settings(event = "Button - Wallet Connect")
object ScanNewCard : Settings(event = "Button - Scan New Card")
class ButtonSocialNetwork(network: SocialNetwork) : Settings(
event = "Button - Social Network",
@ -78,5 +79,10 @@ sealed class Settings(
)
object ButtonEnableBiometricAuthentication : AppSettings(event = "Button - Enable Biometric Authentication")
class MainCurrencyChanged(currencyType: String) : MainScreen(
event = "Main Currency Changed",
params = mapOf("Currency Type" to currencyType),
)
}
}

View file

@ -45,6 +45,7 @@ class CardContextInterceptor(
ProductType.Note -> "Note"
ProductType.Twins -> "Twin"
ProductType.Wallet -> "Wallet"
ProductType.Wallet2 -> "Wallet 2.0"
ProductType.Start2Coin -> "Start2Coin"
else -> if (DemoHelper.isDemoCard(scanResponse)) {
if (DemoHelper.isTestDemoCard(scanResponse)) {

View file

@ -169,7 +169,7 @@ private fun fragmentFactory(screen: AppScreen): Fragment {
AppScreen.AddCustomToken -> AddCustomTokenFragment()
AppScreen.WalletDetails -> {
val featureToggles = store.state.daggerGraphState.get(
getDependency = DaggerGraphState::tokenDetailsFeatureToggles,
getDependency = DaggerGraphState::walletFeatureToggles,
)
if (featureToggles.isRedesignedScreenEnabled) {
store.state.daggerGraphState

View file

@ -3,10 +3,12 @@ package com.tangem.tap.common.redux.global
import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.guard
import com.tangem.core.analytics.Analytics
import com.tangem.datasource.config.models.Config
import com.tangem.domain.common.LogConfig
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.common.analytics.events.Basic
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
import com.tangem.tap.common.extensions.dispatchDialogShow
@ -14,7 +16,6 @@ import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.extensions.dispatchWithMain
import com.tangem.tap.common.redux.AppDialog
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
import com.tangem.tap.features.send.redux.SendAction
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.network.exchangeServices.BuyExchangeService
@ -84,10 +85,10 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di
is GlobalAction.HideWarningMessage -> {
store.state.globalState.warningManager?.let {
if (it.hideWarning(action.warning)) {
if (WarningMessagesManager.isAlreadySignedHashesWarning(action.warning)) {
// TODO: No appropriate warningMessage identification. Make it better later
store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId)
}
// if (WarningMessagesManager.isAlreadySignedHashesWarning()) {
// // TODO: No appropriate warningMessage identification. Make it better later
// store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId)
// }
store.dispatch(WalletAction.Warnings.Update)
store.dispatch(SendAction.Warnings.Update)
@ -183,6 +184,8 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di
action.manager.selectedUserWallet
.distinctUntilChanged()
.onEach { userWallet ->
Analytics.send(event = Basic.WalletOpened())
store.state.globalState.feedbackManager?.infoHolder?.let { infoHolder ->
infoHolder.setCardInfo(data = userWallet.scanResponse)

View file

@ -0,0 +1,20 @@
package com.tangem.tap.di.analytics
import com.tangem.domain.analytics.ChangeCardAnalyticsContextUseCase
import com.tangem.tap.common.analytics.DefaultChangeCardAnalyticsContextUseCase
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
internal object AnalyticsModule {
@Provides
@Singleton
fun provideChangeCardAnalyticsContextUseCase(): ChangeCardAnalyticsContextUseCase {
return DefaultChangeCardAnalyticsContextUseCase()
}
}

View file

@ -16,6 +16,7 @@ import dagger.hilt.android.scopes.ViewModelScoped
@Module
@InstallIn(ViewModelComponent::class)
@Suppress("TooManyFunctions")
internal object TokensDomainModule {
@Provides
@ -122,6 +123,16 @@ internal object TokensDomainModule {
return FetchCurrencyStatusUseCase(currenciesRepository, networksRepository, quotesRepository)
}
@Provides
@ViewModelScoped
fun provideFetchCardTokenListUseCase(
currenciesRepository: CurrenciesRepository,
quotesRepository: QuotesRepository,
networksRepository: NetworksRepository,
): FetchCardTokenListUseCase {
return FetchCardTokenListUseCase(currenciesRepository, networksRepository, quotesRepository)
}
@Provides
@ViewModelScoped
fun provideGetCryptoCurrencyUseCase(currenciesRepository: CurrenciesRepository): GetCryptoCurrencyUseCase {
@ -202,4 +213,12 @@ internal object TokensDomainModule {
networksRepository = networksRepository,
)
}
@Provides
@ViewModelScoped
fun provideHasMissedAddressesCryptoCurrenciesUseCase(
currenciesRepository: CurrenciesRepository,
): GetMissedAddressesCryptoCurrenciesUseCase {
return GetMissedAddressesCryptoCurrenciesUseCase(currenciesRepository = currenciesRepository)
}
}

View file

@ -26,6 +26,12 @@ internal object WalletsDomainModule {
return GetUserWalletUseCase(walletsStateHolder = walletsStateHolder)
}
@Provides
@ViewModelScoped
fun providesGetSelectedWalletSyncUseCase(walletsStateHolder: WalletsStateHolder): GetSelectedWalletSyncUseCase {
return GetSelectedWalletSyncUseCase(walletsStateHolder = walletsStateHolder)
}
@Provides
@ViewModelScoped
fun providesGetSelectedWalletUseCase(walletsStateHolder: WalletsStateHolder): GetSelectedWalletUseCase {

View file

@ -8,6 +8,8 @@ import java.util.concurrent.CopyOnWriteArrayList
/**
[REDACTED_AUTHOR]
*/
// TODO: Delete with WalletFeatureToggles
@Deprecated(message = "Used only in old wallet screen")
class WarningMessagesManager {
private val warningsList = CopyOnWriteArrayList<WarningMessage>()
@ -73,7 +75,7 @@ class WarningMessagesManager {
location = listOf(WarningMessage.Location.MainScreen),
blockchains = null,
titleResId = R.string.common_warning,
messageResId = R.string.alert_developer_card,
// messageResId = R.string.alert_developer_card,
origin = WarningMessage.Origin.Local,
)
@ -85,7 +87,7 @@ class WarningMessagesManager {
location = listOf(WarningMessage.Location.MainScreen),
blockchains = null,
titleResId = R.string.common_warning,
messageResId = R.string.alert_card_signed_transactions,
// messageResId = R.string.alert_card_signed_transactions,
origin = WarningMessage.Origin.Local,
)
@ -96,8 +98,8 @@ class WarningMessagesManager {
priority = WarningMessage.Priority.Info,
location = listOf(WarningMessage.Location.MainScreen),
blockchains = null,
titleResId = R.string.warning_important_security_info,
messageResId = R.string.warning_signed_tx_previously,
// titleResId = R.string.warning_important_security_info,
// messageResId = R.string.warning_signed_tx_previously,
origin = WarningMessage.Origin.Local,
buttonTextId = R.string.warning_button_learn_more,
titleFormatArg = "\u26A0",
@ -147,7 +149,7 @@ class WarningMessagesManager {
location = listOf(WarningMessage.Location.MainScreen),
blockchains = null,
titleResId = R.string.common_warning,
messageResId = R.string.alert_demo_message,
// messageResId = R.string.alert_demo_message,
origin = WarningMessage.Origin.Local,
)
@ -160,14 +162,14 @@ class WarningMessagesManager {
location = listOf(WarningMessage.Location.MainScreen),
blockchains = null,
titleResId = R.string.common_warning,
messageResId = R.string.warning_low_signatures_format,
// messageResId = R.string.warning_low_signatures_format,
origin = WarningMessage.Origin.Local,
messageFormatArg = remainingSignatures.toString(),
)
}
fun isAlreadySignedHashesWarning(warning: WarningMessage): Boolean {
return warning.messageResId == R.string.alert_card_signed_transactions
}
// fun isAlreadySignedHashesWarning(warning: WarningMessage): Boolean {
// return warning.messageResId == R.string.alert_card_signed_transactions
// }
}
}

View file

@ -26,6 +26,7 @@ import com.tangem.tap.features.disclaimer.redux.DisclaimerCallback
import com.tangem.tap.features.onboarding.OnboardingHelper
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

View file

@ -8,13 +8,13 @@ import com.tangem.core.navigation.AppScreen
import com.tangem.core.navigation.NavigationAction
import com.tangem.domain.card.ScanCardException
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.domain.scanCard.chains.*
import com.tangem.tap.domain.scanCard.utils.ScanCardExceptionConverter
import com.tangem.tap.preferencesStorage
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.store
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
import kotlinx.coroutines.delay
internal object UseCaseScanProcessor {

View file

@ -11,7 +11,6 @@ import com.tangem.domain.common.TapWorkarounds.canSkipBackup
import com.tangem.domain.common.util.twinsIsTwinned
import com.tangem.domain.core.chain.Chain
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
import com.tangem.tap.common.extensions.addContext
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.extensions.setContext
@ -21,6 +20,7 @@ import com.tangem.tap.domain.TapWalletManager
import com.tangem.tap.features.onboarding.OnboardingHelper
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
import kotlinx.coroutines.delay
import org.rekotlin.Store

View file

@ -209,7 +209,9 @@ private class ScanWalletProcessor(
session: CardSession,
callback: (result: CompletionResult<ScanResponse>) -> Unit,
) {
val productType = ProductType.Wallet
val isWallet2 = card.settings.isKeysImportAllowed || card.firmwareVersion >= FirmwareVersion.KeysImportAvailable
val productType = if (isWallet2) ProductType.Wallet2 else ProductType.Wallet
val config = CardConfig.createConfig(card)
scope.launch {
val scanResponse = ScanResponse(

View file

@ -57,21 +57,11 @@ internal class BiometricUserWalletsListManager(
get() = state.value.userWallets.size
override suspend fun unlock(): CompletionResult<UserWallet> {
return unlockWithBiometryInternal()
.mapFailure { error ->
if (error is UserWalletsListError) {
error
} else {
UserWalletsListError.UnableToUnlockUserWallets(cause = error)
}
}
.map {
selectedUserWalletSync.guard {
throw UserWalletsListError.UnableToUnlockUserWallets(
cause = IllegalStateException("No user wallet selected"),
)
}
}
return unlockWithBiometryInternal().mapUnlockResult()
}
override suspend fun unlockAndSelect(selectedWalletId: UserWalletId): CompletionResult<UserWallet> {
return unlockWithBiometryInternal(selectedWalletId = selectedWalletId).mapUnlockResult()
}
override fun lock() {
@ -198,7 +188,7 @@ internal class BiometricUserWalletsListManager(
}
}
private suspend fun unlockWithBiometryInternal(): CompletionResult<Unit> {
private suspend fun unlockWithBiometryInternal(selectedWalletId: UserWalletId? = null): CompletionResult<Unit> {
return keysRepository.getAll()
.map { keys ->
state.update { prevState ->
@ -207,7 +197,7 @@ internal class BiometricUserWalletsListManager(
)
}
}
.flatMap { loadModels() }
.flatMap { loadModels(selectedWalletId = selectedWalletId) }
.map {
state.update { prevState ->
val hasLockedUserWallets = prevState.userWallets.any { it.isLocked }
@ -216,6 +206,24 @@ internal class BiometricUserWalletsListManager(
}
}
private fun CompletionResult<Unit>.mapUnlockResult(): CompletionResult<UserWallet> {
return this
.mapFailure { error ->
if (error is UserWalletsListError) {
error
} else {
UserWalletsListError.UnableToUnlockUserWallets(cause = error)
}
}
.map {
selectedUserWalletSync.guard {
throw UserWalletsListError.UnableToUnlockUserWallets(
cause = IllegalStateException("No user wallet selected"),
)
}
}
}
private suspend fun saveEncryptionKeyIfNotNull(userWallet: UserWallet): CompletionResult<ByteArray?> {
val encryptionKey = userWallet.scanResponse.card.encryptionKey
?.let { UserWalletEncryptionKey(userWallet.walletId, it) }
@ -237,7 +245,7 @@ internal class BiometricUserWalletsListManager(
}
}
private suspend fun loadModels(): CompletionResult<Unit> {
private suspend fun loadModels(selectedWalletId: UserWalletId? = null): CompletionResult<Unit> {
return getSavedUserWallets()
.map { userWallets ->
if (userWallets.isNotEmpty()) {
@ -247,7 +255,7 @@ internal class BiometricUserWalletsListManager(
prevState.copy(
userWallets = wallets,
selectedUserWalletId = findOrSetSelectedUserWalletId(
prevSelectedWalletId = prevState.selectedUserWalletId,
prevSelectedWalletId = selectedWalletId ?: prevState.selectedUserWalletId,
userWallets = wallets,
),
)

View file

@ -1,7 +1,7 @@
package com.tangem.tap.features.customtoken.impl.di
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.tap.features.customtoken.impl.data.DefaultCustomTokenRepository
import com.tangem.tap.features.customtoken.impl.domain.CustomTokenInteractor
import com.tangem.tap.features.customtoken.impl.domain.DefaultCustomTokenInteractor
@ -25,7 +25,7 @@ internal object CustomTokenInteractorModule {
fun provideCustomTokenInteractor(
tangemTechApi: TangemTechApi,
appCoroutineDispatcherProvider: AppCoroutineDispatcherProvider,
getSelectedWalletUseCase: GetSelectedWalletUseCase,
getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
reduxStateHolder: AppStateHolder,
): CustomTokenInteractor {
return DefaultCustomTokenInteractor(
@ -34,8 +34,7 @@ internal object CustomTokenInteractorModule {
dispatchers = appCoroutineDispatcherProvider,
reduxStateHolder = reduxStateHolder,
),
getSelectedWalletUseCase = getSelectedWalletUseCase,
reduxStateHolder = reduxStateHolder,
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
)
}
}

View file

@ -19,7 +19,7 @@ import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.operations.derivation.ExtendedPublicKeysMap
import com.tangem.tap.*
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
@ -29,8 +29,8 @@ import com.tangem.tap.domain.TapError
import com.tangem.tap.features.customtoken.impl.domain.models.FoundToken
import com.tangem.tap.features.tokens.legacy.redux.TokensMiddleware
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.proxy.AppStateHolder
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import timber.log.Timber
@ -39,14 +39,12 @@ import timber.log.Timber
* Default implementation of custom token interactor
*
* @property featureRepository feature repository
* @property reduxStateHolder redux state holder
*
[REDACTED_AUTHOR]
*/
class DefaultCustomTokenInteractor(
private val featureRepository: CustomTokenRepository,
private val getSelectedWalletUseCase: GetSelectedWalletUseCase,
private val reduxStateHolder: AppStateHolder,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
) : CustomTokenInteractor {
override suspend fun findToken(address: String, blockchain: Blockchain): FoundToken {
@ -57,28 +55,30 @@ class DefaultCustomTokenInteractor(
}
override suspend fun saveToken(customCurrency: CustomCurrency) {
val scanResponse = reduxStateHolder.scanResponse ?: return
val userWallet = getSelectedWalletSyncUseCase().fold(ifLeft = { return }, ifRight = { it })
val currency = Currency.fromCustomCurrency(customCurrency)
val isNeedToDerive = isNeedToDerive(scanResponse, currency)
val isNeedToDerive = isNeedToDerive(userWallet, currency)
if (isNeedToDerive) {
deriveMissingBlockchains(scanResponse = scanResponse, currencyList = listOf(currency)) {
submitAdd(scanResponse = it, currency = currency)
deriveMissingBlockchains(userWallet = userWallet, currencyList = listOf(currency)) {
submitAdd(userWallet = userWallet, currency = currency)
}
} else {
submitAdd(scanResponse, currency)
submitAdd(userWallet, currency)
}
}
private fun isNeedToDerive(scanResponse: ScanResponse, currency: Currency): Boolean {
private fun isNeedToDerive(userWallet: UserWallet, currency: Currency): Boolean {
val scanResponse = userWallet.scanResponse
return currency.derivationPath?.let { !scanResponse.hasDerivation(currency.blockchain, it) } ?: false
}
private suspend fun deriveMissingBlockchains(
scanResponse: ScanResponse,
userWallet: UserWallet,
currencyList: List<Currency>,
onSuccess: suspend (ScanResponse) -> Unit,
) {
val scanResponse = userWallet.scanResponse
val config = CardConfig.createConfig(scanResponse.card)
val derivationDataList = currencyList.mapNotNull { currency ->
val curve = config.primaryCurve(currency.blockchain)
@ -161,14 +161,15 @@ class DefaultCustomTokenInteractor(
return TokensMiddleware.DerivationData(derivations = mapKeyOfWalletPublicKey to toDerive)
}
private suspend fun submitAdd(scanResponse: ScanResponse, currency: Currency) {
private suspend fun submitAdd(userWallet: UserWallet, currency: Currency) {
val scanResponse = userWallet.scanResponse
val walletFeatureToggles = store.state.daggerGraphState.get(DaggerGraphState::walletFeatureToggles)
if (walletFeatureToggles.isRedesignedScreenEnabled) {
val cryptoCurrencyFactory = CryptoCurrencyFactory()
submitNewAdd(
userWalletId = getSelectedWalletUseCase().fold(ifLeft = { return }, ifRight = UserWallet::walletId),
userWalletId = userWallet.walletId,
updatedScanResponse = scanResponse,
currencyList = listOfNotNull(
when (currency) {
@ -219,7 +220,7 @@ class DefaultCustomTokenInteractor(
currencyList: List<CryptoCurrency>,
) {
val currenciesRepository = store.state.daggerGraphState.get(DaggerGraphState::currenciesRepository)
val networksRepository = store.state.daggerGraphState.get(DaggerGraphState::networksRepository)
scope.launch {
userWalletsListManager.update(
userWalletId = userWalletId,
@ -227,6 +228,12 @@ class DefaultCustomTokenInteractor(
)
currenciesRepository.addCurrencies(userWalletId = userWalletId, currencies = currencyList)
val networks = currencyList.map { it.network }.toSet()
networksRepository.getNetworkStatusesSync(
userWalletId = userWalletId,
networks = networks,
refresh = true,
)
}
}
}

View file

@ -24,7 +24,7 @@ import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.features.addCustomToken.CustomCurrency
import com.tangem.domain.tokens.GetCryptoCurrenciesUseCase
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
import com.tangem.tap.domain.model.WalletDataModel
import com.tangem.tap.features.customtoken.impl.domain.CustomTokenInteractor
@ -54,11 +54,11 @@ import javax.inject.Inject
/**
* ViewModel for add custom token screen
*
* @param analyticsEventHandler analytics event handler
* @param featureRouter feature router
* @property featureInteractor feature interactor
* @property getSelectedWalletUseCase use case that returns selected wallet
* @property dispatchers coroutine dispatchers provider
* @param analyticsEventHandler analytics event handler
* @param featureRouter feature router
* @property featureInteractor feature interactor
* @property getSelectedWalletSyncUseCase use case that returns selected wallet
* @property dispatchers coroutine dispatchers provider
*
[REDACTED_AUTHOR]
*/
@ -70,7 +70,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
getCurrenciesUseCase: GetCryptoCurrenciesUseCase,
private val featureInteractor: CustomTokenInteractor,
private val dispatchers: AppCoroutineDispatcherProvider,
private val getSelectedWalletUseCase: GetSelectedWalletUseCase,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
private val walletFeatureToggles: WalletFeatureToggles,
) : ViewModel(), DefaultLifecycleObserver {
@ -90,7 +90,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
init {
if (walletFeatureToggles.isRedesignedScreenEnabled) {
viewModelScope.launch(dispatchers.main) {
currentCryptoCurrencies = getSelectedWalletUseCase().fold(
currentCryptoCurrencies = getSelectedWalletSyncUseCase().fold(
ifLeft = { emptyList() },
ifRight = { selectedWallet ->
getCurrenciesUseCase(selectedWallet.walletId).fold(
@ -231,7 +231,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
private fun getNetworkSelectorItems(): List<SelectorItem.Title> {
val defaultNetwork = createNetworkSelectorItem(blockchain = Blockchain.Unknown)
val scanResponse = getSelectedWalletUseCase().fold(
val scanResponse = getSelectedWalletSyncUseCase().fold(
ifLeft = { null },
ifRight = { it.scanResponse },
)
@ -288,7 +288,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
}
private fun createDerivationPathsSelectorField(): AddCustomTokenSelectorField.DerivationPath? {
return getSelectedWalletUseCase().fold(
return getSelectedWalletSyncUseCase().fold(
ifLeft = { null },
ifRight = {
if (!it.scanResponse.card.settings.isHDWalletAllowed) return null
@ -344,7 +344,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
}
private fun createDerivationPathInputField(): AddCustomTokenInputField.DerivationPath? {
return getSelectedWalletUseCase().fold(
return getSelectedWalletSyncUseCase().fold(
ifLeft = { null },
ifRight = {
if (!it.scanResponse.card.settings.isHDWalletAllowed) return null
@ -474,7 +474,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
val isSupportedToken = if (!isNetworkSelected()) {
true
} else {
getSelectedWalletUseCase().fold(
getSelectedWalletSyncUseCase().fold(
ifLeft = { false },
ifRight = {
it.scanResponse.card.canHandleToken(
@ -517,7 +517,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
blockchain = networkSelectorValue,
)
val isSupportedToken = getSelectedWalletUseCase().fold(
val isSupportedToken = getSelectedWalletSyncUseCase().fold(
ifLeft = { false },
ifRight = {
it.scanResponse.card.canHandleToken(
@ -726,7 +726,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
private fun getDerivationPathForBlockchain(blockchain: Blockchain?): DerivationPath? {
if (blockchain == null) return null
val derivationStyle = getSelectedWalletUseCase().fold(
val derivationStyle = getSelectedWalletSyncUseCase().fold(
ifLeft = { null },
ifRight = {
it.scanResponse.derivationStyleProvider.getDerivationStyle()
@ -742,7 +742,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
}
private fun isUnsupportedBlockchain(blockchain: Blockchain): Boolean {
return getSelectedWalletUseCase().fold(
return getSelectedWalletSyncUseCase().fold(
ifLeft = { false },
ifRight = {
!it.scanResponse.card.canHandleBlockchain(

View file

@ -2,10 +2,12 @@ package com.tangem.tap.features.details.ui.appcurrency
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.navigation.ReduxNavController
import com.tangem.domain.appcurrency.GetAvailableCurrenciesUseCase
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.SelectAppCurrencyUseCase
import com.tangem.tap.common.analytics.events.Settings
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.StateFlow
@ -20,6 +22,7 @@ internal class AppCurrencySelectorViewModel @Inject constructor(
private val selectAppCurrencyUseCase: SelectAppCurrencyUseCase,
private val reduxNavController: ReduxNavController,
private val dispatchers: CoroutineDispatcherProvider,
private val analyticsEventHandler: AnalyticsEventHandler,
) : ViewModel(), AppCurrencySelectorIntents {
private val stateController = AppCurrencySelectorStateHolder(
@ -45,7 +48,12 @@ internal class AppCurrencySelectorViewModel @Inject constructor(
override fun onCurrencyClick(currency: AppCurrencySelectorState.Currency) {
viewModelScope.launch(dispatchers.io) {
selectAppCurrencyUseCase(currency.id)
.onRight { reduxNavController.popBackStack() }
.onRight {
analyticsEventHandler.send(
event = Settings.AppSettings.MainCurrencyChanged(currencyType = currency.name),
)
reduxNavController.popBackStack()
}
}
}
@ -60,14 +68,12 @@ internal class AppCurrencySelectorViewModel @Inject constructor(
.getOrNull()
getSelectedAppCurrencyUseCase().collectLatest { maybeSelectedCurrency ->
maybeSelectedCurrency
.onRight { selectedCurrency ->
val selectedCurrencyIndex = availableCurrencies?.indexOfFirst { it == selectedCurrency }
val selectedCurrency = maybeSelectedCurrency.getOrNull() ?: return@collectLatest
val selectedCurrencyIndex = availableCurrencies?.indexOfFirst { it == selectedCurrency }
if (selectedCurrencyIndex != null && selectedCurrencyIndex != -1) {
stateController.updateStateWithSelectedCurrency(selectedCurrency, selectedCurrencyIndex)
}
}
if (selectedCurrencyIndex != null && selectedCurrencyIndex != -1) {
stateController.updateStateWithSelectedCurrency(selectedCurrency, selectedCurrencyIndex)
}
}
}
}

View file

@ -9,7 +9,7 @@ import arrow.core.Either
import com.tangem.core.analytics.Analytics
import com.tangem.domain.common.TapWorkarounds.isTangemTwins
import com.tangem.domain.common.getTwinCardIdForUser
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Settings
import com.tangem.tap.common.extensions.dispatchOnMain
@ -17,15 +17,15 @@ import com.tangem.tap.features.details.redux.CardSettingsState
import com.tangem.tap.features.details.redux.DetailsAction
import com.tangem.tap.features.details.redux.DetailsState
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.store
import dagger.hilt.android.lifecycle.HiltViewModel
import org.rekotlin.StoreSubscriber
import com.tangem.tap.store
import timber.log.Timber
import javax.inject.Inject
@HiltViewModel
internal class CardSettingsViewModel @Inject constructor(
private val getSelectedWalletUseCase: GetSelectedWalletUseCase,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
) :
ViewModel(), DefaultLifecycleObserver, StoreSubscriber<DetailsState> {
@ -33,7 +33,7 @@ internal class CardSettingsViewModel @Inject constructor(
mutableStateOf(updateState(store.state.detailsState.cardSettingsState))
override fun onStart(owner: LifecycleOwner) {
when (val selectedWalletEither = getSelectedWalletUseCase()) {
when (val selectedWalletEither = getSelectedWalletSyncUseCase()) {
is Either.Left -> {
Timber.e(selectedWalletEither.value.toString())
}

View file

@ -161,6 +161,7 @@ internal class DetailsViewModel(
}
private fun scanAndSaveUserWallet() {
Analytics.send(Settings.ScanNewCard)
store.dispatch(DetailsAction.ScanAndSaveUserWallet)
}

View file

@ -8,6 +8,7 @@ import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.ComposeView
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsControllerCompat
@ -16,6 +17,7 @@ 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.components.SystemBarsEffect
import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.tokens.TokensAction
import com.tangem.tap.common.analytics.events.IntroductionProcess
@ -52,6 +54,12 @@ class HomeFragment : Fragment(), StoreSubscriber<HomeState> {
BackHandler {
requireActivity().finish()
}
SystemBarsEffect {
setSystemBarsColor(
color = Color.Transparent,
darkIcons = false,
)
}
ScreenContent()
}
}

View file

@ -12,18 +12,13 @@ import androidx.compose.foundation.layout.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
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.*
@ -43,7 +38,6 @@ fun StoriesScreen(
onShopButtonClick: () -> Unit,
onSearchTokensClick: () -> Unit,
) {
val systemUiController = rememberSystemUiController()
val state = homeState.value
var currentStory by remember { mutableStateOf(state.firstStory) }
@ -62,13 +56,6 @@ fun StoriesScreen(
}
}
LaunchedEffect(key1 = currentStory.isDarkBackground) {
systemUiController.setSystemBarsColor(
color = Color.Transparent,
darkIcons = !currentStory.isDarkBackground,
)
}
StoriesScreenContent(
modifier = Modifier.fillMaxSize(),
config = StoriesScreenContentConfig(
@ -90,13 +77,12 @@ fun StoriesScreen(
@Composable
private fun StoriesScreenContent(config: StoriesScreenContentConfig, modifier: Modifier = Modifier) {
var isPressed by remember { mutableStateOf(value = false) }
var hideContent by remember { mutableStateOf(value = true) }
val isPaused = isPressed || config.isScanInProgress
val currentStoryDuration = config.currentStory.duration
Box(
modifier = modifier.background(Color(0xFF090E13)),
modifier = modifier.background(Color(0xFF010101)),
) {
Row(
modifier = Modifier.fillMaxSize(),
@ -138,14 +124,6 @@ private fun StoriesScreenContent(config: StoriesScreenContentConfig, modifier: M
},
)
}
if (!config.currentStory.isDarkBackground) {
Image(
modifier = Modifier.fillMaxSize(),
painter = painterResource(id = R.drawable.ic_overlay),
contentDescription = null,
contentScale = ContentScale.FillBounds,
)
}
Column(
modifier = Modifier
@ -166,30 +144,23 @@ private fun StoriesScreenContent(config: StoriesScreenContentConfig, modifier: M
contentDescription = null,
contentScale = ContentScale.FillHeight,
modifier = Modifier
.padding(start = 16.dp, top = 10.dp)
.height(17.dp)
.alpha(if (hideContent) 0f else 1f)
.padding(
start = TangemTheme.dimens.spacing16,
top = TangemTheme.dimens.spacing16,
)
.height(TangemTheme.dimens.size18)
.align(Alignment.Start),
colorFilter = if (config.currentStory.isDarkBackground) {
null
} else {
ColorFilter.tint(TangemColorPalette.Dark6)
},
)
when (config.currentStory) {
Stories.OneInchPromo -> Learn2earnStoriesScreen(config.onLearn2earnClick)
Stories.TangemIntro -> FirstStoriesContent(
isPaused = isPaused,
duration = currentStoryDuration,
isNewWalletAvailable = config.currentStory.isNewWalletAvailable,
) {
hideContent = it
}
Stories.RevolutionaryWallet -> StoriesRevolutionaryWallet(currentStoryDuration)
)
Stories.RevolutionaryWallet -> StoriesRevolutionaryWallet()
is Stories.UltraSecureBackup -> StoriesUltraSecureBackup(
isPaused = isPaused,
stepDuration = currentStoryDuration,
isNewWalletAvailable = config.currentStory.isNewWalletAvailable,
)
Stories.Currencies -> StoriesCurrencies(isPaused, currentStoryDuration)
Stories.Web3 -> StoriesWeb3(isPaused, currentStoryDuration)
@ -223,7 +194,6 @@ private fun StoriesScreenContent(config: StoriesScreenContentConfig, modifier: M
) {
HomeButtons(
modifier = Modifier.fillMaxWidth(),
isDarkBackground = config.currentStory.isDarkBackground,
btnScanStateInProgress = config.isScanInProgress,
onScanButtonClick = config.onScanButtonClick,
onShopButtonClick = config.onShopButtonClick,

View file

@ -5,79 +5,56 @@ import androidx.compose.foundation.Image
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
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.components.SpacerH16
import com.tangem.core.ui.components.SpacerH32
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.tap.features.home.compose.StoriesBottomImageAnimation
import com.tangem.tap.features.home.compose.StoriesTextAnimation
import com.tangem.wallet.R
@Composable
fun StoriesRevolutionaryWallet(stepDuration: Int) {
fun StoriesRevolutionaryWallet() {
SplitContent(
topContent = {
TopContent(
titleText = stringResource(id = R.string.story_awe_title),
subtitleText = stringResource(id = R.string.story_awe_description).annotated(),
isDarkBackground = true,
subtitleText = stringResource(id = R.string.story_awe_description),
)
},
bottomContent = {
StoriesBottomImageAnimation(
totalDuration = stepDuration,
firstStepDuration = 300,
) { modifier ->
StoriesImage(
modifier = modifier,
drawableResId = R.drawable.revolutionary_wallet,
isDarkBackground = true,
)
}
SpacerH32()
StoriesImage(
modifier = Modifier,
drawableResId = R.drawable.img_revolutionary_wallet,
)
},
)
}
@Composable
fun StoriesUltraSecureBackup(isPaused: Boolean, stepDuration: Int, isNewWalletAvailable: MutableState<Boolean>) {
val subtitleText = buildAnnotatedString {
append(stringResource(id = R.string.story_backup_description_1))
append(" ")
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
append(stringResource(id = R.string.story_backup_description_2_bold))
}
append(" ")
append(stringResource(id = R.string.story_backup_description_3))
}
fun StoriesUltraSecureBackup(isPaused: Boolean, stepDuration: Int) {
SplitContent(
topContent = {
TopContent(
titleText = stringResource(id = R.string.story_backup_title),
subtitleText = subtitleText,
isDarkBackground = false,
subtitleText = stringResource(id = R.string.story_backup_description),
)
},
bottomContent = {
SpacerH32()
FloatingCardsContent(
isPaused = isPaused,
stepDuration = stepDuration,
isNewWalletAvailable = isNewWalletAvailable,
)
},
)
@ -89,11 +66,11 @@ fun StoriesCurrencies(isPaused: Boolean, stepDuration: Int) {
topContent = {
TopContent(
titleText = stringResource(id = R.string.story_currencies_title),
subtitleText = stringResource(id = R.string.story_currencies_description).annotated(),
isDarkBackground = false,
subtitleText = stringResource(id = R.string.story_currencies_description),
)
},
bottomContent = {
SpacerH32()
StoriesCurrenciesContent(paused = isPaused, duration = stepDuration)
},
)
@ -105,11 +82,11 @@ fun StoriesWeb3(isPaused: Boolean, stepDuration: Int) {
topContent = {
TopContent(
titleText = stringResource(id = R.string.story_web3_title),
subtitleText = stringResource(id = R.string.story_web3_description).annotated(),
isDarkBackground = false,
subtitleText = stringResource(id = R.string.story_web3_description),
)
},
bottomContent = {
SpacerH(TangemTheme.dimens.spacing70)
StoriesWeb3Content(paused = isPaused, duration = stepDuration)
},
)
@ -121,20 +98,21 @@ fun StoriesWalletForEveryone(stepDuration: Int) {
topContent = {
TopContent(
titleText = stringResource(id = R.string.story_finish_title),
subtitleText = stringResource(id = R.string.story_finish_description).annotated(),
isDarkBackground = true,
subtitleText = stringResource(id = R.string.story_finish_description),
)
},
bottomContent = {
StoriesBottomImageAnimation(
totalDuration = stepDuration,
firstStepDuration = 500,
) { modifier ->
StoriesImage(
modifier = modifier,
drawableResId = R.drawable.wallet_for_everyone,
isDarkBackground = true,
)
SpacerH32()
BoxWithGradient {
StoriesBottomImageAnimation(
totalDuration = stepDuration,
firstStepDuration = 500,
) { modifier ->
StoriesImage(
modifier = modifier,
drawableResId = R.drawable.img_tangem_for_everyone,
)
}
}
},
)
@ -154,22 +132,20 @@ private fun SplitContent(topContent: @Composable () -> Unit, bottomContent: @Com
}
@Composable
private fun TopContent(titleText: String, subtitleText: AnnotatedString, isDarkBackground: Boolean) {
SpacerH32()
private fun TopContent(titleText: String, subtitleText: String) {
SpacerH(TangemTheme.dimens.spacing36)
StoriesTitleText(
text = titleText,
isDarkBackground = isDarkBackground,
)
SpacerH16()
StoriesSubtitleText(
subtitleText = subtitleText,
)
SpacerH32()
}
@Suppress("MagicNumber")
@Composable
private fun StoriesTitleText(text: String, isDarkBackground: Boolean) {
private fun StoriesTitleText(text: String) {
StoriesTextAnimation(
slideInDuration = 500,
slideInDelay = 150,
@ -178,10 +154,8 @@ private fun StoriesTitleText(text: String, isDarkBackground: Boolean) {
modifier = modifier
.padding(start = 40.dp, end = 40.dp),
text = text,
fontSize = 32.sp,
lineHeight = 38.sp,
fontWeight = FontWeight.SemiBold,
color = if (isDarkBackground) Color.White else Color(0xFF090E13),
style = TangemTheme.typography.head,
color = TangemColorPalette.White,
textAlign = TextAlign.Center,
)
}
@ -189,9 +163,7 @@ private fun StoriesTitleText(text: String, isDarkBackground: Boolean) {
@Suppress("MagicNumber")
@Composable
private fun StoriesSubtitleText(subtitleText: AnnotatedString) {
val color = Color(0xFFA6AAAD)
private fun StoriesSubtitleText(subtitleText: String) {
StoriesTextAnimation(
slideInDuration = 500,
slideInDelay = 400,
@ -199,35 +171,28 @@ private fun StoriesSubtitleText(subtitleText: AnnotatedString) {
Text(
modifier = modifier
.padding(start = 40.dp, end = 40.dp),
fontWeight = FontWeight.Normal,
text = subtitleText,
fontSize = 20.sp,
lineHeight = 26.sp,
color = color,
style = TangemTheme.typography.body1,
color = TangemColorPalette.Dark1,
textAlign = TextAlign.Center,
)
}
}
@Composable
private fun StoriesImage(@DrawableRes drawableResId: Int, isDarkBackground: Boolean, modifier: Modifier = Modifier) {
private fun StoriesImage(@DrawableRes drawableResId: Int, modifier: Modifier = Modifier) {
Image(
painter = painterResource(id = drawableResId),
contentDescription = null,
contentScale = if (isDarkBackground) ContentScale.Inside else ContentScale.FillWidth,
contentScale = ContentScale.FillWidth,
modifier = modifier.fillMaxWidth(),
)
}
private fun String.annotated(): AnnotatedString {
val source = this
return buildAnnotatedString { append(source) }
}
@Preview
@Composable
private fun RevolutionaryWalletPreview() {
StoriesRevolutionaryWallet(6000)
StoriesRevolutionaryWallet()
}
@Preview
@ -236,9 +201,6 @@ private fun UltraSecureBackupPreview() {
StoriesUltraSecureBackup(
false,
6000,
remember {
mutableStateOf(true)
},
)
}

View file

@ -40,7 +40,7 @@ fun StoriesCurrenciesContent(paused: Boolean, duration: Int) {
val decreaseRate = remember { 1f / currencyDrawableList.size }
val designItemHeight = remember { 82.dp }
LightenBox {
BoxWithGradient {
Column(modifier = Modifier.graphicsLayer(clip = false)) {
currencyDrawableList.forEachIndexed { index, drawableResId ->
val painter = painterResource(id = drawableResId)
@ -72,7 +72,7 @@ fun StoriesCurrenciesContent(paused: Boolean, duration: Int) {
fun StoriesWeb3Content(paused: Boolean, duration: Int) {
val dappsItemList = remember {
listOf(
R.drawable.dapps0,
R.drawable.dapps1,
R.drawable.dapps1,
R.drawable.dapps2,
R.drawable.dapps3,
@ -84,7 +84,7 @@ fun StoriesWeb3Content(paused: Boolean, duration: Int) {
val decreaseRate = remember { 1f / dappsItemList.size }
val designItemHeight = 75.dp
LightenBox {
BoxWithGradient {
Column(modifier = Modifier.graphicsLayer(clip = false)) {
dappsItemList.forEachIndexed { index, drawableResId ->
val painter = painterResource(id = drawableResId)
@ -111,7 +111,7 @@ fun StoriesWeb3Content(paused: Boolean, duration: Int) {
}
@Composable
private fun LightenBox(content: @Composable () -> Unit) {
internal fun BoxWithGradient(content: @Composable () -> Unit) {
val bottomInsetsPx = WindowInsets.navigationBars.getBottom(LocalDensity.current)
Box(modifier = Modifier.fillMaxSize()) {
@ -133,9 +133,9 @@ private fun scaleToDesignSize(itemSize: DpSize, designItemHeight: Dp): DpSize {
private val BottomGradient: Brush = Brush.verticalGradient(
colors = listOf(
TangemColorPalette.White.copy(alpha = 0f),
TangemColorPalette.White.copy(alpha = 0.75f),
TangemColorPalette.White.copy(alpha = 0.95f),
TangemColorPalette.White,
TangemColorPalette.Black.copy(alpha = 0f),
TangemColorPalette.Black.copy(alpha = 0.75f),
TangemColorPalette.Black.copy(alpha = 0.95f),
TangemColorPalette.Black,
),
)

View file

@ -1,46 +1,36 @@
package com.tangem.tap.features.home.compose.content
import androidx.annotation.StringRes
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.tap.common.compose.FontSizeRange
import com.tangem.tap.common.compose.TextAutoSize
import com.tangem.tap.features.home.compose.StoriesBottomImageAnimation
import com.tangem.tap.features.home.compose.StoriesTextAnimation
import com.tangem.wallet.R
@Suppress("LongMethod", "ComplexMethod", "MagicNumber")
@Composable
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) }
fun FirstStoriesContent(isPaused: Boolean, duration: Int) {
val progress = remember { Animatable(0f) }
LaunchedEffect(isPaused) {
@ -57,142 +47,51 @@ fun FirstStoriesContent(
}
}
when (progress.value) {
in 0f..0.2f -> screenState.value = StartingScreenState.INIT
in 0.2f..0.3f -> screenState.value = StartingScreenState.BUY
in 0.3f..0.4f -> screenState.value = StartingScreenState.STORE
in 0.4f..0.5f -> screenState.value = StartingScreenState.SEND
in 0.5f..0.6f -> screenState.value = StartingScreenState.PAY
in 0.6f..0.7f -> screenState.value = StartingScreenState.EXCHANGE
in 0.7f..0.8f -> screenState.value = StartingScreenState.BORROW
in 0.8f..1f -> screenState.value = StartingScreenState.LEND
in 1f..1.2f -> screenState.value = StartingScreenState.SHOW_CARD
in 1.2f..2f -> screenState.value = StartingScreenState.MEET_TANGEM
}
if (screenState.value == StartingScreenState.INIT) onHideContent(true)
if (screenState.value == StartingScreenState.BUY) onHideContent(false)
val style = TextStyle(
fontSize = 60.sp,
fontSize = 46.sp,
fontWeight = FontWeight.SemiBold,
color = Color.White,
textAlign = TextAlign.Center,
)
val textId = screenState.textId()
Box(modifier = Modifier.fillMaxSize()) {
if (screenState.isSplashingTextDisplaying()) {
TextAutoSize(
modifier = Modifier
.align(Alignment.Center)
.padding(start = 20.dp, end = 20.dp, bottom = 100.dp),
text = textId?.let { stringResource(textId) } ?: "",
textStyle = style,
fontSizeRange = FontSizeRange(20.sp, 60.sp),
)
} else {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Box(
modifier = Modifier
.weight(0.7f),
) {
if (screenState.isMeetTangemDisplaying()) {
StoriesTextAnimation(
slideInDelay = 0,
) { modifier ->
TextAutoSize(
modifier = modifier
.padding(start = 20.dp, end = 20.dp, top = 50.dp)
.alpha(if (screenState.value == StartingScreenState.SHOW_CARD) 0f else 1f),
text = textId?.let { stringResource(textId) } ?: "",
textStyle = style,
fontSizeRange = FontSizeRange(30.sp, 50.sp),
)
}
}
}
Box(
modifier = Modifier
.fillMaxWidth()
.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 = painter,
contentDescription = "Tangem Wallet card",
)
}
}
Box {
Column(
modifier = Modifier
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
SpacerH(TangemTheme.dimens.spacing94)
StoriesTextAnimation(
slideInDuration = 500,
slideInDelay = 150,
) { modifier ->
Text(
modifier = modifier
.weight(1f),
text = stringResource(R.string.story_meet_title),
style = style,
color = TangemColorPalette.White,
textAlign = TextAlign.Center,
)
}
SpacerH(TangemTheme.dimens.spacing46)
}
Box(
Image(
modifier = Modifier
.align(Alignment.BottomCenter)
.fillMaxWidth()
.height(TangemTheme.dimens.size72 + bottomInsetsPx.dp)
.background(BottomGradient),
.fillMaxWidth(),
painter = painterResource(R.drawable.img_meet_tangem),
contentScale = ContentScale.FillWidth,
contentDescription = "Tangem Wallet card",
)
}
}
private val BottomGradient: Brush = Brush.verticalGradient(
colors = listOf(
TangemColorPalette.Black.copy(alpha = 0f),
TangemColorPalette.Black.copy(alpha = 0.75f),
TangemColorPalette.Black.copy(alpha = 0.95f),
TangemColorPalette.Black,
),
)
private enum class StartingScreenState {
INIT, BUY, STORE, SEND, PAY, EXCHANGE, BORROW, LEND, SHOW_CARD, MEET_TANGEM
}
@StringRes
private fun MutableState<StartingScreenState>.textId(): Int? = when (this.value) {
StartingScreenState.INIT -> null
StartingScreenState.BUY -> R.string.story_meet_buy
StartingScreenState.STORE -> R.string.story_meet_store
StartingScreenState.SEND -> R.string.story_meet_send
StartingScreenState.PAY -> R.string.story_meet_pay
StartingScreenState.EXCHANGE -> R.string.story_meet_exchange
StartingScreenState.BORROW -> R.string.story_meet_borrow
StartingScreenState.LEND -> R.string.story_meet_lend
StartingScreenState.SHOW_CARD -> R.string.story_meet_title
StartingScreenState.MEET_TANGEM -> R.string.story_meet_title
}
private fun MutableState<StartingScreenState>.isSplashingTextDisplaying(): Boolean {
return this.value != StartingScreenState.MEET_TANGEM &&
this.value != StartingScreenState.SHOW_CARD
}
private fun MutableState<StartingScreenState>.isMeetTangemDisplaying(): Boolean {
return this.value == StartingScreenState.MEET_TANGEM
}
@Preview
@Composable
private fun FirstStoriesPreview() {
FirstStoriesContent(
false,
8000,
remember {
mutableStateOf(false)
},
) {}
)
}

View file

@ -1,18 +1,11 @@
package com.tangem.tap.features.home.compose.content
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
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.tap.common.compose.extensions.AnimatedValue
import com.tangem.tap.common.compose.extensions.asImageBitmap
import com.tangem.tap.common.compose.extensions.toAnimatable
@ -22,13 +15,8 @@ import com.tangem.wallet.R
[REDACTED_AUTHOR]
*/
@Composable
fun FloatingCardsContent(isPaused: Boolean, stepDuration: Int, isNewWalletAvailable: MutableState<Boolean>) {
val bottomInsetsPx = WindowInsets.navigationBars.getBottom(LocalDensity.current)
val imageBitmap = if (isNewWalletAvailable.value) {
asImageBitmap(R.drawable.img_card_placeholder_wallet_2)
} else {
asImageBitmap(R.drawable.card_placeholder_wallet)
}
fun FloatingCardsContent(isPaused: Boolean, stepDuration: Int) {
val imageBitmap = asImageBitmap(R.drawable.img_card_placeholder_wallet_2)
val cards = listOf(
FloatingCard.first(),
FloatingCard.second(),
@ -44,14 +32,6 @@ fun FloatingCardsContent(isPaused: Boolean, stepDuration: Int, isNewWalletAvaila
stepDuration = stepDuration,
)
}
Box(
modifier = Modifier
.align(Alignment.BottomCenter)
.fillMaxWidth()
.height(bottomInsetsPx.dp)
.background(BottomGradient),
)
}
}
@ -114,12 +94,4 @@ private object FloatingCard {
rotationZ = -45f to -30f,
scale = 0.6f to 0.75f,
)
}
private val BottomGradient: Brush = Brush.verticalGradient(
colors = listOf(
TangemColorPalette.White.copy(alpha = 0f),
TangemColorPalette.White.copy(alpha = 0.75f),
TangemColorPalette.White.copy(alpha = 0.95f),
),
)
}

View file

@ -24,7 +24,6 @@ import com.tangem.wallet.R
@Suppress("MagicNumber")
@Composable
internal fun HomeButtons(
isDarkBackground: Boolean,
btnScanStateInProgress: Boolean,
onScanButtonClick: () -> Unit,
onShopButtonClick: () -> Unit,
@ -36,31 +35,24 @@ internal fun HomeButtons(
) {
ScanCardButton(
modifier = Modifier.weight(weight = 1f),
isDarkBackground = isDarkBackground,
showProgress = btnScanStateInProgress,
onClick = onScanButtonClick,
)
SpacerW8()
OrderCardButton(
modifier = Modifier.weight(weight = 1f),
isDarkBackground = isDarkBackground,
onClick = onShopButtonClick,
)
}
}
@Composable
private fun ScanCardButton(
isDarkBackground: Boolean,
showProgress: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
private fun ScanCardButton(showProgress: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) {
TangemButton(
modifier = modifier,
text = stringResource(id = R.string.home_button_scan),
icon = TangemButtonIconPosition.End(iconResId = R.drawable.ic_tangem_24),
colors = if (isDarkBackground) DarkBgScanCardButtonColors else LightBgScanCardButtonColors,
colors = LightBgScanCardButtonColors,
showProgress = showProgress,
enabled = true,
onClick = onClick,
@ -68,12 +60,12 @@ private fun ScanCardButton(
}
@Composable
private fun OrderCardButton(isDarkBackground: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) {
private fun OrderCardButton(onClick: () -> Unit, modifier: Modifier = Modifier) {
TangemButton(
modifier = modifier,
text = stringResource(id = R.string.home_button_order),
icon = TangemButtonIconPosition.None,
colors = if (isDarkBackground) DarkBgOrderCardButtonColors else LightBgOrderCardButtonColors,
colors = LightBgOrderCardButtonColors,
showProgress = false,
enabled = true,
onClick = onClick,
@ -87,13 +79,6 @@ private val LightBgScanCardButtonColors: ButtonColors = TangemButtonColors(
disabledContentColor = TangemColorPalette.Dark6,
)
private val DarkBgScanCardButtonColors: ButtonColors = TangemButtonColors(
backgroundColor = TangemColorPalette.Dark5,
contentColor = TangemColorPalette.White,
disabledBackgroundColor = TangemColorPalette.Dark5,
disabledContentColor = TangemColorPalette.White,
)
private val LightBgOrderCardButtonColors: ButtonColors = TangemButtonColors(
backgroundColor = TangemColorPalette.Dark6,
contentColor = TangemColorPalette.White,
@ -101,24 +86,16 @@ private val LightBgOrderCardButtonColors: ButtonColors = TangemButtonColors(
disabledContentColor = TangemColorPalette.White,
)
private val DarkBgOrderCardButtonColors: ButtonColors = TangemButtonColors(
backgroundColor = TangemColorPalette.Light1,
contentColor = TangemColorPalette.Dark6,
disabledBackgroundColor = TangemColorPalette.Light1,
disabledContentColor = TangemColorPalette.Dark6,
)
// region Preview
@Preview(showBackground = true, widthDp = 360)
@Composable
private fun HomeButtonsPreview(@PreviewParameter(HomeButtonsParameterProvider::class) state: HomeButtonsState) {
TangemTheme {
Box(
modifier = Modifier.background(if (state.isDarkBackground) Color.Black else Color.White),
modifier = Modifier.background(Color.Black),
) {
HomeButtons(
modifier = Modifier.padding(all = TangemTheme.dimens.spacing16),
isDarkBackground = state.isDarkBackground,
btnScanStateInProgress = state.btnScanStateInProgress,
onScanButtonClick = {},
onShopButtonClick = {},
@ -130,26 +107,15 @@ private fun HomeButtonsPreview(@PreviewParameter(HomeButtonsParameterProvider::c
private class HomeButtonsParameterProvider : CollectionPreviewParameterProvider<HomeButtonsState>(
collection = listOf(
HomeButtonsState(
isDarkBackground = false,
btnScanStateInProgress = false,
),
HomeButtonsState(
isDarkBackground = true,
btnScanStateInProgress = false,
),
HomeButtonsState(
isDarkBackground = false,
btnScanStateInProgress = true,
),
HomeButtonsState(
isDarkBackground = true,
btnScanStateInProgress = true,
),
),
)
private data class HomeButtonsState(
val isDarkBackground: Boolean,
val btnScanStateInProgress: Boolean,
)
// endregion Preview

View file

@ -24,8 +24,8 @@ internal fun SearchCurrenciesButton(onClick: () -> Unit, modifier: Modifier = Mo
}
private val SearchCurrenciesButtonColors: ButtonColors = TangemButtonColors(
backgroundColor = TangemColorPalette.Light2,
contentColor = TangemColorPalette.Dark6,
disabledBackgroundColor = TangemColorPalette.Light2,
disabledContentColor = TangemColorPalette.Dark6,
backgroundColor = TangemColorPalette.Dark5,
contentColor = TangemColorPalette.White,
disabledBackgroundColor = TangemColorPalette.Dark5,
disabledContentColor = TangemColorPalette.White,
)

View file

@ -1,19 +1,26 @@
package com.tangem.tap.features.home.compose.views
import android.provider.Settings
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.SpacerW4
import com.tangem.core.ui.res.TangemTheme
import kotlinx.coroutines.delay
private const val STORIES_ANIMATION_SPEED_ZERO_DURATION = 3000L
@Composable
fun StoriesProgressBar(
@ -25,10 +32,20 @@ fun StoriesProgressBar(
) {
val progress = remember(currentStep) { Animatable(0f) }
val context = LocalContext.current
val animatorSpeed = Settings.Global.getFloat(
context.contentResolver,
Settings.Global.ANIMATOR_DURATION_SCALE,
0f,
)
LaunchedEffect(paused, currentStep) {
if (paused) {
progress.stop()
} else {
if (animatorSpeed == 0f) {
delay(STORIES_ANIMATION_SPEED_ZERO_DURATION)
}
progress.animateTo(
targetValue = 1f,
animationSpec = tween(
@ -44,18 +61,23 @@ fun StoriesProgressBar(
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
// .height()
.padding(start = 9.dp, end = 9.dp, top = 16.dp),
.padding(
start = TangemTheme.dimens.spacing16,
end = TangemTheme.dimens.spacing16,
top = TangemTheme.dimens.spacing16,
),
) {
for (index in 0..steps) {
Row(
modifier = Modifier
.height(2.dp)
.height(TangemTheme.dimens.size2)
.weight(1f)
.clip(RoundedCornerShape(TangemTheme.dimens.radius2))
.background(Color.White.copy(alpha = 0.4f)),
) {
Box(
modifier = Modifier
.clip(RoundedCornerShape(TangemTheme.dimens.radius2))
.background(Color.White)
.fillMaxHeight().let {
when (index) {

View file

@ -49,15 +49,14 @@ data class HomeState(
}
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)
object RevolutionaryWallet : Stories(true, duration = 6000)
object UltraSecureBackup : Stories(false, duration = 6000)
object Currencies : Stories(false, duration = 6000)
object Web3 : Stories(false, duration = 6000)
object WalletForEveryone : Stories(true, duration = 6000)
object OneInchPromo : Stories(duration = 8000)
object TangemIntro : Stories(duration = 6000)
object RevolutionaryWallet : Stories(duration = 6000)
object UltraSecureBackup : Stories(duration = 6000)
object Currencies : Stories(duration = 6000)
object Web3 : Stories(duration = 6000)
object WalletForEveryone : Stories(duration = 6000)
}

View file

@ -53,7 +53,7 @@ object OnboardingHelper {
fun whereToNavigate(scanResponse: ScanResponse): AppScreen {
return when (scanResponse.productType) {
ProductType.Note -> AppScreen.OnboardingNote
ProductType.Wallet -> if (scanResponse.card.settings.isBackupAllowed) {
ProductType.Wallet, ProductType.Wallet2 -> if (scanResponse.card.settings.isBackupAllowed) {
AppScreen.OnboardingWallet
} else {
AppScreen.OnboardingOther

View file

@ -6,7 +6,6 @@ import com.tangem.core.analytics.Analytics
import com.tangem.core.navigation.NavigationAction
import com.tangem.domain.common.extensions.makePrimaryWalletManager
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Onboarding
import com.tangem.tap.common.extensions.*
@ -26,6 +25,7 @@ import com.tangem.tap.features.wallet.redux.models.WalletDialog
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.rekotlin.Action

View file

@ -7,13 +7,17 @@ import com.tangem.domain.common.BlockchainNetwork
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.tap.*
import com.tangem.tap.common.analytics.events.Onboarding
import com.tangem.tap.common.postUi
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.features.onboarding.OnboardingHelper
import com.tangem.tap.features.wallet.models.toCurrencies
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
import com.tangem.tap.userTokensRepository
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.rekotlin.Action

View file

@ -12,7 +12,6 @@ import com.tangem.domain.common.util.twinsIsTwinned
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.userwallets.UserWalletIdBuilder
import com.tangem.domain.wallets.legacy.isLockedSync
import com.tangem.tap.*
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Onboarding
import com.tangem.tap.common.extensions.*
@ -29,7 +28,12 @@ import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.redux.ProgressState
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.redux.models.WalletDialog
import com.tangem.tap.preferencesStorage
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.userWalletsListManager
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.rekotlin.Action

View file

@ -237,7 +237,12 @@ private fun handleWallet2Action(action: OnboardingWallet2Action) {
SeedPhraseSource.IMPORTED -> AnalyticsParam.WalletCreationType.SeedImport
SeedPhraseSource.GENERATED -> AnalyticsParam.WalletCreationType.NewSeed
}
Analytics.send(Onboarding.CreateWallet.WalletCreatedSuccessfully(creationType))
Analytics.send(
event = Onboarding.CreateWallet.WalletCreatedSuccessfully(
creationType = creationType,
seedPhraseLength = action.mnemonicComponents.size,
),
)
val response = CreateWalletResponse(
card = result.data.card,
derivedKeys = result.data.derivedKeys,

View file

@ -191,7 +191,7 @@ class OnboardingWalletFragment :
}
}
internal fun loadImageIntoImageView(uri: Uri?, view: ImageView) {
private fun loadImageIntoImageView(uri: Uri?, view: ImageView) {
view.load(uri) {
placeholder(R.drawable.card_placeholder_black)
error(R.drawable.card_placeholder_black)
@ -412,7 +412,7 @@ class OnboardingWalletFragment :
animator.showWriteBackupCard(state, cardNumber)
}
internal fun showSuccess() = with(binding) {
private fun showSuccess() = with(binding) {
toolbar.title = getString(R.string.onboarding_done_header)
tvHeader.text = getText(R.string.onboarding_done_header)
@ -427,9 +427,7 @@ class OnboardingWalletFragment :
layoutButtonsCommon.btnWalletAlternativeAction.hide()
layoutButtonsCommon.btnWalletMainAction.setOnClickListener {
showConfetti(false)
lifecycleScope.launch {
store.dispatch(OnboardingWalletAction.FinishOnboarding(lifecycleCoroutineScope = lifecycleScope))
}
store.dispatch(OnboardingWalletAction.FinishOnboarding(lifecycleCoroutineScope = lifecycleScope))
}
animator.showSuccess {

View file

@ -30,12 +30,14 @@ internal class SaveWalletViewModel @Inject constructor(
}
fun saveWallet() {
analyticsEventHandler.send(WalletScreenAnalyticsEvent.EnableBiometrics(AnalyticsParam.OnOffState.On))
analyticsEventHandler.send(WalletScreenAnalyticsEvent.MainScreen.EnableBiometrics(AnalyticsParam.OnOffState.On))
store.dispatch(SaveWalletAction.Save)
}
fun cancelOrClose() {
analyticsEventHandler.send(WalletScreenAnalyticsEvent.EnableBiometrics(AnalyticsParam.OnOffState.Off))
analyticsEventHandler.send(
WalletScreenAnalyticsEvent.MainScreen.EnableBiometrics(AnalyticsParam.OnOffState.Off),
)
store.dispatch(SaveWalletAction.Dismiss)
}

View file

@ -19,13 +19,15 @@ import com.tangem.domain.common.extensions.minimalAmount
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.tokens.legacy.TradeCryptoAction
import com.tangem.tap.*
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Basic
import com.tangem.tap.common.analytics.events.Basic.TransactionSent.MemoType
import com.tangem.tap.common.analytics.events.Token
import com.tangem.tap.common.analytics.events.Token.Send.SelectedCurrency.CurrencyType
import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.extensions.dispatchErrorNotification
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.extensions.stripZeroPlainString
import com.tangem.tap.common.redux.AppDialog
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
@ -39,6 +41,11 @@ import com.tangem.tap.features.send.redux.FeeAction.RequestFee
import com.tangem.tap.features.send.redux.states.*
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.userWalletsListManager
import com.tangem.tap.walletCurrenciesManager
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
import com.tangem.wallet.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay

View file

@ -8,7 +8,7 @@ import com.tangem.domain.tokens.UpdateDelayedNetworkStatusUseCase
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.features.send.navigation.SendRouter
import com.tangem.tap.di.DelayedWork
import com.tangem.tap.features.send.redux.AmountAction
@ -32,7 +32,7 @@ internal class SendViewModel @Inject constructor(
private val isBalanceHiddenUseCase: IsBalanceHiddenUseCase,
private val listenToFlipsUseCase: ListenToFlipsUseCase,
private val updateDelayedCurrencyStatusUseCase: UpdateDelayedNetworkStatusUseCase,
private val getSelectedWalletUseCase: GetSelectedWalletUseCase,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
private val fetchPendingTransactionsUseCase: FetchPendingTransactionsUseCase,
@DelayedWork private val coroutineScope: CoroutineScope,
savedStateHandle: SavedStateHandle,
@ -60,7 +60,7 @@ internal class SendViewModel @Inject constructor(
fun updateCurrencyDelayed() {
if (cryptoCurrency != null) {
coroutineScope.launch {
getSelectedWalletUseCase()
getSelectedWalletSyncUseCase()
.fold(
ifLeft = { Timber.e(it.toString()) },
ifRight = { wallet ->

View file

@ -6,7 +6,7 @@ import androidx.paging.PagingData
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.local.testnet.TestnetTokensStorage
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.tap.features.tokens.impl.domain.TokensListRepository
import com.tangem.tap.features.tokens.impl.domain.models.Token
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
@ -15,17 +15,17 @@ import kotlinx.coroutines.flow.Flow
/**
* Default repository implementation of tokens list feature
*
* @property tangemTechApi Tangem Tech API
* @property dispatchers coroutine dispatchers provider
* @property getSelectedWalletUseCase use case that returns selected wallet
* @property testnetTokensStorage storage for getting testnet tokens data
* @property tangemTechApi Tangem Tech API
* @property dispatchers coroutine dispatchers provider
* @property getSelectedWalletSyncUseCase use case that returns selected wallet
* @property testnetTokensStorage storage for getting testnet tokens data
*
[REDACTED_AUTHOR]
*/
internal class DefaultTokensListRepository(
private val tangemTechApi: TangemTechApi,
private val dispatchers: CoroutineDispatcherProvider,
private val getSelectedWalletUseCase: GetSelectedWalletUseCase,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
private val testnetTokensStorage: TestnetTokensStorage,
) : TokensListRepository {
@ -40,11 +40,11 @@ internal class DefaultTokensListRepository(
val defaultSource = TangemApiTokensPagingSource(
api = tangemTechApi,
dispatchers = dispatchers,
getSelectedWalletUseCase = getSelectedWalletUseCase,
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
searchText = searchText,
)
getSelectedWalletUseCase().fold(
getSelectedWalletSyncUseCase().fold(
ifLeft = { defaultSource },
ifRight = {
if (it.scanResponse.card.isTestCard) {

View file

@ -7,7 +7,7 @@ import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.domain.common.extensions.supportedBlockchains
import com.tangem.domain.common.extensions.toNetworkId
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.tap.features.tokens.impl.data.converters.CoinsResponseConverter
import com.tangem.tap.features.tokens.impl.domain.models.Token
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
@ -16,15 +16,15 @@ import com.tangem.utils.coroutines.runCatching
/**
* Paging source that get tokens by Tangem Tech API
*
* @property api Tangem Tech API
* @property dispatchers coroutine dispatchers provider
* @property getSelectedWalletUseCase use case that returns selected wallet
* @property searchText search text
* @property api Tangem Tech API
* @property dispatchers coroutine dispatchers provider
* @property getSelectedWalletSyncUseCase use case that returns selected wallet
* @property searchText search text
*/
internal class TangemApiTokensPagingSource(
private val api: TangemTechApi,
private val dispatchers: CoroutineDispatcherProvider,
private val getSelectedWalletUseCase: GetSelectedWalletUseCase,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
private val searchText: String?,
) : PagingSource<Int, Token>() {
@ -39,7 +39,7 @@ internal class TangemApiTokensPagingSource(
val page = params.key ?: 0
return runCatching(dispatchers.io) {
val supportedBlockchains = getSelectedWalletUseCase().fold(
val supportedBlockchains = getSelectedWalletSyncUseCase().fold(
ifLeft = { Blockchain.values().toList() },
ifRight = { it.scanResponse.card.supportedBlockchains(it.scanResponse.cardTypesResolver) },
)

View file

@ -2,7 +2,7 @@ package com.tangem.tap.features.tokens.impl.di
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.local.testnet.TestnetTokensStorage
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.tap.features.tokens.impl.data.DefaultTokensListRepository
import com.tangem.tap.features.tokens.impl.domain.DefaultTokensListInteractor
import com.tangem.tap.features.tokens.impl.domain.TokensListInteractor
@ -25,14 +25,14 @@ internal object TokensListInteractorModule {
fun provideTokensListInteractor(
tangemTechApi: TangemTechApi,
dispatchers: CoroutineDispatcherProvider,
getSelectedWalletUseCase: GetSelectedWalletUseCase,
getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
testnetTokensStorage: TestnetTokensStorage,
): TokensListInteractor {
return DefaultTokensListInteractor(
repository = DefaultTokensListRepository(
tangemTechApi = tangemTechApi,
dispatchers = dispatchers,
getSelectedWalletUseCase = getSelectedWalletUseCase,
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
testnetTokensStorage = testnetTokensStorage,
),
)

View file

@ -2,7 +2,7 @@ package com.tangem.tap.features.tokens.impl.di
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.local.testnet.TestnetTokensStorage
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.tap.features.tokens.impl.data.DefaultTokensListRepository
import com.tangem.tap.features.tokens.impl.domain.TokensListRepository
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
@ -24,13 +24,13 @@ internal object TokensListRepositoryModule {
fun providesTokensListRepository(
tangemTechApi: TangemTechApi,
dispatchers: CoroutineDispatcherProvider,
getSelectedWalletUseCase: GetSelectedWalletUseCase,
getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
testnetTokensStorage: TestnetTokensStorage,
): TokensListRepository {
return DefaultTokensListRepository(
tangemTechApi = tangemTechApi,
dispatchers = dispatchers,
getSelectedWalletUseCase = getSelectedWalletUseCase,
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
testnetTokensStorage = testnetTokensStorage,
)
}

View file

@ -151,7 +151,7 @@ private fun DifferentAddressesWarning() {
),
contentAlignment = Alignment.Center,
) {
val text = stringResource(id = R.string.alert_manage_tokens_addresses_message)
val text = stringResource(id = R.string.warning_manage_tokens_legacy_derivation_message)
Text(
text = text,
modifier = Modifier.padding(

View file

@ -11,7 +11,7 @@ import com.tangem.domain.tokens.TokenWithBlockchain
import com.tangem.domain.tokens.TokensAction
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
import com.tangem.tap.domain.model.WalletDataModel
import com.tangem.tap.features.wallet.models.Currency
@ -22,13 +22,13 @@ import kotlin.properties.Delegates
/**
* Class that divide a new and legacy logic when user uses tokens list screen
*
* @property walletFeatureToggles wallet feature toggles
* @property getSelectedWalletUseCase use case that returns selected wallet
* @property getCurrenciesUseCase use case that returns crypto currencies of a specified wallet
* @property walletFeatureToggles wallet feature toggles
* @property getSelectedWalletSyncUseCase use case that returns selected wallet
* @property getCurrenciesUseCase use case that returns crypto currencies of a specified wallet
*/
internal class TokensListMigration(
private val walletFeatureToggles: WalletFeatureToggles,
private val getSelectedWalletUseCase: GetSelectedWalletUseCase,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
private val getCurrenciesUseCase: GetCryptoCurrenciesUseCase,
) {
@ -47,7 +47,7 @@ internal class TokensListMigration(
}
private suspend fun getNewCryptoCurrencies(): TokensListCryptoCurrencies {
return when (val selectedWalletEither = getSelectedWalletUseCase()) {
return when (val selectedWalletEither = getSelectedWalletSyncUseCase()) {
is Either.Left -> {
Timber.e(selectedWalletEither.value.toString())
TokensListCryptoCurrencies(coins = emptyList(), tokens = emptyList())

View file

@ -21,7 +21,7 @@ import com.tangem.domain.common.extensions.supportedTokens
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.tokens.GetCryptoCurrenciesUseCase
import com.tangem.domain.tokens.TokenWithBlockchain
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
import com.tangem.tap.common.extensions.fullNameWithoutTestnet
import com.tangem.tap.common.extensions.getGreyedOutIconRes
@ -53,11 +53,11 @@ import com.tangem.blockchain.common.Token as BlockchainToken
/**
* ViewModel for tokens list screen
*
* @property interactor feature interactor
* @property router feature router
* @property dispatchers coroutine dispatchers provider
* @property getSelectedWalletUseCase use case that returns selected wallet
* @param analyticsEventHandler analytics event handler
* @property interactor feature interactor
* @property router feature router
* @property dispatchers coroutine dispatchers provider
* @property getSelectedWalletSyncUseCase use case that returns selected wallet
* @param analyticsEventHandler analytics event handler
*
[REDACTED_AUTHOR]
*/
@ -67,7 +67,7 @@ internal class TokensListViewModel @Inject constructor(
private val interactor: TokensListInteractor,
private val router: TokensListRouter,
private val dispatchers: AppCoroutineDispatcherProvider,
private val getSelectedWalletUseCase: GetSelectedWalletUseCase,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
analyticsEventHandler: AnalyticsEventHandler,
getCurrenciesUseCase: GetCryptoCurrenciesUseCase,
walletFeatureToggles: WalletFeatureToggles,
@ -89,7 +89,7 @@ internal class TokensListViewModel @Inject constructor(
private val tokensListMigration = TokensListMigration(
walletFeatureToggles = walletFeatureToggles,
getSelectedWalletUseCase = getSelectedWalletUseCase,
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
getCurrenciesUseCase = getCurrenciesUseCase,
)
@ -148,7 +148,7 @@ internal class TokensListViewModel @Inject constructor(
}
private fun isDifferentAddressesBlockVisible(): Boolean {
return getSelectedWalletUseCase().fold(
return getSelectedWalletSyncUseCase().fold(
ifLeft = { false },
ifRight = { it.scanResponse.card.useOldStyleDerivation },
)
@ -407,7 +407,7 @@ internal class TokensListViewModel @Inject constructor(
}
private fun isUnsupportedToken(blockchain: Blockchain): SupportTokensState? {
return getSelectedWalletUseCase().fold(
return getSelectedWalletSyncUseCase().fold(
ifLeft = { null },
ifRight = {
val cardTypesResolver = it.scanResponse.cardTypesResolver
@ -431,7 +431,7 @@ internal class TokensListViewModel @Inject constructor(
}
private fun isUnsupportedBlockchain(blockchain: Blockchain): Boolean {
return getSelectedWalletUseCase().fold(
return getSelectedWalletSyncUseCase().fold(
ifLeft = { false },
ifRight = {
!it.scanResponse.card.canHandleBlockchain(

View file

@ -28,11 +28,13 @@ import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.domain.TapError
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.rekotlin.Middleware
import timber.log.Timber
@Suppress("LargeClass")
object TokensMiddleware {
val tokensMiddleware: Middleware<AppState> = { _, _ ->
@ -220,10 +222,21 @@ object TokensMiddleware {
) {
val config = CardConfig.createConfig(scanResponse.card)
val derivationDataList = currencyList.mapNotNull { currency ->
config.primaryCurve(blockchain = Blockchain.fromId(currency.network.id.value))
?.let { curve -> getNewDerivations(curve, scanResponse, currency) }
val curve = config.primaryCurve(blockchain = Blockchain.fromId(currency.network.id.value))
curve?.let { getNewDerivations(curve, scanResponse, currency) }
}
val derivations = derivationDataList.associate(DerivationData::derivations)
val derivations = buildMap<ByteArrayKey, MutableList<DerivationPath>> {
derivationDataList.forEach {
val current = this[it.derivations.first]
if (current != null) {
current.addAll(it.derivations.second)
current.distinct()
} else {
this[it.derivations.first] = it.derivations.second.toMutableList()
}
}
}
if (derivations.isEmpty()) {
onSuccess(scanResponse)
return
@ -360,6 +373,7 @@ object TokensMiddleware {
currencyList: List<CryptoCurrency>,
) {
val currenciesRepository = store.state.daggerGraphState.get(DaggerGraphState::currenciesRepository)
val networksRepository = store.state.daggerGraphState.get(DaggerGraphState::networksRepository)
scope.launch {
userWalletsListManager.update(
@ -368,6 +382,12 @@ object TokensMiddleware {
)
currenciesRepository.addCurrencies(userWalletId = userWalletId, currencies = currencyList)
networksRepository.getNetworkStatusesSync(
userWalletId = userWalletId,
networks = currencyList.map(CryptoCurrency::network).toSet(),
refresh = true,
)
}
}

View file

@ -1,6 +1,5 @@
package com.tangem.tap.features.wallet.redux.middlewares
import androidx.core.os.bundleOf
import com.tangem.common.doOnSuccess
import com.tangem.common.extensions.guard
import com.tangem.common.flatMap
@ -8,7 +7,6 @@ import com.tangem.core.analytics.Analytics
import com.tangem.core.navigation.AppScreen
import com.tangem.core.navigation.NavigationAction
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.features.tokendetails.navigation.TokenDetailsRouter
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Token.ButtonRemoveToken
import com.tangem.tap.common.extensions.addContext
@ -17,7 +15,6 @@ import com.tangem.tap.common.extensions.dispatchErrorNotification
import com.tangem.tap.common.extensions.dispatchWithMain
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.domain.TapError
import com.tangem.tap.features.wallet.converters.CryptoCurrencyConverter
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.redux.WalletState
import com.tangem.tap.features.wallet.redux.models.WalletDialog
@ -32,21 +29,12 @@ import timber.log.Timber
class MultiWalletMiddleware {
private val cryptoCurrencyConverter by lazy { CryptoCurrencyConverter() }
@Suppress("LongMethod", "ComplexMethod")
fun handle(action: WalletAction.MultiWallet, walletState: WalletState?) {
when (action) {
is WalletAction.MultiWallet.SelectWallet -> {
if (action.currency != null) {
val userWalletId = userWalletsListManager.selectedUserWalletSync?.walletId
val bundle = bundleOf(
TokenDetailsRouter.USER_WALLET_ID_KEY to userWalletId?.stringValue,
TokenDetailsRouter.CRYPTO_CURRENCY_KEY to cryptoCurrencyConverter.convert(action.currency),
)
store.dispatch(NavigationAction.NavigateTo(screen = AppScreen.WalletDetails, bundle = bundle))
store.dispatch(NavigationAction.NavigateTo(screen = AppScreen.WalletDetails))
}
}
is WalletAction.MultiWallet.TryToRemoveWallet -> {

View file

@ -19,11 +19,12 @@ import com.tangem.tap.preferencesStorage
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.wallet.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
// TODO: Delete with WalletFeatureToggles
@Deprecated(message = "Used only in old wallet screen")
class WarningsMiddleware {
fun handle(action: WalletAction.Warnings, globalState: GlobalState?) {
when (action) {
@ -49,7 +50,7 @@ class WarningsMiddleware {
if (action.remainingSignatures != null &&
action.remainingSignatures <= WarningMessagesManager.REMAINING_SIGNATURES_WARNING
) {
store.state.globalState.warningManager?.removeWarnings(R.string.warning_low_signatures_format)
// store.state.globalState.warningManager?.removeWarnings(R.string.warning_low_signatures_format)
addWarningMessage(
warning = WarningMessagesManager.remainingSignaturesNotEnough(action.remainingSignatures),
autoUpdate = true,

View file

@ -10,6 +10,8 @@ import com.tangem.tap.store
import com.tangem.wallet.R
import com.tangem.wallet.databinding.CardBalanceBinding
// TODO: Delete with WalletFeatureToggles
@Deprecated(message = "Used only in old wallet screen")
class BalanceWidget(
private val binding: CardBalanceBinding,
private val fragment: WalletFragment,
@ -46,12 +48,11 @@ class BalanceWidget(
val statusView = if (blockchainWalletData.status is WalletDataModel.VerifiedOnline) {
R.id.tv_status_verified
} else {
tvStatusError.text =
fragment.getText(R.string.wallet_balance_tx_in_progress)
// tvStatusError.text = fragment.getText(R.string.wallet_balance_tx_in_progress)
R.id.group_error
}
showStatus(statusView)
tvStatusErrorMessage.hide()
// tvStatusErrorMessage.hide()
if (tokenWalletData != null) {
showBalanceWithToken(blockchainWalletData, true)
@ -70,12 +71,12 @@ class BalanceWidget(
tvCurrency.text = currency
tvAmount.text = ""
tvStatusErrorMessage.text = blockchainWalletData.status.errorMessage
tvStatusError.text =
fragment.getString(R.string.wallet_balance_blockchain_unreachable)
// tvStatusErrorMessage.text = blockchainWalletData.status.errorMessage
// TODO: Delete with WalletFeatureToggles
// tvStatusError.text = fragment.getString(R.string.wallet_balance_blockchain_unreachable)
showStatus(R.id.group_error)
tvStatusErrorMessage.show(!blockchainWalletData.status.errorMessage.isNullOrBlank())
// tvStatusErrorMessage.show(!blockchainWalletData.status.errorMessage.isNullOrBlank())
}
is WalletDataModel.NoAccount -> with(binding.lBalanceError) {
binding.lBalance.root.hide()
@ -93,7 +94,7 @@ class BalanceWidget(
}
private fun showStatus(@IdRes viewRes: Int) = with(binding.lBalance) {
groupError.show(viewRes == R.id.group_error)
// groupError.show(viewRes == R.id.group_error)
tvStatusLoading.show(viewRes == R.id.tv_status_loading)
tvStatusVerified.show(viewRes == R.id.tv_status_verified)
}

View file

@ -62,7 +62,9 @@ import javax.inject.Inject
/**
* Wallet details fragment - use only for MultiWallet
*/
// TODO: Delete with WalletFeatureToggles
@Suppress("LargeClass", "MagicNumber")
@Deprecated(message = "Used only in old wallet screen")
@AndroidEntryPoint
class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), SafeStoreSubscriber<WalletState> {
@ -436,10 +438,11 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), SafeSt
lBalance.root.show()
lBalance.groupBalance.hide()
lBalance.tvError.show()
lBalance.tvError.setWarningStatus(
R.string.wallet_balance_blockchain_unreachable,
status.errorMessage,
)
// TODO: Delete with WalletFeatureToggles
// lBalance.tvError.setWarningStatus(
// R.string.wallet_balance_blockchain_unreachable,
// status.errorMessage,
// )
}
is WalletDataModel.NoAccount -> {
lBalance.root.hide()

View file

@ -64,6 +64,7 @@ internal class WalletViewModel @Inject constructor(
batch = scanResponse.card.batchId,
signInType = signInType,
walletsCount = store.state.globalState.userWalletsListManager?.walletsCount.toString(),
hasBackup = scanResponse.card.backupStatus?.isActive,
),
)
}

View file

@ -9,43 +9,45 @@ import com.tangem.wallet.R
/**
[REDACTED_AUTHOR]
*/
// TODO: Delete with WalletFeatureToggles
@Deprecated(message = "Used only in old wallet screen")
class WalletWarningConverter(
private val context: Context,
) : ModuleMessageConverter<WalletWarning, WalletWarningDescription> {
override fun convert(message: WalletWarning): WalletWarningDescription {
val warningMessage = when (message) {
is WalletWarning.ExistentialDeposit -> {
context.getString(
R.string.warning_existential_deposit_message,
message.currencyName,
message.edStringValueWithSymbol,
)
}
is WalletWarning.BalanceNotEnoughForFee -> {
context.getString(
R.string.token_details_send_blocked_fee_format,
message.currencyName,
message.blockchainFullName,
message.currencyName,
message.blockchainFullName,
message.blockchainSymbol,
)
}
is WalletWarning.TransactionInProgress -> {
context.getString(
R.string.token_details_send_blocked_tx_format,
message.currencyName,
)
}
is WalletWarning.Rent -> {
context.getString(
R.string.solana_rent_warning,
message.walletRent.rent,
message.walletRent.exemptionAmount,
)
}
}
return WalletWarningDescription(context.getString(R.string.common_warning), warningMessage)
// val warningMessage = when (message) {
// is WalletWarning.ExistentialDeposit -> {
// context.getString(
// R.string.warning_existential_deposit_message,
// message.currencyName,
// message.edStringValueWithSymbol,
// )
// }
// is WalletWarning.BalanceNotEnoughForFee -> {
// context.getString(
// R.string.token_details_send_blocked_fee_format,
// message.currencyName,
// message.blockchainFullName,
// message.currencyName,
// message.blockchainFullName,
// message.blockchainSymbol,
// )
// }
// is WalletWarning.TransactionInProgress -> {
// context.getString(
// R.string.token_details_send_blocked_tx_format,
// message.currencyName,
// )
// }
// is WalletWarning.Rent -> {
// context.getString(
// R.string.solana_rent_warning,
// message.walletRent.rent,
// message.walletRent.exemptionAmount,
// )
// }
// }
return WalletWarningDescription(context.getString(R.string.common_warning), "")
}
}

View file

@ -22,6 +22,8 @@ import com.tangem.tap.store
import com.tangem.wallet.R
import com.tangem.wallet.databinding.ItemCurrencyWalletBinding
// TODO: Delete with WalletFeatureToggles
@Deprecated(message = "Used only in old wallet screen")
class WalletAdapter : ListAdapter<WalletDataModel, WalletAdapter.WalletsViewHolder>(DiffUtilCallback) {
override fun getItemId(position: Int): Long {
@ -59,7 +61,8 @@ class WalletAdapter : ListAdapter<WalletDataModel, WalletAdapter.WalletsViewHold
root.getString(R.string.wallet_balance_tx_in_progress)
}
is WalletDataModel.Unreachable -> {
root.getString(R.string.wallet_balance_blockchain_unreachable)
// TODO: Delete with WalletFeatureToggles
// root.getString(R.string.wallet_balance_blockchain_unreachable)
}
is WalletDataModel.MissedDerivation -> {
root.getString(R.string.wallet_balance_missing_derivation)
@ -86,7 +89,7 @@ class WalletAdapter : ListAdapter<WalletDataModel, WalletAdapter.WalletsViewHold
lContent.tvAmount.text = wallet.getFormattedCryptoAmount()
lContent.tvStatus.isVisible = statusMessage != null
lContent.tvStatus.text = statusMessage
// lContent.tvStatus.text = statusMessage
lContent.tvExchangeRate.isVisible = statusMessage == null
lContent.tvExchangeRate.text = wallet.getFormattedFiatRate(

View file

@ -10,12 +10,7 @@ import com.google.android.play.core.review.ReviewManagerFactory
import com.tangem.core.analytics.Analytics
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.MainScreen
import com.tangem.tap.common.extensions.getActivity
import com.tangem.tap.common.extensions.getColor
import com.tangem.tap.common.extensions.getString
import com.tangem.tap.common.extensions.hide
import com.tangem.tap.common.extensions.show
import com.tangem.tap.common.feedback.RateCanBeBetterEmail
import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
import com.tangem.tap.features.wallet.redux.WalletAction
@ -24,6 +19,8 @@ import com.tangem.wallet.R
import com.tangem.wallet.databinding.LayoutWarningCardActionBinding
import timber.log.Timber
// TODO: Delete with WalletFeatureToggles
@Deprecated(message = "Used only in old wallet screen")
class WarningMessagesAdapter : ListAdapter<WarningMessage, WarningMessageVH>(DiffUtilCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WarningMessageVH {
@ -94,11 +91,11 @@ class WarningMessageVH(val binding: LayoutWarningCardActionBinding) : RecyclerVi
val buttonAction =
when (warning.titleResId) {
R.string.warning_important_security_info -> {
View.OnClickListener {
store.dispatch(WalletAction.DialogAction.SignedHashesMultiWalletDialog)
}
}
// R.string.warning_important_security_info -> {
// View.OnClickListener {
// store.dispatch(WalletAction.DialogAction.SignedHashesMultiWalletDialog)
// }
// }
else -> {
View.OnClickListener {
store.dispatch(GlobalAction.HideWarningMessage(warning))
@ -120,12 +117,12 @@ class WarningMessageVH(val binding: LayoutWarningCardActionBinding) : RecyclerVi
store.dispatch(GlobalAction.HideWarningMessage(warning))
store.dispatch(WalletAction.Warnings.AppRating.RemindLater)
}
binding.btnCanBeBetter.setOnClickListener {
Analytics.send(MainScreen.NoticeRateAppButton(AnalyticsParam.RateApp.Disliked))
store.dispatch(WalletAction.Warnings.AppRating.SetNeverToShow)
store.dispatch(GlobalAction.HideWarningMessage(warning))
store.dispatch(GlobalAction.SendEmail(RateCanBeBetterEmail()))
}
// binding.btnCanBeBetter.setOnClickListener {
// Analytics.send(MainScreen.NoticeRateAppButton(AnalyticsParam.RateApp.Disliked))
// store.dispatch(WalletAction.Warnings.AppRating.SetNeverToShow)
// store.dispatch(GlobalAction.HideWarningMessage(warning))
// store.dispatch(GlobalAction.SendEmail(RateCanBeBetterEmail()))
// }
binding.btnReallyCool.setOnClickListener {
val activity = binding.root.context.getActivity() ?: return@setOnClickListener

View file

@ -9,11 +9,13 @@ import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.store
import com.tangem.wallet.R
// TODO: Delete with WalletFeatureToggles
@Deprecated(message = "Used only in old wallet screen")
object SignedHashesWarningDialog {
fun create(context: Context): AlertDialog {
return MaterialAlertDialogBuilder(context, R.style.CustomMaterialDialog).apply {
setTitle(context.getString(R.string.warning_important_security_info, "\u26A0"))
setMessage(R.string.alert_signed_hashes_message)
// setTitle(context.getString(R.string.warning_important_security_info, "\u26A0"))
// setMessage(R.string.alert_signed_hashes_message)
setPositiveButton(R.string.common_understand) { _, _ ->
store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId)
store.dispatch(

View file

@ -288,6 +288,9 @@ internal class WalletSelectorMiddleware {
}
private fun refreshUserWalletsAmounts() {
val featureToggles = store.state.daggerGraphState.get(DaggerGraphState::walletFeatureToggles)
if (featureToggles.isRedesignedScreenEnabled) return
scope.launch {
walletStoresManager.updateAmounts(
userWallets = userWalletsListManager.userWallets.firstOrNull().orEmpty(),

View file

@ -6,12 +6,15 @@ import com.tangem.common.doOnFailure
import com.tangem.common.doOnResult
import com.tangem.common.doOnSuccess
import com.tangem.common.flatMap
import com.tangem.core.analytics.Analytics
import com.tangem.core.navigation.AppScreen
import com.tangem.core.navigation.NavigationAction
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.userwallets.UserWalletBuilder
import com.tangem.domain.wallets.legacy.unlockIfLockable
import com.tangem.tap.*
import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Basic
import com.tangem.tap.common.extensions.dispatchOnMain
@ -88,6 +91,11 @@ internal class WelcomeMiddleware {
store.dispatchWithMain(WelcomeAction.ProceedWithBiometrics.Error(error))
}
.doOnSuccess { selectedUserWallet ->
sendSignedInAnalyticsEvent(
scanResponse = selectedUserWallet.scanResponse,
signInType = Basic.SignedIn.SignInType.Biometric,
)
store.dispatchWithMain(SignInAction.SetSignInType(Basic.SignedIn.SignInType.Biometric))
store.dispatchWithMain(NavigationAction.NavigateTo(AppScreen.Wallet))
store.dispatchWithMain(WelcomeAction.ProceedWithBiometrics.Success)
@ -116,6 +124,8 @@ internal class WelcomeMiddleware {
store.dispatchWithMain(WelcomeAction.ProceedWithCard.Error(error))
}
.doOnSuccess {
sendSignedInAnalyticsEvent(scanResponse = scanResponse, signInType = Basic.SignedIn.SignInType.Card)
store.dispatchWithMain(SignInAction.SetSignInType(Basic.SignedIn.SignInType.Card))
store.dispatchWithMain(NavigationAction.NavigateTo(AppScreen.Wallet))
store.dispatchWithMain(WelcomeAction.ProceedWithCard.Success)
@ -128,6 +138,24 @@ internal class WelcomeMiddleware {
}
}
private fun sendSignedInAnalyticsEvent(scanResponse: ScanResponse, signInType: Basic.SignedIn.SignInType) {
val currency = ParamCardCurrencyConverter().convert(
value = scanResponse.cardTypesResolver,
)
if (currency != null) {
Analytics.send(
event = Basic.SignedIn(
currency = currency,
batch = scanResponse.card.batchId,
signInType = signInType,
walletsCount = store.state.globalState.userWalletsListManager?.walletsCount.toString(),
hasBackup = scanResponse.card.backupStatus?.isActive,
),
)
}
}
private suspend fun disableUserWalletsSaving() {
userWalletsListManager.clear()
.flatMap { walletStoresManager.clear() }

View file

@ -9,6 +9,7 @@ import com.tangem.domain.redux.ReduxStateHolder
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.legacy.WalletsStateHolder
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.domain.TangemSdkManager
import com.tangem.tap.domain.tokens.UserTokensRepository
@ -53,13 +54,13 @@ class AppStateHolder @Inject constructor() : WalletsStateHolder, ReduxNavControl
}
override fun navigate(action: NavigationAction) {
mainStore?.dispatch(action)
mainStore?.dispatchOnMain(action)
}
override fun getBackStack(): List<AppScreen> = mainStore?.state?.navigationState?.backStack.orEmpty()
override fun popBackStack(screen: AppScreen?) {
mainStore?.dispatch(NavigationAction.PopBackTo(screen))
mainStore?.dispatchOnMain(NavigationAction.PopBackTo(screen))
}
override fun dispatch(action: Action) {

View file

@ -20,13 +20,13 @@ import com.tangem.domain.common.util.hasDerivation
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.lib.crypto.DerivationManager
import com.tangem.lib.crypto.models.Currency
import com.tangem.lib.crypto.models.Currency.NonNativeToken
import com.tangem.lib.crypto.models.errors.UserCancelledException
import com.tangem.operations.derivation.ExtendedPublicKeysMap
import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.redux.global.GlobalAction
@ -34,6 +34,7 @@ import com.tangem.tap.domain.TapError
import com.tangem.tap.features.tokens.legacy.redux.TokensMiddleware
import com.tangem.tap.scope
import com.tangem.tap.userWalletsListManager
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.coroutines.suspendCoroutine
@ -42,6 +43,7 @@ import com.tangem.tap.features.wallet.models.Currency as WalletModelCurrency
class DerivationManagerImpl(
private val appStateHolder: AppStateHolder,
private val currenciesRepository: CurrenciesRepository,
private val networksRepository: NetworksRepository,
) : DerivationManager {
override suspend fun deriveMissingBlockchains(currency: Currency) = suspendCoroutine { continuation ->
@ -155,16 +157,20 @@ class DerivationManagerImpl(
derivationPath: String,
derivationStyleProvider: DerivationStyleProvider,
) {
val cryptoCurrency = convertCurrency(
blockchain = blockchain,
currency = currency,
derivationPath = derivationPath,
derivationStyleProvider = derivationStyleProvider,
)
currenciesRepository.addCurrencies(
userWalletId,
listOf(
convertCurrency(
blockchain = blockchain,
currency = currency,
derivationPath = derivationPath,
derivationStyleProvider = derivationStyleProvider,
),
),
listOf(cryptoCurrency),
)
networksRepository.getNetworkStatusesSync(
userWalletId = userWalletId,
networks = setOf(cryptoCurrency.network),
refresh = true,
)
}

View file

@ -7,6 +7,7 @@ import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.feature.learn2earn.domain.api.Learn2earnDependencyProvider
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
@ -70,10 +71,12 @@ class ProxyModule {
fun provideDerivationManager(
appStateHolder: AppStateHolder,
currenciesRepository: CurrenciesRepository,
networksRepository: NetworksRepository,
): DerivationManager {
return DerivationManagerImpl(
appStateHolder = appStateHolder,
currenciesRepository = currenciesRepository,
networksRepository = networksRepository,
)
}

View file

@ -9,12 +9,12 @@ import com.tangem.domain.card.ScanCardProcessor
import com.tangem.domain.card.ScanCardUseCase
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles
import com.tangem.features.managetokens.navigation.ManageTokensRouter
import com.tangem.features.tester.api.TesterRouter
import com.tangem.features.tokendetails.featuretoggles.TokenDetailsFeatureToggles
import com.tangem.features.tokendetails.navigation.TokenDetailsRouter
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
import com.tangem.features.wallet.navigation.WalletRouter
@ -37,7 +37,6 @@ data class DaggerGraphState(
val walletConnectRepository: WalletConnectRepository? = null,
val walletConnectSessionsRepository: WalletConnectSessionsRepository? = null,
val walletConnectInteractor: WalletConnectInteractor? = null,
val tokenDetailsFeatureToggles: TokenDetailsFeatureToggles? = null,
val tokenDetailsRouter: TokenDetailsRouter? = null,
val manageTokensFeatureToggles: ManageTokensFeatureToggles? = null,
val manageTokensRouter: ManageTokensRouter? = null,
@ -50,6 +49,7 @@ data class DaggerGraphState(
val balanceHidingRepository: BalanceHidingRepository? = null,
val detailsFeatureToggles: DetailsFeatureToggles? = null,
val walletsRepository: WalletsRepository? = null,
val networksRepository: NetworksRepository? = null,
// FIXME: It is used only for TokensList screen. Remove after refactoring of TokensList
val currenciesRepository: CurrenciesRepository? = null,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

After

Width:  |  Height:  |  Size: 140 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View file

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 127 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View file

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 KiB

After

Width:  |  Height:  |  Size: 234 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

View file

Before

Width:  |  Height:  |  Size: 222 KiB

After

Width:  |  Height:  |  Size: 222 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 303 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 512 KiB

After

Width:  |  Height:  |  Size: 509 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

View file

Before

Width:  |  Height:  |  Size: 484 KiB

After

Width:  |  Height:  |  Size: 484 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 616 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 901 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

View file

Before

Width:  |  Height:  |  Size: 818 KiB

After

Width:  |  Height:  |  Size: 818 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 819 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 917 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 136 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 137 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 140 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 128 KiB

Before After
Before After

View file

@ -38,41 +38,40 @@
app:layout_constraintTop_toBottomOf="@id/tv_currency"
tools:visibility="visible" />
<TextView
android:id="@+id/tv_status_error"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="5dp"
android:paddingStart="16dp"
android:paddingTop="4dp"
android:paddingEnd="16dp"
android:text="@string/wallet_balance_blockchain_unreachable"
android:textColor="@color/warning"
android:textSize="14sp"
android:visibility="gone"
app:drawableStartCompat="@drawable/ic_warning_small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_currency" />
<TextView
android:id="@+id/tv_status_error_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="4dp"
android:paddingEnd="16dp"
android:textColor="@color/darkGray2"
android:textSize="14sp"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_status_error" />
<androidx.constraintlayout.widget.Group
android:id="@+id/group_error"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="tv_status_error, tv_status_error_message" />
<!-- TODO: Delete with WalletFeatureToggles -->
<!--<TextView-->
<!-- android:id="@+id/tv_status_error"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:drawablePadding="5dp"-->
<!-- android:paddingStart="16dp"-->
<!-- android:paddingTop="4dp"-->
<!-- android:paddingEnd="16dp"-->
<!-- android:text="@string/wallet_balance_blockchain_unreachable"-->
<!-- android:textColor="@color/warning"-->
<!-- android:textSize="14sp"-->
<!-- android:visibility="gone"-->
<!-- app:drawableStartCompat="@drawable/ic_warning_small"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/tv_currency" />-->
<!--<TextView-->
<!-- android:id="@+id/tv_status_error_message"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:paddingStart="16dp"-->
<!-- android:paddingTop="4dp"-->
<!-- android:paddingEnd="16dp"-->
<!-- android:textColor="@color/darkGray2"-->
<!-- android:textSize="14sp"-->
<!-- android:visibility="gone"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/tv_status_error" />-->
<!--<androidx.constraintlayout.widget.Group-->
<!-- android:id="@+id/group_error"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:visibility="gone"-->
<!-- app:constraint_referenced_ids="tv_status_error, tv_status_error_message" />-->
<TextView
android:id="@+id/tv_status_loading"

View file

@ -29,78 +29,73 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.skydoves.androidveil.VeilLayout
android:id="@+id/veil_balance"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
app:layout_constraintBottom_toTopOf="@id/tv_processing"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title"
app:veilLayout_baseColor="@color/lightGray0"
app:veilLayout_highlightColor="@color/lightGray1"
app:veilLayout_layout="@layout/card_total_balance_shimmer"
app:veilLayout_radius="4dp"
app:veilLayout_shimmerEnable="true"
app:veilLayout_veiled="true"
tools:veilLayout_veiled="false">
<TextView
android:id="@+id/tv_balance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:minWidth="152dp"
android:textColor="@color/text_primary_1"
android:textSize="24sp"
android:textStyle="bold"
tools:text="22 325.40 $" />
</com.skydoves.androidveil.VeilLayout>
<com.skydoves.androidveil.VeilLayout
android:id="@+id/veil_balance_crypto"
android:layout_width="wrap_content"
android:layout_height="18dp"
android:layout_marginTop="4dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/veil_balance"
app:veilLayout_baseColor="@color/lightGray0"
app:veilLayout_highlightColor="@color/lightGray1"
app:veilLayout_layout="@layout/card_total_balance_shimmer"
app:veilLayout_radius="4dp"
app:veilLayout_shimmerEnable="true"
app:veilLayout_veiled="true"
tools:veilLayout_veiled="false"
tools:visibility="visible">
<TextView
android:id="@+id/tv_balance_crypto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:maxLines="1"
android:minWidth="152dp"
android:textColor="@color/text_tertiary"
android:textSize="12sp"
tools:text="5.13123123123 ETH"
tools:visibility="visible" />
</com.skydoves.androidveil.VeilLayout>
<TextView
android:id="@+id/tv_processing"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="@string/wallet_balance_blockchain_unreachable"
android:textColor="@color/warning"
android:textSize="12sp"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/veil_balance"
tools:visibility="visible" />
<!--TODO: Delete with WalletFeatureToggles-->
<!--<com.skydoves.androidveil.VeilLayout-->
<!-- android:id="@+id/veil_balance"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginTop="4dp"-->
<!-- app:layout_constraintBottom_toTopOf="@id/tv_processing"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/tv_title"-->
<!-- app:veilLayout_baseColor="@color/lightGray0"-->
<!-- app:veilLayout_highlightColor="@color/lightGray1"-->
<!-- app:veilLayout_layout="@layout/card_total_balance_shimmer"-->
<!-- app:veilLayout_radius="4dp"-->
<!-- app:veilLayout_shimmerEnable="true"-->
<!-- app:veilLayout_veiled="true"-->
<!-- tools:veilLayout_veiled="false">-->
<!-- <TextView-->
<!-- android:id="@+id/tv_balance"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:maxLines="1"-->
<!-- android:minWidth="152dp"-->
<!-- android:textColor="@color/text_primary_1"-->
<!-- android:textSize="24sp"-->
<!-- android:textStyle="bold"-->
<!-- tools:text="22 325.40 $" />-->
<!--</com.skydoves.androidveil.VeilLayout>-->
<!-- <com.skydoves.androidveil.VeilLayout
android:id="@+id/veil_balance_crypto"
android:layout_width="wrap_content"
android:layout_height="18dp"
android:layout_marginTop="4dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/veil_balance"
app:veilLayout_baseColor="@color/lightGray0"
app:veilLayout_highlightColor="@color/lightGray1"
app:veilLayout_layout="@layout/card_total_balance_shimmer"
app:veilLayout_radius="4dp"
app:veilLayout_shimmerEnable="true"
app:veilLayout_veiled="true"
tools:veilLayout_veiled="false"
tools:visibility="visible">
<TextView
android:id="@+id/tv_balance_crypto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:maxLines="1"
android:minWidth="152dp"
android:textColor="@color/text_tertiary"
android:textSize="12sp"
tools:text="5.13123123123 ETH"
tools:visibility="visible" />
</com.skydoves.androidveil.VeilLayout>-->
<!--<TextView-->
<!-- android:id="@+id/tv_processing"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginTop="2dp"-->
<!-- android:text="@string/wallet_balance_blockchain_unreachable"-->
<!-- android:textColor="@color/warning"-->
<!-- android:textSize="12sp"-->
<!-- android:visibility="gone"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/veil_balance"-->
<!-- tools:visibility="visible" />-->
<TextView
android:id="@+id/tv_currency_name"

Some files were not shown because too many files have changed in this diff Show more