From da93332bc0568a0ee4c912026f84c69c0e993d6d Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 19 Sep 2023 16:22:34 +0300 Subject: [PATCH 1/6] Updated on 2026-08-14 --- .../paramsInterceptor/CardContextInterceptor.kt | 1 + .../tangem/tap/domain/tasks/product/ScanProductTask.kt | 10 +++++++++- .../com/tangem/domain/common/extensions/Blockchain.kt | 5 ++--- .../com/tangem/domain/models/scan/ScanResponse.kt | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt index 0db51098a3..6db15ac882 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt @@ -45,6 +45,7 @@ class CardContextInterceptor( ProductType.Note -> "Note" ProductType.Twins -> "Twin" ProductType.Wallet -> "Wallet" + ProductType.Wallet2 -> "Wallet 2.0" ProductType.Start2Coin -> "Start2Coin" else -> if (DemoHelper.isDemoCard(scanResponse)) { if (DemoHelper.isTestDemoCard(scanResponse)) { diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt index 31a7a1ade4..b587dee326 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt @@ -216,7 +216,7 @@ private class ScanWalletProcessor( session: CardSession, callback: (result: CompletionResult) -> Unit, ) { - val productType = ProductType.Wallet + val productType = getWalletProductType(card) val config = CardConfig.createConfig(card) scope.launch { val scanResponse = ScanResponse( @@ -280,6 +280,14 @@ private class ScanWalletProcessor( return blockchainsToDerive.distinct() } + private fun getWalletProductType(card: CardDTO): ProductType { + return if (card.firmwareVersion >= FirmwareVersion.Ed25519Slip0010Available) { + ProductType.Wallet2 + } else { + ProductType.Wallet + } + } + private fun getDefaultBlockchains( derivationStyleProvider: DerivationStyleProvider, ): MutableList { diff --git a/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt b/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt index 0970e85d77..3d315d3d8e 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt @@ -175,7 +175,6 @@ fun Blockchain.toCoinId(): String { Blockchain.Dash -> "dash" Blockchain.Kaspa -> "kaspa" Blockchain.TON, Blockchain.TONTestnet -> "the-open-network" - Blockchain.Unknown -> "unknown" Blockchain.Kava, Blockchain.KavaTestnet -> "kava" Blockchain.Ravencoin, Blockchain.RavencoinTestnet -> "ravencoin" Blockchain.Cosmos, Blockchain.CosmosTestnet -> "cosmos" @@ -185,8 +184,8 @@ fun Blockchain.toCoinId(): String { Blockchain.Telos, Blockchain.TelosTestnet -> "telos" Blockchain.AlephZero, Blockchain.AlephZeroTestnet -> "aleph-zero" Blockchain.OctaSpace, Blockchain.OctaSpaceTestnet -> "octaspace" - Blockchain.Chia -> "chia" - Blockchain.ChiaTestnet -> "chia/test" + Blockchain.Chia, Blockchain.ChiaTestnet -> "chia" + Blockchain.Unknown -> "unknown" } } diff --git a/domain/models/src/main/kotlin/com/tangem/domain/models/scan/ScanResponse.kt b/domain/models/src/main/kotlin/com/tangem/domain/models/scan/ScanResponse.kt index c6f1d9f75c..74a552e520 100644 --- a/domain/models/src/main/kotlin/com/tangem/domain/models/scan/ScanResponse.kt +++ b/domain/models/src/main/kotlin/com/tangem/domain/models/scan/ScanResponse.kt @@ -21,5 +21,5 @@ data class ScanResponse( typealias KeyWalletPublicKey = ByteArrayKey enum class ProductType { - Note, Twins, Wallet, Start2Coin + Note, Twins, Wallet, Start2Coin, Wallet2 } \ No newline at end of file From 8c792a2ce85c5be1de704ff53dd7885c95b0d51d Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 4 Oct 2023 14:33:33 +0500 Subject: [PATCH 2/6] Updated on 2026-08-14 --- .../wallet/redux/middlewares/WalletMiddleware.kt | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index 889dab19e8..b4f81bd001 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -180,7 +180,7 @@ class WalletMiddleware { } if (walletState.isMultiwalletAllowed) { - val amountToSend = sendableAmounts.find { it.currencySymbol == currency.currencySymbol } + val amountToSend = findAmountToSend(currency = currency, amounts = sendableAmounts) if (amountToSend == null) { val error = TapError.UnsupportedState("WalletAction.Send: Amount to send is null") FirebaseCrashlytics.getInstance().recordException(IllegalStateException(error.stateError)) @@ -277,6 +277,18 @@ class WalletMiddleware { } } + private fun findAmountToSend(currency: Currency, amounts: List): Amount? { + return amounts.find { amount -> + val amountType = amount.type + if (amountType is AmountType.Token && currency is Currency.Token) { + val token = amountType.token + token.symbol == currency.currencySymbol && token.contractAddress == currency.token.contractAddress + } else { + amount.currencySymbol == currency.currencySymbol + } + } + } + private fun makeInitSendStateActionByAmount( amount: Amount, walletStore: WalletStoreModel, From 131079f46330cc59b24d4b28f7600245b41d82cd Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 17 Oct 2023 11:19:08 +0300 Subject: [PATCH 3/6] Updated on 2026-08-14 --- app/build.gradle.kts | 31 +++++++-- app/src/main/AndroidManifest.xml | 16 +++-- .../java/com/tangem/tap/TapApplication.kt | 2 +- .../com/tangem/tap/common/chat/ChatManager.kt | 26 ++------ .../implementation/SprinklrChatOpener.kt | 53 +++++++++++---- .../com/tangem/tap/common/redux/AppReducer.kt | 2 - .../com/tangem/tap/common/redux/AppState.kt | 4 -- .../common/redux/global/GlobalMiddleware.kt | 4 +- .../features/onboarding/OnboardingHelper.kt | 4 +- .../features/sprinklr/redux/SprinklrAction.kt | 10 --- .../sprinklr/redux/SprinklrMiddleware.kt | 42 ------------ .../sprinklr/redux/SprinklrReducer.kt | 22 ------- .../features/sprinklr/redux/SprinklrState.kt | 6 -- .../sprinklr/redux/model/SprinklrUrl.kt | 27 -------- .../features/sprinklr/ui/SprinklrActivity.kt | 54 --------------- .../sprinklr/ui/SprinklrScreenContent.kt | 25 ------- .../sprinklr/ui/SprinklrScreenState.kt | 10 --- .../features/sprinklr/ui/SprinklrViewModel.kt | 66 ------------------- .../ui/webview/SprinklrWebViewClient.kt | 24 ------- .../datasource/config/ConfigManagerImpl.kt | 1 + .../datasource/config/models/ChatConfig.kt | 6 +- .../tangem/datasource/config/models/Config.kt | 1 + .../datasource/config/models/JsonModels.kt | 1 + .../card/DefaultCardSdkConfigRepository.kt | 1 + .../domain/userwallets/UserWalletBuilder.kt | 4 +- .../domain/userwallets/UserWalletIdBuilder.kt | 1 + gradle/dependencies.toml | 2 + settings.gradle.kts | 1 + 28 files changed, 104 insertions(+), 342 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrAction.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrMiddleware.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrReducer.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrState.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/sprinklr/redux/model/SprinklrUrl.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrActivity.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrScreenContent.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrScreenState.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrViewModel.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/sprinklr/ui/webview/SprinklrWebViewClient.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 570f9e96e3..e6e2daa7a3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -9,14 +9,34 @@ plugins { id("configuration") } -//conflict of dependencies when adding WalletConnectV2.0 library configurations { all { exclude(group = "org.bouncycastle", module = "bcprov-jdk15to18") - resolutionStrategy { - force("org.bouncycastle:bcpkix-jdk15on:1.70") - } exclude(group = "com.github.komputing.kethereum") + + resolutionStrategy { + dependencySubstitution { + substitute(module("com.facebook.react:react-native")) + .using(module("com.facebook.react:react-android:0.72.4")) + .because( + "The current version of SPR Client (3.6.2) is not compatible with the latest " + + "React Native version" + ) + + substitute(module("com.facebook.react:hermes-engine")) + .using(module("com.facebook.react:hermes-android:0.72.4")) + .because( + "The current version of SPR Client (3.6.2) is not compatible with the latest " + + "Hermes Engine version" + ) + } + + force( + "org.bouncycastle:bcpkix-jdk15on:1.70", + "com.facebook.react:react-android:0.72.4", + "com.facebook.react:hermes-android:0.72.4", + ) + } } } @@ -159,6 +179,9 @@ dependencies { implementation(deps.walletConnectCore) implementation(deps.walletConnectWeb3) implementation(deps.prettyLogger) + implementation(deps.sprClient) { + exclude(group = "com.github.stephenc.jcip") + } /** Testing libraries */ testImplementation(deps.test.junit) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 53d4be3c7f..c1b1d65718 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,6 +12,16 @@ + + + + + @@ -39,7 +49,7 @@ android:extractNativeLibs="true" android:supportsRtl="true" tools:ignore="GoogleAppIndexingWarning" - tools:replace="android:allowBackup, android:fullBackupContent"> + tools:replace="android:allowBackup, android:fullBackupContent, android:label"> - - diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index cfd38560ca..8c4091a21f 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -336,7 +336,7 @@ class TapApplication : Application(), ImageLoaderFactory { val feedbackManager = FeedbackManager( infoHolder = additionalFeedbackInfo, logCollector = tangemLogCollector, - chatManager = ChatManager(preferencesStorage, foregroundActivityObserver, store), + chatManager = ChatManager(preferencesStorage, foregroundActivityObserver), ) store.dispatch(GlobalAction.SetFeedbackManager(feedbackManager)) } diff --git a/app/src/main/java/com/tangem/tap/common/chat/ChatManager.kt b/app/src/main/java/com/tangem/tap/common/chat/ChatManager.kt index 56ded693ad..693113b27a 100644 --- a/app/src/main/java/com/tangem/tap/common/chat/ChatManager.kt +++ b/app/src/main/java/com/tangem/tap/common/chat/ChatManager.kt @@ -2,37 +2,31 @@ package com.tangem.tap.common.chat 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.SprinklrConfig import com.tangem.datasource.config.models.ZendeskConfig -import com.tangem.data.source.preferences.PreferencesDataSource import com.tangem.tap.ForegroundActivityObserver 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.ZendeskChatOpener -import com.tangem.tap.common.redux.AppState -import org.rekotlin.Store import java.io.File class ChatManager( private val preferencesStorage: PreferencesDataSource, private val foregroundActivityObserver: ForegroundActivityObserver, - private val store: Store, ) { private val openers = mutableMapOf() fun open(config: ChatConfig, createLogsFile: (Context) -> File?, createFeedbackFile: (Context) -> File?) { val opener = openers.getOrPut(config) { when (config) { - is SprinklrConfig -> SprinklrChatOpener(getSprinklrUserId(), config, store, foregroundActivityObserver) + is SprinklrConfig -> SprinklrChatOpener(config, foregroundActivityObserver) is ZendeskConfig -> ZendeskChatOpener(getZendeskUserId(), config, foregroundActivityObserver) } } - opener.open( - createFeedbackFile = createFeedbackFile, - createLogsFile = createLogsFile, - ) + opener.open(createFeedbackFile, createLogsFile) } private fun getZendeskUserId(): String { @@ -40,18 +34,6 @@ class ChatManager( preferencesStorage.zendeskFirstLaunchTime = System.currentTimeMillis() } - return getChatUserId(preferencesStorage.zendeskFirstLaunchTime!!) - } - - private fun getSprinklrUserId(): String { - if (preferencesStorage.sprinklrFirstLaunchTime == null) { - preferencesStorage.sprinklrFirstLaunchTime = System.currentTimeMillis() - } - - return getChatUserId(preferencesStorage.sprinklrFirstLaunchTime!!) - } - - private fun getChatUserId(firstLaunchTimeMillis: Long): String { - return "${firstLaunchTimeMillis}${Build.MODEL}".hashCode().toString() + return "${preferencesStorage.zendeskFirstLaunchTime}${Build.MODEL}".hashCode().toString() } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/chat/opener/implementation/SprinklrChatOpener.kt b/app/src/main/java/com/tangem/tap/common/chat/opener/implementation/SprinklrChatOpener.kt index f8936d6abd..0fcb2a4cf2 100644 --- a/app/src/main/java/com/tangem/tap/common/chat/opener/implementation/SprinklrChatOpener.kt +++ b/app/src/main/java/com/tangem/tap/common/chat/opener/implementation/SprinklrChatOpener.kt @@ -1,28 +1,57 @@ package com.tangem.tap.common.chat.opener.implementation +import android.annotation.SuppressLint +import android.app.Application import android.content.Context -import android.content.Intent +import android.provider.Settings +import com.spr.messengerclient.config.SPRMessenger +import com.spr.messengerclient.config.bean.SPRMessengerConfig +import com.tangem.common.extensions.guard import com.tangem.datasource.config.models.SprinklrConfig import com.tangem.tap.ForegroundActivityObserver import com.tangem.tap.common.chat.opener.ChatOpener -import com.tangem.tap.common.redux.AppState -import com.tangem.tap.features.sprinklr.redux.SprinklrAction -import com.tangem.tap.features.sprinklr.ui.SprinklrActivity -import com.tangem.tap.withForegroundActivity -import org.rekotlin.Store +import timber.log.Timber import java.io.File +import java.util.Locale internal class SprinklrChatOpener( - private val userId: String, private val config: SprinklrConfig, - private val store: Store, private val foregroundActivityObserver: ForegroundActivityObserver, ) : ChatOpener { + override fun open(createFeedbackFile: (Context) -> File?, createLogsFile: (Context) -> File?) { - store.dispatch(SprinklrAction.Init(userId, config)) - foregroundActivityObserver.withForegroundActivity { activity -> - val intent = Intent(activity, SprinklrActivity::class.java) - activity.startActivity(intent) + val messenger = SPRMessenger.shared() + + if (messenger.config == null) { + initSprConfig(messenger) + } + + messenger.startApplication() + } + + private fun initSprConfig(messenger: SPRMessenger) { + val application = foregroundActivityObserver.foregroundActivity?.application.guard { + Timber.e("The SPR chat cannot be opened because there are no activities in foreground") + return + } + + messenger.takeOff(application, createSprConfig(application, config)) + } + + @SuppressLint("HardwareIds") + private fun createSprConfig(application: Application, config: SprinklrConfig): SPRMessengerConfig { + return SPRMessengerConfig().apply { + appId = config.appId + appKey = CHAT_APP_KEY + deviceId = Settings.Secure.getString(application.contentResolver, Settings.Secure.ANDROID_ID) + environment = config.environment + skin = CHAT_SKIN + locale = Locale.getDefault().language } } + + private companion object { + const val CHAT_APP_KEY = "com.sprinklr.messenger.release" + const val CHAT_SKIN = "MODERN" + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt index 7210599e41..8175888c08 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt @@ -14,7 +14,6 @@ import com.tangem.tap.features.saveWallet.redux.SaveWalletReducer import com.tangem.tap.features.send.redux.reducers.SendScreenReducer import com.tangem.tap.features.shop.redux.ShopReducer import com.tangem.tap.features.signin.redux.SignInReducer -import com.tangem.tap.features.sprinklr.redux.SprinklrReducer import com.tangem.tap.features.tokens.legacy.redux.TokensReducer import com.tangem.tap.features.wallet.redux.reducers.WalletReducer import com.tangem.tap.features.walletSelector.redux.WalletSelectorReducer @@ -45,7 +44,6 @@ fun appReducer(action: Action, state: AppState?, appStateHolder: AppStateHolder) welcomeState = WelcomeReducer.reduce(action, state), saveWalletState = SaveWalletReducer.reduce(action, state), walletSelectorState = WalletSelectorReducer.reduce(action, state), - sprinklrState = SprinklrReducer.reduce(action, state), signInState = SignInReducer.reduce(action, state), daggerGraphState = DaggerGraphReducer.reduce(action, state), ) diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt index 71be2aa020..19248b08b9 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt @@ -32,8 +32,6 @@ import com.tangem.tap.features.shop.redux.ShopMiddleware import com.tangem.tap.features.shop.redux.ShopState import com.tangem.tap.features.signin.redux.SignInMiddleware import com.tangem.tap.features.signin.redux.SignInState -import com.tangem.tap.features.sprinklr.redux.SprinklrMiddleware -import com.tangem.tap.features.sprinklr.redux.SprinklrState import com.tangem.tap.features.tokens.legacy.redux.TokensMiddleware import com.tangem.tap.features.tokens.legacy.redux.TokensState import com.tangem.tap.features.wallet.redux.WalletState @@ -66,7 +64,6 @@ data class AppState( val welcomeState: WelcomeState = WelcomeState(), val saveWalletState: SaveWalletState = SaveWalletState(), val walletSelectorState: WalletSelectorState = WalletSelectorState(), - val sprinklrState: SprinklrState = SprinklrState(), val signInState: SignInState = SignInState(), val daggerGraphState: DaggerGraphState = DaggerGraphState(), ) : StateType { @@ -108,7 +105,6 @@ data class AppState( WalletSelectorMiddleware().middleware, LockUserWalletsTimerMiddleware().middleware, AccessCodeRequestPolicyMiddleware().middleware, - SprinklrMiddleware().middleware, SignInMiddleware.middleware, DaggerGraphMiddleware.daggerGraphMiddleware, ) diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt index 287b5d35f1..176841c442 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt @@ -100,10 +100,10 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di } // if config not set -> try to get it based on a scanResponse.productType - val unsafeChatConfig = action.chatConfig ?: config.zendesk + val unsafeChatConfig = action.chatConfig ?: config.sprinklr val chatConfig = unsafeChatConfig.guard { - store.dispatchDebugErrorNotification("ZendeskConfig not initialized") + store.dispatchDebugErrorNotification("The chat config is not initialized") return } feedbackManager.openChat(chatConfig, action.feedbackData) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt index baf5ed2fcf..68a4bb6df8 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt @@ -52,7 +52,9 @@ object OnboardingHelper { fun whereToNavigate(scanResponse: ScanResponse): AppScreen { return when (scanResponse.productType) { ProductType.Note -> AppScreen.OnboardingNote - ProductType.Wallet -> if (scanResponse.card.settings.isBackupAllowed) { + ProductType.Wallet, + ProductType.Wallet2, + -> if (scanResponse.card.settings.isBackupAllowed) { AppScreen.OnboardingWallet } else { AppScreen.OnboardingOther diff --git a/app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrAction.kt b/app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrAction.kt deleted file mode 100644 index b781ee102f..0000000000 --- a/app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrAction.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.tangem.tap.features.sprinklr.redux - -import com.tangem.datasource.config.models.SprinklrConfig -import org.rekotlin.Action - -sealed interface SprinklrAction : Action { - data class Init(val userId: String, val config: SprinklrConfig) : SprinklrAction - data class UpdateUrl(val url: String) : SprinklrAction - data class UpdateSprinklrDomains(val domains: List) : SprinklrAction -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrMiddleware.kt b/app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrMiddleware.kt deleted file mode 100644 index 922e3a2e67..0000000000 --- a/app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrMiddleware.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.tangem.tap.features.sprinklr.redux - -import com.tangem.datasource.config.models.SprinklrConfig -import com.tangem.tap.common.extensions.dispatchOnMain -import com.tangem.tap.common.redux.AppState -import com.tangem.tap.features.sprinklr.redux.model.SprinklrUrl -import com.tangem.tap.store -import org.rekotlin.Middleware - -internal class SprinklrMiddleware { - val middleware: Middleware = { _, appStateProvider -> - { next -> - { action -> - val appState = appStateProvider() - if (action is SprinklrAction && appState != null) { - handleAction(action) - } - next(action) - } - } - } - - private fun handleAction(action: SprinklrAction) { - when (action) { - is SprinklrAction.Init -> updateUrl(action.userId, action.config) - is SprinklrAction.UpdateUrl, - is SprinklrAction.UpdateSprinklrDomains, - -> Unit - } - } - - private fun updateUrl(userId: String, config: SprinklrConfig) { - updateSprinklrDomains(config.baseUrl) - val url = SprinklrUrl.Prod(userId, config.baseUrl, config.appId).url - store.dispatchOnMain(SprinklrAction.UpdateUrl(url)) - } - - private fun updateSprinklrDomains(baseUrl: String) { - val domains = listOf(baseUrl, SprinklrUrl.Static.url) - store.dispatchOnMain(SprinklrAction.UpdateSprinklrDomains(domains)) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrReducer.kt b/app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrReducer.kt deleted file mode 100644 index a27d16d2db..0000000000 --- a/app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrReducer.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.tangem.tap.features.sprinklr.redux - -import com.tangem.tap.common.redux.AppState -import org.rekotlin.Action - -internal object SprinklrReducer { - fun reduce(action: Action, state: AppState): SprinklrState { - return if (action is SprinklrAction) { - internalReduce(action, state.sprinklrState) - } else { - state.sprinklrState - } - } - - private fun internalReduce(action: SprinklrAction, state: SprinklrState): SprinklrState { - return when (action) { - is SprinklrAction.Init -> state - is SprinklrAction.UpdateUrl -> state.copy(url = action.url) - is SprinklrAction.UpdateSprinklrDomains -> state.copy(sprinklrDomains = action.domains) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrState.kt b/app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrState.kt deleted file mode 100644 index 12ba5b8672..0000000000 --- a/app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrState.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.tangem.tap.features.sprinklr.redux - -data class SprinklrState( - val url: String = "", - val sprinklrDomains: List = emptyList(), -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/sprinklr/redux/model/SprinklrUrl.kt b/app/src/main/java/com/tangem/tap/features/sprinklr/redux/model/SprinklrUrl.kt deleted file mode 100644 index 2d1eb1be87..0000000000 --- a/app/src/main/java/com/tangem/tap/features/sprinklr/redux/model/SprinklrUrl.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.tangem.tap.features.sprinklr.redux.model - -internal sealed class SprinklrUrl { - abstract val url: String - - class Prod(userId: String, baseUrl: String, appId: String) : SprinklrUrl() { - private val locale = java.util.Locale.getDefault().language - - override val url: String = "$baseUrl/page" + - "?appId=$appId" + - "&device=$Device" + - "&enableClose=$CloseEnabled" + - "&zoom=$ZoomEnabled" + - "&locale=$locale" + - "&user_id=$userId" - - companion object { - private const val Device = "MOBILE" - private const val CloseEnabled = true - private const val ZoomEnabled = false - } - } - - object Static : SprinklrUrl() { - override val url: String = "live-chat-static.sprinklr.com" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrActivity.kt b/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrActivity.kt deleted file mode 100644 index 7ddbf49c68..0000000000 --- a/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrActivity.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.tangem.tap.features.sprinklr.ui - -import android.os.Bundle -import androidx.activity.compose.BackHandler -import androidx.activity.viewModels -import androidx.compose.foundation.layout.imePadding -import androidx.compose.foundation.layout.systemBarsPadding -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.tangem.core.analytics.Analytics -import com.tangem.core.ui.components.SystemBarsEffect -import com.tangem.core.ui.res.TangemTheme -import com.tangem.core.ui.screen.ComposeActivity -import com.tangem.core.ui.theme.AppThemeModeHolder -import com.tangem.tap.common.analytics.events.Chat -import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject - -@AndroidEntryPoint -internal class SprinklrActivity : ComposeActivity() { - - @Inject - override lateinit var appThemeModeHolder: AppThemeModeHolder - - private val viewModel by viewModels() - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - Analytics.send(Chat.ScreenOpened()) - viewModel.setNavigateBackCallback { - this.finish() - } - } - - @Composable - override fun ScreenContent(modifier: Modifier) { - val state by viewModel.state.collectAsStateWithLifecycle() - - val systemBarsColor = TangemTheme.colors.background.primary - SystemBarsEffect { - setSystemBarsColor(systemBarsColor) - } - - BackHandler(onBack = state.onNavigateBack) - SprinklrScreenContent( - modifier = modifier - .systemBarsPadding() - .imePadding(), - state = state, - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrScreenContent.kt b/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrScreenContent.kt deleted file mode 100644 index 5277ba0cea..0000000000 --- a/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrScreenContent.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.tangem.tap.features.sprinklr.ui - -import android.annotation.SuppressLint -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import com.google.accompanist.web.WebView -import com.google.accompanist.web.rememberWebViewState -import com.tangem.tap.features.sprinklr.ui.webview.SprinklrWebViewClient - -@SuppressLint("SetJavaScriptEnabled") -@Composable -internal fun SprinklrScreenContent(state: SprinklrScreenState, modifier: Modifier = Modifier) { - WebView( - modifier = modifier, - state = rememberWebViewState(url = state.initialUrl), - onCreated = { webView -> - with(webView.settings) { - javaScriptEnabled = true - domStorageEnabled = true - } - }, - client = remember { SprinklrWebViewClient(state.onNewUrl) }, - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrScreenState.kt b/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrScreenState.kt deleted file mode 100644 index 8757f6e167..0000000000 --- a/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrScreenState.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.tangem.tap.features.sprinklr.ui - -import com.google.accompanist.web.WebContent - -internal data class SprinklrScreenState( - val initialUrl: String = "", - val sprinklrDomains: List = emptyList(), - val onNavigateBack: () -> Unit = {}, - val onNewUrl: WebContent.(String) -> WebContent = { this }, -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrViewModel.kt b/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrViewModel.kt deleted file mode 100644 index a6cf3abe13..0000000000 --- a/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrViewModel.kt +++ /dev/null @@ -1,66 +0,0 @@ -package com.tangem.tap.features.sprinklr.ui - -import androidx.lifecycle.ViewModel -import com.google.accompanist.web.WebContent -import com.tangem.core.navigation.NavigationAction -import com.tangem.tap.common.extensions.dispatchOnMain -import com.tangem.tap.features.sprinklr.redux.SprinklrState -import com.tangem.tap.store -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.update -import org.rekotlin.StoreSubscriber - -internal class SprinklrViewModel : ViewModel(), StoreSubscriber { - private val stateInternal = MutableStateFlow(SprinklrScreenState()) - val state = stateInternal.asStateFlow() - - init { - subscribeToStoreChanges() - } - - override fun newState(state: SprinklrState) { - stateInternal.update { prevState -> - prevState.copy( - initialUrl = state.url, - sprinklrDomains = state.sprinklrDomains, - onNewUrl = { updateWebContentOrOpenExternalUrl(it) }, - ) - } - } - - override fun onCleared() { - store.unsubscribe(this) - } - - fun setNavigateBackCallback(callback: () -> Unit) { - stateInternal.update { prevState -> - prevState.copy( - onNavigateBack = callback, - ) - } - } - - private fun subscribeToStoreChanges() { - store.subscribe(this) { appState -> - appState.skip { old, new -> old.sprinklrState == new.sprinklrState } - .select { it.sprinklrState } - } - } - - private fun WebContent.updateWebContentOrOpenExternalUrl(url: String): WebContent { - return if (isExternalUrl(url)) { - store.dispatchOnMain(NavigationAction.OpenUrl(url)) - this - } else { - when (this) { - is WebContent.Url -> copy(url = url) - else -> WebContent.Url(url) - } - } - } - - private fun isExternalUrl(url: String): Boolean { - return state.value.sprinklrDomains.none { url.contains(it) } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/sprinklr/ui/webview/SprinklrWebViewClient.kt b/app/src/main/java/com/tangem/tap/features/sprinklr/ui/webview/SprinklrWebViewClient.kt deleted file mode 100644 index 2f2487c88a..0000000000 --- a/app/src/main/java/com/tangem/tap/features/sprinklr/ui/webview/SprinklrWebViewClient.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.tangem.tap.features.sprinklr.ui.webview - -import android.webkit.WebResourceRequest -import android.webkit.WebView -import com.google.accompanist.web.AccompanistWebViewClient -import com.google.accompanist.web.WebContent - -internal class SprinklrWebViewClient( - private val onNewUrl: WebContent.(String) -> WebContent, -) : AccompanistWebViewClient() { - - override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean { - // If the url hasn't changed, this is probably an internal event like - // a javascript reload. We should let it happen. - if (view?.url == request?.url.toString()) { - return false - } - - request?.let { - state.content = onNewUrl(state.content, it.url.toString()) - } - return true - } -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt b/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt index 493d6b2e9e..2a1e34d105 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt @@ -103,6 +103,7 @@ internal class ConfigManagerImpl @Inject constructor() : ConfigManager { amplitudeApiKey = configValues.amplitudeApiKey, shopify = configValues.shopifyShop, zendesk = configValues.zendesk, + sprinklr = configValues.sprinklr, swapReferrerAccount = configValues.swapReferrerAccount, walletConnectProjectId = configValues.walletConnectProjectId, tangemComAuthorization = configValues.tangemComAuthorization, diff --git a/core/datasource/src/main/java/com/tangem/datasource/config/models/ChatConfig.kt b/core/datasource/src/main/java/com/tangem/datasource/config/models/ChatConfig.kt index d34275da0f..2ab45d66bc 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/config/models/ChatConfig.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/config/models/ChatConfig.kt @@ -23,6 +23,8 @@ data class ZendeskConfig( data class SprinklrConfig( @Json(name = "appID") val appId: String, - @Json(name = "baseURL") - val baseUrl: String, + @Json(name = "apiKey") + val apiKey: String, + @Json(name = "environment") + val environment: String, ) : ChatConfig \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/config/models/Config.kt b/core/datasource/src/main/java/com/tangem/datasource/config/models/Config.kt index 3d0bf5be7f..f8fe099745 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/config/models/Config.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/config/models/Config.kt @@ -16,6 +16,7 @@ data class Config( val isCreatingTwinCardsAllowed: Boolean = false, val shopify: ShopifyShop? = null, val zendesk: ZendeskConfig? = null, + val sprinklr: SprinklrConfig? = null, val swapReferrerAccount: SwapReferrerAccount? = null, val walletConnectProjectId: String = "", val tangemComAuthorization: String? = null, diff --git a/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt b/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt index 83ffe5d09a..93210485ef 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt @@ -32,6 +32,7 @@ class ConfigValueModel( val appsFlyer: AppsFlyer, val shopifyShop: ShopifyShop?, val zendesk: ZendeskConfig?, + val sprinklr: SprinklrConfig?, val tronGridApiKey: String, val amplitudeApiKey: String, val swapReferrerAccount: SwapReferrerAccount?, diff --git a/data/card/src/main/java/com/tangem/data/card/DefaultCardSdkConfigRepository.kt b/data/card/src/main/java/com/tangem/data/card/DefaultCardSdkConfigRepository.kt index 321a48b0bf..4e3b7acdef 100644 --- a/data/card/src/main/java/com/tangem/data/card/DefaultCardSdkConfigRepository.kt +++ b/data/card/src/main/java/com/tangem/data/card/DefaultCardSdkConfigRepository.kt @@ -49,6 +49,7 @@ internal class DefaultCardSdkConfigRepository( ProductType.Twins -> CardIdDisplayFormat.LastLuhn(numbers = 4) ProductType.Note, ProductType.Wallet, + ProductType.Wallet2, ProductType.Start2Coin, -> CardIdDisplayFormat.Full } diff --git a/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletBuilder.kt b/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletBuilder.kt index 565930ae9d..b843a98ee2 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletBuilder.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletBuilder.kt @@ -20,7 +20,9 @@ class UserWalletBuilder( ProductType.Note -> "Note" ProductType.Twins -> "Twin" ProductType.Start2Coin -> "Start2Coin" - ProductType.Wallet -> when { + ProductType.Wallet, + ProductType.Wallet2, + -> when { card.isBackupNotAllowed -> "Tangem card" cardTypesResolver.isStart2Coin() -> "Start2Coin" else -> "Wallet" diff --git a/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletIdBuilder.kt b/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletIdBuilder.kt index cad0957152..40ac39de3c 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletIdBuilder.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletIdBuilder.kt @@ -60,6 +60,7 @@ class UserWalletIdBuilder private constructor( ProductType.Twins -> scanResponse.secondTwinPublicKey?.hexToBytes() ProductType.Note, ProductType.Wallet, + ProductType.Wallet2, ProductType.Start2Coin, -> null }, diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index d4c76f2594..a239eb22ab 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -78,6 +78,7 @@ walletConnectCore = "1.18.0" walletConnectWeb3 = "1.11.0" prettyLogger = "2.2.0" okHttp-prettyLogging = "3.1.0" +spr-client = "3.6.2" # endregion Other libraries # region Tangem @@ -227,4 +228,5 @@ reactive-network = { module = "com.github.pwittchen:reactivenetwork-rx2", versio walletConnectCore = { module = "com.walletconnect:android-core", version.ref = "walletConnectCore" } walletConnectWeb3 = { module = "com.walletconnect:web3wallet", version.ref = "walletConnectWeb3" } prettyLogger = { module = "com.orhanobut:logger", version.ref = "prettyLogger" } +sprClient = { module = "com.spr:messengerclient", version.ref = "spr-client" } # endregion Other diff --git a/settings.gradle.kts b/settings.gradle.kts index b2c3126321..7e4c66d7d8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -40,6 +40,7 @@ dependencyResolutionManagement { } maven("https://jitpack.io") maven("https://zendesk.jfrog.io/zendesk/repo") + maven("https://clients-nexus.sprinklr.com/") } versionCatalogs { From b327b560a37ad52347a1098ddf22b0b6e3642771 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 17 Oct 2023 14:00:47 +0300 Subject: [PATCH 4/6] Updated on 2026-08-14 --- gradle/dependencies.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index a239eb22ab..843863953e 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -82,7 +82,7 @@ spr-client = "3.6.2" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "release-app_4.11-349" +tangemBlockchainSdk = "release-app_4.11-360" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "release-app_4.11-295" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds From 38a41bc6737cdbd899ce1cba194be4ac8f52ee91 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 17 Oct 2023 16:37:20 +0400 Subject: [PATCH 5/6] Updated on 2026-08-14 --- app/build.gradle.kts | 42 ++++++++----------- .../extension/AppExtensionConfigurations.kt | 1 + 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e6e2daa7a3..1ff2af8354 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -9,37 +9,28 @@ plugins { id("configuration") } -configurations { - all { - exclude(group = "org.bouncycastle", module = "bcprov-jdk15to18") - exclude(group = "com.github.komputing.kethereum") +configurations.all { + exclude(group = "org.bouncycastle", module = "bcprov-jdk15to18") + exclude(group = "com.github.komputing.kethereum") - resolutionStrategy { - dependencySubstitution { - substitute(module("com.facebook.react:react-native")) - .using(module("com.facebook.react:react-android:0.72.4")) - .because( - "The current version of SPR Client (3.6.2) is not compatible with the latest " + - "React Native version" - ) + resolutionStrategy { + dependencySubstitution { + substitute(module("com.facebook.react:react-native")) + .using(module("com.facebook.react:react-android:0.72.4")) - substitute(module("com.facebook.react:hermes-engine")) - .using(module("com.facebook.react:hermes-android:0.72.4")) - .because( - "The current version of SPR Client (3.6.2) is not compatible with the latest " + - "Hermes Engine version" - ) - } - - force( - "org.bouncycastle:bcpkix-jdk15on:1.70", - "com.facebook.react:react-android:0.72.4", - "com.facebook.react:hermes-android:0.72.4", - ) + substitute(module("com.facebook.react:hermes-engine")) + .using(module("com.facebook.react:hermes-android:0.72.4")) } + + force( + "org.bouncycastle:bcpkix-jdk15on:1.70", + "com.facebook.react:react-android:0.72.4", + "com.facebook.react:hermes-android:0.72.4", + ) } } + dependencies { implementation(files("libs/walletconnect-1.5.6.aar")) implementation(project(":domain:legacy")) @@ -179,6 +170,7 @@ dependencies { implementation(deps.walletConnectCore) implementation(deps.walletConnectWeb3) implementation(deps.prettyLogger) + implementation("com.facebook.react:react-android:0.72.4") implementation(deps.sprClient) { exclude(group = "com.github.stephenc.jcip") } diff --git a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/AppExtensionConfigurations.kt b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/AppExtensionConfigurations.kt index 1ba8b81a2d..05b2b465c2 100644 --- a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/AppExtensionConfigurations.kt +++ b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/AppExtensionConfigurations.kt @@ -76,6 +76,7 @@ private fun AndroidBuildType.configureBuildVariant(extension: AppExtension, buil BuildType.External, -> { initWith(extension.buildTypes.getByName(BuildType.Release.id)) + matchingFallbacks.add(BuildType.Release.id) signingConfig = extension.signingConfigs.getByName(BuildType.Debug.id) } } From bd7ddae482f2123e710037109b538fb46523edcb Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 18 Oct 2023 13:36:27 +0400 Subject: [PATCH 6/6] Updated on 2026-08-14 --- app/src/main/assets/tangem-app-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index b84b1e1ab1..2b49c08b92 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit b84b1e1ab11b0eb0f6ca6e28f551f9e2ca6809fe +Subproject commit 2b49c08b924c03322f35542a7482e4e9fb1928d3