Updated on 2026-08-14
This commit is contained in:
parent
7124a57c4e
commit
30d2fab208
10 changed files with 120 additions and 149 deletions
|
|
@ -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,9 +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.WarningMessagesManager
|
||||
import com.tangem.tap.domain.tokens.CurrenciesRepository
|
||||
import com.tangem.tap.domain.walletconnect.WalletConnectRepository
|
||||
|
|
@ -36,7 +36,7 @@ import timber.log.Timber
|
|||
val store = Store(
|
||||
reducer = ::appReducer,
|
||||
middleware = AppState.getMiddleware(),
|
||||
state = AppState()
|
||||
state = AppState(),
|
||||
)
|
||||
val logConfig = LogConfig()
|
||||
|
||||
|
|
@ -48,98 +48,98 @@ 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
|
||||
})
|
||||
}
|
||||
|
||||
foregroundActivityObserver = ForegroundActivityObserver()
|
||||
registerActivityLifecycleCallbacks(foregroundActivityObserver.callbacks)
|
||||
|
||||
DomainLayer.init()
|
||||
NetworkConnectivity.createInstance(store, this)
|
||||
preferencesStorage = PreferencesStorage(this)
|
||||
currenciesRepository = CurrenciesRepository(this, store.state.domainNetworks.tangemTechService)
|
||||
walletConnectRepository = WalletConnectRepository(this)
|
||||
|
||||
foregroundActivityObserver = ForegroundActivityObserver()
|
||||
registerActivityLifecycleCallbacks(foregroundActivityObserver.callbacks)
|
||||
initFeedbackManager()
|
||||
loadConfigs()
|
||||
val configLoader = FeaturesLocalLoader(AndroidAssetReader(this), MoshiConverter.defaultMoshi())
|
||||
initConfigManager(configLoader) { config ->
|
||||
shopService = TangemShopService(this, config.shopify!!)
|
||||
initAppsFlyer(this, config)
|
||||
initFeedbackManager(this, preferencesStorage, config)
|
||||
}
|
||||
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)
|
||||
}
|
||||
store.dispatch(GlobalAction.SetWarningManager(WarningMessagesManager())) }
|
||||
}
|
||||
|
||||
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 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(
|
||||
|
|
|
|||
32
app/src/main/java/com/tangem/tap/common/AssetReader.kt
Normal file
32
app/src/main/java/com/tangem/tap/common/AssetReader.kt
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
package com.tangem.tap.common
|
||||
|
||||
import android.content.Context
|
||||
import com.tangem.tap.common.extensions.readAssetAsString
|
||||
import com.tangem.tap.common.extensions.readFile
|
||||
import com.tangem.tap.common.extensions.rewriteFile
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface AssetReader {
|
||||
fun readAssetAsString(name: String): String
|
||||
fun readFile(fileName: String): String
|
||||
fun rewriteFile(content: String, fileName: String)
|
||||
}
|
||||
|
||||
class AndroidAssetReader(
|
||||
private val context: Context,
|
||||
) : AssetReader {
|
||||
|
||||
override fun readAssetAsString(name: String): String {
|
||||
return context.readAssetAsString(name)
|
||||
}
|
||||
|
||||
override fun readFile(fileName: String): String {
|
||||
return context.readFile(fileName)
|
||||
}
|
||||
|
||||
override fun rewriteFile(content: String, fileName: String) {
|
||||
context.rewriteFile(content, fileName)
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String, String>
|
||||
) {
|
||||
AppsFlyerLib.getInstance().logEvent(context,
|
||||
event.event, prepareParams(card, blockchain))
|
||||
AppsFlyerLib.getInstance().logEvent(context, event.event, prepareParams(card, blockchain))
|
||||
}
|
||||
|
||||
override fun logCardSdkError(
|
||||
|
|
|
|||
|
|
@ -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<AnalyticsHandler>) :
|
|||
}
|
||||
|
||||
companion object {
|
||||
fun createDefaultAnalyticHandlers(context: Application): GlobalAnalyticsHandler {
|
||||
fun createDefaultAnalyticHandlers(context: Context): GlobalAnalyticsHandler {
|
||||
return GlobalAnalyticsHandler(
|
||||
listOf(
|
||||
FirebaseAnalyticsHandler,
|
||||
|
|
|
|||
|
|
@ -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 ?: ""
|
||||
|
|
|
|||
|
|
@ -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<ConfigModel> {
|
||||
|
||||
override fun load(onComplete: (ConfigModel) -> Unit) {
|
||||
|
|
@ -23,8 +19,8 @@ class FeaturesLocalLoader(
|
|||
val featureAdapter: JsonAdapter<FeatureModel> = moshi.adapter(FeatureModel::class.java)
|
||||
val valuesAdapter: JsonAdapter<ConfigValueModel> = 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<ConfigModel> {
|
||||
|
||||
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<FeatureModel> = moshi.adapter(FeatureModel::class.java)
|
||||
onComplete(ConfigModel(featureAdapter.fromJson(jsonConfig), null))
|
||||
} else {
|
||||
onComplete(emptyConfig)
|
||||
}
|
||||
}.addOnFailureListener {
|
||||
FirebaseAnalyticsHandler.logException("remote_config_error.features", it)
|
||||
onComplete(emptyConfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,26 +24,19 @@ data class Config(
|
|||
val zendesk: ZendeskConfig? = null,
|
||||
)
|
||||
|
||||
class ConfigManager(
|
||||
private val localLoader: Loader<ConfigModel>,
|
||||
private val remoteLoader: Loader<ConfigModel>
|
||||
) {
|
||||
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<ConfigModel>, 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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<TwinCardsState>() {
|
|||
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<TwinCardsState>() {
|
|||
store.dispatch(
|
||||
TwinCardsAction.Wallet.LaunchFirstStep(
|
||||
Message(getString(R.string.twins_recreate_title_format, twinIndexNumber)),
|
||||
assetReader
|
||||
AndroidAssetReader(requireContext()),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue