Updated on 2026-08-14

This commit is contained in:
Tangem 2022-07-31 14:42:24 +04:00
commit 252bd57891
20 changed files with 170 additions and 99 deletions

View file

@ -144,7 +144,7 @@ dependencies {
implementation("com.squareup.okhttp3:logging-interceptor")
// Support
implementation("com.zendesk:support:5.0.9")
implementation("com.zendesk:chat:3.3.5")
implementation("com.zendesk:messaging:5.2.4")
//Crypto

View file

@ -47,7 +47,7 @@
<activity
android:exported="true"
android:name="com.tangem.tap.MainActivity"
android:launchMode="singleTask"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize">
<intent-filter>

View file

@ -8,6 +8,7 @@ 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
@ -108,7 +109,21 @@ class TapApplication : Application(), ImageLoaderFactory {
val infoHolder = AdditionalFeedbackInfo()
infoHolder.setAppVersion(this)
val logWriter = 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,
)
val logWriter = TangemLogCollector(
levels = logLevels,
messageFormatter = LogFormat.StairsFormatter()
)
Log.addLogger(logWriter)
store.dispatch(GlobalAction.SetFeedbackManager(FeedbackManager(infoHolder, logWriter)))
@ -126,4 +141,5 @@ class TapApplication : Application(), ImageLoaderFactory {
data class LogConfig(
val coil: Boolean = BuildConfig.DEBUG,
val storeAction: Boolean = BuildConfig.DEBUG,
val zendesk: Boolean = BuildConfig.DEBUG,
)

View file

@ -27,6 +27,7 @@ fun Blockchain.getRoundIconRes(): Int {
Blockchain.BSC, Blockchain.BSCTestnet, Blockchain.Binance, Blockchain.BinanceTestnet -> R.drawable.ic_bsc_round
Blockchain.Dogecoin -> R.drawable.ic_dogecoin_round
Blockchain.Tron, Blockchain.TronTestnet -> R.drawable.ic_tron_round
Blockchain.Gnosis -> R.drawable.ic_gnosis_round
else -> R.drawable.ic_tangem_logo
}
}
@ -53,6 +54,7 @@ fun Blockchain.getGreyedOutIconRes(): Int {
Blockchain.BSC, Blockchain.BSCTestnet, Blockchain.Binance, Blockchain.BinanceTestnet -> R.drawable.ic_bsc_no_color
Blockchain.Dogecoin -> R.drawable.ic_dogecoin_no_color
Blockchain.Tron, Blockchain.TronTestnet -> R.drawable.ic_tron_no_color
Blockchain.Gnosis -> R.drawable.ic_gnosis_no_color
else -> R.drawable.ic_tangem_logo
}
}

View file

@ -6,18 +6,19 @@ 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.logConfig
import com.tangem.tap.withForegroundActivity
import com.tangem.wallet.R
import com.zendesk.logger.Logger
import timber.log.Timber
import zendesk.chat.Chat
import zendesk.chat.ChatConfiguration
import zendesk.chat.ChatEngine
import zendesk.configurations.Configuration
import zendesk.messaging.MessagingActivity
import java.io.File
import java.io.FileWriter
import java.io.StringWriter
import timber.log.Timber
import zendesk.configurations.Configuration
import zendesk.core.AnonymousIdentity
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]
@ -30,14 +31,14 @@ class FeedbackManager(
context: Context,
zendeskConfig: ZendeskConfig,
) {
Zendesk.INSTANCE.init(
/* context = */ context,
/* zendeskUrl = */ zendeskConfig.url,
/* applicationId = */ zendeskConfig.appId,
/* oauthClientId = */ zendeskConfig.clientId,
Chat.INSTANCE.init(
context,
zendeskConfig.accountKey,
zendeskConfig.appId
)
Support.INSTANCE.init(Zendesk.INSTANCE)
Zendesk.INSTANCE.setIdentity(AnonymousIdentity())
// Zendesk logs
Logger.setLoggable(logConfig.zendesk)
}
fun sendEmail(feedbackData: FeedbackData, onFail: ((Exception) -> Unit)? = null) {
@ -57,11 +58,8 @@ class FeedbackManager(
fun openChat(feedbackData: FeedbackData) {
feedbackData.prepare(infoHolder)
foregroundActivityObserver.withForegroundActivity { activity ->
RequestListActivity.builder()
.show(
/* context = */ activity,
/* configurations = */ buildConfigs(activity, feedbackData)
)
setChatVisitorNote(activity, feedbackData)
showMessagingActivity(activity)
}
}
@ -84,20 +82,30 @@ class FeedbackManager(
}
}
private fun buildConfigs(
private fun setChatVisitorNote(
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(),
)
) {
Chat.INSTANCE.providers()
?.profileProvider()
?.setVisitorNote(feedbackData.joinTogether(context, infoHolder))
}
private fun showMessagingActivity(context: Context) {
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()
}
private fun getSupportEmail(): String {

View file

@ -1,25 +1,31 @@
package com.tangem.tap.common.log
import com.tangem.Log
import com.tangem.LogFormat
import com.tangem.TangemSdkLogger
import java.text.SimpleDateFormat
import java.util.Date
import java.util.*
class TangemLogCollector(
private val levels: List<Log.Level>,
private val messageFormatter: LogFormat,
) : TangemSdkLogger {
class TangemLogCollector : TangemSdkLogger {
private val dateFormatter = SimpleDateFormat("HH:mm:ss.SSS")
private val logs = mutableListOf<String>()
private val mutex = Object()
override fun log(message: () -> String, level: Log.Level) {
val time = dateFormatter.format(Date())
if (!levels.contains(level)) return
synchronized(mutex) {
logs.add("$time: ${message()}\n")
val formattedMessage = messageFormatter.format(message, level)
val logMessage = "${dateFormatter.format(Date())}: $formattedMessage"
logs.add("$logMessage\n")
}
}
fun getLogs(): List<String> = synchronized(mutex) { logs.toList() }
fun clearLogs() {
synchronized(mutex) { logs.clear() }
}
fun clearLogs() = synchronized(mutex) { logs.clear() }
}

View file

@ -11,6 +11,8 @@ data class ZendeskConfig(
val appId: String,
@Json(name = "zendeskClientId")
val clientId: String,
@Json(name = "zendeskAccountKey")
val accountKey: String,
@Json(name = "zendeskUrl")
val url: String,
)

View file

@ -28,11 +28,15 @@ class WalletConnectNetworkUtils {
peer.name.contains("BSC") -> {
Blockchain.BSC
}
peer.url.contains("honeyswap.1hive.eth.limo") -> {
// Check if something's changed after this bug report:
// https://github.com/1Hive/honeyswap-interface/issues/83
Blockchain.Gnosis
}
else -> {
Blockchain.Ethereum
Blockchain.Ethereum
}
}
}
}
}

View file

@ -2,7 +2,16 @@ package com.tangem.tap.features.tokens.ui.compose
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Divider
import androidx.compose.material.Text
@ -132,7 +141,9 @@ fun ExpandedCurrencyItem(
val contract = currency.contracts.firstOrNull { it.blockchain == blockchain }
?: return@map
val added = if (contract.address != null) {
addedTokens.map { it.token.contractAddress }.contains(contract.address)
addedTokens.any {
it.token.contractAddress == contract.address && it.blockchain == contract.blockchain
}
} else {
addedBlockchains.contains(blockchain)
}

View file

@ -9,7 +9,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.Token
import com.tangem.domain.common.TapWorkarounds.derivationStyle
import com.tangem.tap.common.extensions.getGreyedOutIconRes
import com.tangem.tap.common.extensions.getRoundIconRes
import com.tangem.tap.common.extensions.getString
import com.tangem.tap.common.extensions.hide
import com.tangem.tap.common.extensions.show
@ -118,7 +118,7 @@ class WalletAdapter
badgeCustomBalance.isVisible = isCustomCurrency
ivBlockchain.isVisible = wallet.currency.isToken()
ivBlockchain.setImageResource(wallet.currency.blockchain.getGreyedOutIconRes())
ivBlockchain.setImageResource(wallet.currency.blockchain.getRoundIconRes())
cardWallet.setOnClickListener {
store.dispatch(WalletAction.MultiWallet.SelectWallet(wallet))

View file

@ -24,7 +24,6 @@ class CurrencyIconView @JvmOverloads constructor(
init {
elevation = 0f
cardElevation = 0f
radius = dpToPx(8f)
background = null
radius = dpToPx(6f)
}
}

View file

@ -0,0 +1,21 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="22dp"
android:height="22dp"
android:viewportWidth="22"
android:viewportHeight="22">
<path
android:pathData="M11,0L11,0A11,11 0,0 1,22 11L22,11A11,11 0,0 1,11 22L11,22A11,11 0,0 1,0 11L0,11A11,11 0,0 1,11 0z"
android:fillColor="#F1F1F1" />
<path
android:pathData="M7.703,12.11C8.163,12.11 8.612,11.957 8.974,11.677L6.058,8.761C5.356,9.669 5.524,10.978 6.432,11.68C6.799,11.957 7.243,12.11 7.703,12.11Z"
android:fillColor="#A1A1A4" />
<path
android:pathData="M16.376,10.028C16.376,9.568 16.223,9.12 15.942,8.757L13.026,11.673C13.935,12.376 15.24,12.208 15.942,11.299C16.223,10.936 16.376,10.488 16.376,10.028Z"
android:fillColor="#A1A1A4" />
<path
android:pathData="M17.845,6.854L16.555,8.144C17.594,9.389 17.43,11.243 16.185,12.282C15.094,13.194 13.508,13.194 12.417,12.282L11,13.699L9.587,12.286C8.342,13.325 6.488,13.161 5.449,11.916C4.536,10.824 4.536,9.239 5.449,8.148L4.787,7.486L4.159,6.854C3.4,8.103 3,9.538 3,11C3,15.419 6.581,19 11,19C15.419,19 19,15.419 19,11C19.004,9.538 18.6,8.103 17.845,6.854Z"
android:fillColor="#A1A1A4" />
<path
android:pathData="M16.787,5.478C13.74,2.282 8.679,2.163 5.482,5.209C5.389,5.299 5.299,5.389 5.213,5.478C5.015,5.688 4.828,5.905 4.652,6.133L11,12.484L17.348,6.133C17.176,5.905 16.985,5.688 16.787,5.478ZM11,4.047C12.869,4.047 14.611,4.768 15.92,6.084L11,11.004L6.08,6.084C7.389,4.768 9.131,4.047 11,4.047Z"
android:fillColor="#A1A1A4" />
</vector>

View file

@ -0,0 +1,8 @@
<vector android:height="22dp" android:viewportHeight="22"
android:viewportWidth="22" android:width="22dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#3A775B" android:pathData="M11,0L11,0A11,11 0,0 1,22 11L22,11A11,11 0,0 1,11 22L11,22A11,11 0,0 1,0 11L0,11A11,11 0,0 1,11 0z"/>
<path android:fillColor="#ffffff" android:pathData="M7.703,12.11C8.163,12.11 8.612,11.957 8.974,11.677L6.058,8.761C5.356,9.669 5.524,10.978 6.432,11.68C6.799,11.957 7.243,12.11 7.703,12.11Z"/>
<path android:fillColor="#ffffff" android:pathData="M16.376,10.028C16.376,9.568 16.223,9.12 15.942,8.757L13.026,11.673C13.935,12.376 15.24,12.208 15.942,11.299C16.223,10.936 16.376,10.488 16.376,10.028Z"/>
<path android:fillColor="#ffffff" android:pathData="M17.845,6.854L16.555,8.144C17.594,9.389 17.43,11.243 16.185,12.282C15.094,13.194 13.508,13.194 12.417,12.282L11,13.699L9.587,12.286C8.342,13.325 6.488,13.161 5.449,11.916C4.536,10.824 4.536,9.239 5.449,8.148L4.787,7.486L4.159,6.854C3.4,8.103 3,9.538 3,11C3,15.419 6.581,19 11,19C15.419,19 19,15.419 19,11C19.004,9.538 18.6,8.103 17.845,6.854Z"/>
<path android:fillColor="#ffffff" android:pathData="M16.787,5.478C13.74,2.282 8.679,2.163 5.482,5.209C5.389,5.299 5.299,5.389 5.213,5.478C5.015,5.688 4.828,5.905 4.652,6.133L11,12.484L17.348,6.133C17.176,5.905 16.985,5.688 16.787,5.478ZM11,4.047C12.869,4.047 14.611,4.768 15.92,6.084L11,11.004L6.08,6.084C7.389,4.768 9.131,4.047 11,4.047Z"/>
</vector>

View file

@ -6,14 +6,14 @@
android:layout_height="wrap_content">
<com.google.android.material.card.MaterialCardView
android:id="@+id/card_wallet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:background="@android:color/white"
android:elevation="3dp">
android:id="@+id/card_wallet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:background="@android:color/white"
android:elevation="3dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
@ -42,16 +42,16 @@
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@id/iv_currency"
app:layout_constraintEnd_toEndOf="@id/iv_currency"
app:layout_constraintStart_toStartOf="@id/iv_currency"
app:layout_constraintTop_toTopOf="@id/iv_currency"
tools:text="J" />
app:layout_constraintEnd_toEndOf="@id/iv_currency"
app:layout_constraintStart_toStartOf="@id/iv_currency"
app:layout_constraintTop_toTopOf="@id/iv_currency"
tools:text="J" />
<ImageView
android:id="@+id/iv_blockchain"
android:layout_width="16dp"
android:layout_height="16dp"
android:padding="1dp"
android:layout_width="18dp"
android:layout_height="18dp"
android:padding="2dp"
android:translationX="4dp"
android:translationY="-4dp"
android:background="@drawable/shape_circle"
@ -60,7 +60,7 @@
android:visibility="gone"
app:layout_constraintTop_toTopOf="@id/iv_currency"
app:layout_constraintEnd_toEndOf="@id/iv_currency"
tools:src="@drawable/ic_eth_no_color"
tools:src="@drawable/ic_eth"
tools:visibility="visible" />
<View
@ -74,24 +74,24 @@
tools:visibility="visible" />
<include
layout="@layout/item_currency_wallet_content"
android:id="@+id/l_content"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="8dp"
android:visibility="gone"
app:layout_constraintStart_toEndOf="@id/iv_currency"
app:layout_constraintEnd_toEndOf="parent"
tools:visibility="visible" />
layout="@layout/item_currency_wallet_content"
android:id="@+id/l_content"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="8dp"
android:visibility="gone"
app:layout_constraintStart_toEndOf="@id/iv_currency"
app:layout_constraintEnd_toEndOf="parent"
tools:visibility="visible" />
<include
layout="@layout/item_currency_wallet_shimmer"
android:id="@+id/l_shimmer"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="8dp"
app:layout_constraintStart_toEndOf="@id/iv_currency"
app:layout_constraintEnd_toEndOf="parent" />
layout="@layout/item_currency_wallet_shimmer"
android:id="@+id/l_shimmer"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="8dp"
app:layout_constraintStart_toEndOf="@id/iv_currency"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>

View file

@ -77,6 +77,7 @@
<string name="common_yes">Да</string>
<string name="details_ask_a_question">Чат</string>
<string name="chat_bot_name">Tangem Bot</string>
<string name="card_settings_title">Настройки карты</string>
<string name="card_settings_security_mode">Тип безопасности</string>

View file

@ -78,6 +78,7 @@
<string name="common_no">No</string>
<string name="details_ask_a_question">Chat</string>
<string name="chat_bot_name">Tangem Bot</string>
<string name="card_settings_title">Card Settings</string>

View file

@ -4,15 +4,4 @@
<item name="colorPrimary">@color/darkGray6</item>
<item name="colorPrimaryDark">@color/darkGray6</item>
</style>
// Contact us FAB style
<style name="zs_contact_us_fab">
<item name="android:gravity">bottom|end</item>
<item name="android:layout_margin">@dimen/zs_fab_margin</item>
<item name="android:contentDescription">@string/zs_general_contact_us_button_label_accessibility</item>
<item name="android:visibility">gone</item>
<item name="backgroundTint">@color/selector_btn_green</item>
<item name="srcCompat">@drawable/zs_create_ticket_fab</item>
<item name="tint">@color/white</item>
</style>
</resources>

View file

@ -1,12 +1,12 @@
ext.versions = [
kotlin : '1.6.10',
build_gradle : '7.1.3',
tamgem_card_sdk : 'develop-156',
tamgem_blockchain_sdk: 'develop-96',
kotlin : '1.6.10',
build_gradle : '7.1.3',
tamgem_card_sdk : 'develop-157',
tamgem_blockchain_sdk: 'develop-99',
]
ext.environmentConfig = [
environment : "ENVIRONMENT",
testActionEnabled: "TEST_ACTION_ENABLED",
logEnabled : "LOG_ENABLED",
]
]

View file

@ -37,6 +37,7 @@ fun Blockchain.Companion.fromNetworkId(networkId: String): Blockchain? {
"tron" -> Blockchain.Tron
"tron/test" -> Blockchain.TronTestnet
"xrp", "ripple" -> Blockchain.XRP
"xdai" -> Blockchain.Gnosis
else -> null
}
}
@ -78,6 +79,7 @@ fun Blockchain.toNetworkId(): String {
Blockchain.XRP -> "xrp"
Blockchain.Tron -> "tron"
Blockchain.TronTestnet -> "tron/test"
Blockchain.Gnosis -> "xdai"
}
}
@ -102,6 +104,7 @@ fun Blockchain.toCoinId(): String {
Blockchain.XRP -> "ripple"
Blockchain.Dogecoin -> "dogecoin"
Blockchain.Tron, Blockchain.TronTestnet -> "tron"
else -> "unknown"
Blockchain.Gnosis -> "xdai"
Blockchain.Unknown -> "unknown"
}
}