Updated on 2026-08-14
This commit is contained in:
commit
53cbe15b78
430 changed files with 12468 additions and 1527 deletions
|
|
@ -25,11 +25,17 @@ dependencies {
|
|||
implementation(project(":domain:legacy"))
|
||||
implementation(project(":domain:models"))
|
||||
implementation(project(":domain:core"))
|
||||
implementation(project(":domain:card"))
|
||||
implementation(projects.domain.card)
|
||||
implementation(projects.domain.demo)
|
||||
implementation(project(":domain:wallets"))
|
||||
implementation(project(":domain:wallets:models"))
|
||||
implementation(projects.domain.settings)
|
||||
implementation(projects.domain.tokens)
|
||||
implementation(projects.domain.txhistory)
|
||||
|
||||
implementation(project(":common"))
|
||||
implementation(project(":core:analytics"))
|
||||
implementation(projects.core.analytics.models)
|
||||
implementation(project(":core:navigation"))
|
||||
implementation(project(":core:featuretoggles"))
|
||||
implementation(project(":core:res"))
|
||||
|
|
@ -38,7 +44,13 @@ dependencies {
|
|||
implementation(project(":core:utils"))
|
||||
implementation(project(":libs:crypto"))
|
||||
implementation(project(":libs:auth"))
|
||||
|
||||
implementation(project(":data:source:preferences"))
|
||||
implementation(projects.data.card)
|
||||
implementation(projects.data.common)
|
||||
implementation(projects.data.settings)
|
||||
implementation(projects.data.tokens)
|
||||
implementation(projects.data.txhistory)
|
||||
|
||||
/** Features */
|
||||
implementation(project(":features:onboarding"))
|
||||
|
|
@ -119,13 +131,6 @@ dependencies {
|
|||
implementation(deps.appsflyer)
|
||||
implementation(deps.amplitude)
|
||||
implementation(deps.kotsonGson)
|
||||
//TODO: refactoring: remove it when all network services moved to the datasource module
|
||||
implementation(deps.retrofit)
|
||||
implementation(deps.retrofit.moshi)
|
||||
implementation(deps.moshi)
|
||||
implementation(deps.moshi.kotlin)
|
||||
implementation(deps.okHttp)
|
||||
implementation(deps.okHttp.logging)
|
||||
implementation(deps.zendesk.chat)
|
||||
implementation(deps.zendesk.messaging)
|
||||
implementation(deps.spongecastle.core)
|
||||
|
|
@ -144,6 +149,7 @@ dependencies {
|
|||
implementation(deps.kotlin.serialization)
|
||||
implementation(deps.walletConnectCore)
|
||||
implementation(deps.walletConnectWeb3)
|
||||
implementation(deps.prettyLogger)
|
||||
|
||||
/** Testing libraries */
|
||||
testImplementation(deps.test.junit)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit b791bd4cf6c5eca9778f89e87cd62b72d24f5ce9
|
||||
Subproject commit 8c1c53b73950698d4acfa4d925b8c14bf6f0da63
|
||||
|
|
@ -10,10 +10,11 @@ import androidx.core.view.WindowCompat
|
|||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tangem.TangemSdk
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.data.card.sdk.CardSdkLifecycleObserver
|
||||
import com.tangem.domain.card.ScanCardUseCase
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.features.tester.api.TesterRouter
|
||||
import com.tangem.features.tokendetails.navigation.TokenDetailsRouter
|
||||
|
|
@ -56,7 +57,6 @@ import java.lang.ref.WeakReference
|
|||
import javax.inject.Inject
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
lateinit var tangemSdk: TangemSdk
|
||||
lateinit var tangemSdkManager: TangemSdkManager
|
||||
lateinit var backupService: BackupService
|
||||
internal var lockUserWalletsTimer: LockUserWalletsTimer? = null
|
||||
|
|
@ -88,7 +88,10 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
lateinit var testerRouter: TesterRouter
|
||||
|
||||
@Inject
|
||||
lateinit var injectedTangemSdk: TangemSdk
|
||||
lateinit var cardSdkLifecycleObserver: CardSdkLifecycleObserver
|
||||
|
||||
@Inject
|
||||
lateinit var cardSdkConfigRepository: CardSdkConfigRepository
|
||||
|
||||
@Inject
|
||||
lateinit var injectedTangemSdkManager: TangemSdkManager
|
||||
|
|
@ -122,11 +125,11 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
systemActions()
|
||||
store.dispatch(NavigationAction.ActivityCreated(WeakReference(this)))
|
||||
|
||||
tangemSdk = injectedTangemSdk
|
||||
cardSdkLifecycleObserver.onCreate(context = this)
|
||||
|
||||
tangemSdkManager = injectedTangemSdkManager
|
||||
appStateHolder.tangemSdkManager = tangemSdkManager
|
||||
appStateHolder.tangemSdk = tangemSdk
|
||||
backupService = BackupService.init(tangemSdk, this)
|
||||
backupService = BackupService.init(cardSdkConfigRepository.sdk, this)
|
||||
lockUserWalletsTimer = LockUserWalletsTimer(owner = this)
|
||||
|
||||
initUserWalletsListManager()
|
||||
|
|
@ -144,10 +147,37 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
walletRouter = walletRouter,
|
||||
walletConnectInteractor = walletConnectInteractor,
|
||||
tokenDetailsRouter = tokenDetailsRouter,
|
||||
cardSdkConfigRepository = cardSdkConfigRepository,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
dialogManager.onStart(this)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
// TODO: RESEARCH! NotificationsHandler is created in onResume and destroyed in onStop
|
||||
notificationsHandler = NotificationsHandler(binding.fragmentContainer)
|
||||
|
||||
navigateToInitialScreenIfNeededOnResume(intent)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
notificationsHandler = null
|
||||
dialogManager.onStop()
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
store.dispatch(NavigationAction.ActivityDestroyed(WeakReference(this)))
|
||||
intentProcessor.removeAll()
|
||||
cardSdkLifecycleObserver.onDestroy()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private fun initIntentHandlers() {
|
||||
val hasSavedWalletsProvider = { store.state.globalState.userWalletsListManager?.hasUserWallets == true }
|
||||
intentProcessor.addHandler(BackgroundScanIntentHandler(hasSavedWalletsProvider))
|
||||
|
|
@ -183,13 +213,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
notificationsHandler = NotificationsHandler(binding.fragmentContainer)
|
||||
|
||||
navigateToInitialScreenIfNeededOnResume(intent)
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
super.onNewIntent(intent)
|
||||
scope.launch {
|
||||
|
|
@ -197,23 +220,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
dialogManager.onStart(this)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
notificationsHandler = null
|
||||
dialogManager.onStop()
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
store.dispatch(NavigationAction.ActivityDestroyed(WeakReference(this)))
|
||||
intentProcessor.removeAll()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun showSnackbar(text: Int, buttonTitle: Int?, action: View.OnClickListener?) {
|
||||
if (snackbar != null) return
|
||||
|
||||
|
|
|
|||
|
|
@ -5,21 +5,26 @@ import android.content.Context
|
|||
import android.content.pm.PackageManager
|
||||
import coil.ImageLoader
|
||||
import coil.ImageLoaderFactory
|
||||
import com.orhanobut.logger.AndroidLogAdapter
|
||||
import com.orhanobut.logger.Logger
|
||||
import com.tangem.Log
|
||||
import com.tangem.LogFormat
|
||||
import com.tangem.blockchain.common.BlockchainSdkConfig
|
||||
import com.tangem.blockchain.common.ExceptionHandler
|
||||
import com.tangem.blockchain.common.WalletManagerFactory
|
||||
import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
|
||||
import com.tangem.data.source.preferences.PreferencesDataSource
|
||||
import com.tangem.datasource.api.common.MoshiConverter
|
||||
import com.tangem.datasource.api.common.createNetworkLoggingInterceptor
|
||||
import com.tangem.datasource.asset.AssetReader
|
||||
import com.tangem.datasource.config.ConfigManager
|
||||
import com.tangem.datasource.config.FeaturesLocalLoader
|
||||
import com.tangem.datasource.config.models.Config
|
||||
import com.tangem.datasource.connection.NetworkConnectionManager
|
||||
import com.tangem.domain.DomainLayer
|
||||
import com.tangem.domain.card.ScanCardProcessor
|
||||
import com.tangem.domain.common.LogConfig
|
||||
import com.tangem.domain.wallets.legacy.WalletManagersRepository
|
||||
import com.tangem.feature.learn2earn.domain.api.Learn2earnInteractor
|
||||
|
|
@ -27,6 +32,7 @@ import com.tangem.features.tokendetails.featuretoggles.TokenDetailsFeatureToggle
|
|||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import com.tangem.tap.common.analytics.AnalyticsFactory
|
||||
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
|
||||
import com.tangem.tap.common.analytics.handlers.BlockchainExceptionHandler
|
||||
import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeAnalyticsHandler
|
||||
import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerAnalyticsHandler
|
||||
import com.tangem.tap.common.analytics.handlers.firebase.FirebaseAnalyticsHandler
|
||||
|
|
@ -59,7 +65,6 @@ import com.tangem.tap.proxy.redux.DaggerGraphState
|
|||
import com.tangem.wallet.BuildConfig
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import org.rekotlin.Store
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
|
@ -151,6 +156,12 @@ class TapApplication : Application(), ImageLoaderFactory {
|
|||
@Inject
|
||||
lateinit var tokenDetailsFeatureToggles: TokenDetailsFeatureToggles
|
||||
|
||||
@Inject
|
||||
lateinit var scanCardProcessor: ScanCardProcessor
|
||||
|
||||
@Inject
|
||||
lateinit var blockchainExceptionHandler: BlockchainExceptionHandler
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
|
|
@ -168,12 +179,20 @@ class TapApplication : Application(), ImageLoaderFactory {
|
|||
walletConnectRepository = walletConnect2Repository,
|
||||
walletConnectSessionsRepository = walletConnectSessionsRepository,
|
||||
tokenDetailsFeatureToggles = tokenDetailsFeatureToggles,
|
||||
scanCardProcessor = scanCardProcessor,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Timber.plant(Timber.DebugTree())
|
||||
Logger.addLogAdapter(AndroidLogAdapter())
|
||||
Timber.plant(
|
||||
object : Timber.DebugTree() {
|
||||
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
||||
Logger.log(priority, tag, message, t)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
foregroundActivityObserver = ForegroundActivityObserver()
|
||||
|
|
@ -192,7 +211,7 @@ class TapApplication : Application(), ImageLoaderFactory {
|
|||
|
||||
if (LogConfig.network.blockchainSdkNetwork) {
|
||||
BlockchainSdkRetrofitBuilder.interceptors = listOf(
|
||||
HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY },
|
||||
createNetworkLoggingInterceptor(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -266,6 +285,7 @@ class TapApplication : Application(), ImageLoaderFactory {
|
|||
jsonConverter = MoshiConverter.sdkMoshiConverter,
|
||||
)
|
||||
factory.build(Analytics, buildData)
|
||||
ExceptionHandler.append(blockchainExceptionHandler)
|
||||
}
|
||||
|
||||
private fun initFeedbackManager(
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.tap.common.analytics.converters
|
|||
import com.shopify.buy3.Storefront
|
||||
import com.tangem.common.Converter
|
||||
import com.tangem.tap.common.analytics.events.Shop
|
||||
import com.tangem.tap.common.shop.data.ProductType
|
||||
import com.tangem.tap.features.shop.domain.models.ProductType
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
|
|||
|
|
@ -157,5 +157,10 @@ sealed class AnalyticsParam {
|
|||
const val ERROR_KEY = "Error Key"
|
||||
const val CREATION_TYPE = "Creation type"
|
||||
const val DAPP_NAME = "DApp Name"
|
||||
const val DAPP_URL = "DApp Url"
|
||||
const val METHOD_NAME = "Method Name"
|
||||
const val VALIDATION = "Validation"
|
||||
const val BLOCKCHAIN_EXCEPTION_HOST = "exception_host"
|
||||
const val BLOCKCHAIN_SELECTED_HOST = "selected_host"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.common.analytics.events
|
||||
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.tap.common.analytics.events
|
||||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
||||
class BlockchainExceptionEvent(
|
||||
selectedHost: String,
|
||||
exceptionHost: String,
|
||||
error: String,
|
||||
) : AnalyticsEvent(
|
||||
category = "BlockchainSdk",
|
||||
event = "Exception",
|
||||
params = mapOf(
|
||||
AnalyticsParam.BLOCKCHAIN_SELECTED_HOST to selectedHost,
|
||||
AnalyticsParam.BLOCKCHAIN_EXCEPTION_HOST to exceptionHost,
|
||||
AnalyticsParam.ERROR_DESCRIPTION to error,
|
||||
),
|
||||
)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.common.analytics.events
|
||||
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.common.analytics.events
|
||||
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.common.analytics.events
|
||||
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.common.analytics.events
|
||||
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -13,7 +13,6 @@ sealed class MainScreen(
|
|||
class ScreenOpened : MainScreen("Screen opened")
|
||||
class ButtonScanCard : MainScreen("Button - Scan Card")
|
||||
class ButtonMyWallets : MainScreen("Button - My Wallets")
|
||||
class ButtonBuy : MainScreen("Button - Buy")
|
||||
|
||||
class EnableBiometrics(state: AnalyticsParam.OnOffState) : MainScreen(
|
||||
event = "Enable Biometric",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.common.analytics.events
|
||||
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.domain.common.extensions.toNetworkId
|
||||
import com.tangem.domain.features.addCustomToken.CustomCurrency
|
||||
import com.tangem.tap.common.extensions.filterNotNull
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.common.analytics.events
|
||||
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
||||
sealed class MyWallets(
|
||||
event: String,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.common.analytics.events
|
||||
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -72,26 +72,8 @@ sealed class Onboarding(
|
|||
class SetupFinished : Twins("Twin Setup Finished")
|
||||
}
|
||||
|
||||
class PinScreenOpened : Onboarding("Onboarding", "PIN screen opened")
|
||||
class ButtonSetPinCode : Onboarding("Onboarding", "Button - Set PIN Code")
|
||||
class CardConnectionScreenOpened : Onboarding("Onboarding", "Card Connection Screen Opened")
|
||||
class ButtonConnect : Onboarding("Onboarding", "Button - Connect")
|
||||
class PinCodeSet : Onboarding("Onboarding", "PIN Code Set")
|
||||
|
||||
class KYCScreenOpened : Onboarding("Onboarding", "KYC screen opened")
|
||||
class KYCStarted : Onboarding("Onboarding", "KYC Started")
|
||||
class KYCInProgress : Onboarding("Onboarding", "KYC In Progress")
|
||||
class KYCRejected : Onboarding("Onboarding", "KYC Rejected")
|
||||
|
||||
class ClaimScreenOpened : Onboarding("Onboarding", "Claim Screen Opened")
|
||||
class ButtonClaim : Onboarding("Onboarding", "Button - Claim")
|
||||
class ClaimWasSuccessfully : Onboarding("Onboarding", "Claim Was Successfully")
|
||||
|
||||
class ButtonChat : Onboarding("Onboarding", "Button - Chat")
|
||||
|
||||
class NotEnoughGasError : Onboarding("Onboarding", "Not Enough Gas Error")
|
||||
class CardNotPassedError : Onboarding("Onboarding", "Card Not Passed Error")
|
||||
|
||||
class EnableBiometrics(state: AnalyticsParam.OnOffState) : Onboarding(
|
||||
category = "Onboarding / Biometric",
|
||||
event = "Enable Biometric",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.common.analytics.events
|
||||
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.common.analytics.events
|
||||
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.tap.features.details.ui.details.SocialNetwork
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.common.analytics.events
|
||||
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.tap.common.extensions.filterNotNull
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.common.analytics.events
|
||||
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.common.analytics.events
|
||||
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam.CurrencyType
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.common.analytics.events
|
||||
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.tap.common.extensions.filterNotNull
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -12,16 +13,51 @@ sealed class WalletConnect(
|
|||
) : AnalyticsEvent("Wallet Connect", event, params, error) {
|
||||
|
||||
class ScreenOpened : WalletConnect(event = "WC Screen Opened")
|
||||
class NewSessionEstablished(dAppName: String) : WalletConnect(
|
||||
class NewSessionEstablished(dAppName: String, dAppUrl: String) : WalletConnect(
|
||||
event = "New Session Established",
|
||||
params = mapOf(
|
||||
AnalyticsParam.DAPP_NAME to dAppName,
|
||||
AnalyticsParam.DAPP_URL to dAppUrl,
|
||||
),
|
||||
)
|
||||
|
||||
class SessionDisconnected : WalletConnect("Session Disconnected")
|
||||
class RequestSigned : WalletConnect("Request Signed")
|
||||
class SessionDisconnected(dAppName: String, dAppUrl: String) : WalletConnect(
|
||||
event = "Session Disconnected",
|
||||
params = mapOf(
|
||||
AnalyticsParam.DAPP_NAME to dAppName,
|
||||
AnalyticsParam.DAPP_URL to dAppUrl,
|
||||
),
|
||||
)
|
||||
|
||||
class SignError(error: Throwable) : WalletConnect("Sign", error = error)
|
||||
class TransactionError(error: Throwable) : WalletConnect("Transaction", error = error)
|
||||
class RequestHandled(
|
||||
params: RequestHandledParams,
|
||||
) : WalletConnect(
|
||||
event = "Request Handled",
|
||||
params = params.toParamsMap(),
|
||||
)
|
||||
|
||||
data class RequestHandledParams(
|
||||
val dAppName: String,
|
||||
val dAppUrl: String,
|
||||
val methodName: String,
|
||||
val blockchain: String,
|
||||
val errorCode: String? = null,
|
||||
) {
|
||||
fun toParamsMap(): Map<String, String> {
|
||||
val validation = if (errorCode == null) Validation.SUCCESS.param else Validation.FAIL.param
|
||||
return mapOf(
|
||||
AnalyticsParam.DAPP_NAME to dAppName,
|
||||
AnalyticsParam.DAPP_URL to dAppUrl,
|
||||
AnalyticsParam.METHOD_NAME to methodName,
|
||||
AnalyticsParam.BLOCKCHAIN to blockchain,
|
||||
AnalyticsParam.VALIDATION to validation,
|
||||
if (errorCode != null) AnalyticsParam.ERROR_CODE to errorCode else null to null,
|
||||
).filterNotNull()
|
||||
}
|
||||
}
|
||||
|
||||
enum class Validation(val param: String) {
|
||||
SUCCESS("Success"),
|
||||
FAIL("Fail"),
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.tap.common.analytics.handlers
|
||||
|
||||
import com.tangem.blockchain.common.ExceptionHandlerOutput
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.tap.common.analytics.events.BlockchainExceptionEvent
|
||||
import javax.inject.Inject
|
||||
|
||||
class BlockchainExceptionHandler @Inject constructor(
|
||||
private val analyticsHandler: AnalyticsEventHandler,
|
||||
) : ExceptionHandlerOutput {
|
||||
override fun handleApiSwitch(currentHost: String, nextHost: String, message: String) {
|
||||
analyticsHandler.send(
|
||||
BlockchainExceptionEvent(
|
||||
selectedHost = nextHost,
|
||||
exceptionHost = currentHost,
|
||||
error = message,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package com.tangem.tap.common.analytics.handlers.appsFlyer
|
||||
|
||||
import com.appsflyer.AFInAppEventType
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.api.AnalyticsHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
|
||||
import com.tangem.tap.common.analytics.events.Shop
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
package com.tangem.tap.common.analytics.handlers.firebase
|
||||
|
||||
import com.google.firebase.analytics.FirebaseAnalytics
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.api.AnalyticsHandler
|
||||
import com.tangem.core.analytics.api.ErrorEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
|
||||
import com.tangem.tap.common.analytics.converters.AnalyticsErrorConverter
|
||||
import com.tangem.tap.common.analytics.events.Shop
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tap.common.analytics.paramsInterceptor
|
||||
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.api.ParamsInterceptor
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
package com.tangem.tap.common.analytics.paramsInterceptor
|
||||
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.api.ParamsInterceptor
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class LinkedCardContextInterceptor(
|
||||
private val scanResponse: ScanResponse,
|
||||
scanResponse: ScanResponse,
|
||||
val parent: LinkedCardContextInterceptor? = null,
|
||||
) : ParamsInterceptor {
|
||||
|
||||
|
|
|
|||
|
|
@ -9,19 +9,19 @@ import com.tangem.domain.common.BlockchainNetwork
|
|||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.userwallets.UserWalletIdBuilder
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.tap.common.analytics.converters.TopUpEventConverter
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.extensions.copy
|
||||
import com.tangem.tap.domain.model.TotalFiatBalance
|
||||
import com.tangem.tap.domain.model.WalletDataModel
|
||||
import com.tangem.tap.domain.model.WalletStoreModel
|
||||
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
|
||||
import com.tangem.tap.domain.walletCurrencies.WalletCurrenciesManager
|
||||
import com.tangem.tap.domain.walletStores.WalletStoresManager
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.utils.extensions.copy
|
||||
import kotlinx.coroutines.launch
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ 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,
|
||||
|
|
@ -20,7 +21,7 @@ class ChatManager(
|
|||
) {
|
||||
private val openers = mutableMapOf<ChatConfig, ChatOpener>()
|
||||
|
||||
fun open(config: ChatConfig, feedbackDataBuilder: (Context) -> String) {
|
||||
fun open(config: ChatConfig, createLogsFile: (Context) -> File?, createFeedbackFile: (Context) -> File?) {
|
||||
val opener = openers.getOrPut(config) {
|
||||
when (config) {
|
||||
is SprinklrConfig -> SprinklrChatOpener(getSprinklrUserId(), config, store, foregroundActivityObserver)
|
||||
|
|
@ -28,7 +29,10 @@ class ChatManager(
|
|||
}
|
||||
}
|
||||
|
||||
opener.open(feedbackDataBuilder)
|
||||
opener.open(
|
||||
createFeedbackFile = createFeedbackFile,
|
||||
createLogsFile = createLogsFile,
|
||||
)
|
||||
}
|
||||
|
||||
private fun getZendeskUserId(): String {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
package com.tangem.tap.common.chat.opener
|
||||
|
||||
import android.content.Context
|
||||
import java.io.File
|
||||
|
||||
internal interface ChatOpener {
|
||||
fun open(feedbackDataBuilder: (Context) -> String)
|
||||
fun open(createFeedbackFile: (Context) -> File?, createLogsFile: (Context) -> File?)
|
||||
}
|
||||
|
|
@ -2,14 +2,15 @@ package com.tangem.tap.common.chat.opener.implementation
|
|||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.tangem.datasource.config.models.SprinklrConfig
|
||||
import com.tangem.tap.ForegroundActivityObserver
|
||||
import com.tangem.tap.common.chat.opener.ChatOpener
|
||||
import com.tangem.datasource.config.models.SprinklrConfig
|
||||
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 java.io.File
|
||||
|
||||
internal class SprinklrChatOpener(
|
||||
private val userId: String,
|
||||
|
|
@ -17,7 +18,7 @@ internal class SprinklrChatOpener(
|
|||
private val store: Store<AppState>,
|
||||
private val foregroundActivityObserver: ForegroundActivityObserver,
|
||||
) : ChatOpener {
|
||||
override fun open(feedbackDataBuilder: (Context) -> String) {
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -2,34 +2,34 @@ 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.datasource.config.models.ZendeskConfig
|
||||
import com.tangem.tap.withForegroundActivity
|
||||
import com.tangem.wallet.R
|
||||
import com.zendesk.logger.Logger
|
||||
import zendesk.chat.Chat
|
||||
import zendesk.chat.ChatConfiguration
|
||||
import zendesk.chat.ChatEngine
|
||||
import zendesk.chat.ChatProvidersConfiguration
|
||||
import zendesk.chat.VisitorInfo
|
||||
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
|
||||
|
||||
override fun open(feedbackDataBuilder: (Context) -> String) {
|
||||
override fun open(createFeedbackFile: (Context) -> File?, createLogsFile: (Context) -> File?) {
|
||||
foregroundActivityObserver.withForegroundActivity { activity ->
|
||||
initZendeskIfNeeded(activity.applicationContext)
|
||||
setChatVisitorInfo()
|
||||
setChatVisitorNote(feedbackDataBuilder(activity))
|
||||
showMessagingActivity(activity)
|
||||
sendFeedbackFile(createFeedbackFile(activity))
|
||||
sendLogsFile(createLogsFile(activity))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -48,8 +48,20 @@ internal class ZendeskChatOpener(
|
|||
ChatProvidersConfiguration.builder().withVisitorInfo(visitorInfo).build()
|
||||
}
|
||||
|
||||
private fun setChatVisitorNote(note: String) {
|
||||
Chat.INSTANCE.providers()?.profileProvider()?.setVisitorNote(note)
|
||||
private fun sendFeedbackFile(feedbackFile: File?) {
|
||||
if (isInitialized && feedbackFile != null) {
|
||||
Chat.INSTANCE.providers()?.chatProvider()?.sendFile(feedbackFile) { _, bytesUploaded, _ ->
|
||||
Timber.d("Log file sent", "bytesUploaded: $bytesUploaded")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendLogsFile(logsFile: File?) {
|
||||
if (isInitialized && logsFile != null) {
|
||||
Chat.INSTANCE.providers()?.chatProvider()?.sendFile(logsFile) { _, bytesUploaded, _ ->
|
||||
Timber.d("Log file sent", "bytesUploaded: $bytesUploaded")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showMessagingActivity(context: Context) {
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
package com.tangem.tap.common.di.domain.wallets
|
||||
|
||||
import com.tangem.domain.wallets.legacy.WalletsStateHolder
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ViewModelComponent
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
|
||||
@Module
|
||||
@InstallIn(ViewModelComponent::class)
|
||||
object WalletsDomainModule {
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun providesGetWalletsUseCase(walletsStateHolder: WalletsStateHolder): GetWalletsUseCase {
|
||||
return GetWalletsUseCase(walletsStateHolder = walletsStateHolder)
|
||||
}
|
||||
}
|
||||
|
|
@ -45,6 +45,7 @@ fun Blockchain.getGreyedOutIconRes(): Int {
|
|||
Blockchain.Cronos -> R.drawable.ic_cronos_no_color
|
||||
Blockchain.Telos, Blockchain.TelosTestnet -> R.drawable.ic_telos_no_color
|
||||
Blockchain.AlephZero, Blockchain.AlephZeroTestnet -> R.drawable.ic_azero_no_color
|
||||
Blockchain.OctaSpace, Blockchain.OctaSpaceTestnet -> R.drawable.ic_octaspace_no_color
|
||||
else -> R.drawable.ic_tangem_logo
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
fun <T> MutableList<T>.removeBy(predicate: (T) -> Boolean): Boolean {
|
||||
val toRemove = this.filter(predicate)
|
||||
this.removeAll(toRemove)
|
||||
return toRemove.isNotEmpty()
|
||||
}
|
||||
|
||||
fun <T> MutableList<T>.replaceBy(item: T, predicate: (T) -> Boolean): Boolean {
|
||||
val toRemove = this.filter(predicate)
|
||||
if (toRemove.isEmpty()) return false
|
||||
|
||||
val indexes = toRemove.map { indexOf(it) }
|
||||
this.removeAll(toRemove)
|
||||
indexes.forEach { this.add(it, item) }
|
||||
return true
|
||||
}
|
||||
|
||||
fun <T> MutableList<T>.replaceByOrAdd(item: T, predicate: (T) -> Boolean) {
|
||||
if (!replaceBy(item, predicate)) add(item)
|
||||
}
|
||||
|
||||
fun <T> MutableList<T>.copy(): MutableList<T> {
|
||||
return this.map { it }.toMutableList()
|
||||
}
|
||||
|
|
@ -24,13 +24,17 @@ fun BigDecimal.toFormattedString(
|
|||
df.decimalFormatSymbols = symbols
|
||||
df.maximumFractionDigits = decimals
|
||||
df.minimumFractionDigits = 0
|
||||
df.isGroupingUsed = false
|
||||
df.isGroupingUsed = true
|
||||
df.roundingMode = roundingMode
|
||||
return df.format(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* To formatted crypto currency string
|
||||
* Specific method because there is no crypto currency codes in Locale
|
||||
*/
|
||||
@Suppress("MagicNumber")
|
||||
fun BigDecimal.toFormattedCurrencyString(
|
||||
fun BigDecimal.toFormattedCryptoCurrencyString(
|
||||
decimals: Int,
|
||||
currency: String,
|
||||
roundingMode: RoundingMode = RoundingMode.DOWN,
|
||||
|
|
@ -41,16 +45,34 @@ fun BigDecimal.toFormattedCurrencyString(
|
|||
} else {
|
||||
decimals
|
||||
}
|
||||
try {
|
||||
val locale = Locale.getDefault()
|
||||
val formatter = NumberFormat.getCurrencyInstance(locale)
|
||||
// first create currency instance for "USD" with Locale default to replace currency to crypto later
|
||||
Currency.getInstance("USD")?.let { currencyTmp ->
|
||||
formatter.currency = currencyTmp
|
||||
formatter.maximumFractionDigits = decimalsForRounding
|
||||
formatter.minimumFractionDigits = 0
|
||||
formatter.isGroupingUsed = true
|
||||
formatter.roundingMode = roundingMode
|
||||
// cause formatter created for USD, replace Currency with Crypto symbol on right by Locale place
|
||||
return formatter.format(this).replace(currencyTmp.getSymbol(locale), "$currency ")
|
||||
}
|
||||
} catch (e: IllegalArgumentException) {
|
||||
Timber.e(e, "can't parse currency")
|
||||
}
|
||||
// if something went wrong - use old way to format
|
||||
val formattedAmount = this.toFormattedString(
|
||||
decimals = decimalsForRounding,
|
||||
roundingMode = roundingMode,
|
||||
locale = Locale.getDefault(),
|
||||
)
|
||||
return "$formattedAmount $currency"
|
||||
return "$formattedAmount $currency "
|
||||
}
|
||||
|
||||
fun BigDecimal.toFiatRateString(fiatCurrencyName: String, fiatCode: String): String {
|
||||
try {
|
||||
val formatter = NumberFormat.getCurrencyInstance()
|
||||
val formatter = NumberFormat.getCurrencyInstance(Locale.getDefault())
|
||||
Currency.getInstance(fiatCode)?.let { currency ->
|
||||
formatter.currency = currency
|
||||
formatter.maximumFractionDigits = 2
|
||||
|
|
@ -91,7 +113,7 @@ fun BigDecimal.toFormattedFiatValue(
|
|||
formatWithSpaces: Boolean = false,
|
||||
): String {
|
||||
try {
|
||||
val formatter = NumberFormat.getCurrencyInstance()
|
||||
val formatter = NumberFormat.getCurrencyInstance(Locale.getDefault())
|
||||
Currency.getInstance(fiatCode)?.let { currency ->
|
||||
formatter.currency = currency
|
||||
formatter.maximumFractionDigits = 2
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ import com.tangem.blockchain.common.BlockchainSdkError
|
|||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.common.services.Result
|
||||
import com.tangem.domain.common.extensions.amountToCreateAccount
|
||||
import com.tangem.tap.common.TestActions
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.extensions.amountToCreateAccount
|
||||
import com.tangem.tap.domain.getFirstToken
|
||||
import com.tangem.tap.domain.model.WalletDataModel
|
||||
import com.tangem.tap.features.demo.isDemoCard
|
||||
|
|
|
|||
|
|
@ -1,17 +1,12 @@
|
|||
package com.tangem.tap.common.feedback
|
||||
|
||||
import android.os.Build
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.common.address.Address
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.userwallets.UserWalletIdBuilder
|
||||
import com.tangem.tap.common.extensions.stripZeroPlainString
|
||||
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
|
||||
|
||||
class AdditionalFeedbackInfo {
|
||||
class EmailWalletInfo(
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
package com.tangem.tap.common.feedback
|
||||
|
||||
import android.content.Context
|
||||
import com.tangem.datasource.config.models.ChatConfig
|
||||
import com.tangem.domain.common.TapWorkarounds
|
||||
import com.tangem.tap.common.chat.ChatManager
|
||||
import com.tangem.datasource.config.models.ChatConfig
|
||||
import com.tangem.tap.common.extensions.sendEmail
|
||||
import com.tangem.tap.common.log.TangemLogCollector
|
||||
import com.tangem.tap.foregroundActivityObserver
|
||||
|
|
@ -22,32 +22,61 @@ class FeedbackManager(
|
|||
private val chatManager: ChatManager,
|
||||
) {
|
||||
|
||||
private var sessionFeedbackFile: File? = null
|
||||
private var sessionLogsFile: File? = null
|
||||
|
||||
fun sendEmail(feedbackData: FeedbackData, onFail: ((Exception) -> Unit)? = null) {
|
||||
feedbackData.prepare(infoHolder)
|
||||
foregroundActivityObserver.withForegroundActivity { activity ->
|
||||
val fileLog = createLogFile(activity)
|
||||
activity.sendEmail(
|
||||
email = getSupportEmail(),
|
||||
subject = activity.getString(feedbackData.subjectResId),
|
||||
message = feedbackData.joinTogether(activity, infoHolder),
|
||||
file = fileLog,
|
||||
file = getLogFile(activity),
|
||||
onFail = onFail,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun openChat(config: ChatConfig, feedbackData: FeedbackData) {
|
||||
chatManager.open(config) { context ->
|
||||
feedbackData.run {
|
||||
chatManager.open(
|
||||
config = config,
|
||||
createLogsFile = ::getLogFile,
|
||||
createFeedbackFile = { context -> getFeedbackFile(context, feedbackData) },
|
||||
)
|
||||
}
|
||||
|
||||
private fun getFeedbackFile(context: Context, feedbackData: FeedbackData): File? {
|
||||
return try {
|
||||
if (sessionFeedbackFile != null) {
|
||||
return sessionFeedbackFile
|
||||
}
|
||||
val file = File(context.filesDir, FEEDBACK_FILE)
|
||||
file.delete()
|
||||
file.createNewFile()
|
||||
|
||||
val feedback = feedbackData.run {
|
||||
prepare(infoHolder)
|
||||
joinTogether(context, infoHolder)
|
||||
}
|
||||
val fileWriter = FileWriter(file)
|
||||
fileWriter.write(feedback)
|
||||
fileWriter.close()
|
||||
|
||||
sessionFeedbackFile = file
|
||||
sessionFeedbackFile
|
||||
} catch (ex: Exception) {
|
||||
Timber.e(ex, "Can't create the logs file")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun createLogFile(context: Context): File? {
|
||||
private fun getLogFile(context: Context): File? {
|
||||
return try {
|
||||
val file = File(context.filesDir, "logs.txt")
|
||||
if (sessionLogsFile != null) {
|
||||
return sessionLogsFile
|
||||
}
|
||||
val file = File(context.filesDir, LOGS_FILE)
|
||||
file.delete()
|
||||
file.createNewFile()
|
||||
|
||||
|
|
@ -57,7 +86,8 @@ class FeedbackManager(
|
|||
fileWriter.write(stringWriter.toString())
|
||||
fileWriter.close()
|
||||
logCollector.clearLogs()
|
||||
file
|
||||
sessionLogsFile = file
|
||||
sessionLogsFile
|
||||
} catch (ex: Exception) {
|
||||
Timber.e(ex, "Can't create the logs file")
|
||||
null
|
||||
|
|
@ -75,5 +105,7 @@ class FeedbackManager(
|
|||
companion object {
|
||||
const val DEFAULT_SUPPORT_EMAIL = "support@tangem.com"
|
||||
const val S2C_SUPPORT_EMAIL = "cardsupport@start2coin.com"
|
||||
const val FEEDBACK_FILE = "feedback.txt"
|
||||
const val LOGS_FILE = "logs.txt"
|
||||
}
|
||||
}
|
||||
|
|
@ -4,8 +4,8 @@ import android.content.Context
|
|||
import android.util.Log
|
||||
import coil.ImageLoader
|
||||
import coil.util.Logger
|
||||
import com.tangem.datasource.api.common.createNetworkLoggingInterceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import timber.log.Timber
|
||||
|
||||
private const val COIL_LOG_TAG = "COIL"
|
||||
|
|
@ -18,14 +18,7 @@ fun createCoilImageLoader(context: Context, logEnabled: Boolean = false): ImageL
|
|||
logger(CoilTimberLogger())
|
||||
okHttpClient {
|
||||
OkHttpClient.Builder()
|
||||
.addNetworkInterceptor(
|
||||
HttpLoggingInterceptor { message ->
|
||||
Timber.tag(COIL_LOG_TAG).d(message)
|
||||
}
|
||||
.apply {
|
||||
level = HttpLoggingInterceptor.Level.BODY
|
||||
},
|
||||
)
|
||||
.addNetworkInterceptor(createNetworkLoggingInterceptor())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import android.os.Bundle
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import com.google.zxing.Result
|
||||
import com.otaliastudios.cameraview.CameraView.PERMISSION_REQUEST_CODE
|
||||
import me.dm7.barcodescanner.zxing.ZXingScannerView
|
||||
|
|
@ -16,11 +17,15 @@ import me.dm7.barcodescanner.zxing.ZXingScannerView
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class ScanQrCodeActivity : AppCompatActivity(), ZXingScannerView.ResultHandler {
|
||||
|
||||
private lateinit var mScannerView: ZXingScannerView
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
mScannerView = ZXingScannerView(this)
|
||||
|
||||
mScannerView = ZXingScannerView(this).apply {
|
||||
setFormats(listOf(BarcodeFormat.QR_CODE))
|
||||
}
|
||||
setContentView(mScannerView)
|
||||
|
||||
if (!permissionIsGranted()) requestPermission()
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ package com.tangem.tap.common.redux
|
|||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.preferencesStorage
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
class AccessCodeRequestPolicyMiddleware {
|
||||
|
|
@ -19,9 +20,8 @@ class AccessCodeRequestPolicyMiddleware {
|
|||
}
|
||||
|
||||
private fun updateAccessCodeRequestPolicy(scanResponse: ScanResponse) {
|
||||
tangemSdkManager.setAccessCodeRequestPolicy(
|
||||
useBiometricsForAccessCode = preferencesStorage.shouldSaveAccessCodes &&
|
||||
scanResponse.card.isAccessCodeSet,
|
||||
store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy(
|
||||
isBiometricsRequestPolicy = preferencesStorage.shouldSaveAccessCodes && scanResponse.card.isAccessCodeSet,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,11 +2,11 @@ package com.tangem.tap.common.redux.global
|
|||
|
||||
import com.tangem.domain.redux.domainStore
|
||||
import com.tangem.domain.redux.global.DomainGlobalAction
|
||||
import com.tangem.tap.common.extensions.replaceBy
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.onboarding.OnboardingManager
|
||||
import com.tangem.tap.preferencesStorage
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import com.tangem.utils.extensions.replaceBy
|
||||
import org.rekotlin.Action
|
||||
|
||||
@Suppress("LongMethod", "ComplexMethod")
|
||||
|
|
|
|||
|
|
@ -8,12 +8,13 @@ import com.tangem.core.analytics.Analytics
|
|||
import com.tangem.datasource.config.models.ShopifyShop
|
||||
import com.tangem.tap.common.analytics.converters.ShopOrderToEventConverter
|
||||
import com.tangem.tap.common.extensions.filterNotNull
|
||||
import com.tangem.tap.common.shop.data.ProductType
|
||||
import com.tangem.tap.common.shop.data.TangemProduct
|
||||
import com.tangem.tap.common.shop.data.TotalSum
|
||||
import com.tangem.tap.common.shop.googlepay.GooglePayService
|
||||
import com.tangem.tap.common.shop.shopify.ShopifyService
|
||||
import com.tangem.tap.common.shop.shopify.data.CheckoutItem
|
||||
import com.tangem.tap.features.shop.domain.models.ProductType
|
||||
import com.tangem.tap.features.shop.domain.models.ProductType.Companion.SKUS_TO_DISPLAY
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
|
|
@ -206,12 +207,6 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TANGEM_WALLET_2_CARDS_SKU = "TG115X2-S"
|
||||
const val TANGEM_WALLET_3_CARDS_SKU = "TG115X3-S"
|
||||
val SKUS_TO_DISPLAY = listOf(TANGEM_WALLET_2_CARDS_SKU, TANGEM_WALLET_3_CARDS_SKU)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Storefront.MoneyV2.format(): String {
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
package com.tangem.tap.common.shop.data
|
||||
|
||||
import com.tangem.tap.common.shop.TangemShopService
|
||||
|
||||
enum class ProductType(val sku: String) {
|
||||
WALLET_2_CARDS(TangemShopService.TANGEM_WALLET_2_CARDS_SKU),
|
||||
WALLET_3_CARDS(TangemShopService.TANGEM_WALLET_3_CARDS_SKU),
|
||||
;
|
||||
|
||||
companion object {
|
||||
fun fromSku(sku: String): ProductType? {
|
||||
return when (sku) {
|
||||
WALLET_2_CARDS.sku -> WALLET_2_CARDS
|
||||
WALLET_3_CARDS.sku -> WALLET_3_CARDS
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
package com.tangem.tap.common.shop.data
|
||||
|
||||
import com.tangem.tap.features.shop.domain.models.ProductType
|
||||
|
||||
data class TangemProduct(
|
||||
val type: ProductType,
|
||||
val totalSum: TotalSum? = null,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
package com.tangem.tap.data
|
||||
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.wallets.legacy.WalletsStateHolder
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
|
||||
// FIXME: Workaround, remove it once the normal UserWalletsStore has been implemented
|
||||
// [REDACTED_JIRA]
|
||||
internal class RuntimeUserWalletsStore(
|
||||
private val walletsStateHolder: WalletsStateHolder,
|
||||
) : UserWalletsStore {
|
||||
|
||||
override suspend fun getSyncOrNull(key: UserWalletId): UserWallet? {
|
||||
return walletsStateHolder.userWalletsListManager
|
||||
?.userWallets
|
||||
?.firstOrNull()
|
||||
?.singleOrNull { it.walletId == key }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +1,43 @@
|
|||
package com.tangem.tap.di
|
||||
|
||||
import android.content.Context
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.tangem.TangemSdk
|
||||
import com.tangem.domain.card.ScanCardUseCase
|
||||
import com.tangem.sdk.extensions.initWithBiometrics
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.tap.domain.TangemSdkManager
|
||||
import com.tangem.tap.domain.scanCard.repository.DefaultScanCardRepository
|
||||
import com.tangem.tap.userTokensRepository
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ActivityComponent
|
||||
import dagger.hilt.android.qualifiers.ActivityContext
|
||||
import dagger.hilt.android.scopes.ActivityScoped
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(ActivityComponent::class)
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object ActivityModule {
|
||||
|
||||
@Provides
|
||||
@ActivityScoped
|
||||
fun provideTangemSdk(@ActivityContext context: Context): TangemSdk {
|
||||
return TangemSdk.initWithBiometrics(context as FragmentActivity, TangemSdkManager.config)
|
||||
@Singleton
|
||||
fun provideTangemSdkManager(
|
||||
@ApplicationContext context: Context,
|
||||
cardSdkConfigRepository: CardSdkConfigRepository,
|
||||
): TangemSdkManager {
|
||||
return TangemSdkManager(cardSdkConfigRepository = cardSdkConfigRepository, resources = context.resources)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ActivityScoped
|
||||
fun provideTangemSdkManager(@ActivityContext context: Context, tangemSdk: TangemSdk): TangemSdkManager {
|
||||
return TangemSdkManager(tangemSdk, context)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ActivityScoped
|
||||
fun provideScanCardUseCase(tangemSdk: TangemSdk, tangemSdkManager: TangemSdkManager): ScanCardUseCase {
|
||||
@Singleton
|
||||
fun provideScanCardUseCase(
|
||||
tangemSdkManager: TangemSdkManager,
|
||||
cardSdkConfigRepository: CardSdkConfigRepository,
|
||||
): ScanCardUseCase {
|
||||
return ScanCardUseCase(
|
||||
tangemSdk = tangemSdk,
|
||||
scanCardRepository = DefaultScanCardRepository(userTokensRepository, tangemSdkManager),
|
||||
cardSdkConfigRepository = cardSdkConfigRepository,
|
||||
scanCardRepository = DefaultScanCardRepository(
|
||||
userTokensRepository = userTokensRepository,
|
||||
tangemSdkManager = tangemSdkManager,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.tangem.tap.di.data
|
||||
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.wallets.legacy.WalletsStateHolder
|
||||
import com.tangem.tap.data.RuntimeUserWalletsStore
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object UserWalletsStoreModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideUserWalletsStore(walletsStateHolder: WalletsStateHolder): UserWalletsStore {
|
||||
return RuntimeUserWalletsStore(walletsStateHolder)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.card.*
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.demo.DemoConfig
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ViewModelComponent
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
|
||||
@Module
|
||||
@InstallIn(ViewModelComponent::class)
|
||||
internal object CardDomainModule {
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideGetBiometricsStatusUseCase(
|
||||
cardSdkConfigRepository: CardSdkConfigRepository,
|
||||
): GetBiometricsStatusUseCase {
|
||||
return GetBiometricsStatusUseCase(cardSdkConfigRepository = cardSdkConfigRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideSetAccessCodeRequestPolicyUseCase(
|
||||
cardSdkConfigRepository: CardSdkConfigRepository,
|
||||
): SetAccessCodeRequestPolicyUseCase {
|
||||
return SetAccessCodeRequestPolicyUseCase(cardSdkConfigRepository = cardSdkConfigRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideGetAccessCodeSavingStatusUseCase(
|
||||
cardSdkConfigRepository: CardSdkConfigRepository,
|
||||
): GetAccessCodeSavingStatusUseCase {
|
||||
return GetAccessCodeSavingStatusUseCase(cardSdkConfigRepository = cardSdkConfigRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideGetCardWasScannedUseCase(cardRepository: CardRepository): GetCardWasScannedUseCase {
|
||||
return GetCardWasScannedUseCase(cardRepository = cardRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideIsDemoCardUseCase(): IsDemoCardUseCase = IsDemoCardUseCase(config = DemoConfig())
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.card.*
|
||||
import com.tangem.tap.domain.scanCard.DefaultScanCardProcessor
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object CardLegacyDomainModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideScanCardUseCase(): ScanCardProcessor = DefaultScanCardProcessor()
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.settings.IsUserAlreadyRateAppUseCase
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ViewModelComponent
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
|
||||
@Module
|
||||
@InstallIn(ViewModelComponent::class)
|
||||
internal object SettingsDomainModule {
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun providesGetWalletsUseCase(settingsRepository: SettingsRepository): IsUserAlreadyRateAppUseCase {
|
||||
return IsUserAlreadyRateAppUseCase(settingsRepository = settingsRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.tokens.*
|
||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||
import com.tangem.domain.tokens.repository.TokensRepository
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ViewModelComponent
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
|
||||
@Module
|
||||
@InstallIn(ViewModelComponent::class)
|
||||
internal object TokensDomainModule {
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideGetTokenListUseCase(
|
||||
tokensRepository: TokensRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): GetTokenListUseCase {
|
||||
return GetTokenListUseCase(tokensRepository, quotesRepository, networksRepository, dispatchers)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideGetPrimaryCurrencyUseCase(
|
||||
tokensRepository: TokensRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): GetPrimaryCurrencyUseCase {
|
||||
return GetPrimaryCurrencyUseCase(tokensRepository, quotesRepository, networksRepository, dispatchers)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideToggleTokenListGroupingUseCase(
|
||||
networksRepository: NetworksRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): ToggleTokenListGroupingUseCase {
|
||||
return ToggleTokenListGroupingUseCase(networksRepository, dispatchers)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideToggleTokenListSortingUseCase(dispatchers: CoroutineDispatcherProvider): ToggleTokenListSortingUseCase {
|
||||
return ToggleTokenListSortingUseCase(dispatchers)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideApplyTokenListSortingUseCase(
|
||||
tokensRepository: TokensRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): ApplyTokenListSortingUseCase {
|
||||
return ApplyTokenListSortingUseCase(tokensRepository, dispatchers)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.tokens.*
|
||||
import com.tangem.domain.txhistory.repository.TxHistoryRepository
|
||||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ViewModelComponent
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
|
||||
@Module
|
||||
@InstallIn(ViewModelComponent::class)
|
||||
internal object TxHistoryDomainModule {
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideGetTxHistoryItemsCountUseCase(txHistoryRepository: TxHistoryRepository): GetTxHistoryItemsCountUseCase {
|
||||
return GetTxHistoryItemsCountUseCase(repository = txHistoryRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideGetTxHistoryItemsUseCase(txHistoryRepository: TxHistoryRepository): GetTxHistoryItemsUseCase {
|
||||
return GetTxHistoryItemsUseCase(repository = txHistoryRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.datasource.config.ConfigManager
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.datasource.local.walletmanager.WalletManagersStore
|
||||
import com.tangem.domain.walletmanager.DefaultWalletManagersFacade
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object WalletManagersFacadeModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideWalletManagersFacade(
|
||||
walletManagersStore: WalletManagersStore,
|
||||
userWalletsStore: UserWalletsStore,
|
||||
configManager: ConfigManager,
|
||||
): WalletManagersFacade {
|
||||
return DefaultWalletManagersFacade(walletManagersStore, userWalletsStore, configManager)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.legacy.WalletsStateHolder
|
||||
import com.tangem.domain.wallets.usecase.GetExploreUrlUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.domain.wallets.usecase.SaveWalletUseCase
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ViewModelComponent
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
|
||||
@Module
|
||||
@InstallIn(ViewModelComponent::class)
|
||||
internal object WalletsDomainModule {
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun providesGetWalletsUseCase(walletsStateHolder: WalletsStateHolder): GetWalletsUseCase {
|
||||
return GetWalletsUseCase(walletsStateHolder = walletsStateHolder)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun providesSaveWalletUseCase(walletsStateHolder: WalletsStateHolder): SaveWalletUseCase {
|
||||
return SaveWalletUseCase(walletsStateHolder = walletsStateHolder)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun providesGetExploreUrlUseCase(walletsManagersFacade: WalletManagersFacade): GetExploreUrlUseCase {
|
||||
return GetExploreUrlUseCase(walletsManagersFacade = walletsManagersFacade)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.domain
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import androidx.annotation.StringRes
|
||||
import com.tangem.Message
|
||||
import com.tangem.TangemSdk
|
||||
|
|
@ -14,14 +14,13 @@ import com.tangem.common.usersCode.UserCodeRepository
|
|||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.crypto.bip39.DefaultMnemonic
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.operations.ScanTask
|
||||
import com.tangem.operations.derivation.DerivationTaskResponse
|
||||
import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask
|
||||
import com.tangem.operations.pins.CheckUserCodesCommand
|
||||
import com.tangem.operations.pins.CheckUserCodesResponse
|
||||
import com.tangem.operations.pins.SetUserCodeCommand
|
||||
import com.tangem.operations.usersetttings.SetUserCodeRecoveryAllowedTask
|
||||
import com.tangem.tap.common.analytics.events.Basic
|
||||
|
|
@ -38,7 +37,10 @@ import kotlinx.coroutines.withContext
|
|||
import kotlin.coroutines.resume
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Context) {
|
||||
class TangemSdkManager(private val cardSdkConfigRepository: CardSdkConfigRepository, private val resources: Resources) {
|
||||
|
||||
private val tangemSdk: TangemSdk
|
||||
get() = cardSdkConfigRepository.sdk
|
||||
|
||||
private val userCodeRepository by lazy {
|
||||
UserCodeRepository(
|
||||
|
|
@ -63,7 +65,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
|
|||
messageRes: Int? = null,
|
||||
allowsRequestAccessCodeFromRepository: Boolean = false,
|
||||
): CompletionResult<ScanResponse> {
|
||||
val message = Message(context.getString(messageRes ?: R.string.initial_message_scan_header))
|
||||
val message = Message(resources.getString(messageRes ?: R.string.initial_message_scan_header))
|
||||
return runTaskAsyncReturnOnMain(
|
||||
runnable = ScanProductTask(
|
||||
card = null,
|
||||
|
|
@ -80,7 +82,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
|
|||
return runTaskAsync(
|
||||
CreateProductWalletTask(scanResponse.cardTypesResolver),
|
||||
scanResponse.card.cardId,
|
||||
Message(context.getString(R.string.initial_message_create_wallet_body)),
|
||||
Message(resources.getString(R.string.initial_message_create_wallet_body)),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -92,7 +94,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
|
|||
is CompletionResult.Success -> runTaskAsync(
|
||||
CreateProductWalletTask(scanResponse.cardTypesResolver, seedResult.data),
|
||||
scanResponse.card.cardId,
|
||||
Message(context.getString(R.string.initial_message_create_wallet_body)),
|
||||
Message(resources.getString(R.string.initial_message_create_wallet_body)),
|
||||
)
|
||||
|
||||
is CompletionResult.Failure -> CompletionResult.Failure(seedResult.error)
|
||||
|
|
@ -111,7 +113,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
|
|||
return runTaskAsyncReturnOnMain(
|
||||
CreateWalletAndRescanTask(),
|
||||
cardId,
|
||||
initialMessage = Message(context.getString(R.string.initial_message_create_wallet_body)),
|
||||
initialMessage = Message(resources.getString(R.string.initial_message_create_wallet_body)),
|
||||
)
|
||||
.map { CardDTO(it) }
|
||||
}
|
||||
|
|
@ -127,7 +129,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
|
|||
return runTaskAsyncReturnOnMain(
|
||||
runnable = ResetToFactorySettingsTask(),
|
||||
cardId = cardId,
|
||||
initialMessage = Message(context.getString(R.string.card_settings_reset_card_to_factory)),
|
||||
initialMessage = Message(resources.getString(R.string.card_settings_reset_card_to_factory)),
|
||||
)
|
||||
.map { CardDTO(it) }
|
||||
}
|
||||
|
|
@ -154,7 +156,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
|
|||
return runTaskAsyncReturnOnMain(
|
||||
SetUserCodeCommand.changePasscode(null),
|
||||
cardId,
|
||||
initialMessage = Message(context.getString(R.string.initial_message_change_passcode_body)),
|
||||
initialMessage = Message(resources.getString(R.string.initial_message_change_passcode_body)),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -162,7 +164,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
|
|||
return runTaskAsyncReturnOnMain(
|
||||
SetUserCodeCommand.changeAccessCode(null),
|
||||
cardId,
|
||||
initialMessage = Message(context.getString(R.string.initial_message_change_access_code_body)),
|
||||
initialMessage = Message(resources.getString(R.string.initial_message_change_access_code_body)),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -170,15 +172,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
|
|||
return runTaskAsyncReturnOnMain(
|
||||
SetUserCodeCommand.resetUserCodes(),
|
||||
cardId,
|
||||
initialMessage = Message(context.getString(R.string.initial_message_tap_header)),
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun checkUserCodes(cardId: String?): CompletionResult<CheckUserCodesResponse> {
|
||||
return runTaskAsyncReturnOnMain(
|
||||
CheckUserCodesCommand(),
|
||||
cardId,
|
||||
initialMessage = Message(context.getString(R.string.initial_message_tap_header)),
|
||||
initialMessage = Message(resources.getString(R.string.initial_message_tap_header)),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +180,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
|
|||
return runTaskAsyncReturnOnMain(
|
||||
SetUserCodeRecoveryAllowedTask(enabled),
|
||||
cardId,
|
||||
initialMessage = Message(context.getString(R.string.initial_message_tap_header)),
|
||||
initialMessage = Message(resources.getString(R.string.initial_message_tap_header)),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -197,7 +191,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
|
|||
return runTaskAsyncReturnOnMain(
|
||||
runnable = ScanTask(allowRequestAccessCodeFromRepository),
|
||||
cardId = cardId,
|
||||
initialMessage = Message(context.getString(R.string.initial_message_tap_header)),
|
||||
initialMessage = Message(resources.getString(R.string.initial_message_tap_header)),
|
||||
)
|
||||
.map { CardDTO(it) }
|
||||
}
|
||||
|
|
@ -233,8 +227,9 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
|
|||
}
|
||||
}
|
||||
|
||||
@Deprecated("TangemSdkManager shouldn't returns a string from resources")
|
||||
fun getString(@StringRes stringResId: Int, vararg formatArgs: Any?): String {
|
||||
return context.getString(stringResId, *formatArgs)
|
||||
return resources.getString(stringResId, *formatArgs)
|
||||
}
|
||||
|
||||
fun setAccessCodeRequestPolicy(useBiometricsForAccessCode: Boolean) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tap.domain.configurable.warningMessage
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.tap.common.extensions.removeBy
|
||||
import com.tangem.utils.extensions.removeByReplace
|
||||
import com.tangem.wallet.R
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
|
|
@ -44,12 +44,12 @@ class WarningMessagesManager {
|
|||
}
|
||||
|
||||
fun removeWarnings(origin: WarningMessage.Origin) {
|
||||
warningsList.removeBy { it.origin == origin }
|
||||
warningsList.removeByReplace { it.origin == origin }
|
||||
sortByPriority()
|
||||
}
|
||||
|
||||
fun removeWarnings(messageRes: Int) {
|
||||
warningsList.removeBy { it.messageResId == messageRes }
|
||||
warningsList.removeByReplace { it.messageResId == messageRes }
|
||||
}
|
||||
|
||||
fun containsWarning(warning: WarningMessage) = warning in warningsList
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
package com.tangem.tap.domain.extensions
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.common.card.EllipticCurve
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
fun Blockchain.amountToCreateAccount(token: Token? = null): BigDecimal? {
|
||||
return when (this) {
|
||||
Blockchain.Stellar -> if (token?.symbol == NODL) BigDecimal(1.5) else BigDecimal.ONE
|
||||
Blockchain.XRP -> BigDecimal(10)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun Blockchain.minimalAmount(): BigDecimal {
|
||||
return 1.toBigDecimal().movePointLeft(decimals())
|
||||
}
|
||||
|
||||
fun Blockchain.getPrimaryCurve(): EllipticCurve? {
|
||||
return when {
|
||||
getSupportedCurves().contains(EllipticCurve.Secp256k1) -> {
|
||||
EllipticCurve.Secp256k1
|
||||
}
|
||||
getSupportedCurves().contains(EllipticCurve.Ed25519) -> {
|
||||
EllipticCurve.Ed25519
|
||||
}
|
||||
else -> {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val NODL = "NODL"
|
||||
|
|
@ -1,24 +1,17 @@
|
|||
package com.tangem.tap.domain.extensions
|
||||
|
||||
import com.tangem.common.card.FirmwareVersion
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.common.services.Result
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.common.TwinCardNumber
|
||||
import com.tangem.domain.common.getTwinCardNumber
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.userwallets.Artwork
|
||||
import com.tangem.operations.attestation.CardVerifyAndGetInfo
|
||||
import com.tangem.operations.attestation.OnlineCardVerifier
|
||||
import com.tangem.tap.features.wallet.redux.Artwork
|
||||
|
||||
val CardDTO.remainingSignatures: Int?
|
||||
get() = this.wallets.firstOrNull()?.remainingSignatures
|
||||
|
||||
val CardDTO.isWalletDataSupported: Boolean
|
||||
get() = this.firmwareVersion.major >= 4
|
||||
|
||||
val CardDTO.isFirmwareMultiwalletAllowed: Boolean
|
||||
get() = firmwareVersion >= FirmwareVersion.MultiWalletAvailable && settings.maxWalletsCount > 1
|
||||
|
||||
val CardDTO.isHdWalletAllowedByApp: Boolean
|
||||
get() = settings.isHDWalletAllowed
|
||||
|
||||
|
|
@ -58,16 +51,4 @@ suspend fun CardDTO.getOrLoadCardArtworkUrl(cardInfo: Result<CardVerifyAndGetInf
|
|||
|
||||
is Result.Failure -> ifAnyError()
|
||||
}
|
||||
}
|
||||
|
||||
fun CardDTO.getArtworkUrl(artworkId: String?): String? {
|
||||
return when {
|
||||
artworkId != null -> {
|
||||
OnlineCardVerifier.getUrlForArtwork(cardId, cardPublicKey.toHexString(), artworkId)
|
||||
}
|
||||
|
||||
cardId.startsWith(Artwork.SERGIO_CARD_ID) -> Artwork.SERGIO_CARD_URL
|
||||
cardId.startsWith(Artwork.MARTA_CARD_ID) -> Artwork.MARTA_CARD_URL
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
|
@ -2,21 +2,22 @@ package com.tangem.tap.domain.scanCard
|
|||
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.domain.card.ScanCardProcessor
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
|
||||
// TODO: Remove this object after feature toggle was removed and use ScanCardUseCase instead
|
||||
internal object ScanCardProcessor {
|
||||
internal class DefaultScanCardProcessor : ScanCardProcessor {
|
||||
private val isNewCardScanningEnabled: Boolean
|
||||
get() = store.state.daggerGraphState
|
||||
.get(DaggerGraphState::customTokenFeatureToggles)
|
||||
.isNewCardScanningEnabled
|
||||
|
||||
suspend fun scan(
|
||||
cardId: String? = null,
|
||||
allowsRequestAccessCodeFromRepository: Boolean = false,
|
||||
override suspend fun scan(
|
||||
cardId: String?,
|
||||
allowsRequestAccessCodeFromRepository: Boolean,
|
||||
): CompletionResult<ScanResponse> {
|
||||
return if (isNewCardScanningEnabled) {
|
||||
UseCaseScanProcessor.scan(cardId, allowsRequestAccessCodeFromRepository)
|
||||
|
|
@ -26,15 +27,15 @@ internal object ScanCardProcessor {
|
|||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
suspend fun scan(
|
||||
analyticsEvent: AnalyticsEvent? = null,
|
||||
cardId: String? = null,
|
||||
onProgressStateChange: suspend (showProgress: Boolean) -> Unit = {},
|
||||
onScanStateChange: suspend (scanInProgress: Boolean) -> Unit = {},
|
||||
onWalletNotCreated: suspend () -> Unit = {},
|
||||
disclaimerWillShow: () -> Unit = {},
|
||||
onFailure: suspend (error: TangemError) -> Unit = {},
|
||||
onSuccess: suspend (scanResponse: ScanResponse) -> Unit = {},
|
||||
override suspend fun scan(
|
||||
analyticsEvent: AnalyticsEvent?,
|
||||
cardId: String?,
|
||||
onProgressStateChange: suspend (showProgress: Boolean) -> Unit,
|
||||
onScanStateChange: suspend (scanInProgress: Boolean) -> Unit,
|
||||
onWalletNotCreated: suspend () -> Unit,
|
||||
disclaimerWillShow: () -> Unit,
|
||||
onFailure: suspend (error: TangemError) -> Unit,
|
||||
onSuccess: suspend (scanResponse: ScanResponse) -> Unit,
|
||||
) {
|
||||
if (isNewCardScanningEnabled) {
|
||||
UseCaseScanProcessor.scan(
|
||||
|
|
@ -6,7 +6,7 @@ import com.tangem.common.core.TangemSdkError
|
|||
import com.tangem.common.doOnFailure
|
||||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.common.TapWorkarounds.canSkipBackup
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.tap.domain.scanCard
|
|||
import arrow.fx.coroutines.resourceScope
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.card.ScanCardException
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.tap.domain.scanCard.chains
|
|||
import arrow.core.Either
|
||||
import arrow.core.right
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.domain.card.ScanCardException
|
||||
import com.tangem.domain.core.chain.Chain
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@ class ResetToFactorySettingsTask : CardSessionRunnable<Card> {
|
|||
}
|
||||
|
||||
private fun resetBackup(session: CardSession, callback: (result: CompletionResult<Card>) -> Unit) {
|
||||
val backupStatus = session.environment.card?.backupStatus
|
||||
if (backupStatus == null || backupStatus == Card.BackupStatus.NoBackup) {
|
||||
if (session.environment.card?.backupStatus?.isActive != true) {
|
||||
callback(CompletionResult.Success(session.environment.card!!))
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import com.tangem.domain.common.TapWorkarounds.isStart2Coin
|
|||
import com.tangem.domain.common.TapWorkarounds.isTangemTwins
|
||||
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
|
||||
import com.tangem.domain.common.TwinsHelper
|
||||
import com.tangem.domain.common.extensions.getPrimaryCurve
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
|
@ -30,7 +31,6 @@ import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask
|
|||
import com.tangem.operations.files.ReadFilesTask
|
||||
import com.tangem.operations.issuerAndUserData.ReadIssuerDataCommand
|
||||
import com.tangem.tap.domain.TapSdkError
|
||||
import com.tangem.tap.domain.extensions.getPrimaryCurve
|
||||
import com.tangem.tap.domain.tokens.UserTokensRepository
|
||||
import com.tangem.tap.preferencesStorage
|
||||
import com.tangem.tap.scope
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import com.tangem.datasource.connection.NetworkConnectionManager
|
|||
import com.tangem.datasource.files.AndroidFileReader
|
||||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
|
||||
import com.tangem.domain.userwallets.UserWalletIdBuilder
|
||||
import com.tangem.tap.domain.tokens.converters.CurrencyConverter
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
|
|
@ -79,8 +79,8 @@ class UserTokensRepository(
|
|||
private fun List<Currency>.toUserTokensResponse(): UserTokensResponse {
|
||||
return UserTokensResponse(
|
||||
tokens = CurrencyConverter.convertList(input = this),
|
||||
group = GROUP_DEFAULT_VALUE,
|
||||
sort = SORT_DEFAULT_VALUE,
|
||||
group = UserTokensResponse.GroupType.NONE,
|
||||
sort = UserTokensResponse.SortType.MANUAL,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -121,8 +121,6 @@ class UserTokensRepository(
|
|||
private fun getUserWalletId(card: CardDTO): String? = UserWalletIdBuilder.card(card).build()?.stringValue
|
||||
|
||||
companion object {
|
||||
private const val GROUP_DEFAULT_VALUE = "none"
|
||||
private const val SORT_DEFAULT_VALUE = "manual"
|
||||
private const val NOT_FOUND_HTTP_CODE = "404"
|
||||
|
||||
// TODO("After adding DI") get dependencies by DI
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
|||
import com.tangem.datasource.files.FileReader
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
|
||||
@Deprecated("Use [com.tangem.datasource.local.token.UserTokensStore] instead.")
|
||||
class UserTokensStorageService(private val fileReader: FileReader) {
|
||||
private val userTokensAdapter: JsonAdapter<UserTokensResponse> =
|
||||
MoshiConverter.networkMoshi.adapter(UserTokensResponse::class.java)
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ import com.tangem.common.flatMap
|
|||
import com.tangem.common.services.secure.SecureStorage
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.tap.common.extensions.replaceByOrAdd
|
||||
import com.tangem.tap.domain.userWalletList.model.UserWalletPublicInformation
|
||||
import com.tangem.tap.domain.userWalletList.repository.UserWalletsPublicInformationRepository
|
||||
import com.tangem.tap.domain.userWalletList.utils.publicInformation
|
||||
import com.tangem.utils.extensions.plusOrReplace
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
|
|
@ -29,12 +29,9 @@ internal class DefaultUserWalletsPublicInformationRepository(
|
|||
getAll()
|
||||
.flatMap { savedInformation ->
|
||||
val infoToSave = withContext(Dispatchers.Default) {
|
||||
savedInformation.toMutableList()
|
||||
.apply {
|
||||
replaceByOrAdd(userWallet.publicInformation) {
|
||||
userWallet.walletId == it.walletId
|
||||
}
|
||||
}
|
||||
savedInformation.plusOrReplace(userWallet.publicInformation) {
|
||||
userWallet.walletId == it.walletId
|
||||
}
|
||||
}
|
||||
|
||||
save(infoToSave)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import com.tangem.domain.wallets.models.UserWallet
|
|||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.tap.common.TestActions
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.common.extensions.replaceByOrAdd
|
||||
import com.tangem.tap.domain.model.WalletStoreModel
|
||||
import com.tangem.tap.domain.walletStores.WalletStoresError
|
||||
import com.tangem.tap.domain.walletStores.repository.WalletAmountsRepository
|
||||
|
|
@ -32,6 +31,7 @@ import com.tangem.tap.features.wallet.models.getPendingTransactions
|
|||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.extensions.plusOrReplace
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import timber.log.Timber
|
||||
|
|
@ -428,11 +428,10 @@ internal class DefaultWalletAmountsRepository(
|
|||
private suspend fun updateWalletManagerInStorage(userWalletId: UserWalletId, walletManager: WalletManager) =
|
||||
withContext(Dispatchers.Default) {
|
||||
WalletManagerStorage.update { prevManagers ->
|
||||
val newManagersForUserWallet = prevManagers[userWalletId].orEmpty().toMutableList().apply {
|
||||
replaceByOrAdd(walletManager) {
|
||||
val newManagersForUserWallet = prevManagers[userWalletId].orEmpty()
|
||||
.plusOrReplace(walletManager) {
|
||||
it.wallet.blockchain == walletManager.wallet.blockchain
|
||||
}
|
||||
}
|
||||
|
||||
prevManagers.apply {
|
||||
set(userWalletId, newManagersForUserWallet)
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@ import com.tangem.crypto.hdWallet.DerivationPath
|
|||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.TapWorkarounds.isTestCard
|
||||
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
|
||||
import com.tangem.domain.common.extensions.makeWalletManagerForApp
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.wallets.legacy.WalletManagersRepository
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.tap.domain.extensions.makeWalletManagerForApp
|
||||
import com.tangem.tap.domain.walletStores.WalletStoresError
|
||||
import com.tangem.tap.domain.walletStores.storage.WalletManagerStorage
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import com.tangem.blockchain.common.BlockchainSdkError
|
|||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.blockchain.common.address.AddressType
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.tap.domain.extensions.amountToCreateAccount
|
||||
import com.tangem.domain.common.extensions.amountToCreateAccount
|
||||
import com.tangem.tap.domain.getFirstToken
|
||||
import com.tangem.tap.domain.model.WalletDataModel
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@ package com.tangem.tap.domain.walletconnect
|
|||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.common.card.EllipticCurve
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.datasource.api.common.createNetworkLoggingInterceptor
|
||||
import com.tangem.domain.common.extensions.toNetworkId
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.common.analytics.events.WalletConnect
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.TapError
|
||||
|
|
@ -36,7 +35,6 @@ import okhttp3.Interceptor
|
|||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
|
@ -56,8 +54,9 @@ class WalletConnectManager {
|
|||
.addInterceptor(RetryInterceptor())
|
||||
.build()
|
||||
}
|
||||
|
||||
private val interceptor by lazy {
|
||||
HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY }
|
||||
createNetworkLoggingInterceptor()
|
||||
}
|
||||
|
||||
private var sessions: MutableMap<Topic, WalletConnectActiveData> = mutableMapOf()
|
||||
|
|
@ -226,7 +225,6 @@ class WalletConnectManager {
|
|||
}
|
||||
|
||||
private fun onSessionClosed(session: WCSession) {
|
||||
Analytics.send(WalletConnect.SessionDisconnected())
|
||||
sessions.remove(session.topic)
|
||||
walletConnectRepository.removeSession(session)
|
||||
store.dispatchOnMain(WalletConnectAction.RemoveSession(session))
|
||||
|
|
@ -394,7 +392,6 @@ class WalletConnectManager {
|
|||
),
|
||||
)
|
||||
}
|
||||
Analytics.send(WalletConnect.NewSessionEstablished(""))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras
|
|||
import com.tangem.blockchain.blockchains.ethereum.EthereumUtils
|
||||
import com.tangem.blockchain.blockchains.ethereum.EthereumUtils.Companion.toKeccak
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.blockchain.extensions.SimpleResult
|
||||
import com.tangem.blockchain.extensions.hexToBigDecimal
|
||||
import com.tangem.blockchain.extensions.isAscii
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.common.extensions.toDecompressedPublicKey
|
||||
import com.tangem.common.extensions.toHexString
|
||||
|
|
@ -22,7 +22,6 @@ import com.tangem.operations.sign.SignHashCommand
|
|||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Basic
|
||||
import com.tangem.tap.common.analytics.events.Basic.TransactionSent.MemoType
|
||||
import com.tangem.tap.common.analytics.events.WalletConnect
|
||||
import com.tangem.tap.common.extensions.safeUpdate
|
||||
import com.tangem.tap.common.extensions.toFormattedString
|
||||
import com.tangem.tap.domain.walletconnect.BnbHelper.toWCBinanceTradeOrder
|
||||
|
|
@ -35,8 +34,8 @@ import com.tangem.tap.domain.walletconnect2.domain.models.binance.WcBinanceTrans
|
|||
import com.tangem.tap.features.details.redux.walletconnect.*
|
||||
import com.tangem.tap.features.details.ui.walletconnect.dialogs.PersonalSignDialogData
|
||||
import com.tangem.tap.features.details.ui.walletconnect.dialogs.TransactionRequestDialogData
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdk
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import com.trustwallet.walletconnect.models.ethereum.WCEthereumSignMessage.WCSignType.*
|
||||
import timber.log.Timber
|
||||
|
|
@ -76,7 +75,8 @@ class WalletConnectSdkHelper {
|
|||
|
||||
val transactionData = TransactionData(
|
||||
amount = Amount(value, wallet.blockchain),
|
||||
fee = Amount(fee, wallet.blockchain),
|
||||
// TODO refactoring
|
||||
fee = Fee.Common(Amount(fee, wallet.blockchain)),
|
||||
sourceAddress = transaction.from,
|
||||
destinationAddress = transaction.to!!,
|
||||
extras = EthereumTransactionExtras(
|
||||
|
|
@ -161,7 +161,10 @@ class WalletConnectSdkHelper {
|
|||
private suspend fun sendTransaction(data: WcTransactionData, cardId: String?): String? {
|
||||
val result = (data.walletManager as TransactionSender).send(
|
||||
transactionData = data.transaction,
|
||||
signer = CommonSigner(tangemSdk, cardId),
|
||||
signer = CommonSigner(
|
||||
tangemSdk = store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository).sdk,
|
||||
cardId = cardId,
|
||||
),
|
||||
)
|
||||
return when (result) {
|
||||
SimpleResult.Success -> {
|
||||
|
|
@ -170,7 +173,6 @@ class WalletConnectSdkHelper {
|
|||
HEX_PREFIX + data.walletManager.wallet.recentTransactions.last().hash
|
||||
}
|
||||
is SimpleResult.Failure -> {
|
||||
(result.error as? TangemSdkError)?.let { Analytics.send(WalletConnect.TransactionError(it)) }
|
||||
Timber.e(result.error as BlockchainSdkError)
|
||||
null
|
||||
}
|
||||
|
|
@ -182,7 +184,6 @@ class WalletConnectSdkHelper {
|
|||
transactionData = data.transaction,
|
||||
nonce = null,
|
||||
blockchain = data.walletManager.wallet.blockchain,
|
||||
gasLimit = null,
|
||||
) ?: return null
|
||||
|
||||
val command = SignHashCommand(
|
||||
|
|
@ -201,7 +202,6 @@ class WalletConnectSdkHelper {
|
|||
).toHexString()
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
(result.error as? TangemSdkError)?.let { Analytics.send(WalletConnect.SignError(it)) }
|
||||
Timber.e(result.error.customMessage)
|
||||
null
|
||||
}
|
||||
|
|
@ -240,7 +240,6 @@ class WalletConnectSdkHelper {
|
|||
)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
(result.error as? TangemSdkError)?.let { Analytics.send(WalletConnect.TransactionError(it)) }
|
||||
Timber.e(result.error.customMessage)
|
||||
null
|
||||
}
|
||||
|
|
@ -334,7 +333,6 @@ class WalletConnectSdkHelper {
|
|||
)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
(result.error as? TangemSdkError)?.let { Analytics.send(WalletConnect.SignError(it)) }
|
||||
Timber.e(result.error.customMessage)
|
||||
null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ package com.tangem.tap.domain.walletconnect2.data
|
|||
|
||||
import android.app.Application
|
||||
import arrow.core.flatten
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.tap.common.analytics.events.WalletConnect
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectRepository
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WcJrpcMethods
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WcJrpcRequestsDeserializer
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WcRequest
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.*
|
||||
|
|
@ -25,6 +26,7 @@ import javax.inject.Inject
|
|||
class WalletConnectRepositoryImpl @Inject constructor(
|
||||
private val application: Application,
|
||||
private val wcRequestDeserializer: WcJrpcRequestsDeserializer,
|
||||
private val analyticsHandler: AnalyticsEventHandler,
|
||||
) : WalletConnectRepository {
|
||||
|
||||
private var sessionProposal: Wallet.Model.SessionProposal? = null
|
||||
|
|
@ -37,6 +39,8 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
private val _activeSessions: MutableSharedFlow<List<WalletConnectSession>> = MutableSharedFlow()
|
||||
override val activeSessions: Flow<List<WalletConnectSession>> = _activeSessions
|
||||
|
||||
private var currentSessions: List<WalletConnectSession> = emptyList()
|
||||
|
||||
/**
|
||||
* @param projectId Project ID at https://cloud.walletconnect.com/
|
||||
*/
|
||||
|
|
@ -127,8 +131,12 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
// we can send approval automatically, because in WC 2.0 the list of chains is approved when
|
||||
// initial connection is established
|
||||
sendRequest(
|
||||
topic = sessionRequest.topic,
|
||||
id = sessionRequest.request.id,
|
||||
RequestData(
|
||||
topic = sessionRequest.topic,
|
||||
requestId = sessionRequest.request.id,
|
||||
blockchain = sessionRequest.chainId.toString(),
|
||||
method = WcJrpcMethods.WALLET_ADD_ETHEREUM_CHAIN.code,
|
||||
),
|
||||
result = "",
|
||||
)
|
||||
}
|
||||
|
|
@ -142,6 +150,7 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
id = sessionRequest.request.id,
|
||||
metaUrl = sessionRequest.peerMetaData?.url ?: "",
|
||||
metaName = sessionRequest.peerMetaData?.name ?: "",
|
||||
method = sessionRequest.request.method,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -263,7 +272,12 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
params = sessionApproval,
|
||||
onSuccess = {
|
||||
Timber.d("Approved successfully: $it")
|
||||
Analytics.send(WalletConnect.NewSessionEstablished(sessionProposal.name))
|
||||
analyticsHandler.send(
|
||||
WalletConnect.NewSessionEstablished(
|
||||
dAppName = sessionProposal.name,
|
||||
dAppUrl = sessionProposal.url,
|
||||
),
|
||||
)
|
||||
},
|
||||
onError = {
|
||||
Timber.d("Error while approving: $it")
|
||||
|
|
@ -278,23 +292,56 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
override fun sendRequest(topic: String, id: Long, result: String) {
|
||||
override fun sendRequest(requestData: RequestData, result: String) {
|
||||
val session = currentSessions.find { it.topic == requestData.topic }
|
||||
analyticsHandler.send(
|
||||
WalletConnect.RequestHandled(
|
||||
WalletConnect.RequestHandledParams(
|
||||
dAppName = session?.name ?: "",
|
||||
dAppUrl = session?.url ?: "",
|
||||
methodName = requestData.method,
|
||||
blockchain = requestData.blockchain,
|
||||
),
|
||||
),
|
||||
)
|
||||
Web3Wallet.respondSessionRequest(
|
||||
params = Wallet.Params.SessionRequestResponse(
|
||||
sessionTopic = topic,
|
||||
sessionTopic = requestData.topic,
|
||||
jsonRpcResponse = Wallet.Model.JsonRpcResponse.JsonRpcResult(
|
||||
id = id,
|
||||
id = requestData.requestId,
|
||||
result = result,
|
||||
),
|
||||
),
|
||||
onSuccess = {},
|
||||
onError = {
|
||||
Analytics.send(WalletConnect.TransactionError(it.throwable))
|
||||
WalletConnect.RequestHandledParams(
|
||||
dAppName = session?.name ?: "",
|
||||
dAppUrl = session?.url ?: "",
|
||||
methodName = requestData.method,
|
||||
blockchain = requestData.blockchain,
|
||||
errorCode = WalletConnectError.ValidationError.toString(),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override fun rejectRequest(topic: String, id: Long) {
|
||||
override fun rejectRequest(requestData: RequestData, error: WalletConnectError) {
|
||||
val session = currentSessions.find { it.topic == requestData.topic }
|
||||
analyticsHandler.send(
|
||||
WalletConnect.RequestHandled(
|
||||
WalletConnect.RequestHandledParams(
|
||||
dAppName = session?.name ?: "",
|
||||
dAppUrl = session?.url ?: "",
|
||||
methodName = requestData.method,
|
||||
blockchain = requestData.blockchain,
|
||||
errorCode = error.toString(),
|
||||
),
|
||||
),
|
||||
)
|
||||
cancelRequest(requestData.topic, requestData.requestId)
|
||||
}
|
||||
|
||||
override fun cancelRequest(topic: String, id: Long) {
|
||||
Web3Wallet.respondSessionRequest(
|
||||
params = Wallet.Params.SessionRequestResponse(
|
||||
sessionTopic = topic,
|
||||
|
|
@ -325,10 +372,16 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
}
|
||||
|
||||
override fun disconnect(topic: String) {
|
||||
val session = currentSessions.find { it.topic == topic }
|
||||
Web3Wallet.disconnectSession(
|
||||
params = Wallet.Params.SessionDisconnect(topic),
|
||||
onSuccess = {
|
||||
Analytics.send(WalletConnect.SessionDisconnected())
|
||||
analyticsHandler.send(
|
||||
WalletConnect.SessionDisconnected(
|
||||
dAppName = session?.name ?: "",
|
||||
dAppUrl = session?.url ?: "",
|
||||
),
|
||||
)
|
||||
updateSessions()
|
||||
Timber.d("Disconnected successfully: $it")
|
||||
},
|
||||
|
|
@ -364,6 +417,7 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
)
|
||||
}
|
||||
Timber.d("Available sessions: $availableSessions")
|
||||
currentSessions = availableSessions
|
||||
_activeSessions.emit(availableSessions)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package com.tangem.tap.domain.walletconnect2.domain
|
||||
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.tap.common.analytics.events.WalletConnect
|
||||
import com.tangem.tap.common.extensions.filterNotNull
|
||||
import com.tangem.tap.domain.walletconnect.WalletConnectSdkHelper
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.*
|
||||
|
|
@ -148,8 +146,8 @@ class WalletConnectInteractor(
|
|||
walletConnectRepository.disconnect(topic)
|
||||
}
|
||||
|
||||
fun rejectRequest(topic: String, id: Long) {
|
||||
walletConnectRepository.rejectRequest(topic, id)
|
||||
fun cancelRequest(topic: String, id: Long) {
|
||||
walletConnectRepository.cancelRequest(topic, id)
|
||||
}
|
||||
|
||||
private suspend fun handleRequest(sessionRequest: WalletConnectEvents.SessionRequest) {
|
||||
|
|
@ -164,16 +162,23 @@ class WalletConnectInteractor(
|
|||
null
|
||||
}
|
||||
}
|
||||
val networkId = sessionRequest.chainId?.let { blockchainHelper.chainIdToNetworkIdOrNull(it) } ?: ""
|
||||
val requestData = RequestData(
|
||||
topic = sessionRequest.topic,
|
||||
requestId = sessionRequest.id,
|
||||
blockchain = networkId,
|
||||
method = sessionRequest.method,
|
||||
)
|
||||
|
||||
if (error != null) {
|
||||
walletConnectRepository.rejectRequest(sessionRequest.topic, sessionRequest.id)
|
||||
walletConnectRepository.rejectRequest(requestData, error)
|
||||
return
|
||||
}
|
||||
|
||||
when (sessionRequest.request) {
|
||||
is WcRequest.BnbCancel -> Unit
|
||||
is WcRequest.BnbTxConfirm -> walletConnectRepository.sendRequest(
|
||||
topic = sessionRequest.topic,
|
||||
id = sessionRequest.id,
|
||||
requestData = requestData,
|
||||
result = "",
|
||||
)
|
||||
else -> {
|
||||
|
|
@ -212,16 +217,18 @@ class WalletConnectInteractor(
|
|||
|
||||
Timber.d("Signed hash: $signedHash")
|
||||
|
||||
val requestData = RequestData(
|
||||
topic = request.topic,
|
||||
requestId = request.requestId,
|
||||
blockchain = networkId,
|
||||
method = currentRequest.method,
|
||||
)
|
||||
|
||||
if (signedHash == null) {
|
||||
walletConnectRepository.rejectRequest(
|
||||
topic = request.topic,
|
||||
id = request.requestId,
|
||||
)
|
||||
walletConnectRepository.rejectRequest(requestData, WalletConnectError.SigningError)
|
||||
} else {
|
||||
Analytics.send(WalletConnect.RequestSigned())
|
||||
walletConnectRepository.sendRequest(
|
||||
topic = request.topic,
|
||||
id = request.requestId,
|
||||
requestData = requestData,
|
||||
result = signedHash,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
package com.tangem.tap.domain.walletconnect2.domain
|
||||
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.Account
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.NetworkNamespace
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectEvents
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectSession
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface WalletConnectRepository {
|
||||
|
|
@ -24,7 +21,9 @@ interface WalletConnectRepository {
|
|||
|
||||
fun reject()
|
||||
|
||||
fun sendRequest(topic: String, id: Long, result: String)
|
||||
fun sendRequest(requestData: RequestData, result: String)
|
||||
|
||||
fun rejectRequest(topic: String, id: Long)
|
||||
fun rejectRequest(requestData: RequestData, error: WalletConnectError)
|
||||
|
||||
fun cancelRequest(topic: String, id: Long)
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.tap.domain.walletconnect2.domain.models
|
||||
|
||||
data class RequestData(
|
||||
val topic: String,
|
||||
val requestId: Long,
|
||||
val method: String,
|
||||
val blockchain: String,
|
||||
)
|
||||
|
|
@ -7,4 +7,6 @@ sealed class WalletConnectError : Exception() {
|
|||
data class ExternalApprovalError(override val message: String?) : WalletConnectError()
|
||||
object WrongUserWallet : WalletConnectError()
|
||||
object UnsupportedMethod : WalletConnectError()
|
||||
object SigningError : WalletConnectError()
|
||||
object ValidationError : WalletConnectError()
|
||||
}
|
||||
|
|
@ -24,5 +24,6 @@ sealed interface WalletConnectEvents {
|
|||
val id: Long,
|
||||
val metaName: String,
|
||||
val metaUrl: String,
|
||||
val method: String,
|
||||
) : WalletConnectEvents
|
||||
}
|
||||
|
|
@ -1,16 +1,7 @@
|
|||
package com.tangem.tap.features.demo
|
||||
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.TransactionSender
|
||||
import com.tangem.blockchain.common.TransactionSigner
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.toBlockchainSdkError
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.blockchain.extensions.SimpleResult
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.domain.demo.DemoConfig
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.common.demo.DemoConfig
|
||||
import com.tangem.tap.common.extensions.dispatchNotification
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.details.redux.DetailsAction
|
||||
|
|
@ -21,13 +12,6 @@ import com.tangem.tap.store
|
|||
import com.tangem.wallet.R
|
||||
import org.rekotlin.Action
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface DemoMiddleware {
|
||||
fun tryHandle(config: DemoConfig, scanResponse: ScanResponse, action: Action): Boolean
|
||||
}
|
||||
|
||||
object DemoHelper {
|
||||
val config = DemoConfig()
|
||||
|
||||
|
|
@ -66,59 +50,10 @@ object DemoHelper {
|
|||
return false
|
||||
}
|
||||
|
||||
fun injectDemoBalance(walletManager: WalletManager?) {
|
||||
val manager = walletManager ?: return
|
||||
|
||||
val blockchain = walletManager.wallet.blockchain
|
||||
val amount = config.getBalance(blockchain)
|
||||
manager.wallet.setAmount(amount)
|
||||
}
|
||||
|
||||
private fun getScanResponse(appState: () -> AppState?): ScanResponse? {
|
||||
val state = appState() ?: return null
|
||||
|
||||
return state.globalState.onboardingState.onboardingManager?.scanResponse
|
||||
?: state.globalState.scanResponse
|
||||
}
|
||||
}
|
||||
|
||||
class DemoTransactionSender(private val walletManager: WalletManager) : TransactionSender {
|
||||
|
||||
override suspend fun getFee(amount: Amount, destination: String): Result<List<Amount>> {
|
||||
val blockchain = walletManager.wallet.blockchain
|
||||
return Result.Success(
|
||||
listOf(
|
||||
Amount(0.0001.toBigDecimal(), blockchain),
|
||||
Amount(0.0002.toBigDecimal(), blockchain),
|
||||
Amount(0.0003.toBigDecimal(), blockchain),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
override suspend fun send(transactionData: TransactionData, signer: TransactionSigner): SimpleResult {
|
||||
val dataToSign = randomString(32).toByteArray()
|
||||
val signerResponse = signer.sign(
|
||||
hash = dataToSign,
|
||||
publicKey = walletManager.wallet.publicKey,
|
||||
)
|
||||
return when (signerResponse) {
|
||||
is CompletionResult.Success -> SimpleResult.Failure(Exception(ID).toBlockchainSdkError())
|
||||
is CompletionResult.Failure -> SimpleResult.fromTangemSdkError(signerResponse.error)
|
||||
}
|
||||
}
|
||||
|
||||
private fun randomInt(from: Int, to: Int): Int = kotlin.random.Random.nextInt(from, to)
|
||||
|
||||
private fun randomString(length: Int): String {
|
||||
val charPool: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')
|
||||
return (1..length)
|
||||
.map { randomInt(0, charPool.size) }
|
||||
.map(charPool::get)
|
||||
.joinToString("")
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = DemoTransactionSender::class.java.simpleName
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.tap.features.demo
|
||||
|
||||
import com.tangem.domain.demo.DemoConfig
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import org.rekotlin.Action
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface DemoMiddleware {
|
||||
fun tryHandle(config: DemoConfig, scanResponse: ScanResponse, action: Action): Boolean
|
||||
}
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
package com.tangem.tap.features.demo
|
||||
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.common.demo.DemoConfig
|
||||
import com.tangem.domain.common.extensions.makePrimaryWalletManager
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.tap.domain.extensions.makePrimaryWalletManager
|
||||
import com.tangem.domain.demo.DemoConfig
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteAction
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
import com.tangem.tap.features.wallet.redux.ProgressState
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
package com.tangem.tap.features.demo
|
||||
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.blockchain.extensions.SimpleResult
|
||||
import com.tangem.common.CompletionResult
|
||||
import kotlin.random.Random
|
||||
|
||||
class DemoTransactionSender(private val walletManager: WalletManager) : TransactionSender {
|
||||
|
||||
override suspend fun getFee(amount: Amount, destination: String): Result<TransactionFee> {
|
||||
val blockchain = walletManager.wallet.blockchain
|
||||
return Result.Success(
|
||||
TransactionFee.Choosable(
|
||||
minimum = Fee.Common(Amount(minimumFee, blockchain)),
|
||||
normal = Fee.Common(Amount(normalFee, blockchain)),
|
||||
priority = Fee.Common(Amount(priorityFee, blockchain)),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun send(transactionData: TransactionData, signer: TransactionSigner): SimpleResult {
|
||||
val signerResponse = signer.sign(
|
||||
hash = getDataToSign(),
|
||||
publicKey = walletManager.wallet.publicKey,
|
||||
)
|
||||
return when (signerResponse) {
|
||||
is CompletionResult.Success -> SimpleResult.Failure(Exception(ID).toBlockchainSdkError())
|
||||
is CompletionResult.Failure -> SimpleResult.fromTangemSdkError(signerResponse.error)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDataToSign(): ByteArray {
|
||||
val charPool: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')
|
||||
return IntRange(start = 1, endInclusive = 32)
|
||||
.map { Random.nextInt(from = 0, until = charPool.size) }
|
||||
.map(charPool::get)
|
||||
.joinToString(separator = "")
|
||||
.toByteArray()
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID: String = DemoTransactionSender::class.java.simpleName
|
||||
|
||||
private val minimumFee = 0.0001.toBigDecimal()
|
||||
private val normalFee = 0.0002.toBigDecimal()
|
||||
private val priorityFee = 0.0003.toBigDecimal()
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,8 @@ import com.tangem.core.navigation.NavigationAction
|
|||
import com.tangem.domain.common.TapWorkarounds.isTangemTwins
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.userwallets.UserWalletBuilder
|
||||
import com.tangem.domain.userwallets.UserWalletIdBuilder
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
|
|
@ -23,9 +25,6 @@ import com.tangem.tap.common.extensions.onUserWalletSelected
|
|||
import com.tangem.tap.common.redux.AppDialog
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.model.builders.UserWalletBuilder
|
||||
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
|
||||
import com.tangem.tap.domain.scanCard.ScanCardProcessor
|
||||
import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation
|
||||
import com.tangem.tap.domain.userWalletList.di.provideRuntimeImplementation
|
||||
import com.tangem.tap.domain.userWalletList.isLockedSync
|
||||
|
|
@ -33,6 +32,7 @@ import com.tangem.tap.features.demo.DemoHelper
|
|||
import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -74,7 +74,8 @@ class DetailsMiddleware {
|
|||
is DetailsAction.AccessCodeRecovery -> accessCodeRecoveryMiddleware.handle(state, action)
|
||||
DetailsAction.ScanCard -> {
|
||||
scope.launch {
|
||||
ScanCardProcessor.scan(allowsRequestAccessCodeFromRepository = true)
|
||||
store.state.daggerGraphState.get(DaggerGraphState::scanCardProcessor)
|
||||
.scan(allowsRequestAccessCodeFromRepository = true)
|
||||
.doOnSuccess { scanResponse ->
|
||||
// if we use biometric, scanResponse in GlobalState is null, and crashes NPE on twin cards
|
||||
store.dispatch(GlobalAction.SaveScanResponse(scanResponse))
|
||||
|
|
@ -371,9 +372,9 @@ class DetailsMiddleware {
|
|||
Analytics.send(Settings.AppSettings.SaveAccessCodeSwitcherChanged(AnalyticsParam.OnOffState.On))
|
||||
|
||||
preferencesStorage.shouldSaveAccessCodes = true
|
||||
tangemSdkManager.setAccessCodeRequestPolicy(
|
||||
useBiometricsForAccessCode = scanResponse?.card?.isAccessCodeSet == true,
|
||||
)
|
||||
store.state.daggerGraphState
|
||||
.get(DaggerGraphState::cardSdkConfigRepository)
|
||||
.setAccessCodeRequestPolicy(isBiometricsRequestPolicy = scanResponse?.card?.isAccessCodeSet == true)
|
||||
|
||||
return CompletionResult.Success(Unit)
|
||||
}
|
||||
|
|
@ -384,9 +385,9 @@ class DetailsMiddleware {
|
|||
Analytics.send(Settings.AppSettings.SaveAccessCodeSwitcherChanged(AnalyticsParam.OnOffState.Off))
|
||||
|
||||
preferencesStorage.shouldSaveAccessCodes = false
|
||||
tangemSdkManager.setAccessCodeRequestPolicy(
|
||||
useBiometricsForAccessCode = false,
|
||||
)
|
||||
store.state.daggerGraphState
|
||||
.get(DaggerGraphState::cardSdkConfigRepository)
|
||||
.setAccessCodeRequestPolicy(isBiometricsRequestPolicy = false)
|
||||
}
|
||||
.doOnFailure { error ->
|
||||
Timber.e(error, "Unable to delete saved access codes")
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ class WalletConnectMiddleware {
|
|||
}
|
||||
is WalletConnectAction.RejectRequest -> {
|
||||
walletConnectManager.rejectRequest(action.topic, action.id)
|
||||
walletConnectInteractor.rejectRequest(action.topic, action.id)
|
||||
walletConnectInteractor.cancelRequest(action.topic, action.id)
|
||||
}
|
||||
is WalletConnectAction.SendTransaction -> {
|
||||
walletConnectManager.completeTransaction(action.topic)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import androidx.activity.OnBackPressedCallback
|
|||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import com.google.zxing.Result
|
||||
import com.otaliastudios.cameraview.CameraView
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
|
|
@ -38,10 +39,19 @@ class QrScanFragment : Fragment(0), ZXingScannerView.ResultHandler {
|
|||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
if (!permissionIsGranted()) requestPermission()
|
||||
|
||||
scannerView = ZXingScannerView(activity)
|
||||
scannerView = ZXingScannerView(activity).apply {
|
||||
setFormats(listOf(BarcodeFormat.QR_CODE))
|
||||
}
|
||||
|
||||
return scannerView
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
scannerView?.setResultHandler(this)
|
||||
scannerView?.startCamera()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
scannerView?.stopCamera()
|
||||
|
|
@ -52,12 +62,6 @@ class QrScanFragment : Fragment(0), ZXingScannerView.ResultHandler {
|
|||
setFitSystemWindows(fit = false)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
scannerView?.setResultHandler(this)
|
||||
scannerView?.startCamera()
|
||||
}
|
||||
|
||||
override fun handleResult(result: Result) {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
setFitSystemWindows(fit = false)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.features.home.redux
|
||||
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Basic
|
||||
import com.tangem.tap.common.entities.IndeterminateProgressButton
|
||||
|
|
|
|||
|
|
@ -5,11 +5,10 @@ import com.tangem.common.doOnResult
|
|||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.Basic
|
||||
import com.tangem.tap.common.analytics.events.IntroductionProcess
|
||||
import com.tangem.tap.common.analytics.events.Shop
|
||||
|
|
@ -21,10 +20,14 @@ import com.tangem.tap.common.extensions.onUserWalletSelected
|
|||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.model.builders.UserWalletBuilder
|
||||
import com.tangem.tap.domain.scanCard.ScanCardProcessor
|
||||
import com.tangem.tap.features.home.redux.HomeMiddleware.NEW_BUY_WALLET_URL
|
||||
import com.tangem.tap.features.send.redux.states.ButtonState
|
||||
import com.tangem.tap.features.signin.redux.SignInAction
|
||||
import com.tangem.tap.preferencesStorage
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.userWalletsListManager
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Action
|
||||
|
|
@ -76,11 +79,11 @@ private fun handleHomeAction(action: Action) {
|
|||
|
||||
private fun readCard(analyticsEvent: AnalyticsEvent?) = scope.launch {
|
||||
delay(timeMillis = 200)
|
||||
tangemSdkManager.setAccessCodeRequestPolicy(
|
||||
useBiometricsForAccessCode = preferencesStorage.shouldSaveAccessCodes,
|
||||
store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy(
|
||||
isBiometricsRequestPolicy = preferencesStorage.shouldSaveAccessCodes,
|
||||
)
|
||||
|
||||
ScanCardProcessor.scan(
|
||||
store.state.daggerGraphState.get(DaggerGraphState::scanCardProcessor).scan(
|
||||
analyticsEvent = analyticsEvent,
|
||||
onProgressStateChange = { showProgress ->
|
||||
if (showProgress) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.content.Intent
|
|||
import android.nfc.NfcAdapter
|
||||
import android.nfc.Tag
|
||||
import android.os.Build
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.features.intentHandler.IntentHandler
|
||||
import com.tangem.tap.features.welcome.redux.WelcomeAction
|
||||
|
|
@ -41,10 +42,10 @@ class BackgroundScanIntentHandler(
|
|||
// TODO: Remove delay after [REDACTED_JIRA]
|
||||
scope.launch {
|
||||
delay(timeMillis = 200)
|
||||
store.dispatch(WelcomeAction.ProceedWithCard)
|
||||
store.dispatchWithMain(WelcomeAction.ProceedWithCard)
|
||||
}
|
||||
} else {
|
||||
store.dispatch(HomeAction.ReadCard())
|
||||
store.dispatchWithMain(HomeAction.ReadCard())
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.features.intentHandler.handlers
|
||||
|
||||
import android.content.Intent
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.features.intentHandler.IntentHandler
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.store
|
||||
|
|
@ -20,7 +21,7 @@ class SellCurrencyIntentHandler : IntentHandler {
|
|||
val destinationAddress = intentData.getQueryParameter(DEPOSIT_WALLET_ADDRESS_PARAM) ?: return false
|
||||
|
||||
Timber.d("MoonPay Sell: $amount $currency to $destinationAddress")
|
||||
store.dispatch(
|
||||
store.dispatchWithMain(
|
||||
WalletAction.TradeCryptoAction.SendCrypto(
|
||||
currencyId = currency,
|
||||
amount = amount,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.features.intentHandler.handlers
|
||||
|
||||
import android.content.Intent
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.extensions.removePrefixOrNull
|
||||
import com.tangem.tap.domain.walletconnect.WalletConnectManager
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
|
||||
|
|
@ -25,7 +26,7 @@ class WalletConnectLinkIntentHandler : IntentHandler {
|
|||
return if (wcUri == null) {
|
||||
false
|
||||
} else {
|
||||
store.dispatch(WalletConnectAction.HandleDeepLink(wcUri))
|
||||
store.dispatchWithMain(WalletConnectAction.HandleDeepLink(wcUri))
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ import com.tangem.domain.common.util.cardTypesResolver
|
|||
import com.tangem.domain.common.util.twinsIsTwinned
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.userwallets.UserWalletBuilder
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.onUserWalletSelected
|
||||
import com.tangem.tap.common.extensions.removeContext
|
||||
import com.tangem.tap.common.extensions.setContext
|
||||
import com.tangem.tap.domain.model.builders.UserWalletBuilder
|
||||
import com.tangem.tap.features.saveWallet.redux.SaveWalletAction
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.tangem.common.CompletionResult
|
|||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.common.extensions.makePrimaryWalletManager
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
|
|
@ -14,7 +15,6 @@ import com.tangem.tap.common.redux.AppDialog
|
|||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.extensions.makePrimaryWalletManager
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
|
||||
import com.tangem.tap.features.onboarding.OnboardingDialog
|
||||
|
|
|
|||
|
|
@ -6,9 +6,11 @@ import com.tangem.common.extensions.guard
|
|||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.common.extensions.makePrimaryWalletManager
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.common.util.twinsIsTwinned
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.userwallets.UserWalletIdBuilder
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Onboarding
|
||||
|
|
@ -18,8 +20,6 @@ import com.tangem.tap.common.redux.AppDialog
|
|||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.extensions.makePrimaryWalletManager
|
||||
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
|
||||
import com.tangem.tap.domain.twins.TwinCardsManager
|
||||
import com.tangem.tap.domain.userWalletList.isLockedSync
|
||||
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
|
||||
|
|
|
|||
|
|
@ -17,15 +17,12 @@ import com.tangem.core.analytics.Analytics
|
|||
import com.tangem.core.navigation.ShareElement
|
||||
import com.tangem.core.ui.fragments.setStatusBarColor
|
||||
import com.tangem.datasource.asset.AssetReader
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.common.TwinCardNumber
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.userwallets.Artwork
|
||||
import com.tangem.sdk.ui.widget.leapfrogWidget.LeapfrogWidget
|
||||
import com.tangem.tap.common.analytics.events.Onboarding
|
||||
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.show
|
||||
import com.tangem.tap.common.extensions.stripZeroPlainString
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.toggleWidget.RefreshBalanceWidget
|
||||
import com.tangem.tap.common.transitions.InternalNoteLayoutTransition
|
||||
import com.tangem.tap.domain.twins.TwinsCardWidget
|
||||
|
|
@ -35,7 +32,6 @@ import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletM
|
|||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep
|
||||
import com.tangem.tap.features.wallet.redux.Artwork
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import com.tangem.wallet.databinding.LayoutOnboardingContainerTopBinding
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import com.tangem.domain.common.extensions.withMainContext
|
|||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.userwallets.Artwork
|
||||
import com.tangem.feature.onboarding.data.model.CreateWalletResponse
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.analytics.SeedPhraseSource
|
||||
import com.tangem.operations.backup.BackupService
|
||||
|
|
@ -30,10 +31,9 @@ import com.tangem.tap.features.home.redux.HomeAction
|
|||
import com.tangem.tap.features.onboarding.OnboardingDialog
|
||||
import com.tangem.tap.features.onboarding.OnboardingHelper
|
||||
import com.tangem.tap.features.wallet.models.toCurrencies
|
||||
import com.tangem.tap.features.wallet.redux.Artwork
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Action
|
||||
import org.rekotlin.DispatchFunction
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
object OnboardingWalletMiddleware {
|
||||
|
|
@ -44,8 +44,8 @@ private val onboardingWalletMiddleware: Middleware<AppState> = { dispatch, state
|
|||
{ next ->
|
||||
{ action ->
|
||||
when (action) {
|
||||
is OnboardingWallet2Action -> handleWallet2Action(action, state)
|
||||
else -> handleWalletAction(action, state, dispatch)
|
||||
is OnboardingWallet2Action -> handleWallet2Action(action)
|
||||
else -> handleWalletAction(action)
|
||||
}
|
||||
next(action)
|
||||
}
|
||||
|
|
@ -53,7 +53,7 @@ private val onboardingWalletMiddleware: Middleware<AppState> = { dispatch, state
|
|||
}
|
||||
|
||||
@Suppress("LongMethod", "ComplexMethod")
|
||||
private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: DispatchFunction) {
|
||||
private fun handleWalletAction(action: Action) {
|
||||
if (action !is OnboardingWalletAction) return
|
||||
|
||||
val globalState = store.state.globalState
|
||||
|
|
@ -179,7 +179,7 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch:
|
|||
}
|
||||
|
||||
@Suppress("LongMethod", "ComplexMethod")
|
||||
private fun handleWallet2Action(action: OnboardingWallet2Action, state: () -> AppState?) {
|
||||
private fun handleWallet2Action(action: OnboardingWallet2Action) {
|
||||
val globalState = store.state.globalState
|
||||
val onboardingManager = globalState.onboardingState.onboardingManager
|
||||
|
||||
|
|
@ -330,7 +330,9 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction)
|
|||
is BackupAction.AddBackupCard -> {
|
||||
backupService.addBackupCard { result ->
|
||||
backupService.skipCompatibilityChecks = false
|
||||
tangemSdk.config.filter.cardIdFilter = null
|
||||
store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository).sdk
|
||||
.config.filter.cardIdFilter = null
|
||||
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
store.dispatchOnMain(BackupAction.AddBackupCard.Success)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import com.tangem.common.flatMap
|
|||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.userwallets.UserWalletBuilder
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
|
|
@ -18,10 +19,10 @@ import com.tangem.tap.common.extensions.dispatchOnMain
|
|||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.model.builders.UserWalletBuilder
|
||||
import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation
|
||||
import com.tangem.tap.domain.userWalletList.isLockable
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Middleware
|
||||
import timber.log.Timber
|
||||
|
|
@ -110,9 +111,10 @@ internal class SaveWalletMiddleware {
|
|||
// Enable saving access codes only if this is the first time user save the wallet
|
||||
if (isFirstSavedWallet) {
|
||||
preferencesStorage.shouldSaveAccessCodes = true
|
||||
tangemSdkManager.setAccessCodeRequestPolicy(
|
||||
useBiometricsForAccessCode = userWallet.hasAccessCode,
|
||||
)
|
||||
store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository)
|
||||
.setAccessCodeRequestPolicy(
|
||||
isBiometricsRequestPolicy = userWallet.hasAccessCode,
|
||||
)
|
||||
}
|
||||
|
||||
val savedUserWallet = userWalletsListManager.selectedUserWalletSync.guard {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.tangem.Message
|
|||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.tap.common.analytics.events.Token.Send.AddressEntered
|
||||
import com.tangem.tap.common.redux.StateDialog
|
||||
|
|
@ -114,7 +115,7 @@ sealed class FeeAction : SendScreenAction {
|
|||
|
||||
object RequestFee : FeeAction()
|
||||
sealed class FeeCalculation : FeeAction() {
|
||||
data class SetFeeResult(val fee: List<Amount>) : FeeCalculation()
|
||||
data class SetFeeResult(val fee: TransactionFee) : FeeCalculation()
|
||||
object ClearResult : FeeCalculation()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ class AmountMiddleware {
|
|||
}
|
||||
|
||||
val amountToSend = Amount(typedAmount, sendState.getTotalAmountToSend(inputCrypto))
|
||||
val transactionErrors = walletManager.validateTransaction(amountToSend, sendState.feeState.currentFee)
|
||||
val transactionErrors = walletManager.validateTransaction(amountToSend, sendState.feeState.currentFee?.amount)
|
||||
val amountFieldErrors = filterErrorsForAmountField(transactionErrors)
|
||||
if (amountFieldErrors.isEmpty()) {
|
||||
dispatch(AmountAction.SetAmountError(null))
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.tap.features.send.redux.middlewares
|
|||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.BlockchainSdkError
|
||||
import com.tangem.blockchain.common.TransactionSender
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
|
|
@ -53,15 +54,18 @@ class RequestFeeMiddleware {
|
|||
val result = feeResult.data
|
||||
// val result = FeeMock.getFee(walletManager.wallet.blockchain)
|
||||
dispatch(FeeAction.FeeCalculation.SetFeeResult(result))
|
||||
if (result.size == 1) {
|
||||
val fee = result[0].value ?: BigDecimal.ZERO
|
||||
if (fee.isZero()) {
|
||||
dispatch(FeeAction.ChangeLayoutVisibility(main = false))
|
||||
} else {
|
||||
dispatch(FeeAction.ChangeLayoutVisibility(main = true, chipGroup = false))
|
||||
when (result) {
|
||||
is TransactionFee.Single -> {
|
||||
val fee = result.normal.amount.value ?: BigDecimal.ZERO
|
||||
if (fee.isZero()) {
|
||||
dispatch(FeeAction.ChangeLayoutVisibility(main = false))
|
||||
} else {
|
||||
dispatch(FeeAction.ChangeLayoutVisibility(main = true, chipGroup = false))
|
||||
}
|
||||
}
|
||||
is TransactionFee.Choosable -> {
|
||||
dispatch(FeeAction.ChangeLayoutVisibility(main = true, chipGroup = true))
|
||||
}
|
||||
} else {
|
||||
dispatch(FeeAction.ChangeLayoutVisibility(main = true, chipGroup = true))
|
||||
}
|
||||
}
|
||||
is Result.Failure -> {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue