Updated on 2026-08-14
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ internal class DetailsViewModel(
|
|||
}
|
||||
|
||||
private fun scanAndSaveUserWallet() {
|
||||
Analytics.send(Settings.ScanNewCard)
|
||||
store.dispatch(DetailsAction.ScanAndSaveUserWallet)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
|
|
@ -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)
|
||||
},
|
||||
) {}
|
||||
)
|
||||
}
|
||||
|
|
@ -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),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ->
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) },
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 -> {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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), "")
|
||||
}
|
||||
}
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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() }
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 140 KiB |
BIN
app/src/main/res/drawable-hdpi/img_revolutionary_wallet.webp
Normal file
|
After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 66 KiB |
BIN
app/src/main/res/drawable-mdpi/img_revolutionary_wallet.webp
Normal file
|
After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 266 KiB After Width: | Height: | Size: 234 KiB |
BIN
app/src/main/res/drawable-xhdpi/img_revolutionary_wallet.webp
Normal file
|
After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 222 KiB After Width: | Height: | Size: 222 KiB |
|
Before Width: | Height: | Size: 303 KiB |
|
Before Width: | Height: | Size: 512 KiB After Width: | Height: | Size: 509 KiB |
BIN
app/src/main/res/drawable-xxhdpi/img_revolutionary_wallet.webp
Normal file
|
After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 484 KiB After Width: | Height: | Size: 484 KiB |
|
Before Width: | Height: | Size: 616 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/img_meet_tangem.webp
Normal file
|
After Width: | Height: | Size: 901 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/img_revolutionary_wallet.webp
Normal file
|
After Width: | Height: | Size: 243 KiB |
|
Before Width: | Height: | Size: 818 KiB After Width: | Height: | Size: 818 KiB |
|
Before Width: | Height: | Size: 819 KiB |
|
Before Width: | Height: | Size: 917 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 140 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 128 KiB |
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||