Updated on 2026-08-14
This commit is contained in:
commit
c2cd7e6b4c
675 changed files with 9577 additions and 4375 deletions
|
|
@ -215,6 +215,7 @@ dependencies {
|
|||
implementation(projects.data.walletManager)
|
||||
implementation(projects.data.yieldSupply)
|
||||
implementation(projects.data.hotWallet)
|
||||
implementation(projects.data.news)
|
||||
|
||||
/** Features */
|
||||
implementation(projects.features.referral.impl)
|
||||
|
|
|
|||
|
|
@ -7,23 +7,91 @@ import dagger.hilt.android.testing.OnComponentReadyRunner
|
|||
import org.junit.rules.TestRule
|
||||
import org.junit.runner.Description
|
||||
import org.junit.runners.model.Statement
|
||||
import timber.log.Timber
|
||||
|
||||
class ApplicationInjectionExecutionRule : TestRule {
|
||||
class ApplicationInjectionExecutionRule(
|
||||
private val toggleStates: Map<String, Boolean>
|
||||
) : TestRule {
|
||||
|
||||
private val tangemApplication: TangemApplication
|
||||
get() = ApplicationProvider.getApplicationContext()
|
||||
|
||||
private var originalFeatureTogglesValues: Map<String, String>? = null
|
||||
|
||||
override fun apply(base: Statement, description: Description): Statement {
|
||||
return object : Statement() {
|
||||
override fun evaluate() {
|
||||
saveOriginalFeatureToggles()
|
||||
overrideFeatureToggles()
|
||||
|
||||
OnComponentReadyRunner.addListener(
|
||||
tangemApplication, ApplicationEntryPoint::class.java
|
||||
) { _: ApplicationEntryPoint ->
|
||||
tangemApplication.preInit()
|
||||
tangemApplication.init()
|
||||
}
|
||||
base.evaluate()
|
||||
|
||||
try {
|
||||
base.evaluate()
|
||||
} finally {
|
||||
restoreOriginalFeatureToggles()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun saveOriginalFeatureToggles() {
|
||||
try {
|
||||
val featureTogglesClass = Class.forName("com.tangem.core.configtoggle.FeatureToggles")
|
||||
val valuesField = featureTogglesClass.getDeclaredField("values")
|
||||
valuesField.isAccessible = true
|
||||
originalFeatureTogglesValues = valuesField.get(null) as Map<String, String>
|
||||
} catch (e: Exception) {
|
||||
Timber.e("Failed to save original toggles values: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun overrideFeatureToggles() {
|
||||
try {
|
||||
val featureTogglesClass = Class.forName("com.tangem.core.configtoggle.FeatureToggles")
|
||||
val valuesField = featureTogglesClass.getDeclaredField("values")
|
||||
valuesField.isAccessible = true
|
||||
|
||||
val originalValues = originalFeatureTogglesValues ?:
|
||||
(valuesField.get(null) as Map<String, String>)
|
||||
|
||||
val newValues = originalValues.toMutableMap()
|
||||
|
||||
toggleStates.forEach { (toggle, enabled) ->
|
||||
if (enabled) {
|
||||
newValues[toggle] = "1.0.0"
|
||||
} else {
|
||||
newValues.remove(toggle)
|
||||
}
|
||||
}
|
||||
|
||||
valuesField.set(null, newValues)
|
||||
|
||||
Timber.i("FeatureToggles.values updated: $toggleStates")
|
||||
|
||||
} catch (e: Exception) {
|
||||
Timber.e("FeatureToggles.values didn't change with error: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun restoreOriginalFeatureToggles() {
|
||||
try {
|
||||
if (originalFeatureTogglesValues != null) {
|
||||
val featureTogglesClass = Class.forName("com.tangem.core.configtoggle.FeatureToggles")
|
||||
val valuesField = featureTogglesClass.getDeclaredField("values")
|
||||
valuesField.isAccessible = true
|
||||
valuesField.set(null, originalFeatureTogglesValues)
|
||||
Timber.i("FeatureToggles.values restored")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e("FeatureToggles.values didn't restored with error: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,8 +16,6 @@ import com.tangem.common.allure.FailedStepScreenshotInterceptor
|
|||
import com.tangem.common.constants.TestConstants.ALLURE_LABEL_NAME
|
||||
import com.tangem.common.constants.TestConstants.ALLURE_LABEL_VALUE
|
||||
import com.tangem.common.rules.ApiEnvironmentRule
|
||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import com.tangem.core.configtoggle.feature.MutableFeatureTogglesManager
|
||||
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
|
|
@ -53,9 +51,6 @@ abstract class BaseTestCase : TestCase(
|
|||
@Inject
|
||||
lateinit var appPreferencesStore: AppPreferencesStore
|
||||
|
||||
@Inject
|
||||
lateinit var featureTogglesManager: FeatureTogglesManager
|
||||
|
||||
@Inject
|
||||
lateinit var promoRepository: PromoRepository
|
||||
|
||||
|
|
@ -75,7 +70,7 @@ abstract class BaseTestCase : TestCase(
|
|||
@JvmField
|
||||
val ruleChain: TestRule = RuleChain
|
||||
.outerRule(hiltRule)
|
||||
.around(ApplicationInjectionExecutionRule())
|
||||
.around(applicationInjectionRule())
|
||||
.around(permissionRule)
|
||||
.around(apiEnvironmentRule)
|
||||
.around(composeTestRule)
|
||||
|
|
@ -110,7 +105,6 @@ abstract class BaseTestCase : TestCase(
|
|||
apiEnvironmentRule.setup(apiConfigsManager)
|
||||
ActivityScenario.launch(MainActivity::class.java)
|
||||
Intents.init()
|
||||
setFeatureToggles()
|
||||
additionalBeforeSection()
|
||||
}.after {
|
||||
additionalAfterSection()
|
||||
|
|
@ -141,14 +135,15 @@ abstract class BaseTestCase : TestCase(
|
|||
|
||||
fun waitForIdle() = composeTestRule.waitForIdle()
|
||||
|
||||
private fun setFeatureToggles() {
|
||||
runBlocking {
|
||||
with(featureTogglesManager as MutableFeatureTogglesManager) {
|
||||
changeToggle("NEW_TOKEN_RECEIVE_ENABLED", true)
|
||||
changeToggle("WALLET_BALANCE_FETCHER_ENABLED", true)
|
||||
changeToggle("SWAP_REDESIGN_ENABLED", true)
|
||||
changeToggle("NEW_ONRAMP_MAIN_ENABLED", true)
|
||||
}
|
||||
}
|
||||
private fun applicationInjectionRule(): ApplicationInjectionExecutionRule {
|
||||
return ApplicationInjectionExecutionRule(
|
||||
toggleStates = mapOf(
|
||||
"NEW_TOKEN_RECEIVE_ENABLED" to true,
|
||||
"WALLET_BALANCE_FETCHER_ENABLED" to true,
|
||||
"SWAP_REDESIGN_ENABLED" to true,
|
||||
"NEW_ONRAMP_MAIN_ENABLED" to true,
|
||||
"HOT_WALLET_ENABLED" to true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -26,8 +26,11 @@ fun BaseTestCase.scanCard(
|
|||
step("Click on 'Accept' button") {
|
||||
onDisclaimerScreen { acceptButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click on 'Scan' button") {
|
||||
onStoriesScreen { scanButton.clickWithAssertion() }
|
||||
step("Click on 'Get started' button") {
|
||||
onStoriesScreen { getStartedButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click on 'Scan card or ring' button") {
|
||||
onCreateWalletStartScreen { scanCardOrRingButton.clickWithAssertion() }
|
||||
}
|
||||
if (alreadyActivatedDialogIsShown) {
|
||||
step("Click on 'This is my wallet' button") {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
import com.tangem.features.onboarding.v2.impl.R as OnboardingImplR
|
||||
|
||||
class CreateWalletStartPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<CreateWalletStartPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val scanCardOrRingButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(OnboardingImplR.string.welcome_unlock_card))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onCreateWalletStartScreen(function: CreateWalletStartPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -42,6 +42,7 @@ class DetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
|||
hasTestTag(DetailsScreenTestTags.SCREEN_ITEM)
|
||||
hasText(getResourceString(R.string.app_settings_title))
|
||||
}
|
||||
|
||||
val contactSupportButton: KNode = child {
|
||||
hasTestTag(DetailsScreenTestTags.SCREEN_ITEM)
|
||||
hasText(getResourceString(R.string.common_contact_support))
|
||||
|
|
@ -50,6 +51,11 @@ class DetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
|||
hasTestTag(DetailsScreenTestTags.SCREEN_ITEM)
|
||||
hasText(getResourceString(R.string.disclaimer_title))
|
||||
}
|
||||
|
||||
val versionName: KNode = child {
|
||||
hasTestTag(DetailsScreenTestTags.VERSION_NAME)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onDetailsScreen(function: DetailsPageObject.() -> Unit) =
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onCompose
|
|||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
import com.tangem.features.send.v2.impl.R as SendR
|
||||
import androidx.compose.ui.test.hasText as withText
|
||||
|
||||
class SendPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<SendPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
|
@ -38,6 +39,11 @@ class SendPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
|||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val amountErrorText: KNode = child {
|
||||
hasTestTag(SendScreenTestTags.AMOUNT_ERROR_TEXT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val equivalentInputAmount: KNode = child {
|
||||
hasTestTag(SendScreenTestTags.EQUIVALENT_INPUT_AMOUNT)
|
||||
useUnmergedTree = true
|
||||
|
|
@ -69,8 +75,8 @@ class SendPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
|||
}
|
||||
|
||||
val nextButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(SendR.string.common_next))
|
||||
hasTestTag(BaseButtonTestTags.BUTTON)
|
||||
hasAnyDescendant(withText(getResourceString(SendR.string.common_next)))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,20 +2,20 @@ package com.tangem.screens
|
|||
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.core.ui.test.StoriesScreenTestTags
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import com.tangem.features.onboarding.v2.impl.R
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
|
||||
class StoriesPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<StoriesPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val scanButton: KNode = child {
|
||||
hasTestTag(StoriesScreenTestTags.SCAN_BUTTON)
|
||||
}
|
||||
|
||||
val orderButton: KNode = child {
|
||||
hasTestTag(StoriesScreenTestTags.ORDER_BUTTON)
|
||||
val getStartedButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.common_get_started))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,7 @@ import com.tangem.common.BaseTestCase
|
|||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.screens.onDetailsScreen
|
||||
import com.tangem.screens.onReferralProgramScreen
|
||||
import com.tangem.screens.onTopBar
|
||||
import com.tangem.screens.onWalletSettingsScreen
|
||||
import com.tangem.screens.*
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
|
|
@ -31,9 +28,6 @@ class DetailsTest : BaseTestCase() {
|
|||
step("Assert 'Wallet connect' button is visible") {
|
||||
walletConnectButton.assertIsDisplayed()
|
||||
}
|
||||
step("Assert 'Scan card' button is visible") {
|
||||
scanCardButton.assertIsDisplayed()
|
||||
}
|
||||
step("Assert 'Buy Tangem card' button is visible") {
|
||||
buyTangemButton.assertIsDisplayed()
|
||||
}
|
||||
|
|
@ -131,9 +125,6 @@ class DetailsTest : BaseTestCase() {
|
|||
step("Assert 'Wallet connect' button does not exist") {
|
||||
walletConnectButton.assertIsNotDisplayed()
|
||||
}
|
||||
step("Assert 'Scan card' button is visible") {
|
||||
scanCardButton.assertIsDisplayed()
|
||||
}
|
||||
step("Assert 'Buy Tangem card' button is visible") {
|
||||
buyTangemButton.assertIsDisplayed()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,8 +139,11 @@ class FeedbackTest : BaseTestCase() {
|
|||
step("Set scanning error") {
|
||||
MockProvider.setEmulateError(TangemSdkError.TagLost())
|
||||
}
|
||||
step("Click on 'Scan' button") {
|
||||
onStoriesScreen { scanButton.performClick() }
|
||||
step("Click on 'Get started' button") {
|
||||
onStoriesScreen { getStartedButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click on 'Scan card or ring' button") {
|
||||
onCreateWalletStartScreen { scanCardOrRingButton.clickWithAssertion() }
|
||||
}
|
||||
step("Force show 'Scan warning' dialog"){
|
||||
runOnUiThread {
|
||||
|
|
@ -178,8 +181,11 @@ class FeedbackTest : BaseTestCase() {
|
|||
step("Click on 'Accept' button") {
|
||||
onDisclaimerScreen { acceptButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click on 'Scan' button") {
|
||||
onStoriesScreen { scanButton.clickWithAssertion() }
|
||||
step("Click on 'Get started' button") {
|
||||
onStoriesScreen { getStartedButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click on 'Scan card or ring' button") {
|
||||
onCreateWalletStartScreen { scanCardOrRingButton.clickWithAssertion() }
|
||||
}
|
||||
step("Check 'Already used Wallet' dialog") {
|
||||
checkAlreadyUsedWalletDialog()
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.screens.onDisclaimerScreen
|
||||
import com.tangem.screens.onMainScreen
|
||||
import com.tangem.screens.onStoriesScreen
|
||||
import com.tangem.tap.domain.sdk.mocks.MockProvider
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import org.junit.Test
|
||||
|
||||
@HiltAndroidTest
|
||||
class ScanErrorTest : BaseTestCase() {
|
||||
|
||||
@Test
|
||||
fun goToMainTest() =
|
||||
setupHooks().run {
|
||||
onDisclaimerScreen {
|
||||
step("Click on 'Accept' button") {
|
||||
acceptButton.clickWithAssertion()
|
||||
}
|
||||
}
|
||||
onStoriesScreen {
|
||||
step("Click on 'Scan' button emulating scan error") {
|
||||
MockProvider.setEmulateError()
|
||||
scanButton.clickWithAssertion()
|
||||
}
|
||||
step("Click on 'Scan' button again without emulating error") {
|
||||
MockProvider.resetEmulateError()
|
||||
scanButton.clickWithAssertion()
|
||||
}
|
||||
}
|
||||
onMainScreen {
|
||||
step("Make sure wallet screen is visible") {
|
||||
assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import android.content.Intent.ACTION_VIEW
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.screens.onDisclaimerScreen
|
||||
import com.tangem.screens.onStoriesScreen
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.github.kakaocup.kakao.intent.KIntent
|
||||
|
||||
@HiltAndroidTest
|
||||
class StoriesTest : BaseTestCase() {
|
||||
|
||||
// @Test
|
||||
fun clickOnOrderButtonTest() =
|
||||
setupHooks().run {
|
||||
val buyWalletUrl = "https://buy.tangem.com/"
|
||||
onDisclaimerScreen {
|
||||
step("Click on 'Accept' button") {
|
||||
acceptButton.clickWithAssertion()
|
||||
}
|
||||
}
|
||||
onStoriesScreen {
|
||||
step("Click on 'Order' button") {
|
||||
orderButton.clickWithAssertion()
|
||||
}
|
||||
step("Assert: browser opened") {
|
||||
val expectedIntent = KIntent {
|
||||
hasAction(ACTION_VIEW)
|
||||
hasData { toString().startsWith(buyWalletUrl) }
|
||||
}
|
||||
expectedIntent.intended()
|
||||
device.uiDevice.pressBack()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -37,8 +37,7 @@ class TermsOfServiceTest : BaseTestCase() {
|
|||
}
|
||||
step("Assert 'Stories' screen is opened") {
|
||||
onStoriesScreen {
|
||||
scanButton.assertIsDisplayed()
|
||||
orderButton.assertIsDisplayed()
|
||||
getStartedButton.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -91,8 +90,7 @@ class TermsOfServiceTest : BaseTestCase() {
|
|||
}
|
||||
step("Assert 'Stories' screen is opened") {
|
||||
onStoriesScreen {
|
||||
scanButton.assertIsDisplayed()
|
||||
orderButton.assertIsDisplayed()
|
||||
getStartedButton.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
step("Stop app") {
|
||||
|
|
@ -103,8 +101,7 @@ class TermsOfServiceTest : BaseTestCase() {
|
|||
}
|
||||
step("Assert 'Stories' screen is opened") {
|
||||
onStoriesScreen {
|
||||
scanButton.assertIsDisplayed()
|
||||
orderButton.assertIsDisplayed()
|
||||
getStartedButton.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -276,7 +276,10 @@ class RecentBlockTest : BaseTestCase() {
|
|||
}
|
||||
step("Swipe up") {
|
||||
waitForIdle()
|
||||
swipeVertical(SwipeDirection.UP, startHeightRatio = 0.6f)
|
||||
onSendAddressScreen {
|
||||
swipeVertical(SwipeDirection.UP, startHeightRatio = 0.6f)
|
||||
swipeVertical(SwipeDirection.UP, startHeightRatio = 0.6f)
|
||||
}
|
||||
}
|
||||
step("Check recent address item №7") {
|
||||
checkRecentAddressItem(address = recipientAddressBase + "f", description = recentTransactionAmount2)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,145 @@
|
|||
package com.tangem.tests.send.amountScreen
|
||||
|
||||
import android.view.KeyEvent
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.utils.setClipboardText
|
||||
import com.tangem.scenarios.*
|
||||
import com.tangem.screens.*
|
||||
import com.tangem.wallet.R
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
import org.junit.Test
|
||||
|
||||
@HiltAndroidTest
|
||||
class SendAmountScreenTest : BaseTestCase() {
|
||||
|
||||
@AllureId("4761")
|
||||
@DisplayName("Send (amount screen): validate different amounts")
|
||||
@Test
|
||||
fun validateDifferentAmountsTest() {
|
||||
val tokenName = "Ethereum"
|
||||
val manualSendAmount = "1"
|
||||
val clipboardSendAmount = "0.5"
|
||||
val invalidAmount = "2"
|
||||
val errorText = getResourceString(R.string.send_validation_amount_exceeds_balance)
|
||||
val context = device.context
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Send' screen") {
|
||||
openSendScreen(tokenName)
|
||||
}
|
||||
step("Type '$manualSendAmount' in input text field") {
|
||||
onSendScreen {
|
||||
amountInputTextField.performClick()
|
||||
amountInputTextField.performTextReplacement(manualSendAmount)
|
||||
}
|
||||
}
|
||||
step("Assert send amount = '$manualSendAmount'") {
|
||||
onSendScreen { amountInputTextField.assertTextContains(manualSendAmount, substring = true) }
|
||||
}
|
||||
step("Assert 'Next' button is enabled") {
|
||||
onSendScreen { nextButton.assertIsEnabled() }
|
||||
}
|
||||
step("Press system 'Delete' button") {
|
||||
waitForIdle()
|
||||
device.uiDevice.pressDelete()
|
||||
}
|
||||
step("Set clipboard text") {
|
||||
setClipboardText(context, clipboardSendAmount)
|
||||
}
|
||||
step("Click on input text field") {
|
||||
onSendScreen { amountInputTextField.performClick() }
|
||||
}
|
||||
step("Paste from clipboard") {
|
||||
device.uiDevice.pressKeyCode(KeyEvent.KEYCODE_V, KeyEvent.META_CTRL_ON)
|
||||
}
|
||||
step("Assert send amount = '$clipboardSendAmount'") {
|
||||
onSendScreen { amountInputTextField.assertTextContains(clipboardSendAmount, substring = true) }
|
||||
}
|
||||
step("Assert 'Next' button is enabled") {
|
||||
onSendScreen { nextButton.assertIsEnabled() }
|
||||
}
|
||||
step("Press system 'Delete' button") {
|
||||
waitForIdle()
|
||||
device.uiDevice.pressDelete()
|
||||
}
|
||||
step("Type '$invalidAmount' in input text field") {
|
||||
onSendScreen {
|
||||
amountInputTextField.performClick()
|
||||
amountInputTextField.performTextReplacement(invalidAmount)
|
||||
}
|
||||
}
|
||||
step("Assert send amount = '$invalidAmount'") {
|
||||
onSendScreen { amountInputTextField.assertTextContains(invalidAmount, substring = true) }
|
||||
}
|
||||
step("Assert amount error contains text '$errorText'") {
|
||||
onSendScreen { amountErrorText.assertTextContains(errorText) }
|
||||
}
|
||||
step("Assert 'Next' button is disabled") {
|
||||
onSendScreen { nextButton.assertIsNotEnabled() }
|
||||
}
|
||||
step("Click on 'Max' button") {
|
||||
onSendScreen { maxButton.performClick() }
|
||||
}
|
||||
step("Assert send amount = '$manualSendAmount'") {
|
||||
onSendScreen { amountInputTextField.assertTextContains(manualSendAmount, substring = true) }
|
||||
}
|
||||
step("Assert 'Next' button is enabled") {
|
||||
onSendScreen { nextButton.assertIsEnabled() }
|
||||
}
|
||||
step("Click on 'Close' button") {
|
||||
onSendScreen { closeButton.performClick() }
|
||||
}
|
||||
step("Assert 'Token Details' screen is displayed") {
|
||||
onTokenDetailsScreen { screenContainer.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("4762")
|
||||
@DisplayName("Send (amount screen): switch equivalent")
|
||||
@Test
|
||||
fun switchEquivalentTest() {
|
||||
val tokenName = "Ethereum"
|
||||
val tokenAmount = "1"
|
||||
val fiatAmount = "$2,535.63"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Send' screen") {
|
||||
openSendScreen(tokenName)
|
||||
}
|
||||
step("Type '$tokenAmount' in input text field") {
|
||||
onSendScreen {
|
||||
amountInputTextField.performClick()
|
||||
amountInputTextField.performTextReplacement(tokenAmount)
|
||||
}
|
||||
}
|
||||
step("Assert send amount = '$tokenAmount'") {
|
||||
onSendScreen { amountInputTextField.assertTextContains(tokenAmount, substring = true) }
|
||||
}
|
||||
step("Assert equivalent amount = '$fiatAmount'") {
|
||||
onSendScreen { equivalentInputAmount.assertTextContains(fiatAmount, substring = true) }
|
||||
}
|
||||
step("Click on 'Exchange' button") {
|
||||
onSendScreen { exchangeIcon.performClick() }
|
||||
}
|
||||
step("Assert send amount = '$fiatAmount'") {
|
||||
onSendScreen { amountInputTextField.assertTextContains(fiatAmount, substring = true) }
|
||||
}
|
||||
step("Assert equivalent amount = '$tokenAmount'") {
|
||||
onSendScreen { equivalentInputAmount.assertTextContains(tokenAmount, substring = true) }
|
||||
}
|
||||
step("Click on 'Exchange' button") {
|
||||
onSendScreen { exchangeIcon.performClick() }
|
||||
}
|
||||
step("Assert send amount = '$tokenAmount'") {
|
||||
onSendScreen { amountInputTextField.assertTextContains(tokenAmount, substring = true) }
|
||||
}
|
||||
step("Assert equivalent amount = '$fiatAmount'") {
|
||||
onSendScreen { equivalentInputAmount.assertTextContains(fiatAmount, substring = true) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@ class SolanaWarningsTest : BaseTestCase() {
|
|||
private val tokenName = "Solana"
|
||||
private val amountToLeaveLessThanRent = "0.0016941"
|
||||
private val amountToLeaveGreaterThanRent = "0.0000941"
|
||||
private val amountToLeaveRentOnly = "0.00168934"
|
||||
private val amountToLeaveRentOnly = "0.001689338"
|
||||
private val rentAmount = "SOL 0.00089088"
|
||||
|
||||
private val invalidAmountTitle = getResourceString(R.string.send_notification_invalid_amount_title)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
<uses-feature android:name="android.hardware.camera.autofocus" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.nfc"
|
||||
android:required="true" />
|
||||
android:required="false" />
|
||||
|
||||
<queries>
|
||||
<intent>
|
||||
|
|
|
|||
|
|
@ -367,7 +367,7 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
|
||||
val isFromPush = intent.extras?.containsKey(OPENED_FROM_GCM_PUSH) == true
|
||||
if (isFromPush) {
|
||||
analyticsEventsHandler.send(Push.PushNotificationOpened)
|
||||
analyticsEventsHandler.send(Push.PushNotificationOpened())
|
||||
}
|
||||
|
||||
handleDeepLink(intent = intent, isFromOnNewIntent = true)
|
||||
|
|
|
|||
|
|
@ -328,7 +328,7 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
|
|||
|
||||
ExceptionHandler.append(blockchainExceptionHandler)
|
||||
|
||||
if (LogConfig.network.blockchainSdkNetwork) {
|
||||
if (LogConfig.network.isBlockchainSdkNetworkLogEnabled) {
|
||||
BlockchainSdkRetrofitBuilder.interceptors = listOf(
|
||||
createNetworkLoggingInterceptor(),
|
||||
ChuckerInterceptor(this),
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@ internal class DefaultTrackingContextProxy(private val abTestsManager: ABTestsMa
|
|||
override fun setContext(scanResponse: ScanResponse) {
|
||||
val userWalletId = UserWalletIdBuilder.scanResponse(scanResponse).build()
|
||||
|
||||
Analytics.setContext(userWalletId, scanResponse)
|
||||
|
||||
abTestsManager.setUserProperties(
|
||||
userId = calculateUserIdHash(userWalletId),
|
||||
batch = scanResponse.card.batchId,
|
||||
|
|
|
|||
|
|
@ -12,12 +12,6 @@ sealed class AnalyticsParam {
|
|||
class Amount(amount: com.tangem.blockchain.common.Amount) : CurrencyType(amount.currencySymbol)
|
||||
}
|
||||
|
||||
sealed class CardBalanceState(val value: String) {
|
||||
data object Empty : CardBalanceState("Empty")
|
||||
data object Full : CardBalanceState("Full")
|
||||
companion object
|
||||
}
|
||||
|
||||
sealed class RateApp(val value: String) {
|
||||
data object Liked : RateApp("Liked")
|
||||
data object Closed : RateApp("Close")
|
||||
|
|
|
|||
|
|
@ -11,85 +11,5 @@ sealed class Onboarding(
|
|||
params: Map<String, String> = emptyMap(),
|
||||
) : AnalyticsEvent(category, event, params) {
|
||||
|
||||
class Started : Onboarding("Onboarding", "Onboarding Started")
|
||||
class Finished : Onboarding("Onboarding", "Onboarding Finished")
|
||||
|
||||
sealed class CreateWallet(
|
||||
event: String,
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : Onboarding("Onboarding / Create Wallet", event, params) {
|
||||
|
||||
class ScreenOpened : CreateWallet("Create Wallet Screen Opened")
|
||||
class ButtonCreateWallet : CreateWallet("Button - Create Wallet")
|
||||
class WalletCreatedSuccessfully(
|
||||
creationType: AnalyticsParam.WalletCreationType = AnalyticsParam.WalletCreationType.PrivateKey,
|
||||
seedPhraseLength: Int? = null,
|
||||
) : CreateWallet(
|
||||
event = "Wallet Created Successfully",
|
||||
params = buildMap {
|
||||
put(AnalyticsParam.CREATION_TYPE, creationType.value)
|
||||
|
||||
if (seedPhraseLength != null) put(AnalyticsParam.SEED_PHRASE_LENGTH, seedPhraseLength.toString())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
sealed class Backup(
|
||||
event: String,
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : Onboarding("Onboarding / Backup", event, params) {
|
||||
|
||||
class ScreenOpened : Backup("Backup Screen Opened")
|
||||
class Started : Backup("Backup Started")
|
||||
class Skipped : Backup("Backup Skipped")
|
||||
class SettingAccessCodeStarted : Backup("Setting Access Code Started")
|
||||
class AccessCodeEntered : Backup("Access Code Entered")
|
||||
class AccessCodeReEntered : Backup("Access Code Re-entered")
|
||||
|
||||
class Finished(cardsCount: Int) : Backup(
|
||||
event = "Backup Finished",
|
||||
params = mapOf("Cards count" to "$cardsCount"),
|
||||
)
|
||||
|
||||
object ResetCancelEvent : Backup(
|
||||
event = "Reset Card Notification",
|
||||
params = mapOf("Option" to "Cancel"),
|
||||
)
|
||||
|
||||
object ResetPerformEvent : Backup(
|
||||
event = "Reset Card Notification",
|
||||
params = mapOf("Option" to "Reset"),
|
||||
)
|
||||
}
|
||||
|
||||
sealed class Topup(
|
||||
event: String,
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : Onboarding("Onboarding / Top Up", event, params) {
|
||||
|
||||
class ScreenOpened : Topup("Activation Screen Opened")
|
||||
|
||||
class ButtonBuyCrypto(currency: AnalyticsParam.CurrencyType) : Topup(
|
||||
event = "Button - Buy Crypto",
|
||||
params = mapOf(AnalyticsParam.CURRENCY to currency.value),
|
||||
)
|
||||
|
||||
class ButtonShowWalletAddress : Topup("Button - Show the Wallet Address")
|
||||
}
|
||||
|
||||
sealed class Twins(
|
||||
event: String,
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : Onboarding("Onboarding / Twins", event, params) {
|
||||
|
||||
class ScreenOpened : Twins("Twinning Screen Opened")
|
||||
class SetupStarted : Twins("Twin Setup Started")
|
||||
class SetupFinished : Twins("Twin Setup Finished")
|
||||
}
|
||||
|
||||
class EnableBiometrics(state: AnalyticsParam.OnOffState) : Onboarding(
|
||||
category = "Onboarding / Biometric",
|
||||
event = "Enable Biometric",
|
||||
params = mapOf("State" to state.value),
|
||||
)
|
||||
}
|
||||
|
|
@ -8,5 +8,5 @@ internal sealed class Push(event: String) : AnalyticsEvent(
|
|||
params = emptyMap(),
|
||||
) {
|
||||
|
||||
data object PushNotificationOpened : Push(event = "Push Notification Opened")
|
||||
class PushNotificationOpened : Push(event = "Push Notification Opened")
|
||||
}
|
||||
|
|
@ -67,7 +67,7 @@ sealed class Settings(
|
|||
params = mapOf("State" to state.value),
|
||||
)
|
||||
|
||||
object ButtonEnableBiometricAuthentication : AppSettings(event = "Button - Enable Biometric Authentication")
|
||||
class ButtonEnableBiometricAuthentication : AppSettings(event = "Button - Enable Biometric Authentication")
|
||||
|
||||
class MainCurrencyChanged(currencyType: String) : AppSettings(
|
||||
event = "Main Currency Changed",
|
||||
|
|
@ -79,7 +79,7 @@ sealed class Settings(
|
|||
params = mapOf("State" to theme.value),
|
||||
)
|
||||
|
||||
object EnableBiometrics : AppSettings(event = "Notice - Enable Biometric")
|
||||
class EnableBiometrics : AppSettings(event = "Notice - Enable Biometric")
|
||||
|
||||
class HideBalanceChanged(state: AnalyticsParam.OnOffState) : AppSettings(
|
||||
event = "Hide Balance Changed",
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ sealed class SignIn(
|
|||
params: Map<String, String> = emptyMap(),
|
||||
) : AnalyticsEvent("Sign In", event, params) {
|
||||
|
||||
class ScreenOpened : SignIn(event = "Sign In Screen Opened")
|
||||
|
||||
class ButtonBiometricSignIn : SignIn(event = "Button - Biometric Sign In")
|
||||
class ButtonCardSignIn : SignIn(event = "Button - Card Sign In")
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ class AmplitudeAnalyticsHandler(
|
|||
class Builder : AnalyticsHandlerBuilder {
|
||||
override fun build(data: AnalyticsHandlerBuilder.Data): AnalyticsHandler {
|
||||
return AmplitudeAnalyticsHandler(
|
||||
client = if (data.logConfig.amplitude) {
|
||||
client = if (data.logConfig.isAmplitudeLogEnabled) {
|
||||
AmplitudeLogClient(data.jsonConverter)
|
||||
} else {
|
||||
AmplitudeClient(data.application, data.config.amplitudeApiKey)
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ class FirebaseAnalyticsHandler(
|
|||
class Builder : AnalyticsHandlerBuilder {
|
||||
override fun build(data: AnalyticsHandlerBuilder.Data): AnalyticsHandler? = when {
|
||||
!data.isDebug -> FirebaseClient()
|
||||
data.isDebug && data.logConfig.firebase -> FirebaseLogClient(data.jsonConverter)
|
||||
data.isDebug && data.logConfig.isFirebaseLogEnabled -> FirebaseLogClient(data.jsonConverter)
|
||||
else -> null
|
||||
}?.let { FirebaseAnalyticsHandler(it) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.tap.common.analytics.paramsInterceptor
|
|||
import com.tangem.core.analytics.api.ParamsInterceptor
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.event.SignIn
|
||||
import com.tangem.domain.card.analytics.IntroductionProcess
|
||||
import com.tangem.domain.card.analytics.ParamCardCurrencyConverter
|
||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||
|
|
@ -30,7 +31,11 @@ class CardContextInterceptor(
|
|||
|
||||
override fun canBeAppliedTo(event: AnalyticsEvent): Boolean {
|
||||
return when (event) {
|
||||
is IntroductionProcess.ButtonScanCard -> false
|
||||
is IntroductionProcess.ButtonScanCard,
|
||||
is IntroductionProcess.ButtonScanCardLegacy,
|
||||
is SignIn.ScreenOpened,
|
||||
is SignIn.ButtonAddWallet,
|
||||
-> false
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package com.tangem.tap.common.analytics.paramsInterceptor
|
|||
import com.tangem.core.analytics.api.ParamsInterceptor
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.event.SignIn
|
||||
import com.tangem.domain.card.analytics.IntroductionProcess
|
||||
|
||||
class HotWalletContextInterceptor(
|
||||
val parent: ParamsInterceptor? = null,
|
||||
|
|
@ -10,10 +12,22 @@ class HotWalletContextInterceptor(
|
|||
|
||||
override fun id(): String = HotWalletContextInterceptor.id()
|
||||
|
||||
override fun canBeAppliedTo(event: AnalyticsEvent): Boolean = true
|
||||
override fun canBeAppliedTo(event: AnalyticsEvent): Boolean {
|
||||
return when (event) {
|
||||
is SignIn.ScreenOpened,
|
||||
is SignIn.ButtonAddWallet,
|
||||
is SignIn.ButtonUnlockAllWithBiometric,
|
||||
is IntroductionProcess.ButtonScanCard,
|
||||
-> false
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
||||
override fun intercept(params: MutableMap<String, String>) {
|
||||
params[AnalyticsParam.PRODUCT_TYPE] = AnalyticsParam.ProductType.MobileWallet.value
|
||||
params.remove(AnalyticsParam.BATCH)
|
||||
params.remove(AnalyticsParam.FIRMWARE)
|
||||
params.remove(AnalyticsParam.CURRENCY)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -67,11 +67,13 @@ internal object AccountDomainModule {
|
|||
accountsCRUDRepository: AccountsCRUDRepository,
|
||||
mainAccountTokensMigration: MainAccountTokensMigration,
|
||||
cryptoCurrencyBalanceFetcher: CryptoCurrencyBalanceFetcher,
|
||||
singleAccountListFetcher: SingleAccountListFetcher,
|
||||
): RecoverCryptoPortfolioUseCase {
|
||||
return RecoverCryptoPortfolioUseCase(
|
||||
crudRepository = accountsCRUDRepository,
|
||||
mainAccountTokensMigration = mainAccountTokensMigration,
|
||||
cryptoCurrencyBalanceFetcher = cryptoCurrencyBalanceFetcher,
|
||||
singleAccountListFetcher = singleAccountListFetcher,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.hotwallet.GetAccessCodeSkippedUseCase
|
||||
import com.tangem.domain.hotwallet.IsHotWalletCreationSupported
|
||||
import com.tangem.domain.hotwallet.IsAccessCodeSimpleUseCase
|
||||
import com.tangem.domain.hotwallet.SetAccessCodeSkippedUseCase
|
||||
import com.tangem.domain.hotwallet.repository.HotWalletRepository
|
||||
import dagger.Module
|
||||
|
|
@ -24,4 +26,18 @@ internal object HotWalletDomainModule {
|
|||
fun provideSetAccessCodeSkippedUseCase(hotWalletRepository: HotWalletRepository): SetAccessCodeSkippedUseCase {
|
||||
return SetAccessCodeSkippedUseCase(hotWalletRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideIsAccessCodeSimpleUseCase(): IsAccessCodeSimpleUseCase {
|
||||
return IsAccessCodeSimpleUseCase()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideIsWalletCreationSupportedUseCase(
|
||||
hotWalletRepository: HotWalletRepository,
|
||||
): IsHotWalletCreationSupported {
|
||||
return IsHotWalletCreationSupported(hotWalletRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ import com.tangem.domain.managetokens.repository.ManageTokensRepository
|
|||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
||||
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
||||
import com.tangem.domain.staking.StakingIdFactory
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceFetcher
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||
|
|
@ -74,7 +74,7 @@ internal object ManageTokensDomainModule {
|
|||
derivationsRepository: DerivationsRepository,
|
||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||
multiStakingBalanceFetcher: MultiStakingBalanceFetcher,
|
||||
stakingIdFactory: StakingIdFactory,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): SaveManagedTokensUseCase {
|
||||
|
|
@ -85,7 +85,7 @@ internal object ManageTokensDomainModule {
|
|||
derivationsRepository = derivationsRepository,
|
||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||
multiStakingBalanceFetcher = multiStakingBalanceFetcher,
|
||||
stakingIdFactory = stakingIdFactory,
|
||||
parallelUpdatingScope = CoroutineScope(SupervisorJob() + dispatchers.default),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@ import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
|||
import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.staking.StakingIdFactory
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceFetcher
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.features.hotwallet.HotWalletFeatureToggles
|
||||
|
|
@ -65,20 +66,22 @@ object MarketsDomainModule {
|
|||
fun provideSaveMarketTokensUseCase(
|
||||
derivationsRepository: DerivationsRepository,
|
||||
marketsTokenRepository: MarketsTokenRepository,
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||
multiStakingBalanceFetcher: MultiStakingBalanceFetcher,
|
||||
stakingIdFactory: StakingIdFactory,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): SaveMarketTokensUseCase {
|
||||
return SaveMarketTokensUseCase(
|
||||
derivationsRepository = derivationsRepository,
|
||||
marketsTokenRepository = marketsTokenRepository,
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
currenciesRepository = currenciesRepository,
|
||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||
multiStakingBalanceFetcher = multiStakingBalanceFetcher,
|
||||
stakingIdFactory = stakingIdFactory,
|
||||
parallelUpdatingScope = CoroutineScope(SupervisorJob() + dispatchers.default),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
||||
import com.tangem.domain.account.supplier.SingleAccountListSupplier
|
||||
import com.tangem.domain.networks.single.SingleNetworkStatusSupplier
|
||||
import com.tangem.domain.nft.*
|
||||
import com.tangem.domain.nft.repository.NFTRepository
|
||||
import com.tangem.domain.nft.utils.NFTCleaner
|
||||
import com.tangem.domain.quotes.single.SingleQuoteStatusFetcher
|
||||
import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier
|
||||
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesSupplier
|
||||
|
|
@ -27,12 +27,12 @@ internal object NFTDomainModule {
|
|||
fun providesGetNFTCollectionsUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
nftRepository: NFTRepository,
|
||||
singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
|
||||
singleAccountListSupplier: SingleAccountListSupplier,
|
||||
accountsFeatureToggles: AccountsFeatureToggles,
|
||||
): GetNFTCollectionsUseCase = GetNFTCollectionsUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
nftRepository = nftRepository,
|
||||
singleAccountStatusListSupplier = singleAccountStatusListSupplier,
|
||||
singleAccountListSupplier = singleAccountListSupplier,
|
||||
accountsFeatureToggles = accountsFeatureToggles,
|
||||
)
|
||||
|
||||
|
|
@ -67,12 +67,12 @@ internal object NFTDomainModule {
|
|||
@Singleton
|
||||
fun providesGetNFTAvailableNetworksUseCase(
|
||||
nftRepository: NFTRepository,
|
||||
singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
|
||||
singleAccountListSupplier: SingleAccountListSupplier,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
): GetNFTNetworksUseCase = GetNFTNetworksUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
nftRepository = nftRepository,
|
||||
singleAccountStatusListSupplier = singleAccountStatusListSupplier,
|
||||
singleAccountListSupplier = singleAccountListSupplier,
|
||||
)
|
||||
|
||||
@Provides
|
||||
|
|
@ -126,13 +126,13 @@ internal object NFTDomainModule {
|
|||
@Singleton
|
||||
fun provideDisableWalletNFTUseCase(
|
||||
walletsRepository: WalletsRepository,
|
||||
nftRepository: NFTRepository,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
nftCleaner: NFTCleaner,
|
||||
): DisableWalletNFTUseCase {
|
||||
return DisableWalletNFTUseCase(
|
||||
walletsRepository = walletsRepository,
|
||||
nftRepository = nftRepository,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
nftCleaner = nftCleaner,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -145,13 +145,13 @@ internal object NFTDomainModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideClearNFTCacheUseCase(
|
||||
nftRepository: NFTRepository,
|
||||
nftCleaner: NFTCleaner,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
accountsFeatureToggles: AccountsFeatureToggles,
|
||||
singleAccountListSupplier: SingleAccountListSupplier,
|
||||
): ObserveAndClearNFTCacheIfNeedUseCase {
|
||||
return ObserveAndClearNFTCacheIfNeedUseCase(
|
||||
nftRepository = nftRepository,
|
||||
nftCleaner = nftCleaner,
|
||||
currenciesRepository = currenciesRepository,
|
||||
accountsFeatureToggles = accountsFeatureToggles,
|
||||
singleAccountListSupplier = singleAccountListSupplier,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.news.repository.NewsRepository
|
||||
import com.tangem.domain.news.usecase.GetNewsCategoriesUseCase
|
||||
import com.tangem.domain.news.usecase.GetNewsListBatchFlowUseCase
|
||||
import com.tangem.domain.news.usecase.ObserveNewsDetailsUseCase
|
||||
import com.tangem.domain.news.usecase.ManageTrendingNewsUseCase
|
||||
import com.tangem.domain.news.usecase.*
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -38,4 +35,10 @@ internal object NewsDomainModule {
|
|||
fun provideGetNewsListBatchFlowUseCase(repository: NewsRepository): GetNewsListBatchFlowUseCase {
|
||||
return GetNewsListBatchFlowUseCase(repository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideFetchTrendingNewsUseCase(repository: NewsRepository): FetchTrendingNewsUseCase {
|
||||
return FetchTrendingNewsUseCase(repository)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.di.domain
|
|||
|
||||
import com.tangem.domain.onramp.*
|
||||
import com.tangem.domain.onramp.repositories.*
|
||||
import com.tangem.domain.promo.PromoRepository
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -264,12 +265,14 @@ internal object OnrampDomainModule {
|
|||
onrampErrorResolver: OnrampErrorResolver,
|
||||
onrampTransactionRepository: OnrampTransactionRepository,
|
||||
settingsRepository: SettingsRepository,
|
||||
promoRepository: PromoRepository,
|
||||
): GetOnrampOffersUseCase {
|
||||
return GetOnrampOffersUseCase(
|
||||
onrampRepository = onrampRepository,
|
||||
errorResolver = onrampErrorResolver,
|
||||
onrampTransactionRepository = onrampTransactionRepository,
|
||||
settingsRepository = settingsRepository,
|
||||
promoRepository = promoRepository,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -7,8 +7,8 @@ import com.tangem.domain.staking.repositories.StakingErrorResolver
|
|||
import com.tangem.domain.staking.repositories.StakeKitRepository
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.staking.repositories.StakeKitTransactionHashRepository
|
||||
import com.tangem.domain.staking.single.SingleYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.toggles.StakingFeatureToggles
|
||||
import com.tangem.domain.staking.single.SingleStakingBalanceFetcher
|
||||
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import dagger.Module
|
||||
|
|
@ -113,11 +113,11 @@ internal object StakingDomainModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideFetchStakingYieldBalanceUseCase(
|
||||
singleYieldBalanceFetcher: SingleYieldBalanceFetcher,
|
||||
singleStakingBalanceFetcher: SingleStakingBalanceFetcher,
|
||||
stakingIdFactory: StakingIdFactory,
|
||||
): FetchStakingYieldBalanceUseCase {
|
||||
return FetchStakingYieldBalanceUseCase(
|
||||
singleYieldBalanceFetcher = singleYieldBalanceFetcher,
|
||||
singleStakingBalanceFetcher = singleStakingBalanceFetcher,
|
||||
stakingIdFactory = stakingIdFactory,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,15 +12,18 @@ import com.tangem.domain.quotes.QuotesRepository
|
|||
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
||||
import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier
|
||||
import com.tangem.domain.staking.StakingIdFactory
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceSupplier
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceFetcher
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceSupplier
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.staking.single.SingleYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.single.SingleYieldBalanceSupplier
|
||||
import com.tangem.domain.staking.single.SingleStakingBalanceFetcher
|
||||
import com.tangem.domain.staking.single.SingleStakingBalanceSupplier
|
||||
import com.tangem.domain.tokens.*
|
||||
import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations
|
||||
import com.tangem.domain.tokens.operations.CachedCurrenciesStatusesOperations
|
||||
import com.tangem.domain.tokens.repository.*
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
|
||||
import com.tangem.domain.tokens.repository.TokenReceiveWarningsViewedRepository
|
||||
import com.tangem.domain.tokens.repository.YieldSupplyWarningsViewedRepository
|
||||
import com.tangem.domain.tokens.wallet.WalletBalanceFetcher
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.tap.domain.tokens.DefaultTokensFeatureToggles
|
||||
|
|
@ -40,17 +43,19 @@ internal object TokensDomainModule {
|
|||
@Singleton
|
||||
fun provideAddCryptoCurrenciesUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
singleYieldBalanceFetcher: SingleYieldBalanceFetcher,
|
||||
singleStakingBalanceFetcher: SingleStakingBalanceFetcher,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
stakingIdFactory: StakingIdFactory,
|
||||
): AddCryptoCurrenciesUseCase {
|
||||
return AddCryptoCurrenciesUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
singleYieldBalanceFetcher = singleYieldBalanceFetcher,
|
||||
singleStakingBalanceFetcher = singleStakingBalanceFetcher,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
stakingIdFactory = stakingIdFactory,
|
||||
)
|
||||
|
|
@ -148,7 +153,7 @@ internal object TokensDomainModule {
|
|||
currenciesRepository: CurrenciesRepository,
|
||||
singleNetworkStatusFetcher: SingleNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
singleYieldBalanceFetcher: SingleYieldBalanceFetcher,
|
||||
singleStakingBalanceFetcher: SingleStakingBalanceFetcher,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
stakingIdFactory: StakingIdFactory,
|
||||
): FetchCurrencyStatusUseCase {
|
||||
|
|
@ -156,7 +161,7 @@ internal object TokensDomainModule {
|
|||
currenciesRepository = currenciesRepository,
|
||||
singleNetworkStatusFetcher = singleNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
singleYieldBalanceFetcher = singleYieldBalanceFetcher,
|
||||
singleStakingBalanceFetcher = singleStakingBalanceFetcher,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
stakingIdFactory = stakingIdFactory,
|
||||
)
|
||||
|
|
@ -339,8 +344,8 @@ internal object TokensDomainModule {
|
|||
singleNetworkStatusSupplier: SingleNetworkStatusSupplier,
|
||||
multiNetworkStatusSupplier: MultiNetworkStatusSupplier,
|
||||
singleQuoteStatusSupplier: SingleQuoteStatusSupplier,
|
||||
singleYieldBalanceSupplier: SingleYieldBalanceSupplier,
|
||||
multiYieldBalanceSupplier: MultiYieldBalanceSupplier,
|
||||
singleStakingBalanceSupplier: SingleStakingBalanceSupplier,
|
||||
multiStakingBalanceSupplier: MultiStakingBalanceSupplier,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
stakingIdFactory: StakingIdFactory,
|
||||
): BaseCurrencyStatusOperations {
|
||||
|
|
@ -350,8 +355,8 @@ internal object TokensDomainModule {
|
|||
singleNetworkStatusSupplier = singleNetworkStatusSupplier,
|
||||
multiNetworkStatusSupplier = multiNetworkStatusSupplier,
|
||||
singleQuoteStatusSupplier = singleQuoteStatusSupplier,
|
||||
singleYieldBalanceSupplier = singleYieldBalanceSupplier,
|
||||
multiYieldBalanceSupplier = multiYieldBalanceSupplier,
|
||||
singleStakingBalanceSupplier = singleStakingBalanceSupplier,
|
||||
multiStakingBalanceSupplier = multiStakingBalanceSupplier,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
stakingIdFactory = stakingIdFactory,
|
||||
)
|
||||
|
|
@ -371,7 +376,7 @@ internal object TokensDomainModule {
|
|||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||
multiStakingBalanceFetcher: MultiStakingBalanceFetcher,
|
||||
stakingIdFactory: StakingIdFactory,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): WalletBalanceFetcher {
|
||||
|
|
@ -381,7 +386,7 @@ internal object TokensDomainModule {
|
|||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||
multiStakingBalanceFetcher = multiStakingBalanceFetcher,
|
||||
stakingIdFactory = stakingIdFactory,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ internal class LegacyScanProcessor @Inject constructor(
|
|||
) {
|
||||
if (error is TangemSdkError.CardVerificationFailed) {
|
||||
analyticsEventHandler.send(
|
||||
event = OnboardingAnalyticsEvent.Onboarding.OfflineAttestationFailed(
|
||||
event = OnboardingAnalyticsEvent.Error.OfflineAttestationFailed(
|
||||
analyticsSource,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,8 +7,10 @@ import com.tangem.common.authentication.storage.AuthenticatedStorage
|
|||
import com.tangem.common.json.TangemSdkAdapter
|
||||
import com.tangem.common.services.secure.SecureStorage
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.utils.TrackingContextProxy
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.hotwallet.repository.HotWalletRepository
|
||||
import com.tangem.domain.models.scan.serialization.*
|
||||
import com.tangem.domain.visa.model.VisaActivationRemoteState
|
||||
import com.tangem.domain.visa.model.VisaCardActivationStatus
|
||||
|
|
@ -125,6 +127,9 @@ internal object UserWalletsListManagerModule {
|
|||
appPreferencesStore: AppPreferencesStore,
|
||||
hotWalletAccessCodeAttemptsRepository: HotWalletAccessCodeAttemptsRepository,
|
||||
tangemHotSdk: TangemHotSdk,
|
||||
trackingContextProxy: TrackingContextProxy,
|
||||
analyticsEventHandler: AnalyticsEventHandler,
|
||||
hotWalletRepository: HotWalletRepository,
|
||||
): UserWalletsListRepository {
|
||||
val moshi = buildMoshi()
|
||||
val secureStorage = buildSecureStorage(applicationContext = applicationContext)
|
||||
|
|
@ -172,6 +177,9 @@ internal object UserWalletsListManagerModule {
|
|||
savePersistentInformation = ProviderSuspend { true }, // Always save persistent information for now
|
||||
hotWalletAccessCodeAttemptsRepository = hotWalletAccessCodeAttemptsRepository,
|
||||
tangemHotSdk = tangemHotSdk,
|
||||
trackingContextProxy = trackingContextProxy,
|
||||
analyticsEventHandler = analyticsEventHandler,
|
||||
hotWalletRepository = hotWalletRepository,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,12 +7,16 @@ import arrow.core.raise.either
|
|||
import arrow.core.right
|
||||
import com.tangem.common.*
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.core.analytics.utils.TrackingContextProxy
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
import com.tangem.datasource.local.preferences.utils.getSyncOrDefault
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository.LockMethod
|
||||
import com.tangem.domain.common.wallets.error.*
|
||||
import com.tangem.domain.hotwallet.repository.HotWalletRepository
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.models.wallet.isLocked
|
||||
|
|
@ -50,6 +54,9 @@ internal class DefaultUserWalletsListRepository(
|
|||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val hotWalletAccessCodeAttemptsRepository: HotWalletAccessCodeAttemptsRepository,
|
||||
private val tangemHotSdk: TangemHotSdk,
|
||||
private val trackingContextProxy: TrackingContextProxy,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val hotWalletRepository: HotWalletRepository,
|
||||
) : UserWalletsListRepository {
|
||||
|
||||
override val userWallets = MutableStateFlow<List<UserWallet>?>(null)
|
||||
|
|
@ -204,7 +211,7 @@ internal class DefaultUserWalletsListRepository(
|
|||
|
||||
userWalletEncryptionKeysRepository.delete(userWalletIds)
|
||||
|
||||
removeHotWalletsFromSDK(userWalletIds)
|
||||
removeHotWalletsFromSDKAndRepos(userWalletIds)
|
||||
|
||||
userWallets.update { currentWallets ->
|
||||
val updatedWallets = currentWallets?.filter { userWalletIds.contains(it.walletId).not() }
|
||||
|
|
@ -235,6 +242,7 @@ internal class DefaultUserWalletsListRepository(
|
|||
when (unlockMethod) {
|
||||
UserWalletsListRepository.UnlockMethod.Biometric -> {
|
||||
unlockAllWallets().bind()
|
||||
trackSignInEvent(userWallet, Basic.SignedIn.SignInType.Biometric)
|
||||
select(userWalletId)
|
||||
}
|
||||
UserWalletsListRepository.UnlockMethod.AccessCode -> {
|
||||
|
|
@ -263,7 +271,10 @@ internal class DefaultUserWalletsListRepository(
|
|||
removePasswordAttempts(userWallet)
|
||||
|
||||
sensitiveInformationRepository.getAll(listOf(encryptionKey))
|
||||
.doOnSuccess { sensitiveInfo -> updateWallets { it?.updateWith(sensitiveInfo) } }
|
||||
.doOnSuccess { sensitiveInfo ->
|
||||
updateWallets { it?.updateWith(sensitiveInfo) }
|
||||
trackSignInEvent(userWallet, Basic.SignedIn.SignInType.AccessCode)
|
||||
}
|
||||
.doOnFailure { error -> raise(UnlockWalletError.UnableToUnlock.RawException(error)) }
|
||||
}
|
||||
is UserWalletsListRepository.UnlockMethod.Scan -> {
|
||||
|
|
@ -291,7 +302,10 @@ internal class DefaultUserWalletsListRepository(
|
|||
)
|
||||
|
||||
sensitiveInformationRepository.getAll(listOf(encryptionKey))
|
||||
.doOnSuccess { sensitiveInfo -> updateWallets { it?.updateWith(sensitiveInfo) } }
|
||||
.doOnSuccess { sensitiveInfo ->
|
||||
updateWallets { it?.updateWith(sensitiveInfo) }
|
||||
trackSignInEvent(userWallet, Basic.SignedIn.SignInType.Card)
|
||||
}
|
||||
.doOnFailure { error -> raise(UnlockWalletError.UnableToUnlock.RawException(error)) }
|
||||
}
|
||||
}
|
||||
|
|
@ -332,6 +346,9 @@ internal class DefaultUserWalletsListRepository(
|
|||
sensitiveInformationRepository.getAll(allKeys)
|
||||
.doOnSuccess { sensitiveInfo ->
|
||||
updateWallets { wallets -> wallets?.updateWith(sensitiveInfo) }
|
||||
selectedUserWallet.value?.let {
|
||||
trackSignInEvent(it, Basic.SignedIn.SignInType.Biometric)
|
||||
}
|
||||
}
|
||||
.doOnFailure { error -> raise(UnlockWalletError.UnableToUnlock.RawException(error)) }
|
||||
}
|
||||
|
|
@ -373,7 +390,7 @@ internal class DefaultUserWalletsListRepository(
|
|||
if (newUserWallet.walletId == oldUserWallet.walletId &&
|
||||
oldUserWallet is UserWallet.Hot && newUserWallet is UserWallet.Cold
|
||||
) {
|
||||
removeHotWalletsFromSDK(walletIds = listOf(oldUserWallet.walletId))
|
||||
removeHotWalletsFromSDKAndRepos(walletIds = listOf(oldUserWallet.walletId))
|
||||
// When upgrading from Hot to Cold, if biometric lock is available, set it
|
||||
if (hasBiometry()) {
|
||||
setLock(newUserWallet.walletId, LockMethod.Biometric, changeUnsecured = true)
|
||||
|
|
@ -384,13 +401,14 @@ internal class DefaultUserWalletsListRepository(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun removeHotWalletsFromSDK(walletIds: List<UserWalletId>) {
|
||||
private suspend fun removeHotWalletsFromSDKAndRepos(walletIds: List<UserWalletId>) {
|
||||
val hotWalletsToDelete = userWalletsSync()
|
||||
.filterIsInstance<UserWallet.Hot>()
|
||||
.filter { walletIds.contains(it.walletId) }
|
||||
|
||||
hotWalletsToDelete.forEach {
|
||||
tangemHotSdk.delete(it.hotWalletId)
|
||||
hotWalletsToDelete.forEach { wallet ->
|
||||
hotWalletRepository.setAccessCodeSkipped(wallet.walletId, false) // In case the wallet is added again
|
||||
tangemHotSdk.delete(wallet.hotWalletId)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -508,4 +526,14 @@ internal class DefaultUserWalletsListRepository(
|
|||
|
||||
return lastOrNull()
|
||||
}
|
||||
|
||||
private fun trackSignInEvent(userWallet: UserWallet, type: Basic.SignedIn.SignInType) {
|
||||
trackingContextProxy.addContext(userWallet)
|
||||
analyticsEventHandler.send(
|
||||
event = Basic.SignedIn(
|
||||
signInType = type,
|
||||
walletsCount = userWallets.value?.size ?: 0,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import com.squareup.moshi.JsonAdapter
|
|||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import com.tangem.common.authentication.storage.AuthenticatedStorage
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.services.secure.SecureStorage
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.hot.sdk.android.crypto.AESEncryptionProtocol
|
||||
|
|
@ -96,7 +97,13 @@ internal class UserWalletEncryptionKeysRepository(
|
|||
StorageKey.UserWalletEncryptionKey(userWalletId).name
|
||||
}
|
||||
|
||||
authenticatedStorage.get(keys).mapNotNull {
|
||||
val result = authenticatedStorage.get(keys)
|
||||
|
||||
if (keys.isNotEmpty() && result.isEmpty()) {
|
||||
throw TangemSdkError.KeystoreInvalidated(Exception("Keys is empty"))
|
||||
}
|
||||
|
||||
result.mapNotNull {
|
||||
it.value.decodeToKey()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ class DetailsMiddleware {
|
|||
}
|
||||
|
||||
private fun enrollBiometrics() {
|
||||
Analytics.send(Settings.AppSettings.ButtonEnableBiometricAuthentication)
|
||||
Analytics.send(Settings.AppSettings.ButtonEnableBiometricAuthentication())
|
||||
store.inject(DaggerGraphState::settingsManager).openBiometricSettings()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ internal class AppSettingsItemsAnalyticsSender @Inject constructor(
|
|||
|
||||
private fun getEvent(item: AppSettingsScreenState.Item): AnalyticsEvent? {
|
||||
return when (item.id) {
|
||||
AppSettingsItemsFactory.ID_ENROLL_BIOMETRICS_CARD -> Settings.AppSettings.EnableBiometrics
|
||||
AppSettingsItemsFactory.ID_ENROLL_BIOMETRICS_CARD -> Settings.AppSettings.EnableBiometrics()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import androidx.compose.ui.layout.ContentScale
|
|||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
|
@ -24,6 +25,9 @@ import com.tangem.tap.features.details.ui.common.DetailsMainButton
|
|||
import com.tangem.tap.features.details.ui.common.SettingsScreensScaffold
|
||||
import com.tangem.wallet.R
|
||||
|
||||
private const val CARD_PLACEHOLDER_SECONDARY_ROTATION = -15f
|
||||
private const val CARD_PLACEHOLDER_PRIMARY_ROTATION = -1f
|
||||
|
||||
@Composable
|
||||
internal fun CardSettingsScreen(state: CardSettingsScreenState, modifier: Modifier = Modifier) {
|
||||
val isCardReadingNeeded = state.cardDetails == null
|
||||
|
|
@ -42,74 +46,82 @@ internal fun CardSettingsScreen(state: CardSettingsScreenState, modifier: Modifi
|
|||
)
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
@Composable
|
||||
private fun CardSettingsReadCard(onScanCardClick: () -> Unit) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = TangemTheme.dimens.spacing40)
|
||||
.testTag(DeviceSettingsScreenTestTags.IMAGE_BLOCK),
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing80,
|
||||
end = TangemTheme.dimens.spacing80,
|
||||
top = TangemTheme.dimens.spacing70,
|
||||
)
|
||||
.rotate(-15f),
|
||||
painter = painterResource(id = R.drawable.card_placeholder_secondary),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.FillWidth,
|
||||
)
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing60,
|
||||
end = TangemTheme.dimens.spacing60,
|
||||
)
|
||||
.rotate(-1f),
|
||||
painter = painterResource(id = R.drawable.card_placeholder_black),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.FillWidth,
|
||||
)
|
||||
}
|
||||
CardPlaceholderImages()
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Column(
|
||||
ScanCardContent(onScanCardClick = onScanCardClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CardPlaceholderImages() {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = TangemTheme.dimens.spacing40)
|
||||
.testTag(DeviceSettingsScreenTestTags.IMAGE_BLOCK),
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing16,
|
||||
end = TangemTheme.dimens.spacing16,
|
||||
bottom = TangemTheme.dimens.spacing32,
|
||||
),
|
||||
) {
|
||||
Text(
|
||||
text = stringResourceSafe(id = R.string.scan_card_settings_title),
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.h3,
|
||||
)
|
||||
Spacer(modifier = Modifier.size(TangemTheme.dimens.size20))
|
||||
Text(
|
||||
text = stringResourceSafe(id = R.string.scan_card_settings_message),
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
style = TangemTheme.typography.body1,
|
||||
modifier = Modifier
|
||||
.verticalScroll(rememberScrollState())
|
||||
.weight(weight = 1f, fill = false),
|
||||
)
|
||||
Spacer(modifier = Modifier.size(TangemTheme.dimens.size32))
|
||||
DetailsMainButton(
|
||||
title = stringResourceSafe(id = R.string.scan_card_settings_button),
|
||||
onClick = onScanCardClick,
|
||||
)
|
||||
}
|
||||
start = TangemTheme.dimens.spacing80,
|
||||
end = TangemTheme.dimens.spacing80,
|
||||
top = TangemTheme.dimens.spacing70,
|
||||
)
|
||||
.rotate(CARD_PLACEHOLDER_SECONDARY_ROTATION),
|
||||
painter = painterResource(id = R.drawable.card_placeholder_secondary),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.FillWidth,
|
||||
)
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing60,
|
||||
end = TangemTheme.dimens.spacing60,
|
||||
)
|
||||
.rotate(CARD_PLACEHOLDER_PRIMARY_ROTATION),
|
||||
painter = painterResource(id = R.drawable.card_placeholder_black),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.FillWidth,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ScanCardContent(onScanCardClick: () -> Unit) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing16,
|
||||
end = TangemTheme.dimens.spacing16,
|
||||
bottom = TangemTheme.dimens.spacing32,
|
||||
),
|
||||
) {
|
||||
Text(
|
||||
text = stringResourceSafe(id = R.string.scan_card_settings_title),
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.h3,
|
||||
)
|
||||
Spacer(modifier = Modifier.size(TangemTheme.dimens.size20))
|
||||
Text(
|
||||
text = stringResourceSafe(id = R.string.scan_card_settings_message),
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
style = TangemTheme.typography.body1,
|
||||
)
|
||||
Spacer(modifier = Modifier.size(TangemTheme.dimens.size32))
|
||||
DetailsMainButton(
|
||||
title = stringResourceSafe(id = R.string.scan_card_settings_button),
|
||||
onClick = onScanCardClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
package com.tangem.tap.features.details.ui.cardsettings
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.tap.features.details.redux.SecurityOption
|
||||
import com.tangem.tap.features.details.ui.securitymode.toTitleRes
|
||||
import com.tangem.wallet.R
|
||||
|
|
@ -32,7 +30,7 @@ internal sealed class CardInfo(
|
|||
|
||||
class SignedHashes(hashes: String) : CardInfo(
|
||||
titleRes = TextReference.Res(R.string.details_row_title_signed_hashes),
|
||||
subtitle = TextReference.Res(R.string.details_row_subtitle_signed_hashes_format, hashes),
|
||||
subtitle = TextReference.Res(R.string.details_row_subtitle_signed_hashes_format, wrappedList(hashes)),
|
||||
)
|
||||
|
||||
class SecurityMode(securityOption: SecurityOption, clickable: Boolean) : CardInfo(
|
||||
|
|
@ -47,7 +45,7 @@ internal sealed class CardInfo(
|
|||
isClickable = true,
|
||||
)
|
||||
|
||||
class AccessCodeRecovery(val isEnabled: Boolean) : CardInfo(
|
||||
class AccessCodeRecovery(isEnabled: Boolean) : CardInfo(
|
||||
titleRes = TextReference.Res(R.string.card_settings_access_code_recovery_title),
|
||||
subtitle = if (isEnabled) {
|
||||
TextReference.Res(R.string.common_enabled)
|
||||
|
|
@ -62,22 +60,4 @@ internal sealed class CardInfo(
|
|||
subtitle = description,
|
||||
isClickable = true,
|
||||
)
|
||||
}
|
||||
|
||||
// TODO("Remove and use the same from coreUI")
|
||||
internal sealed interface TextReference {
|
||||
class Res(@StringRes val id: Int, val formatArgs: List<Any> = emptyList()) : TextReference {
|
||||
constructor(@StringRes id: Int, vararg formatArgs: Any) : this(id, formatArgs.toList())
|
||||
}
|
||||
|
||||
class Str(val value: String) : TextReference
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
internal fun TextReference.resolveReference(): String {
|
||||
return when (this) {
|
||||
is TextReference.Res -> stringResourceSafe(this.id, *this.formatArgs.toTypedArray())
|
||||
is TextReference.Str -> this.value
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tap.features.details.ui.common.utils
|
||||
|
||||
import com.tangem.domain.card.CardTypesResolver
|
||||
import com.tangem.tap.features.details.ui.cardsettings.TextReference
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.wallet.R
|
||||
|
||||
internal fun getResetToFactoryDescription(
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ import com.tangem.core.ui.extensions.stringResourceSafe
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.ResetCardScreenTestTags
|
||||
import com.tangem.tap.features.details.ui.cardsettings.TextReference
|
||||
import com.tangem.tap.features.details.ui.cardsettings.resolveReference
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.tap.features.details.ui.common.DetailsMainButton
|
||||
import com.tangem.tap.features.details.ui.common.SettingsScreensScaffold
|
||||
import com.tangem.wallet.R
|
||||
|
|
@ -198,7 +198,7 @@ private fun ResetButton(enabled: Boolean, onResetButtonClick: () -> Unit) {
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun CommonResetDialog(dialog: ResetCardScreenState.Dialog) {
|
||||
private fun CommonResetDialog(dialog: ResetCardDialog) {
|
||||
BasicDialog(
|
||||
title = stringResourceSafe(dialog.titleResId),
|
||||
message = stringResourceSafe(dialog.messageResId),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tap.features.details.ui.resetcard
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import com.tangem.tap.features.details.ui.cardsettings.TextReference
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.wallet.R
|
||||
|
||||
internal data class ResetCardScreenState(
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ object UnfinishedBackupFoundDialog {
|
|||
setTitle(R.string.common_warning)
|
||||
setMessage(R.string.welcome_interrupted_backup_alert_message)
|
||||
setPositiveButton(R.string.welcome_interrupted_backup_alert_resume) { _, _ ->
|
||||
Analytics.send(OnboardingEvent.Backup.ResumeInterruptedBackup)
|
||||
Analytics.send(OnboardingEvent.Backup.ResumeInterruptedBackup())
|
||||
store.dispatch(GlobalAction.HideDialog)
|
||||
store.dispatch(BackupAction.ResumeFoundUnfinishedBackup(scanResponse))
|
||||
}
|
||||
setNegativeButton(R.string.welcome_interrupted_backup_alert_discard) { _, _ ->
|
||||
Analytics.send(OnboardingEvent.Backup.CancelInterruptedBackup)
|
||||
Analytics.send(OnboardingEvent.Backup.CancelInterruptedBackup())
|
||||
store.dispatch(GlobalAction.HideDialog)
|
||||
store.dispatch(GlobalAction.ShowDialog(BackupDialog.ConfirmDiscardingBackup(scanResponse)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import com.tangem.core.navigation.finisher.AppFinisher
|
|||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||
import com.tangem.tap.common.analytics.events.SignIn
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.features.details.ui.cardsettings.TextReference
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.tap.features.welcome.component.WelcomeComponent
|
||||
import com.tangem.tap.features.welcome.redux.WelcomeAction
|
||||
import com.tangem.tap.features.welcome.redux.WelcomeState
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ internal class WelcomeMiddleware {
|
|||
.doOnSuccess { selectedUserWallet ->
|
||||
sendSignedInAnalyticsEvent(
|
||||
userWallet = selectedUserWallet,
|
||||
signInType = Basic.SignedIn.SignInType.Biometric,
|
||||
signInType = Basic.SignedInLegacy.SignInType.Biometric,
|
||||
)
|
||||
|
||||
store.dispatchNavigationAction { replaceAll(AppRoute.Wallet) }
|
||||
|
|
@ -80,7 +80,7 @@ internal class WelcomeMiddleware {
|
|||
store.dispatchWithMain(WelcomeAction.ProceedWithCard.Error(error))
|
||||
}
|
||||
.doOnSuccess {
|
||||
sendSignedInAnalyticsEvent(userWallet, signInType = Basic.SignedIn.SignInType.Card)
|
||||
sendSignedInAnalyticsEvent(userWallet, signInType = Basic.SignedInLegacy.SignInType.Card)
|
||||
|
||||
store.dispatchNavigationAction { replaceAll(AppRoute.Wallet) }
|
||||
store.dispatchWithMain(WelcomeAction.ProceedWithCard.Success)
|
||||
|
|
@ -89,9 +89,7 @@ internal class WelcomeMiddleware {
|
|||
}
|
||||
}
|
||||
|
||||
private fun sendSignedInAnalyticsEvent(userWallet: UserWallet, signInType: Basic.SignedIn.SignInType) {
|
||||
// TODO [REDACTED_TASK_KEY] [Hot Wallet] Analytics
|
||||
|
||||
private fun sendSignedInAnalyticsEvent(userWallet: UserWallet, signInType: Basic.SignedInLegacy.SignInType) {
|
||||
if (userWallet !is UserWallet.Cold) {
|
||||
return
|
||||
}
|
||||
|
|
@ -108,7 +106,7 @@ internal class WelcomeMiddleware {
|
|||
val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager)
|
||||
|
||||
Analytics.send(
|
||||
event = Basic.SignedIn(
|
||||
event = Basic.SignedInLegacy(
|
||||
currency = currency,
|
||||
batch = scanResponse.card.batchId,
|
||||
signInType = signInType,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.features.welcome.ui
|
||||
|
||||
import com.tangem.tap.features.details.ui.cardsettings.TextReference
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.tap.features.welcome.ui.model.WarningModel
|
||||
|
||||
internal data class WelcomeScreenState(
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
|||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.tap.features.details.ui.cardsettings.TextReference
|
||||
import com.tangem.tap.features.details.ui.cardsettings.resolveReference
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.tap.features.welcome.component.WelcomeComponent
|
||||
import com.tangem.tap.features.welcome.component.impl.PreviewWelcomeComponent
|
||||
import com.tangem.tap.features.welcome.ui.WelcomeScreenState
|
||||
|
|
|
|||
|
|
@ -51,7 +51,9 @@ internal class DefaultAuthProvider(
|
|||
ApiEnvironment.DEV_2,
|
||||
ApiEnvironment.DEV_3,
|
||||
-> environmentConfigStorage.getConfigSync().tangemApiKeyDev
|
||||
ApiEnvironment.STAGE -> environmentConfigStorage.getConfigSync().tangemApiKeyStage
|
||||
ApiEnvironment.STAGE_2,
|
||||
ApiEnvironment.STAGE,
|
||||
-> environmentConfigStorage.getConfigSync().tangemApiKeyStage
|
||||
ApiEnvironment.PROD -> environmentConfigStorage.getConfigSync().tangemApiKey
|
||||
} ?: error("No tangem tech api config provided")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.network.auth
|
||||
|
||||
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
|
||||
import com.tangem.domain.staking.model.ethpool.P2PStakingConfig
|
||||
import com.tangem.lib.auth.P2PEthPoolAuthProvider
|
||||
|
||||
internal class DefaultP2PEthPoolAuthProvider(
|
||||
|
|
@ -11,6 +12,6 @@ internal class DefaultP2PEthPoolAuthProvider(
|
|||
val keys = environmentConfigStorage.getConfigSync().p2pApiKey
|
||||
?: error("No P2P api keys provided")
|
||||
|
||||
return keys.mainnet
|
||||
return if (P2PStakingConfig.USE_TESTNET) keys.hoodi else keys.mainnet
|
||||
}
|
||||
}
|
||||
|
|
@ -11,8 +11,11 @@ import com.arkivanov.essenty.lifecycle.subscribe
|
|||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.entity.InitScreenLaunchMode
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.api.AnalyticsExceptionHandler
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.core.analytics.models.ExceptionAnalyticsEvent
|
||||
import com.tangem.core.analytics.utils.TrackingContextProxy
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.child
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
|
|
@ -26,6 +29,7 @@ import com.tangem.domain.common.wallets.UserWalletsListRepository
|
|||
import com.tangem.domain.models.wallet.isLocked
|
||||
import com.tangem.domain.onboarding.repository.OnboardingRepository
|
||||
import com.tangem.features.hotwallet.HotAccessCodeRequestComponent
|
||||
import com.tangem.features.hotwallet.HotWalletFeatureToggles
|
||||
import com.tangem.features.hotwallet.accesscoderequest.proxy.HotWalletPasswordRequesterProxy
|
||||
import com.tangem.features.walletconnect.components.WcRoutingComponent
|
||||
import com.tangem.hot.sdk.TangemHotSdk
|
||||
|
|
@ -63,6 +67,9 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
|||
private val userWalletsListRepository: UserWalletsListRepository,
|
||||
private val cardRepository: CardRepository,
|
||||
private val onboardingRepository: OnboardingRepository,
|
||||
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
||||
private val trackingContextProxy: TrackingContextProxy,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val analyticsExceptionHandler: AnalyticsExceptionHandler,
|
||||
) : RoutingComponent,
|
||||
AppComponentContext by context,
|
||||
|
|
@ -151,6 +158,7 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
|||
)
|
||||
}
|
||||
else -> {
|
||||
trackSignInEvent()
|
||||
AppRoute.Wallet
|
||||
}
|
||||
}.also {
|
||||
|
|
@ -235,4 +243,18 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
|||
store.dispatch(GlobalAction.ShowDialog(BackupDialog.UnfinishedBackupFound(onboardingScanResponse)))
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun trackSignInEvent() {
|
||||
if (hotWalletFeatureToggles.isHotWalletEnabled) {
|
||||
val userWallets = userWalletsListRepository.userWalletsSync()
|
||||
val selectedWallet = userWalletsListRepository.selectedUserWalletSync() ?: return
|
||||
trackingContextProxy.addContext(selectedWallet)
|
||||
analyticsEventHandler.send(
|
||||
event = Basic.SignedIn(
|
||||
signInType = Basic.SignedIn.SignInType.NoSecurity,
|
||||
walletsCount = userWallets.size,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,6 @@ object RoutingTransitionAnimationFactory {
|
|||
@Suppress("MagicNumber")
|
||||
fun create(appRoute: AppRoute): StackAnimator {
|
||||
return when (appRoute) {
|
||||
is AppRoute.Onboarding,
|
||||
is AppRoute.Welcome,
|
||||
is AppRoute.Home,
|
||||
-> fade(tween(400)).plus(scale(tween(400)))
|
||||
|
|
|
|||
|
|
@ -529,7 +529,9 @@ internal class ChildFactory @Inject constructor(
|
|||
is AppRoute.CreateMobileWallet -> {
|
||||
createComponentChild(
|
||||
context = context,
|
||||
params = Unit,
|
||||
params = CreateMobileWalletComponent.Params(
|
||||
source = route.source,
|
||||
),
|
||||
componentFactory = createMobileWalletComponentFactory,
|
||||
)
|
||||
}
|
||||
|
|
@ -565,7 +567,7 @@ internal class ChildFactory @Inject constructor(
|
|||
params = CreateWalletBackupComponent.Params(
|
||||
userWalletId = route.userWalletId,
|
||||
isUpgradeFlow = route.isUpgradeFlow,
|
||||
shouldSetAccessCode = route.setAccessCode,
|
||||
shouldSetAccessCode = route.shouldSetAccessCode,
|
||||
analyticsSource = route.analyticsSource,
|
||||
analyticsAction = route.analyticsAction,
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue