Updated on 2026-08-14
This commit is contained in:
parent
c3de434c54
commit
be0b066598
15 changed files with 6 additions and 163 deletions
|
|
@ -156,8 +156,6 @@ dependencies {
|
||||||
implementation(deps.appsflyer)
|
implementation(deps.appsflyer)
|
||||||
implementation(deps.amplitude)
|
implementation(deps.amplitude)
|
||||||
implementation(deps.kotsonGson)
|
implementation(deps.kotsonGson)
|
||||||
implementation(deps.zendesk.chat)
|
|
||||||
implementation(deps.zendesk.messaging)
|
|
||||||
implementation(deps.spongecastle.core)
|
implementation(deps.spongecastle.core)
|
||||||
implementation(deps.lottie)
|
implementation(deps.lottie)
|
||||||
implementation(deps.shopify.buy) {
|
implementation(deps.shopify.buy) {
|
||||||
|
|
|
||||||
|
|
@ -141,10 +141,6 @@
|
||||||
android:name="com.tangem.tap.common.qrCodeScan.ScanQrCodeActivity"
|
android:name="com.tangem.tap.common.qrCodeScan.ScanQrCodeActivity"
|
||||||
android:theme="@style/AppTheme" />
|
android:theme="@style/AppTheme" />
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name="zendesk.messaging.MessagingActivity"
|
|
||||||
android:theme="@style/ZendeskTheme" />
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.tangem.feature.learn2earn.presentation.webView.Learn2earnWebViewActivity"
|
android:name="com.tangem.feature.learn2earn.presentation.webView.Learn2earnWebViewActivity"
|
||||||
android:theme="@style/AppTheme" />
|
android:theme="@style/AppTheme" />
|
||||||
|
|
|
||||||
|
|
@ -338,7 +338,7 @@ internal class TapApplication : Application(), ImageLoaderFactory {
|
||||||
private fun initWithConfigDependency(config: Config) {
|
private fun initWithConfigDependency(config: Config) {
|
||||||
shopService = TangemShopService(this, config.shopify!!)
|
shopService = TangemShopService(this, config.shopify!!)
|
||||||
initAnalytics(this, config)
|
initAnalytics(this, config)
|
||||||
initFeedbackManager(this, preferencesStorage, foregroundActivityObserver, store)
|
initFeedbackManager(this, foregroundActivityObserver, store)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initAnalytics(application: Application, config: Config) {
|
private fun initAnalytics(application: Application, config: Config) {
|
||||||
|
|
@ -360,7 +360,6 @@ internal class TapApplication : Application(), ImageLoaderFactory {
|
||||||
|
|
||||||
private fun initFeedbackManager(
|
private fun initFeedbackManager(
|
||||||
context: Context,
|
context: Context,
|
||||||
preferencesStorage: PreferencesDataSource,
|
|
||||||
foregroundActivityObserver: ForegroundActivityObserver,
|
foregroundActivityObserver: ForegroundActivityObserver,
|
||||||
store: Store<AppState>,
|
store: Store<AppState>,
|
||||||
) {
|
) {
|
||||||
|
|
@ -399,7 +398,7 @@ internal class TapApplication : Application(), ImageLoaderFactory {
|
||||||
val feedbackManager = FeedbackManager(
|
val feedbackManager = FeedbackManager(
|
||||||
infoHolder = additionalFeedbackInfo,
|
infoHolder = additionalFeedbackInfo,
|
||||||
logCollector = tangemLogCollector,
|
logCollector = tangemLogCollector,
|
||||||
chatManager = ChatManager(preferencesStorage, foregroundActivityObserver),
|
chatManager = ChatManager(foregroundActivityObserver),
|
||||||
)
|
)
|
||||||
store.dispatch(GlobalAction.SetFeedbackManager(feedbackManager))
|
store.dispatch(GlobalAction.SetFeedbackManager(feedbackManager))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,23 @@
|
||||||
package com.tangem.tap.common.chat
|
package com.tangem.tap.common.chat
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
|
||||||
import com.tangem.data.source.preferences.PreferencesDataSource
|
|
||||||
import com.tangem.datasource.config.models.ChatConfig
|
import com.tangem.datasource.config.models.ChatConfig
|
||||||
import com.tangem.datasource.config.models.SprinklrConfig
|
import com.tangem.datasource.config.models.SprinklrConfig
|
||||||
import com.tangem.datasource.config.models.ZendeskConfig
|
|
||||||
import com.tangem.tap.ForegroundActivityObserver
|
import com.tangem.tap.ForegroundActivityObserver
|
||||||
import com.tangem.tap.common.chat.opener.ChatOpener
|
import com.tangem.tap.common.chat.opener.ChatOpener
|
||||||
import com.tangem.tap.common.chat.opener.implementation.SprinklrChatOpener
|
import com.tangem.tap.common.chat.opener.implementation.SprinklrChatOpener
|
||||||
import com.tangem.tap.common.chat.opener.implementation.ZendeskChatOpener
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class ChatManager(
|
class ChatManager(private val foregroundActivityObserver: ForegroundActivityObserver) {
|
||||||
private val preferencesStorage: PreferencesDataSource,
|
|
||||||
private val foregroundActivityObserver: ForegroundActivityObserver,
|
|
||||||
) {
|
|
||||||
private val openers = mutableMapOf<ChatConfig, ChatOpener>()
|
private val openers = mutableMapOf<ChatConfig, ChatOpener>()
|
||||||
|
|
||||||
fun open(config: ChatConfig, createLogsFile: (Context) -> File?, createFeedbackFile: (Context) -> File?) {
|
fun open(config: ChatConfig, createLogsFile: (Context) -> File?, createFeedbackFile: (Context) -> File?) {
|
||||||
val opener = openers.getOrPut(config) {
|
val opener = openers.getOrPut(config) {
|
||||||
when (config) {
|
when (config) {
|
||||||
is SprinklrConfig -> SprinklrChatOpener(config, foregroundActivityObserver)
|
is SprinklrConfig -> SprinklrChatOpener(config, foregroundActivityObserver)
|
||||||
is ZendeskConfig -> ZendeskChatOpener(getZendeskUserId(), config, foregroundActivityObserver)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
opener.open(createFeedbackFile, createLogsFile)
|
opener.open(createFeedbackFile, createLogsFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getZendeskUserId(): String {
|
|
||||||
if (preferencesStorage.zendeskFirstLaunchTime == null) {
|
|
||||||
preferencesStorage.zendeskFirstLaunchTime = System.currentTimeMillis()
|
|
||||||
}
|
|
||||||
|
|
||||||
return "${preferencesStorage.zendeskFirstLaunchTime}${Build.MODEL}".hashCode().toString()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
package com.tangem.tap.common.chat.opener.implementation
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import com.tangem.core.analytics.Analytics
|
|
||||||
import com.tangem.datasource.config.models.ZendeskConfig
|
|
||||||
import com.tangem.domain.common.LogConfig
|
|
||||||
import com.tangem.tap.ForegroundActivityObserver
|
|
||||||
import com.tangem.tap.common.chat.opener.ChatOpener
|
|
||||||
import com.tangem.tap.withForegroundActivity
|
|
||||||
import com.tangem.wallet.R
|
|
||||||
import com.zendesk.logger.Logger
|
|
||||||
import timber.log.Timber
|
|
||||||
import zendesk.chat.*
|
|
||||||
import zendesk.configurations.Configuration
|
|
||||||
import zendesk.messaging.MessagingActivity
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
internal class ZendeskChatOpener(
|
|
||||||
private val userId: String,
|
|
||||||
private val config: ZendeskConfig,
|
|
||||||
private val foregroundActivityObserver: ForegroundActivityObserver,
|
|
||||||
) : ChatOpener {
|
|
||||||
|
|
||||||
private var isInitialized = false
|
|
||||||
private var isFilesSent = false
|
|
||||||
|
|
||||||
override fun open(createFeedbackFile: (Context) -> File?, createLogsFile: (Context) -> File?) {
|
|
||||||
foregroundActivityObserver.withForegroundActivity { activity ->
|
|
||||||
initZendeskIfNeeded(activity.applicationContext)
|
|
||||||
setChatVisitorInfo()
|
|
||||||
showMessagingActivity(activity)
|
|
||||||
sendFeedbackFile(createFeedbackFile(activity))
|
|
||||||
sendLogsFile(createLogsFile(activity))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initZendeskIfNeeded(context: Context) {
|
|
||||||
if (isInitialized) return
|
|
||||||
isInitialized = true
|
|
||||||
|
|
||||||
Chat.INSTANCE.init(context, config.accountKey, config.appId)
|
|
||||||
Logger.setLoggable(LogConfig.zendesk)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setChatVisitorInfo() {
|
|
||||||
val visitorInfo = VisitorInfo.builder().withName("User $userId").build()
|
|
||||||
|
|
||||||
Chat.INSTANCE.chatProvidersConfiguration =
|
|
||||||
ChatProvidersConfiguration.builder().withVisitorInfo(visitorInfo).build()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun sendFeedbackFile(feedbackFile: File?) {
|
|
||||||
if (isInitialized && feedbackFile != null && !isFilesSent) {
|
|
||||||
Chat.INSTANCE.providers()?.chatProvider()?.sendFile(feedbackFile) { _, bytesUploaded, _ ->
|
|
||||||
Timber.d("Log file sent", "bytesUploaded: $bytesUploaded")
|
|
||||||
}
|
|
||||||
isFilesSent = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun sendLogsFile(logsFile: File?) {
|
|
||||||
if (isInitialized && logsFile != null && !isFilesSent) {
|
|
||||||
Chat.INSTANCE.providers()?.chatProvider()?.sendFile(logsFile) { _, bytesUploaded, _ ->
|
|
||||||
Timber.d("Log file sent", "bytesUploaded: $bytesUploaded")
|
|
||||||
}
|
|
||||||
isFilesSent = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
.withBotAvatarDrawable(R.mipmap.ic_launcher)
|
|
||||||
.withEngines(ChatEngine.engine())
|
|
||||||
.show(context, buildChatConfig())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildChatConfig(): Configuration {
|
|
||||||
return ChatConfiguration.builder()
|
|
||||||
.withOfflineFormEnabled(true)
|
|
||||||
.withAgentAvailabilityEnabled(true)
|
|
||||||
.withPreChatFormEnabled(false)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<style name="ZendeskTheme" parent="ZendeskThemeBase">
|
|
||||||
<item name="android:forceDarkAllowed">false</item>
|
|
||||||
</style>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<style name="ZendeskTheme" parent="ZendeskThemeBase" />
|
|
||||||
|
|
||||||
<style name="ZendeskThemeBase" parent="ZendeskSdkTheme.Light">
|
|
||||||
<item name="colorPrimary">@color/darkGray6</item>
|
|
||||||
<item name="colorPrimaryDark">@color/darkGray6</item>
|
|
||||||
</style>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -102,7 +102,6 @@ internal class ConfigManagerImpl @Inject constructor() : ConfigManager {
|
||||||
appsFlyerDevKey = configValues.appsFlyer.appsFlyerDevKey,
|
appsFlyerDevKey = configValues.appsFlyer.appsFlyerDevKey,
|
||||||
amplitudeApiKey = configValues.amplitudeApiKey,
|
amplitudeApiKey = configValues.amplitudeApiKey,
|
||||||
shopify = configValues.shopifyShop,
|
shopify = configValues.shopifyShop,
|
||||||
zendesk = configValues.zendesk,
|
|
||||||
sprinklr = configValues.sprinklr,
|
sprinklr = configValues.sprinklr,
|
||||||
swapReferrerAccount = configValues.swapReferrerAccount,
|
swapReferrerAccount = configValues.swapReferrerAccount,
|
||||||
walletConnectProjectId = configValues.walletConnectProjectId,
|
walletConnectProjectId = configValues.walletConnectProjectId,
|
||||||
|
|
|
||||||
|
|
@ -5,26 +5,9 @@ import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
sealed interface ChatConfig
|
sealed interface ChatConfig
|
||||||
|
|
||||||
@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 = "zendeskAccountKey")
|
|
||||||
val accountKey: String,
|
|
||||||
@Json(name = "zendeskUrl")
|
|
||||||
val url: String,
|
|
||||||
) : ChatConfig
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class SprinklrConfig(
|
data class SprinklrConfig(
|
||||||
@Json(name = "appID")
|
@Json(name = "appID") val appId: String,
|
||||||
val appId: String,
|
@Json(name = "apiKey") val apiKey: String,
|
||||||
@Json(name = "apiKey")
|
@Json(name = "environment") val environment: String,
|
||||||
val apiKey: String,
|
|
||||||
@Json(name = "environment")
|
|
||||||
val environment: String,
|
|
||||||
) : ChatConfig
|
) : ChatConfig
|
||||||
|
|
@ -15,7 +15,6 @@ data class Config(
|
||||||
@Deprecated("Not relevant since version 3.23")
|
@Deprecated("Not relevant since version 3.23")
|
||||||
val isCreatingTwinCardsAllowed: Boolean = false,
|
val isCreatingTwinCardsAllowed: Boolean = false,
|
||||||
val shopify: ShopifyShop? = null,
|
val shopify: ShopifyShop? = null,
|
||||||
val zendesk: ZendeskConfig? = null,
|
|
||||||
val sprinklr: SprinklrConfig? = null,
|
val sprinklr: SprinklrConfig? = null,
|
||||||
val swapReferrerAccount: SwapReferrerAccount? = null,
|
val swapReferrerAccount: SwapReferrerAccount? = null,
|
||||||
val walletConnectProjectId: String = "",
|
val walletConnectProjectId: String = "",
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ class ConfigValueModel(
|
||||||
val infuraProjectId: String?,
|
val infuraProjectId: String?,
|
||||||
val appsFlyer: AppsFlyer,
|
val appsFlyer: AppsFlyer,
|
||||||
val shopifyShop: ShopifyShop?,
|
val shopifyShop: ShopifyShop?,
|
||||||
val zendesk: ZendeskConfig?,
|
|
||||||
val sprinklr: SprinklrConfig?,
|
val sprinklr: SprinklrConfig?,
|
||||||
val tronGridApiKey: String,
|
val tronGridApiKey: String,
|
||||||
val amplitudeApiKey: String,
|
val amplitudeApiKey: String,
|
||||||
|
|
|
||||||
|
|
@ -42,10 +42,6 @@ class PreferencesDataSource @Inject internal constructor(applicationContext: Con
|
||||||
toppedUpWalletStorage = ToppedUpWalletStorage(preferences, moshiConverter)
|
toppedUpWalletStorage = ToppedUpWalletStorage(preferences, moshiConverter)
|
||||||
}
|
}
|
||||||
|
|
||||||
var zendeskFirstLaunchTime: Long?
|
|
||||||
get() = preferences.getLong(ZENDESK_FIRST_LAUNCH_KEY, 0).takeIf { it != 0L }
|
|
||||||
set(value) = preferences.edit { putLong(ZENDESK_FIRST_LAUNCH_KEY, value ?: 0) }
|
|
||||||
|
|
||||||
var sprinklrFirstLaunchTime: Long?
|
var sprinklrFirstLaunchTime: Long?
|
||||||
get() = preferences.getLong(SPRINKLR_FIRST_LAUNCH_KEY, 0).takeIf { it != 0L }
|
get() = preferences.getLong(SPRINKLR_FIRST_LAUNCH_KEY, 0).takeIf { it != 0L }
|
||||||
set(value) = preferences.edit { putLong(SPRINKLR_FIRST_LAUNCH_KEY, value ?: 0) }
|
set(value) = preferences.edit { putLong(SPRINKLR_FIRST_LAUNCH_KEY, value ?: 0) }
|
||||||
|
|
@ -93,7 +89,6 @@ class PreferencesDataSource @Inject internal constructor(applicationContext: Con
|
||||||
private const val PREFERENCES_NAME = "tapPrefs"
|
private const val PREFERENCES_NAME = "tapPrefs"
|
||||||
private const val TWINS_ONBOARDING_SHOWN_KEY = "twinsOnboardingShown"
|
private const val TWINS_ONBOARDING_SHOWN_KEY = "twinsOnboardingShown"
|
||||||
private const val APP_LAUNCH_COUNT_KEY = "launchCount"
|
private const val APP_LAUNCH_COUNT_KEY = "launchCount"
|
||||||
private const val ZENDESK_FIRST_LAUNCH_KEY = "chatFirstLaunchKey"
|
|
||||||
private const val SPRINKLR_FIRST_LAUNCH_KEY = "sprinklrFirstLaunch"
|
private const val SPRINKLR_FIRST_LAUNCH_KEY = "sprinklrFirstLaunch"
|
||||||
private const val SAVE_WALLET_DIALOG_SHOWN_KEY = "saveUserWalletShown"
|
private const val SAVE_WALLET_DIALOG_SHOWN_KEY = "saveUserWalletShown"
|
||||||
private const val SAVE_ACCESS_CODES_KEY = "saveAccessCodes"
|
private const val SAVE_ACCESS_CODES_KEY = "saveAccessCodes"
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import com.tangem.domain.features.BuildConfig
|
||||||
object LogConfig {
|
object LogConfig {
|
||||||
const val imageLoader: Boolean = false
|
const val imageLoader: Boolean = false
|
||||||
val storeAction: Boolean = BuildConfig.DEBUG
|
val storeAction: Boolean = BuildConfig.DEBUG
|
||||||
const val zendesk: Boolean = false
|
|
||||||
val network: NetworkLogConfig = NetworkLogConfig
|
val network: NetworkLogConfig = NetworkLogConfig
|
||||||
val analyticsHandlers: AnalyticsHandlersLogConfig = AnalyticsHandlersLogConfig
|
val analyticsHandlers: AnalyticsHandlersLogConfig = AnalyticsHandlersLogConfig
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,8 +67,6 @@ spongycastleCryptoCore = "1.58.0.0"
|
||||||
timber = "4.7.1"
|
timber = "4.7.1"
|
||||||
viewBindingDelegate = "1.5.9"
|
viewBindingDelegate = "1.5.9"
|
||||||
xmlShimmer = "1.1.3"
|
xmlShimmer = "1.1.3"
|
||||||
zendeskChat = "3.3.5"
|
|
||||||
zendeskMessaging = "5.2.4"
|
|
||||||
zxingQrBarcodeScanner = "1.9.8"
|
zxingQrBarcodeScanner = "1.9.8"
|
||||||
zxingQrCode = "3.5.1"
|
zxingQrCode = "3.5.1"
|
||||||
mviCore = "1.3.1"
|
mviCore = "1.3.1"
|
||||||
|
|
@ -219,8 +217,6 @@ retrofit-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.re
|
||||||
timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" }
|
timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" }
|
||||||
viewBindingDelegate = { module = "com.github.kirich1409:viewbindingpropertydelegate-noreflection", version.ref = "viewBindingDelegate" }
|
viewBindingDelegate = { module = "com.github.kirich1409:viewbindingpropertydelegate-noreflection", version.ref = "viewBindingDelegate" }
|
||||||
xmlShimmer = { module = "com.github.skydoves:androidveil", version.ref = "xmlShimmer" }
|
xmlShimmer = { module = "com.github.skydoves:androidveil", version.ref = "xmlShimmer" }
|
||||||
zendesk-chat = { module = "com.zendesk:chat", version.ref = "zendeskChat" }
|
|
||||||
zendesk-messaging = { module = "com.zendesk:messaging", version.ref = "zendeskMessaging" }
|
|
||||||
zxing-qrBarcodeScanner = { module = "me.dm7.barcodescanner:zxing", version.ref = "zxingQrBarcodeScanner" }
|
zxing-qrBarcodeScanner = { module = "me.dm7.barcodescanner:zxing", version.ref = "zxingQrBarcodeScanner" }
|
||||||
zxing-qrCore = { module = "com.google.zxing:core", version.ref = "zxingQrCode" }
|
zxing-qrCore = { module = "com.google.zxing:core", version.ref = "zxingQrCode" }
|
||||||
mviCore-watcher = { module = "com.github.badoo.mvicore:mvicore-diff", version.ref = "mviCore" }
|
mviCore-watcher = { module = "com.github.badoo.mvicore:mvicore-diff", version.ref = "mviCore" }
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@ dependencyResolutionManagement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
maven("https://jitpack.io")
|
maven("https://jitpack.io")
|
||||||
maven("https://zendesk.jfrog.io/zendesk/repo")
|
|
||||||
maven("https://clients-nexus.sprinklr.com/")
|
maven("https://clients-nexus.sprinklr.com/")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue