Updated on 2026-08-14

This commit is contained in:
Tangem 2023-11-21 11:17:20 +04:00
parent ddf5f8af9f
commit 6558188794
10 changed files with 0 additions and 242 deletions

View file

@ -46,7 +46,6 @@ import com.tangem.tap.common.analytics.handlers.BlockchainExceptionHandler
import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeAnalyticsHandler
import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerAnalyticsHandler
import com.tangem.tap.common.analytics.handlers.firebase.FirebaseAnalyticsHandler
import com.tangem.tap.common.analytics.topup.TopUpController
import com.tangem.tap.common.chat.ChatManager
import com.tangem.tap.common.feedback.AdditionalFeedbackInfo
import com.tangem.tap.common.feedback.FeedbackManager
@ -61,8 +60,6 @@ import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
import com.tangem.tap.domain.tasks.product.DerivationsFinder
import com.tangem.tap.domain.tokens.UserTokensRepository
import com.tangem.tap.domain.tokens.UserTokensStorageService
import com.tangem.tap.domain.totalBalance.TotalFiatBalanceCalculator
import com.tangem.tap.domain.totalBalance.di.provideDefaultImplementation
import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation
import com.tangem.tap.domain.userWalletList.di.provideRuntimeImplementation
import com.tangem.tap.domain.walletCurrencies.WalletCurrenciesManager
@ -132,9 +129,6 @@ val walletCurrenciesManager by lazy {
appCurrencyProvider = { store.state.globalState.appCurrency },
)
}
val totalFiatBalanceCalculator by lazy {
TotalFiatBalanceCalculator.provideDefaultImplementation()
}
@HiltAndroidApp
internal class TapApplication : Application(), ImageLoaderFactory {
@ -282,7 +276,6 @@ internal class TapApplication : Application(), ImageLoaderFactory {
appStateHolder.userTokensRepository = userTokensRepository
appStateHolder.walletStoresManager = walletStoresManager
initTopUpController()
walletConnect2Repository.init(projectId = configManager.config.walletConnectProjectId)
}
@ -315,18 +308,6 @@ internal class TapApplication : Application(), ImageLoaderFactory {
)
}
private fun initTopUpController() {
val topUpController = TopUpController(
scanResponseProvider = {
store.state.globalState.scanResponse
?: store.state.globalState.onboardingState.onboardingManager?.scanResponse
},
walletStoresManagerProvider = { walletStoresManager },
topupWalletStorage = preferencesStorage.toppedUpWalletStorage,
)
store.dispatch(GlobalAction.SetTopUpController(topUpController))
}
override fun newImageLoader(): ImageLoader {
return createCoilImageLoader(
context = this,

View file

@ -1,207 +0,0 @@
package com.tangem.tap.common.analytics.topup
import com.tangem.common.extensions.guard
import com.tangem.common.extensions.isZero
import com.tangem.core.analytics.Analytics
import com.tangem.data.source.preferences.model.DataSourceTopupInfo
import com.tangem.data.source.preferences.storage.ToppedUpWalletStorage
import com.tangem.domain.common.BlockchainNetwork
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.userwallets.UserWalletIdBuilder
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.tap.common.analytics.converters.TopUpEventConverter
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.domain.model.TotalFiatBalance
import com.tangem.tap.domain.model.WalletDataModel
import com.tangem.tap.domain.model.WalletStoreModel
import com.tangem.tap.domain.walletCurrencies.WalletCurrenciesManager
import com.tangem.tap.domain.walletStores.WalletStoresManager
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.scope
import com.tangem.utils.extensions.copy
import kotlinx.coroutines.launch
import java.math.BigDecimal
/**
[REDACTED_AUTHOR]
*/
class TopUpController(
var scanResponseProvider: (() -> ScanResponse?)? = null,
var walletStoresManagerProvider: (() -> WalletStoresManager)? = null,
private val topupWalletStorage: ToppedUpWalletStorage,
) : WalletCurrenciesManager.Listener {
private var hadMissedDerivations: Boolean = false
private val addedCurrencies = mutableListOf<Currency>()
override fun didUpdate(userWallet: UserWallet, currency: Currency) {
tryToSend()
}
override fun willCurrenciesAdd(userWallet: UserWallet, currenciesToAdd: List<Currency>) {
addedCurrencies.addAll(currenciesToAdd.distinct())
}
fun walletStoresChanged(walletStores: List<WalletStoreModel>) {
val missedDerivations = walletStores
.flatMap { it.walletsData }
.map { it.status }
.filterIsInstance<WalletDataModel.MissedDerivation>()
hadMissedDerivations = missedDerivations.isNotEmpty()
}
fun scanToGetDerivations() {
hadMissedDerivations = true
}
fun addMissingDerivations(blockchains: List<BlockchainNetwork>) {
hadMissedDerivations = blockchains.isNotEmpty()
}
fun totalBalanceStateChanged(totalFiatBalance: TotalFiatBalance) {
if (totalFiatBalance is TotalFiatBalance.Loaded) tryToSend()
}
fun loadDataSuccess() {
tryToSend()
}
private fun tryToSend() {
if (hadMissedDerivations) return
val scanResponse = scanResponseProvider?.invoke() ?: return
val userWalletId = UserWalletIdBuilder.scanResponse(scanResponse).build() ?: return
val walletStoresManager = walletStoresManagerProvider?.invoke() ?: return
scope.launch {
val walletDataModels = walletStoresManager.getSync(userWalletId).flatMap { it.walletsData }
if (walletDataModels.isEmpty()) return@launch
val isCorrectStatus = walletDataModels.any {
it.status is WalletDataModel.Loading ||
it.status is WalletDataModel.NoAccount ||
it.status is WalletDataModel.Unreachable ||
it.status is WalletDataModel.MissedDerivation ||
it.status.isErrorStatus
}
if (isCorrectStatus) return@launch
val isToppedUpInPast = findToppedUpCurrenciesInPast(walletDataModels).isNotEmpty()
if (isToppedUpInPast) {
val newWalletInfo = DataSourceTopupInfo(
walletId = userWalletId.stringValue,
cardBalanceState = DataSourceTopupInfo.CardBalanceState.Full,
)
topupWalletStorage.save(newWalletInfo)
return@launch
}
val cardBalanceState = BalanceCalculator(walletDataModels).calculate().toCardBalanceState()
send(userWalletId, cardBalanceState, scanResponse.cardTypesResolver)
}
}
/**
* A UserWalletId registration should be after creating wallets
*/
fun registerEmptyWallet(scanResponse: ScanResponse) {
UserWalletIdBuilder.scanResponse(scanResponse).build()?.let {
topupWalletStorage.save(
DataSourceTopupInfo(
walletId = it.stringValue,
cardBalanceState = DataSourceTopupInfo.CardBalanceState.Empty,
),
)
}
}
fun send(scanResponse: ScanResponse, cardBalanceState: AnalyticsParam.CardBalanceState) {
UserWalletIdBuilder.scanResponse(scanResponse).build()?.let {
send(it, cardBalanceState, scanResponse.cardTypesResolver)
}
}
fun send(
userWalletId: UserWalletId,
cardBalanceState: AnalyticsParam.CardBalanceState,
cardTypesResolver: CardTypesResolver,
) {
val topupInfo = topupWalletStorage.restore(userWalletId.stringValue).guard {
val topupInfo = DataSourceTopupInfo(
walletId = userWalletId.stringValue,
cardBalanceState = when (cardBalanceState) {
AnalyticsParam.CardBalanceState.BlockchainError ->
DataSourceTopupInfo.CardBalanceState.BlockchainError
AnalyticsParam.CardBalanceState.CustomToken ->
DataSourceTopupInfo.CardBalanceState.CustomToken
AnalyticsParam.CardBalanceState.Empty ->
DataSourceTopupInfo.CardBalanceState.Empty
AnalyticsParam.CardBalanceState.Full ->
DataSourceTopupInfo.CardBalanceState.Full
AnalyticsParam.CardBalanceState.NoRate ->
DataSourceTopupInfo.CardBalanceState.NoRate
},
)
topupWalletStorage.save(topupInfo)
return
}
val isToppedUp = topupInfo.cardBalanceState == DataSourceTopupInfo.CardBalanceState.Full
if (isToppedUp) return
if (cardBalanceState.isToppedUp()) {
topupWalletStorage.save(topupInfo.copy(cardBalanceState = DataSourceTopupInfo.CardBalanceState.Full))
TopUpEventConverter().convert(value = userWalletId to cardTypesResolver)?.let {
Analytics.send(it)
}
}
}
private fun findToppedUpCurrenciesInPast(walletDataModels: List<WalletDataModel>): List<WalletDataModel> {
val currenciesToppedUpInPast = addedCurrencies.copy()
.mapNotNull { currency ->
val foundCurrencyModel = walletDataModels
.find { it.currency == currency }
?: return@mapNotNull null
if (foundCurrencyModel.status.amount.isZero()) null else foundCurrencyModel
}
addedCurrencies.clear()
return currenciesToppedUpInPast
}
private fun BigDecimal.toCardBalanceState(): AnalyticsParam.CardBalanceState = when {
isZero() -> AnalyticsParam.CardBalanceState.Empty
else -> AnalyticsParam.CardBalanceState.Full
}
private fun AnalyticsParam.CardBalanceState.isToppedUp(): Boolean = this == AnalyticsParam.CardBalanceState.Full
}
private interface IBalanceCalculator {
fun calculate(): BigDecimal
}
private class BalanceCalculator(
private val walletDataModels: List<WalletDataModel>,
) : IBalanceCalculator {
override fun calculate(): BigDecimal {
val singleToken = walletDataModels
.filter { it.currency.isToken() }
.firstOrNull { it.isCardSingleToken }
val totalAmount = singleToken?.status?.amount
?: walletDataModels.calculateTotalCryptoAmount()
return totalAmount
}
private fun List<WalletDataModel>.calculateTotalCryptoAmount(): BigDecimal = this
.map { it.status.amount }
.reduce(BigDecimal::plus)
}

View file

@ -8,7 +8,6 @@ import com.tangem.datasource.config.models.ChatConfig
import com.tangem.domain.apptheme.model.AppThemeMode
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.tap.common.analytics.topup.TopUpController
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.common.feedback.FeedbackData
import com.tangem.tap.common.feedback.FeedbackManager
@ -78,7 +77,6 @@ sealed class GlobalAction : Action {
data class SetConfigManager(val configManager: ConfigManager) : GlobalAction()
data class SetWarningManager(val warningManager: WarningMessagesManager) : GlobalAction()
data class SetFeedbackManager(val feedbackManager: FeedbackManager) : GlobalAction()
data class SetTopUpController(val topUpController: TopUpController) : GlobalAction()
data class SendEmail(val feedbackData: FeedbackData) : GlobalAction()
data class OpenChat(val feedbackData: FeedbackData, val chatConfig: ChatConfig? = null) : GlobalAction()

View file

@ -164,9 +164,6 @@ private fun handleAction(action: Action, appState: () -> AppState?) {
}
}
}
is GlobalAction.SetTopUpController -> {
walletCurrenciesManager.addListener(action.topUpController)
}
is GlobalAction.UpdateUserWalletsListManager -> {
val walletManagersFacade = store.state.daggerGraphState.get(DaggerGraphState::walletManagersFacade)

View file

@ -52,7 +52,6 @@ fun globalReducer(action: Action, state: AppState, appStateHolder: AppStateHolde
globalState.copy(configManager = action.configManager)
}
is GlobalAction.SetWarningManager -> globalState.copy(warningManager = action.warningManager)
is GlobalAction.SetTopUpController -> globalState.copy(topUpController = action.topUpController)
is GlobalAction.UpdateWalletSignedHashes -> {
val card = globalState.scanResponse?.card ?: return globalState
val wallet = card.wallets

View file

@ -5,7 +5,6 @@ import com.tangem.datasource.config.ConfigManager
import com.tangem.domain.apptheme.model.AppThemeMode
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.tap.common.analytics.topup.TopUpController
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.common.feedback.FeedbackManager
import com.tangem.tap.domain.TapWalletManager
@ -29,7 +28,6 @@ data class GlobalState(
val exchangeManager: CurrencyExchangeManager = CurrencyExchangeManager.dummy(),
val userCountryCode: String? = null,
val userWalletsListManager: UserWalletsListManager? = null,
val topUpController: TopUpController? = null,
val appThemeMode: AppThemeMode = AppThemeMode.DEFAULT,
) : StateType

View file

@ -102,7 +102,6 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch
val updatedResponse = scanResponse.copy(card = result.data.card)
onboardingManager.scanResponse = updatedResponse
onboardingManager.activationStarted(updatedResponse.card.cardId)
store.state.globalState.topUpController?.registerEmptyWallet(updatedResponse)
store.dispatch(OnboardingNoteAction.SetStepOfScreen(OnboardingNoteStep.TopUpWallet))
}
is CompletionResult.Failure -> Unit
@ -151,8 +150,6 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch
is OnboardingNoteAction.Balance.Set -> {
if (action.balance.balanceIsToppedUp()) {
OnboardingHelper.sendToppedUpEvent(scanResponse)
store.state.globalState.topUpController?.send(scanResponse, AnalyticsParam.CardBalanceState.Full)
store.dispatch(OnboardingNoteAction.SetStepOfScreen(OnboardingNoteStep.Done))
}
}

View file

@ -89,7 +89,6 @@ private fun handleOtherCardsAction(action: Action) {
val updatedCard = updatedResponse.card
onboardingManager.scanResponse = updatedResponse
onboardingManager.activationStarted(updatedCard.cardId)
store.state.globalState.topUpController?.registerEmptyWallet(updatedResponse)
val primaryBlockchain = updatedResponse.cardTypesResolver.getBlockchain()
val blockchainNetworks = if (primaryBlockchain != Blockchain.Unknown) {

View file

@ -200,7 +200,6 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
is Result.Success -> {
Analytics.send(Onboarding.Twins.SetupFinished())
updateScanResponse(result.data)
store.state.globalState.topUpController?.registerEmptyWallet(result.data)
delay(DELAY_SDK_DIALOG_CLOSE)
withMainContext {
@ -259,8 +258,6 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
is TwinCardsAction.Balance.Set -> {
if (action.balance.balanceIsToppedUp()) {
OnboardingHelper.sendToppedUpEvent(getScanResponse())
store.state.globalState.topUpController?.send(getScanResponse(), AnalyticsParam.CardBalanceState.Full)
store.dispatchOnMain(TwinCardsAction.SetStepOfScreen(TwinCardsStep.Done))
}
}

View file

@ -142,7 +142,6 @@ private fun handleWalletAction(action: Action) {
primaryCard = result.data.primaryCard,
)
onboardingManager.scanResponse = updatedResponse
store.state.globalState.topUpController?.registerEmptyWallet(updatedResponse)
val blockchainNetworks = if (DemoHelper.isDemoCardId(result.data.card.cardId)) {
DemoHelper.config.demoBlockchains