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.tangem.Log import com.tangem.LogFormat 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.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 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 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 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.warningMessage.WarningMessagesManager import com.tangem.tap.domain.tokens.UserTokensRepository import com.tangem.tap.domain.totalBalance.TotalFiatBalanceCalculator import com.tangem.tap.domain.totalBalance.di.provideDefaultImplementation import com.tangem.tap.domain.walletCurrencies.WalletCurrenciesManager import com.tangem.tap.domain.walletCurrencies.di.provideDefaultImplementation import com.tangem.tap.domain.walletStores.WalletStoresManager import com.tangem.tap.domain.walletStores.di.provideDefaultImplementation import com.tangem.tap.domain.walletStores.repository.WalletAmountsRepository import com.tangem.tap.domain.walletStores.repository.WalletManagersRepository import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository import com.tangem.tap.domain.walletStores.repository.di.provideDefaultImplementation 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.tap.proxy.AppStateHolder import com.tangem.wallet.BuildConfig import com.zendesk.logger.Logger import dagger.hilt.android.HiltAndroidApp import org.rekotlin.Store import timber.log.Timber import zendesk.chat.Chat import javax.inject.Inject lateinit var store: Store lateinit var foregroundActivityObserver: ForegroundActivityObserver lateinit var activityResultCaller: ActivityResultCaller lateinit var preferencesStorage: PreferencesStorage lateinit var walletConnectRepository: WalletConnectRepository lateinit var shopService: TangemShopService lateinit var assetReader: AssetReader lateinit var userTokensRepository: UserTokensRepository private val walletStoresRepository by lazy { WalletStoresRepository.provideDefaultImplementation() } private val walletManagersRepository by lazy { WalletManagersRepository.provideDefaultImplementation( walletManagerFactory = WalletManagerFactory( blockchainSdkConfig = store.state.globalState.configManager ?.config ?.blockchainSdkConfig ?: BlockchainSdkConfig(), ), ) } private val walletAmountsRepository by lazy { WalletAmountsRepository.provideDefaultImplementation( tangemTechService = store.state.domainNetworks.tangemTechService, ) } val walletStoresManager by lazy { WalletStoresManager.provideDefaultImplementation( userTokensRepository = userTokensRepository, walletStoresRepository = walletStoresRepository, walletManagersRepository = walletManagersRepository, walletAmountsRepository = walletAmountsRepository, appCurrencyProvider = { store.state.globalState.appCurrency }, ) } val walletCurrenciesManager by lazy { WalletCurrenciesManager.provideDefaultImplementation( userTokensRepository = userTokensRepository, walletStoresRepository = walletStoresRepository, walletManagersRepository = walletManagersRepository, walletAmountsRepository = walletAmountsRepository, appCurrencyProvider = { store.state.globalState.appCurrency }, ) } val totalFiatBalanceCalculator by lazy { TotalFiatBalanceCalculator.provideDefaultImplementation() } val intentHandler by lazy { IntentHandler() } @HiltAndroidApp class TapApplication : Application(), ImageLoaderFactory { @Inject lateinit var appStateHolder: AppStateHolder override fun onCreate() { super.onCreate() store = Store( reducer = { action, state -> appReducer(action, state, appStateHolder) }, middleware = AppState.getMiddleware(), state = AppState(), ) if (BuildConfig.DEBUG) { Timber.plant(Timber.DebugTree()) } foregroundActivityObserver = ForegroundActivityObserver() activityResultCaller = 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.INSTANCE.moshi) initConfigManager(configLoader, ::initWithConfigDependency) initWarningMessagesManager() BlockchainSdkRetrofitBuilder.enableNetworkLogging = LogConfig.network.blockchainSdkNetwork userTokensRepository = UserTokensRepository.init( context = this, tangemTechService = store.state.domainNetworks.tangemTechService, ) appStateHolder.mainStore = store appStateHolder.userTokensRepository = userTokensRepository appStateHolder.walletStoresManager = walletStoresManager } //todo refactor: move to datasource and provide via DI 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, logEnabled = LogConfig.imageLoader, ) } private fun initConfigManager(loader: FeaturesLocalLoader, onComplete: (Config) -> Unit) { val configManager = ConfigManager() configManager.load(loader) { config -> store.dispatch(GlobalAction.SetConfigManager(configManager)) onComplete(config) } } private fun initWithConfigDependency(config: Config) { shopService = TangemShopService(this, config.shopify!!) initAnalytics(this, config) initFeedbackManager(this, preferencesStorage, config) } private fun initAnalytics(application: Application, config: Config) { val factory = AnalyticsFactory() factory.addHandlerBuilder(AmplitudeAnalyticsHandler.Builder()) factory.addHandlerBuilder(AppsFlyerAnalyticsHandler.Builder()) factory.addHandlerBuilder(FirebaseAnalyticsHandler.Builder()) factory.addFilter(ShopPurchasedEventFilter()) factory.addFilter(BasicSignInFilter()) factory.addFilter(BasicTopUpFilter(preferencesStorage.toppedUpWalletStorage)) val buildData = AnalyticsHandlerBuilder.Data( application = application, config = config, isDebug = BuildConfig.DEBUG, logConfig = LogConfig.analyticsHandlers, jsonConverter = MoshiConverter.INSTANCE, ) factory.build(Analytics, buildData) } 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.chatInitializer = { zendeskConfig -> Chat.INSTANCE.init(context, zendeskConfig.accountKey, zendeskConfig.appId) Logger.setLoggable(LogConfig.zendesk) } store.dispatch(GlobalAction.SetFeedbackManager(feedbackManager)) } private fun initWarningMessagesManager() { store.dispatch(GlobalAction.SetWarningManager(WarningMessagesManager())) } }