From b0d9a8957f5be94c903f9a8ea4749b84d97bf7b8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 15 Nov 2022 00:17:49 +0500 Subject: [PATCH 01/40] Updated on 2026-08-14 --- .../com/tangem/tap/common/DialogManager.kt | 3 ++- .../note/redux/OnboardingNoteMiddleware.kt | 12 +++++++++++- .../tap/features/wallet/redux/WalletAction.kt | 5 ++++- .../middlewares/WalletDialogsMiddleware.kt | 2 +- .../wallet/redux/models/WalletDialog.kt | 5 ++++- ...ssianCardholdersWarningBottomSheetDialog.kt | 18 ++++++++++++++++-- 6 files changed, 38 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/DialogManager.kt b/app/src/main/java/com/tangem/tap/common/DialogManager.kt index ed8d4542b9..4d1c3734ea 100644 --- a/app/src/main/java/com/tangem/tap/common/DialogManager.kt +++ b/app/src/main/java/com/tangem/tap/common/DialogManager.kt @@ -152,7 +152,8 @@ class DialogManager : StoreSubscriber { primaryButtonRes = state.dialog.primaryButtonRes, primaryButtonAction = state.dialog.onOk, ) - is WalletDialog.RussianCardholdersWarningDialog -> RussianCardholdersWarningBottomSheetDialog(context) + is WalletDialog.RussianCardholdersWarningDialog -> + RussianCardholdersWarningBottomSheetDialog(context, state.dialog.data) else -> null } dialog?.show() 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 ef0c5a743a..5ecccaa431 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 @@ -10,6 +10,7 @@ import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.extensions.dispatchDebugErrorNotification 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.dispatchOpenUrl import com.tangem.tap.common.extensions.getAddressData import com.tangem.tap.common.extensions.getTopUpUrl @@ -24,8 +25,11 @@ import com.tangem.tap.domain.TapError import com.tangem.tap.domain.extensions.hasWallets import com.tangem.tap.domain.extensions.makePrimaryWalletManager import com.tangem.tap.features.demo.DemoHelper +import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE 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.scope import com.tangem.tap.store import com.tangem.tap.tangemSdkManager @@ -172,11 +176,17 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch return } + val topUpUrl = walletManager.getTopUpUrl() ?: return val blockchain = walletManager.wallet.blockchain + if (globalState.userCountryCode == RUSSIA_COUNTRY_CODE) { + val dialogData = WalletDialog.RussianCardholdersWarningDialog.Data(topUpUrl, blockchain) + store.dispatchOnMain(WalletAction.DialogAction.RussianCardholdersWarningDialog(dialogData)) + return + } + val currencyType = AnalyticsParam.CurrencyType.Blockchain(blockchain) Analytics.send(Onboarding.Topup.ButtonBuyCrypto(currencyType)) - val topUpUrl = walletManager.getTopUpUrl() ?: return store.dispatchOpenUrl(topUpUrl) } OnboardingNoteAction.Done -> { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt index 8843a8eb40..02e6073066 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt @@ -15,6 +15,7 @@ import com.tangem.tap.domain.TapError import com.tangem.tap.domain.configurable.warningMessage.WarningMessage import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.wallet.models.Currency +import com.tangem.tap.features.wallet.redux.models.WalletDialog import com.tangem.wallet.R import org.rekotlin.Action import java.math.BigDecimal @@ -154,7 +155,9 @@ sealed class WalletAction : Action { object SignedHashesMultiWalletDialog : DialogAction() object ChooseTradeActionDialog : DialogAction() data class ChooseCurrency(val amounts: List?) : DialogAction() - object RussianCardholdersWarningDialog : DialogAction() + data class RussianCardholdersWarningDialog( + val dialogData: WalletDialog.RussianCardholdersWarningDialog.Data? = null + ) : DialogAction() object Hide : DialogAction() } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletDialogsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletDialogsMiddleware.kt index 64d2122fa2..f94e6def86 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletDialogsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletDialogsMiddleware.kt @@ -38,7 +38,7 @@ class WalletDialogsMiddleware { ) } is WalletAction.DialogAction.RussianCardholdersWarningDialog -> { - store.dispatchDialogShow(WalletDialog.RussianCardholdersWarningDialog) + store.dispatchDialogShow(WalletDialog.RussianCardholdersWarningDialog(action.dialogData)) } is WalletAction.DialogAction.Hide -> { store.dispatchDialogHide() diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/models/WalletDialog.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/models/WalletDialog.kt index 68718acd45..fc182e2c4f 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/models/WalletDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/models/WalletDialog.kt @@ -1,6 +1,7 @@ package com.tangem.tap.features.wallet.redux.models import com.tangem.blockchain.common.Amount +import com.tangem.blockchain.common.Blockchain import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.redux.StateDialog import com.tangem.wallet.R @@ -31,5 +32,7 @@ sealed interface WalletDialog : StateDialog { val titleRes: Int = R.string.token_details_unable_hide_alert_title } - object RussianCardholdersWarningDialog : WalletDialog + data class RussianCardholdersWarningDialog(val data: Data?) : WalletDialog { + data class Data(val topUpUrl: String, val blockchain: Blockchain) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt index 526b991006..b8022e2724 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt @@ -5,14 +5,22 @@ import android.os.Bundle import android.view.LayoutInflater import com.google.android.material.bottomsheet.BottomSheetDialog import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.dispatchDialogHide +import com.tangem.tap.common.extensions.dispatchOpenUrl import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.features.wallet.redux.models.WalletDialog import com.tangem.tap.store import com.tangem.wallet.databinding.DialogRussiansCardholdersWarningBinding -class RussianCardholdersWarningBottomSheetDialog(context: Context) : BottomSheetDialog(context) { +class RussianCardholdersWarningBottomSheetDialog( + context: Context, + private val dialogData: WalletDialog.RussianCardholdersWarningDialog.Data?, +) : BottomSheetDialog + (context) { private var binding: DialogRussiansCardholdersWarningBinding? = null @@ -32,7 +40,13 @@ class RussianCardholdersWarningBottomSheetDialog(context: Context) : BottomSheet } binding?.btnYes?.setOnClickListener { - store.dispatch(WalletAction.TradeCryptoAction.Buy(checkUserLocation = false)) + if (dialogData != null) { + val currencyType = AnalyticsParam.CurrencyType.Blockchain(dialogData.blockchain) + Analytics.send(Onboarding.Topup.ButtonBuyCrypto(currencyType)) + store.dispatchOpenUrl(dialogData.topUpUrl) + } else { + store.dispatch(WalletAction.TradeCryptoAction.Buy(checkUserLocation = false)) + } dismiss() } binding?.btnNo?.setOnClickListener { From 4424a8b9b6af6c03d1b5fb3b585db9b1381d9fbf Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 15 Nov 2022 02:27:54 +0500 Subject: [PATCH 02/40] Updated on 2026-08-14 --- .../java/com/tangem/tap/TapApplication.kt | 18 ++++++++-- .../com/tangem/tap/common/moshi/Adapters.kt | 16 +++++++++ .../tap/persistence/PreferencesStorage.kt | 8 ++--- .../tap/persistence/ToppedUpWalletStorage.kt | 21 ++++++++++- .../tangem/network/common/MoshiConverter.kt | 35 +++++++------------ 5 files changed, 69 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/common/moshi/Adapters.kt diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 568ca4af60..5074f09e8d 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -27,6 +27,7 @@ import com.tangem.tap.common.feedback.AdditionalFeedbackInfo import com.tangem.tap.common.feedback.FeedbackManager import com.tangem.tap.common.images.createCoilImageLoader import com.tangem.tap.common.log.TangemLogCollector +import com.tangem.tap.common.moshi.BigDecimalAdapter import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.appReducer import com.tangem.tap.common.redux.global.GlobalAction @@ -38,6 +39,7 @@ import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager import com.tangem.tap.domain.tokens.UserTokensRepository import com.tangem.tap.domain.walletconnect.WalletConnectRepository import com.tangem.tap.network.NetworkConnectivity +import com.tangem.tap.persistence.CardBalanceStateAdapter import com.tangem.tap.persistence.PreferencesStorage import com.tangem.wallet.BuildConfig import com.zendesk.logger.Logger @@ -70,13 +72,14 @@ class TapApplication : Application(), ImageLoaderFactory { foregroundActivityObserver = ForegroundActivityObserver() registerActivityLifecycleCallbacks(foregroundActivityObserver.callbacks) + initMoshiConverter() DomainLayer.init() NetworkConnectivity.createInstance(store, this) preferencesStorage = PreferencesStorage(this) walletConnectRepository = WalletConnectRepository(this) assetReader = AndroidAssetReader(this) - val configLoader = FeaturesLocalLoader(assetReader, MoshiConverter.defaultMoshi()) + val configLoader = FeaturesLocalLoader(assetReader, MoshiConverter.INSTANCE.moshi) initConfigManager(configLoader, ::initWithConfigDependency) initWarningMessagesManager() @@ -88,6 +91,17 @@ class TapApplication : Application(), ImageLoaderFactory { ) } + private fun initMoshiConverter() { + fun appAdapters(): List = listOf( + BigDecimalAdapter(), + CardBalanceStateAdapter(), + ) + MoshiConverter.reInitInstance( + adapters = appAdapters() + MoshiJsonConverter.getTangemSdkAdapters(), + typedAdapters = MoshiJsonConverter.getTangemSdkTypedAdapters(), + ) + } + override fun newImageLoader(): ImageLoader { return createCoilImageLoader( context = this, @@ -124,7 +138,7 @@ class TapApplication : Application(), ImageLoaderFactory { config = config, isDebug = BuildConfig.DEBUG, logConfig = LogConfig.analyticsHandlers, - jsonConverter = MoshiJsonConverter.INSTANCE, + jsonConverter = MoshiConverter.INSTANCE, ) factory.build(Analytics, buildData) } diff --git a/app/src/main/java/com/tangem/tap/common/moshi/Adapters.kt b/app/src/main/java/com/tangem/tap/common/moshi/Adapters.kt new file mode 100644 index 0000000000..c0ec09ea9c --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/moshi/Adapters.kt @@ -0,0 +1,16 @@ +package com.tangem.tap.common.moshi + +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson +import java.math.BigDecimal + +/** +[REDACTED_AUTHOR] + */ +class BigDecimalAdapter { + @FromJson + fun fromJson(value: String) = BigDecimal(value) + + @ToJson + fun toJson(value: BigDecimal) = value.toString() +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt b/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt index 38a03e482d..0e213fc01b 100644 --- a/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt +++ b/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt @@ -4,7 +4,7 @@ import android.app.Application import android.content.Context import android.content.SharedPreferences import androidx.core.content.edit -import com.tangem.common.json.MoshiJsonConverter +import com.tangem.network.common.MoshiConverter import java.util.* class PreferencesStorage(applicationContext: Application) { @@ -21,12 +21,12 @@ class PreferencesStorage(applicationContext: Application) { init { incrementLaunchCounter() appRatingLaunchObserver = AppRatingLaunchObserver(preferences, getCountOfLaunches()) - usedCardsPrefStorage = UsedCardsPrefStorage(preferences, MoshiJsonConverter.INSTANCE) + usedCardsPrefStorage = UsedCardsPrefStorage(preferences, MoshiConverter.INSTANCE) usedCardsPrefStorage.migrate() - fiatCurrenciesPrefStorage = FiatCurrenciesPrefStorage(preferences, MoshiJsonConverter.INSTANCE) + fiatCurrenciesPrefStorage = FiatCurrenciesPrefStorage(preferences, MoshiConverter.INSTANCE) fiatCurrenciesPrefStorage.migrate() disclaimerPrefStorage = DisclaimerPrefStorage(preferences) - toppedUpWalletStorage = ToppedUpWalletStorage(preferences, MoshiJsonConverter.INSTANCE) + toppedUpWalletStorage = ToppedUpWalletStorage(preferences, MoshiConverter.INSTANCE) } var chatFirstLaunchTime: Long? 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 7ec028e8ea..e270b2b820 100644 --- a/app/src/main/java/com/tangem/tap/persistence/ToppedUpWalletStorage.kt +++ b/app/src/main/java/com/tangem/tap/persistence/ToppedUpWalletStorage.kt @@ -2,7 +2,10 @@ package com.tangem.tap.persistence import android.content.SharedPreferences import androidx.core.content.edit +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson import com.tangem.common.json.MoshiJsonConverter +import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.filters.BasicTopUpFilter import timber.log.Timber @@ -44,7 +47,9 @@ class ToppedUpWalletStorage( private fun restore(): MutableSet { val json = preferences.getString(KEY, null) ?: return mutableSetOf() return try { - jsonConverter.fromJson(json, jsonConverter.typedList(BasicTopUpFilter.Data::class.java))!! + val typedList = jsonConverter.typedList(BasicTopUpFilter.Data::class.java) + val listData = jsonConverter.fromJson>(json, typedList)!! + listData.toMutableSet() } catch (ex: Exception) { preferences.edit(true) { remove(KEY) } mutableSetOf() @@ -54,4 +59,18 @@ class ToppedUpWalletStorage( companion object { private const val KEY = "userWalletsInfo" } +} + +class CardBalanceStateAdapter { + @ToJson + fun toJson(src: AnalyticsParam.CardBalanceState): String = src.value + + @FromJson + fun fromJson(json: String): AnalyticsParam.CardBalanceState { + return when (json) { + AnalyticsParam.CardBalanceState.Empty.value -> AnalyticsParam.CardBalanceState.Empty + AnalyticsParam.CardBalanceState.Full.value -> AnalyticsParam.CardBalanceState.Full + else -> throw IllegalArgumentException() + } + } } \ No newline at end of file diff --git a/network/src/main/java/com/tangem/network/common/MoshiConverter.kt b/network/src/main/java/com/tangem/network/common/MoshiConverter.kt index 1f967032e3..47b5cc4b64 100644 --- a/network/src/main/java/com/tangem/network/common/MoshiConverter.kt +++ b/network/src/main/java/com/tangem/network/common/MoshiConverter.kt @@ -1,38 +1,29 @@ package com.tangem.network.common -import com.squareup.moshi.FromJson +import com.squareup.moshi.JsonAdapter import com.squareup.moshi.Moshi -import com.squareup.moshi.ToJson -import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import com.tangem.common.json.MoshiJsonConverter -import com.tangem.common.json.TangemSdkAdapter import retrofit2.Converter import retrofit2.converter.moshi.MoshiConverterFactory -import java.math.BigDecimal /** [REDACTED_AUTHOR] */ -class MoshiConverter { +object MoshiConverter { - companion object { - fun createFactory(moshi: Moshi = defaultMoshi()): Converter.Factory = MoshiConverterFactory.create(moshi) + var INSTANCE = MoshiJsonConverter() + private set - fun defaultMoshi(): Moshi = Moshi.Builder() - .add(BigDecimalAdapter) - .add(KotlinJsonAdapterFactory()) - .add(TangemSdkAdapter.DerivationPathAdapter()) - .add(TangemSdkAdapter.DerivationNodeAdapter()) - .build() - - fun sdkMoshi(): Moshi = MoshiJsonConverter.INSTANCE.moshi + fun reInitInstance( + adapters: List = listOf(), + typedAdapters: Map, JsonAdapter<*>> = mapOf(), + ) { + INSTANCE = MoshiJsonConverter(adapters, typedAdapters) } -} -object BigDecimalAdapter { - @FromJson - fun fromJson(string: String) = BigDecimal(string) + fun createFactory(moshi: Moshi = INSTANCE.moshi): Converter.Factory = MoshiConverterFactory.create(moshi) - @ToJson - fun toJson(value: BigDecimal) = value.toString() + fun defaultMoshi(): Moshi = INSTANCE.moshi + + fun sdkMoshi(): Moshi = MoshiJsonConverter.INSTANCE.moshi } \ No newline at end of file From 327d84b8cf0064c7f43f66e08975cd91705d5dd4 Mon Sep 17 00:00:00 2001 From: Tangem Date: Sat, 19 Nov 2022 16:42:19 +0500 Subject: [PATCH 03/40] Updated on 2026-08-14 --- .../onboarding/products/note/redux/OnboardingNoteMiddleware.kt | 1 - 1 file changed, 1 deletion(-) 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 97e13e9aaf..5ecccaa431 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 @@ -30,7 +30,6 @@ 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.features.wallet.redux.WalletAction import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.tangemSdkManager From bd0797b3d2b85b96a0eb48f4a241fb97de7f6ead Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 16 Dec 2022 00:04:18 +0300 Subject: [PATCH 04/40] Updated on 2026-08-14 --- .../tap/domain/configurable/config/ConfigManager.kt | 8 +++++--- .../tap/domain/extensions/WalletManagerFactory.kt | 3 +-- .../products/wallet/saltPay/GnosisRegistrator.kt | 5 ++--- .../products/wallet/saltPay/SaltPayConfig.kt | 12 +++++++++++- buildSrc/src/main/java/Versions.kt | 3 ++- .../com/tangem/domain/common/SaltPayWorkaround.kt | 9 +-------- .../java/com/tangem/domain/common/ScanResponse.kt | 2 +- .../tangem/domain/common/extensions/Blockchain.kt | 4 +--- 8 files changed, 24 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt b/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt index b95d540bf0..5073c369a4 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt @@ -66,12 +66,12 @@ class ConfigManager { config = config.copy( isTopUpEnabled = model.isTopUpEnabled, isSendingToPayIdEnabled = model.isSendingToPayIdEnabled, - isCreatingTwinCardsAllowed = model.isCreatingTwinCardsAllowed + isCreatingTwinCardsAllowed = model.isCreatingTwinCardsAllowed, ) defaultConfig = defaultConfig.copy( isTopUpEnabled = model.isTopUpEnabled, isSendingToPayIdEnabled = model.isSendingToPayIdEnabled, - isCreatingTwinCardsAllowed = model.isCreatingTwinCardsAllowed + isCreatingTwinCardsAllowed = model.isCreatingTwinCardsAllowed, ) } @@ -88,7 +88,8 @@ class ConfigManager { blockchairAuthorizationToken = values.blockchairAuthorizationToken, blockcypherTokens = values.blockcypherTokens, infuraProjectId = values.infuraProjectId, - tronGridApiKey = values.tronGridApiKey + tronGridApiKey = values.tronGridApiKey, + saltPayAuthToken = values.saltPay.credentials.token, ), appsFlyerDevKey = values.appsFlyerDevKey, amplitudeApiKey = values.amplitudeApiKey, @@ -107,6 +108,7 @@ class ConfigManager { blockchairAuthorizationToken = values.blockchairAuthorizationToken, blockcypherTokens = values.blockcypherTokens, infuraProjectId = values.infuraProjectId, + saltPayAuthToken = values.saltPay.credentials.token, ), appsFlyerDevKey = values.appsFlyerDevKey, amplitudeApiKey = values.amplitudeApiKey, diff --git a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt index 874e562a2a..e3c30fa01b 100644 --- a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt +++ b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt @@ -143,8 +143,7 @@ fun WalletManagerFactory.makeSaltPayWalletManager( scanResponse: ScanResponse, ): EthereumWalletManager { val blockchain = scanResponse.getBlockchain() - if (blockchain != Blockchain.SaltPay && blockchain != Blockchain.SaltPayTestnet) - throw IllegalArgumentException() + if (blockchain != Blockchain.SaltPay) throw IllegalArgumentException() val token = SaltPayWorkaround.tokenFrom(blockchain) val cardWallet = scanResponse.card.wallets.firstOrNull().guard { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/GnosisRegistrator.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/GnosisRegistrator.kt index 771fca7d4b..42c54a9395 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/GnosisRegistrator.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/GnosisRegistrator.kt @@ -38,12 +38,11 @@ class GnosisRegistrator( } private val otpProcessorContractAddress: String = when (walletManager.wallet.blockchain) { - Blockchain.SaltPay -> "0x3B4397C817A26521Df8bD01a949AFDE2251d91C2" - Blockchain.SaltPayTestnet -> "0x710BF23486b549836509a08c184cE0188830f197" + Blockchain.SaltPay -> "0xc659f4FEd7A84a188F54cBA4A7a49D77c1a20522" else -> throw IllegalArgumentException("GnosisRegistrator supports only the SaltPay blockchain") } - private val addressTreasureSafe = "0x8e9260a049d3Aa9ac60D0d4F27017320E0e2396B" + private val addressTreasureSafe = "0x24A3c2382497075b6D93258f5938f7B661c06318" private val atomicNonce = AtomicLong() diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayConfig.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayConfig.kt index d853819a57..19048168de 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayConfig.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayConfig.kt @@ -1,6 +1,7 @@ package com.tangem.tap.features.onboarding.products.wallet.saltPay import com.tangem.tap.common.zendesk.ZendeskConfig +import org.spongycastle.util.encoders.Base64.toBase64String /** [REDACTED_AUTHOR] @@ -8,12 +9,14 @@ import com.tangem.tap.common.zendesk.ZendeskConfig data class SaltPayConfig( val zendesk: ZendeskConfig, val kycProvider: KYCProvider, + val credentials: Credentials, ) { companion object { fun stub(): SaltPayConfig { return SaltPayConfig( zendesk = ZendeskConfig("", "", "", "", ""), kycProvider = KYCProvider("", "", "", ""), + credentials = Credentials("", ""), ) } } @@ -24,4 +27,11 @@ data class KYCProvider( val externalIdParameterKey: String, val sidParameterKey: String, val sidValue: String, -) \ No newline at end of file +) + +data class Credentials( + val user: String, + val password: String, +) { + val token: String by lazy { "Basic ${toBase64String("$user:$password".toByteArray())}" } +} \ No newline at end of file diff --git a/buildSrc/src/main/java/Versions.kt b/buildSrc/src/main/java/Versions.kt index e5985c63df..3a15fb0a04 100644 --- a/buildSrc/src/main/java/Versions.kt +++ b/buildSrc/src/main/java/Versions.kt @@ -58,7 +58,8 @@ object Versions { // endregion Other libraries // region Tangem - const val tangemBlockchainSdk = "develop-141" + const val tangemBlockchainSdk = "develop-142" + // const val tangemBlockchainSdk = "0.0.1" const val tangemCardSgk = "develop-173" // endregion Tangem diff --git a/domain/src/main/java/com/tangem/domain/common/SaltPayWorkaround.kt b/domain/src/main/java/com/tangem/domain/common/SaltPayWorkaround.kt index c397160c2d..1328643534 100644 --- a/domain/src/main/java/com/tangem/domain/common/SaltPayWorkaround.kt +++ b/domain/src/main/java/com/tangem/domain/common/SaltPayWorkaround.kt @@ -11,17 +11,10 @@ object SaltPayWorkaround { Blockchain.SaltPay -> Token( name = "WXDAI", symbol = "wxDAI", - contractAddress = "0x4346186e7461cB4DF06bCFCB4cD591423022e417", + contractAddress = "0x4200000000000000000000000000000000000006", decimals = 18, id = "wrapped-xdai", ) - Blockchain.SaltPayTestnet -> Token( - name = "WXDAI Test", - symbol = "MyERC20", - contractAddress = "0x69cca8D8295de046C7c14019D9029Ccc77987A48", - decimals = 0, - id = "wrapped-xdai", - ) else -> throw IllegalArgumentException() } } diff --git a/domain/src/main/java/com/tangem/domain/common/ScanResponse.kt b/domain/src/main/java/com/tangem/domain/common/ScanResponse.kt index ad0538d7a5..01ef016471 100644 --- a/domain/src/main/java/com/tangem/domain/common/ScanResponse.kt +++ b/domain/src/main/java/com/tangem/domain/common/ScanResponse.kt @@ -30,7 +30,7 @@ data class ScanResponse( ) : CommandResponse { fun getBlockchain(): Blockchain { return when (productType) { - ProductType.SaltPay -> if (card.isTestCard) Blockchain.SaltPayTestnet else Blockchain.SaltPay + ProductType.SaltPay -> Blockchain.SaltPay ProductType.Note -> card.getTangemNoteBlockchain() ?: Blockchain.Unknown else -> { val blockchainName: String = walletData?.blockchain ?: return Blockchain.Unknown diff --git a/domain/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt b/domain/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt index 0fde777794..c684dbe3f5 100644 --- a/domain/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt +++ b/domain/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt @@ -48,7 +48,6 @@ fun Blockchain.Companion.fromNetworkId(networkId: String): Blockchain? { "optimistic-ethereum/test" -> Blockchain.OptimismTestnet "dash" -> Blockchain.Dash "sxdai" -> Blockchain.SaltPay - "sxdai/test" -> Blockchain.SaltPayTestnet else -> null } } @@ -101,7 +100,6 @@ fun Blockchain.toNetworkId(): String { Blockchain.OptimismTestnet -> "optimistic-ethereum/test" Blockchain.Dash -> "dash" Blockchain.SaltPay -> "sxdai" - Blockchain.SaltPayTestnet -> "sxdai/test" } } @@ -133,7 +131,7 @@ fun Blockchain.toCoinId(): String { Blockchain.Kusama -> "kusama" Blockchain.Optimism, Blockchain.OptimismTestnet -> "ethereum" Blockchain.Dash -> "dash" - Blockchain.SaltPay, Blockchain.SaltPayTestnet -> "xdai" + Blockchain.SaltPay -> "xdai" Blockchain.Unknown -> "unknown" } } From 7dbfbdd2ac74e2448e5f9b51b0e399e1dbcfa54a Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 11 Jan 2023 08:00:05 +0300 Subject: [PATCH 05/40] Updated on 2026-08-14 --- app/src/main/assets/tangem-app-config | 2 +- .../java/com/tangem/tap/TapApplication.kt | 2 -- .../converters/BasicEventConverter.kt | 2 +- .../filters/ShopPurchasedEventFilter.kt | 25 ------------------- .../appsFlyer/AppsFlyerAnalyticsHandler.kt | 11 ++++++++ .../firebase/FirebaseAnalyticsHandler.kt | 14 ++++++++--- 6 files changed, 24 insertions(+), 32 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index 8453faa078..8ef48dcffb 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit 8453faa078220801858166081947972639f166db +Subproject commit 8ef48dcffbbf6dbe9c1bb565790824e7b1f2061b diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 5074f09e8d..dc85dff25e 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -19,7 +19,6 @@ import com.tangem.tap.common.analytics.AnalyticsFactory import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder import com.tangem.tap.common.analytics.filters.BasicSignInFilter import com.tangem.tap.common.analytics.filters.BasicTopUpFilter -import com.tangem.tap.common.analytics.filters.ShopPurchasedEventFilter 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 @@ -129,7 +128,6 @@ class TapApplication : Application(), ImageLoaderFactory { factory.addHandlerBuilder(AppsFlyerAnalyticsHandler.Builder()) factory.addHandlerBuilder(FirebaseAnalyticsHandler.Builder()) - factory.addFilter(ShopPurchasedEventFilter()) factory.addFilter(BasicSignInFilter()) factory.addFilter(BasicTopUpFilter(preferencesStorage.toppedUpWalletStorage)) 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 index 3950f458bc..02db18e5a8 100644 --- 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 @@ -70,7 +70,7 @@ private fun statesIsReadyToCreateEvent(scanResponse: ScanResponse, state: Wallet if (it.currencyData.amount == null) 0 else 1 }.reduce { acc, i -> acc + i } - if (balancesCount != state.wallets.size) return false + if (balancesCount != state.walletsData.size) return false return true } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt b/app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt deleted file mode 100644 index dffa123240..0000000000 --- a/app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.tangem.tap.common.analytics.filters - -import com.tangem.tap.common.analytics.api.AnalyticsEventFilter -import com.tangem.tap.common.analytics.api.AnalyticsHandler -import com.tangem.tap.common.analytics.events.AnalyticsEvent -import com.tangem.tap.common.analytics.events.Shop -import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerAnalyticsHandler -import com.tangem.tap.common.analytics.handlers.firebase.FirebaseAnalyticsHandler - -/** -[REDACTED_AUTHOR] - */ -class ShopPurchasedEventFilter : AnalyticsEventFilter { - - override fun canBeAppliedTo(event: AnalyticsEvent): Boolean = event is Shop.Purchased - - override fun canBeSent(event: AnalyticsEvent): Boolean = true - - override fun canBeConsumedByHandler(handler: AnalyticsHandler, event: AnalyticsEvent): Boolean { - return when (handler) { - is AppsFlyerAnalyticsHandler, is FirebaseAnalyticsHandler -> true - else -> false - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerAnalyticsHandler.kt index c3968d9d72..80039ad002 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerAnalyticsHandler.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerAnalyticsHandler.kt @@ -1,7 +1,10 @@ package com.tangem.tap.common.analytics.handlers.appsFlyer +import com.appsflyer.AFInAppEventType import com.tangem.tap.common.analytics.api.AnalyticsHandler import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder +import com.tangem.tap.common.analytics.events.AnalyticsEvent +import com.tangem.tap.common.analytics.events.Shop class AppsFlyerAnalyticsHandler( private val client: AppsFlyerAnalyticsClient, @@ -13,6 +16,14 @@ class AppsFlyerAnalyticsHandler( client.logEvent(event, params) } + override fun send(event: AnalyticsEvent) { + if (event is Shop.Purchased) { + send(AFInAppEventType.PURCHASE, event.params) + } else { + super.send(event) + } + } + companion object { const val ID = "AppsFlyer" } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseAnalyticsHandler.kt index 109e61d0a5..bd8bd6d445 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseAnalyticsHandler.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseAnalyticsHandler.kt @@ -1,10 +1,12 @@ package com.tangem.tap.common.analytics.handlers.firebase +import com.google.firebase.analytics.FirebaseAnalytics import com.tangem.tap.common.analytics.api.AnalyticsHandler import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder import com.tangem.tap.common.analytics.api.ErrorEventHandler import com.tangem.tap.common.analytics.converters.AnalyticsErrorConverter import com.tangem.tap.common.analytics.events.AnalyticsEvent +import com.tangem.tap.common.analytics.events.Shop class FirebaseAnalyticsHandler( private val client: FirebaseAnalyticsClient, @@ -17,9 +19,9 @@ class FirebaseAnalyticsHandler( } override fun send(event: AnalyticsEvent) { - when (event.error) { - null -> super.send(event) - else -> { + val error = event.error + when { + error != null -> { val errorConverter = AnalyticsErrorConverter() if (!errorConverter.canBeHandled(event.error)) return @@ -29,6 +31,12 @@ class FirebaseAnalyticsHandler( errorParams.putAll(event.params) send(event.error, errorParams) } + event is Shop.Purchased -> { + send(FirebaseAnalytics.Event.PURCHASE, event.params) + } + else -> { + super.send(event) + } } } From 029e4e1cd8a0aa0b1508adf80fbb42519a0ade52 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 11 Jan 2023 15:07:05 +0400 Subject: [PATCH 06/40] Updated on 2026-08-14 --- .../tap/features/wallet/models/WalletWarning.kt | 7 ++++++- .../tangem/tap/features/wallet/redux/WalletState.kt | 11 ++++++++--- .../tap/features/wallet/ui/WalletWarningConverter.kt | 6 +++++- app/src/main/res/values-de/strings_final.xml | 2 +- app/src/main/res/values-fr/strings_final.xml | 2 +- app/src/main/res/values-it/strings_final.xml | 2 +- app/src/main/res/values-ru/strings_final.xml | 2 +- app/src/main/res/values/strings_final.xml | 2 +- 8 files changed, 24 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/models/WalletWarning.kt b/app/src/main/java/com/tangem/tap/features/wallet/models/WalletWarning.kt index 3b80a95845..3e960b5123 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/models/WalletWarning.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/models/WalletWarning.kt @@ -9,7 +9,12 @@ sealed class WalletWarning( ) : WalletWarning(1) object TransactionInProgress : WalletWarning(10) - data class BalanceNotEnoughForFee(val blockchainFullName: String) : WalletWarning(30) + data class BalanceNotEnoughForFee( + val tokenName: String, + val blockchainFullName: String, + val blockchainCurrencyName: String, + ) : WalletWarning(30) + data class Rent(val walletRent: WalletRent) : WalletWarning(40) } 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 6219fea552..2973700363 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 @@ -370,11 +370,16 @@ data class WalletData( } private fun assembleTokenWarnings(walletWarnings: MutableList){ - if (!currency.isToken()) return + if (currency !is Currency.Token) return - val blockchainFullName = currency.blockchain.fullName if ((blockchainAmountIsEmpty() && !tokenAmountIsEmpty())) { - walletWarnings.add(WalletWarning.BalanceNotEnoughForFee(blockchainFullName)) + walletWarnings.add( + WalletWarning.BalanceNotEnoughForFee( + tokenName = currency.token.name, + blockchainFullName = currency.blockchain.fullName, + blockchainCurrencyName = currency.blockchain.currency, + ), + ) } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletWarningConverter.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletWarningConverter.kt index 624d34da3e..321d88db1c 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletWarningConverter.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletWarningConverter.kt @@ -24,7 +24,11 @@ class WalletWarningConverter( is WalletWarning.BalanceNotEnoughForFee -> { context.getString( R.string.token_details_send_blocked_fee_format, - message.blockchainFullName, message.blockchainFullName, + message.tokenName, + message.blockchainFullName, + message.tokenName, + message.blockchainFullName, + message.blockchainCurrencyName, ) } WalletWarning.TransactionInProgress -> { diff --git a/app/src/main/res/values-de/strings_final.xml b/app/src/main/res/values-de/strings_final.xml index b7e64d53df..4a635afd9a 100644 --- a/app/src/main/res/values-de/strings_final.xml +++ b/app/src/main/res/values-de/strings_final.xml @@ -37,7 +37,7 @@ Search tokens You are currently running in Demo mode. All funds are not real. This feature is disabled in Demo mode - Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first. + %s is a token in the %s network. To make a %s transaction you need to deposit some %s (%s) to cover the network fee. Available networks Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds. Tokens in Solana network are not supported by this card due to firmware limitation. diff --git a/app/src/main/res/values-fr/strings_final.xml b/app/src/main/res/values-fr/strings_final.xml index b7e64d53df..4a635afd9a 100644 --- a/app/src/main/res/values-fr/strings_final.xml +++ b/app/src/main/res/values-fr/strings_final.xml @@ -37,7 +37,7 @@ Search tokens You are currently running in Demo mode. All funds are not real. This feature is disabled in Demo mode - Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first. + %s is a token in the %s network. To make a %s transaction you need to deposit some %s (%s) to cover the network fee. Available networks Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds. Tokens in Solana network are not supported by this card due to firmware limitation. diff --git a/app/src/main/res/values-it/strings_final.xml b/app/src/main/res/values-it/strings_final.xml index b7e64d53df..4a635afd9a 100644 --- a/app/src/main/res/values-it/strings_final.xml +++ b/app/src/main/res/values-it/strings_final.xml @@ -37,7 +37,7 @@ Search tokens You are currently running in Demo mode. All funds are not real. This feature is disabled in Demo mode - Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first. + %s is a token in the %s network. To make a %s transaction you need to deposit some %s (%s) to cover the network fee. Available networks Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds. Tokens in Solana network are not supported by this card due to firmware limitation. diff --git a/app/src/main/res/values-ru/strings_final.xml b/app/src/main/res/values-ru/strings_final.xml index ad4f23ca35..21c250d6c4 100644 --- a/app/src/main/res/values-ru/strings_final.xml +++ b/app/src/main/res/values-ru/strings_final.xml @@ -37,7 +37,7 @@ Поиск токенов Приложение работает в демонстрационном режиме. Средства на всех счетах ненастоящие. Эта функция недоступна в демонстрационном режиме - Недостаточно средств для комиссии на вашем %s кошельке для отправки транзакции. Сначала пополните свой %s кошелек. + %s — это токен в сети %s. Чтобы отправить транзакцию %s, необходимо пополнить баланс %s (%s) для оплаты комиссии сети. Доступные сети Внимание! Валюты на разных сетях имеют разные адреса. Убедитесь, что адрес соответствует сети, в которой вы отправляете средства. Токены в сети Solana не поддерживаются этой картой из-за ограничений прошивки. diff --git a/app/src/main/res/values/strings_final.xml b/app/src/main/res/values/strings_final.xml index 70e85346c6..4a8c50e734 100644 --- a/app/src/main/res/values/strings_final.xml +++ b/app/src/main/res/values/strings_final.xml @@ -37,7 +37,7 @@ Search tokens You are currently running in Demo mode. All funds are not real. This feature is disabled in Demo mode - Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first. + %s is a token in the %s network. To make a %s transaction you need to deposit some %s (%s) to cover the network fee. Available networks Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds. Tokens in Solana network are not supported by this card due to firmware limitation. From 629eae99d535c5c7b057b9c494c630bc8565aeef Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 11 Jan 2023 14:57:29 +0300 Subject: [PATCH 07/40] Updated on 2026-08-14 --- app/src/main/assets/tangem-app-config | 2 +- .../tangem/tap/domain/configurable/config/ConfigManager.kt | 4 ++-- .../tangem/tap/domain/configurable/config/JsonModels.kt | 7 ++++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index 8ef48dcffb..93150ef69d 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit 8ef48dcffbbf6dbe9c1bb565790824e7b1f2061b +Subproject commit 93150ef69daf244a92266d7cdfbc9294b745b4e2 diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt b/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt index 12e3d14a80..67b78dff14 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt @@ -102,7 +102,7 @@ class ConfigManager { infuraProjectId = values.infuraProjectId, tronGridApiKey = values.tronGridApiKey, ), - appsFlyerDevKey = values.appsFlyerDevKey, + appsFlyerDevKey = values.appsFlyer.appsFlyerDevKey, amplitudeApiKey = values.amplitudeApiKey, shopify = values.shopifyShop, zendesk = values.zendesk, @@ -130,7 +130,7 @@ class ConfigManager { ), infuraProjectId = values.infuraProjectId, ), - appsFlyerDevKey = values.appsFlyerDevKey, + appsFlyerDevKey = values.appsFlyer.appsFlyerDevKey, amplitudeApiKey = values.amplitudeApiKey, shopify = values.shopifyShop, zendesk = values.zendesk, diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/config/JsonModels.kt b/app/src/main/java/com/tangem/tap/domain/configurable/config/JsonModels.kt index 1966ac9303..77a1f0d6cc 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/config/JsonModels.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/config/JsonModels.kt @@ -29,7 +29,7 @@ class ConfigValueModel( val bscQuiknodeApiKey: String, val blockcypherTokens: Set?, val infuraProjectId: String?, - val appsFlyerDevKey: String, + val appsFlyer: AppsFlyer, val shopifyShop: ShopifyShop?, val zendesk: ZendeskConfig?, val saltPay: SaltPayConfig, @@ -37,6 +37,11 @@ class ConfigValueModel( val amplitudeApiKey: String, ) +data class AppsFlyer( + val appsFlyerDevKey: String, + val appsFlyerAppID: String, +) + class ConfigModel( val features: FeatureModel?, val configValues: ConfigValueModel?, From 7c84005df348e716cf136bafbb56813e2194a093 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 13 Jan 2023 15:42:41 +0300 Subject: [PATCH 08/40] Updated on 2026-08-14 --- .../tap/common/analytics/events/Onboarding.kt | 1 + .../tangem/tap/common/analytics/events/Shop.kt | 6 +++--- .../tangem/tap/common/feedback/FeedbackManager.kt | 2 ++ .../features/details/redux/DetailsMiddleware.kt | 6 ++++-- .../details/ui/details/DetailsScreenState.kt | 6 +++--- .../tap/features/home/redux/HomeMiddleware.kt | 2 ++ .../features/onboarding/OnboardingMenuProvider.kt | 3 +++ .../products/twins/redux/TwinCardsMiddleware.kt | 15 +++++++++------ .../tap/features/shop/redux/ShopMiddleware.kt | 3 +++ .../tangem/tap/features/shop/ui/ShopFragment.kt | 3 --- .../tap/features/tokens/ui/AddTokensFragment.kt | 1 - .../wallet/redux/middlewares/WalletMiddleware.kt | 4 ++++ .../features/wallet/ui/wallet/MultiWalletView.kt | 3 +++ 13 files changed, 37 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Onboarding.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Onboarding.kt index 5634c25afa..6d5e5f44f1 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Onboarding.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Onboarding.kt @@ -73,4 +73,5 @@ sealed class Onboarding( class ClaimScreenOpened : Onboarding("Onboarding", "Claim screen opened") class ButtonClaim : Onboarding("Onboarding", "Button - Claim") class ClaimWasSuccessfully : Onboarding("Onboarding", "Claim was successfully") + class ButtonChat: Onboarding("Onboarding", "Button - Chat") } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Shop.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Shop.kt index 9634f2929b..f2cb5268c1 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Shop.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Shop.kt @@ -10,7 +10,7 @@ sealed class Shop( params: Map = mapOf(), ) : AnalyticsEvent("Shop", event, params) { - class ScreenOpened : IntroductionProcess("Shop Screen Opened") + class ScreenOpened : Shop("Shop Screen Opened") class Purchased(sku: String, count: String, amount: String, couponCode: String?) : Shop( event = "Purchased", @@ -22,8 +22,8 @@ sealed class Shop( ).filterNotNull(), ) - class Redirected(partnerName: String) : Shop( + class Redirected(partnerName: String?) : Shop( event = "Redirected", - params = mapOf("Partner" to partnerName), + params = partnerName?.let { mapOf("Partner" to partnerName) } ?: mapOf(), ) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/feedback/FeedbackManager.kt b/app/src/main/java/com/tangem/tap/common/feedback/FeedbackManager.kt index 12fe1e42e9..3ee976483c 100644 --- a/app/src/main/java/com/tangem/tap/common/feedback/FeedbackManager.kt +++ b/app/src/main/java/com/tangem/tap/common/feedback/FeedbackManager.kt @@ -3,6 +3,7 @@ package com.tangem.tap.common.feedback import android.content.Context import android.os.Build import com.tangem.domain.common.TapWorkarounds +import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.extensions.sendEmail import com.tangem.tap.common.log.TangemLogCollector import com.tangem.tap.common.zendesk.ZendeskConfig @@ -108,6 +109,7 @@ class FeedbackManager( } private fun showMessagingActivity(context: Context) { + Analytics.send(com.tangem.tap.common.analytics.events.Chat.ScreenOpened()) MessagingActivity.builder() .withMultilineResponseOptionsEnabled(false) .withBotLabelStringRes(R.string.chat_bot_name) diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index b316098ff4..e3fc84b294 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -126,7 +126,8 @@ class DetailsMiddleware { store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Home)) } is CompletionResult.Failure -> { - (result.error as? TangemSdkError)?.let { error -> + val error = result.error + if (error is TangemSdkError && error !is TangemSdkError.UserCancelled) { Analytics.send(Settings.CardSettings.FactoryResetFinished(error)) } } @@ -166,7 +167,8 @@ class DetailsMiddleware { store.dispatch(DetailsAction.ManageSecurity.SaveChanges.Success) } is CompletionResult.Failure -> { - (result.error as? TangemSdkError)?.let { error -> + val error = result.error + if (error is TangemSdkError && error !is TangemSdkError.UserCancelled) { Analytics.send(Settings.CardSettings.SecurityModeChanged(paramValue, error)) } store.dispatch(DetailsAction.ManageSecurity.SaveChanges.Failure) diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt index a92efc7e2b..ac1ae7916e 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt @@ -41,7 +41,7 @@ sealed class SocialNetwork(val id: String, val iconRes: Int) { object Facebook : SocialNetwork("Facebook", R.drawable.ic_facebook) object Instagram : SocialNetwork("Instagram", R.drawable.ic_instagram) object GitHub : SocialNetwork("GitHub", R.drawable.ic_github) - object Youtube : SocialNetwork("Youtube", R.drawable.ic_youtube) + object YouTube : SocialNetwork("YouTube", R.drawable.ic_youtube) object LinkedIn : SocialNetwork("LinkedIn", R.drawable.ic_linkedin) } @@ -52,7 +52,7 @@ object TangemSocialAccounts { SocialNetworkLink(SocialNetwork.Facebook, "https://m.facebook.com/TangemCards/"), SocialNetworkLink(SocialNetwork.Instagram, "https://instagram.com/tangemcards"), SocialNetworkLink(SocialNetwork.GitHub, "https://github.com/tangem"), - SocialNetworkLink(SocialNetwork.Youtube, "https://youtube.com/channel/UCFGwLS7yggzVkP6ozte0m1w"), + SocialNetworkLink(SocialNetwork.YouTube, "https://youtube.com/channel/UCFGwLS7yggzVkP6ozte0m1w"), SocialNetworkLink(SocialNetwork.LinkedIn, "https://www.linkedin.com/company/tangem"), ) val accountsRu: List = listOf( @@ -61,7 +61,7 @@ object TangemSocialAccounts { SocialNetworkLink(SocialNetwork.Facebook, "https://m.facebook.com/TangemCards/"), SocialNetworkLink(SocialNetwork.Instagram, "https://instagram.com/tangemcards"), SocialNetworkLink(SocialNetwork.GitHub, "https://github.com/tangem"), - SocialNetworkLink(SocialNetwork.Youtube, "https://youtube.com/channel/UCFGwLS7yggzVkP6ozte0m1w"), + SocialNetworkLink(SocialNetwork.YouTube, "https://youtube.com/channel/UCFGwLS7yggzVkP6ozte0m1w"), SocialNetworkLink(SocialNetwork.LinkedIn, "https://www.linkedin.com/company/tangem"), ) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt index c3c0145ec8..37a1da2c8b 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt @@ -11,6 +11,7 @@ import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE import com.tangem.tap.backupService import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.events.IntroductionProcess +import com.tangem.tap.common.analytics.events.Shop import com.tangem.tap.common.analytics.paramsInterceptor.BatchIdParamsInterceptor import com.tangem.tap.common.entities.IndeterminateProgressButton import com.tangem.tap.common.extensions.dispatchDialogShow @@ -100,6 +101,7 @@ private fun handleHomeAction(appState: () -> AppState?, action: Action, dispatch postUiDelayBg(300) { store.dispatch(scanCardAction) } } is HomeAction.GoToShop -> { + Analytics.send(Shop.ScreenOpened()) when (action.userCountryCode) { RUSSIA_COUNTRY_CODE, BELARUS_COUNTRY_CODE -> store.dispatchOpenUrl(BUY_WALLET_URL) else -> store.dispatch(NavigationAction.NavigateTo(AppScreen.Shop)) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt index 2fff1d0fab..7c816d9210 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt @@ -4,6 +4,8 @@ import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import androidx.core.view.MenuProvider +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.feedback.SupportInfo import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.store @@ -19,6 +21,7 @@ class OnboardingMenuProvider : MenuProvider { override fun onMenuItemSelected(menuItem: MenuItem): Boolean = when (menuItem.itemId) { R.id.menu_item_chat_support -> { + Analytics.send(Onboarding.ButtonChat()) store.dispatch(GlobalAction.OpenChat(SupportInfo())) true } 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 aa6de330d6..cfb3159305 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 @@ -101,10 +101,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) { CreateTwinWalletMode.CreateWallet -> { if (preferencesStorage.wasTwinsOnboardingShown()) { val step = when { - !scanResponse.twinsIsTwinned() -> { - Analytics.send(Onboarding.CreateWallet.ScreenOpened()) - TwinCardsStep.CreateFirstWallet - } + !scanResponse.twinsIsTwinned() -> TwinCardsStep.CreateFirstWallet twinCardsState.walletBalance.balanceIsToppedUp() -> TwinCardsStep.Done else -> TwinCardsStep.TopUpWallet } @@ -145,7 +142,14 @@ private fun handle(action: Action, dispatch: DispatchFunction) { Analytics.send(Onboarding.Twins.ScreenOpened()) preferencesStorage.saveTwinsOnboardingShown() } - TwinCardsStep.TopUpWallet -> store.dispatch(TwinCardsAction.Balance.Update) + TwinCardsStep.CreateFirstWallet -> { + Analytics.send(Onboarding.CreateWallet.ScreenOpened()) + Analytics.send(Onboarding.Twins.SetupStarted()) + } + TwinCardsStep.TopUpWallet -> { + Analytics.send(Onboarding.Topup.ScreenOpened()) + store.dispatch(TwinCardsAction.Balance.Update) + } TwinCardsStep.Done -> { finishCardActivation() postUi(500) { store.dispatch(TwinCardsAction.Confetti.Show) } @@ -153,7 +157,6 @@ private fun handle(action: Action, dispatch: DispatchFunction) { } } is TwinCardsAction.Wallet.LaunchFirstStep -> { - Analytics.send(Onboarding.Twins.SetupStarted()) val manager = TwinCardsManager( card = getScanResponse().card, assetReader = action.reader, diff --git a/app/src/main/java/com/tangem/tap/features/shop/redux/ShopMiddleware.kt b/app/src/main/java/com/tangem/tap/features/shop/redux/ShopMiddleware.kt index f7f126c05f..5c5a9d72b9 100644 --- a/app/src/main/java/com/tangem/tap/features/shop/redux/ShopMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/shop/redux/ShopMiddleware.kt @@ -1,5 +1,7 @@ package com.tangem.tap.features.shop.redux +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Shop import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.dispatchOpenUrl import com.tangem.tap.common.redux.AppState @@ -113,6 +115,7 @@ private fun handle(action: Action) { } } ShopAction.StartWebCheckout -> { + Analytics.send(Shop.Redirected(null)) store.dispatchOpenUrl(shopService.getCheckoutUrl(shopState.selectedProduct)) store.dispatch(ShopAction.FinishSuccessfulOrder) } diff --git a/app/src/main/java/com/tangem/tap/features/shop/ui/ShopFragment.kt b/app/src/main/java/com/tangem/tap/features/shop/ui/ShopFragment.kt index 338561267b..622f440a18 100644 --- a/app/src/main/java/com/tangem/tap/features/shop/ui/ShopFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/shop/ui/ShopFragment.kt @@ -12,8 +12,6 @@ import androidx.activity.OnBackPressedCallback import by.kirich1409.viewbindingdelegate.viewBinding import com.tangem.tap.common.GlobalLayoutStateHandler import com.tangem.tap.common.KeyboardObserver -import com.tangem.tap.common.analytics.Analytics -import com.tangem.tap.common.analytics.events.Shop import com.tangem.tap.common.extensions.show import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.common.shop.data.ProductType @@ -43,7 +41,6 @@ class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSubscriber< override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - Analytics.send(Shop.ScreenOpened()) activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/AddTokensFragment.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/AddTokensFragment.kt index 36b1f82337..1c8ffe8305 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/AddTokensFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/ui/AddTokensFragment.kt @@ -50,7 +50,6 @@ class AddTokensFragment : Fragment(R.layout.fragment_add_tokens), override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) - Analytics.send(ManageTokens.ScreenOpened()) activity?.onBackPressedDispatcher?.addCallback( this, 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 5e245d4038..0210359cfd 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 @@ -12,6 +12,7 @@ import com.tangem.domain.common.extensions.withMainContext import com.tangem.operations.attestation.Attestation import com.tangem.operations.attestation.OnlineCardVerifier import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.copyToClipboard import com.tangem.tap.common.extensions.dispatchDebugErrorNotification @@ -261,6 +262,9 @@ class WalletMiddleware { } else { store.dispatch(newAction) if (newAction is PrepareSendScreen) { + store.state.walletState.getSelectedWalletData()?.currency?.let { currency -> + Analytics.send(Token.ButtonSend(AnalyticsParam.CurrencyType.Currency(currency))) + } store.dispatch(NavigationAction.NavigateTo(AppScreen.Send)) } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt index d4172e31ef..f9cb956296 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt @@ -8,6 +8,7 @@ import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.events.MainScreen +import com.tangem.tap.common.analytics.events.ManageTokens import com.tangem.tap.common.analytics.events.Portfolio import com.tangem.tap.common.extensions.animateVisibility import com.tangem.tap.common.extensions.formatAmountAsSpannedString @@ -105,6 +106,8 @@ class MultiWalletView : WalletView() { derivationStyle = card.derivationStyle, ), ) + + Analytics.send(ManageTokens.ScreenOpened()) store.dispatch(NavigationAction.NavigateTo(AppScreen.AddTokens)) } handleErrorStates(state = state, binding = binding, fragment = fragment) From f436569bd33441687b7d41af6bd8edc6ff74df90 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 17 Jan 2023 16:49:22 +0300 Subject: [PATCH 09/40] Updated on 2026-08-14 --- app/src/debug/res/values-ru/strings.xml | 2 +- app/src/debug/res/values/strings.xml | 2 +- app/src/debug_beta/res/values-ru/strings.xml | 2 +- app/src/debug_beta/res/values/strings.xml | 2 +- app/src/main/AndroidManifest.xml | 2 +- .../tap/features/details/ui/details/DetailsScreenState.kt | 2 +- app/src/tangemAccess/res/values/strings.xml | 2 +- core/res/src/main/res/values-de/strings.xml | 2 +- core/res/src/main/res/values-fr/strings.xml | 2 +- core/res/src/main/res/values-it/strings.xml | 2 +- core/res/src/main/res/values-ru/strings.xml | 2 +- core/res/src/main/res/values/strings.xml | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/src/debug/res/values-ru/strings.xml b/app/src/debug/res/values-ru/strings.xml index 1abc31ee12..682b552975 100644 --- a/app/src/debug/res/values-ru/strings.xml +++ b/app/src/debug/res/values-ru/strings.xml @@ -1,6 +1,6 @@ - DebugTangem + DebugTangem \ No newline at end of file diff --git a/app/src/debug/res/values/strings.xml b/app/src/debug/res/values/strings.xml index bf9ef4d842..764dd201cc 100644 --- a/app/src/debug/res/values/strings.xml +++ b/app/src/debug/res/values/strings.xml @@ -1,6 +1,6 @@ - DebugTangem + DebugTangem \ No newline at end of file diff --git a/app/src/debug_beta/res/values-ru/strings.xml b/app/src/debug_beta/res/values-ru/strings.xml index 3e2d147b31..3ae149049f 100644 --- a/app/src/debug_beta/res/values-ru/strings.xml +++ b/app/src/debug_beta/res/values-ru/strings.xml @@ -1,6 +1,6 @@ - BetaTangem + BetaTangem \ No newline at end of file diff --git a/app/src/debug_beta/res/values/strings.xml b/app/src/debug_beta/res/values/strings.xml index 3e2d147b31..3ae149049f 100644 --- a/app/src/debug_beta/res/values/strings.xml +++ b/app/src/debug_beta/res/values/strings.xml @@ -1,6 +1,6 @@ - BetaTangem + BetaTangem \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e7d11764b4..f09883d42e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -29,7 +29,7 @@ Unit, val onSocialNetworkClick: (SocialNetworkLink) -> Unit, ) { - val appNameRes: Int = R.string.app_name + val appNameRes: Int = R.string.tangem_app_name } @Immutable diff --git a/app/src/tangemAccess/res/values/strings.xml b/app/src/tangemAccess/res/values/strings.xml index 1f911a6e51..845dc9021a 100644 --- a/app/src/tangemAccess/res/values/strings.xml +++ b/app/src/tangemAccess/res/values/strings.xml @@ -1,6 +1,6 @@ - Tangem + Tangem \ No newline at end of file diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index 82a3dd2859..8eff587ac8 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -218,7 +218,7 @@ %d selected biometric authentication biometrics - Tangem + Tangem Änderungen speichern Warnung Erledigt diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index 61aac3f965..f3004f001d 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -218,7 +218,7 @@ %d selected biometric authentication biometrics - Tangem + Tangem Sauvegarder les modifications Alerte Exécuté diff --git a/core/res/src/main/res/values-it/strings.xml b/core/res/src/main/res/values-it/strings.xml index d766d3879f..d3906dabb8 100644 --- a/core/res/src/main/res/values-it/strings.xml +++ b/core/res/src/main/res/values-it/strings.xml @@ -218,7 +218,7 @@ %d selected biometric authentication biometrics - Tangem + Tangem Mantieni le modifiche Avviso Fatto diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 2356e45af1..3ecb8d910d 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -218,7 +218,7 @@ %d выбрано биометрическую аутентификацию биометрией - Tangem + Tangem Сохранить изменения Предупреждение Готово diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index afed5beb51..091568c2f0 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -218,7 +218,7 @@ %d selected biometric authentication biometrics - Tangem + Tangem Save changes Warning Done From 5a6594aee04ad9e6926abd304acafb3c9f8e209e Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 19 Jan 2023 12:51:42 +0300 Subject: [PATCH 10/40] Updated on 2026-08-14 --- .../java/com/tangem/tap/common/analytics/events/Settings.kt | 1 + .../com/tangem/tap/common/analytics/events/WalletConnect.kt | 1 + .../tangem/tap/features/details/ui/details/DetailsViewModel.kt | 1 + .../features/details/ui/walletconnect/WalletConnectFragment.kt | 3 +++ .../tap/features/wallet/redux/middlewares/WalletMiddleware.kt | 2 ++ 5 files changed, 8 insertions(+) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt index 38725048a7..6f1834839a 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt @@ -20,6 +20,7 @@ sealed class Settings( class ButtonCardSettings : Settings(event = "Button - Card Settings") class ButtonAppSettings : Settings(event = "Button - App Settings") class ButtonCreateBackup : Settings(event = "Button - Create Backup") + class ButtonWalletConnect : Settings(event = "Button - Wallet Connect") class ButtonSocialNetwork(network: SocialNetwork) : Settings( event = "Button - Social Network", diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt index 1ff587b2aa..1c406f24b1 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt @@ -9,6 +9,7 @@ sealed class WalletConnect( error: Throwable? = null, ) : AnalyticsEvent("Wallet Connect", event, params, error) { + class ScreenOpened : Settings(event = "WC Screen Opened") class NewSessionEstablished : WalletConnect("New Session Established") class SessionDisconnected : WalletConnect("Session Disconnected") class RequestSigned : WalletConnect("Request Signed") diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt index c48aeab31d..5645d3c90f 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt @@ -61,6 +61,7 @@ class DetailsViewModel(private val store: Store) { private fun handleClickingSettingsItem(item: SettingsElement) { when (item) { SettingsElement.WalletConnect -> { + Analytics.send(Settings.ButtonWalletConnect()) store.dispatch(NavigationAction.NavigateTo(AppScreen.WalletConnectSessions)) } SettingsElement.Chat -> { diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectFragment.kt index 8d3de292ae..f642f91320 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectFragment.kt @@ -10,6 +10,8 @@ import androidx.compose.ui.platform.ComposeView import androidx.fragment.app.Fragment import androidx.transition.TransitionInflater import com.google.accompanist.appcompattheme.AppCompatTheme +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.WalletConnect import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction import com.tangem.tap.features.details.redux.walletconnect.WalletConnectState @@ -23,6 +25,7 @@ class WalletConnectFragment : Fragment(), StoreSubscriber { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + Analytics.send(WalletConnect.ScreenOpened()) val inflater = TransitionInflater.from(requireContext()) enterTransition = inflater.inflateTransition(android.R.transition.fade) exitTransition = inflater.inflateTransition(android.R.transition.fade) 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 0210359cfd..dca805579a 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 @@ -237,10 +237,12 @@ class WalletMiddleware { } } is WalletAction.CopyAddress -> { + Analytics.send(Token.Recieve.ButtonCopyAddress()) action.context.copyToClipboard(action.address) store.dispatch(WalletAction.CopyAddress.Success) } is WalletAction.ShareAddress -> { + Analytics.send(Token.Recieve.ButtonShareAddress()) action.context.shareText(action.address) } is WalletAction.ExploreAddress -> { From 03c10dac668dfd1a2ced010c6ced8d9678729333 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 16 Jan 2023 22:05:39 +0300 Subject: [PATCH 11/40] Updated on 2026-08-14 --- .../converters/ShopOrderToEventConverter.kt | 12 +++++----- .../tap/common/shop/TangemShopService.kt | 4 ++-- .../note/redux/OnboardingNoteMiddleware.kt | 12 +++++----- .../twins/redux/TwinCardsMiddleware.kt | 23 +++++++++++++++---- .../middlewares/TradeCryptoMiddleware.kt | 9 ++++---- .../wallet/redux/models/WalletDialog.kt | 3 +-- ...sianCardholdersWarningBottomSheetDialog.kt | 4 ---- 7 files changed, 39 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/ShopOrderToEventConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/ShopOrderToEventConverter.kt index ddbd1683bd..49f6762db9 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/converters/ShopOrderToEventConverter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/ShopOrderToEventConverter.kt @@ -8,19 +8,19 @@ import com.tangem.tap.common.shop.data.ProductType /** [REDACTED_AUTHOR] */ -class ShopOrderToEventConverter : Converter, Shop.Purchased> { +class ShopOrderToEventConverter : Converter, Shop.Purchased> { - override fun convert(value: Pair): Shop.Purchased { - val order = value.first + override fun convert(value: Pair): Shop.Purchased { + val checkout = value.first val productType = value.second - val sku = order.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: productType.sku + val sku = checkout.lineItems?.edges?.firstOrNull()?.node?.variant?.sku ?: productType.sku val count = when (productType) { ProductType.WALLET_2_CARDS -> "2" ProductType.WALLET_3_CARDS -> "3" } - val amount = "${order.totalPriceV2.amount} ${order.totalPriceV2.currencyCode.name}" - val code = (order.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code + val amount = "${checkout.totalPriceV2.amount} ${checkout.totalPriceV2.currencyCode.name}" + val code = (checkout.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code return Shop.Purchased(sku, count, amount, code) } diff --git a/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt b/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt index 808cb5bbbc..848ef979a6 100644 --- a/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt +++ b/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt @@ -200,8 +200,8 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) { suspend fun waitForCheckout(productType: ProductType) { val result = shopifyService.checkout(true, checkouts[productType]!!.id) result.onSuccess { checkout -> - checkout.order?.let { - val event = ShopOrderToEventConverter().convert(it to productType) + if (checkout.order != null && checkout.lineItems != null) { + val event = ShopOrderToEventConverter().convert(checkout to productType) Analytics.send(event) } } 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 5ecccaa431..fe20b14405 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 @@ -178,16 +178,16 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch val topUpUrl = walletManager.getTopUpUrl() ?: return val blockchain = walletManager.wallet.blockchain - if (globalState.userCountryCode == RUSSIA_COUNTRY_CODE) { - val dialogData = WalletDialog.RussianCardholdersWarningDialog.Data(topUpUrl, blockchain) - store.dispatchOnMain(WalletAction.DialogAction.RussianCardholdersWarningDialog(dialogData)) - return - } val currencyType = AnalyticsParam.CurrencyType.Blockchain(blockchain) Analytics.send(Onboarding.Topup.ButtonBuyCrypto(currencyType)) - store.dispatchOpenUrl(topUpUrl) + if (globalState.userCountryCode == RUSSIA_COUNTRY_CODE) { + val dialogData = WalletDialog.RussianCardholdersWarningDialog.Data(topUpUrl) + store.dispatchOnMain(WalletAction.DialogAction.RussianCardholdersWarningDialog(dialogData)) + } else { + store.dispatchOpenUrl(topUpUrl) + } } OnboardingNoteAction.Done -> { store.dispatch(GlobalAction.Onboarding.Stop) 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 cfb3159305..b4967c1f39 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 @@ -1,6 +1,5 @@ package com.tangem.tap.features.onboarding.products.twins.redux -import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.extensions.Result import com.tangem.common.CompletionResult import com.tangem.common.extensions.guard @@ -10,8 +9,10 @@ import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Onboarding +import com.tangem.tap.common.extensions.dispatchDebugErrorNotification 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.dispatchOpenUrl import com.tangem.tap.common.extensions.getAddressData import com.tangem.tap.common.extensions.getTopUpUrl @@ -25,8 +26,11 @@ import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.TapError import com.tangem.tap.domain.extensions.makePrimaryWalletManager import com.tangem.tap.domain.twins.TwinCardsManager +import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE 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.scope import com.tangem.tap.store @@ -277,12 +281,23 @@ private fun handle(action: Action, dispatch: DispatchFunction) { store.dispatchDialogShow(appDialog) } is TwinCardsAction.TopUp -> { - val topUpUrl = twinCardsState.walletManager?.getTopUpUrl() ?: return + val walletManager = twinCardsState.walletManager.guard { + store.dispatchDebugErrorNotification("NPE: WalletManager") + return + } - val currencyType = AnalyticsParam.CurrencyType.Blockchain(Blockchain.Bitcoin) + val topUpUrl = walletManager.getTopUpUrl() ?: return + val blockchain = walletManager.wallet.blockchain + + val currencyType = AnalyticsParam.CurrencyType.Blockchain(blockchain) Analytics.send(Onboarding.Topup.ButtonBuyCrypto(currencyType)) - store.dispatchOpenUrl(topUpUrl) + if (globalState.userCountryCode == RUSSIA_COUNTRY_CODE) { + val dialogData = WalletDialog.RussianCardholdersWarningDialog.Data(topUpUrl) + store.dispatchOnMain(WalletAction.DialogAction.RussianCardholdersWarningDialog(dialogData)) + } else { + store.dispatchOpenUrl(topUpUrl) + } } TwinCardsAction.Done -> { scope.launch { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt index 5d6a9fc2d7..7134d73f7d 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt @@ -39,21 +39,22 @@ class TradeCryptoMiddleware { state: () -> AppState?, action: WalletAction.TradeCryptoAction.Buy, ) { + val selectedWalletData = store.state.walletState.getSelectedWalletData() ?: return + + val currency = selectedWalletData.currency + Analytics.send(Token.ButtonBuy(AnalyticsParam.CurrencyType.Currency(currency))) + if (action.checkUserLocation && state()?.globalState?.userCountryCode == RUSSIA_COUNTRY_CODE) { store.dispatchOnMain(WalletAction.DialogAction.RussianCardholdersWarningDialog()) return } - val selectedWalletData = store.state.walletState.getSelectedWalletData() ?: return val card = store.state.globalState.scanResponse?.card ?: return - val addresses = selectedWalletData.walletAddresses?.list.orEmpty() if (addresses.isEmpty()) return val exchangeManager = store.state.globalState.exchangeManager val appCurrency = store.state.globalState.appCurrency - val currency = selectedWalletData.currency - Analytics.send(Token.ButtonBuy(AnalyticsParam.CurrencyType.Currency(currency))) if (currency is Currency.Token && currency.blockchain.isTestnet()) { val walletManager = store.state.walletState.getWalletManager(currency) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/models/WalletDialog.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/models/WalletDialog.kt index fc182e2c4f..6e809d677e 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/models/WalletDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/models/WalletDialog.kt @@ -1,7 +1,6 @@ package com.tangem.tap.features.wallet.redux.models import com.tangem.blockchain.common.Amount -import com.tangem.blockchain.common.Blockchain import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.redux.StateDialog import com.tangem.wallet.R @@ -33,6 +32,6 @@ sealed interface WalletDialog : StateDialog { } data class RussianCardholdersWarningDialog(val data: Data?) : WalletDialog { - data class Data(val topUpUrl: String, val blockchain: Blockchain) + data class Data(val topUpUrl: String) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt index b8022e2724..5d65240001 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt @@ -5,8 +5,6 @@ import android.os.Bundle import android.view.LayoutInflater import com.google.android.material.bottomsheet.BottomSheetDialog import com.tangem.tap.common.analytics.Analytics -import com.tangem.tap.common.analytics.events.AnalyticsParam -import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.dispatchDialogHide import com.tangem.tap.common.extensions.dispatchOpenUrl @@ -41,8 +39,6 @@ class RussianCardholdersWarningBottomSheetDialog( binding?.btnYes?.setOnClickListener { if (dialogData != null) { - val currencyType = AnalyticsParam.CurrencyType.Blockchain(dialogData.blockchain) - Analytics.send(Onboarding.Topup.ButtonBuyCrypto(currencyType)) store.dispatchOpenUrl(dialogData.topUpUrl) } else { store.dispatch(WalletAction.TradeCryptoAction.Buy(checkUserLocation = false)) From 223858d6e64a4f174aaef321b1aa26798b18b5a2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 19 Jan 2023 16:45:59 +0300 Subject: [PATCH 12/40] Updated on 2026-08-14 --- .../java/com/tangem/tap/common/IntentHandler.kt | 2 +- .../com/tangem/tap/features/home/HomeFragment.kt | 2 +- .../tangem/tap/features/home/redux/HomeAction.kt | 6 +++++- .../tap/features/home/redux/HomeMiddleware.kt | 13 +++++++++---- .../wallet/redux/OnboardingWalletMiddleware.kt | 2 +- 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/IntentHandler.kt b/app/src/main/java/com/tangem/tap/common/IntentHandler.kt index 1e41053369..be6ef95e79 100644 --- a/app/src/main/java/com/tangem/tap/common/IntentHandler.kt +++ b/app/src/main/java/com/tangem/tap/common/IntentHandler.kt @@ -35,7 +35,7 @@ class IntentHandler { intent.action = null store.dispatch(NavigationAction.NavigateTo(AppScreen.Home)) store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) - store.dispatch(HomeAction.ReadCard) + store.dispatch(HomeAction.ReadCard()) } } } diff --git a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt index c06f921c2f..587e981005 100644 --- a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt @@ -86,7 +86,7 @@ class HomeFragment : Fragment(), StoreSubscriber { homeState, onScanButtonClick = { Analytics.send(IntroductionProcess.ButtonScanCard()) - store.dispatch(HomeAction.ReadCard) + store.dispatch(HomeAction.ReadCard()) }, onShopButtonClick = { Analytics.send(IntroductionProcess.ButtonBuyCards()) diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt index 0a276dff4f..74dde30ea8 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt @@ -1,6 +1,7 @@ package com.tangem.tap.features.home.redux import com.tangem.tap.common.entities.IndeterminateProgressButton +import com.tangem.tap.common.redux.navigation.AppScreen import org.rekotlin.Action sealed class HomeAction : Action { @@ -9,7 +10,10 @@ sealed class HomeAction : Action { data class ShouldScanCardOnResume(val shouldScanCard: Boolean) : HomeAction() // from ui - object ReadCard : HomeAction() + data class ReadCard( + val fromScreen: AppScreen = AppScreen.Home, + ) : HomeAction() + data class ScanInProgress(val scanInProgress: Boolean) : HomeAction() data class GoToShop(val userCountryCode: String?) : HomeAction() diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt index 37a1da2c8b..23c14d184a 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt @@ -11,6 +11,7 @@ import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE import com.tangem.tap.backupService import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.events.IntroductionProcess +import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.analytics.events.Shop import com.tangem.tap.common.analytics.paramsInterceptor.BatchIdParamsInterceptor import com.tangem.tap.common.entities.IndeterminateProgressButton @@ -76,7 +77,7 @@ private fun handleHomeAction(appState: () -> AppState?, action: Action, dispatch is HomeAction.ShouldScanCardOnResume -> { if (action.shouldScanCard) { store.dispatch(HomeAction.ShouldScanCardOnResume(false)) - postUiDelayBg(700) { store.dispatch(HomeAction.ReadCard) } + postUiDelayBg(700) { store.dispatch(HomeAction.ReadCard(AppScreen.Wallet)) } } } is HomeAction.ReadCard -> { @@ -90,7 +91,7 @@ private fun handleHomeAction(appState: () -> AppState?, action: Action, dispatch nextHandler = { showDisclaimerIfNeed( scanResponse = scanResponse, - nextHandler = ::onScanSuccess, + nextHandler = { onScanSuccess(action.fromScreen, scanResponse) }, ) }, ) @@ -154,8 +155,12 @@ private fun showDisclaimerIfNeed(scanResponse: ScanResponse, nextHandler: (ScanR } } -private fun onScanSuccess(scanResponse: ScanResponse) { - Analytics.send(IntroductionProcess.CardWasScanned()) +private fun onScanSuccess(fromScreen: AppScreen, scanResponse: ScanResponse) { + when (fromScreen) { + AppScreen.Wallet -> Analytics.send(MainScreen.CardWasScanned()) + else -> Analytics.send(IntroductionProcess.CardWasScanned()) + } + val globalState = store.state.globalState val tapWalletManager = globalState.tapWalletManager tapWalletManager.updateConfigManager(scanResponse) 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 dfe53282ed..b0be522213 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 @@ -149,7 +149,7 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: if (scanResponse == null) { store.dispatch(NavigationAction.PopBackTo()) - store.dispatch(HomeAction.ReadCard) + store.dispatch(HomeAction.ReadCard()) } else { val backupState = store.state.onboardingWalletState.backupState val updatedScanResponse = updateScanResponseAfterBackup(scanResponse, backupState) From bc9fce72247ae209a28db2129c0d4ab7d904498c Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 20 Jan 2023 20:04:57 +0300 Subject: [PATCH 13/40] Updated on 2026-08-14 --- app/src/main/java/com/tangem/tap/TapApplication.kt | 13 +------------ .../handlers/appsFlyer/AppsFlyerAnalyticsHandler.kt | 3 +-- .../tangem/tap/common/feedback/FeedbackManager.kt | 2 +- .../ui/walletconnect/WalletConnectFragment.kt | 2 +- .../features/onboarding/OnboardingMenuProvider.kt | 2 +- .../tap/features/shop/redux/ShopMiddleware.kt | 2 +- .../wallet/redux/middlewares/WalletMiddleware.kt | 2 +- .../features/wallet/redux/models/WalletDialog.kt | 6 +++--- .../features/wallet/ui/WalletWarningConverter.kt | 5 +---- 9 files changed, 11 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 3ccb770ad4..d2b413e412 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -11,13 +11,13 @@ import com.tangem.blockchain.common.BlockchainSdkConfig import com.tangem.blockchain.common.WalletManagerFactory import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder import com.tangem.common.json.MoshiJsonConverter +import com.tangem.core.analytics.Analytics import com.tangem.datasource.api.common.MoshiConverter import com.tangem.domain.DomainLayer import com.tangem.domain.common.LogConfig import com.tangem.tap.common.AndroidAssetReader import com.tangem.tap.common.AssetReader import com.tangem.tap.common.IntentHandler -import com.tangem.core.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsFactory import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder import com.tangem.tap.common.analytics.filters.BasicSignInFilter @@ -170,17 +170,6 @@ class TapApplication : Application(), ImageLoaderFactory { ) } - private fun initMoshiConverter() { - fun appAdapters(): List = listOf( - BigDecimalAdapter(), - CardBalanceStateAdapter(), - ) - MoshiConverter.reInitInstance( - adapters = appAdapters() + MoshiJsonConverter.getTangemSdkAdapters(), - typedAdapters = MoshiJsonConverter.getTangemSdkTypedAdapters(), - ) - } - override fun newImageLoader(): ImageLoader { return createCoilImageLoader( context = this, diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerAnalyticsHandler.kt index e9ece28a44..d1b3189ab1 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerAnalyticsHandler.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerAnalyticsHandler.kt @@ -1,10 +1,9 @@ package com.tangem.tap.common.analytics.handlers.appsFlyer import com.appsflyer.AFInAppEventType +import com.tangem.core.analytics.AnalyticsEvent import com.tangem.core.analytics.api.AnalyticsHandler -import com.tangem.tap.common.analytics.api.AnalyticsHandler import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder -import com.tangem.tap.common.analytics.events.AnalyticsEvent import com.tangem.tap.common.analytics.events.Shop class AppsFlyerAnalyticsHandler( diff --git a/app/src/main/java/com/tangem/tap/common/feedback/FeedbackManager.kt b/app/src/main/java/com/tangem/tap/common/feedback/FeedbackManager.kt index 3ee976483c..b44db4004b 100644 --- a/app/src/main/java/com/tangem/tap/common/feedback/FeedbackManager.kt +++ b/app/src/main/java/com/tangem/tap/common/feedback/FeedbackManager.kt @@ -2,8 +2,8 @@ package com.tangem.tap.common.feedback import android.content.Context import android.os.Build +import com.tangem.core.analytics.Analytics import com.tangem.domain.common.TapWorkarounds -import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.extensions.sendEmail import com.tangem.tap.common.log.TangemLogCollector import com.tangem.tap.common.zendesk.ZendeskConfig diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectFragment.kt index 4b01e513a2..8b29784828 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectFragment.kt @@ -9,8 +9,8 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.platform.ComposeView import androidx.fragment.app.Fragment import androidx.transition.TransitionInflater +import com.tangem.core.analytics.Analytics import com.tangem.core.ui.res.TangemTheme -import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.events.WalletConnect import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt index 7c816d9210..4af057eb58 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt @@ -4,7 +4,7 @@ import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import androidx.core.view.MenuProvider -import com.tangem.tap.common.analytics.Analytics +import com.tangem.core.analytics.Analytics import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.feedback.SupportInfo import com.tangem.tap.common.redux.global.GlobalAction diff --git a/app/src/main/java/com/tangem/tap/features/shop/redux/ShopMiddleware.kt b/app/src/main/java/com/tangem/tap/features/shop/redux/ShopMiddleware.kt index 5c5a9d72b9..62e21e95e1 100644 --- a/app/src/main/java/com/tangem/tap/features/shop/redux/ShopMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/shop/redux/ShopMiddleware.kt @@ -1,6 +1,6 @@ package com.tangem.tap.features.shop.redux -import com.tangem.tap.common.analytics.Analytics +import com.tangem.core.analytics.Analytics import com.tangem.tap.common.analytics.events.Shop import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.dispatchOpenUrl 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 f26b34fa01..dc19d83445 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 @@ -276,7 +276,7 @@ class WalletMiddleware { } else { store.dispatch(newAction) if (newAction is PrepareSendScreen) { - store.state.walletState.getSelectedWalletData()?.currency?.let { currency -> + store.state.walletState.selectedWalletData?.currency?.let { currency -> Analytics.send(Token.ButtonSend(AnalyticsParam.CurrencyType.Currency(currency))) } store.dispatch(NavigationAction.NavigateTo(AppScreen.Send)) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/models/WalletDialog.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/models/WalletDialog.kt index f1a7575391..fb16e8420c 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/models/WalletDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/models/WalletDialog.kt @@ -16,7 +16,7 @@ sealed interface WalletDialog : StateDialog { data class RemoveWalletDialog( val currencyTitle: String, - val onOk: () -> Unit + val onOk: () -> Unit, ) : WalletDialog { val messageRes: Int = R.string.token_details_hide_alert_message val titleRes: Int = R.string.token_details_hide_alert_title @@ -25,13 +25,13 @@ sealed interface WalletDialog : StateDialog { data class TokensAreLinkedDialog( val currencyTitle: String, - val currencySymbol: String + val currencySymbol: String, ) : WalletDialog { val messageRes: Int = R.string.token_details_unable_hide_alert_message val titleRes: Int = R.string.token_details_unable_hide_alert_title } data class RussianCardholdersWarningDialog(val data: Data?) : WalletDialog { - data class Data(val topUpUrl: String, val blockchain: Blockchain) + data class Data(val topUpUrl: String) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletWarningConverter.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletWarningConverter.kt index 0effd1a9ba..a3ffb44b3a 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletWarningConverter.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletWarningConverter.kt @@ -24,17 +24,14 @@ class WalletWarningConverter( is WalletWarning.BalanceNotEnoughForFee -> { context.getString( R.string.token_details_send_blocked_fee_format, - message.tokenName, message.blockchainFullName, - message.tokenName, message.blockchainFullName, - message.blockchainCurrencyName, ) } is WalletWarning.TransactionInProgress -> { context.getString( R.string.token_details_send_blocked_tx_format, - message.currencyName + message.currencyName, ) } is WalletWarning.Rent -> { From 3bb298da17e735bb47e1dcb984a309e521cadc32 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 19 Jan 2023 16:41:20 +0300 Subject: [PATCH 14/40] Updated on 2026-08-14 --- .../DefaultWalletCurrenciesManager.kt | 38 +++++++++------- .../utils/WalletDataOperations.kt | 4 +- .../utils/WalletStoreOperations.kt | 43 ++++++++----------- 3 files changed, 43 insertions(+), 42 deletions(-) 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 dd19a02575..2b5a565f7e 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 @@ -1,5 +1,6 @@ package com.tangem.tap.domain.walletCurrencies.implementation +import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.DerivationStyle import com.tangem.common.CompletionResult import com.tangem.common.flatMap @@ -54,28 +55,17 @@ internal class DefaultWalletCurrenciesManager( currenciesToAdd: List, ): CompletionResult = withContext(Dispatchers.Default) { val card = userWallet.scanResponse.card - val updatedBlockchainNetworks = currenciesToAdd - .addMissingBlockchains(card) - .toBlockchainNetworks() val newCurrencies = (getSavedCurrencies(userWallet.walletId) + currenciesToAdd) .addMissingBlockchains(card) - updateWalletStores(userWallet, updatedBlockchainNetworks) + updateWalletStores(userWallet, newCurrencies.toBlockchainNetworks()) .map { saveUserCurrencies(card, newCurrencies) } .flatMap { - val updatedBlockchains = updatedBlockchainNetworks - .map { it.blockchain } - val updatedWalletStores = walletStoresRepository.get(userWallet.walletId) - .firstOrNull() - ?.filter { it.blockchain in updatedBlockchains } - ?: return@flatMap CompletionResult.Success(Unit) - - walletAmountsRepository.updateAmountsForWalletStores( - walletStores = updatedWalletStores, + updateWalletStoresAmounts( userWallet = userWallet, - fiatCurrency = appCurrencyProvider(), + updatedBlockchains = currenciesToAdd.map { it.blockchain }.distinct(), ) } } @@ -161,6 +151,10 @@ internal class DefaultWalletCurrenciesManager( return newCurrencies } + private fun findDerivationPath(currency: Currency, cardDerivationStyle: DerivationStyle?): String? { + return currency.derivationPath ?: currency.blockchain.derivationPath(cardDerivationStyle)?.rawPath + } + private suspend fun updateWalletStores( userWallet: UserWallet, blockchainNetworks: List, @@ -184,7 +178,19 @@ internal class DefaultWalletCurrenciesManager( .fold() } - private fun findDerivationPath(currency: Currency, cardDerivationStyle: DerivationStyle?): String? { - return currency.derivationPath ?: currency.blockchain.derivationPath(cardDerivationStyle)?.rawPath + private suspend fun updateWalletStoresAmounts( + userWallet: UserWallet, + updatedBlockchains: List, + ): CompletionResult { + val updatedWalletStores = walletStoresRepository.get(userWallet.walletId) + .firstOrNull() + ?.filter { it.blockchain in updatedBlockchains } + ?: return CompletionResult.Success(Unit) + + return walletAmountsRepository.updateAmountsForWalletStores( + walletStores = updatedWalletStores, + userWallet = userWallet, + fiatCurrency = appCurrencyProvider(), + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt index 7ad0e38363..64e2241737 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt @@ -158,12 +158,12 @@ internal fun List.updateWithUnreachable(): List.updateWithSelf( - walletsData: List, + newWalletsData: List, ): List { val oldWalletsData = this val updatedWalletsData = arrayListOf() - walletsData.forEach { newWalletData -> + newWalletsData.forEach { newWalletData -> val walletDataToUpdate = oldWalletsData.find(newWalletData::isSameWalletData) if (walletDataToUpdate != null) { updatedWalletsData.add(walletDataToUpdate.updateWithSelf(newWalletData)) diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt index 2aa7ffcf2d..0e9e9d8715 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt @@ -88,39 +88,34 @@ internal fun WalletStoreModel.updateWithRent(rent: WalletStoreModel.WalletRent?) ) } -internal fun WalletStoreModel.isSameWalletStore(other: WalletStoreModel): Boolean { - return this.blockchain == other.blockchain && - this.derivationPath == other.derivationPath -} - private inline fun List.replaceWalletStores( walletStoresToUpdate: List, update: (walletStore: WalletStoreModel) -> WalletStoreModel, ): List { val mutableStores = ArrayList(this) - walletStoresToUpdate - .asSequence() - .map { it.blockchain to it.derivationPath } - .forEach { (blockchain, derivationPath) -> - val index = mutableStores.indexOfFirst { - it.blockchain == blockchain && it.derivationPath == derivationPath - } - val currentWalletStore = mutableStores[index] - val updatedWalletStore = update(currentWalletStore) + walletStoresToUpdate.forEach { walletStoreToUpdate -> + val index = mutableStores.indexOfFirst(walletStoreToUpdate::isSameWalletStore) + val currentWalletStore = mutableStores[index] + val updatedWalletStore = update(currentWalletStore) - if (currentWalletStore != updatedWalletStore) { - Timber.d( - """ - Update wallet store in storage - |- User wallet ID: ${updatedWalletStore.userWalletId} - |- Blockchain: ${updatedWalletStore.blockchain} - """.trimIndent(), - ) + if (currentWalletStore != updatedWalletStore) { + Timber.d( + """ + Update wallet store in storage + |- User wallet ID: ${updatedWalletStore.userWalletId} + |- Blockchain: ${updatedWalletStore.blockchain} + """.trimIndent(), + ) - mutableStores[index] = updatedWalletStore - } + mutableStores[index] = updatedWalletStore } + } return mutableStores +} + +internal fun WalletStoreModel.isSameWalletStore(other: WalletStoreModel): Boolean { + return this.blockchain == other.blockchain && + this.derivationPath == other.derivationPath } \ No newline at end of file From a029f8527c2d1e6ee576d0e3dcda95800b6ecca1 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 23 Jan 2023 16:27:08 +0300 Subject: [PATCH 15/40] Updated on 2026-08-14 --- .../com/tangem/tap/common/analytics/events/Token.kt | 10 +++++----- .../onboarding/AddressInfoBottomSheetDialog.kt | 6 +++--- .../wallet/redux/middlewares/WalletMiddleware.kt | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt index 99badb9998..0ad3ca514e 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt @@ -46,14 +46,14 @@ sealed class Token( params = mapOf("Token" to type.value), ) - sealed class Recieve( + sealed class Receive( event: String, params: Map = mapOf(), - ) : Token("Token / Recieve", event, params) { + ) : Token("Token / Receive", event, params) { - class ScreenOpened : Recieve("Recieve Screen Opened") - class ButtonCopyAddress : Recieve("Button - Copy Address") - class ButtonShareAddress : Recieve("Button - Share Address") + class ScreenOpened : Receive("Receive Screen Opened") + class ButtonCopyAddress : Receive("Button - Copy Address") + class ButtonShareAddress : Receive("Button - Share Address") } sealed class Send( diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/AddressInfoBottomSheetDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/AddressInfoBottomSheetDialog.kt index 0372ae6ee4..66e30fe595 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/AddressInfoBottomSheetDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/AddressInfoBottomSheetDialog.kt @@ -42,7 +42,7 @@ class AddressInfoBottomSheetDialog( override fun show() { super.show() - Analytics.send(Token.Recieve.ScreenOpened()) + Analytics.send(Token.Receive.ScreenOpened()) showData(data = stateDialog.addressData) } @@ -54,12 +54,12 @@ class AddressInfoBottomSheetDialog( imvQrCode.setImageBitmap(data.qrCode) tvAddress.text = data.address btnFlCopyAddress.setOnClickListener { - Analytics.send(Token.Recieve.ButtonCopyAddress()) + Analytics.send(Token.Receive.ButtonCopyAddress()) context.copyToClipboard(data.address) store.dispatchToastNotification(R.string.copy_toast_msg) } btnFlShare.setOnClickListener { - Analytics.send(Token.Recieve.ButtonShareAddress()) + Analytics.send(Token.Receive.ButtonShareAddress()) store.dispatchShare(data.shareUrl) } val blockchain = stateDialog.currency.blockchain 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 dc19d83445..1bbe68a519 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 @@ -249,12 +249,12 @@ class WalletMiddleware { } } is WalletAction.CopyAddress -> { - Analytics.send(Token.Recieve.ButtonCopyAddress()) + Analytics.send(Token.Receive.ButtonCopyAddress()) action.context.copyToClipboard(action.address) store.dispatch(WalletAction.CopyAddress.Success) } is WalletAction.ShareAddress -> { - Analytics.send(Token.Recieve.ButtonShareAddress()) + Analytics.send(Token.Receive.ButtonShareAddress()) action.context.shareText(action.address) } is WalletAction.ExploreAddress -> { From 9e8b302330cd07c609576cb5bb2d88425dad5f4c Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 23 Jan 2023 16:48:34 +0300 Subject: [PATCH 16/40] Updated on 2026-08-14 --- .../com/tangem/tap/common/analytics/events/WalletConnect.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt index 2d6c404ce7..9ce10213ac 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt @@ -11,7 +11,7 @@ sealed class WalletConnect( error: Throwable? = null, ) : AnalyticsEvent("Wallet Connect", event, params, error) { - class ScreenOpened : Settings(event = "WC Screen Opened") + class ScreenOpened : WalletConnect(event = "WC Screen Opened") class NewSessionEstablished : WalletConnect("New Session Established") class SessionDisconnected : WalletConnect("Session Disconnected") class RequestSigned : WalletConnect("Request Signed") From b80a3444de5f8288244d89d6bc983f27ba9167f4 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 23 Jan 2023 17:01:14 +0300 Subject: [PATCH 17/40] Updated on 2026-08-14 --- .../tap/common/analytics/events/SignIn.kt | 17 +++++++++++++++++ .../tap/features/welcome/ui/WelcomeFragment.kt | 8 ++++++++ .../tap/features/welcome/ui/WelcomeViewModel.kt | 4 ++++ 3 files changed, 29 insertions(+) create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/events/SignIn.kt diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/SignIn.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/SignIn.kt new file mode 100644 index 0000000000..5b7fff71ea --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/SignIn.kt @@ -0,0 +1,17 @@ +package com.tangem.tap.common.analytics.events + +import com.tangem.core.analytics.AnalyticsEvent + +/** +[REDACTED_AUTHOR] + */ +sealed class SignIn( + event: String, + params: Map = mapOf(), + error: Throwable? = null, +) : AnalyticsEvent("Sign In", event, params, error) { + + class ScreenOpened : SignIn(event = "Sing In Screen Opened") + class ButtonBiometricSignIn : SignIn(event = "Button - Biometric Sign In") + class ButtonCardSignIn : SignIn(event = "Button - Card Sign In") +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeFragment.kt b/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeFragment.kt index 9ff1ad727f..70477f5ad1 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeFragment.kt @@ -1,5 +1,6 @@ package com.tangem.tap.features.welcome.ui +import android.os.Bundle import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth @@ -18,9 +19,11 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.colorResource import androidx.fragment.app.viewModels +import com.tangem.core.analytics.Analytics import com.tangem.core.ui.components.SystemBarsEffect import com.tangem.core.ui.fragments.ComposeFragment import com.tangem.core.ui.res.TangemTheme +import com.tangem.tap.common.analytics.events.SignIn import com.tangem.tap.features.details.ui.cardsettings.resolveReference import com.tangem.tap.features.welcome.ui.components.WelcomeScreenContent import com.tangem.wallet.R @@ -28,6 +31,11 @@ import com.tangem.wallet.R internal class WelcomeFragment : ComposeFragment() { private val viewModel by viewModels() + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + Analytics.send(SignIn.ScreenOpened()) + } + @Composable override fun provideState(): State { return viewModel.state.collectAsState() diff --git a/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeViewModel.kt b/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeViewModel.kt index a047d8518e..b810503287 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeViewModel.kt @@ -1,6 +1,8 @@ package com.tangem.tap.features.welcome.ui import androidx.lifecycle.ViewModel +import com.tangem.core.analytics.Analytics +import com.tangem.tap.common.analytics.events.SignIn import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.features.details.ui.cardsettings.TextReference import com.tangem.tap.features.welcome.redux.WelcomeAction @@ -21,10 +23,12 @@ internal class WelcomeViewModel : ViewModel(), StoreSubscriber { } fun unlockWallets() { + Analytics.send(SignIn.ButtonBiometricSignIn()) store.dispatch(WelcomeAction.ProceedWithBiometrics) } fun scanCard() { + Analytics.send(SignIn.ButtonCardSignIn()) store.dispatch(WelcomeAction.ProceedWithCard) } From ecb01b46528b2dd395719ec81c99ff5ddbea162c Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 23 Jan 2023 18:54:12 +0300 Subject: [PATCH 18/40] Updated on 2026-08-14 --- .../tap/common/analytics/events/MyWallets.kt | 16 +++++++-------- .../tap/domain/scanCard/ScanCardProcessor.kt | 19 ++++++++++++------ .../tap/features/home/redux/HomeAction.kt | 7 +++---- .../tap/features/home/redux/HomeMiddleware.kt | 20 +++++-------------- .../tap/features/home/redux/HomeReducer.kt | 3 --- .../tap/features/home/redux/HomeState.kt | 1 - .../tap/features/wallet/redux/WalletAction.kt | 3 ++- .../middlewares/MultiWalletMiddleware.kt | 5 +++-- .../redux/middlewares/WalletMiddleware.kt | 8 ++++++-- .../redux/WalletSelectorMiddleware.kt | 11 +++++----- .../ui/WalletSelectorBottomSheetFragment.kt | 4 ++-- .../welcome/redux/WelcomeMiddleware.kt | 2 ++ 12 files changed, 49 insertions(+), 50 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/MyWallets.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/MyWallets.kt index 2b660fa11d..d83a8371d6 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/MyWallets.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/MyWallets.kt @@ -7,14 +7,14 @@ sealed class MyWallets( params: Map = mapOf(), ) : AnalyticsEvent("My Wallets", event, params) { - object MyWalletsScreenOpened : MyWallets(event = "My Wallets Screen Opened") - object CardWasScanned : MyWallets(event = "Card Was Scanned") - object WalletUnlockTapped : MyWallets(event = "Wallet Unlock Tapped") + class MyWalletsScreenOpened : MyWallets(event = "My Wallets Screen Opened") + class CardWasScanned : MyWallets(event = "Card Was Scanned") + class WalletUnlockTapped : MyWallets(event = "Wallet Unlock Tapped") - object Button { - object ScanNewCard : MyWallets(event = "Button - Scan New Card") - object UnlockWithBiometrics : MyWallets(event = "Button - Unlock all with Face ID") - object EditWalletTapped : MyWallets(event = "Button - Edit Wallet Tapped") - object DeleteWalletTapped : MyWallets(event = "Button - Delete Wallet Tapped") + sealed class Button { + class ScanNewCard : MyWallets(event = "Button - Scan New Card") + class UnlockWithBiometrics : MyWallets(event = "Button - Unlock all with Face ID") + class EditWalletTapped : MyWallets(event = "Button - Edit Wallet Tapped") + class DeleteWalletTapped : MyWallets(event = "Button - Delete Wallet Tapped") } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt index 7b33c2f9fc..b9e8f526f9 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt @@ -6,13 +6,13 @@ import com.tangem.common.core.TangemSdkError import com.tangem.common.doOnFailure import com.tangem.common.doOnSuccess import com.tangem.common.services.Result +import com.tangem.core.analytics.Analytics +import com.tangem.core.analytics.AnalyticsEvent import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.extensions.withMainContext import com.tangem.operations.backup.BackupService import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE import com.tangem.tap.backupService -import com.tangem.core.analytics.Analytics -import com.tangem.tap.common.analytics.events.IntroductionProcess import com.tangem.tap.common.analytics.paramsInterceptor.BatchIdParamsInterceptor import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchOnMain @@ -45,6 +45,7 @@ import kotlinx.coroutines.launch // TODO: Create repository for that object ScanCardProcessor { suspend fun scan( + analyticsEvent: AnalyticsEvent? = null, additionalBlockchainsToDerive: Collection? = null, cardId: String? = null, onProgressStateChange: suspend (showProgress: Boolean) -> Unit = {}, @@ -77,6 +78,8 @@ object ScanCardProcessor { tangemSdkManager.changeDisplayedCardIdNumbersCount(scanResponse) onScanStateChange(false) + sendAnalytics(analyticsEvent, scanResponse.card.batchId) + checkForUnfinishedBackupForSaltPay( backupService = backupService, scanResponse = scanResponse, @@ -102,6 +105,14 @@ object ScanCardProcessor { } } + private fun sendAnalytics( + analyticsEvent: AnalyticsEvent?, + batchId: String, + ) { + Analytics.addParamsInterceptor(BatchIdParamsInterceptor(batchId)) + analyticsEvent?.let { Analytics.send(it) } + } + /** * It checks only the SaltPay cards. To check for unfinished backups for the standard Wallet cards * see BackupAction.CheckForUnfinishedBackup @@ -173,14 +184,10 @@ object ScanCardProcessor { crossinline onSuccess: suspend (ScanResponse) -> Unit, crossinline onFailure: suspend (error: TangemError) -> Unit, ) { - Analytics.send(IntroductionProcess.CardWasScanned()) - val globalState = store.state.globalState val tapWalletManager = globalState.tapWalletManager tapWalletManager.updateConfigManager(scanResponse) - Analytics.addParamsInterceptor(BatchIdParamsInterceptor(scanResponse.card.batchId)) - store.dispatchOnMain(TwinCardsAction.IfTwinsPrepareState(scanResponse)) if (scanResponse.isSaltPay()) { diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt index e7d0c79e2e..59e169ee04 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt @@ -1,17 +1,16 @@ package com.tangem.tap.features.home.redux +import com.tangem.core.analytics.AnalyticsEvent +import com.tangem.tap.common.analytics.events.IntroductionProcess import com.tangem.tap.common.entities.IndeterminateProgressButton -import com.tangem.tap.common.redux.navigation.AppScreen import org.rekotlin.Action sealed class HomeAction : Action { object Init : HomeAction() - data class ShouldScanCardOnResume(val shouldScanCard: Boolean) : HomeAction() - // from ui data class ReadCard( - val fromScreen: AppScreen = AppScreen.Home, + val analyticsEvent: AnalyticsEvent? = IntroductionProcess.CardWasScanned(), ) : HomeAction() data class ScanInProgress(val scanInProgress: Boolean) : HomeAction() diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt index 33bf357557..b85a6601c5 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt @@ -4,16 +4,13 @@ import com.tangem.common.doOnFailure import com.tangem.common.doOnResult import com.tangem.common.doOnSuccess import com.tangem.core.analytics.Analytics -import com.tangem.tap.common.analytics.events.IntroductionProcess -import com.tangem.tap.common.analytics.events.MainScreen +import com.tangem.core.analytics.AnalyticsEvent import com.tangem.tap.common.analytics.events.Shop -import com.tangem.tap.common.analytics.paramsInterceptor.BatchIdParamsInterceptor import com.tangem.tap.common.entities.IndeterminateProgressButton import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.dispatchOpenUrl import com.tangem.tap.common.extensions.onCardScanned import com.tangem.tap.common.extensions.onUserWalletSelected -import com.tangem.tap.common.postUiDelayBg import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.navigation.AppScreen @@ -59,13 +56,9 @@ private fun handleHomeAction(action: Action) { store.dispatch(GlobalAction.ExchangeManager.Init) store.dispatch(GlobalAction.FetchUserCountry) } - is HomeAction.ShouldScanCardOnResume -> { - if (action.shouldScanCard) { - store.dispatch(HomeAction.ShouldScanCardOnResume(false)) - postUiDelayBg(700) { store.dispatch(HomeAction.ReadCard(AppScreen.Wallet)) } - } + is HomeAction.ReadCard -> { + readCard(action.analyticsEvent) } - is HomeAction.ReadCard -> readCard(action.fromScreen) is HomeAction.GoToShop -> { Analytics.send(Shop.ScreenOpened()) when (action.userCountryCode) { @@ -76,12 +69,13 @@ private fun handleHomeAction(action: Action) { } } -private fun readCard(fromScreen: AppScreen) = scope.launch { +private fun readCard(analyticsEvent: AnalyticsEvent?) = scope.launch { delay(timeMillis = 200) tangemSdkManager.setAccessCodeRequestPolicy( useBiometricsForAccessCode = preferencesStorage.shouldSaveAccessCodes, ) ScanCardProcessor.scan( + analyticsEvent = analyticsEvent, onProgressStateChange = { showProgress -> if (showProgress) { changeButtonState(ButtonState.PROGRESS) @@ -97,10 +91,6 @@ private fun readCard(fromScreen: AppScreen) = scope.launch { changeButtonState(ButtonState.ENABLED) }, onSuccess = { scanResponse -> - when (fromScreen) { - AppScreen.Wallet -> Analytics.send(MainScreen.CardWasScanned()) - else -> Analytics.send(IntroductionProcess.CardWasScanned()) - } scope.launch { if (preferencesStorage.shouldSaveUserWallets) { val userWallet = UserWalletBuilder(scanResponse).build() ?: return@launch diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt index 511aea3ddc..8e1583baa5 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt @@ -18,9 +18,6 @@ private fun internalReduce(action: Action, state: AppState): HomeState { is HomeAction.ScanInProgress -> { state = state.copy(scanInProgress = action.scanInProgress) } - is HomeAction.ShouldScanCardOnResume -> { - state = state.copy(shouldScanCardOnResume = action.shouldScanCard) - } is HomeAction.ChangeScanCardButtonState -> { state = state.copy(btnScanState = action.state) } diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt index 9ef6ea2b57..618e432dec 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt @@ -6,7 +6,6 @@ import com.tangem.tap.features.wallet.redux.ProgressState import org.rekotlin.StateType data class HomeState( - val shouldScanCardOnResume: Boolean = false, val scanInProgress: Boolean = false, val btnScanState: IndeterminateProgressButton = IndeterminateProgressButton(ButtonState.ENABLED), ) : StateType { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt index 0cc8039e96..c261f4c7ba 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt @@ -7,6 +7,7 @@ import com.tangem.blockchain.common.Token import com.tangem.blockchain.common.Wallet import com.tangem.blockchain.common.WalletManager import com.tangem.blockchain.common.address.AddressType +import com.tangem.core.analytics.AnalyticsEvent import com.tangem.domain.common.CardDTO import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.redux.NotificationAction @@ -142,7 +143,7 @@ sealed class WalletAction : Action { object Failure : WalletAction() } - object Scan : WalletAction() + data class Scan(val onScanSuccessEvent: AnalyticsEvent?) : WalletAction() data class Send(val amount: Amount? = null) : WalletAction() 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 87341ef9c0..1a9f71f51a 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 @@ -5,8 +5,8 @@ import com.tangem.blockchain.common.Token import com.tangem.blockchain.common.WalletManager import com.tangem.common.doOnSuccess import com.tangem.common.extensions.guard -import com.tangem.domain.common.extensions.withMainContext import com.tangem.core.analytics.Analytics +import com.tangem.domain.common.extensions.withMainContext import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.analytics.events.Token.ButtonRemoveToken @@ -173,7 +173,7 @@ class MultiWalletMiddleware { if (selectedWallet != null) { scanAndUpdateCard(selectedWallet, walletState) } else { - store.dispatch(WalletAction.Scan) + store.dispatch(WalletAction.Scan(onScanSuccessEvent = null)) } } } @@ -185,6 +185,7 @@ class MultiWalletMiddleware { ) = scope.launch(Dispatchers.Default) { Analytics.send(MainScreen.CardWasScanned()) ScanCardProcessor.scan( + analyticsEvent = null, cardId = selectedUserWallet.cardId, additionalBlockchainsToDerive = state?.missingDerivations?.map { it.blockchain }, ) { scanResponse -> 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 1bbe68a519..a20c8b5b36 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 @@ -59,6 +59,7 @@ import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.rekotlin.Action import org.rekotlin.DispatchFunction @@ -194,8 +195,11 @@ class WalletMiddleware { } } is WalletAction.Scan -> { - store.dispatch(HomeAction.ShouldScanCardOnResume(true)) store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) + scope.launch { + delay(700) + store.dispatchOnMain(HomeAction.ReadCard(action.onScanSuccessEvent)) + } } is WalletAction.LoadCardInfo -> { val attestationFailed = action.card.attestation.status == Attestation.Status.Failed @@ -366,7 +370,7 @@ class WalletMiddleware { } else -> { Analytics.send(MainScreen.ButtonScanCard()) - store.dispatch(WalletAction.Scan) + store.dispatch(WalletAction.Scan(MainScreen.CardWasScanned())) } } } diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt index 38832e455a..ed12b4cd7b 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt @@ -121,7 +121,7 @@ internal class WalletSelectorMiddleware { } private fun unlockWalletsWithBiometry() { - Analytics.send(MyWallets.Button.UnlockWithBiometrics) + Analytics.send(MyWallets.Button.UnlockWithBiometrics()) scope.launch { userWalletsListManager.unlockWithBiometry() @@ -135,7 +135,7 @@ internal class WalletSelectorMiddleware { } private fun addWallet() = scope.launch { - Analytics.send(MyWallets.Button.ScanNewCard) + Analytics.send(MyWallets.Button.ScanNewCard()) val prevUseBiometricsForAccessCode = tangemSdkManager.useBiometricsForAccessCode() @@ -145,6 +145,7 @@ internal class WalletSelectorMiddleware { ) ScanCardProcessor.scan( + analyticsEvent = MyWallets.CardWasScanned(), onWalletNotCreated = { // No need to rollback policy, continue with the policy set before the card scan store.dispatchOnMain(WalletSelectorAction.AddWallet.Success) @@ -175,8 +176,6 @@ internal class WalletSelectorMiddleware { return userWalletsListManager.save(userWallet) .doOnSuccess { - Analytics.send(MyWallets.CardWasScanned) - store.dispatchOnMain(WalletSelectorAction.AddWallet.Success) store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Wallet)) store.onUserWalletSelected(userWallet) @@ -227,7 +226,7 @@ internal class WalletSelectorMiddleware { } private fun deleteWallets(userWalletsIds: List, state: WalletSelectorState) { - Analytics.send(MyWallets.Button.DeleteWalletTapped) + Analytics.send(MyWallets.Button.DeleteWalletTapped()) scope.launch { when (userWalletsIds.size) { @@ -244,7 +243,7 @@ internal class WalletSelectorMiddleware { } private fun renameWallet(userWalletId: UserWalletId, newName: String) { - Analytics.send(MyWallets.Button.EditWalletTapped) + Analytics.send(MyWallets.Button.EditWalletTapped()) scope.launch { userWalletsListManager.update(userWalletId) { it.copy(name = newName) } diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt index 96bba1df0e..f8bc829bde 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt @@ -20,9 +20,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.rememberNestedScrollInteropConnection import androidx.fragment.app.viewModels +import com.tangem.core.analytics.Analytics import com.tangem.core.ui.fragments.ComposeBottomSheetFragment import com.tangem.core.ui.res.TangemTheme -import com.tangem.core.analytics.Analytics import com.tangem.tap.common.analytics.events.MyWallets import com.tangem.tap.features.details.ui.cardsettings.resolveReference import com.tangem.tap.features.walletSelector.ui.components.RenameWalletDialogContent @@ -33,7 +33,7 @@ internal class WalletSelectorBottomSheetFragment : ComposeBottomSheetFragment() override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - Analytics.send(MyWallets.MyWalletsScreenOpened) + Analytics.send(MyWallets.MyWalletsScreenOpened()) return super.onCreateDialog(savedInstanceState) } diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt index e7cb2e01e7..808f4ea74f 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt @@ -4,6 +4,7 @@ import android.content.Intent import com.tangem.common.doOnFailure import com.tangem.common.doOnSuccess import com.tangem.domain.common.ScanResponse +import com.tangem.tap.common.analytics.events.IntroductionProcess import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.onUserWalletSelected import com.tangem.tap.common.redux.AppState @@ -98,6 +99,7 @@ internal class WelcomeMiddleware { useBiometricsForAccessCode = preferencesStorage.shouldSaveAccessCodes, ) ScanCardProcessor.scan( + analyticsEvent = IntroductionProcess.CardWasScanned(), onSuccess = { scanResponse -> scope.launch { onCardScanned(scanResponse) } }, From caaea924a27341d304b2cc21c18c09e2767b940f Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 23 Jan 2023 20:17:29 +0300 Subject: [PATCH 19/40] Updated on 2026-08-14 --- .../saveWallet/ui/SaveWalletBottomSheetFragment.kt | 11 +++++++---- .../tap/features/saveWallet/ui/SaveWalletViewModel.kt | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/saveWallet/ui/SaveWalletBottomSheetFragment.kt b/app/src/main/java/com/tangem/tap/features/saveWallet/ui/SaveWalletBottomSheetFragment.kt index f4663eda6e..63803d4095 100644 --- a/app/src/main/java/com/tangem/tap/features/saveWallet/ui/SaveWalletBottomSheetFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/saveWallet/ui/SaveWalletBottomSheetFragment.kt @@ -28,9 +28,9 @@ internal class SaveWalletBottomSheetFragment : ComposeBottomSheetFragment() - override fun onDismiss(dialog: DialogInterface) { - viewModel.dismiss() - super.onDismiss(dialog) + override fun onCancel(dialog: DialogInterface) { + viewModel.cancelOrClose() + super.onCancel(dialog) } @Composable @@ -51,7 +51,10 @@ internal class SaveWalletBottomSheetFragment : ComposeBottomSheetFragment Date: Mon, 23 Jan 2023 22:13:52 +0300 Subject: [PATCH 20/40] Updated on 2026-08-14 --- .../java/com/tangem/tap/common/analytics/events/MyWallets.kt | 2 +- .../features/walletSelector/redux/WalletSelectorMiddleware.kt | 3 +-- .../tap/features/walletSelector/ui/WalletSelectorViewModel.kt | 3 +++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/MyWallets.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/MyWallets.kt index d83a8371d6..4db0526ad2 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/MyWallets.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/MyWallets.kt @@ -9,12 +9,12 @@ sealed class MyWallets( class MyWalletsScreenOpened : MyWallets(event = "My Wallets Screen Opened") class CardWasScanned : MyWallets(event = "Card Was Scanned") - class WalletUnlockTapped : MyWallets(event = "Wallet Unlock Tapped") sealed class Button { class ScanNewCard : MyWallets(event = "Button - Scan New Card") class UnlockWithBiometrics : MyWallets(event = "Button - Unlock all with Face ID") class EditWalletTapped : MyWallets(event = "Button - Edit Wallet Tapped") class DeleteWalletTapped : MyWallets(event = "Button - Delete Wallet Tapped") + class WalletUnlockTapped : MyWallets(event = "Button - Wallet Unlock Tapped") } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt index ed12b4cd7b..fcf97e11db 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt @@ -206,6 +206,7 @@ internal class WalletSelectorMiddleware { } private suspend fun unlockUserWalletWithScannedCard(userWallet: UserWallet): CompletionResult { + Analytics.send(MyWallets.Button.WalletUnlockTapped()) tangemSdkManager.changeDisplayedCardIdNumbersCount(userWallet.scanResponse) return tangemSdkManager.scanCard(userWallet.cardId) .map { scannedCard -> @@ -243,8 +244,6 @@ internal class WalletSelectorMiddleware { } private fun renameWallet(userWalletId: UserWalletId, newName: String) { - Analytics.send(MyWallets.Button.EditWalletTapped()) - scope.launch { userWalletsListManager.update(userWalletId) { it.copy(name = newName) } .doOnFailure { error -> diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorViewModel.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorViewModel.kt index 52a99013e3..edb923f5ba 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorViewModel.kt @@ -2,7 +2,9 @@ package com.tangem.tap.features.walletSelector.ui import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.tangem.core.analytics.Analytics import com.tangem.domain.common.util.UserWalletId +import com.tangem.tap.common.analytics.events.MyWallets import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.features.walletSelector.redux.WalletSelectorAction import com.tangem.tap.features.walletSelector.redux.WalletSelectorState @@ -71,6 +73,7 @@ internal class WalletSelectorViewModel : ViewModel(), StoreSubscriber From 35dbee86913c6777370d682261c0cd92a43464d5 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 23 Jan 2023 23:09:44 +0300 Subject: [PATCH 21/40] Updated on 2026-08-14 --- .../features/wallet/redux/middlewares/MultiWalletMiddleware.kt | 2 -- 1 file changed, 2 deletions(-) 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 1a9f71f51a..e6632583c4 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 @@ -8,7 +8,6 @@ import com.tangem.common.extensions.guard import com.tangem.core.analytics.Analytics import com.tangem.domain.common.extensions.withMainContext import com.tangem.tap.common.analytics.events.AnalyticsParam -import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.analytics.events.Token.ButtonRemoveToken import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchErrorNotification @@ -183,7 +182,6 @@ class MultiWalletMiddleware { selectedUserWallet: UserWallet, state: WalletState?, ) = scope.launch(Dispatchers.Default) { - Analytics.send(MainScreen.CardWasScanned()) ScanCardProcessor.scan( analyticsEvent = null, cardId = selectedUserWallet.cardId, From 3a57ac60c2204d3566463faf7dab94dda283533c Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 25 Jan 2023 01:33:28 +0300 Subject: [PATCH 22/40] Updated on 2026-08-14 --- .../converters/BasicEventConverter.kt | 171 +++++++++++++----- .../converters/ParamCardCurrencyConverter.kt | 1 + .../filters/ShopPurchasedEventFilter.kt | 0 .../com/tangem/tap/domain/TapWalletManager.kt | 7 +- .../walletStores/WalletStoresManager.kt | 1 + .../DefaultWalletStoresManager.kt | 4 + .../DummyWalletStoresManager.kt | 4 + .../tap/features/wallet/redux/WalletAction.kt | 1 + .../tap/features/wallet/redux/WalletState.kt | 4 + .../middlewares/MultiWalletMiddleware.kt | 4 + .../redux/middlewares/WalletMiddleware.kt | 21 +++ .../redux/reducers/MultiWalletReducer.kt | 8 +- .../tap/features/wallet/ui/WalletFragment.kt | 12 +- 13 files changed, 177 insertions(+), 61 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt 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 index 4936e61523..1eeda46c6f 100644 --- 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 @@ -2,77 +2,156 @@ 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.extensions.isMultiwalletAllowed +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.WalletData 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 BasicSignInEventConverter( - private val scanResponse: ScanResponse, -) : Converter { +class BasicEventsPreChecker { - override fun convert(value: WalletState): Basic.SignedIn? { - if (!statesIsReadyToCreateEvent(scanResponse, value)) return null - val cardCurrency = ParamCardCurrencyConverter().convert(scanResponse) ?: return null + fun tryToSend(converterData: BasicEventsSourceData) { + if (!isReadyToSend(converterData)) return + + BasicSignInEventConverter().convert(converterData)?.let { Analytics.send(it) } + BasicTopUpEventConverter().convert(converterData)?.let { Analytics.send(it) } + } + + private fun isReadyToSend(data: BasicEventsSourceData): Boolean { + val (scanResponse, walletState, biometricsWalletDataModels) = data + if (walletState.derivationsCheckIsScheduled) { + Timber.d("FAILED: derivationsCheckIsScheduled") + return false + } + if (scanResponse.card.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 + } + + if (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 + }) { + 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 batchId: String by lazy { scanResponse.card.batchId } + + val userWalletIdStringValue: String? by lazy { + UserWalletIdBuilder.scanResponse(scanResponse) + .build() + ?.stringValue + } + + val paramCardCurrency: AnalyticsParam.CardCurrency? by lazy { ParamCardCurrencyConverter().convert(scanResponse) } + + val paramCardBalanceState: AnalyticsParam.CardBalanceState by lazy { calculateAmount().toCardBalanceState() } + + private fun calculateAmount(): BigDecimal { + return biometricsWalletDataModels?.calculateTotalCryptoAmount() + ?: walletState.walletsDataFromStores.calculateTotalCryptoAmount() + } + + private fun BigDecimal.toCardBalanceState(): AnalyticsParam.CardBalanceState = when { + isZero() -> AnalyticsParam.CardBalanceState.Empty + else -> AnalyticsParam.CardBalanceState.Full + } + + private fun List.calculateTotalCryptoAmount(): BigDecimal { + return this + .map { it.status.amount } + .reduce(BigDecimal::plus) + } +} + +class BasicSignInEventConverter : Converter { + + override fun convert(value: BasicEventsSourceData): Basic.SignedIn? { + if (value.paramCardCurrency == null || value.userWalletIdStringValue == null) return null return Basic.SignedIn( - state = AnalyticsParam.CardBalanceState.from(value.walletsDataFromStores), - currency = cardCurrency, - batch = scanResponse.card.batchId, + state = value.paramCardBalanceState, + currency = value.paramCardCurrency!!, + batch = value.batchId, ).apply { - filterData = UserWalletIdBuilder.scanResponse(scanResponse) - .build() - ?.stringValue + filterData = value.userWalletIdStringValue } } } -class BasicTopUpEventConverter( - private val scanResponse: ScanResponse, -) : Converter { +class BasicTopUpEventConverter : Converter { - override fun convert(value: WalletState): Basic.ToppedUp? { - if (!statesIsReadyToCreateEvent(scanResponse, value)) return null - val cardCurrency = ParamCardCurrencyConverter().convert(scanResponse) ?: return null + override fun convert(value: BasicEventsSourceData): Basic.ToppedUp? { + if (value.paramCardCurrency == null || value.userWalletIdStringValue == null) return null val data = BasicTopUpFilter.Data( - walletId = UserWalletIdBuilder.scanResponse(scanResponse).build()?.stringValue ?: "", - cardBalanceState = AnalyticsParam.CardBalanceState.from(value.walletsDataFromStores), + walletId = value.userWalletIdStringValue!!, + cardBalanceState = value.paramCardBalanceState, ) - return Basic.ToppedUp(cardCurrency).apply { filterData = data } + return Basic.ToppedUp(value.paramCardCurrency!!).apply { filterData = data } } -} - -private fun AnalyticsParam.CardBalanceState.Companion.from(walletsData: List): AnalyticsParam.CardBalanceState { - val totalCryptoAmount = walletsData.calculateTotalCryptoAmount() - return when { - totalCryptoAmount.isZero() -> AnalyticsParam.CardBalanceState.Empty - else -> AnalyticsParam.CardBalanceState.Full - } -} - -private fun statesIsReadyToCreateEvent(scanResponse: ScanResponse, state: WalletState): Boolean { - if (scanResponse.card.isMultiwalletAllowed && state.missingDerivations.isNotEmpty()) return false - if (state.walletsDataFromStores.isEmpty()) return false - - val totalBalanceState = state.totalBalance?.state ?: return false - if (totalBalanceState == ProgressState.Loading || totalBalanceState == ProgressState.Refreshing) return false - - val balancesCount = state.walletsDataFromStores.map { - if (it.currencyData.amount == null) 0 else 1 - }.reduce { acc, i -> acc + i } - - if (balancesCount != state.walletsDataFromStores.size) return false - - return true } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt index e64b751f4f..e359de8e5a 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt @@ -22,6 +22,7 @@ class ParamCardCurrencyConverter : Converter AnalyticsParam.CurrencyType.Blockchain(Blockchain.Bitcoin) value.isSaltPay() -> AnalyticsParam.CurrencyType.Token(SaltPayWorkaround.tokenFrom(Blockchain.SaltPay)) + value.getBlockchain() != Blockchain.Unknown -> AnalyticsParam.CurrencyType.Blockchain(value.getBlockchain()) value.getPrimaryToken() != null -> AnalyticsParam.CurrencyType.Token(value.getPrimaryToken()!!) else -> null } ?: return null diff --git a/app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt b/app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt deleted file mode 100644 index e69de29bb2..0000000000 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 ea26d15848..4eb41fd759 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -31,6 +31,7 @@ import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.wallet.models.toBlockchainNetworks import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.features.wallet.redux.middlewares.handleBasicAnalyticsEvent import com.tangem.tap.network.NetworkConnectivity import com.tangem.tap.store import com.tangem.tap.tangemSdkManager @@ -117,6 +118,7 @@ class TapWalletManager { .doOnSuccess { Timber.d("Wallet stores fetched for ${userWallet.walletId}") store.dispatchOnMain(WalletAction.LoadData.Success) + handleBasicAnalyticsEvent() } .doOnFailure { error -> val errorAction = when (error) { @@ -190,6 +192,7 @@ class TapWalletManager { } if (data.card.isMultiwalletAllowed) { + dispatchOnMain(WalletAction.MultiWallet.ScheduleCheckForMissingDerivation) loadMultiWalletData(data) } else { loadSingleWalletData(data) @@ -212,9 +215,7 @@ class TapWalletManager { .filter { it.derivationPath != null && !scanResponse.hasDerivation(it.blockchain, it.derivationPath) } - if (missingDerivations.isNotEmpty()) { - store.dispatch(WalletAction.MultiWallet.AddMissingDerivations(missingDerivations)) - } + store.dispatch(WalletAction.MultiWallet.AddMissingDerivations(missingDerivations)) } private suspend fun loadSingleWalletData(data: ScanResponse) { diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresManager.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresManager.kt index e834cf0541..f1fdaff7aa 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresManager.kt @@ -9,6 +9,7 @@ import kotlinx.coroutines.flow.Flow interface WalletStoresManager { fun getAll(): Flow>> fun get(userWalletId: UserWalletId): Flow> + suspend fun getSync(userWalletId: UserWalletId): List suspend fun delete(userWalletsIds: List): CompletionResult suspend fun clear(): CompletionResult diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt index 219d7f4af1..22e86d2fa1 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt @@ -44,6 +44,10 @@ internal class DefaultWalletStoresManager( .distinctUntilChanged() } + override suspend fun getSync(userWalletId: UserWalletId): List { + return walletStoresRepository.getSync(userWalletId) + } + override suspend fun delete(userWalletsIds: List): CompletionResult { return walletStoresRepository.delete(userWalletsIds) .flatMap { walletManagersRepository.delete(userWalletsIds) } diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DummyWalletStoresManager.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DummyWalletStoresManager.kt index b1729a0b11..7657f2d47b 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DummyWalletStoresManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DummyWalletStoresManager.kt @@ -17,6 +17,10 @@ internal class DummyWalletStoresManager : WalletStoresManager { return emptyFlow() } + override suspend fun getSync(userWalletId: UserWalletId): List { + return emptyList() + } + override suspend fun delete(userWalletsIds: List): CompletionResult { return CompletionResult.Success(Unit) } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt index c261f4c7ba..dc3e074fac 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt @@ -102,6 +102,7 @@ sealed class WalletAction : Action { data class SetPrimaryToken(val token: Token) : MultiWallet() data class ShowWalletBackupWarning(val show: Boolean) : MultiWallet() object BackupWallet : MultiWallet() + object ScheduleCheckForMissingDerivation : MultiWallet() data class AddMissingDerivations(val blockchains: List) : MultiWallet() object ScanToGetDerivations : MultiWallet() } 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 49773a9854..0566b5d4a4 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 @@ -29,6 +29,9 @@ import org.rekotlin.StateType import java.math.BigDecimal import kotlin.properties.ReadOnlyProperty +/** + * @property derivationsCheckIsScheduled - used only for analytics + */ data class WalletState( val cardId: String = "", val state: ProgressState = ProgressState.Done, @@ -46,6 +49,7 @@ 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, ) : StateType { 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 e6632583c4..e6798ea6ca 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 @@ -167,6 +167,9 @@ class MultiWalletMiddleware { store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingWallet)) } } + is WalletAction.MultiWallet.AddMissingDerivations -> { + scope.launch { handleBasicAnalyticsEvent() } + } is WalletAction.MultiWallet.ScanToGetDerivations -> { val selectedWallet = userWalletsListManager.selectedUserWalletSync if (selectedWallet != null) { @@ -182,6 +185,7 @@ class MultiWalletMiddleware { selectedUserWallet: UserWallet, state: WalletState?, ) = scope.launch(Dispatchers.Default) { + dispatchOnMain(WalletAction.MultiWallet.ScheduleCheckForMissingDerivation) ScanCardProcessor.scan( analyticsEvent = null, cardId = selectedUserWallet.cardId, 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 a20c8b5b36..80b1ddfc2b 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 @@ -12,6 +12,8 @@ import com.tangem.core.analytics.Analytics import com.tangem.domain.common.extensions.withMainContext import com.tangem.operations.attestation.Attestation import com.tangem.operations.attestation.OnlineCardVerifier +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.MainScreen import com.tangem.tap.common.analytics.events.Token @@ -34,6 +36,7 @@ import com.tangem.tap.domain.failedRates import com.tangem.tap.domain.loadedRates 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.features.demo.DemoHelper import com.tangem.tap.features.home.redux.HomeAction import com.tangem.tap.features.send.redux.PrepareSendScreen @@ -55,6 +58,7 @@ 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.async @@ -108,6 +112,7 @@ class WalletMiddleware { walletState.walletManagers.map { walletManager -> async { globalState.tapWalletManager.loadWalletData(walletManager) } }.awaitAll() + handleBasicAnalyticsEvent() } else { val walletManager = walletState.getWalletManager(action.blockchain) ?: action.walletManager @@ -295,6 +300,7 @@ class WalletMiddleware { } is WalletAction.UserWalletChanged -> Unit is WalletAction.WalletStoresChanged -> { + store.dispatchOnMain(WalletAction.MultiWallet.ScheduleCheckForMissingDerivation) updateWalletStores(action.walletStores, walletState) fetchTotalFiatBalance(action.walletStores) findMissedDerivations(action.walletStores) @@ -489,4 +495,19 @@ class WalletMiddleware { } } } +} + +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, store.state.walletState, 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 afb523a5ca..711373d52f 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 @@ -185,7 +185,13 @@ class MultiWalletReducer { is WalletAction.MultiWallet.SetPrimaryToken -> state.copy(primaryToken = action.token) is WalletAction.MultiWallet.SaveCurrencies -> state is WalletAction.MultiWallet.ShowWalletBackupWarning -> state.copy(showBackupWarning = action.show) - is WalletAction.MultiWallet.AddMissingDerivations -> state.copy(missingDerivations = action.blockchains) + 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 7c622df177..15eacf8c99 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,13 +17,11 @@ import androidx.transition.TransitionInflater import by.kirich1409.viewbindingdelegate.viewBinding import coil.load import coil.size.Scale +import com.tangem.core.analytics.Analytics import com.tangem.core.ui.fragments.setStatusBarColor import com.tangem.core.ui.utils.OneTouchClickListener import com.tangem.domain.common.TapWorkarounds.isSaltPay import com.tangem.tap.MainActivity -import com.tangem.core.analytics.Analytics -import com.tangem.tap.common.analytics.converters.BasicSignInEventConverter -import com.tangem.tap.common.analytics.converters.BasicTopUpEventConverter import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.analytics.events.Portfolio import com.tangem.tap.common.extensions.show @@ -148,7 +146,6 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber Date: Wed, 25 Jan 2023 02:26:34 +0300 Subject: [PATCH 23/40] Updated on 2026-08-14 --- .../java/com/tangem/tap/common/analytics/events/SignIn.kt | 2 ++ .../tangem/tap/features/welcome/redux/WelcomeMiddleware.kt | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/SignIn.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/SignIn.kt index 5b7fff71ea..cad34430d9 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/SignIn.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/SignIn.kt @@ -12,6 +12,8 @@ sealed class SignIn( ) : AnalyticsEvent("Sign In", event, params, error) { class ScreenOpened : SignIn(event = "Sing In Screen Opened") + class CardWasScanned : SignIn(event = "Card Was Scanned") + class ButtonBiometricSignIn : SignIn(event = "Button - Biometric Sign In") class ButtonCardSignIn : SignIn(event = "Button - Card Sign In") } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt index 808f4ea74f..c1cdf0f74e 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt @@ -4,7 +4,7 @@ import android.content.Intent import com.tangem.common.doOnFailure import com.tangem.common.doOnSuccess import com.tangem.domain.common.ScanResponse -import com.tangem.tap.common.analytics.events.IntroductionProcess +import com.tangem.tap.common.analytics.events.SignIn import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.onUserWalletSelected import com.tangem.tap.common.redux.AppState @@ -99,7 +99,7 @@ internal class WelcomeMiddleware { useBiometricsForAccessCode = preferencesStorage.shouldSaveAccessCodes, ) ScanCardProcessor.scan( - analyticsEvent = IntroductionProcess.CardWasScanned(), + analyticsEvent = SignIn.CardWasScanned(), onSuccess = { scanResponse -> scope.launch { onCardScanned(scanResponse) } }, From 2633d5f7138dc05e2f8e5dafda3694f696d66d8b Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 25 Jan 2023 02:35:37 +0300 Subject: [PATCH 24/40] Updated on 2026-08-14 --- .../features/walletSelector/redux/WalletSelectorMiddleware.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt index fcf97e11db..4405407dcd 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt @@ -10,6 +10,7 @@ import com.tangem.core.analytics.Analytics import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.util.UserWalletId import com.tangem.tap.common.analytics.events.MyWallets +import com.tangem.tap.common.analytics.paramsInterceptor.BatchIdParamsInterceptor import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.onUserWalletSelected import com.tangem.tap.common.redux.AppState @@ -198,6 +199,9 @@ internal class WalletSelectorMiddleware { .doOnSuccess { val selectedUserWallet = userWalletsListManager.selectedUserWalletSync if (selectedUserWallet != null) { + val batchId = selectedUserWallet.scanResponse.card.batchId + Analytics.addParamsInterceptor(BatchIdParamsInterceptor(batchId)) + store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Wallet)) store.onUserWalletSelected(selectedUserWallet) } From 1d5dcc057724fa39c0d677ae35c6d199ad3a5dea Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 16 Dec 2022 09:58:29 +0300 Subject: [PATCH 25/40] Updated on 2026-08-14 --- .../com/tangem/tap/common/DialogManager.kt | 14 +++-- .../redux/OnboardingWalletMiddleware.kt | 53 +++++++++---------- .../wallet/redux/OnboardingWalletState.kt | 13 +++-- ...Dialog.kt => InterruptOnboardingDialog.kt} | 7 +-- .../wallet/saltPay/dialog/SaltPayDialog.kt | 2 - 5 files changed, 44 insertions(+), 45 deletions(-) rename app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/{TryToInterruptRegistrationDialog.kt => InterruptOnboardingDialog.kt} (79%) diff --git a/app/src/main/java/com/tangem/tap/common/DialogManager.kt b/app/src/main/java/com/tangem/tap/common/DialogManager.kt index f25d1ddf4c..94dd3ff6c1 100644 --- a/app/src/main/java/com/tangem/tap/common/DialogManager.kt +++ b/app/src/main/java/com/tangem/tap/common/DialogManager.kt @@ -17,10 +17,11 @@ import com.tangem.tap.features.onboarding.AddressInfoBottomSheetDialog import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.onboarding.products.twins.ui.dialog.CreateWalletInterruptDialog import com.tangem.tap.features.onboarding.products.wallet.redux.BackupDialog +import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingDialog +import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.InterruptOnboardingDialog import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.NoFundsForActivationDialog import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.RegistrationErrorDialog import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.SaltPayDialog -import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.TryToInterruptRegistrationDialog import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.AddMoreBackupCardsDialog import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.BackupInProgressDialog import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.ConfirmDiscardingBackupDialog @@ -72,8 +73,8 @@ class DialogManager : StoreSubscriber { is AppDialog.ScanFailsDialog -> ScanFailsDialog.create(context) is AppDialog.AddressInfoDialog -> AddressInfoBottomSheetDialog(state.dialog, context) is AppDialog.TestActionsDialog -> TestActionsBottomSheetDialog(state.dialog, context) - is TwinCardsAction.Wallet.ShowInterruptDialog -> - CreateWalletInterruptDialog.create(state.dialog, context) + is TwinCardsAction.Wallet.ShowInterruptDialog -> CreateWalletInterruptDialog.create(state.dialog, context) + is OnboardingDialog.InterruptOnboarding -> InterruptOnboardingDialog.create(context, state.dialog) is WalletConnectDialog.UnsupportedCard -> SimpleAlertDialog.create( titleRes = R.string.wallet_connect_title, @@ -109,10 +110,8 @@ class DialogManager : StoreSubscriber { ChooseNetworkDialog.create(state.dialog.session, state.dialog.networks, context) is WalletConnectDialog.ClipboardOrScanQr -> ClipboardOrScanQrDialog.create(state.dialog.clipboardUri, context) - is WalletConnectDialog.RequestTransaction -> - TransactionDialog.create(state.dialog.dialogData, context) - is WalletConnectDialog.PersonalSign -> - PersonalSignDialog.create(state.dialog.data, context) + is WalletConnectDialog.RequestTransaction -> TransactionDialog.create(state.dialog.dialogData, context) + is WalletConnectDialog.PersonalSign -> PersonalSignDialog.create(state.dialog.data, context) is WalletConnectDialog.BnbTransactionDialog -> BnbTransactionDialog.create( data = state.dialog.data, @@ -132,7 +131,6 @@ class DialogManager : StoreSubscriber { is BackupDialog.UnfinishedBackupFound -> UnfinishedBackupFoundDialog.create(context) is BackupDialog.ConfirmDiscardingBackup -> ConfirmDiscardingBackupDialog.create(context) is SaltPayDialog.Activation.NoGas -> NoFundsForActivationDialog.create(context) - is SaltPayDialog.Activation.TryToInterrupt -> TryToInterruptRegistrationDialog.create(context, state.dialog) is SaltPayDialog.Activation.OnError -> RegistrationErrorDialog.create(context, state.dialog) is WalletDialog.CurrencySelectionDialog -> CurrencySelectionDialog.create(state.dialog, context) is WalletDialog.ChooseTradeActionDialog -> ChooseTradeActionBottomSheetDialog(context) 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 84e02b7b66..939236339c 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 @@ -22,7 +22,6 @@ import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.home.redux.HomeAction import com.tangem.tap.features.onboarding.OnboardingHelper -import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.SaltPayDialog import com.tangem.tap.features.onboarding.products.wallet.saltPay.redux.OnboardingSaltPayAction import com.tangem.tap.features.onboarding.products.wallet.saltPay.redux.OnboardingSaltPayState import com.tangem.tap.features.wallet.redux.Artwork @@ -188,12 +187,7 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: } newAction?.let { store.dispatch(it) } } - OnboardingWalletAction.OnBackPressed -> { - when { - onboardingWalletState.isSaltPay -> handleOnBackPressedSaltPay(onboardingWalletState) - else -> handleOnBackPressed(onboardingWalletState) - } - } + OnboardingWalletAction.OnBackPressed -> handleOnBackPressed(onboardingWalletState) } } @@ -408,30 +402,33 @@ private fun initSaltPayOnBackupFinishedIfNeeded( } } -private fun handleOnBackPressedSaltPay(state: OnboardingWalletState) { +private fun handleOnBackPressed(state: OnboardingWalletState) { when (state.backupState.backupStep) { - BackupStep.Finished -> { - store.dispatchDialogShow( - SaltPayDialog.Activation.TryToInterrupt( - onOk = { store.dispatch(NavigationAction.PopBackTo()) }, - onCancel = { /* do nothing */ }, - ), - ) + BackupStep.InitBackup, BackupStep.ScanOriginCard, BackupStep.AddBackupCards, BackupStep.EnterAccessCode, + BackupStep.ReenterAccessCode, BackupStep.SetAccessCode, BackupStep.WritePrimaryCard, + -> { + showInterruptOnboardingDialog() + } + is BackupStep.WriteBackupCard -> { + store.dispatch(GlobalAction.ShowDialog(BackupDialog.BackupInProgress)) + } + BackupStep.Finished -> { + if (state.isSaltPay) { + showInterruptOnboardingDialog() + } else { + store.dispatch(NavigationAction.PopBackTo()) + } } - else -> handleOnBackPressed(state) } } -private fun handleOnBackPressed(state: OnboardingWalletState) { - when (state.backupState.backupStep) { - BackupStep.InitBackup, BackupStep.Finished -> store.dispatch(NavigationAction.PopBackTo()) - BackupStep.ScanOriginCard, BackupStep.AddBackupCards, BackupStep.EnterAccessCode, - BackupStep.ReenterAccessCode, BackupStep.SetAccessCode, BackupStep.WritePrimaryCard, - -> { - store.dispatch(BackupAction.DiscardBackup) - store.dispatch(NavigationAction.PopBackTo()) - } - is BackupStep.WriteBackupCard -> - store.dispatch(GlobalAction.ShowDialog(BackupDialog.BackupInProgress)) - } +private fun showInterruptOnboardingDialog() { + store.dispatchDialogShow( + OnboardingDialog.InterruptOnboarding( + onOk = { + store.dispatch(BackupAction.DiscardBackup) + store.dispatch(NavigationAction.PopBackTo()) + }, + ), + ) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletState.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletState.kt index 6fc233d092..aa04272085 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletState.kt @@ -2,6 +2,7 @@ package com.tangem.tap.features.onboarding.products.wallet.redux import android.graphics.Bitmap import com.tangem.common.CardFilter +import com.tangem.common.extensions.VoidCallback import com.tangem.domain.common.SaltPayWorkaround import com.tangem.tap.common.redux.StateDialog import com.tangem.tap.features.onboarding.products.wallet.saltPay.redux.OnboardingSaltPayState @@ -104,9 +105,13 @@ sealed class BackupStep { object Finished : BackupStep() } +sealed class OnboardingDialog: StateDialog { + data class InterruptOnboarding(val onOk: VoidCallback) : BackupDialog() +} + sealed class BackupDialog : StateDialog { - object AddMoreBackupCards : StateDialog - object BackupInProgress : StateDialog - object UnfinishedBackupFound : StateDialog - object ConfirmDiscardingBackup : StateDialog + object AddMoreBackupCards : BackupDialog() + object BackupInProgress : BackupDialog() + object UnfinishedBackupFound : BackupDialog() + object ConfirmDiscardingBackup : BackupDialog() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/TryToInterruptRegistrationDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/InterruptOnboardingDialog.kt similarity index 79% rename from app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/TryToInterruptRegistrationDialog.kt rename to app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/InterruptOnboardingDialog.kt index 6f02df9120..1636675ae1 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/TryToInterruptRegistrationDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/InterruptOnboardingDialog.kt @@ -4,20 +4,21 @@ import android.app.Dialog import android.content.Context import androidx.appcompat.app.AlertDialog import com.tangem.tap.common.extensions.dispatchDialogHide +import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingDialog import com.tangem.tap.store import com.tangem.wallet.R /** [REDACTED_AUTHOR] */ -class TryToInterruptRegistrationDialog { +class InterruptOnboardingDialog { companion object { - fun create(context: Context, dialog: SaltPayDialog.Activation.TryToInterrupt): Dialog { + fun create(context: Context, dialog: OnboardingDialog.InterruptOnboarding): Dialog { return AlertDialog.Builder(context).apply { setTitle(context.getString(R.string.onboarding_exit_alert_title)) setMessage(context.getString(R.string.onboarding_exit_alert_message)) setPositiveButton(R.string.common_ok) { _, _ -> dialog.onOk() } - setNegativeButton(R.string.common_cancel) { _, _ -> dialog.onCancel() } + setNegativeButton(R.string.common_cancel) { _, _ -> } setOnDismissListener { store.dispatchDialogHide() } setCancelable(false) }.create() diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/SaltPayDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/SaltPayDialog.kt index fda1331a37..b8b512aef1 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/SaltPayDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/SaltPayDialog.kt @@ -1,6 +1,5 @@ package com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog -import com.tangem.common.extensions.VoidCallback import com.tangem.tap.common.redux.StateDialog import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayActivationError @@ -11,6 +10,5 @@ sealed class SaltPayDialog : StateDialog { sealed class Activation : SaltPayDialog() { object NoGas : SaltPayDialog() data class OnError(val error: SaltPayActivationError) : SaltPayDialog() - data class TryToInterrupt(val onOk: VoidCallback, val onCancel: VoidCallback) : SaltPayDialog() } } \ No newline at end of file From 37f3d52362792aaa4d0db4ab10477b7e827aee3a Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 16 Jan 2023 20:43:47 +0300 Subject: [PATCH 26/40] Updated on 2026-08-14 --- .../tap/domain/scanCard/ScanCardProcessor.kt | 9 +-------- .../features/home/compose/views/HomeButtons.kt | 1 + .../tap/features/home/redux/HomeMiddleware.kt | 17 ++++++++++------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt index b9e8f526f9..4dc0722d61 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt @@ -70,7 +70,6 @@ object ScanCardProcessor { result .doOnFailure { error -> - onProgressStateChange(false) onScanStateChange(false) onFailure(error) } @@ -87,7 +86,6 @@ object ScanCardProcessor { nextHandler = { scanResponse1 -> showDisclaimerIfNeed( scanResponse = scanResponse1, - onProgressStateChange = onProgressStateChange, disclaimerWillShow = disclaimerWillShow, onFailure = onFailure, nextHandler = { scanResponse2 -> @@ -144,7 +142,6 @@ object ScanCardProcessor { private suspend inline fun showDisclaimerIfNeed( scanResponse: ScanResponse, crossinline disclaimerWillShow: () -> Unit = {}, - crossinline onProgressStateChange: suspend (showProgress: Boolean) -> Unit, crossinline nextHandler: suspend (ScanResponse) -> Unit, crossinline onFailure: suspend (error: TangemError) -> Unit, ) { @@ -167,7 +164,6 @@ object ScanCardProcessor { }, onDismiss = { scope.launch(Dispatchers.Main) { - onProgressStateChange(false) onFailure(TangemSdkError.UserCancelled()) } }, @@ -208,14 +204,12 @@ object ScanCardProcessor { } else { delay(DELAY_SDK_DIALOG_CLOSE) onSuccess(scanResponse) - onProgressStateChange(false) } } is Result.Failure -> { SaltPayExceptionHandler.handle(result.error) delay(DELAY_SDK_DIALOG_CLOSE) onFailure(TangemSdkError.ExceptionError(result.error)) - onProgressStateChange(false) } } } @@ -223,10 +217,10 @@ object ScanCardProcessor { delay(DELAY_SDK_DIALOG_CLOSE) if (scanResponse.card.backupStatus?.isActive == false) { showSaltPayTapVisaLogoCardDialog() + onProgressStateChange(false) } else { onSuccess(scanResponse) } - onProgressStateChange(false) } } else { if (OnboardingHelper.isOnboardingCase(scanResponse)) { @@ -242,7 +236,6 @@ object ScanCardProcessor { } else { delay(DELAY_SDK_DIALOG_CLOSE) onSuccess(scanResponse) - onProgressStateChange(false) } } } diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtons.kt b/app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtons.kt index cea593e6fe..b5ca216aeb 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtons.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtons.kt @@ -95,6 +95,7 @@ fun ProgressButton( Button( modifier = modifier, onClick = onClick, + enabled = !inProgress, colors = ButtonDefaults.textButtonColors( backgroundColor = backgroundColor, contentColor = contentColor, diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt index b85a6601c5..76048ed0f4 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt @@ -79,10 +79,9 @@ private fun readCard(analyticsEvent: AnalyticsEvent?) = scope.launch { onProgressStateChange = { showProgress -> if (showProgress) { changeButtonState(ButtonState.PROGRESS) + } else { + changeButtonState(ButtonState.ENABLED) } - // else { //todo hide this because - // changeButtonState(ButtonState.ENABLED) - // } }, onScanStateChange = { scanInProgress -> store.dispatch(HomeAction.ScanInProgress(scanInProgress)) @@ -103,19 +102,23 @@ private fun readCard(analyticsEvent: AnalyticsEvent?) = scope.launch { scope.launch { store.onUserWalletSelected(userWallet) } } .doOnResult { - changeButtonState(ButtonState.ENABLED) - store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Wallet)) + navigateTo(AppScreen.Wallet) } } else { store.onCardScanned(scanResponse) - changeButtonState(ButtonState.ENABLED) - store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Wallet)) + navigateTo(AppScreen.Wallet) } } }, ) } +private suspend fun navigateTo(appScreen: AppScreen) { + store.dispatchOnMain(NavigationAction.NavigateTo(appScreen)) + delay(200) + changeButtonState(ButtonState.ENABLED) +} + private fun changeButtonState(state: ButtonState) { store.dispatchOnMain(HomeAction.ChangeScanCardButtonState(IndeterminateProgressButton(state))) } \ No newline at end of file From 9558000f09d8ccbe44ee43914a7e366558498c89 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 26 Jan 2023 21:52:45 +0300 Subject: [PATCH 27/40] Updated on 2026-08-14 --- buildSrc/src/main/java/Versions.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/java/Versions.kt b/buildSrc/src/main/java/Versions.kt index 6b4b0626f5..c0d9908ef0 100644 --- a/buildSrc/src/main/java/Versions.kt +++ b/buildSrc/src/main/java/Versions.kt @@ -59,7 +59,7 @@ object Versions { // endregion Other libraries // region Tangem - const val tangemBlockchainSdk = "develop-151" + const val tangemBlockchainSdk = "develop-152" // const val tangemBlockchainSdk = "0.0.1" const val tangemCardSgk = "develop-179" From d759651934555fafa7b367d92487ee7e128a9f0b Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 26 Jan 2023 21:55:32 +0300 Subject: [PATCH 28/40] Updated on 2026-08-14 --- .../wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt index ce3390eba1..b7bcb4761b 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt @@ -6,11 +6,11 @@ import com.tangem.blockchain.extensions.successOr import com.tangem.common.Filter import com.tangem.common.extensions.guard import com.tangem.common.services.Result -import com.tangem.domain.common.extensions.successOr -import com.tangem.domain.common.extensions.withMainContext +import com.tangem.core.analytics.Analytics import com.tangem.datasource.api.paymentology.KYCStatus import com.tangem.datasource.api.paymentology.RegistrationResponse -import com.tangem.core.analytics.Analytics +import com.tangem.domain.common.extensions.successOr +import com.tangem.domain.common.extensions.withMainContext import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.extensions.dispatchDebugErrorNotification import com.tangem.tap.common.extensions.dispatchOnMain @@ -286,7 +286,7 @@ suspend fun SaltPayActivationManager.update( return Result.Failure(ex) } - // checkGasIfNeeded(this, newStep).successOr { return it } + checkGasIfNeeded(this, newStep).successOr { return it } Timber.d("update: success: %s", newStep) return Result.Success(newStep) From 2dcee55f99022c30f8e6faca50f5c9c8ac387ae8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 27 Jan 2023 13:17:56 +0300 Subject: [PATCH 29/40] Updated on 2026-08-14 --- .../implementation/DefaultTotalFiatBalanceCalculator.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt b/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt index 12fd8abb1e..71f3f0a663 100644 --- a/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt +++ b/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt @@ -43,7 +43,8 @@ internal class DefaultTotalFiatBalanceCalculator : TotalFiatBalanceCalculator { private fun Sequence.mapToStatus(): Sequence { return this.map { walletData -> - when (walletData.status) { + if (walletData.fiatRate == null) TotalFiatBalanceStatus.Error + else when (walletData.status) { is WalletDataModel.VerifiedOnline, is WalletDataModel.SameCurrencyTransactionInProgress, is WalletDataModel.TransactionInProgress, From 6d1117a3e0c10b5f09373d9d00e9b4644faa3651 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 27 Jan 2023 14:31:27 +0300 Subject: [PATCH 30/40] Updated on 2026-08-14 --- .../tap/domain/model/WalletDataModel.kt | 2 + .../model/builders/WalletStoreBuilder.kt | 8 +- .../wallet/redux/middlewares/Mapper.kt | 121 ++++++++++++------ .../redux/middlewares/WalletMiddleware.kt | 2 +- 4 files changed, 94 insertions(+), 39 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/model/WalletDataModel.kt b/app/src/main/java/com/tangem/tap/domain/model/WalletDataModel.kt index 4462f4d8ec..3429afa07c 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/WalletDataModel.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/WalletDataModel.kt @@ -14,6 +14,7 @@ import java.math.BigDecimal * @param existentialDeposit Amount that must be held on currency's balance, if balance is below that amount all * founds will be destroyed. Null if currency don't have existential deposit * @param fiatRate Wallet's fiat rate, used to calculate fiat balance. Null if not provided + * @param isCardSingleToken shows that [Currency] is a card token * */ data class WalletDataModel( val currency: Currency, @@ -21,6 +22,7 @@ data class WalletDataModel( val walletAddresses: List, val existentialDeposit: BigDecimal?, val fiatRate: BigDecimal?, + val isCardSingleToken: Boolean, ) { /** diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt index e76a291668..2bfbe6283d 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt @@ -73,13 +73,13 @@ private class WalletMangerWalletStoreBuilderImpl( override fun build(): WalletStoreModel { val wallet = walletManager.wallet val blockchainWalletData = wallet.blockchain.toBlockchainWalletData(walletManager) - val tokenWalletsData = wallet.getTokens().firstOrNull()?.toTokenWalletData(walletManager) + val tokenWalletsData = walletManager.cardTokens.map { it.toTokenWalletData(walletManager) } return WalletStoreModel( userWalletId = userWalletId, blockchain = wallet.blockchain, derivationPath = wallet.publicKey.derivationPath, - walletsData = (listOf(blockchainWalletData) + listOfNotNull(tokenWalletsData)), + walletsData = (listOf(blockchainWalletData) + tokenWalletsData), walletRent = null, walletManager = walletManager, blockchainNetwork = BlockchainNetwork.fromWalletManager(walletManager), @@ -97,6 +97,7 @@ private fun BlockchainNetwork.getBlockchainWalletData(walletManager: WalletManag walletAddresses = walletManager?.wallet?.createAddressesData().orEmpty(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, + isCardSingleToken = false ) } @@ -113,6 +114,7 @@ private fun BlockchainNetwork.getTokensWalletsData(walletManager: WalletManager? walletAddresses = walletManager?.wallet?.createAddressesData().orEmpty(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, + isCardSingleToken = walletManager?.cardTokens?.contains(token) ?: false ) } } @@ -128,6 +130,7 @@ private fun Blockchain.toBlockchainWalletData(walletManager: WalletManager): Wal walletAddresses = wallet.createAddressesData(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, + isCardSingleToken = false, ) } @@ -143,6 +146,7 @@ private fun Token.toTokenWalletData(walletManager: WalletManager): WalletDataMod walletAddresses = wallet.createAddressesData(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, + isCardSingleToken = walletManager.cardTokens.contains(this) ) } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt index 75b79e6a61..8209e5f65a 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt @@ -1,6 +1,6 @@ package com.tangem.tap.features.wallet.redux.middlewares -import com.tangem.blockchain.common.AmountType +import com.tangem.blockchain.common.Blockchain import com.tangem.common.extensions.isZero import com.tangem.tap.common.extensions.stripZeroPlainString import com.tangem.tap.common.extensions.toFiatRateString @@ -10,7 +10,6 @@ import com.tangem.tap.common.extensions.toFormattedFiatValue 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.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.TotalBalance import com.tangem.tap.features.wallet.models.WalletRent import com.tangem.tap.features.wallet.redux.ProgressState @@ -22,13 +21,12 @@ import com.tangem.tap.features.wallet.ui.BalanceStatus import com.tangem.tap.features.wallet.ui.BalanceWidgetData import com.tangem.tap.features.wallet.ui.TokenData import com.tangem.tap.store +import timber.log.Timber import java.math.BigDecimal -internal fun List.mapToReduxModels( - isMultiWalletAllowed: Boolean, -): List { +internal fun List.mapToReduxModels(): List { return this.map { walletStoreModel -> - walletStoreModel.mapToReduxModel(isMultiWalletAllowed) + walletStoreModel.mapToReduxModel() } } @@ -44,19 +42,20 @@ internal fun TotalFiatBalance.mapToReduxModel(): TotalBalance { ) } -internal fun WalletStoreModel.mapToReduxModel( - isMultiWalletAllowed: Boolean, -): WalletStore { +internal fun WalletStoreModel.mapToReduxModel(): WalletStore { + val appCurrencySymbol = store.state.globalState.appCurrency.symbol return WalletStore( walletManager = walletManager, blockchainNetwork = blockchainNetwork, - walletsData = walletsData.mapToReduxModel(isMultiWalletAllowed, walletRent), + walletsData = walletsData.mapToReduxModel(walletRent, appCurrencySymbol), ) + .updateTokenModels(blockchain) + .setupIfHadCardSingleToken(blockchain, walletsData, appCurrencySymbol) } private fun List.mapToReduxModel( - isMultiWalletAllowed: Boolean, walletRent: WalletStoreModel.WalletRent?, + appCurrencySymbol: String, ): List { return this.map { walletDataModel -> with(walletDataModel) { @@ -65,13 +64,11 @@ private fun List.mapToReduxModel( decimals = currency.decimals, currency = currency.currencySymbol, ) - val appCurrency = store.state.globalState.appCurrency val fiatAmount = fiatRate?.let { status.amount.toFiatValue(it) } val fiatAmountFormatted = fiatAmount ?.takeIf { !status.isErrorStatus } - ?.toFormattedFiatValue(appCurrency.symbol) - val fiatRateFormatted = fiatRate?.toFiatRateString(appCurrency.symbol) - val blockchainAmountValue = getBlockchainAmount() + ?.toFormattedFiatValue(appCurrencySymbol) + val fiatRateFormatted = fiatRate?.toFiatRateString(appCurrencySymbol) WalletData( currency = currency, @@ -86,9 +83,7 @@ private fun List.mapToReduxModel( fiatRateString = fiatRateFormatted, pendingTransactions = status.pendingTransactions, mainButton = WalletMainButton.SendButton( - enabled = !blockchainAmountValue.isZero() - && !status.amount.isZero() - && status.pendingTransactions.isEmpty(), + enabled = !status.amount.isZero() && status.pendingTransactions.isEmpty(), ), walletRent = walletRent?.let { WalletRent( @@ -108,25 +103,12 @@ private fun List.mapToReduxModel( }, currency = currency.currencyName, currencySymbol = currency.currencySymbol, - blockchainAmount = blockchainAmountValue, + blockchainAmount = BigDecimal.ZERO, amount = amount, amountFormatted = amountFormatted, fiatAmount = fiatAmount, fiatAmountFormatted = fiatAmountFormatted, - token = when { - !isMultiWalletAllowed && currency is Currency.Token -> { - TokenData( - amount = amount, - amountFormatted = amountFormatted, - fiatAmount = fiatAmount, - fiatAmountFormatted = fiatAmountFormatted, - tokenSymbol = currency.currencySymbol, - fiatRate = fiatRate, - fiatRateString = fiatRateFormatted, - ) - } - else -> null - }, + token = null, amountToCreateAccount = (status as? WalletDataModel.NoAccount) ?.amountToCreateAccount ?.toString(), @@ -137,7 +119,74 @@ private fun List.mapToReduxModel( } } -private fun WalletDataModel.getBlockchainAmount(): BigDecimal { - val walletStore = store.state.walletState.getWalletStore(currency) ?: return BigDecimal.ZERO - return walletStore.walletManager?.wallet?.amounts?.get(AmountType.Coin)?.value ?: BigDecimal.ZERO +private fun WalletStore.updateTokenModels(blockchain: Blockchain): WalletStore { + val foundBlockchains = this.walletsData.filter { + it.currency.isBlockchain() && it.currency.blockchain == blockchain + } + if (foundBlockchains.size != 1) { + val warningMessage = "Can't update information about Tokens in the WalletData list, because " + + "of the WalletStore doesn't contains the Blockchain: %s, or contains more than one" + Timber.w(warningMessage, blockchain.id) + return this + } + + val blockchainAmountValue = foundBlockchains.first().currencyData.blockchainAmount ?: BigDecimal.ZERO + val updatedTokensWalletData = walletsData.filter { it.currency.isToken() }.map { + it.copy( + mainButton = when (it.mainButton) { + is WalletMainButton.SendButton -> { + WalletMainButton.SendButton(it.mainButton.enabled && !blockchainAmountValue.isZero()) + } + is WalletMainButton.CreateWalletButton -> it.mainButton + }, + currencyData = it.currencyData.copy( + blockchainAmount = blockchainAmountValue, + ), + ) + } + return updateWallets(updatedTokensWalletData) +} + +private fun WalletStore.setupIfHadCardSingleToken( + blockchain: Blockchain, + walletsDataModel: List, + appCurrencySymbol: String, +): WalletStore { + // Card with single token contains only 2 model - blockchain and token + if (walletsData.size != 2) return this + + val blockchainWalletData = walletsData.firstOrNull { + it.currency.isBlockchain() && it.currency.blockchain == blockchain + } + val cardSingleTokenWalletData = walletsDataModel.firstOrNull { + it.currency.isToken() && it.currency.blockchain == blockchain && it.isCardSingleToken + } + if (blockchainWalletData == null || cardSingleTokenWalletData == null) return this + + val blockchainWalletDataWithSingleToken = blockchainWalletData.copy( + currencyData = blockchainWalletData.currencyData.copy( + token = cardSingleTokenWalletData.toTokenData(appCurrencySymbol), + ), + ) + return updateWallets(listOf(blockchainWalletDataWithSingleToken)) +} + +private fun WalletDataModel.toTokenData(appCurrencySymbol: String): TokenData { + val amount = status.amount + val fiatAmount = fiatRate?.let { status.amount.toFiatValue(it) } + + return TokenData( + amount = amount, + amountFormatted = amount.toFormattedCurrencyString( + decimals = currency.decimals, + currency = currency.currencySymbol, + ), + fiatAmount = fiatAmount, + fiatAmountFormatted = fiatAmount + ?.takeIf { !status.isErrorStatus } + ?.toFormattedFiatValue(appCurrencySymbol), + tokenSymbol = currency.currencySymbol, + fiatRate = fiatRate, + fiatRateString = fiatRate?.toFiatRateString(appCurrencySymbol), + ) } \ No newline at end of file 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 80b1ddfc2b..03b26092b2 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 @@ -318,7 +318,7 @@ class WalletMiddleware { } } - val reduxWalletStores = wallStores.mapToReduxModels(state.isMultiwalletAllowed) + val reduxWalletStores = wallStores.mapToReduxModels() store.dispatchOnMain( WalletAction.WalletStoresChanged.UpdateWalletStores( reduxWalletStores = reduxWalletStores, From 64542aca34016716b6a4673252afad4805485810 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 27 Jan 2023 14:43:27 +0300 Subject: [PATCH 31/40] Updated on 2026-08-14 --- .../tap/features/wallet/ui/wallet/SingleWalletView.kt | 8 ++++++-- app/src/main/res/layout/fragment_wallet.xml | 9 ++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt index 18ebc3dd4b..e7587a6983 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt @@ -12,6 +12,7 @@ import com.tangem.tap.common.extensions.show import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.PendingTransaction +import com.tangem.tap.features.wallet.models.PendingTransactionType import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletData import com.tangem.tap.features.wallet.redux.WalletMainButton @@ -72,8 +73,11 @@ class SingleWalletView : WalletView() { } private fun showPendingTransactionsIfPresent(pendingTransactions: List) { - pendingTransactionAdapter.submitList(pendingTransactions) - binding?.rvPendingTransaction?.show(pendingTransactions.isNotEmpty()) + val knownTransactions = pendingTransactions.filterNot { + it.type == PendingTransactionType.Unknown + } + pendingTransactionAdapter.submitList(knownTransactions) + binding?.rvPendingTransaction?.show(knownTransactions.isNotEmpty()) } private fun setupBalance(state: WalletState, primaryWallet: WalletData) { diff --git a/app/src/main/res/layout/fragment_wallet.xml b/app/src/main/res/layout/fragment_wallet.xml index b3d1b54730..50b77c777f 100644 --- a/app/src/main/res/layout/fragment_wallet.xml +++ b/app/src/main/res/layout/fragment_wallet.xml @@ -151,13 +151,12 @@ android:id="@+id/rv_pending_transaction" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="16dp" + android:layout_marginTop="12dp" android:nestedScrollingEnabled="false" android:overScrollMode="never" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/l_card_total_balance" - app:layout_goneMarginTop="12dp" /> + app:layout_constraintTop_toBottomOf="@id/rv_warning_messages" /> + app:layout_constraintTop_toBottomOf="@id/l_card_total_balance" /> + app:layout_constraintTop_toBottomOf="@id/rv_warning_messages" /> Date: Fri, 27 Jan 2023 13:47:40 +0300 Subject: [PATCH 32/40] Updated on 2026-08-14 --- .../tangem/tap/common/extensions/Specific.kt | 2 +- .../tap/features/walletSelector/ui/Mapper.kt | 13 +++-- .../walletSelector/ui/components/MockData.kt | 6 +-- .../ui/components/WalletItem.kt | 53 +++++++++++++------ .../walletSelector/ui/model/UserWalletItem.kt | 11 ++-- core/ui/src/main/res/drawable/ic_alert_24.xml | 9 ++++ 6 files changed, 66 insertions(+), 28 deletions(-) create mode 100644 core/ui/src/main/res/drawable/ic_alert_24.xml diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt index 795bc8e268..8ff6116155 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt @@ -68,7 +68,7 @@ fun BigDecimal.toFormattedFiatValue( ): String { val fiatValue = this.setScale(2, RoundingMode.HALF_UP) .let { if (formatWithSpaces) it.formatWithSpaces() else it } - return " ${fiatValue}  $fiatCurrencyName" + return " $fiatValue $fiatCurrencyName" } fun BigDecimal.stripZeroPlainString(): String = this.stripTrailingZeros().toPlainString() diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt index e5dc088a55..5d18c5baa9 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt @@ -9,6 +9,7 @@ import com.tangem.tap.features.walletSelector.redux.WalletSelectorState import com.tangem.tap.features.walletSelector.ui.model.MultiCurrencyUserWalletItem import com.tangem.tap.features.walletSelector.ui.model.SingleCurrencyUserWalletItem import com.tangem.tap.features.walletSelector.ui.model.UserWalletItem +import java.math.BigDecimal internal fun WalletSelectorScreenState.updateWithNewState( newState: WalletSelectorState, @@ -50,10 +51,14 @@ private fun List.toUiModels( ): Sequence { return this.asSequence().map { userWalletModel -> with(userWalletModel) { - val balance = UserWalletItem.Balance( - amount = fiatBalance.amount.toFormattedFiatValue(appCurrency.symbol), - isLoading = fiatBalance is TotalFiatBalance.Loading, - ) + val formatAmount = { amount: BigDecimal -> + amount.toFormattedFiatValue(appCurrency.symbol) + } + val balance = when (fiatBalance) { + is TotalFiatBalance.Error -> UserWalletItem.Balance.Error(formatAmount(fiatBalance.amount)) + is TotalFiatBalance.Loaded -> UserWalletItem.Balance.Loaded(formatAmount(fiatBalance.amount)) + is TotalFiatBalance.Loading -> UserWalletItem.Balance.Loading + } when (type) { is UserWalletModel.Type.MultiCurrency -> MultiCurrencyUserWalletItem( id = id, diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/MockData.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/MockData.kt index 65349386dc..db09868d03 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/MockData.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/MockData.kt @@ -9,9 +9,8 @@ import com.tangem.tap.features.walletSelector.ui.model.UserWalletItem internal object MockData { private val multiCurrencyUserWallet = MultiCurrencyUserWalletItem( id = UserWalletId("wallet_1"), - balance = UserWalletItem.Balance( + balance = UserWalletItem.Balance.Loaded( amount = "6781.05 $", - isLoading = false, ), name = "Wallet", imageUrl = "https://app.tangem.com/cards/card_default.png", @@ -22,9 +21,8 @@ internal object MockData { private val singleCurrencyUserWallet = SingleCurrencyUserWalletItem( id = UserWalletId("wallet_4"), - balance = UserWalletItem.Balance( + balance = UserWalletItem.Balance.Loaded( amount = "6781.05 $", - isLoading = false, ), name = "Wallet", imageUrl = "https://app.tangem.com/cards/card_default.png", diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt index 3b6f021dba..6e67669815 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt @@ -180,15 +180,24 @@ private fun TokensInfo( if (isLocked) { LockedPlaceholder() } else { - if (balance.isLoading) { - LoadingTokensInfo( - isMultiCurrencyWallet = tokensCount != null, - ) - } else { - LoadedTokensInfo( - balanceAmount = balance.amount, - tokensCount = tokensCount, - ) + when (balance) { + is UserWalletItem.Balance.Error -> { + LoadedTokensInfo( + balanceAmount = balance.amount, + tokensCount = tokensCount, + showWarning = true, + ) + } + is UserWalletItem.Balance.Loaded -> { + LoadedTokensInfo( + balanceAmount = balance.amount, + tokensCount = tokensCount, + showWarning = false, + ) + } + is UserWalletItem.Balance.Loading -> { + LoadingTokensInfo(isMultiCurrencyWallet = tokensCount != null) + } } } } @@ -234,17 +243,31 @@ private fun LoadedTokensInfo( modifier: Modifier = Modifier, balanceAmount: String, tokensCount: Int?, + showWarning: Boolean, ) { Column( modifier = modifier, horizontalAlignment = Alignment.End, ) { - Text( - text = balanceAmount, - style = TangemTheme.typography.subtitle1, - color = TangemTheme.colors.text.primary1, - textAlign = TextAlign.End, - ) + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4), + ) { + Text( + text = balanceAmount, + style = TangemTheme.typography.subtitle1, + color = TangemTheme.colors.text.primary1, + textAlign = TextAlign.End, + ) + if (showWarning) { + Icon( + modifier = Modifier.size(TangemTheme.dimens.size16), + painter = painterResource(id = R.drawable.ic_alert_24), + tint = TangemTheme.colors.icon.attention, + contentDescription = null, + ) + } + } if (tokensCount != null) { SpacerH2() Text( diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/model/UserWalletItem.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/model/UserWalletItem.kt index ddd7518ca6..eeca9d7611 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/model/UserWalletItem.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/model/UserWalletItem.kt @@ -9,10 +9,13 @@ internal sealed interface UserWalletItem { val balance: Balance val isLocked: Boolean - data class Balance( - val amount: String, - val isLoading: Boolean, - ) + sealed interface Balance { + object Loading : Balance + + data class Error(val amount: String) : Balance + + data class Loaded(val amount: String) : Balance + } } internal data class MultiCurrencyUserWalletItem( diff --git a/core/ui/src/main/res/drawable/ic_alert_24.xml b/core/ui/src/main/res/drawable/ic_alert_24.xml new file mode 100644 index 0000000000..231b822412 --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_alert_24.xml @@ -0,0 +1,9 @@ + + + From e16ad321a72deb7d2322b55b808d774b1bb97248 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 27 Jan 2023 17:08:52 +0300 Subject: [PATCH 33/40] Updated on 2026-08-14 --- .../DefaultWalletAmountsRepository.kt | 11 ++++++++++- .../implementation/utils/WalletDataOperations.kt | 14 ++++++++++++++ .../implementation/utils/WalletStoreOperations.kt | 8 ++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt index 444d6fc480..93c70be9ef 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt @@ -27,6 +27,7 @@ import com.tangem.tap.domain.walletStores.repository.WalletAmountsRepository import com.tangem.tap.domain.walletStores.repository.implementation.utils.replaceWalletStore import com.tangem.tap.domain.walletStores.repository.implementation.utils.replaceWalletStores import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithAmounts +import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithDemoAmounts import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithError import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithFiatRates import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithMissedDerivation @@ -34,6 +35,7 @@ import com.tangem.tap.domain.walletStores.repository.implementation.utils.update import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithUnreachable import com.tangem.tap.domain.walletStores.storage.WalletManagerStorage import com.tangem.tap.domain.walletStores.storage.WalletStoresStorage +import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.wallet.models.PendingTransactionType import com.tangem.tap.features.wallet.models.filterByCoin import com.tangem.tap.features.wallet.models.getPendingTransactions @@ -207,6 +209,8 @@ internal class DefaultWalletAmountsRepository( updateWalletStoreWithAmounts( walletStore = walletStore, updatedWallet = walletManager.wallet, + // fixme move DemoHelper to Demo core module maybe + isDemo = DemoHelper.isDemoCardId(scanResponse.card.cardId), ) } .flatMap { fetchWalletStoreRentIfNeeded(walletStore, walletManager) } @@ -296,6 +300,7 @@ internal class DefaultWalletAmountsRepository( private suspend fun updateWalletStoreWithAmounts( walletStore: WalletStoreModel, updatedWallet: Wallet, + isDemo: Boolean, ) = withContext(Dispatchers.Default) { Timber.d( """ @@ -309,7 +314,11 @@ internal class DefaultWalletAmountsRepository( prevState.replaceWalletStore( walletStoreToUpdate = walletStore, update = { - it.updateWithAmounts(wallet = updatedWallet) + if (isDemo) { + it.updateWithDemoAmounts(wallet = updatedWallet) + } else { + it.updateWithAmounts(wallet = updatedWallet) + } }, ) } diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt index 64e2241737..dc1765ac47 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt @@ -7,6 +7,7 @@ import com.tangem.common.core.TangemError import com.tangem.tap.domain.extensions.amountToCreateAccount import com.tangem.tap.domain.getFirstToken import com.tangem.tap.domain.model.WalletDataModel +import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.getPendingTransactions import java.math.BigDecimal @@ -74,12 +75,25 @@ internal fun WalletDataModel.updateWithAmount(wallet: Wallet): WalletDataModel { ) } +internal fun WalletDataModel.updateWithDemoAmount(wallet: Wallet): WalletDataModel { + val amount = DemoHelper.config.getBalance(wallet.blockchain) + return this.copy( + status = WalletDataModel.VerifiedOnline(amount = amount.value ?: BigDecimal.ZERO), + ) +} + internal fun List.updateWithAmounts(wallet: Wallet): List { return this.map { walletData -> walletData.updateWithAmount(wallet) } } +internal fun List.updateWithDemoAmounts(wallet: Wallet): List { + return this.map { walletData -> + walletData.updateWithDemoAmount(wallet) + } +} + internal fun WalletDataModel.updateWithError( wallet: Wallet, error: TangemError, diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt index 0e9e9d8715..6679dc7a1d 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt @@ -49,6 +49,14 @@ internal fun WalletStoreModel.updateWithAmounts( ) } +internal fun WalletStoreModel.updateWithDemoAmounts( + wallet: Wallet, +): WalletStoreModel { + return this.copy( + walletsData = walletsData.updateWithDemoAmounts(wallet = wallet), + ) +} + internal fun WalletStoreModel.updateWithFiatRates( rates: Map, ): WalletStoreModel { From b101375ba10d8b4585ef79f24e4d75a20cbc8930 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 27 Jan 2023 18:38:51 +0300 Subject: [PATCH 34/40] Updated on 2026-08-14 --- .../tangem/tap/domain/model/builders/WalletStoreBuilder.kt | 6 +++--- .../products/wallet/redux/OnboardingWalletState.kt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt index 2bfbe6283d..651ab25018 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt @@ -97,7 +97,7 @@ private fun BlockchainNetwork.getBlockchainWalletData(walletManager: WalletManag walletAddresses = walletManager?.wallet?.createAddressesData().orEmpty(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, - isCardSingleToken = false + isCardSingleToken = false, ) } @@ -114,7 +114,7 @@ private fun BlockchainNetwork.getTokensWalletsData(walletManager: WalletManager? walletAddresses = walletManager?.wallet?.createAddressesData().orEmpty(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, - isCardSingleToken = walletManager?.cardTokens?.contains(token) ?: false + isCardSingleToken = walletManager?.cardTokens?.contains(token) ?: false, ) } } @@ -146,7 +146,7 @@ private fun Token.toTokenWalletData(walletManager: WalletManager): WalletDataMod walletAddresses = wallet.createAddressesData(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, - isCardSingleToken = walletManager.cardTokens.contains(this) + isCardSingleToken = walletManager.cardTokens.contains(this), ) } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletState.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletState.kt index aa04272085..4e3cad3657 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletState.kt @@ -105,7 +105,7 @@ sealed class BackupStep { object Finished : BackupStep() } -sealed class OnboardingDialog: StateDialog { +sealed class OnboardingDialog : StateDialog { data class InterruptOnboarding(val onOk: VoidCallback) : BackupDialog() } From 4bf71325702852b5d2c859e084f8b77281ffee62 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 27 Jan 2023 17:03:22 +0300 Subject: [PATCH 35/40] Updated on 2026-08-14 --- .../redux/WalletSelectorAction.kt | 4 +- .../redux/WalletSelectorMiddleware.kt | 37 +++++++++---------- .../redux/WalletSelectorReducer.kt | 17 +-------- 3 files changed, 22 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorAction.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorAction.kt index 0985f4b68c..0fd46c00ba 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorAction.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorAction.kt @@ -24,8 +24,8 @@ internal sealed interface WalletSelectorAction : Action { val walletsStores: Map>, ) : WalletSelectorAction - data class BalanceLoaded( - val userWalletModel: UserWalletModel, + data class BalancesLoaded( + val userWalletModels: List, ) : WalletSelectorAction object UnlockWithBiometry : WalletSelectorAction { diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt index 4405407dcd..9d690e7df7 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt @@ -35,7 +35,6 @@ import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.launch import org.rekotlin.Middleware import timber.log.Timber -import java.math.BigDecimal internal class WalletSelectorMiddleware { val middleware: Middleware = { _, appStateProvider -> @@ -81,7 +80,7 @@ internal class WalletSelectorMiddleware { is WalletSelectorAction.SelectedWalletChanged, is WalletSelectorAction.UnlockWithBiometry.Error, is WalletSelectorAction.UnlockWithBiometry.Success, - is WalletSelectorAction.BalanceLoaded, + is WalletSelectorAction.BalancesLoaded, is WalletSelectorAction.IsLockedChanged, is WalletSelectorAction.HandleError, is WalletSelectorAction.CloseError, @@ -104,20 +103,10 @@ internal class WalletSelectorMiddleware { state: WalletSelectorState, ) { if (updatedWalletStores.isNotEmpty()) scope.launch(Dispatchers.Default) { - state.wallets - .associateWith { updatedWalletStores[it.id] } - .forEach { (wallet, walletStores) -> - val isWalletTokensEmpty = (wallet.type as? UserWalletModel.Type.MultiCurrency)?.tokensCount == 0 - val updatedWallet = if (walletStores == null && isWalletTokensEmpty) { - wallet.copy(fiatBalance = TotalFiatBalance.Loaded(BigDecimal.ZERO)) - } else { - wallet.updateWalletStoresAndCalculateFiatBalance(walletStores.orEmpty()) - } - - if (wallet != updatedWallet) { - store.dispatchOnMain(WalletSelectorAction.BalanceLoaded(updatedWallet)) - } - } + val updatedWallets = state.wallets.updateWalletStoresAndCalculateFiatBalance(updatedWalletStores) + if (updatedWallets != state.wallets) { + store.dispatchOnMain(WalletSelectorAction.BalancesLoaded(updatedWallets)) + } } } @@ -314,18 +303,28 @@ internal class WalletSelectorMiddleware { } } + private suspend fun List.updateWalletStoresAndCalculateFiatBalance( + walletStores: Map>, + ): List { + return this + .associateWith { walletStores[it.id] } + .map { (wallet, walletStores) -> + wallet.updateWalletStoresAndCalculateFiatBalance(walletStores) + } + } + private suspend fun UserWalletModel.updateWalletStoresAndCalculateFiatBalance( - walletStores: List, + walletStores: List?, ): UserWalletModel { return this.copy( type = when (type) { is UserWalletModel.Type.MultiCurrency -> type.copy( - tokensCount = walletStores.flatMap { it.walletsData }.size, + tokensCount = walletStores?.flatMap { it.walletsData }?.size ?: 0, ) is UserWalletModel.Type.SingleCurrency -> type }, fiatBalance = totalFiatBalanceCalculator.calculate( - walletStores = walletStores, + walletStores = walletStores.orEmpty(), initial = TotalFiatBalance.Loading, ), ) diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt index b64fe0a3ce..277d3f45dd 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt @@ -24,8 +24,8 @@ internal object WalletSelectorReducer { is WalletSelectorAction.IsLockedChanged -> state.copy( isLocked = action.isLocked, ) - is WalletSelectorAction.BalanceLoaded -> state.copy( - wallets = state.wallets.updateWithBalance(action.userWalletModel), + is WalletSelectorAction.BalancesLoaded -> state.copy( + wallets = action.userWalletModels, ) is WalletSelectorAction.HandleError -> state.copy(error = action.error) is WalletSelectorAction.CloseError -> state.copy(error = null) @@ -85,19 +85,6 @@ internal object WalletSelectorReducer { } } - private fun List.updateWithBalance( - userWalletModel: UserWalletModel, - ): List { - return ArrayList(this).apply { - val index = indexOfFirst { it.id == userWalletModel.id } - if (index == -1) { - add(userWalletModel) - } else { - this[index] = userWalletModel - } - } - } - private fun UserWallet.getType(prevType: UserWalletModel.Type? = null): UserWalletModel.Type { return if (isMultiCurrency) { UserWalletModel.Type.MultiCurrency( From 385f8e3f0478433f9ea45fe8a11bcd7325a600bf Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 24 Jan 2023 15:07:35 +0300 Subject: [PATCH 36/40] Updated on 2026-08-14 --- .../tap/domain/model/WalletStoreModel.kt | 8 + .../utils/WalletDataOperations.kt | 4 +- .../utils/WalletStoreOperations.kt | 6 +- .../wallet/redux/middlewares/Mapper.kt | 160 ++++++++--------- .../wallet/ui/WalletDetailsFragment.kt | 168 +++++++++++------- 5 files changed, 197 insertions(+), 149 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/model/WalletStoreModel.kt b/app/src/main/java/com/tangem/tap/domain/model/WalletStoreModel.kt index a0511784e2..7bca1028c0 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/WalletStoreModel.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/WalletStoreModel.kt @@ -6,10 +6,12 @@ import com.tangem.common.hdWallet.DerivationPath import com.tangem.domain.common.util.UserWalletId import com.tangem.tap.domain.model.WalletStoreModel.WalletRent import com.tangem.tap.domain.tokens.models.BlockchainNetwork +import com.tangem.tap.features.wallet.models.Currency import java.math.BigDecimal /** * Contains info about the blockchain and its currencies + * * @param userWalletId ID of the associated [UserWallet] * @param blockchain [Blockchain] of this WalletStore * @param derivationPath [DerivationPath] of this store, null if the card does not support the @@ -21,6 +23,9 @@ import java.math.BigDecimal * TODO: Remove after WalletMiddleware refactoring * @param walletManager [WalletManager], may be null if it fails to create this manager. * TODO: Remove after WalletMiddleware refactoring + * + * @property blockchainWalletData Returns the [WalletDataModel] of the blockchain of this wallet store + * or throw [NoSuchElementException] if this wallet store not contains [WalletDataModel] of the blockchain * */ data class WalletStoreModel( val userWalletId: UserWalletId, @@ -34,6 +39,9 @@ data class WalletStoreModel( val walletManager: WalletManager?, ) { + val blockchainWalletData: WalletDataModel + get() = walletsData.first { it.currency is Currency.Blockchain } + /** * Represents wallet blockchain rent * @param rent Amount that will be charged in overtime if the blockchain does not have an amount greater than diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt index dc1765ac47..cb49fe33c1 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt @@ -178,7 +178,7 @@ internal fun List.updateWithSelf( val updatedWalletsData = arrayListOf() newWalletsData.forEach { newWalletData -> - val walletDataToUpdate = oldWalletsData.find(newWalletData::isSameWalletData) + val walletDataToUpdate = oldWalletsData.firstOrNull(newWalletData::isSameWalletData) if (walletDataToUpdate != null) { updatedWalletsData.add(walletDataToUpdate.updateWithSelf(newWalletData)) } else { @@ -190,5 +190,5 @@ internal fun List.updateWithSelf( } internal fun WalletDataModel.isSameWalletData(other: WalletDataModel): Boolean { - return currency == other.currency + return this.currency == other.currency } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt index 6679dc7a1d..0c3e47861c 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt @@ -104,6 +104,9 @@ private inline fun List.replaceWalletStores( walletStoresToUpdate.forEach { walletStoreToUpdate -> val index = mutableStores.indexOfFirst(walletStoreToUpdate::isSameWalletStore) + // Can be possible if user hides wallet store when it's tokens is loading + if (index == -1) return@forEach + val currentWalletStore = mutableStores[index] val updatedWalletStore = update(currentWalletStore) @@ -124,6 +127,7 @@ private inline fun List.replaceWalletStores( } internal fun WalletStoreModel.isSameWalletStore(other: WalletStoreModel): Boolean { - return this.blockchain == other.blockchain && + return this.userWalletId == other.userWalletId && + this.blockchain == other.blockchain && this.derivationPath == other.derivationPath } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt index 8209e5f65a..155ce6ebd7 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt @@ -21,7 +21,6 @@ import com.tangem.tap.features.wallet.ui.BalanceStatus import com.tangem.tap.features.wallet.ui.BalanceWidgetData import com.tangem.tap.features.wallet.ui.TokenData import com.tangem.tap.store -import timber.log.Timber import java.math.BigDecimal internal fun List.mapToReduxModels(): List { @@ -47,100 +46,102 @@ internal fun WalletStoreModel.mapToReduxModel(): WalletStore { return WalletStore( walletManager = walletManager, blockchainNetwork = blockchainNetwork, - walletsData = walletsData.mapToReduxModel(walletRent, appCurrencySymbol), + walletsData = walletsData.mapToReduxModels(walletRent, appCurrencySymbol), ) - .updateTokenModels(blockchain) - .setupIfHadCardSingleToken(blockchain, walletsData, appCurrencySymbol) + .updateTokenModels(blockchainWalletData.status.amount) + .setupIfHadCardSingleToken( + blockchain = blockchain, + walletsDataModel = walletsData, + appCurrencySymbol = appCurrencySymbol, + blockchainWalletData = blockchainWalletData.mapToReduxModel( + walletRent = walletRent, + appCurrencySymbol = appCurrencySymbol, + ), + ) } -private fun List.mapToReduxModel( +private fun List.mapToReduxModels( walletRent: WalletStoreModel.WalletRent?, appCurrencySymbol: String, ): List { return this.map { walletDataModel -> - with(walletDataModel) { - val amount = status.amount - val amountFormatted = amount.toFormattedCurrencyString( - decimals = currency.decimals, - currency = currency.currencySymbol, - ) - val fiatAmount = fiatRate?.let { status.amount.toFiatValue(it) } - val fiatAmountFormatted = fiatAmount - ?.takeIf { !status.isErrorStatus } - ?.toFormattedFiatValue(appCurrencySymbol) - val fiatRateFormatted = fiatRate?.toFiatRateString(appCurrencySymbol) - - WalletData( - currency = currency, - walletAddresses = walletAddresses.getOrNull(0)?.let { selectedAddress -> - WalletAddresses( - selectedAddress = selectedAddress, - list = walletAddresses, - ) - }, - existentialDepositString = existentialDeposit?.toPlainString(), - fiatRate = fiatRate, - fiatRateString = fiatRateFormatted, - pendingTransactions = status.pendingTransactions, - mainButton = WalletMainButton.SendButton( - enabled = !status.amount.isZero() && status.pendingTransactions.isEmpty(), - ), - walletRent = walletRent?.let { - WalletRent( - minRentValue = "${it.rent.stripZeroPlainString()} ${currency.blockchain.currency}", - rentExemptValue = "${it.exemptionAmount.stripZeroPlainString()} ${currency.blockchain.currency}", - ) - }, - currencyData = BalanceWidgetData( - status = when (status) { - is WalletDataModel.Loading -> BalanceStatus.Loading - is WalletDataModel.NoAccount -> BalanceStatus.NoAccount - is WalletDataModel.SameCurrencyTransactionInProgress -> BalanceStatus.SameCurrencyTransactionInProgress - is WalletDataModel.TransactionInProgress -> BalanceStatus.TransactionInProgress - is WalletDataModel.Unreachable -> BalanceStatus.Unreachable - is WalletDataModel.MissedDerivation -> BalanceStatus.MissedDerivation - is WalletDataModel.VerifiedOnline -> BalanceStatus.VerifiedOnline - }, - currency = currency.currencyName, - currencySymbol = currency.currencySymbol, - blockchainAmount = BigDecimal.ZERO, - amount = amount, - amountFormatted = amountFormatted, - fiatAmount = fiatAmount, - fiatAmountFormatted = fiatAmountFormatted, - token = null, - amountToCreateAccount = (status as? WalletDataModel.NoAccount) - ?.amountToCreateAccount - ?.toString(), - errorMessage = status.errorMessage, - ), - ) - } + walletDataModel.mapToReduxModel(walletRent, appCurrencySymbol) } } -private fun WalletStore.updateTokenModels(blockchain: Blockchain): WalletStore { - val foundBlockchains = this.walletsData.filter { - it.currency.isBlockchain() && it.currency.blockchain == blockchain - } - if (foundBlockchains.size != 1) { - val warningMessage = "Can't update information about Tokens in the WalletData list, because " + - "of the WalletStore doesn't contains the Blockchain: %s, or contains more than one" - Timber.w(warningMessage, blockchain.id) - return this - } +private fun WalletDataModel.mapToReduxModel( + walletRent: WalletStoreModel.WalletRent?, + appCurrencySymbol: String, +): WalletData { + val amount = status.amount + val amountFormatted = amount.toFormattedCurrencyString( + decimals = currency.decimals, + currency = currency.currencySymbol, + ) + val fiatAmount = fiatRate?.let { status.amount.toFiatValue(it) } + val fiatAmountFormatted = fiatAmount + ?.takeIf { !status.isErrorStatus } + ?.toFormattedFiatValue(appCurrencySymbol) + val fiatRateFormatted = fiatRate?.toFiatRateString(appCurrencySymbol) - val blockchainAmountValue = foundBlockchains.first().currencyData.blockchainAmount ?: BigDecimal.ZERO + return WalletData( + currency = currency, + walletAddresses = walletAddresses.getOrNull(0)?.let { selectedAddress -> + WalletAddresses( + selectedAddress = selectedAddress, + list = walletAddresses, + ) + }, + existentialDepositString = existentialDeposit?.toPlainString(), + fiatRate = fiatRate, + fiatRateString = fiatRateFormatted, + pendingTransactions = status.pendingTransactions, + mainButton = WalletMainButton.SendButton( + enabled = !status.amount.isZero() && status.pendingTransactions.isEmpty(), + ), + walletRent = walletRent?.let { + WalletRent( + minRentValue = "${it.rent.stripZeroPlainString()} ${currency.blockchain.currency}", + rentExemptValue = "${it.exemptionAmount.stripZeroPlainString()} ${currency.blockchain.currency}", + ) + }, + currencyData = BalanceWidgetData( + status = when (status) { + is WalletDataModel.Loading -> BalanceStatus.Loading + is WalletDataModel.NoAccount -> BalanceStatus.NoAccount + is WalletDataModel.SameCurrencyTransactionInProgress -> BalanceStatus.SameCurrencyTransactionInProgress + is WalletDataModel.TransactionInProgress -> BalanceStatus.TransactionInProgress + is WalletDataModel.Unreachable -> BalanceStatus.Unreachable + is WalletDataModel.MissedDerivation -> BalanceStatus.MissedDerivation + is WalletDataModel.VerifiedOnline -> BalanceStatus.VerifiedOnline + }, + currency = currency.currencyName, + currencySymbol = currency.currencySymbol, + blockchainAmount = BigDecimal.ZERO, + amount = amount, + amountFormatted = amountFormatted, + fiatAmount = fiatAmount, + fiatAmountFormatted = fiatAmountFormatted, + token = null, + amountToCreateAccount = (status as? WalletDataModel.NoAccount) + ?.amountToCreateAccount + ?.toString(), + errorMessage = status.errorMessage, + ), + ) +} + +private fun WalletStore.updateTokenModels(blockchainAmount: BigDecimal): WalletStore { val updatedTokensWalletData = walletsData.filter { it.currency.isToken() }.map { it.copy( mainButton = when (it.mainButton) { is WalletMainButton.SendButton -> { - WalletMainButton.SendButton(it.mainButton.enabled && !blockchainAmountValue.isZero()) + WalletMainButton.SendButton(it.mainButton.enabled && !blockchainAmount.isZero()) } is WalletMainButton.CreateWalletButton -> it.mainButton }, currencyData = it.currencyData.copy( - blockchainAmount = blockchainAmountValue, + blockchainAmount = blockchainAmount, ), ) } @@ -151,17 +152,14 @@ private fun WalletStore.setupIfHadCardSingleToken( blockchain: Blockchain, walletsDataModel: List, appCurrencySymbol: String, + blockchainWalletData: WalletData, ): WalletStore { // Card with single token contains only 2 model - blockchain and token if (walletsData.size != 2) return this - val blockchainWalletData = walletsData.firstOrNull { - it.currency.isBlockchain() && it.currency.blockchain == blockchain - } val cardSingleTokenWalletData = walletsDataModel.firstOrNull { it.currency.isToken() && it.currency.blockchain == blockchain && it.isCardSingleToken - } - if (blockchainWalletData == null || cardSingleTokenWalletData == null) return this + } ?: return this val blockchainWalletDataWithSingleToken = blockchainWalletData.copy( currencyData = blockchainWalletData.currencyData.copy( diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt index e65f402169..e38d9d947b 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt @@ -16,6 +16,8 @@ import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.transition.TransitionInflater import by.kirich1409.viewbindingdelegate.viewBinding +import com.badoo.mvicore.DiffStrategy +import com.badoo.mvicore.ModelWatcher import com.badoo.mvicore.modelWatcher import com.tangem.common.doOnResult import com.tangem.core.analytics.Analytics @@ -39,6 +41,8 @@ import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.PendingTransaction +import com.tangem.tap.features.wallet.models.WalletWarning +import com.tangem.tap.features.wallet.redux.AddressData import com.tangem.tap.features.wallet.redux.ErrorType import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletAction @@ -67,7 +71,13 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), private val binding: FragmentWalletDetailsBinding by viewBinding(FragmentWalletDetailsBinding::bind) - private val walletDataWatcher = modelWatcher { + private val walletDataWatcher: ModelWatcher = modelWatcher { + val addressCardStrategy: DiffStrategy = { old, new -> + old.currency != new.currency || + old.walletAddresses?.selectedAddress != new.walletAddresses?.selectedAddress || + old.shouldShowMultipleAddress() != new.shouldShowMultipleAddress() + } + WalletData::pendingTransactions { showPendingTransactionsIfPresent(it) } @@ -77,25 +87,35 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), WalletData::currencyData { setupBalanceData(it) } + WalletData::walletAddresses { walletAddresses -> + setupCopyAndShareButtons(walletAddresses?.selectedAddress?.address) + } + WalletData::assembleWarnings { warnings -> + handleWarnings(warnings) + } (WalletData::currencyData or WalletData::currency) { walletData -> setupCurrency(walletData.currencyData, walletData.currency) setupSwipeRefresh(walletData.currencyData, walletData.currency) } + watch({ it }, addressCardStrategy) { walletData -> + setupAddressCard( + shouldShowMultipleAddress = walletData.shouldShowMultipleAddress(), + selectedAddress = walletData.walletAddresses?.selectedAddress, + currency = walletData.currency, + ) + } } - private val walletStateWatcher = modelWatcher { - (WalletState::selectedCurrency or WalletState::selectedWalletData) { state -> - val selectedWalletData = state.selectedWalletData - if (selectedWalletData != null) { - walletDataWatcher.invoke(selectedWalletData) - setupButtons(selectedWalletData, state.isExchangeServiceFeatureOn) - setupAddressCard(selectedWalletData) - handleWarnings(selectedWalletData) + private val walletStateWatcher: ModelWatcher = modelWatcher { + WalletState::selectedWalletData { selectedWallet -> + if (selectedWallet != null) { + walletDataWatcher.invoke(selectedWallet) } } - (WalletState::selectedCurrency or WalletState::isExchangeServiceFeatureOn) { state -> - if (state.selectedWalletData != null) { - setupButtons(state.selectedWalletData!!, state.isExchangeServiceFeatureOn) + (WalletState::selectedWalletData or WalletState::isExchangeServiceFeatureOn) { state -> + val selectedWallet = state.selectedWalletData + if (selectedWallet != null) { + setupButtonsRow(selectedWallet, state.isExchangeServiceFeatureOn) } } (WalletState::state or WalletState::error) { state -> @@ -132,8 +152,6 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), override fun onStop() { super.onStop() store.unsubscribe(this) - walletDataWatcher.clear() - walletStateWatcher.clear() } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -147,6 +165,11 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), setupTestActionButton() } + override fun onDestroyView() { + super.onDestroyView() + clearWatchers() + } + private fun setupTransactionsRecyclerView() = with(binding) { pendingTransactionAdapter = PendingTransactionsAdapter() rvPendingTransaction.layoutManager = LinearLayoutManager(requireContext()) @@ -251,19 +274,21 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), currencyData.status == BalanceStatus.Refreshing } - private fun setupButtons(selectedWallet: WalletData, isExchangeServiceFeatureOn: Boolean) = with(binding) { - lWalletDetails.btnCopy.setOnClickListener { - selectedWallet.walletAddresses?.selectedAddress?.address?.let { addressString -> - store.dispatch(WalletAction.CopyAddress(addressString, requireContext())) + private fun setupCopyAndShareButtons(walletAddress: String?) { + binding.lWalletDetails.btnCopy.setOnClickListener { + if (walletAddress != null) { + store.dispatch(WalletAction.CopyAddress(walletAddress, requireContext())) } } - lWalletDetails.btnShare.setOnClickListener { - selectedWallet.walletAddresses?.selectedAddress?.address?.let { addressString -> - store.dispatch(WalletAction.ShareAddress(addressString, requireContext())) + binding.lWalletDetails.btnShare.setOnClickListener { + if (walletAddress != null) { + store.dispatch(WalletAction.ShareAddress(walletAddress, requireContext())) } } + } - rowButtons.updateButtonsVisibility( + private fun setupButtonsRow(selectedWallet: WalletData, isExchangeServiceFeatureOn: Boolean) { + binding.rowButtons.updateButtonsVisibility( exchangeServiceFeatureOn = isExchangeServiceFeatureOn, buyAllowed = selectedWallet.isAvailableToBuy, sellAllowed = selectedWallet.isAvailableToSell, @@ -271,9 +296,9 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), ) } - private fun handleWarnings(selectedWallet: WalletData) = with(binding) { + private fun handleWarnings(warnings: List) = with(binding) { val converter = WalletWarningConverter(requireContext()) - val warningDetails = selectedWallet.assembleWarnings().map { converter.convert(it) } + val warningDetails = warnings.map { converter.convert(it) } warningMessagesAdapter.submitList(warningDetails) rvWarningMessages.show(warningDetails.isNotEmpty()) @@ -294,51 +319,59 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), binding.rvPendingTransaction.show(pendingTransactions.isNotEmpty()) } - private fun setupAddressCard(state: WalletData) = with(binding.lWalletDetails) { - if (state.walletAddresses != null) { - if (state.shouldShowMultipleAddress() && state.currency is Currency.Blockchain) { - (cardBalance as? ViewGroup)?.beginDelayedTransition() - chipGroupAddressType.show() - chipGroupAddressType.fitChipsByGroupWidth() + private fun setupAddressCard( + shouldShowMultipleAddress: Boolean, + selectedAddress: AddressData?, + currency: Currency, + ) = with(binding.lWalletDetails) { + if (selectedAddress == null) return@with - val checkedId = - MultipleAddressUiHelper.typeToId(state.walletAddresses.selectedAddress.type) - if (checkedId != View.NO_ID) chipGroupAddressType.check(checkedId) + setupAddressTypeChips(shouldShowMultipleAddress, selectedAddress, currency) - chipGroupAddressType.setOnCheckedChangeListener { group, checkedId -> - if (checkedId == -1) return@setOnCheckedChangeListener - val type = - MultipleAddressUiHelper.idToType(checkedId, state.currency.blockchain) - type?.let { store.dispatch(WalletAction.ChangeSelectedAddress(type)) } - } - } else { - chipGroupAddressType.hide() - } - tvAddress.text = state.walletAddresses.selectedAddress.address - tvExplore.setOnClickListener { - store.dispatch( - WalletAction.ExploreAddress( - state.walletAddresses.selectedAddress.exploreUrl, - requireContext(), - ), - ) - } - ivQrCode.setImageBitmap(state.walletAddresses.selectedAddress.shareUrl.toQrCode()) + tvAddress.text = selectedAddress.address + tvExplore.setOnClickListener { + store.dispatch(WalletAction.ExploreAddress(selectedAddress.exploreUrl, requireContext())) + } + ivQrCode.setImageBitmap(selectedAddress.shareUrl.toQrCode()) - tvReceiveMessage.text = when (val currency = state.currency) { - is Currency.Blockchain -> tvReceiveMessage.getString( - id = R.string.address_qr_code_message_format, - currency.blockchain.fullName, - currency.currencySymbol, - currency.blockchain.fullName, - ) - is Currency.Token -> tvReceiveMessage.getString( - id = R.string.address_qr_code_message_format, - currency.token.name, - currency.currencySymbol, - currency.blockchain.fullName, - ) + tvReceiveMessage.text = when (currency) { + is Currency.Blockchain -> tvReceiveMessage.getString( + id = R.string.address_qr_code_message_format, + currency.blockchain.fullName, + currency.currencySymbol, + currency.blockchain.fullName, + ) + is Currency.Token -> tvReceiveMessage.getString( + id = R.string.address_qr_code_message_format, + currency.token.name, + currency.currencySymbol, + currency.blockchain.fullName, + ) + } + } + + private fun setupAddressTypeChips( + shouldShowMultipleAddress: Boolean, + selectedAddress: AddressData, + currency: Currency, + ) = with(binding.lWalletDetails) { + if (shouldShowMultipleAddress && currency is Currency.Blockchain) { + (cardBalance as? ViewGroup)?.beginDelayedTransition() + chipGroupAddressType.show() + chipGroupAddressType.fitChipsByGroupWidth() + + val checkedId = + MultipleAddressUiHelper.typeToId(selectedAddress.type) + if (checkedId != View.NO_ID) chipGroupAddressType.check(checkedId) + + chipGroupAddressType.setOnCheckedChangeListener { _, checkedId -> + if (checkedId == -1) return@setOnCheckedChangeListener + val type = + MultipleAddressUiHelper.idToType(checkedId, currency.blockchain) + type?.let { store.dispatch(WalletAction.ChangeSelectedAddress(type)) } } + } else { + chipGroupAddressType.hide() } } @@ -425,6 +458,11 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), inflater.inflate(R.menu.menu_wallet_details, menu) } + private fun clearWatchers() { + walletDataWatcher.clear() + walletStateWatcher.clear() + } + private fun TextView.setWarningStatus(mainMessage: Int, error: String? = null) { val text = getString(mainMessage).appendIfNotNull(error, "\nError: ") setStatus(text, R.color.warning, R.drawable.ic_warning_small) From 8c245f60f82ef6067a8b2085da067eed0d45e2f9 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 30 Jan 2023 11:23:21 +0300 Subject: [PATCH 37/40] Updated on 2026-08-14 --- .../implementation/DefaultTotalFiatBalanceCalculator.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt b/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt index 71f3f0a663..faa4628b9b 100644 --- a/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt +++ b/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt @@ -43,13 +43,15 @@ internal class DefaultTotalFiatBalanceCalculator : TotalFiatBalanceCalculator { private fun Sequence.mapToStatus(): Sequence { return this.map { walletData -> - if (walletData.fiatRate == null) TotalFiatBalanceStatus.Error - else when (walletData.status) { + when (walletData.status) { is WalletDataModel.VerifiedOnline, is WalletDataModel.SameCurrencyTransactionInProgress, is WalletDataModel.TransactionInProgress, is WalletDataModel.NoAccount, - -> TotalFiatBalanceStatus.Loaded + -> { + if (walletData.fiatRate == null) TotalFiatBalanceStatus.Error + else TotalFiatBalanceStatus.Loaded + } is WalletDataModel.Unreachable, is WalletDataModel.MissedDerivation, -> TotalFiatBalanceStatus.Error From 29d94db06da12c1bf618b323c792bb852e2bc4f1 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 30 Jan 2023 12:56:19 +0300 Subject: [PATCH 38/40] Updated on 2026-08-14 --- .../com/tangem/tap/common/DialogManager.kt | 2 ++ .../tap/domain/scanCard/ScanCardProcessor.kt | 31 +++++++------------ .../wallet/saltPay/SaltPayExceptionHandler.kt | 5 ++- .../saltPay/dialog/PutVisaCardDialog.kt | 27 ++++++++++++++++ .../wallet/saltPay/dialog/SaltPayDialog.kt | 1 + .../saltPay/message/SaltPayModuleMessage.kt | 2 ++ .../redux/WalletSelectorMiddleware.kt | 11 ++++++- .../welcome/redux/WelcomeMiddleware.kt | 11 ++++++- 8 files changed, 65 insertions(+), 25 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/PutVisaCardDialog.kt diff --git a/app/src/main/java/com/tangem/tap/common/DialogManager.kt b/app/src/main/java/com/tangem/tap/common/DialogManager.kt index 94dd3ff6c1..f36d0656e8 100644 --- a/app/src/main/java/com/tangem/tap/common/DialogManager.kt +++ b/app/src/main/java/com/tangem/tap/common/DialogManager.kt @@ -20,6 +20,7 @@ import com.tangem.tap.features.onboarding.products.wallet.redux.BackupDialog import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingDialog import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.InterruptOnboardingDialog import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.NoFundsForActivationDialog +import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.PutVisaCardDialog import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.RegistrationErrorDialog import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.SaltPayDialog import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.AddMoreBackupCardsDialog @@ -131,6 +132,7 @@ class DialogManager : StoreSubscriber { is BackupDialog.UnfinishedBackupFound -> UnfinishedBackupFoundDialog.create(context) is BackupDialog.ConfirmDiscardingBackup -> ConfirmDiscardingBackupDialog.create(context) is SaltPayDialog.Activation.NoGas -> NoFundsForActivationDialog.create(context) + is SaltPayDialog.Activation.PutVisaCard -> PutVisaCardDialog.create(context) is SaltPayDialog.Activation.OnError -> RegistrationErrorDialog.create(context, state.dialog) is WalletDialog.CurrencySelectionDialog -> CurrencySelectionDialog.create(state.dialog, context) is WalletDialog.ChooseTradeActionDialog -> ChooseTradeActionBottomSheetDialog(context) diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt index 4dc0722d61..452a7a57ff 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt @@ -14,10 +14,8 @@ import com.tangem.operations.backup.BackupService import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE import com.tangem.tap.backupService import com.tangem.tap.common.analytics.paramsInterceptor.BatchIdParamsInterceptor -import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.primaryCardIsSaltPayVisa -import com.tangem.tap.common.redux.AppDialog import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction @@ -30,6 +28,7 @@ import com.tangem.tap.features.onboarding.OnboardingSaltPayHelper import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayExceptionHandler +import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayActivationError import com.tangem.tap.features.onboarding.products.wallet.saltPay.redux.OnboardingSaltPayAction import com.tangem.tap.features.onboarding.products.wallet.saltPay.redux.OnboardingSaltPayState import com.tangem.tap.preferencesStorage @@ -37,7 +36,6 @@ import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.tangemSdkManager import com.tangem.tap.userTokensRepository -import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -82,7 +80,7 @@ object ScanCardProcessor { checkForUnfinishedBackupForSaltPay( backupService = backupService, scanResponse = scanResponse, - onProgressStateChange = { onProgressStateChange(it) }, + onFailure = onFailure, nextHandler = { scanResponse1 -> showDisclaimerIfNeed( scanResponse = scanResponse1, @@ -116,11 +114,11 @@ object ScanCardProcessor { * see BackupAction.CheckForUnfinishedBackup * If user touches card other than Visa SaltPay - show dialog and block next processing */ - private inline fun checkForUnfinishedBackupForSaltPay( + private suspend inline fun checkForUnfinishedBackupForSaltPay( backupService: BackupService, scanResponse: ScanResponse, - onProgressStateChange: (showProgress: Boolean) -> Unit, nextHandler: (ScanResponse) -> Unit, + onFailure: suspend (error: TangemError) -> Unit, ) { if (!backupService.hasIncompletedBackup || !backupService.primaryCardIsSaltPayVisa()) { nextHandler(scanResponse) @@ -132,8 +130,9 @@ object ScanCardProcessor { ?: false if (scanResponse.isSaltPayWallet() || !isTheSamePrimaryCard) { - onProgressStateChange(false) - showSaltPayTapVisaLogoCardDialog() + val error = SaltPayActivationError.PutVisaCard + SaltPayExceptionHandler.handle(error) + onFailure(TangemSdkError.ExceptionError(error)) } else { nextHandler(scanResponse) } @@ -207,8 +206,8 @@ object ScanCardProcessor { } } is Result.Failure -> { - SaltPayExceptionHandler.handle(result.error) delay(DELAY_SDK_DIALOG_CLOSE) + SaltPayExceptionHandler.handle(result.error) onFailure(TangemSdkError.ExceptionError(result.error)) } } @@ -216,8 +215,9 @@ object ScanCardProcessor { } else { delay(DELAY_SDK_DIALOG_CLOSE) if (scanResponse.card.backupStatus?.isActive == false) { - showSaltPayTapVisaLogoCardDialog() - onProgressStateChange(false) + val error = SaltPayActivationError.PutVisaCard + SaltPayExceptionHandler.handle(error) + onFailure(TangemSdkError.ExceptionError(error)) } else { onSuccess(scanResponse) } @@ -241,15 +241,6 @@ object ScanCardProcessor { } } - private fun showSaltPayTapVisaLogoCardDialog() { - store.dispatchDialogShow( - AppDialog.SimpleOkDialogRes( - headerId = R.string.saltpay_error_empty_backup_title, - messageId = R.string.saltpay_error_empty_backup_message, - ), - ) - } - private suspend inline fun navigateTo( screen: AppScreen, onProgressStateChange: (showProgress: Boolean) -> Unit, diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayExceptionHandler.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayExceptionHandler.kt index 3b4ed41a05..0f0b207431 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayExceptionHandler.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayExceptionHandler.kt @@ -18,6 +18,7 @@ class SaltPayExceptionHandler { is SaltPayActivationError -> { val dialog = when (throwable) { is SaltPayActivationError.NoGas -> SaltPayDialog.Activation.NoGas + is SaltPayActivationError.PutVisaCard -> SaltPayDialog.Activation.PutVisaCard else -> SaltPayDialog.Activation.OnError(throwable) } store.dispatchDialogShow(dialog) @@ -28,9 +29,7 @@ class SaltPayExceptionHandler { val message = (throwable).customMessage store.dispatchDialogShow(AppDialog.SimpleOkErrorDialog(message)) } - else -> { - // do nothing - } + else -> Unit } } is BlockchainSdkError -> { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/PutVisaCardDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/PutVisaCardDialog.kt new file mode 100644 index 0000000000..ba689a1449 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/PutVisaCardDialog.kt @@ -0,0 +1,27 @@ +package com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog + +import android.app.Dialog +import android.content.Context +import androidx.appcompat.app.AlertDialog +import com.tangem.tap.common.redux.global.GlobalAction +import com.tangem.tap.store +import com.tangem.wallet.R + +/** +[REDACTED_AUTHOR] + */ +class PutVisaCardDialog { + companion object { + fun create(context: Context): Dialog { + return AlertDialog.Builder(context).apply { + setTitle(R.string.saltpay_error_empty_backup_title) + setMessage(R.string.saltpay_error_empty_backup_message) + setPositiveButton(R.string.common_ok) { _, _ -> } + setOnDismissListener { + store.dispatch(GlobalAction.HideDialog) + } + setCancelable(false) + }.create() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/SaltPayDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/SaltPayDialog.kt index b8b512aef1..26228ba27f 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/SaltPayDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/SaltPayDialog.kt @@ -9,6 +9,7 @@ import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPa sealed class SaltPayDialog : StateDialog { sealed class Activation : SaltPayDialog() { object NoGas : SaltPayDialog() + object PutVisaCard : SaltPayDialog() data class OnError(val error: SaltPayActivationError) : SaltPayDialog() } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/message/SaltPayModuleMessage.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/message/SaltPayModuleMessage.kt index 6f2a5de7ad..6097e52cc2 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/message/SaltPayModuleMessage.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/message/SaltPayModuleMessage.kt @@ -50,6 +50,8 @@ sealed class SaltPayActivationError( object ClaimTransactionFailed : SaltPayActivationError(16) object NotClaimed : SaltPayActivationError(17) + object PutVisaCard : SaltPayActivationError(18) + companion object { const val EMPTY_MESSAGE = "" } diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt index 9d690e7df7..aa4f559888 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt @@ -21,6 +21,7 @@ import com.tangem.tap.domain.model.UserWallet import com.tangem.tap.domain.model.WalletStoreModel import com.tangem.tap.domain.model.builders.UserWalletBuilder import com.tangem.tap.domain.scanCard.ScanCardProcessor +import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayActivationError import com.tangem.tap.preferencesStorage import com.tangem.tap.scope import com.tangem.tap.store @@ -155,7 +156,15 @@ internal class WalletSelectorMiddleware { onFailure = { error -> // Rollback policy if card scanning was failed tangemSdkManager.setAccessCodeRequestPolicy(prevUseBiometricsForAccessCode) - store.dispatchOnMain(WalletSelectorAction.AddWallet.Error(error)) + when { + error is TangemSdkError.ExceptionError && error.cause is SaltPayActivationError -> { + store.dispatchOnMain(WalletSelectorAction.AddWallet.Success) + store.dispatchOnMain(NavigationAction.PopBackTo()) + } + else -> { + store.dispatchOnMain(WalletSelectorAction.AddWallet.Error(error)) + } + } }, ) } diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt index c1cdf0f74e..4c39b5cb3c 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt @@ -1,6 +1,7 @@ package com.tangem.tap.features.welcome.redux import android.content.Intent +import com.tangem.common.core.TangemSdkError import com.tangem.common.doOnFailure import com.tangem.common.doOnSuccess import com.tangem.domain.common.ScanResponse @@ -12,6 +13,7 @@ import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.model.builders.UserWalletBuilder import com.tangem.tap.domain.scanCard.ScanCardProcessor +import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayActivationError import com.tangem.tap.intentHandler import com.tangem.tap.preferencesStorage import com.tangem.tap.scope @@ -104,7 +106,14 @@ internal class WelcomeMiddleware { scope.launch { onCardScanned(scanResponse) } }, onFailure = { - store.dispatchOnMain(WelcomeAction.ProceedWithCard.Error(it)) + when { + it is TangemSdkError.ExceptionError && it.cause is SaltPayActivationError -> { + store.dispatchOnMain(WelcomeAction.ProceedWithCard.Success) + } + else -> { + store.dispatchOnMain(WelcomeAction.ProceedWithCard.Error(it)) + } + } }, onWalletNotCreated = { store.dispatchOnMain(WelcomeAction.ProceedWithCard.Success) From 908ad77fea7bcee9933ab74c1f980b2d53528b47 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 30 Jan 2023 13:37:37 +0300 Subject: [PATCH 39/40] Updated on 2026-08-14 --- app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 4eb41fd759..62e990eeff 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -267,7 +267,9 @@ class TapWalletManager { } suspend fun reloadData(data: ScanResponse) { - loadUserCurrencies(data, walletManagerFactory) + if (data.card.isMultiwalletAllowed) { + loadUserCurrencies(data, walletManagerFactory) + } withContext(Dispatchers.Main) { getActionIfUnknownBlockchainOrEmptyWallet(data)?.let { store.dispatch(it) From a53561e8d86d7a27ea67ecf23827e6f1a64fdfa5 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 30 Jan 2023 13:57:51 +0300 Subject: [PATCH 40/40] Updated on 2026-08-14 --- app/src/main/res/layout/fragment_wallet.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/fragment_wallet.xml b/app/src/main/res/layout/fragment_wallet.xml index b3d1b54730..8b5495c98c 100644 --- a/app/src/main/res/layout/fragment_wallet.xml +++ b/app/src/main/res/layout/fragment_wallet.xml @@ -173,6 +173,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="16dp" + android:layout_marginTop="12dp" android:layout_marginEnd="16dp" android:visibility="gone" app:layout_constraintTop_toBottomOf="@id/rv_pending_transaction" />