Updated on 2026-08-14

This commit is contained in:
Tangem 2022-07-13 00:19:07 +03:00
parent 3f2e5700fb
commit c445651ca9
6 changed files with 108 additions and 40 deletions

View file

@ -27,11 +27,11 @@ import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
import com.tangem.tap.features.shop.redux.ShopAction
import com.tangem.wallet.R
import com.tangem.wallet.databinding.ActivityMainBinding
import java.lang.ref.WeakReference
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import java.lang.ref.WeakReference
import kotlin.coroutines.CoroutineContext
lateinit var tangemSdk: TangemSdk
lateinit var tangemSdkManager: TangemSdkManager
@ -57,7 +57,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
systemActions()
store.state.globalState.feedbackManager?.updateActivity(this)
store.dispatch(NavigationAction.ActivityCreated(WeakReference(this)))
tangemSdk = TangemSdk.init(this, TangemSdkManager.config)

View file

@ -89,9 +89,16 @@ class TapApplication : Application(), ImageLoaderFactory {
val localLoader = FeaturesLocalLoader(this, moshi)
val remoteLoader = FeaturesRemoteLoader(moshi)
val configManager = ConfigManager(localLoader, remoteLoader)
configManager.load {
configManager.load { config ->
store.dispatch(GlobalAction.SetConfigManager(configManager))
shopService = TangemShopService(this, configManager.config.shopify!!)
shopService = TangemShopService(
application = this,
shopifyShop = config.shopify!!
)
store.state.globalState.feedbackManager?.initChat(
context = this,
zendeskConfig = config.zendesk!!
)
}
val warningsManager = WarningMessagesManager(RemoteWarningLoader(moshi))
warningsManager.load { store.dispatch(GlobalAction.SetWarningManager(warningsManager)) }

View file

@ -1,14 +1,22 @@
package com.tangem.tap.common.feedback
import android.app.Activity
import android.content.Context
import com.tangem.domain.common.TapWorkarounds
import com.tangem.tap.common.extensions.sendEmail
import com.tangem.tap.common.log.TangemLogCollector
import com.tangem.tap.common.zendesk.ZendeskConfig
import com.tangem.tap.foregroundActivityObserver
import com.tangem.tap.withForegroundActivity
import java.io.File
import java.io.FileWriter
import java.io.StringWriter
import timber.log.Timber
import zendesk.configurations.Configuration
import zendesk.core.Zendesk
import zendesk.support.Support
import zendesk.support.request.RequestConfiguration
import zendesk.support.requestlist.RequestListActivity
import zendesk.support.requestlist.RequestListConfiguration
/**
[REDACTED_AUTHOR]
@ -17,38 +25,47 @@ class FeedbackManager(
val infoHolder: AdditionalFeedbackInfo,
private val logCollector: TangemLogCollector,
) {
private lateinit var activity: Activity
fun updateActivity(activity: Activity) {
this.activity = activity
fun initChat(
context: Context,
zendeskConfig: ZendeskConfig,
) {
Zendesk.INSTANCE.init(
/* context = */ context,
/* zendeskUrl = */ zendeskConfig.url,
/* applicationId = */ zendeskConfig.appId,
/* oauthClientId = */ zendeskConfig.clientId,
)
Support.INSTANCE.init(Zendesk.INSTANCE)
}
fun sendEmail(feedbackData: FeedbackData, onFail: ((Exception) -> Unit)? = null) {
if (!this::activity.isInitialized) return
feedbackData.prepare(infoHolder)
val fileLog = if (feedbackData is ScanFailsEmail) createLogFile() else null
activity.sendEmail(
email = getSupportEmail(),
subject = activity.getString(feedbackData.subjectResId),
message = feedbackData.joinTogether(activity, infoHolder),
file = fileLog,
onFail = onFail
)
}
private fun getSupportEmail(): String {
return if (TapWorkarounds.isStart2CoinIssuer(infoHolder.cardIssuer)) {
S2C_SUPPORT_EMAIL
} else {
DEFAULT_SUPPORT_EMAIL
foregroundActivityObserver.withForegroundActivity { activity ->
val fileLog = if (feedbackData is ScanFailsEmail) createLogFile(activity) else null
activity.sendEmail(
email = getSupportEmail(),
subject = activity.getString(feedbackData.subjectResId),
message = feedbackData.joinTogether(activity, infoHolder),
file = fileLog,
onFail = onFail
)
}
}
private fun createLogFile(): File? {
fun openChat(feedbackData: FeedbackData) {
feedbackData.prepare(infoHolder)
foregroundActivityObserver.withForegroundActivity { activity ->
RequestListActivity.builder()
.show(
/* context = */ activity,
/* configurations = */ buildConfigs(activity, feedbackData)
)
}
}
private fun createLogFile(context: Context): File? {
return try {
val file = File(activity.filesDir, "logs.txt")
val file = File(context.filesDir, "logs.txt")
file.delete()
file.createNewFile()
@ -60,11 +77,35 @@ class FeedbackManager(
logCollector.clearLogs()
file
} catch (ex: Exception) {
Timber.e(ex, "Can't create a file for email attachment")
Timber.e(ex, "Can't create the logs file")
null
}
}
private fun buildConfigs(
context: Context,
feedbackData: FeedbackData,
): List<Configuration> {
return listOf(
// Request configuration
RequestConfiguration.Builder()
.withRequestSubject(context.getString(feedbackData.subjectResId))
.config(),
// Request list configuration
RequestListConfiguration.Builder()
.withContactUsButtonVisible(true)
.config(),
)
}
private fun getSupportEmail(): String {
return if (TapWorkarounds.isStart2CoinIssuer(infoHolder.cardIssuer)) {
S2C_SUPPORT_EMAIL
} else {
DEFAULT_SUPPORT_EMAIL
}
}
companion object {
const val DEFAULT_SUPPORT_EMAIL = "support@tangem.com"
const val S2C_SUPPORT_EMAIL = "cardsupport@start2coin.com"

View file

@ -0,0 +1,16 @@
package com.tangem.tap.common.zendesk
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class ZendeskConfig(
@Json(name = "zendeskApiKey")
val apiKey: String,
@Json(name = "zendeskAppId")
val appId: String,
@Json(name = "zendeskClientId")
val clientId: String,
@Json(name = "zendeskUrl")
val url: String,
)

View file

@ -1,8 +1,8 @@
package com.tangem.tap.domain.configurable.config
import com.tangem.blockchain.common.BlockchainSdkConfig
import com.tangem.common.extensions.VoidCallback
import com.tangem.tap.common.shop.shopify.ShopifyShop
import com.tangem.tap.common.zendesk.ZendeskConfig
import com.tangem.tap.domain.configurable.Loader
/**
@ -20,7 +20,8 @@ data class Config(
val isTopUpEnabled: Boolean = false,
@Deprecated("Not relevant since version 3.23")
val isCreatingTwinCardsAllowed: Boolean = false,
val shopify: ShopifyShop? = null
val shopify: ShopifyShop? = null,
val zendesk: ZendeskConfig? = null,
)
class ConfigManager(
@ -33,11 +34,11 @@ class ConfigManager(
private var defaultConfig = Config()
fun load(onComplete: VoidCallback? = null) {
localLoader.load { config ->
setupFeature(config.features)
setupKey(config.configValues)
onComplete?.invoke()
fun load(onComplete: ((config: Config) -> Unit)? = null) {
localLoader.load { configModel ->
setupFeature(configModel.features)
setupKey(configModel.configValues)
onComplete?.invoke(config)
}
// Uncomment to enable remote config
// remoteLoader.load { config ->
@ -94,6 +95,7 @@ class ConfigManager(
),
appsFlyerDevKey = values.appsFlyerDevKey,
shopify = values.shopifyShop,
zendesk = values.zendesk,
)
defaultConfig = defaultConfig.copy(
coinMarketCapKey = values.coinMarketCapKey,
@ -109,6 +111,7 @@ class ConfigManager(
),
appsFlyerDevKey = values.appsFlyerDevKey,
shopify = values.shopifyShop,
zendesk = values.zendesk,
)
}

View file

@ -1,6 +1,7 @@
package com.tangem.tap.domain.configurable.config
import com.tangem.tap.common.shop.shopify.ShopifyShop
import com.tangem.tap.common.zendesk.ZendeskConfig
/**
[REDACTED_AUTHOR]
@ -24,7 +25,8 @@ class ConfigValueModel(
val blockcypherTokens: Set<String>?,
val infuraProjectId: String?,
val appsFlyerDevKey: String,
val shopifyShop: ShopifyShop?
val shopifyShop: ShopifyShop?,
val zendesk: ZendeskConfig?,
)
class ConfigModel(val features: FeatureModel?, val configValues: ConfigValueModel?) {