diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 0c69e5de88..4674adf0e6 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -1,17 +1,17 @@ package com.tangem.tap import android.app.Application +import android.content.Context +import android.content.pm.PackageManager import coil.ImageLoader import coil.ImageLoaderFactory import com.appsflyer.AppsFlyerLib -import com.google.firebase.ktx.Firebase -import com.google.firebase.remoteconfig.ktx.remoteConfig -import com.google.firebase.remoteconfig.ktx.remoteConfigSettings import com.tangem.Log import com.tangem.LogFormat import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder import com.tangem.domain.DomainLayer import com.tangem.network.common.MoshiConverter +import com.tangem.tap.common.AndroidAssetReader import com.tangem.tap.common.analytics.GlobalAnalyticsHandler import com.tangem.tap.common.feedback.AdditionalFeedbackInfo import com.tangem.tap.common.feedback.FeedbackManager @@ -21,10 +21,9 @@ import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.appReducer import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.shop.TangemShopService +import com.tangem.tap.domain.configurable.config.Config import com.tangem.tap.domain.configurable.config.ConfigManager import com.tangem.tap.domain.configurable.config.FeaturesLocalLoader -import com.tangem.tap.domain.configurable.config.FeaturesRemoteLoader -import com.tangem.tap.domain.configurable.warningMessage.RemoteWarningLoader import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager import com.tangem.tap.domain.tokens.CurrenciesRepository import com.tangem.tap.domain.walletconnect.WalletConnectRepository @@ -37,7 +36,7 @@ import timber.log.Timber val store = Store( reducer = ::appReducer, middleware = AppState.getMiddleware(), - state = AppState() + state = AppState(), ) val logConfig = LogConfig() @@ -49,101 +48,100 @@ lateinit var walletConnectRepository: WalletConnectRepository lateinit var shopService: TangemShopService class TapApplication : Application(), ImageLoaderFactory { + override fun onCreate() { super.onCreate() - DomainLayer.init() if (BuildConfig.DEBUG) { Timber.plant(Timber.DebugTree()) - Firebase.remoteConfig.setConfigSettingsAsync(remoteConfigSettings { - this.minimumFetchIntervalInSeconds = 60 - }) - } else { - Firebase.remoteConfig.setConfigSettingsAsync(remoteConfigSettings { - this.minimumFetchIntervalInSeconds = 3600 - }) } - NetworkConnectivity.createInstance(store, this) - preferencesStorage = PreferencesStorage(this) - currenciesRepository = CurrenciesRepository( - this, store.state.domainNetworks.tangemTechService - ) - walletConnectRepository = WalletConnectRepository(this) - foregroundActivityObserver = ForegroundActivityObserver() registerActivityLifecycleCallbacks(foregroundActivityObserver.callbacks) - initFeedbackManager() - loadConfigs() + + DomainLayer.init() + NetworkConnectivity.createInstance(store, this) + preferencesStorage = PreferencesStorage(this) + currenciesRepository = CurrenciesRepository(this, store.state.domainNetworks.tangemTechService) + walletConnectRepository = WalletConnectRepository(this) + + val configLoader = FeaturesLocalLoader(AndroidAssetReader(this), MoshiConverter.defaultMoshi()) + initConfigManager(configLoader, ::initWithConfigDependency) + initWarningMessagesManager() BlockchainSdkRetrofitBuilder.enableNetworkLogging = BuildConfig.DEBUG - - initAppsFlyer() } override fun newImageLoader(): ImageLoader { return createCoilImageLoader(context = this) } - private fun loadConfigs() { - val moshi = MoshiConverter.defaultMoshi() - val localLoader = FeaturesLocalLoader(this, moshi) - val remoteLoader = FeaturesRemoteLoader(moshi) - val configManager = ConfigManager(localLoader, remoteLoader) - configManager.load { config -> + private fun initConfigManager(loader: FeaturesLocalLoader, onComplete: (Config) -> Unit) { + val configManager = ConfigManager() + configManager.load(loader) { config -> store.dispatch(GlobalAction.SetConfigManager(configManager)) - shopService = TangemShopService( - application = this, - shopifyShop = config.shopify!! - ) - store.state.globalState.feedbackManager?.initChat( - context = this, - zendeskConfig = config.zendesk!! - ) + onComplete(config) } - val warningsManager = WarningMessagesManager(RemoteWarningLoader(moshi)) - warningsManager.load { store.dispatch(GlobalAction.SetWarningManager(warningsManager)) } } - private fun initFeedbackManager() { - val infoHolder = AdditionalFeedbackInfo() - infoHolder.setAppVersion(this) - - val logLevels = listOf( - Log.Level.ApduCommand, - Log.Level.Apdu, - Log.Level.Tlv, - Log.Level.Nfc, - Log.Level.Command, - Log.Level.Session, - Log.Level.View, - Log.Level.Network, - Log.Level.Error, - ) - val logWriter = TangemLogCollector( - levels = logLevels, - messageFormatter = LogFormat.StairsFormatter(), - ) - Log.addLogger(logWriter) - - store.dispatch( - GlobalAction.SetFeedbackManager( - FeedbackManager( - infoHolder = infoHolder, - logCollector = logWriter, - preferencesStorage = preferencesStorage, - ), - ), - ) + private fun initWithConfigDependency(config: Config) { + shopService = TangemShopService(this, config.shopify!!) + initAppsFlyer(this, config) + initFeedbackManager(this, preferencesStorage, config) } - private fun initAppsFlyer() { - val devKey = store.state.globalState.configManager?.config?.appsFlyerDevKey ?: return - AppsFlyerLib.getInstance().init(devKey, null, this) - AppsFlyerLib.getInstance().start(this) - val analyticsHandler = GlobalAnalyticsHandler.createDefaultAnalyticHandlers(this) + private fun initAppsFlyer(context: Context, config: Config) { + AppsFlyerLib.getInstance().init(config.appsFlyerDevKey, null, context) + AppsFlyerLib.getInstance().start(context) + val analyticsHandler = GlobalAnalyticsHandler.createDefaultAnalyticHandlers(context) store.dispatch(GlobalAction.SetAnanlyticHandlers(analyticsHandler)) } + + private fun initFeedbackManager(context: Context, preferencesStorage: PreferencesStorage, config: Config) { + fun initAdditionalFeedbackInfo(context: Context): AdditionalFeedbackInfo = AdditionalFeedbackInfo().apply { + appVersion = try { + val pInfo = context.packageManager.getPackageInfo(context.packageName, 0) + pInfo.versionName + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + "x.y.z" + } + } + + fun initTangemLogCollector(): TangemLogCollector { + val logLevels = listOf( + Log.Level.ApduCommand, + Log.Level.Apdu, + Log.Level.Tlv, + Log.Level.Nfc, + Log.Level.Command, + Log.Level.Session, + Log.Level.View, + Log.Level.Network, + Log.Level.Error, + ) + return TangemLogCollector(logLevels, LogFormat.StairsFormatter()) + } + + val additionalFeedbackInfo = initAdditionalFeedbackInfo(context) + val tangemLogCollector = initTangemLogCollector() + Log.addLogger(tangemLogCollector) + + val feedbackManager = FeedbackManager( + infoHolder = additionalFeedbackInfo, + logCollector = tangemLogCollector, + preferencesStorage = preferencesStorage, + ) + feedbackManager.initChat( + context = context, + zendeskConfig = config.zendesk!!, + ) + store.dispatch(GlobalAction.SetFeedbackManager(feedbackManager)) + } + + private fun initWarningMessagesManager() { + store.dispatch(GlobalAction.SetWarningManager(WarningMessagesManager())) + } } data class LogConfig( diff --git a/app/src/main/java/com/tangem/tap/common/AssetReader.kt b/app/src/main/java/com/tangem/tap/common/AssetReader.kt new file mode 100644 index 0000000000..3f5eb10dd9 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/AssetReader.kt @@ -0,0 +1,20 @@ +package com.tangem.tap.common + +import android.content.Context +import com.tangem.tap.common.extensions.readAssetAsString + +/** +[REDACTED_AUTHOR] + */ +interface AssetReader { + fun readAssetAsString(name: String): String +} + +class AndroidAssetReader( + private val context: Context, +) : AssetReader { + + override fun readAssetAsString(name: String): String { + return context.readAssetAsString(name) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/AppsFlyerAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/AppsFlyerAnalyticsHandler.kt index 64beb11b4a..16fa1644ab 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/AppsFlyerAnalyticsHandler.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/AppsFlyerAnalyticsHandler.kt @@ -1,6 +1,6 @@ package com.tangem.tap.common.analytics -import android.app.Application +import android.content.Context import com.appsflyer.AFInAppEventParameterName import com.appsflyer.AFInAppEventType import com.appsflyer.AppsFlyerLib @@ -8,7 +8,7 @@ import com.shopify.buy3.Storefront import com.tangem.common.card.Card import com.tangem.common.core.TangemSdkError -class AppsFlyerAnalyticsHandler(val context: Application): AnalyticsHandler() { +class AppsFlyerAnalyticsHandler(val context: Context): AnalyticsHandler() { override fun triggerEvent( event: AnalyticsEvent, @@ -16,8 +16,7 @@ class AppsFlyerAnalyticsHandler(val context: Application): AnalyticsHandler() { blockchain: String?, params: Map ) { - AppsFlyerLib.getInstance().logEvent(context, - event.event, prepareParams(card, blockchain)) + AppsFlyerLib.getInstance().logEvent(context, event.event, prepareParams(card, blockchain)) } override fun logCardSdkError( diff --git a/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsHandler.kt index c500f330b2..197f396621 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsHandler.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsHandler.kt @@ -1,6 +1,6 @@ package com.tangem.tap.common.analytics -import android.app.Application +import android.content.Context import com.shopify.buy3.Storefront import com.tangem.common.card.Card import com.tangem.common.core.TangemSdkError @@ -42,7 +42,7 @@ class GlobalAnalyticsHandler(val analyticsHandlers: List) : } companion object { - fun createDefaultAnalyticHandlers(context: Application): GlobalAnalyticsHandler { + fun createDefaultAnalyticHandlers(context: Context): GlobalAnalyticsHandler { return GlobalAnalyticsHandler( listOf( FirebaseAnalyticsHandler, diff --git a/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt b/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt index ddc7a41b23..70912f24a6 100644 --- a/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt +++ b/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt @@ -1,7 +1,5 @@ package com.tangem.tap.common.feedback -import android.content.Context -import android.content.pm.PackageManager import android.os.Build import com.tangem.blockchain.common.Amount import com.tangem.blockchain.common.AmountType @@ -45,15 +43,6 @@ class AdditionalFeedbackInfo { var fee: String = "" var token: String = "" - fun setAppVersion(context: Context) { - try { - val pInfo = context.packageManager.getPackageInfo(context.packageName, 0) - appVersion = pInfo.versionName - } catch (e: PackageManager.NameNotFoundException) { - e.printStackTrace() - } - } - fun setCardInfo(data: ScanResponse) { cardId = data.card.cardId cardBlockchain = data.walletData?.blockchain ?: "" diff --git a/app/src/main/java/com/tangem/tap/domain/TapErrors.kt b/app/src/main/java/com/tangem/tap/domain/TapErrors.kt index 9d3cc79eee..674487ff78 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapErrors.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapErrors.kt @@ -31,13 +31,13 @@ sealed class TapError( object InsufficientBalance : TapError(R.string.send_error_insufficient_balance) object BlockchainInternalError : TapError(R.string.send_error_blockchain_internal) object AmountExceedsBalance : TapError(R.string.send_validation_amount_exceeds_balance) + data class AmountLowerExistentialDeposit(override val args: List) : TapError(R.string.send_error_minimum_balance_format) object FeeExceedsBalance : TapError(R.string.send_validation_invalid_fee) object TotalExceedsBalance : TapError(R.string.send_validation_invalid_total) object InvalidAmountValue : TapError(R.string.send_validation_invalid_amount) object InvalidFeeValue : TapError(R.string.send_error_invalid_fee_value) data class DustAmount(override val args: List) : TapError(R.string.send_error_dust_amount_format) object DustChange : TapError(R.string.send_error_dust_change) - data class CreateAccountUnderfunded(override val args: List) : TapError(R.string.send_error_no_target_account) data class UnsupportedState( val stateError: String, diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigLoaders.kt b/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigLoaders.kt index 4c19bab889..ba33d98210 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigLoaders.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigLoaders.kt @@ -1,12 +1,8 @@ package com.tangem.tap.domain.configurable.config -import android.content.Context -import com.google.firebase.ktx.Firebase -import com.google.firebase.remoteconfig.ktx.remoteConfig import com.squareup.moshi.JsonAdapter import com.squareup.moshi.Moshi -import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler -import com.tangem.tap.common.extensions.readAssetAsString +import com.tangem.tap.common.AssetReader import com.tangem.tap.domain.configurable.Loader import timber.log.Timber @@ -14,8 +10,8 @@ import timber.log.Timber [REDACTED_AUTHOR] */ class FeaturesLocalLoader( - private val context: Context, - private val moshi: Moshi, + private val assetReader: AssetReader, + private val moshi: Moshi, ) : Loader { override fun load(onComplete: (ConfigModel) -> Unit) { @@ -23,8 +19,8 @@ class FeaturesLocalLoader( val featureAdapter: JsonAdapter = moshi.adapter(FeatureModel::class.java) val valuesAdapter: JsonAdapter = moshi.adapter(ConfigValueModel::class.java) - val jsonFeatures = context.readAssetAsString(Loader.featuresName) - val jsonConfigValues = context.readAssetAsString(Loader.configValuesName) + val jsonFeatures = assetReader.readAssetAsString(Loader.featuresName) + val jsonConfigValues = assetReader.readAssetAsString(Loader.configValuesName) ConfigModel(featureAdapter.fromJson(jsonFeatures), valuesAdapter.fromJson(jsonConfigValues)) } catch (ex: Exception) { @@ -33,31 +29,4 @@ class FeaturesLocalLoader( } onComplete(config) } -} - -class FeaturesRemoteLoader( - private val moshi: Moshi, -) : Loader { - - override fun load(onComplete: (ConfigModel) -> Unit) { - val emptyConfig = ConfigModel.empty() - val remoteConfig = Firebase.remoteConfig - remoteConfig.fetchAndActivate().addOnCompleteListener { - if (it.isSuccessful) { - val config = remoteConfig.getValue(Loader.featuresName) - val jsonConfig = config.asString() - if (jsonConfig.isEmpty()) { - onComplete(emptyConfig) - return@addOnCompleteListener - } - val featureAdapter: JsonAdapter = moshi.adapter(FeatureModel::class.java) - onComplete(ConfigModel(featureAdapter.fromJson(jsonConfig), null)) - } else { - onComplete(emptyConfig) - } - }.addOnFailureListener { - FirebaseAnalyticsHandler.logException("remote_config_error.features", it) - onComplete(emptyConfig) - } - } } \ No newline at end of file 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 bb94004636..62f367cb33 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 @@ -24,26 +24,19 @@ data class Config( val zendesk: ZendeskConfig? = null, ) -class ConfigManager( - private val localLoader: Loader, - private val remoteLoader: Loader -) { +class ConfigManager { var config: Config = Config() private set private var defaultConfig = Config() - fun load(onComplete: ((config: Config) -> Unit)? = null) { - localLoader.load { configModel -> + fun load(configLoader: Loader, onComplete: ((config: Config) -> Unit)? = null) { + configLoader.load { configModel -> setupFeature(configModel.features) setupKey(configModel.configValues) onComplete?.invoke(config) } - // Uncomment to enable remote config -// remoteLoader.load { config -> -// setupFeature(config.features) -// } } fun turnOff(name: String) { diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningLoader.kt b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningLoader.kt deleted file mode 100644 index c95fc39a24..0000000000 --- a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningLoader.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.tangem.tap.domain.configurable.warningMessage - -import com.google.firebase.ktx.Firebase -import com.google.firebase.remoteconfig.ktx.remoteConfig -import com.squareup.moshi.JsonAdapter -import com.squareup.moshi.Moshi -import com.squareup.moshi.Types -import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler -import com.tangem.tap.domain.configurable.Loader - -/** -[REDACTED_AUTHOR] - */ -class RemoteWarningLoader( - private val moshi: Moshi, -) : Loader> { - - override fun load(onComplete: (List) -> Unit) { - val emptyConfig = listOf() - val remoteConfig = Firebase.remoteConfig - remoteConfig.fetchAndActivate().addOnCompleteListener { - if (!it.isSuccessful) { - onComplete(emptyConfig) - return@addOnCompleteListener - } - - val config = remoteConfig.getValue(Loader.warnings) - val jsonConfig = config.asString() - if (jsonConfig.isEmpty()) { - onComplete(emptyConfig) - return@addOnCompleteListener - } - - val adapterType = Types.newParameterizedType(List::class.java, WarningMessage::class.java) - val warningsAdapter: JsonAdapter> = moshi.adapter(adapterType) - try { - val warnings = warningsAdapter.fromJson(jsonConfig) ?: listOf() - onComplete(warnings) - } catch (ex: Exception) { - handleError(ex) - onComplete(emptyConfig) - } - }.addOnFailureListener { - handleError(it) - onComplete(emptyConfig) - } - } - - private fun handleError(ex: Exception) { - FirebaseAnalyticsHandler.logException("remote_config_error.warnings", ex) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt index 10dbcb2cbb..683302ba73 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt @@ -1,35 +1,17 @@ package com.tangem.tap.domain.configurable.warningMessage import com.tangem.blockchain.common.Blockchain -import com.tangem.common.extensions.VoidCallback import com.tangem.tap.common.extensions.containsAny import com.tangem.tap.common.extensions.removeBy -import com.tangem.wallet.BuildConfig import com.tangem.wallet.R /** [REDACTED_AUTHOR] */ -class WarningMessagesManager( - private val warningLoader: RemoteWarningLoader, -) { +class WarningMessagesManager { private val warningsList: MutableList = mutableListOf() - fun load(onComplete: VoidCallback? = null) { - // exclude annoying remote debug warnings - if (BuildConfig.DEBUG) { - onComplete?.invoke() - return - } - warningLoader.load { remoteList -> - warningsList.clear() - warningsList.addAll(remoteList) - sortByPriority() - onComplete?.invoke() - } - } - fun addWarning(warning: WarningMessage) { if (findWarning(warning) == null) { warningsList.add(warning) @@ -37,7 +19,10 @@ class WarningMessagesManager( } } - fun getWarnings(location: WarningMessage.Location, forBlockchains: List = emptyList()): List { + fun getWarnings( + location: WarningMessage.Location, + forBlockchains: List = emptyList(), + ): List { return warningsList .filter { !it.isHidden && it.location.contains(location) } .filter { @@ -94,7 +79,7 @@ class WarningMessagesManager( null, R.string.alert_title, R.string.alert_developer_card, - WarningMessage.Origin.Local + WarningMessage.Origin.Local, ) fun alreadySignedHashesWarning(): WarningMessage = WarningMessage( @@ -106,7 +91,7 @@ class WarningMessagesManager( null, R.string.alert_title, R.string.alert_card_signed_transactions, - WarningMessage.Origin.Local + WarningMessage.Origin.Local, ) fun signedHashesMultiWalletWarning(): WarningMessage = WarningMessage( @@ -131,7 +116,7 @@ class WarningMessagesManager( null, R.string.warning_rate_app_title, R.string.warning_rate_app_message, - WarningMessage.Origin.Local + WarningMessage.Origin.Local, ) fun isAlreadySignedHashesWarning(warning: WarningMessage): Boolean { @@ -147,7 +132,7 @@ class WarningMessagesManager( null, R.string.warning_failed_to_verify_card_title, R.string.warning_failed_to_verify_card_message, - WarningMessage.Origin.Local + WarningMessage.Origin.Local, ) fun remainingSignaturesNotEnough(remainingSignatures: Int): WarningMessage = WarningMessage( @@ -160,7 +145,7 @@ class WarningMessagesManager( titleResId = R.string.alert_title, messageResId = R.string.warning_low_signatures_format, origin = WarningMessage.Origin.Local, - messageFormatArg = remainingSignatures.toString() + messageFormatArg = remainingSignatures.toString(), ) fun testCardWarning(): WarningMessage = WarningMessage( @@ -172,7 +157,7 @@ class WarningMessagesManager( null, R.string.alert_title, R.string.warning_testnet_card_message, - WarningMessage.Origin.Local + WarningMessage.Origin.Local, ) fun demoCardWarning(): WarningMessage = WarningMessage( @@ -184,7 +169,7 @@ class WarningMessagesManager( null, R.string.alert_title, R.string.alert_demo_message, - WarningMessage.Origin.Local + WarningMessage.Origin.Local, ) const val REMAINING_SIGNATURES_WARNING = 10 diff --git a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt index 43c91a54fb..1d02623442 100644 --- a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt @@ -13,6 +13,7 @@ import com.tangem.common.extensions.toHexString import com.tangem.domain.common.ScanResponse import com.tangem.network.common.MoshiConverter import com.tangem.operations.wallet.CreateWalletResponse +import com.tangem.tap.common.AssetReader import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsHandler import com.tangem.tap.tangemSdkManager @@ -119,10 +120,6 @@ class TwinCardsManager( } } -interface AssetReader { - fun readAssetAsString(name: String): String -} - private class Issuer( val id: String, val privateKey: String, diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsAction.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsAction.kt index ee4bd5ddab..5c915f9cb0 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsAction.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsAction.kt @@ -4,9 +4,9 @@ import com.tangem.Message import com.tangem.blockchain.common.WalletManager import com.tangem.common.extensions.VoidCallback import com.tangem.domain.common.ScanResponse +import com.tangem.tap.common.AssetReader import com.tangem.tap.common.redux.StateDialog import com.tangem.tap.domain.TapError -import com.tangem.tap.domain.twins.AssetReader import com.tangem.tap.domain.twins.TwinCardsManager import com.tangem.tap.features.onboarding.OnboardingWalletBalance import org.rekotlin.Action diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt index 7827a4f196..ee7eb79471 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt @@ -15,10 +15,10 @@ import com.tangem.blockchain.common.Blockchain import com.tangem.common.extensions.VoidCallback import com.tangem.domain.common.TwinCardNumber import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapfrogWidget +import com.tangem.tap.common.AndroidAssetReader import com.tangem.tap.common.extensions.beginDelayedTransition import com.tangem.tap.common.extensions.getDrawableCompat import com.tangem.tap.common.extensions.hide -import com.tangem.tap.common.extensions.readAssetAsString import com.tangem.tap.common.extensions.show import com.tangem.tap.common.extensions.stripZeroPlainString import com.tangem.tap.common.redux.navigation.AppScreen @@ -26,7 +26,6 @@ import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.common.redux.navigation.ShareElement import com.tangem.tap.common.toggleWidget.RefreshBalanceWidget import com.tangem.tap.common.transitions.InternalNoteLayoutTransition -import com.tangem.tap.domain.twins.AssetReader import com.tangem.tap.domain.twins.TwinsCardWidget import com.tangem.tap.features.addBackPressHandler import com.tangem.tap.features.onboarding.products.BaseOnboardingFragment @@ -46,13 +45,6 @@ class TwinsCardsFragment : BaseOnboardingFragment() { private lateinit var twinsWidget: TwinsCardWidget private lateinit var btnRefreshBalanceWidget: RefreshBalanceWidget - private val assetReader: AssetReader by lazy { - object : AssetReader { - override fun readAssetAsString(name: String): String = - requireContext().readAssetAsString(name) - } - } - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) postponeEnterTransition() @@ -250,7 +242,7 @@ class TwinsCardsFragment : BaseOnboardingFragment() { store.dispatch( TwinCardsAction.Wallet.LaunchFirstStep( Message(getString(R.string.twins_recreate_title_format, twinIndexNumber)), - assetReader + AndroidAssetReader(requireContext()), ) ) } diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/AmountMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/AmountMiddleware.kt index bfcbc36889..69bdcc3166 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/AmountMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/AmountMiddleware.kt @@ -120,6 +120,7 @@ private fun filterErrorsForAmountField(errors: EnumSet): EnumS TransactionError.TotalExceedsBalance -> { val notAcceptable = listOf(TransactionError.AmountExceedsBalance, TransactionError.FeeExceedsBalance) if (!showIntoAmountField.containsAll(notAcceptable)) showIntoAmountField.add(it) + showIntoAmountField.remove(TransactionError.AmountLowerExistentialDeposit) } else -> showIntoAmountField.add(it) } diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt index ee1b5eb1d2..54be369642 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt @@ -2,6 +2,7 @@ package com.tangem.tap.features.send.redux.middlewares import com.google.firebase.crashlytics.FirebaseCrashlytics import com.tangem.blockchain.blockchains.binance.BinanceTransactionExtras +import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider import com.tangem.blockchain.blockchains.stellar.StellarTransactionExtras import com.tangem.blockchain.blockchains.xrp.XrpTransactionBuilder import com.tangem.blockchain.common.Amount @@ -301,12 +302,21 @@ fun createValidateTransactionError( val tapErrors = errorList.map { when (it) { TransactionError.AmountExceedsBalance -> TapError.AmountExceedsBalance + TransactionError.AmountLowerExistentialDeposit -> { + if (walletManager is ExistentialDepositProvider) { + val args = listOf(walletManager.getExistentialDeposit().stripZeroPlainString()) + TapError.AmountLowerExistentialDeposit(args) + } else { + TapError.UnknownError + } + } TransactionError.FeeExceedsBalance -> TapError.FeeExceedsBalance TransactionError.TotalExceedsBalance -> TapError.TotalExceedsBalance TransactionError.InvalidAmountValue -> TapError.InvalidAmountValue TransactionError.InvalidFeeValue -> TapError.InvalidFeeValue TransactionError.DustAmount -> { - TapError.DustAmount(listOf(walletManager.dustValue?.stripZeroPlainString() ?: "0")) + val args = listOf(walletManager.dustValue?.stripZeroPlainString() ?: "0") + TapError.DustAmount(args) } TransactionError.DustChange -> TapError.DustChange else -> TapError.UnknownError diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt index 9d7ac05a20..4d4154218c 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt @@ -218,7 +218,7 @@ class ReceiptReducer : SendInternalReducer { } private fun String.addPrecisionSign(): String { - val result = if (feeState.feeIsApproximate) "$CAN_BE_LOWER_SIGN $this" else "" + val result = if (feeState.feeIsApproximate) "$CAN_BE_LOWER_SIGN $this" else this return result.trim() } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/SendTransactionFailsDialog.kt b/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/SendTransactionFailsDialog.kt index a4b5ff7539..0e35552e43 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/SendTransactionFailsDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/SendTransactionFailsDialog.kt @@ -2,6 +2,7 @@ package com.tangem.tap.features.send.ui.dialogs import android.content.Context import androidx.appcompat.app.AlertDialog +import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.BlockchainSdkError import com.tangem.common.module.ModuleMessageConverter import com.tangem.tangem_sdk_new.extensions.localizedDescription @@ -47,9 +48,13 @@ private class BlockchainSdkErrorConverter( override fun convert(message: BlockchainSdkError): String { return when (message) { is BlockchainSdkError.CreateAccountUnderfunded -> { - val reserve = message.minReserve.value?.stripZeroPlainString() ?: "0" - val symbol = message.minReserve.currencySymbol - context.getString(R.string.send_error_no_target_account, reserve, symbol) + val resStringId = when (message.blockchain) { + Blockchain.Polkadot, Blockchain.PolkadotTestnet -> R.string.no_account_polkadot + else -> R.string.send_error_no_target_account + } + val reserveValueString = message.minReserve.value?.stripZeroPlainString() ?: "0" + val argument = "$reserveValueString ${message.minReserve.currencySymbol}" + context.getString(resStringId, argument) } else -> message.customMessage } diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt index 31fa218cfd..fe3bee237d 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt @@ -81,7 +81,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : if (!it.viewFieldValue.isFromUserInput) etXlmMemo.setText(it.viewFieldValue.value) if (it.error != null) { if (it.error == TransactionExtraError.INVALID_XLM_MEMO) { - tilXlmMemo.error = fg.getText(R.string.send_error_invalid_memo) + tilXlmMemo.error = fg.getText(R.string.send_extras_error_invalid_memo) } } else { tilXlmMemo.error = null @@ -91,7 +91,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : if (infoState.xrpDestinationTag.error != null) { if (infoState.xrpDestinationTag.error == TransactionExtraError.INVALID_DESTINATION_TAG) { tilDestinationTag.error = - fg.getText(R.string.send_error_invalid_destination_tag) + fg.getText(R.string.send_extras_error_invalid_destination_tag) } } else { tilDestinationTag.error = null @@ -103,7 +103,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : infoState.binanceMemo?.let { if (infoState.binanceMemo.error != null) { if (infoState.binanceMemo.error == TransactionExtraError.INVALID_BINANCE_MEMO) { - tilBinanceMemo.error = fg.getText(R.string.send_error_invalid_memo) + tilBinanceMemo.error = fg.getText(R.string.send_extras_error_invalid_memo) } } else { tilBinanceMemo.error = null diff --git a/app/src/main/res/values-de/strings_blockchain.xml b/app/src/main/res/values-de/strings_blockchain.xml index 2f52667c19..5cb1360d71 100644 --- a/app/src/main/res/values-de/strings_blockchain.xml +++ b/app/src/main/res/values-de/strings_blockchain.xml @@ -5,7 +5,7 @@ Falsche Gebühr Minimaler Betrag ist %s Restbestand zu klein - Das Zielkonto ist nicht erstellt. Der abzusendende Betrag soll %s %s + Gebühr oder mehr sein + Das Zielkonto ist nicht erstellt. Der abzusendende Betrag soll %s + Gebühr oder mehr sein Um ein Konto zu erstellen, senden Sie 1+ XLM an diese Adresse Erhalt der Gebühr fehlgeschlagen Unbekannter Fehler @@ -17,4 +17,11 @@ Der Betrag geht über die Bilanz hinaus Der Gesamtbetrag geht über die Bilanz hinaus Die Gebühr geht über die Bilanz hinaus + Minimum balance is %s + Memo + Tag + Invalid Memo. It won\'t be added to the transaction + Invalid Tag. It won\'t be added to the transaction + %s network has a concept of Existential Deposit. If your account drops below %s %s it will be deactivated and any remaining funds will be destroyed. + Destination account is not active. Send %s or more to activate the account. \ No newline at end of file diff --git a/app/src/main/res/values-de/strings_final.xml b/app/src/main/res/values-de/strings_final.xml index 7e585b36f2..13aa0a643a 100644 --- a/app/src/main/res/values-de/strings_final.xml +++ b/app/src/main/res/values-de/strings_final.xml @@ -86,9 +86,4 @@ Reset to Factory Settings Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. Select network - Memo - Tag - Invalid Memo. It won\'t be added to the transaction - Invalid Tag. It won\'t be added to the transaction - %s network has a concept of Existential Deposit. If your account drops below %s %s it will be deactivated and any remaining funds will be destroyed. \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings_blockchain.xml b/app/src/main/res/values-fr/strings_blockchain.xml index f6e2cdef63..5bbb85c2f3 100644 --- a/app/src/main/res/values-fr/strings_blockchain.xml +++ b/app/src/main/res/values-fr/strings_blockchain.xml @@ -5,7 +5,7 @@ Commission non valide Le montant minimal est de %s Le reste est trop petit - Le compte cible n\'a pas été créé. Le montant à envoyer doit être de %s %s + commissions ou plus + Le compte cible n\'a pas été créé. Le montant à envoyer doit être de %s + commissions ou plus Pour créer un compte, envoyez 1+ XLM à cette adresse Échec de réception des commissions Erreur inconnue @@ -17,4 +17,11 @@ Pour ne pas payer une commission élevée la prochaine fois que vous rechargez votre portefeuille, veuillez réduire le montant de %s XTZ Réduire de %s XTZ Non, envoyer toute la somme + Minimum balance is %s + Memo + Tag + Invalid Memo. It won\'t be added to the transaction + Invalid Tag. It won\'t be added to the transaction + %s network has a concept of Existential Deposit. If your account drops below %s %s it will be deactivated and any remaining funds will be destroyed. + Destination account is not active. Send %s or more to activate the account. \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings_final.xml b/app/src/main/res/values-fr/strings_final.xml index 5d8b24ed0f..737bdd59c1 100644 --- a/app/src/main/res/values-fr/strings_final.xml +++ b/app/src/main/res/values-fr/strings_final.xml @@ -86,9 +86,4 @@ Reset to Factory Settings Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. Select network - Memo - Tag - Invalid Memo. It won\'t be added to the transaction - Invalid Tag. It won\'t be added to the transaction - %s network has a concept of Existential Deposit. If your account drops below %s %s it will be deactivated and any remaining funds will be destroyed. \ No newline at end of file diff --git a/app/src/main/res/values-it/strings_blockchain.xml b/app/src/main/res/values-it/strings_blockchain.xml index cd0f690a23..775778dbb0 100644 --- a/app/src/main/res/values-it/strings_blockchain.xml +++ b/app/src/main/res/values-it/strings_blockchain.xml @@ -7,7 +7,7 @@ L\'importo residuo è molto basso Errore sconosciuto L\'importo supera il saldo - Per creare un account, invia %s %s a questo indirizzo + Per creare un account, invia %s a questo indirizzo Impossibile ottenere la commissione Per creare un account, invia 1+ XLM a questo indirizzo Indirizzo non valido @@ -17,4 +17,11 @@ Per evitare di pagare una commissione maggiore la prossima volta che ricarichi il tuo portafoglio, riduci l\'importo di %s XTZ Riduci di %s XTZ No, invia l\'intero importo + Minimum balance is %s + Memo + Tag + Invalid Memo. It won\'t be added to the transaction + Invalid Tag. It won\'t be added to the transaction + %s network has a concept of Existential Deposit. If your account drops below %s %s it will be deactivated and any remaining funds will be destroyed. + Destination account is not active. Send %s or more to activate the account. \ No newline at end of file diff --git a/app/src/main/res/values-it/strings_final.xml b/app/src/main/res/values-it/strings_final.xml index 5d8b24ed0f..737bdd59c1 100644 --- a/app/src/main/res/values-it/strings_final.xml +++ b/app/src/main/res/values-it/strings_final.xml @@ -86,9 +86,4 @@ Reset to Factory Settings Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. Select network - Memo - Tag - Invalid Memo. It won\'t be added to the transaction - Invalid Tag. It won\'t be added to the transaction - %s network has a concept of Existential Deposit. If your account drops below %s %s it will be deactivated and any remaining funds will be destroyed. \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings_blockchain.xml b/app/src/main/res/values-ru/strings_blockchain.xml index 98b7ad7194..61a4c91467 100644 --- a/app/src/main/res/values-ru/strings_blockchain.xml +++ b/app/src/main/res/values-ru/strings_blockchain.xml @@ -7,7 +7,7 @@ Сдача слишком мала Для создания учетной записи отправьте 1+ XLM на этот адрес Не удалось получить комиссию - Целевая учетная запись не создана. Сумма для отправки должна быть %1$s %2$s + плата за создание или больше + Целевая учетная запись не создана. Сумма для отправки должна быть %s + плата за создание или больше Неизвестная ошибка Неверный адрес Недопустимая сумма @@ -17,4 +17,6 @@ Чтобы не платить повышенную комиссию при следующем пополнении кошелька, уменьшите сумму на %s XTZ Уменьшить на %s XTZ Нет, отправить все + Минимальный баланс: %s + Аккаунт получателя не активирован. Отправьте %s или более для активации аккаунта. \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings_final.xml b/app/src/main/res/values-ru/strings_final.xml index 4bc89187dc..09b2609172 100644 --- a/app/src/main/res/values-ru/strings_final.xml +++ b/app/src/main/res/values-ru/strings_final.xml @@ -99,7 +99,7 @@ Выберите сеть Memo Tag - Недопустимый Memo. Он не будет добавлен в транзакцию. - Недопустимый Tag. Он не будет добавлен в транзакцию. + Недопустимый Memo. Он не будет добавлен в транзакцию. + Недопустимый Tag. Он не будет добавлен в транзакцию. Сеть %s использует концепцию экзистенциального депозита. Если баланс вашего счета опустится ниже %s %s, он будет деактивирован, а все оставшиеся средства будут уничтожены. diff --git a/app/src/main/res/values/strings_blockchain.xml b/app/src/main/res/values/strings_blockchain.xml index 35bc8cf334..6a496314b1 100644 --- a/app/src/main/res/values/strings_blockchain.xml +++ b/app/src/main/res/values/strings_blockchain.xml @@ -7,7 +7,7 @@ Change is too small To create account send 1+ XLM to this address Failed to get fee - Target account is not created. Amount to send should be %s %s + fee or more to create + Target account is not created. Amount to send should be %s + fee or more to create Unknown error Invalid address Invalid amount @@ -17,4 +17,11 @@ To avoid paying an increased commission the next time you top up your wallet, reduce the amount by %s XTZ Reduce by %s XTZ No, send all + Minimum balance is %s + Memo + Tag + Invalid Memo. It won\'t be added to the transaction + Invalid Tag. It won\'t be added to the transaction + %s network has a concept of Existential Deposit. If your account drops below %s %s it will be deactivated and any remaining funds will be destroyed. + Destination account is not active. Send %s or more to activate the account. \ No newline at end of file diff --git a/app/src/main/res/values/strings_final.xml b/app/src/main/res/values/strings_final.xml index fa691840a2..adee69f918 100644 --- a/app/src/main/res/values/strings_final.xml +++ b/app/src/main/res/values/strings_final.xml @@ -99,9 +99,4 @@ Reset to Factory Settings Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. Select network - Memo - Tag - Invalid Memo. It won\'t be added to the transaction - Invalid Tag. It won\'t be added to the transaction - %s network has a concept of Existential Deposit. If your account drops below %s %s it will be deactivated and any remaining funds will be destroyed. diff --git a/dependencies.gradle b/dependencies.gradle index 394b8cc997..8762730416 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -2,7 +2,7 @@ ext.versions = [ kotlin : '1.6.10', build_gradle : '7.1.3', tangem_card_sdk : 'develop-159', - tangem_blockchain_sdk: 'develop-111', + tangem_blockchain_sdk: 'develop-113', // tangem_blockchain_sdk: '0.0.1', ]