From d43e4fb40e87d32a15b0581555076d311bfd6aae Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 27 Mar 2023 13:53:49 +0300 Subject: [PATCH 1/3] Updated on 2026-08-14 --- .../tangem/tap/domain/walletconnect/WalletConnectRepository.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectRepository.kt index 12df7aeb8e..8a5490c31a 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectRepository.kt @@ -41,7 +41,7 @@ class WalletConnectRepository(val context: Application) { .hexToUtf8() walletConnectAdapter.fromJson(json)!!.map { it.toSession() } } catch (exception: Exception) { - Timber.e(exception) + Timber.w(exception) emptyList() } } From db1299b6afa95f49dd1c4f7882472ad11990ff55 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 27 Mar 2023 13:54:20 +0300 Subject: [PATCH 2/3] Updated on 2026-08-14 --- .../java/com/tangem/tap/TapApplication.kt | 12 +- .../converters/BasicEventConverter.kt | 174 ------------------ .../analytics/converters/TopUpConverter.kt | 67 +++++++ .../analytics/filters/BasicTopUpFilter.kt | 50 ----- .../common/analytics/filters/TopUpFilter.kt | 72 ++++++++ .../common/analytics/topup/TopUpController.kt | 156 ++++++++++++++++ .../tap/common/extensions/Collections.kt | 4 + .../tap/common/redux/global/GlobalState.kt | 2 + .../com/tangem/tap/domain/TapWalletManager.kt | 3 +- .../WalletCurrenciesManager.kt | 25 +++ .../DefaultWalletCurrenciesManager.kt | 23 ++- .../tap/features/wallet/redux/WalletState.kt | 4 - .../middlewares/MultiWalletMiddleware.kt | 4 +- .../redux/middlewares/WalletMiddleware.kt | 25 +-- .../redux/reducers/MultiWalletReducer.kt | 4 - .../tap/features/wallet/ui/WalletFragment.kt | 10 + .../tap/persistence/ToppedUpWalletStorage.kt | 23 ++- 17 files changed, 386 insertions(+), 272 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/converters/TopUpConverter.kt delete mode 100644 app/src/main/java/com/tangem/tap/common/analytics/filters/BasicTopUpFilter.kt create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/filters/TopUpFilter.kt create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 05634eb5fb..4247167482 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -22,7 +22,7 @@ import com.tangem.domain.common.LogConfig import com.tangem.tap.common.IntentHandler import com.tangem.tap.common.analytics.AnalyticsFactory import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder -import com.tangem.tap.common.analytics.filters.BasicTopUpFilter +import com.tangem.tap.common.analytics.filters.TopUpFilter 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 @@ -158,6 +158,14 @@ class TapApplication : Application(), ImageLoaderFactory { appStateHolder.mainStore = store appStateHolder.userTokensRepository = userTokensRepository appStateHolder.walletStoresManager = walletStoresManager + initTopUpController() + } + + private fun initTopUpController() { + val topUpController = store.state.globalState.topUpController + topUpController.walletStoresManagerProvider = { walletStoresManager } + topUpController.scanResponseProvider = { store.state.globalState.scanResponse } + walletCurrenciesManager.addListener(topUpController) } override fun newImageLoader(): ImageLoader { @@ -186,7 +194,7 @@ class TapApplication : Application(), ImageLoaderFactory { factory.addHandlerBuilder(AppsFlyerAnalyticsHandler.Builder()) factory.addHandlerBuilder(FirebaseAnalyticsHandler.Builder()) - factory.addFilter(BasicTopUpFilter(preferencesStorage.toppedUpWalletStorage)) + factory.addFilter(TopUpFilter(preferencesStorage.toppedUpWalletStorage)) val buildData = AnalyticsHandlerBuilder.Data( application = application, diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt deleted file mode 100644 index 1e1f9894c8..0000000000 --- a/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt +++ /dev/null @@ -1,174 +0,0 @@ -package com.tangem.tap.common.analytics.converters - -import com.tangem.common.Converter -import com.tangem.common.extensions.isZero -import com.tangem.core.analytics.Analytics -import com.tangem.domain.common.ScanResponse -import com.tangem.tap.common.analytics.events.AnalyticsParam -import com.tangem.tap.common.analytics.events.Basic -import com.tangem.tap.common.analytics.filters.BasicTopUpFilter -import com.tangem.tap.domain.model.WalletDataModel -import com.tangem.tap.domain.model.builders.UserWalletIdBuilder -import com.tangem.tap.features.wallet.redux.ProgressState -import com.tangem.tap.features.wallet.redux.WalletState -import com.tangem.tap.features.wallet.redux.reducers.calculateTotalCryptoAmount -import timber.log.Timber -import java.math.BigDecimal - -/** -[REDACTED_AUTHOR] - */ -class BasicEventsPreChecker { - - fun tryToSend(converterData: BasicEventsSourceData) { - if (!isReadyToSend(converterData)) return - - BasicTopUpEventConverter().convert(converterData)?.let { Analytics.send(it) } - } - - @Suppress("ComplexMethod") - private fun isReadyToSend(data: BasicEventsSourceData): Boolean { - val (scanResponse, walletState, biometricsWalletDataModels) = data - if (walletState.derivationsCheckIsScheduled) { - Timber.d("FAILED: derivationsCheckIsScheduled") - return false - } - if (scanResponse.cardTypesResolver.isMultiwalletAllowed() && walletState.missingDerivations.isNotEmpty()) { - Timber.d("FAILED: isMultiwalletAllowed || missingDerivations.isNotEmpty") - return false - } - - if (biometricsWalletDataModels == null) { - Timber.d("SWITCH: OLD") - val walletsDataFromStores = data.walletState.walletsDataFromStores - if (walletsDataFromStores.isEmpty()) { - Timber.d("FAILED: walletsDataFromStores.isEmpty") - return false - } - - val totalBalanceState = data.walletState.totalBalance?.state - if (totalBalanceState == null || totalBalanceState == ProgressState.Loading || - totalBalanceState == ProgressState.Refreshing - ) { - Timber.d("FAILED: totalBalanceState: ${totalBalanceState?.name}") - return false - } - - val balancesCount = walletsDataFromStores - .map { if (it.currencyData.amount == null) 0 else 1 } - .reduce { acc, i -> acc + i } - - if (balancesCount != walletsDataFromStores.size) { - Timber.d("FAILED: balancesCount != walletsDataFromStores.size") - return false - } - } else { - Timber.d("SWITCH: BIOMETRICS") - if (biometricsWalletDataModels.isEmpty()) { - Timber.d("FAILED: biometricsWalletDataModels.isEmpty") - return false - } - - val isCorrectStatus = biometricsWalletDataModels.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) { - Timber.d("FAILED: by status") - return false - } - } - - Timber.d("SUCCESS") - return true - } -} - -/** - * With biometrics enabled, we should check its storage instead of "WalletState.walletsDataFromStores" - * because the latter is updated after some time. - * @property biometricsWalletDataModels - wallet data models from the 'WalletStoresManager'. If null, then - * the "WalletState.walletsDataFromStores" will be used to determine appropriate state - */ -data class BasicEventsSourceData( - val scanResponse: ScanResponse, - val walletState: WalletState, - val biometricsWalletDataModels: List?, -) { - val userWalletIdStringValue: String? by lazy { - UserWalletIdBuilder.scanResponse(scanResponse).build()?.stringValue - } - - val paramCardCurrency: AnalyticsParam.CardCurrency? by lazy { - ParamCardCurrencyConverter().convert(scanResponse.cardTypesResolver) - } - - val paramCardBalanceState: AnalyticsParam.CardBalanceState by lazy { calculateAmount().toCardBalanceState() } - - private fun calculateAmount(): BigDecimal { - val calculator: IBalanceCalculator = biometricsWalletDataModels - ?.let { BiometricsBalanceCalculator(it) } - ?: BalanceCalculator(walletState) - - return calculator.calculate() - } - - private fun BigDecimal.toCardBalanceState(): AnalyticsParam.CardBalanceState = when { - isZero() -> AnalyticsParam.CardBalanceState.Empty - else -> AnalyticsParam.CardBalanceState.Full - } -} - -private interface IBalanceCalculator { - fun calculate(): BigDecimal -} - -private class BiometricsBalanceCalculator( - private val walletDataModel: List, -) : IBalanceCalculator { - - override fun calculate(): BigDecimal { - val singleToken = walletDataModel - .filter { it.currency.isToken() } - .firstOrNull { it.isCardSingleToken } - - val totalAmount = singleToken?.status?.amount - ?: walletDataModel.calculateTotalCryptoAmount() - - return totalAmount - } - - private fun List.calculateTotalCryptoAmount(): BigDecimal = this - .map { it.status.amount } - .reduce(BigDecimal::plus) -} - -private class BalanceCalculator( - private val walletState: WalletState, -) : IBalanceCalculator { - - override fun calculate(): BigDecimal { - val singleTokenData = walletState.primaryTokenData - val totalAmount = singleTokenData?.currencyData?.amount - ?: walletState.walletsDataFromStores.calculateTotalCryptoAmount() - - return totalAmount - } -} - -class BasicTopUpEventConverter : Converter { - - override fun convert(value: BasicEventsSourceData): Basic.ToppedUp? { - if (value.paramCardCurrency == null || value.userWalletIdStringValue == null) return null - - val data = BasicTopUpFilter.Data( - walletId = value.userWalletIdStringValue!!, - cardBalanceState = value.paramCardBalanceState, - ) - - return Basic.ToppedUp(value.paramCardCurrency!!).apply { filterData = data } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/TopUpConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/TopUpConverter.kt new file mode 100644 index 0000000000..98dc89b12e --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/TopUpConverter.kt @@ -0,0 +1,67 @@ +package com.tangem.tap.common.analytics.converters + +import com.tangem.common.Converter +import com.tangem.common.extensions.isZero +import com.tangem.domain.common.CardTypesResolver +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.Basic +import com.tangem.tap.common.analytics.filters.TopUpFilter +import com.tangem.tap.domain.model.WalletDataModel +import java.math.BigDecimal + +/** +[REDACTED_AUTHOR] + */ +class TopUpEventConverter : Converter { + + override fun convert(value: Data): Basic.ToppedUp? { + val (cardTypesResolver, walletDataModels, userWalletIdValue, isToppedUpInPast) = value + val paramCardCurrency = ParamCardCurrencyConverter().convert(cardTypesResolver) ?: return null + + val cardBalanceState = BalanceCalculator(walletDataModels).calculate().toCardBalanceState() + val filterData = TopUpFilter.Data( + walletId = userWalletIdValue, + cardBalanceState = cardBalanceState, + isToppedUpInPast = isToppedUpInPast, + ) + return Basic.ToppedUp(paramCardCurrency).apply { + this.filterData = filterData + } + } + + private fun BigDecimal.toCardBalanceState(): AnalyticsParam.CardBalanceState = when { + isZero() -> AnalyticsParam.CardBalanceState.Empty + else -> AnalyticsParam.CardBalanceState.Full + } + + data class Data( + val cardTypesResolver: CardTypesResolver, + val walletDataModels: List, + val userWalletIdValue: String, + val isToppedUpInPast: Boolean, + ) +} + +private interface IBalanceCalculator { + fun calculate(): BigDecimal +} + +private class BalanceCalculator( + private val walletDataModels: List, +) : 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.calculateTotalCryptoAmount(): BigDecimal = this + .map { it.status.amount } + .reduce(BigDecimal::plus) +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicTopUpFilter.kt b/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicTopUpFilter.kt deleted file mode 100644 index de89bf9e7e..0000000000 --- a/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicTopUpFilter.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.tangem.tap.common.analytics.filters - -import com.tangem.common.extensions.guard -import com.tangem.core.analytics.api.AnalyticsEventFilter -import com.tangem.core.analytics.api.AnalyticsHandler -import com.tangem.core.analytics.AnalyticsEvent -import com.tangem.tap.common.analytics.events.AnalyticsParam -import com.tangem.tap.common.analytics.events.Basic -import com.tangem.tap.persistence.ToppedUpWalletStorage - -/** -[REDACTED_AUTHOR] - */ -class BasicTopUpFilter( - private val topupWalletStorage: ToppedUpWalletStorage, -) : AnalyticsEventFilter { - - override fun canBeAppliedTo(event: AnalyticsEvent): Boolean = event is Basic.ToppedUp - - override fun canBeSent(event: AnalyticsEvent): Boolean { - val data = event.filterData as? Data ?: return false - - val walletInfo = topupWalletStorage.restore(data.walletId).guard { - val newWalletInfo = Data( - walletId = data.walletId, - cardBalanceState = data.cardBalanceState, - ) - topupWalletStorage.save(newWalletInfo) - return false - } - - if (walletInfo.isToppedUp) return false - - return if (!walletInfo.isToppedUp && data.isToppedUp) { - topupWalletStorage.save(walletInfo.copy(cardBalanceState = AnalyticsParam.CardBalanceState.Full)) - true - } else { - false - } - } - - override fun canBeConsumedByHandler(handler: AnalyticsHandler, event: AnalyticsEvent): Boolean = true - - data class Data( - val walletId: String, - val cardBalanceState: AnalyticsParam.CardBalanceState, - ) { - val isToppedUp: Boolean = cardBalanceState == AnalyticsParam.CardBalanceState.Full - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/filters/TopUpFilter.kt b/app/src/main/java/com/tangem/tap/common/analytics/filters/TopUpFilter.kt new file mode 100644 index 0000000000..658ab218aa --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/filters/TopUpFilter.kt @@ -0,0 +1,72 @@ +package com.tangem.tap.common.analytics.filters + +import com.tangem.common.extensions.guard +import com.tangem.core.analytics.AnalyticsEvent +import com.tangem.core.analytics.api.AnalyticsEventFilter +import com.tangem.core.analytics.api.AnalyticsHandler +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.Basic +import com.tangem.tap.common.analytics.topup.log +import com.tangem.tap.common.extensions.dispatchDebugErrorNotification +import com.tangem.tap.persistence.ToppedUpWalletStorage +import com.tangem.tap.store + +/** +[REDACTED_AUTHOR] + */ +class TopUpFilter( + private val topupWalletStorage: ToppedUpWalletStorage, +) : AnalyticsEventFilter { + + override fun canBeAppliedTo(event: AnalyticsEvent): Boolean = event is Basic.ToppedUp + + override fun canBeSent(event: AnalyticsEvent): Boolean { + val data = event.filterData as? Data ?: return false + + if (data.isToppedUpInPast) { + log("BasicTopUpFilter: [false]: sending is blocked") + val newWalletInfo = ToppedUpWalletStorage.Companion.TopupInfo( + walletId = data.walletId, + cardBalanceState = AnalyticsParam.CardBalanceState.Full, + ) + topupWalletStorage.save(newWalletInfo) + return false + } + + val topupInfo = topupWalletStorage.restore(data.walletId).guard { + log("BasicTopUpFilter: [false]: sending is blocked") + val topupInfo = ToppedUpWalletStorage.Companion.TopupInfo( + walletId = data.walletId, + cardBalanceState = data.cardBalanceState, + ) + topupWalletStorage.save(topupInfo) + return false + } + + if (topupInfo.isToppedUp) { + log("BasicTopUpFilter: [false]: sending is blocked") + return false + } + + return if (!topupInfo.isToppedUp && data.isToppedUp) { + log("BasicTopUpFilter: [TRUE]: !topupInfo.isToppedUp && data.isToppedUp") + log("BasicTopUpFilter: [TRUE]: SEND") + store.dispatchDebugErrorNotification("Topped UP sent") + topupWalletStorage.save(topupInfo.copy(cardBalanceState = AnalyticsParam.CardBalanceState.Full)) + true + } else { + log("BasicTopUpFilter: [false]: sending is blocked") + false + } + } + + override fun canBeConsumedByHandler(handler: AnalyticsHandler, event: AnalyticsEvent): Boolean = true + + data class Data( + val walletId: String, + val cardBalanceState: AnalyticsParam.CardBalanceState, + val isToppedUpInPast: Boolean, + ) { + val isToppedUp: Boolean = cardBalanceState == AnalyticsParam.CardBalanceState.Full + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt b/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt new file mode 100644 index 0000000000..3817d79ba5 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt @@ -0,0 +1,156 @@ +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.domain.common.CardTypesResolver +import com.tangem.domain.common.ScanResponse +import com.tangem.domain.common.util.UserWalletId +import com.tangem.tap.common.analytics.converters.TopUpEventConverter +import com.tangem.tap.common.extensions.copy +import com.tangem.tap.domain.model.UserWallet +import com.tangem.tap.domain.model.WalletDataModel +import com.tangem.tap.domain.model.WalletStoreModel +import com.tangem.tap.domain.model.builders.UserWalletIdBuilder +import com.tangem.tap.domain.tokens.models.BlockchainNetwork +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.features.wallet.redux.ProgressState +import com.tangem.tap.scope +import kotlinx.coroutines.launch +import timber.log.Timber + +/** +[REDACTED_AUTHOR] + */ +class TopUpController( + var scanResponseProvider: (() -> ScanResponse?)? = null, + var walletStoresManagerProvider: (() -> WalletStoresManager)? = null, +) : WalletCurrenciesManager.Listener { + + private var hadMissedDerivations: Boolean = false + private val addedCurrencies = mutableListOf() + + override fun willUpdate(userWallet: UserWallet, currency: Currency) { + } + + override fun didUpdate(userWallet: UserWallet, currency: Currency) { + tryToNotify() + } + + override fun willCurrenciesAdd(userWallet: UserWallet, currenciesToAdd: List) { + addedCurrencies.addAll(currenciesToAdd.distinct()) + log("addCurrencies = [${addedCurrencies.joinToString()}]") + } + + override fun willCurrenciesRemove(userWallet: UserWallet, currenciesToRemove: List) { + } + + override fun willCurrencyRemove(userWallet: UserWallet, currencyToRemove: Currency) { + } + + fun walletStoresChanged(walletStores: List) { + val missedDerivations = walletStores + .flatMap { it.walletsData } + .map { it.status } + .filterIsInstance() + + hadMissedDerivations = missedDerivations.isNotEmpty() + log("walletStoresChanged: hadMissedDerivations = [${hadMissedDerivations}]") + } + + fun scanToGetDerivations() { + hadMissedDerivations = true + log("scanAndUpdateCard: hadMissedDerivations = [${hadMissedDerivations}]") + } + + fun addMissingDerivations(blockchains: List) { + hadMissedDerivations = blockchains.isNotEmpty() + log("addMissingDerivations: hadMissedDerivations = [${hadMissedDerivations}]") + } + + fun totalBalanceStateChanged(state: ProgressState) { + log("totalBalanceStateChanged = [${state.name}]") + if (state == ProgressState.Done) { + tryToNotify() + } + } + + fun loadDataSuccess() { + log("loadDataSuccess") + tryToNotify() + } + + private fun tryToNotify() { + if (hadMissedDerivations) { + log("tryToNotify: FAILED: derivationsCheckIsScheduled") + 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()) { + log("tryToNotify: FAILED: walletDataModels.size = [0]") + 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) { + log("tryToNotify: FAILED: by status") + return@launch + } + notify(userWalletId, walletDataModels, scanResponse.cardTypesResolver) + } + } + + private fun notify( + userWalletId: UserWalletId, + walletDataModels: List, + cardTypesResolver: CardTypesResolver, + ) { + val isToppedUpInPast = findToppedUpCurrenciesInPast(walletDataModels).isNotEmpty() + log("notify: currencies from manage tokens had toppedUp in the past = [${isToppedUpInPast}]") + + val data = TopUpEventConverter.Data( + cardTypesResolver = cardTypesResolver, + walletDataModels = walletDataModels, + userWalletIdValue = userWalletId.stringValue, + isToppedUpInPast = isToppedUpInPast, + ) + val event = TopUpEventConverter().convert(data).guard { + log("notify: TopUpEventConverter can't convert a data to an event") + return + } + + log("notify: Analytics.send(event)") + Analytics.send(event) + } + + private fun findToppedUpCurrenciesInPast(walletDataModels: List): List { + log("findToppedUpCurrenciesInPast: added new currencies = [${addedCurrencies.size}]") + 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 + } +} + +fun log(log: String) { + Timber.d("TopUp: %s", log) +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Collections.kt b/app/src/main/java/com/tangem/tap/common/extensions/Collections.kt index 8492ae44f1..517d8ca5ed 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Collections.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Collections.kt @@ -28,4 +28,8 @@ fun MutableList.replaceBy(item: T, predicate: (T) -> Boolean): Boolean { fun MutableList.replaceByOrAdd(item: T, predicate: (T) -> Boolean) { if (!replaceBy(item, predicate)) add(item) +} + +fun MutableList.copy(): MutableList { + return this.map { it }.toMutableList() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt index 56059c6799..14eeac6618 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt @@ -2,6 +2,7 @@ package com.tangem.tap.common.redux.global import com.tangem.datasource.config.ConfigManager import com.tangem.domain.common.ScanResponse +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.common.redux.StateDialog @@ -28,6 +29,7 @@ data class GlobalState( val exchangeManager: CurrencyExchangeManager = CurrencyExchangeManager.dummy(), val userCountryCode: String? = null, val userWalletsListManager: UserWalletsListManager? = null, + val topUpController: TopUpController = TopUpController(), ) : StateType typealias CryptoCurrencyName = String diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt index 15a3835869..c994e477f6 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -22,7 +22,6 @@ import com.tangem.tap.features.disclaimer.createDisclaimer import com.tangem.tap.features.disclaimer.redux.DisclaimerAction import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.wallet.redux.WalletAction -import com.tangem.tap.features.wallet.redux.middlewares.handleBasicAnalyticsEvent import com.tangem.tap.preferencesStorage import com.tangem.tap.store import com.tangem.tap.tangemSdkManager @@ -67,7 +66,7 @@ class TapWalletManager { .doOnSuccess { Timber.d("Wallet stores fetched for ${userWallet.walletId}") store.dispatchOnMain(WalletAction.LoadData.Success) - handleBasicAnalyticsEvent() + store.state.globalState.topUpController.loadDataSuccess() } .doOnFailure { error -> val errorAction = when (error) { diff --git a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/WalletCurrenciesManager.kt b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/WalletCurrenciesManager.kt index 2738438ac1..47d92b26e0 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/WalletCurrenciesManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/WalletCurrenciesManager.kt @@ -69,6 +69,31 @@ interface WalletCurrenciesManager { currenciesToRemove: List, ): CompletionResult + /** + * Add a callback [Listener] + * + * @param listener The callback that will add + */ + fun addListener(listener: Listener) + + /** + * Remove a callback [Listener] + * + * @param listener The callback that will removed + */ + fun removeListener(listener: Listener) + + /** + * Interface definition for a callbacks + */ + interface Listener { + fun willUpdate(userWallet: UserWallet, currency: Currency) + fun didUpdate(userWallet: UserWallet, currency: Currency) + fun willCurrenciesAdd(userWallet: UserWallet, currenciesToAdd: List) + fun willCurrenciesRemove(userWallet: UserWallet, currenciesToRemove: List) + fun willCurrencyRemove(userWallet: UserWallet, currencyToRemove: Currency) + } + // For provider companion object } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt index 5fe6dd8e22..97d9eb72e5 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt @@ -30,23 +30,31 @@ internal class DefaultWalletCurrenciesManager( private val walletManagersRepository: WalletManagersRepository, private val appCurrencyProvider: () -> FiatCurrency, ) : WalletCurrenciesManager { + + private val listeners = mutableListOf() + override suspend fun update( userWallet: UserWallet, currency: Currency, ): CompletionResult = withContext(Dispatchers.Default) { + listeners.forEach { it.willUpdate(userWallet, currency) } val walletStore = walletStoresRepository.getSync(userWallet.walletId) .find { it.blockchain == currency.blockchain && it.derivationPath?.rawPath == currency.derivationPath } - if (walletStore != null) { + val updateResult = if (walletStore == null) { + CompletionResult.Success(Unit) + } else { walletAmountsRepository.updateAmountsForWalletStore( walletStore = walletStore, userWallet = userWallet, fiatCurrency = appCurrencyProvider(), ) - } else CompletionResult.Success(Unit) + } + listeners.forEach { it.didUpdate(userWallet, currency) } + updateResult } override suspend fun addCurrencies( @@ -55,6 +63,7 @@ internal class DefaultWalletCurrenciesManager( ): CompletionResult = withContext(Dispatchers.Default) { val card = userWallet.scanResponse.card val currenciesToAddWithMissingBlockchains = currenciesToAdd.addMissingBlockchainsIfNeeded(card) + listeners.forEach { it.willCurrenciesAdd(userWallet, currenciesToAddWithMissingBlockchains) } updateWalletStores( userWallet = userWallet, @@ -77,6 +86,7 @@ internal class DefaultWalletCurrenciesManager( userWallet: UserWallet, currenciesToRemove: List, ): CompletionResult = withContext(Dispatchers.Default) { + listeners.forEach { it.willCurrenciesRemove(userWallet, currenciesToRemove) } val card = userWallet.scanResponse.card val remainingCurrencies = getSavedCurrencies(userWallet.walletId) .filter { it !in currenciesToRemove } @@ -96,9 +106,18 @@ internal class DefaultWalletCurrenciesManager( userWallet: UserWallet, currencyToRemove: Currency, ): CompletionResult { + listeners.forEach { it.willCurrencyRemove(userWallet, currencyToRemove) } return removeCurrencies(userWallet, listOf(currencyToRemove)) } + override fun addListener(listener: WalletCurrenciesManager.Listener) { + listeners.add(listener) + } + + override fun removeListener(listener: WalletCurrenciesManager.Listener) { + listeners.remove(listener) + } + private suspend fun getSavedCurrencies(userWalletId: UserWalletId): List { return withContext(Dispatchers.Default) { walletStoresRepository.getSync(userWalletId) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt index 81b306448b..45013512af 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt @@ -19,9 +19,6 @@ import com.tangem.tap.store import org.rekotlin.StateType import kotlin.properties.ReadOnlyProperty -/** - * @property derivationsCheckIsScheduled - used only for analytics - */ data class WalletState( val cardId: String = "", val state: ProgressState = ProgressState.Done, @@ -37,7 +34,6 @@ data class WalletState( val totalBalance: TotalBalance? = null, val showBackupWarning: Boolean = false, val missingDerivations: List = emptyList(), - val derivationsCheckIsScheduled: Boolean = false, val loadingUserTokens: Boolean = false, val walletCardsCount: Int? = null, val canSaveUserWallets: Boolean = false, diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt index 2642cbeb50..52ebe9454f 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt @@ -91,13 +91,14 @@ class MultiWalletMiddleware { store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingWallet)) } is WalletAction.MultiWallet.AddMissingDerivations -> { - scope.launch { handleBasicAnalyticsEvent() } + store.state.globalState.topUpController.addMissingDerivations(action.blockchains) } is WalletAction.MultiWallet.ScanToGetDerivations -> { val selectedUserWallet = userWalletsListManager.selectedUserWalletSync.guard { Timber.e("Unable to scan to get derivations, no user wallet selected") return } + store.state.globalState.topUpController.scanToGetDerivations() scanAndUpdateCard(selectedUserWallet, walletState) } else -> {} @@ -108,7 +109,6 @@ class MultiWalletMiddleware { selectedUserWallet: UserWallet, state: WalletState?, ) = scope.launch(Dispatchers.Default) { - dispatchOnMain(WalletAction.MultiWallet.ScheduleCheckForMissingDerivation) tangemSdkManager.scanProduct( cardId = selectedUserWallet.cardId, userTokensRepository = userTokensRepository, diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index 9b5324ead5..b401c9c0fe 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -6,8 +6,6 @@ import com.tangem.blockchain.common.AmountType import com.tangem.common.CompletionResult import com.tangem.common.extensions.guard import com.tangem.core.analytics.Analytics -import com.tangem.tap.common.analytics.converters.BasicEventsPreChecker -import com.tangem.tap.common.analytics.converters.BasicEventsSourceData import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Basic import com.tangem.tap.common.analytics.events.MainScreen @@ -25,7 +23,6 @@ import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.TapError import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.domain.model.WalletStoreModel -import com.tangem.tap.domain.model.builders.UserWalletIdBuilder import com.tangem.tap.domain.userWalletList.lockIfLockable import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.home.redux.HomeAction @@ -46,7 +43,6 @@ import com.tangem.tap.tangemSdkManager import com.tangem.tap.totalFiatBalanceCalculator import com.tangem.tap.userWalletsListManager import com.tangem.tap.userWalletsListManagerSafe -import com.tangem.tap.walletStoresManager import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay @@ -188,7 +184,7 @@ class WalletMiddleware { } is WalletAction.UserWalletChanged -> Unit is WalletAction.WalletStoresChanged -> { - store.dispatchOnMain(WalletAction.MultiWallet.ScheduleCheckForMissingDerivation) + store.state.globalState.topUpController.walletStoresChanged(action.walletStores) updateWalletStores(action.walletStores, walletState) fetchTotalFiatBalance(action.walletStores) findMissedDerivations(action.walletStores) @@ -351,23 +347,4 @@ class WalletMiddleware { tokenRate = tokenRate, ) } -} - -suspend fun handleBasicAnalyticsEvent() { - val scanResponse = store.state.globalState.scanResponse ?: return - - val biometricsWalletDataModels = if (preferencesStorage.shouldSaveUserWallets) { - UserWalletIdBuilder.scanResponse(scanResponse).build()?.let { userWalletId -> - walletStoresManager.getSync(userWalletId).map { it.walletsData }.flatten() - } - } else { - null - } - - val converterData = BasicEventsSourceData( - scanResponse = scanResponse, - walletState = store.state.walletState, - biometricsWalletDataModels = biometricsWalletDataModels, - ) - BasicEventsPreChecker().tryToSend(converterData) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt index 2dcfeaf198..12d2923899 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt @@ -15,12 +15,8 @@ class MultiWalletReducer { state.copy(selectedCurrency = action.currency) } is WalletAction.MultiWallet.TryToRemoveWallet -> state - is WalletAction.MultiWallet.ScheduleCheckForMissingDerivation -> state.copy( - derivationsCheckIsScheduled = true, - ) is WalletAction.MultiWallet.AddMissingDerivations -> state.copy( missingDerivations = action.blockchains, - derivationsCheckIsScheduled = false, ) is WalletAction.MultiWallet.BackupWallet -> state is WalletAction.MultiWallet.ScanToGetDerivations -> state.copy(state = ProgressState.Loading) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index fae5543edf..e72b7e284e 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -17,6 +17,7 @@ import androidx.transition.TransitionInflater import by.kirich1409.viewbindingdelegate.viewBinding import coil.load import coil.size.Scale +import com.badoo.mvicore.modelWatcher import com.tangem.core.analytics.Analytics import com.tangem.core.ui.fragments.setStatusBarColor import com.tangem.core.ui.utils.OneTouchClickListener @@ -63,6 +64,14 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber() + private val totalBalanceWatcher = modelWatcher { + (WalletState::totalBalance) { totalBalance -> + totalBalance?.state?.let { + store.state.globalState.topUpController.totalBalanceStateChanged(it) + } + } + } + override fun onAttach(context: Context) { super.onAttach(context) lifecycle.addObserver(viewModel) @@ -167,6 +176,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber {} // we keep the same view unless we scan a card that requires a different view } + totalBalanceWatcher.invoke(state) walletView.swapInteractor = swapInteractor diff --git a/app/src/main/java/com/tangem/tap/persistence/ToppedUpWalletStorage.kt b/app/src/main/java/com/tangem/tap/persistence/ToppedUpWalletStorage.kt index 75759b8d75..c7234832fe 100644 --- a/app/src/main/java/com/tangem/tap/persistence/ToppedUpWalletStorage.kt +++ b/app/src/main/java/com/tangem/tap/persistence/ToppedUpWalletStorage.kt @@ -3,7 +3,7 @@ package com.tangem.tap.persistence import android.content.SharedPreferences import androidx.core.content.edit import com.tangem.common.json.MoshiJsonConverter -import com.tangem.tap.common.analytics.filters.BasicTopUpFilter +import com.tangem.tap.common.analytics.events.AnalyticsParam import timber.log.Timber /** @@ -14,23 +14,23 @@ class ToppedUpWalletStorage( private val jsonConverter: MoshiJsonConverter, ) { - private val walletList: MutableSet = mutableSetOf() + private val walletList: MutableSet = mutableSetOf() init { walletList.addAll(restore()) } - fun save(userWalletInfo: BasicTopUpFilter.Data): Boolean { + fun save(userWalletInfo: TopupInfo): Boolean { walletList.removeAll { it.walletId == userWalletInfo.walletId } walletList.add(userWalletInfo) return save(walletList) } - fun restore(walletId: String): BasicTopUpFilter.Data? { + fun restore(walletId: String): TopupInfo? { return walletList.firstOrNull { it.walletId == walletId } } - private fun save(userWallets: MutableSet): Boolean { + private fun save(userWallets: MutableSet): Boolean { return try { val json = jsonConverter.toJson(userWallets) preferences.edit(true) { putString(KEY, json) } @@ -41,11 +41,11 @@ class ToppedUpWalletStorage( } } - private fun restore(): MutableSet { + private fun restore(): MutableSet { val json = preferences.getString(KEY, null) ?: return mutableSetOf() return try { - val typedList = jsonConverter.typedList(BasicTopUpFilter.Data::class.java) - val listData = jsonConverter.fromJson>(json, typedList)!! + val typedList = jsonConverter.typedList(TopupInfo::class.java) + val listData = jsonConverter.fromJson>(json, typedList)!! listData.toMutableSet() } catch (ex: Exception) { preferences.edit(true) { remove(KEY) } @@ -55,5 +55,12 @@ class ToppedUpWalletStorage( companion object { private const val KEY = "userWalletsInfo" + + data class TopupInfo( + val walletId: String, + val cardBalanceState: AnalyticsParam.CardBalanceState, + ) { + val isToppedUp: Boolean = cardBalanceState == AnalyticsParam.CardBalanceState.Full + } } } \ No newline at end of file From 9d8611cee3c70432e28903bd84ee9444ce271a2a Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 27 Mar 2023 17:47:53 +0300 Subject: [PATCH 3/3] Updated on 2026-08-14 --- .../java/com/tangem/tap/TapApplication.kt | 17 ++- .../analytics/converters/TopUpConverter.kt | 58 +------ .../common/analytics/filters/TopUpFilter.kt | 72 --------- .../common/analytics/topup/TopUpController.kt | 141 +++++++++++------- .../tap/common/redux/global/GlobalAction.kt | 2 + .../common/redux/global/GlobalMiddleware.kt | 4 + .../tap/common/redux/global/GlobalReducer.kt | 1 + .../tap/common/redux/global/GlobalState.kt | 2 +- .../com/tangem/tap/domain/TapWalletManager.kt | 2 +- .../WalletCurrenciesManager.kt | 10 +- .../note/redux/OnboardingNoteMiddleware.kt | 18 +-- .../redux/OnboardingOtherCardsMiddleware.kt | 1 + .../twins/redux/TwinCardsMiddleware.kt | 17 +-- .../redux/OnboardingWalletMiddleware.kt | 21 +-- .../middlewares/MultiWalletMiddleware.kt | 4 +- .../redux/middlewares/WalletMiddleware.kt | 2 +- .../tap/features/wallet/ui/WalletFragment.kt | 2 +- .../tap/persistence/ToppedUpWalletStorage.kt | 14 +- .../tangem/core/analytics/AnalyticsEvent.kt | 1 - 19 files changed, 146 insertions(+), 243 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/common/analytics/filters/TopUpFilter.kt diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 4247167482..42d008074f 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -22,10 +22,10 @@ import com.tangem.domain.common.LogConfig import com.tangem.tap.common.IntentHandler import com.tangem.tap.common.analytics.AnalyticsFactory import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder -import com.tangem.tap.common.analytics.filters.TopUpFilter 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 @@ -162,10 +162,15 @@ class TapApplication : Application(), ImageLoaderFactory { } private fun initTopUpController() { - val topUpController = store.state.globalState.topUpController - topUpController.walletStoresManagerProvider = { walletStoresManager } - topUpController.scanResponseProvider = { store.state.globalState.scanResponse } - walletCurrenciesManager.addListener(topUpController) + 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 { @@ -194,8 +199,6 @@ class TapApplication : Application(), ImageLoaderFactory { factory.addHandlerBuilder(AppsFlyerAnalyticsHandler.Builder()) factory.addHandlerBuilder(FirebaseAnalyticsHandler.Builder()) - factory.addFilter(TopUpFilter(preferencesStorage.toppedUpWalletStorage)) - val buildData = AnalyticsHandlerBuilder.Data( application = application, config = config, diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/TopUpConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/TopUpConverter.kt index 98dc89b12e..429b2e5ebc 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/converters/TopUpConverter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/TopUpConverter.kt @@ -1,67 +1,17 @@ package com.tangem.tap.common.analytics.converters import com.tangem.common.Converter -import com.tangem.common.extensions.isZero import com.tangem.domain.common.CardTypesResolver -import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Basic -import com.tangem.tap.common.analytics.filters.TopUpFilter -import com.tangem.tap.domain.model.WalletDataModel -import java.math.BigDecimal /** [REDACTED_AUTHOR] */ -class TopUpEventConverter : Converter { +class TopUpEventConverter : Converter { - override fun convert(value: Data): Basic.ToppedUp? { - val (cardTypesResolver, walletDataModels, userWalletIdValue, isToppedUpInPast) = value - val paramCardCurrency = ParamCardCurrencyConverter().convert(cardTypesResolver) ?: return null + override fun convert(value: CardTypesResolver): Basic.ToppedUp? { + val paramCardCurrency = ParamCardCurrencyConverter().convert(value) ?: return null - val cardBalanceState = BalanceCalculator(walletDataModels).calculate().toCardBalanceState() - val filterData = TopUpFilter.Data( - walletId = userWalletIdValue, - cardBalanceState = cardBalanceState, - isToppedUpInPast = isToppedUpInPast, - ) - return Basic.ToppedUp(paramCardCurrency).apply { - this.filterData = filterData - } + return Basic.ToppedUp(paramCardCurrency) } - - private fun BigDecimal.toCardBalanceState(): AnalyticsParam.CardBalanceState = when { - isZero() -> AnalyticsParam.CardBalanceState.Empty - else -> AnalyticsParam.CardBalanceState.Full - } - - data class Data( - val cardTypesResolver: CardTypesResolver, - val walletDataModels: List, - val userWalletIdValue: String, - val isToppedUpInPast: Boolean, - ) -} - -private interface IBalanceCalculator { - fun calculate(): BigDecimal -} - -private class BalanceCalculator( - private val walletDataModels: List, -) : 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.calculateTotalCryptoAmount(): BigDecimal = this - .map { it.status.amount } - .reduce(BigDecimal::plus) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/filters/TopUpFilter.kt b/app/src/main/java/com/tangem/tap/common/analytics/filters/TopUpFilter.kt deleted file mode 100644 index 658ab218aa..0000000000 --- a/app/src/main/java/com/tangem/tap/common/analytics/filters/TopUpFilter.kt +++ /dev/null @@ -1,72 +0,0 @@ -package com.tangem.tap.common.analytics.filters - -import com.tangem.common.extensions.guard -import com.tangem.core.analytics.AnalyticsEvent -import com.tangem.core.analytics.api.AnalyticsEventFilter -import com.tangem.core.analytics.api.AnalyticsHandler -import com.tangem.tap.common.analytics.events.AnalyticsParam -import com.tangem.tap.common.analytics.events.Basic -import com.tangem.tap.common.analytics.topup.log -import com.tangem.tap.common.extensions.dispatchDebugErrorNotification -import com.tangem.tap.persistence.ToppedUpWalletStorage -import com.tangem.tap.store - -/** -[REDACTED_AUTHOR] - */ -class TopUpFilter( - private val topupWalletStorage: ToppedUpWalletStorage, -) : AnalyticsEventFilter { - - override fun canBeAppliedTo(event: AnalyticsEvent): Boolean = event is Basic.ToppedUp - - override fun canBeSent(event: AnalyticsEvent): Boolean { - val data = event.filterData as? Data ?: return false - - if (data.isToppedUpInPast) { - log("BasicTopUpFilter: [false]: sending is blocked") - val newWalletInfo = ToppedUpWalletStorage.Companion.TopupInfo( - walletId = data.walletId, - cardBalanceState = AnalyticsParam.CardBalanceState.Full, - ) - topupWalletStorage.save(newWalletInfo) - return false - } - - val topupInfo = topupWalletStorage.restore(data.walletId).guard { - log("BasicTopUpFilter: [false]: sending is blocked") - val topupInfo = ToppedUpWalletStorage.Companion.TopupInfo( - walletId = data.walletId, - cardBalanceState = data.cardBalanceState, - ) - topupWalletStorage.save(topupInfo) - return false - } - - if (topupInfo.isToppedUp) { - log("BasicTopUpFilter: [false]: sending is blocked") - return false - } - - return if (!topupInfo.isToppedUp && data.isToppedUp) { - log("BasicTopUpFilter: [TRUE]: !topupInfo.isToppedUp && data.isToppedUp") - log("BasicTopUpFilter: [TRUE]: SEND") - store.dispatchDebugErrorNotification("Topped UP sent") - topupWalletStorage.save(topupInfo.copy(cardBalanceState = AnalyticsParam.CardBalanceState.Full)) - true - } else { - log("BasicTopUpFilter: [false]: sending is blocked") - false - } - } - - override fun canBeConsumedByHandler(handler: AnalyticsHandler, event: AnalyticsEvent): Boolean = true - - data class Data( - val walletId: String, - val cardBalanceState: AnalyticsParam.CardBalanceState, - val isToppedUpInPast: Boolean, - ) { - val isToppedUp: Boolean = cardBalanceState == AnalyticsParam.CardBalanceState.Full - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt b/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt index 3817d79ba5..e17985be26 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt @@ -7,6 +7,7 @@ import com.tangem.domain.common.CardTypesResolver import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.util.UserWalletId import com.tangem.tap.common.analytics.converters.TopUpEventConverter +import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.extensions.copy import com.tangem.tap.domain.model.UserWallet import com.tangem.tap.domain.model.WalletDataModel @@ -17,9 +18,10 @@ 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.features.wallet.redux.ProgressState +import com.tangem.tap.persistence.ToppedUpWalletStorage import com.tangem.tap.scope import kotlinx.coroutines.launch -import timber.log.Timber +import java.math.BigDecimal /** [REDACTED_AUTHOR] @@ -27,27 +29,18 @@ import timber.log.Timber 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() - override fun willUpdate(userWallet: UserWallet, currency: Currency) { - } - override fun didUpdate(userWallet: UserWallet, currency: Currency) { - tryToNotify() + tryToSend() } override fun willCurrenciesAdd(userWallet: UserWallet, currenciesToAdd: List) { addedCurrencies.addAll(currenciesToAdd.distinct()) - log("addCurrencies = [${addedCurrencies.joinToString()}]") - } - - override fun willCurrenciesRemove(userWallet: UserWallet, currenciesToRemove: List) { - } - - override fun willCurrencyRemove(userWallet: UserWallet, currencyToRemove: Currency) { } fun walletStoresChanged(walletStores: List) { @@ -57,46 +50,34 @@ class TopUpController( .filterIsInstance() hadMissedDerivations = missedDerivations.isNotEmpty() - log("walletStoresChanged: hadMissedDerivations = [${hadMissedDerivations}]") } fun scanToGetDerivations() { hadMissedDerivations = true - log("scanAndUpdateCard: hadMissedDerivations = [${hadMissedDerivations}]") } fun addMissingDerivations(blockchains: List) { hadMissedDerivations = blockchains.isNotEmpty() - log("addMissingDerivations: hadMissedDerivations = [${hadMissedDerivations}]") } fun totalBalanceStateChanged(state: ProgressState) { - log("totalBalanceStateChanged = [${state.name}]") - if (state == ProgressState.Done) { - tryToNotify() - } + if (state == ProgressState.Done) tryToSend() } fun loadDataSuccess() { - log("loadDataSuccess") - tryToNotify() + tryToSend() } - private fun tryToNotify() { - if (hadMissedDerivations) { - log("tryToNotify: FAILED: derivationsCheckIsScheduled") - return - } + 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()) { - log("tryToNotify: FAILED: walletDataModels.size = [0]") - return@launch - } + if (walletDataModels.isEmpty()) return@launch + val isCorrectStatus = walletDataModels.any { it.status is WalletDataModel.Loading || it.status is WalletDataModel.NoAccount || @@ -104,39 +85,70 @@ class TopUpController( it.status is WalletDataModel.MissedDerivation || it.status.isErrorStatus } - if (isCorrectStatus) { - log("tryToNotify: FAILED: by status") + if (isCorrectStatus) return@launch + + val isToppedUpInPast = findToppedUpCurrenciesInPast(walletDataModels).isNotEmpty() + if (isToppedUpInPast) { + val newWalletInfo = ToppedUpWalletStorage.TopupInfo( + walletId = userWalletId.stringValue, + cardBalanceState = AnalyticsParam.CardBalanceState.Full, + ) + topupWalletStorage.save(newWalletInfo) return@launch } - notify(userWalletId, walletDataModels, scanResponse.cardTypesResolver) + + val cardBalanceState = BalanceCalculator(walletDataModels).calculate().toCardBalanceState() + send(userWalletId, cardBalanceState, scanResponse.cardTypesResolver) } } - private fun notify( + /** + * A UserWalletId registration should be after creating wallets + */ + fun registerEmptyWallet(scanResponse: ScanResponse) { + UserWalletIdBuilder.scanResponse(scanResponse).build()?.let { + topupWalletStorage.save( + ToppedUpWalletStorage.TopupInfo( + walletId = it.stringValue, + cardBalanceState = AnalyticsParam.CardBalanceState.Empty, + ), + ) + } + } + + fun send( + scanResponse: ScanResponse, + cardBalanceState: AnalyticsParam.CardBalanceState, + ) { + UserWalletIdBuilder.scanResponse(scanResponse).build()?.let { + send(it, cardBalanceState, scanResponse.cardTypesResolver) + } + } + + fun send( userWalletId: UserWalletId, - walletDataModels: List, + cardBalanceState: AnalyticsParam.CardBalanceState, cardTypesResolver: CardTypesResolver, ) { - val isToppedUpInPast = findToppedUpCurrenciesInPast(walletDataModels).isNotEmpty() - log("notify: currencies from manage tokens had toppedUp in the past = [${isToppedUpInPast}]") - - val data = TopUpEventConverter.Data( - cardTypesResolver = cardTypesResolver, - walletDataModels = walletDataModels, - userWalletIdValue = userWalletId.stringValue, - isToppedUpInPast = isToppedUpInPast, - ) - val event = TopUpEventConverter().convert(data).guard { - log("notify: TopUpEventConverter can't convert a data to an event") + val topupInfo = topupWalletStorage.restore(userWalletId.stringValue).guard { + val topupInfo = ToppedUpWalletStorage.TopupInfo( + walletId = userWalletId.stringValue, + cardBalanceState = cardBalanceState, + ) + topupWalletStorage.save(topupInfo) return } + if (topupInfo.isToppedUp) return - log("notify: Analytics.send(event)") - Analytics.send(event) + if (!topupInfo.isToppedUp && cardBalanceState.isToppedUp()) { + topupWalletStorage.save(topupInfo.copy(cardBalanceState = AnalyticsParam.CardBalanceState.Full)) + TopUpEventConverter().convert(cardTypesResolver)?.let { + Analytics.send(it) + } + } } private fun findToppedUpCurrenciesInPast(walletDataModels: List): List { - log("findToppedUpCurrenciesInPast: added new currencies = [${addedCurrencies.size}]") val currenciesToppedUpInPast = addedCurrencies.copy() .mapNotNull { currency -> val foundCurrencyModel = walletDataModels @@ -149,8 +161,35 @@ class TopUpController( 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 } -fun log(log: String) { - Timber.d("TopUp: %s", log) +private interface IBalanceCalculator { + fun calculate(): BigDecimal +} + +private class BalanceCalculator( + private val walletDataModels: List, +) : 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.calculateTotalCryptoAmount(): BigDecimal = this + .map { it.status.amount } + .reduce(BigDecimal::plus) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt index f0f6e8244c..a140fb2d0c 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt @@ -7,6 +7,7 @@ import com.tangem.common.core.TangemError import com.tangem.datasource.config.ConfigManager import com.tangem.datasource.config.models.ChatConfig import com.tangem.domain.common.ScanResponse +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 @@ -88,6 +89,7 @@ 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() diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt index b7fd1db3fe..5d99c5357e 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt @@ -32,6 +32,7 @@ import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.tangemSdkManager import com.tangem.tap.userTokensRepository +import com.tangem.tap.walletCurrenciesManager import com.tangem.wallet.BuildConfig import kotlinx.coroutines.launch import org.rekotlin.Action @@ -194,6 +195,9 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di } } } + is GlobalAction.SetTopUpController -> { + walletCurrenciesManager.addListener(action.topUpController) + } } } diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt index 3ed3751c74..15b8d10c94 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt @@ -49,6 +49,7 @@ 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 diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt index 14eeac6618..1d6dddf647 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt @@ -29,7 +29,7 @@ data class GlobalState( val exchangeManager: CurrencyExchangeManager = CurrencyExchangeManager.dummy(), val userCountryCode: String? = null, val userWalletsListManager: UserWalletsListManager? = null, - val topUpController: TopUpController = TopUpController(), + val topUpController: TopUpController? = null, ) : StateType typealias CryptoCurrencyName = String diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt index c994e477f6..509cd78033 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -66,7 +66,7 @@ class TapWalletManager { .doOnSuccess { Timber.d("Wallet stores fetched for ${userWallet.walletId}") store.dispatchOnMain(WalletAction.LoadData.Success) - store.state.globalState.topUpController.loadDataSuccess() + store.state.globalState.topUpController?.loadDataSuccess() } .doOnFailure { error -> val errorAction = when (error) { diff --git a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/WalletCurrenciesManager.kt b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/WalletCurrenciesManager.kt index 47d92b26e0..fa2bbc0424 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/WalletCurrenciesManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/WalletCurrenciesManager.kt @@ -87,11 +87,11 @@ interface WalletCurrenciesManager { * Interface definition for a callbacks */ interface Listener { - fun willUpdate(userWallet: UserWallet, currency: Currency) - fun didUpdate(userWallet: UserWallet, currency: Currency) - fun willCurrenciesAdd(userWallet: UserWallet, currenciesToAdd: List) - fun willCurrenciesRemove(userWallet: UserWallet, currenciesToRemove: List) - fun willCurrencyRemove(userWallet: UserWallet, currencyToRemove: Currency) + fun willUpdate(userWallet: UserWallet, currency: Currency) {} + fun didUpdate(userWallet: UserWallet, currency: Currency) {} + fun willCurrenciesAdd(userWallet: UserWallet, currenciesToAdd: List) {} + fun willCurrenciesRemove(userWallet: UserWallet, currenciesToRemove: List) {} + fun willCurrencyRemove(userWallet: UserWallet, currencyToRemove: Currency) {} } // For provider diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt index 8ec11cf17c..fddc46b3a8 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt @@ -6,7 +6,6 @@ import com.tangem.core.analytics.Analytics 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.Basic import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.extensions.dispatchDebugErrorNotification import com.tangem.tap.common.extensions.dispatchDialogShow @@ -98,7 +97,7 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch onboardingManager.activationFinished(card.cardId) postUi(DELAY_SDK_DIALOG_CLOSE) { store.dispatch(OnboardingNoteAction.Confetti.Show) } } - else -> {} + else -> Unit } } is OnboardingNoteAction.CreateWallet -> { @@ -111,11 +110,10 @@ 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 -> { -// do nothing - } + is CompletionResult.Failure -> Unit } } } @@ -160,15 +158,7 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch } is OnboardingNoteAction.Balance.Set -> { if (action.balance.balanceIsToppedUp()) { - Analytics.send( - event = Basic.ToppedUp( - currency = AnalyticsParam.CardCurrency.SingleCurrency( - type = AnalyticsParam.CurrencyType.Blockchain( - blockchain = scanResponse.cardTypesResolver.getBlockchain(), - ), - ), - ), - ) + store.state.globalState.topUpController?.send(scanResponse, AnalyticsParam.CardBalanceState.Full) store.dispatch(OnboardingNoteAction.SetStepOfScreen(OnboardingNoteStep.Done)) } } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt index faa3dd2441..73312bd8a9 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt @@ -87,6 +87,7 @@ 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) { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt index f6d021d0f8..e7d4d1edf5 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt @@ -8,7 +8,6 @@ import com.tangem.domain.common.ScanResponse 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.Basic import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.extensions.dispatchDebugErrorNotification import com.tangem.tap.common.extensions.dispatchDialogShow @@ -206,6 +205,8 @@ 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 { when (twinCardsState.mode) { @@ -262,18 +263,8 @@ private fun handle(action: Action, dispatch: DispatchFunction) { } is TwinCardsAction.Balance.Set -> { if (action.balance.balanceIsToppedUp()) { - Analytics.send( - event = Basic.ToppedUp( - currency = AnalyticsParam.CardCurrency.SingleCurrency( - type = AnalyticsParam.CurrencyType.Blockchain( - blockchain = getScanResponse().cardTypesResolver.getBlockchain(), - ), - ), - ), - ) - scope.launch { - withMainContext { store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.Done)) } - } + store.state.globalState.topUpController?.send(getScanResponse(), AnalyticsParam.CardBalanceState.Full) + store.dispatchOnMain(TwinCardsAction.SetStepOfScreen(TwinCardsStep.Done)) } } is TwinCardsAction.ShowAddressInfoDialog -> { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt index 50a9f32619..94fe803ccc 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt @@ -127,6 +127,7 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: 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 @@ -145,9 +146,7 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: startCardActivation(updatedResponse) store.dispatch(OnboardingWalletAction.ResumeBackup) } - is CompletionResult.Failure -> { -// do nothing - } + is CompletionResult.Failure -> Unit } } } @@ -190,7 +189,7 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: newAction?.let { store.dispatch(it) } } OnboardingWalletAction.OnBackPressed -> handleOnBackPressed(onboardingWalletState) - else -> {} + else -> Unit } } @@ -249,8 +248,7 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) is CompletionResult.Success -> { store.dispatchOnMain(BackupAction.StartAddingBackupCards) } - is CompletionResult.Failure -> { - } + is CompletionResult.Failure -> Unit } } } @@ -267,8 +265,7 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) is CompletionResult.Success -> { store.dispatchOnMain(BackupAction.AddBackupCard.Success) } - is CompletionResult.Failure -> { - } + is CompletionResult.Failure -> Unit } } } @@ -308,8 +305,7 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) is CompletionResult.Success -> { store.dispatchOnMain(BackupAction.PrepareToWriteBackupCard(1)) } - is CompletionResult.Failure -> { - } + is CompletionResult.Failure -> Unit } } } @@ -324,8 +320,7 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) store.dispatchOnMain(BackupAction.PrepareToWriteBackupCard(action.cardNumber + 1)) } } - is CompletionResult.Failure -> { - } + is CompletionResult.Failure -> Unit } } } @@ -375,7 +370,7 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) Analytics.send(Onboarding.Finished()) finishCardActivation(notActivatedCardIds) } - else -> {} + else -> Unit } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt index 52ebe9454f..f2cc59a816 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt @@ -91,14 +91,14 @@ class MultiWalletMiddleware { store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingWallet)) } is WalletAction.MultiWallet.AddMissingDerivations -> { - store.state.globalState.topUpController.addMissingDerivations(action.blockchains) + store.state.globalState.topUpController?.addMissingDerivations(action.blockchains) } is WalletAction.MultiWallet.ScanToGetDerivations -> { val selectedUserWallet = userWalletsListManager.selectedUserWalletSync.guard { Timber.e("Unable to scan to get derivations, no user wallet selected") return } - store.state.globalState.topUpController.scanToGetDerivations() + store.state.globalState.topUpController?.scanToGetDerivations() scanAndUpdateCard(selectedUserWallet, walletState) } else -> {} diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index b401c9c0fe..5d12f94a9a 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -184,7 +184,7 @@ class WalletMiddleware { } is WalletAction.UserWalletChanged -> Unit is WalletAction.WalletStoresChanged -> { - store.state.globalState.topUpController.walletStoresChanged(action.walletStores) + store.state.globalState.topUpController?.walletStoresChanged(action.walletStores) updateWalletStores(action.walletStores, walletState) fetchTotalFiatBalance(action.walletStores) findMissedDerivations(action.walletStores) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index e72b7e284e..f3a6eba304 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -67,7 +67,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber totalBalance?.state?.let { - store.state.globalState.topUpController.totalBalanceStateChanged(it) + store.state.globalState.topUpController?.totalBalanceStateChanged(it) } } } diff --git a/app/src/main/java/com/tangem/tap/persistence/ToppedUpWalletStorage.kt b/app/src/main/java/com/tangem/tap/persistence/ToppedUpWalletStorage.kt index c7234832fe..892b1a2370 100644 --- a/app/src/main/java/com/tangem/tap/persistence/ToppedUpWalletStorage.kt +++ b/app/src/main/java/com/tangem/tap/persistence/ToppedUpWalletStorage.kt @@ -53,14 +53,14 @@ class ToppedUpWalletStorage( } } + data class TopupInfo( + val walletId: String, + val cardBalanceState: AnalyticsParam.CardBalanceState, + ) { + val isToppedUp: Boolean = cardBalanceState == AnalyticsParam.CardBalanceState.Full + } + companion object { private const val KEY = "userWalletsInfo" - - data class TopupInfo( - val walletId: String, - val cardBalanceState: AnalyticsParam.CardBalanceState, - ) { - val isToppedUp: Boolean = cardBalanceState == AnalyticsParam.CardBalanceState.Full - } } } \ No newline at end of file diff --git a/core/analytics/src/main/java/com/tangem/core/analytics/AnalyticsEvent.kt b/core/analytics/src/main/java/com/tangem/core/analytics/AnalyticsEvent.kt index e23a503460..1fbc89d977 100644 --- a/core/analytics/src/main/java/com/tangem/core/analytics/AnalyticsEvent.kt +++ b/core/analytics/src/main/java/com/tangem/core/analytics/AnalyticsEvent.kt @@ -8,5 +8,4 @@ open class AnalyticsEvent( val event: String, var params: Map = mapOf(), val error: Throwable? = null, - var filterData: Any? = null, ) \ No newline at end of file