Updated on 2026-08-14
This commit is contained in:
commit
2f84def7cc
1244 changed files with 20573 additions and 7307 deletions
|
|
@ -134,7 +134,6 @@ dependencies {
|
||||||
implementation(projects.core.datasource)
|
implementation(projects.core.datasource)
|
||||||
implementation(projects.core.utils)
|
implementation(projects.core.utils)
|
||||||
implementation(projects.core.decompose)
|
implementation(projects.core.decompose)
|
||||||
implementation(projects.core.deepLinks)
|
|
||||||
implementation(projects.core.error.ext)
|
implementation(projects.core.error.ext)
|
||||||
implementation(projects.libs.crypto)
|
implementation(projects.libs.crypto)
|
||||||
implementation(projects.libs.auth)
|
implementation(projects.libs.auth)
|
||||||
|
|
@ -281,6 +280,8 @@ dependencies {
|
||||||
implementation(tangemDeps.card.android) {
|
implementation(tangemDeps.card.android) {
|
||||||
exclude(module = "joda-time")
|
exclude(module = "joda-time")
|
||||||
}
|
}
|
||||||
|
implementation(tangemDeps.hot.core)
|
||||||
|
implementation(tangemDeps.hot.android)
|
||||||
|
|
||||||
/** DI */
|
/** DI */
|
||||||
implementation(deps.hilt.android)
|
implementation(deps.hilt.android)
|
||||||
|
|
@ -300,6 +301,7 @@ dependencies {
|
||||||
implementation(deps.zxing.qrCore)
|
implementation(deps.zxing.qrCore)
|
||||||
implementation(deps.coil)
|
implementation(deps.coil)
|
||||||
implementation(deps.coil.gif)
|
implementation(deps.coil.gif)
|
||||||
|
implementation(deps.coil.svg)
|
||||||
implementation(deps.amplitude)
|
implementation(deps.amplitude)
|
||||||
implementation(deps.kotsonGson)
|
implementation(deps.kotsonGson)
|
||||||
implementation(deps.spongecastle.core)
|
implementation(deps.spongecastle.core)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
package com.tangem.common
|
package com.tangem.common
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
import androidx.compose.ui.test.junit4.createEmptyComposeRule
|
||||||
|
import androidx.compose.ui.test.onRoot
|
||||||
|
import androidx.compose.ui.test.printToLog
|
||||||
|
import androidx.test.core.app.ActivityScenario
|
||||||
import androidx.test.espresso.intent.Intents
|
import androidx.test.espresso.intent.Intents
|
||||||
import androidx.test.rule.GrantPermissionRule
|
import androidx.test.rule.GrantPermissionRule
|
||||||
import com.kaspersky.components.alluresupport.interceptors.step.ScreenshotStepInterceptor
|
import com.kaspersky.components.alluresupport.interceptors.step.ScreenshotStepInterceptor
|
||||||
|
|
@ -10,8 +13,8 @@ import com.kaspersky.components.composesupport.config.addComposeSupport
|
||||||
import com.kaspersky.kaspresso.kaspresso.Kaspresso
|
import com.kaspersky.kaspresso.kaspresso.Kaspresso
|
||||||
import com.kaspersky.kaspresso.testcases.api.testcase.TestCase
|
import com.kaspersky.kaspresso.testcases.api.testcase.TestCase
|
||||||
import com.tangem.common.allure.FailedStepScreenshotInterceptor
|
import com.tangem.common.allure.FailedStepScreenshotInterceptor
|
||||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
import com.tangem.common.rules.ApiEnvironmentRule
|
||||||
import com.tangem.sdk.api.TangemSdkManager
|
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
|
||||||
import com.tangem.tap.MainActivity
|
import com.tangem.tap.MainActivity
|
||||||
import dagger.hilt.android.testing.HiltAndroidRule
|
import dagger.hilt.android.testing.HiltAndroidRule
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
|
|
@ -35,17 +38,20 @@ abstract class BaseTestCase : TestCase(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var tangemSdkManager: TangemSdkManager
|
lateinit var apiConfigsManager: ApiConfigsManager
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var appPreferencesStore: AppPreferencesStore
|
|
||||||
|
|
||||||
private val hiltRule = HiltAndroidRule(this)
|
private val hiltRule = HiltAndroidRule(this)
|
||||||
private val permissionRule = GrantPermissionRule.grant(
|
private val apiEnvironmentRule = ApiEnvironmentRule()
|
||||||
|
private val permissionRule = GrantPermissionRule.grant(
|
||||||
Manifest.permission.POST_NOTIFICATIONS,
|
Manifest.permission.POST_NOTIFICATIONS,
|
||||||
Manifest.permission.CAMERA,
|
Manifest.permission.CAMERA,
|
||||||
)
|
)
|
||||||
val composeTestRule = createAndroidComposeRule<MainActivity>()
|
|
||||||
|
/**
|
||||||
|
* It is important to use `ComposeRule` without specifying an activity to ensure that the initialization order of
|
||||||
|
* all test rules is fully controlled.
|
||||||
|
*/
|
||||||
|
val composeTestRule = createEmptyComposeRule()
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
@JvmField
|
@JvmField
|
||||||
|
|
@ -53,13 +59,22 @@ abstract class BaseTestCase : TestCase(
|
||||||
.outerRule(hiltRule)
|
.outerRule(hiltRule)
|
||||||
.around(ApplicationInjectionExecutionRule())
|
.around(ApplicationInjectionExecutionRule())
|
||||||
.around(permissionRule)
|
.around(permissionRule)
|
||||||
|
.around(apiEnvironmentRule)
|
||||||
.around(composeTestRule)
|
.around(composeTestRule)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialization order is important:
|
||||||
|
* – DI dependencies must be injected first,
|
||||||
|
* – then the API environment should be set up,
|
||||||
|
* – and only after that the activity should be launched.
|
||||||
|
*/
|
||||||
protected fun setupHooks(
|
protected fun setupHooks(
|
||||||
additionalBeforeSection: () -> Unit = {},
|
additionalBeforeSection: () -> Unit = {},
|
||||||
additionalAfterSection: () -> Unit = {},
|
additionalAfterSection: () -> Unit = {},
|
||||||
) = before {
|
) = before {
|
||||||
hiltRule.inject()
|
hiltRule.inject()
|
||||||
|
apiEnvironmentRule.setup(apiConfigsManager)
|
||||||
|
ActivityScenario.launch(MainActivity::class.java)
|
||||||
Intents.init()
|
Intents.init()
|
||||||
additionalBeforeSection()
|
additionalBeforeSection()
|
||||||
}.after {
|
}.after {
|
||||||
|
|
@ -67,4 +82,21 @@ abstract class BaseTestCase : TestCase(
|
||||||
Intents.release()
|
Intents.release()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the Compose semantics tree to logcat for debugging UI tests.
|
||||||
|
*
|
||||||
|
* @param useUnmergedTree When true, shows unmerged tree with all individual nodes.
|
||||||
|
* Use for accessing inner elements of compound components.
|
||||||
|
* Default: false (merged tree - accessibility view).
|
||||||
|
* @param tag Log tag for filtering in logcat. Default: "SEMANTIC_TREE".
|
||||||
|
* @param maxDepth Maximum nesting level to print. Use to avoid log overflow.
|
||||||
|
* Default: Int.MAX_VALUE (unlimited depth).
|
||||||
|
*/
|
||||||
|
fun printSemanticTree(
|
||||||
|
useUnmergedTree: Boolean = false,
|
||||||
|
tag: String = "SEMANTIC_TREE",
|
||||||
|
maxDepth: Int = Int.MAX_VALUE)
|
||||||
|
{
|
||||||
|
composeTestRule.onRoot(useUnmergedTree = useUnmergedTree).printToLog(tag, maxDepth)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.tangem.common.annotations
|
||||||
|
|
||||||
|
import com.tangem.datasource.api.common.config.ApiEnvironment
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotation to specify the API environment for a class or function.
|
||||||
|
*
|
||||||
|
* @property environment the API environment to be used (defaults to [ApiEnvironment.MOCK])
|
||||||
|
*/
|
||||||
|
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
annotation class ApiEnv(
|
||||||
|
val environment: ApiEnvironment = ApiEnvironment.MOCK,
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.tangem.common.extensions
|
||||||
|
|
||||||
|
import androidx.compose.ui.test.SemanticsMatcher
|
||||||
|
import com.tangem.core.ui.utils.LazyListItemPositionSemantics
|
||||||
|
import io.github.kakaocup.compose.node.builder.ViewBuilder
|
||||||
|
|
||||||
|
fun ViewBuilder.hasLazyListItemPosition(position: Int) = apply {
|
||||||
|
addSemanticsMatcher(SemanticsMatcher.expectValue(LazyListItemPositionSemantics, position))
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
package com.tangem.common.rules
|
||||||
|
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import com.tangem.common.annotations.ApiEnv
|
||||||
|
import com.tangem.datasource.api.common.config.ApiEnvironment
|
||||||
|
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
|
||||||
|
import com.tangem.datasource.api.common.config.managers.MutableApiConfigsManager
|
||||||
|
import com.tangem.wallet.test.BuildConfig
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.junit.rules.TestRule
|
||||||
|
import org.junit.runner.Description
|
||||||
|
import org.junit.runners.model.Statement
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A JUnit rule that sets up the API environment for tests based on annotations or instrumentation arguments.
|
||||||
|
*
|
||||||
|
* This rule allows tests to specify which API environment to use either through an annotation on the test method/class
|
||||||
|
* or via an instrumentation argument.
|
||||||
|
*
|
||||||
|
* This rule only finds and stores the required API environment. The actual environment setup is performed
|
||||||
|
* by calling the [setup] method with an appropriate [ApiConfigsManager] instance.
|
||||||
|
*/
|
||||||
|
class ApiEnvironmentRule : TestRule {
|
||||||
|
|
||||||
|
private var targetEnvironment: ApiEnvironment? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the API environment based on the provided [ApiConfigsManager].
|
||||||
|
* This method is typically called in the test setup phase to ensure the correct API environment is configured.
|
||||||
|
*
|
||||||
|
* @param apiConfigsManager the manager responsible for API configurations
|
||||||
|
*/
|
||||||
|
fun setup(apiConfigsManager: ApiConfigsManager) {
|
||||||
|
val mutableManager = requireNotNull(apiConfigsManager as? MutableApiConfigsManager) {
|
||||||
|
"MutableApiConfigsManager isn't available in build type ${BuildConfig.BUILD_TYPE}."
|
||||||
|
}
|
||||||
|
|
||||||
|
mutableManager.setupEnvironment()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun apply(base: Statement, description: Description): Statement {
|
||||||
|
return object : Statement() {
|
||||||
|
override fun evaluate() {
|
||||||
|
targetEnvironment = determineEnvironment(description)
|
||||||
|
|
||||||
|
base.evaluate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun determineEnvironment(description: Description): ApiEnvironment {
|
||||||
|
val instrumentationArgs = InstrumentationRegistry.getArguments()
|
||||||
|
val envArg = instrumentationArgs.getString(ENV_ARGUMENT)
|
||||||
|
|
||||||
|
if (!envArg.isNullOrEmpty()) return ApiEnvironment.valueOf(envArg.uppercase())
|
||||||
|
|
||||||
|
val methodAnnotation = description.getAnnotation(ApiEnv::class.java)
|
||||||
|
if (methodAnnotation != null) return methodAnnotation.environment
|
||||||
|
|
||||||
|
val classAnnotation = description.testClass.getAnnotation(ApiEnv::class.java)
|
||||||
|
if (classAnnotation != null) return classAnnotation.environment
|
||||||
|
|
||||||
|
return ApiEnvironment.MOCK
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MutableApiConfigsManager.setupEnvironment() {
|
||||||
|
val environment = requireNotNull(targetEnvironment) { "Target environment is null" }
|
||||||
|
|
||||||
|
runBlocking { changeEnvironment(environment) }
|
||||||
|
|
||||||
|
Timber.i("API environment set to: ${environment.name}")
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val ENV_ARGUMENT = "testEnvironment"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.tangem.common.utils
|
||||||
|
|
||||||
|
import androidx.compose.ui.semantics.SemanticsNode
|
||||||
|
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||||
|
import io.github.kakaocup.compose.node.element.lazylist.KLazyListItemNode
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an item node in a LazyList for Compose UI testing.
|
||||||
|
* Allows test actions (clicks, scrolls) and assertions on individual list items.
|
||||||
|
*/
|
||||||
|
class LazyListItemNode(
|
||||||
|
semanticsNode: SemanticsNode,
|
||||||
|
semanticsProvider: SemanticsNodeInteractionsProvider,
|
||||||
|
) : KLazyListItemNode<LazyListItemNode>(semanticsNode, semanticsProvider)
|
||||||
|
|
@ -5,10 +5,7 @@ import com.kaspersky.kaspresso.testcases.api.scenario.Scenario
|
||||||
import com.kaspersky.kaspresso.testcases.core.testcontext.TestContext
|
import com.kaspersky.kaspresso.testcases.core.testcontext.TestContext
|
||||||
import com.tangem.common.extensions.clickWithAssertion
|
import com.tangem.common.extensions.clickWithAssertion
|
||||||
import com.tangem.domain.models.scan.ProductType
|
import com.tangem.domain.models.scan.ProductType
|
||||||
import com.tangem.screens.DisclaimerTestScreen
|
import com.tangem.screens.*
|
||||||
import com.tangem.screens.MainTestScreen
|
|
||||||
import com.tangem.screens.StoriesTestScreen
|
|
||||||
import com.tangem.screens.TestTopBar
|
|
||||||
import com.tangem.tap.domain.sdk.mocks.MockProvider
|
import com.tangem.tap.domain.sdk.mocks.MockProvider
|
||||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||||
|
|
||||||
|
|
@ -20,24 +17,24 @@ class OpenMainScreenScenario(
|
||||||
if (productType != null) {
|
if (productType != null) {
|
||||||
MockProvider.setMocks(productType)
|
MockProvider.setMocks(productType)
|
||||||
}
|
}
|
||||||
ComposeScreen.onComposeScreen<DisclaimerTestScreen>(testRule) {
|
ComposeScreen.onComposeScreen<DisclaimerPageObject>(testRule) {
|
||||||
step("Click on \"Accept\" button") {
|
step("Click on \"Accept\" button") {
|
||||||
acceptButton.clickWithAssertion()
|
acceptButton.clickWithAssertion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ComposeScreen.onComposeScreen<StoriesTestScreen>(testRule) {
|
ComposeScreen.onComposeScreen<StoriesPageObject>(testRule) {
|
||||||
step("Click on \"Scan\" button") {
|
step("Click on \"Scan\" button") {
|
||||||
scanButton.clickWithAssertion()
|
scanButton.clickWithAssertion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ComposeScreen.onComposeScreen<MainTestScreen>(testRule) {
|
ComposeScreen.onComposeScreen<MainScreenPageObject>(testRule) {
|
||||||
step("Make sure wallet screen is visible") {
|
step("Make sure wallet screen is visible") {
|
||||||
assertIsDisplayed()
|
assertIsDisplayed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ComposeScreen.onComposeScreen<TestTopBar>(testRule) {
|
ComposeScreen.onComposeScreen<MarketsTooltipPageObject>(testRule) {
|
||||||
step("Close Markets tooltip"){
|
step("Close Markets tooltip"){
|
||||||
performClick()
|
contentContainer.performClick()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,27 @@
|
||||||
package com.tangem.screens
|
package com.tangem.screens
|
||||||
|
|
||||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||||
import com.tangem.core.ui.test.TestTags
|
import com.tangem.common.BaseTestCase
|
||||||
|
import com.tangem.core.ui.test.DetailsScreenTestTags
|
||||||
import com.tangem.wallet.R
|
import com.tangem.wallet.R
|
||||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
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.compose.node.element.KNode
|
||||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||||
|
|
||||||
class DetailsTestScreen(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
class DetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||||
ComposeScreen<DetailsTestScreen>(
|
ComposeScreen<DetailsPageObject>(
|
||||||
semanticsProvider = semanticsProvider,
|
semanticsProvider = semanticsProvider,
|
||||||
viewBuilderAction = { hasTestTag(TestTags.DETAILS_SCREEN) }
|
viewBuilderAction = { hasTestTag(DetailsScreenTestTags.SCREEN_CONTAINER) }
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val walletConnectButton: KNode = child {
|
val walletConnectButton: KNode = child {
|
||||||
hasTestTag(TestTags.DETAILS_SCREEN_ITEM)
|
hasTestTag(DetailsScreenTestTags.SCREEN_ITEM)
|
||||||
hasText(getResourceString(R.string.wallet_connect_title))
|
hasText(getResourceString(R.string.wallet_connect_title))
|
||||||
}
|
}
|
||||||
|
|
||||||
private val walletBlock: KNode = child {
|
private val walletBlock: KNode = child {
|
||||||
hasTestTag(TestTags.DETAILS_SCREEN_ITEM)
|
hasTestTag(DetailsScreenTestTags.SCREEN_ITEM)
|
||||||
}
|
}
|
||||||
|
|
||||||
val walletNameButton: KNode = walletBlock.child {
|
val walletNameButton: KNode = walletBlock.child {
|
||||||
|
|
@ -32,20 +34,23 @@ class DetailsTestScreen(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||||
}
|
}
|
||||||
|
|
||||||
val buyTangemButton: KNode = child {
|
val buyTangemButton: KNode = child {
|
||||||
hasTestTag(TestTags.DETAILS_SCREEN_ITEM)
|
hasTestTag(DetailsScreenTestTags.SCREEN_ITEM)
|
||||||
hasText(getResourceString(R.string.details_buy_wallet))
|
hasText(getResourceString(R.string.details_buy_wallet))
|
||||||
}
|
}
|
||||||
|
|
||||||
val appSettingsButton: KNode = child {
|
val appSettingsButton: KNode = child {
|
||||||
hasTestTag(TestTags.DETAILS_SCREEN_ITEM)
|
hasTestTag(DetailsScreenTestTags.SCREEN_ITEM)
|
||||||
hasText(getResourceString(R.string.app_settings_title))
|
hasText(getResourceString(R.string.app_settings_title))
|
||||||
}
|
}
|
||||||
val contactSupportButton: KNode = child {
|
val contactSupportButton: KNode = child {
|
||||||
hasTestTag(TestTags.DETAILS_SCREEN_ITEM)
|
hasTestTag(DetailsScreenTestTags.SCREEN_ITEM)
|
||||||
hasText(getResourceString(R.string.details_row_title_contact_to_support))
|
hasText(getResourceString(R.string.details_row_title_contact_to_support))
|
||||||
}
|
}
|
||||||
val toSButton: KNode = child {
|
val toSButton: KNode = child {
|
||||||
hasTestTag(TestTags.DETAILS_SCREEN_ITEM)
|
hasTestTag(DetailsScreenTestTags.SCREEN_ITEM)
|
||||||
hasText(getResourceString(R.string.disclaimer_title))
|
hasText(getResourceString(R.string.disclaimer_title))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun BaseTestCase.onDetailsScreen(function: DetailsPageObject.() -> Unit) =
|
||||||
|
onComposeScreen(composeTestRule, function)
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.tangem.screens
|
||||||
|
|
||||||
|
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||||
|
import com.tangem.common.BaseTestCase
|
||||||
|
import com.tangem.core.ui.R
|
||||||
|
import com.tangem.core.ui.test.DialogTestTags
|
||||||
|
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 DialogPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||||
|
ComposeScreen<DialogPageObject>(semanticsProvider = semanticsProvider) {
|
||||||
|
|
||||||
|
val dialogContainer: KNode = child {
|
||||||
|
hasTestTag(DialogTestTags.DIALOG_CONTAINER)
|
||||||
|
}
|
||||||
|
|
||||||
|
val cancelButton: KNode = child {
|
||||||
|
hasTestTag(DialogTestTags.BUTTON)
|
||||||
|
hasText(getResourceString(R.string.common_cancel))
|
||||||
|
}
|
||||||
|
|
||||||
|
val hideButton: KNode = child {
|
||||||
|
hasTestTag(DialogTestTags.BUTTON)
|
||||||
|
hasText(getResourceString(R.string.token_details_hide_alert_hide))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun BaseTestCase.onDialog(function: DialogPageObject.() -> Unit) =
|
||||||
|
onComposeScreen(composeTestRule, function)
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.tangem.screens
|
||||||
|
|
||||||
|
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||||
|
import com.tangem.common.BaseTestCase
|
||||||
|
import com.tangem.core.ui.test.DisclaimerScreenTestTags
|
||||||
|
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
|
||||||
|
|
||||||
|
class DisclaimerPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||||
|
ComposeScreen<DisclaimerPageObject>(
|
||||||
|
semanticsProvider = semanticsProvider,
|
||||||
|
viewBuilderAction = { hasTestTag(DisclaimerScreenTestTags.SCREEN_CONTAINER) }
|
||||||
|
) {
|
||||||
|
|
||||||
|
val acceptButton: KNode = child {
|
||||||
|
hasTestTag(DisclaimerScreenTestTags.ACCEPT_BUTTON)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun BaseTestCase.onDisclaimerScreen(function: DisclaimerPageObject.() -> Unit) =
|
||||||
|
onComposeScreen(composeTestRule, function)
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package com.tangem.screens
|
|
||||||
|
|
||||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
|
||||||
import com.tangem.core.ui.test.TestTags
|
|
||||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
|
||||||
import io.github.kakaocup.compose.node.element.KNode
|
|
||||||
|
|
||||||
class DisclaimerTestScreen(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
|
||||||
ComposeScreen<DisclaimerTestScreen>(
|
|
||||||
semanticsProvider = semanticsProvider,
|
|
||||||
viewBuilderAction = { hasTestTag(TestTags.DISCLAIMER_SCREEN_CONTAINER) }
|
|
||||||
) {
|
|
||||||
|
|
||||||
val acceptButton: KNode = child {
|
|
||||||
hasTestTag(TestTags.DISCLAIMER_SCREEN_ACCEPT_BUTTON)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
package com.tangem.screens
|
||||||
|
|
||||||
|
import androidx.compose.ui.test.ExperimentalTestApi
|
||||||
|
import androidx.compose.ui.test.SemanticsMatcher
|
||||||
|
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||||
|
import com.tangem.common.BaseTestCase
|
||||||
|
import com.tangem.common.extensions.hasLazyListItemPosition
|
||||||
|
import com.tangem.common.utils.LazyListItemNode
|
||||||
|
import com.tangem.core.ui.test.TokenElementsTestTags
|
||||||
|
import com.tangem.core.ui.test.MainScreenTestTags
|
||||||
|
import com.tangem.core.ui.utils.LazyListItemPositionSemantics
|
||||||
|
import com.tangem.feature.wallet.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.compose.node.element.lazylist.KLazyListNode
|
||||||
|
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||||
|
import androidx.compose.ui.test.hasTestTag as withTestTag
|
||||||
|
import androidx.compose.ui.test.hasText as withText
|
||||||
|
|
||||||
|
class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||||
|
ComposeScreen<MainScreenPageObject>(semanticsProvider = semanticsProvider) {
|
||||||
|
|
||||||
|
private val lazyList = KLazyListNode(
|
||||||
|
semanticsProvider = semanticsProvider,
|
||||||
|
viewBuilderAction = { hasTestTag(MainScreenTestTags.SCREEN_CONTAINER) },
|
||||||
|
itemTypeBuilder = {
|
||||||
|
itemType(::LazyListItemNode)
|
||||||
|
},
|
||||||
|
positionMatcher = { position ->
|
||||||
|
SemanticsMatcher.expectValue(
|
||||||
|
LazyListItemPositionSemantics,
|
||||||
|
position
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
val synchronizeAddressesButton: KNode = child {
|
||||||
|
hasText(getResourceString(R.string.common_generate_addresses))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find token list item with title and address
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalTestApi::class)
|
||||||
|
fun tokenWithTitleAndAddress(tokenTitle: String): KNode {
|
||||||
|
return lazyList.childWith<LazyListItemNode> {
|
||||||
|
hasTestTag(MainScreenTestTags.TOKEN_LIST_ITEM)
|
||||||
|
hasText(tokenTitle)
|
||||||
|
}.child<KNode> {
|
||||||
|
hasTestTag(TokenElementsTestTags.TOKEN_FIAT_AMOUNT)
|
||||||
|
useUnmergedTree = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find node with wallet balance using lazyList. This construction doesn't affect next step with lazyList.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalTestApi::class)
|
||||||
|
fun walletBalance(): KNode {
|
||||||
|
return lazyList.childWith<LazyListItemNode> {
|
||||||
|
hasAnyDescendant(withTestTag(MainScreenTestTags.WALLET_LIST_ITEM))
|
||||||
|
}.child<KNode> {
|
||||||
|
hasTestTag(MainScreenTestTags.WALLET_BALANCE)
|
||||||
|
useUnmergedTree = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalTestApi::class)
|
||||||
|
fun organizeTokensButton(): KNode {
|
||||||
|
return lazyList.childWith<LazyListItemNode> {
|
||||||
|
hasTestTag(MainScreenTestTags.ORGANIZE_TOKENS_BUTTON)
|
||||||
|
}.child<KNode> {
|
||||||
|
hasText(getResourceString(R.string.organize_tokens_title))
|
||||||
|
useUnmergedTree = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tokenNetworkGroupTitle(tokenNetwork: String): KNode {
|
||||||
|
return lazyList.child {
|
||||||
|
hasTestTag(MainScreenTestTags.TOKEN_LIST_ITEM)
|
||||||
|
hasAnyChild(withText(tokenNetwork))
|
||||||
|
useUnmergedTree = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalTestApi::class)
|
||||||
|
fun tokenWithTitleAndPosition(tokenTitle: String, index: Int): KNode {
|
||||||
|
return lazyList.childWith<LazyListItemNode> {
|
||||||
|
hasTestTag(MainScreenTestTags.TOKEN_LIST_ITEM)
|
||||||
|
hasText(tokenTitle)
|
||||||
|
hasLazyListItemPosition(index)
|
||||||
|
}.child<KNode> {
|
||||||
|
hasTestTag(TokenElementsTestTags.TOKEN_TITLE)
|
||||||
|
useUnmergedTree = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This assertion is required to properly verify the token's absence in the semantic tree.
|
||||||
|
* Tests will fail if assertIsNotDisplayed() or assertDoesNotExist() are used instead.
|
||||||
|
*/
|
||||||
|
fun assertTokenDoesNotExist(tokenTitle: String) {
|
||||||
|
try {
|
||||||
|
tokenWithTitleAndAddress(tokenTitle).assertExists()
|
||||||
|
throw AssertionError("Token with title '$tokenTitle' should not exist but was found")
|
||||||
|
} catch (e: AssertionError) {
|
||||||
|
if (e.message?.contains("No node found") == true) {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun BaseTestCase.onMainScreen(function: MainScreenPageObject.() -> Unit) =
|
||||||
|
onComposeScreen(composeTestRule, function)
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
package com.tangem.screens
|
|
||||||
|
|
||||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
|
||||||
import com.tangem.core.ui.test.TestTags
|
|
||||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
|
||||||
|
|
||||||
class MainTestScreen(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
|
||||||
ComposeScreen<MainTestScreen>(
|
|
||||||
semanticsProvider = semanticsProvider,
|
|
||||||
viewBuilderAction = { hasTestTag(TestTags.MAIN_SCREEN) }
|
|
||||||
)
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.tangem.screens
|
||||||
|
|
||||||
|
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||||
|
import com.tangem.common.BaseTestCase
|
||||||
|
import com.tangem.core.ui.test.MarketTooltipTestTags
|
||||||
|
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
|
||||||
|
|
||||||
|
class MarketsTooltipPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||||
|
ComposeScreen<MarketsTooltipPageObject>(semanticsProvider = semanticsProvider) {
|
||||||
|
|
||||||
|
val contentContainer: KNode = child {
|
||||||
|
hasTestTag(MarketTooltipTestTags.CONTAINER)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun BaseTestCase.onMarketsTooltipScreen(function: MarketsTooltipPageObject.() -> Unit) =
|
||||||
|
onComposeScreen(composeTestRule, function)
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
package com.tangem.screens
|
||||||
|
|
||||||
|
import androidx.compose.ui.test.SemanticsMatcher
|
||||||
|
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||||
|
import com.tangem.common.BaseTestCase
|
||||||
|
import com.tangem.common.extensions.hasLazyListItemPosition
|
||||||
|
import com.tangem.common.utils.LazyListItemNode
|
||||||
|
import com.tangem.core.ui.test.TokenElementsTestTags
|
||||||
|
import com.tangem.core.ui.test.OrganizeTokensScreenTestTags
|
||||||
|
import com.tangem.core.ui.utils.LazyListItemPositionSemantics
|
||||||
|
import com.tangem.feature.wallet.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.compose.node.element.lazylist.KLazyListNode
|
||||||
|
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||||
|
import androidx.compose.ui.test.hasText as withText
|
||||||
|
import androidx.compose.ui.test.hasTestTag as withTestTag
|
||||||
|
import androidx.compose.ui.test.hasAnySibling as withAnySibling
|
||||||
|
import androidx.compose.ui.test.hasAnyChild as withAnyChild
|
||||||
|
|
||||||
|
class OrganizeTokensPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||||
|
ComposeScreen<OrganizeTokensPageObject>(semanticsProvider = semanticsProvider) {
|
||||||
|
|
||||||
|
// region TopBar
|
||||||
|
val title: KNode = child {
|
||||||
|
hasText(getResourceString(R.string.organize_tokens_title))
|
||||||
|
}
|
||||||
|
|
||||||
|
private val topBarGroupButton: KNode = child {
|
||||||
|
hasTestTag(OrganizeTokensScreenTestTags.GROUP_BUTTON)
|
||||||
|
}
|
||||||
|
|
||||||
|
val groupButton: KNode = topBarGroupButton.child {
|
||||||
|
hasText(getResourceString(R.string.organize_tokens_group))
|
||||||
|
useUnmergedTree = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val ungroupButton: KNode = topBarGroupButton.child {
|
||||||
|
hasText(getResourceString(R.string.organize_tokens_ungroup))
|
||||||
|
useUnmergedTree = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val sortByBalanceButton: KNode = child {
|
||||||
|
hasTestTag(OrganizeTokensScreenTestTags.SORT_BY_BALANCE_BUTTON)
|
||||||
|
useUnmergedTree = true
|
||||||
|
}
|
||||||
|
// endregion TopBar
|
||||||
|
|
||||||
|
private val lazyList = KLazyListNode(
|
||||||
|
semanticsProvider = semanticsProvider,
|
||||||
|
viewBuilderAction = { hasTestTag(OrganizeTokensScreenTestTags.TOKENS_LAZY_LIST) },
|
||||||
|
itemTypeBuilder = {
|
||||||
|
itemType(::LazyListItemNode)
|
||||||
|
},
|
||||||
|
positionMatcher = { position ->
|
||||||
|
SemanticsMatcher.expectValue(
|
||||||
|
LazyListItemPositionSemantics,
|
||||||
|
position
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
val applyButton: KNode = child {
|
||||||
|
hasTestTag(OrganizeTokensScreenTestTags.APPLY_BUTTON)
|
||||||
|
useUnmergedTree = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val cancelButton: KNode = child {
|
||||||
|
hasTestTag(OrganizeTokensScreenTestTags.CANCEL_BUTTON)
|
||||||
|
useUnmergedTree = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tokenWithTitle(tokenTitle: String): KNode {
|
||||||
|
return lazyList.child {
|
||||||
|
hasTestTag(OrganizeTokensScreenTestTags.TOKEN_LIST_ITEM)
|
||||||
|
hasAnyDescendant(withText(tokenTitle))
|
||||||
|
useUnmergedTree = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tokenNetworkGroupTitle(tokenNetwork: String): KNode {
|
||||||
|
return lazyList.child {
|
||||||
|
hasTestTag(OrganizeTokensScreenTestTags.GROUP_TITLE_ITEM)
|
||||||
|
hasAnyChild(withText(tokenNetwork))
|
||||||
|
useUnmergedTree = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tokenWithTitleAndPosition(tokenTitle: String, index: Int): KNode {
|
||||||
|
return lazyList.child {
|
||||||
|
hasLazyListItemPosition(index)
|
||||||
|
hasTestTag(OrganizeTokensScreenTestTags.TOKEN_LIST_ITEM)
|
||||||
|
hasAnyDescendant(withText(tokenTitle))
|
||||||
|
useUnmergedTree = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tokenDraggableButton(tokenTitle: String): KNode {
|
||||||
|
return lazyList.child {
|
||||||
|
hasTestTag(OrganizeTokensScreenTestTags.DRAGGABLE_IMAGE)
|
||||||
|
useUnmergedTree = true
|
||||||
|
hasParent(withTestTag(TokenElementsTestTags.TOKEN_NON_FIAT_BLOCK)
|
||||||
|
.and(withAnySibling(withTestTag(TokenElementsTestTags.TOKEN_TITLE)
|
||||||
|
.and(withAnyChild(withText(tokenTitle))))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun BaseTestCase.onOrganizeTokensScreen(function: OrganizeTokensPageObject.() -> Unit) =
|
||||||
|
onComposeScreen(composeTestRule, function)
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.tangem.screens
|
||||||
|
|
||||||
|
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||||
|
import com.tangem.common.BaseTestCase
|
||||||
|
import com.tangem.core.ui.R
|
||||||
|
import com.tangem.core.ui.test.PopUpMenuTestTags
|
||||||
|
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 PopUpMenuPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||||
|
ComposeScreen<PopUpMenuPageObject>(semanticsProvider = semanticsProvider) {
|
||||||
|
|
||||||
|
val popUpContainer: KNode = child {
|
||||||
|
hasTestTag(PopUpMenuTestTags.CONTAINER)
|
||||||
|
}
|
||||||
|
|
||||||
|
val hideTokenButton: KNode = child {
|
||||||
|
hasTestTag(PopUpMenuTestTags.BUTTON)
|
||||||
|
hasText(getResourceString(R.string.token_details_hide_token))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun BaseTestCase.onPopUpMenu(function: PopUpMenuPageObject.() -> Unit) =
|
||||||
|
onComposeScreen(composeTestRule, function)
|
||||||
|
|
@ -1,25 +1,27 @@
|
||||||
package com.tangem.screens
|
package com.tangem.screens
|
||||||
|
|
||||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||||
import com.tangem.core.ui.test.TestTags
|
import com.tangem.common.BaseTestCase
|
||||||
|
import com.tangem.core.ui.test.StoriesScreenTestTags
|
||||||
import com.tangem.wallet.R
|
import com.tangem.wallet.R
|
||||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
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.compose.node.element.KNode
|
||||||
import io.github.kakaocup.kakao.common.views.KView
|
import io.github.kakaocup.kakao.common.views.KView
|
||||||
import io.github.kakaocup.kakao.text.KButton
|
import io.github.kakaocup.kakao.text.KButton
|
||||||
|
|
||||||
class StoriesTestScreen(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
class StoriesPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||||
ComposeScreen<StoriesTestScreen>(
|
ComposeScreen<StoriesPageObject>(
|
||||||
semanticsProvider = semanticsProvider,
|
semanticsProvider = semanticsProvider,
|
||||||
viewBuilderAction = { hasTestTag(TestTags.STORIES_SCREEN) }
|
viewBuilderAction = { hasTestTag(StoriesScreenTestTags.SCREEN_CONTAINER) }
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val scanButton: KNode = child {
|
val scanButton: KNode = child {
|
||||||
hasTestTag(TestTags.STORIES_SCREEN_SCAN_BUTTON)
|
hasTestTag(StoriesScreenTestTags.SCAN_BUTTON)
|
||||||
}
|
}
|
||||||
|
|
||||||
val orderButton: KNode = child {
|
val orderButton: KNode = child {
|
||||||
hasTestTag(TestTags.STORIES_SCREEN_ORDER_BUTTON)
|
hasTestTag(StoriesScreenTestTags.ORDER_BUTTON)
|
||||||
}
|
}
|
||||||
|
|
||||||
val enableNFCAlert: KView = KView {
|
val enableNFCAlert: KView = KView {
|
||||||
|
|
@ -29,4 +31,7 @@ class StoriesTestScreen(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||||
val cancelButton: KButton = KButton {
|
val cancelButton: KButton = KButton {
|
||||||
withId(android.R.id.button2)
|
withId(android.R.id.button2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun BaseTestCase.onStoriesScreen(function: StoriesPageObject.() -> Unit) =
|
||||||
|
onComposeScreen(composeTestRule, function)
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
package com.tangem.screens
|
|
||||||
|
|
||||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
|
||||||
import com.tangem.core.ui.test.TestTags
|
|
||||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
|
||||||
import io.github.kakaocup.compose.node.element.KNode
|
|
||||||
|
|
||||||
class TestTopBar(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
|
||||||
ComposeScreen<TestTopBar>(
|
|
||||||
semanticsProvider = semanticsProvider,
|
|
||||||
viewBuilderAction = { hasTestTag(TestTags.MAIN_SCREEN_TOP_BAR) }
|
|
||||||
) {
|
|
||||||
val moreButton: KNode = child {
|
|
||||||
hasTestTag(TestTags.MAIN_SCREEN_MORE_BUTTON)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.tangem.screens
|
||||||
|
|
||||||
|
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||||
|
import com.tangem.common.BaseTestCase
|
||||||
|
import com.tangem.core.ui.test.TokenDetailsScreenTestTags
|
||||||
|
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
|
||||||
|
|
||||||
|
class TokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||||
|
ComposeScreen<TokenDetailsPageObject>(semanticsProvider = semanticsProvider) {
|
||||||
|
|
||||||
|
val screenContainer: KNode = child {
|
||||||
|
hasTestTag(TokenDetailsScreenTestTags.SCREEN_CONTAINER)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun BaseTestCase.onTokenDetailsScreen(function: TokenDetailsPageObject.() -> Unit) =
|
||||||
|
onComposeScreen(composeTestRule, function)
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.tangem.screens
|
||||||
|
|
||||||
|
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||||
|
import com.tangem.common.BaseTestCase
|
||||||
|
import com.tangem.core.ui.test.TokenDetailsTopBarTestTags
|
||||||
|
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
|
||||||
|
|
||||||
|
class TokenDetailsTopBarPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||||
|
ComposeScreen<TokenDetailsTopBarPageObject>(semanticsProvider = semanticsProvider) {
|
||||||
|
|
||||||
|
val moreButton: KNode = child {
|
||||||
|
hasTestTag(TokenDetailsTopBarTestTags.MORE_BUTTON)
|
||||||
|
useUnmergedTree = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val backButton: KNode = child {
|
||||||
|
hasTestTag(TokenDetailsTopBarTestTags.BACK_BUTTON)
|
||||||
|
useUnmergedTree = true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun BaseTestCase.onTokenDetailsTopBar(function: TokenDetailsTopBarPageObject.() -> Unit) =
|
||||||
|
onComposeScreen(composeTestRule, function)
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.tangem.screens
|
||||||
|
|
||||||
|
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||||
|
import com.tangem.common.BaseTestCase
|
||||||
|
import com.tangem.core.ui.test.MainScreenTestTags
|
||||||
|
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
|
||||||
|
|
||||||
|
class TopBarPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||||
|
ComposeScreen<TopBarPageObject>(
|
||||||
|
semanticsProvider = semanticsProvider,
|
||||||
|
viewBuilderAction = { hasTestTag(MainScreenTestTags.TOP_BAR) }
|
||||||
|
) {
|
||||||
|
val moreButton: KNode = child {
|
||||||
|
hasTestTag(MainScreenTestTags.MORE_BUTTON)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun BaseTestCase.onTopBar(function: TopBarPageObject.() -> Unit) =
|
||||||
|
onComposeScreen(composeTestRule, function)
|
||||||
|
|
@ -1,19 +1,21 @@
|
||||||
package com.tangem.screens
|
package com.tangem.screens
|
||||||
|
|
||||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||||
import com.tangem.core.ui.test.TestTags
|
import com.tangem.common.BaseTestCase
|
||||||
|
import com.tangem.core.ui.test.WalletSettingsScreenTestTags
|
||||||
import com.tangem.wallet.R
|
import com.tangem.wallet.R
|
||||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
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.compose.node.element.KNode
|
||||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||||
|
|
||||||
class WalletSettingsTestScreen(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
class WalletSettingsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||||
ComposeScreen<WalletSettingsTestScreen>(
|
ComposeScreen<WalletSettingsPageObject>(
|
||||||
semanticsProvider = semanticsProvider,
|
semanticsProvider = semanticsProvider,
|
||||||
viewBuilderAction = { hasTestTag(TestTags.WALLET_SETTINGS_SCREEN) }
|
viewBuilderAction = { hasTestTag(WalletSettingsScreenTestTags.SCREEN_CONTAINER) }
|
||||||
) {
|
) {
|
||||||
private val walletSettingsItem: KNode = child {
|
private val walletSettingsItem: KNode = child {
|
||||||
hasTestTag(TestTags.WALLET_SETTINGS_SCREEN_ITEM)
|
hasTestTag(WalletSettingsScreenTestTags.SCREEN_ITEM)
|
||||||
}
|
}
|
||||||
|
|
||||||
val linkMoreCardsButton: KNode = walletSettingsItem.child {
|
val linkMoreCardsButton: KNode = walletSettingsItem.child {
|
||||||
|
|
@ -28,4 +30,7 @@ class WalletSettingsTestScreen(semanticsProvider: SemanticsNodeInteractionsProvi
|
||||||
val forgetWalletButton: KNode = walletSettingsItem.child {
|
val forgetWalletButton: KNode = walletSettingsItem.child {
|
||||||
hasText(getResourceString(R.string.settings_forget_wallet))
|
hasText(getResourceString(R.string.settings_forget_wallet))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun BaseTestCase.onWalletSettingsScreen(function: WalletSettingsPageObject.() -> Unit) =
|
||||||
|
onComposeScreen(composeTestRule, function)
|
||||||
|
|
@ -4,152 +4,151 @@ import com.tangem.common.BaseTestCase
|
||||||
import com.tangem.common.extensions.clickWithAssertion
|
import com.tangem.common.extensions.clickWithAssertion
|
||||||
import com.tangem.domain.models.scan.ProductType
|
import com.tangem.domain.models.scan.ProductType
|
||||||
import com.tangem.scenarios.OpenMainScreenScenario
|
import com.tangem.scenarios.OpenMainScreenScenario
|
||||||
import com.tangem.screens.DetailsTestScreen
|
import com.tangem.screens.onDetailsScreen
|
||||||
import com.tangem.screens.TestTopBar
|
import com.tangem.screens.onTopBar
|
||||||
import com.tangem.screens.WalletSettingsTestScreen
|
import com.tangem.screens.onWalletSettingsScreen
|
||||||
import dagger.hilt.android.testing.HiltAndroidTest
|
import dagger.hilt.android.testing.HiltAndroidTest
|
||||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
@HiltAndroidTest
|
@HiltAndroidTest
|
||||||
class DetailsScreenTest : BaseTestCase() {
|
class DetailsTest : BaseTestCase() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun walletWithoutBackupDetails() =
|
fun walletWithoutBackupDetailsTest() =
|
||||||
setupHooks().run {
|
setupHooks().run {
|
||||||
scenario(OpenMainScreenScenario(composeTestRule))
|
scenario(OpenMainScreenScenario(composeTestRule))
|
||||||
ComposeScreen.onComposeScreen<TestTopBar>(composeTestRule) {
|
onTopBar {
|
||||||
step("Open wallet details") {
|
step("Open wallet details") {
|
||||||
moreButton.clickWithAssertion()
|
moreButton.clickWithAssertion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ComposeScreen.onComposeScreen<DetailsTestScreen>(composeTestRule) {
|
onDetailsScreen {
|
||||||
step("Assert wallet connect button is visible") {
|
step("Assert 'Wallet connect' button is visible") {
|
||||||
walletConnectButton.assertIsDisplayed()
|
walletConnectButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert scan card button is visible") {
|
step("Assert 'Scan card' button is visible") {
|
||||||
scanCardButton.assertIsDisplayed()
|
scanCardButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert buy Tangem card button is visible") {
|
step("Assert 'Buy Tangem card' button is visible") {
|
||||||
buyTangemButton.assertIsDisplayed()
|
buyTangemButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert app settings button is visible") {
|
step("Assert 'App settings' button is visible") {
|
||||||
appSettingsButton.assertIsDisplayed()
|
appSettingsButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert contact support button is visible") {
|
step("Assert 'Contact support' button is visible") {
|
||||||
contactSupportButton.assertIsDisplayed()
|
contactSupportButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert terms or service button is visible") {
|
step("Assert 'Terms of service' button is visible") {
|
||||||
toSButton.assertIsDisplayed()
|
toSButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Open wallet settings screen") {
|
step("Open 'Wallet settings' screen") {
|
||||||
walletNameButton.clickWithAssertion()
|
walletNameButton.clickWithAssertion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ComposeScreen.onComposeScreen<WalletSettingsTestScreen>(composeTestRule) {
|
onWalletSettingsScreen {
|
||||||
step("Assert Link more cards button is visible") {
|
step("Assert 'Link more cards' button is visible") {
|
||||||
linkMoreCardsButton.assertIsDisplayed()
|
linkMoreCardsButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert Card Settings button is visible") {
|
step("Assert 'Card Settings' button is visible") {
|
||||||
cardSettingsButton.assertIsDisplayed()
|
cardSettingsButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert Referral program button is visible") {
|
step("Assert 'Referral program' button is visible") {
|
||||||
referralProgramButton.assertIsDisplayed()
|
referralProgramButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert Forget wallet button is visible") {
|
step("Assert 'Forget wallet' button is visible") {
|
||||||
forgetWalletButton.assertIsDisplayed()
|
forgetWalletButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun wallet2Details() =
|
fun wallet2DetailsTest() =
|
||||||
setupHooks().run {
|
setupHooks().run {
|
||||||
scenario(OpenMainScreenScenario(composeTestRule, ProductType.Wallet2))
|
scenario(OpenMainScreenScenario(composeTestRule, ProductType.Wallet2))
|
||||||
ComposeScreen.onComposeScreen<TestTopBar>(composeTestRule) {
|
onTopBar {
|
||||||
step("Open wallet details") {
|
step("Open wallet details") {
|
||||||
moreButton.clickWithAssertion()
|
moreButton.clickWithAssertion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ComposeScreen.onComposeScreen<DetailsTestScreen>(composeTestRule) {
|
onDetailsScreen {
|
||||||
step("Assert wallet connect button is visible") {
|
step("Assert 'Wallet connect' button is visible") {
|
||||||
walletConnectButton.assertIsDisplayed()
|
walletConnectButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert scan card button is visible") {
|
step("Assert 'Scan card' button is visible") {
|
||||||
scanCardButton.assertIsDisplayed()
|
scanCardButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert buy Tangem card button is visible") {
|
step("Assert 'Buy Tangem card' button is visible") {
|
||||||
buyTangemButton.assertIsDisplayed()
|
buyTangemButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert app settings button is visible") {
|
step("Assert 'App settings' button is visible") {
|
||||||
appSettingsButton.assertIsDisplayed()
|
appSettingsButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert contact support button is visible") {
|
step("Assert 'Contact support' button is visible") {
|
||||||
contactSupportButton.assertIsDisplayed()
|
contactSupportButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert terms or service button is visible") {
|
step("Assert 'Terms or service' button is visible") {
|
||||||
toSButton.assertIsDisplayed()
|
toSButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Open wallet settings screen") {
|
step("Open 'Wallet settings' screen") {
|
||||||
walletNameButton.clickWithAssertion()
|
walletNameButton.clickWithAssertion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ComposeScreen.onComposeScreen<WalletSettingsTestScreen>(composeTestRule) {
|
onWalletSettingsScreen {
|
||||||
step("Assert Link more cards button does not exist") {
|
step("Assert 'Link more cards' button does not exist") {
|
||||||
linkMoreCardsButton.assertIsNotDisplayed()
|
linkMoreCardsButton.assertIsNotDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert Card Settings button is visible") {
|
step("Assert 'Card Settings' button is visible") {
|
||||||
cardSettingsButton.assertIsDisplayed()
|
cardSettingsButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert Referral program button is visible") {
|
step("Assert 'Referral program' button is visible") {
|
||||||
referralProgramButton.assertIsDisplayed()
|
referralProgramButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert Forget wallet button is visible") {
|
step("Assert 'Forget wallet' button is visible") {
|
||||||
forgetWalletButton.assertIsDisplayed()
|
forgetWalletButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun noteDetails() =
|
fun noteDetailsTest() =
|
||||||
setupHooks().run {
|
setupHooks().run {
|
||||||
scenario(OpenMainScreenScenario(composeTestRule, ProductType.Note))
|
scenario(OpenMainScreenScenario(composeTestRule, ProductType.Note))
|
||||||
ComposeScreen.onComposeScreen<TestTopBar>(composeTestRule) {
|
onTopBar {
|
||||||
step("Open wallet details") {
|
step("Open wallet details") {
|
||||||
moreButton.clickWithAssertion()
|
moreButton.clickWithAssertion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ComposeScreen.onComposeScreen<DetailsTestScreen>(composeTestRule) {
|
onDetailsScreen {
|
||||||
step("Assert wallet connect button does not exist") {
|
step("Assert 'Wallet connect' button does not exist") {
|
||||||
walletConnectButton.assertIsNotDisplayed()
|
walletConnectButton.assertIsNotDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert scan card button is visible") {
|
step("Assert 'Scan card' button is visible") {
|
||||||
scanCardButton.assertIsDisplayed()
|
scanCardButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert buy Tangem card button is visible") {
|
step("Assert 'Buy Tangem card' button is visible") {
|
||||||
buyTangemButton.assertIsDisplayed()
|
buyTangemButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert app settings button is visible") {
|
step("Assert 'App settings' button is visible") {
|
||||||
appSettingsButton.assertIsDisplayed()
|
appSettingsButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert contact support button is visible") {
|
step("Assert 'Contact support' button is visible") {
|
||||||
contactSupportButton.assertIsDisplayed()
|
contactSupportButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert terms or service button is visible") {
|
step("Assert 'Terms or service' button is visible") {
|
||||||
toSButton.assertIsDisplayed()
|
toSButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Open wallet settings screen") {
|
step("Open 'Wallet settings' screen") {
|
||||||
walletNameButton.clickWithAssertion()
|
walletNameButton.clickWithAssertion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ComposeScreen.onComposeScreen<WalletSettingsTestScreen>(composeTestRule) {
|
onWalletSettingsScreen {
|
||||||
step("Assert Card Settings button is visible") {
|
step("Assert 'Card Settings' button is visible") {
|
||||||
cardSettingsButton.assertIsDisplayed()
|
cardSettingsButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert Referral program button does not exist") {
|
step("Assert 'Referral program' button does not exist") {
|
||||||
referralProgramButton.assertIsNotDisplayed()
|
referralProgramButton.assertIsNotDisplayed()
|
||||||
}
|
}
|
||||||
step("Assert Forget wallet button is visible") {
|
step("Assert 'Forget wallet' button is visible") {
|
||||||
forgetWalletButton.assertIsDisplayed()
|
forgetWalletButton.assertIsDisplayed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
58
app/src/androidTest/kotlin/com/tangem/tests/HideTokenTest.kt
Normal file
58
app/src/androidTest/kotlin/com/tangem/tests/HideTokenTest.kt
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
package com.tangem.tests
|
||||||
|
|
||||||
|
import com.tangem.common.BaseTestCase
|
||||||
|
import com.tangem.common.extensions.clickWithAssertion
|
||||||
|
import com.tangem.scenarios.OpenMainScreenScenario
|
||||||
|
import com.tangem.screens.*
|
||||||
|
import dagger.hilt.android.testing.HiltAndroidTest
|
||||||
|
import io.qameta.allure.kotlin.AllureId
|
||||||
|
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
@HiltAndroidTest
|
||||||
|
class HideTokenTest : BaseTestCase() {
|
||||||
|
|
||||||
|
@AllureId("880")
|
||||||
|
@DisplayName("Hide token in 'Token details' screen by 'Hide' button in topBar menu")
|
||||||
|
@Test
|
||||||
|
fun hideWalletTokenByHideButtonTest() {
|
||||||
|
val tokenTitle = "Polygon"
|
||||||
|
val balance = "<$0.01"
|
||||||
|
setupHooks().run {
|
||||||
|
step("Open 'Main Screen'") {
|
||||||
|
scenario(OpenMainScreenScenario(composeTestRule))
|
||||||
|
}
|
||||||
|
step("Click on 'Synchronize addresses' button" ) {
|
||||||
|
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||||
|
}
|
||||||
|
step("Assert wallet balance = $balance") {
|
||||||
|
onMainScreen { walletBalance().assertTextContains(balance) }
|
||||||
|
}
|
||||||
|
step("Click on token with name: '$tokenTitle'") {
|
||||||
|
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||||
|
}
|
||||||
|
step("Assert 'Token details screen' open") {
|
||||||
|
onTokenDetailsScreen { screenContainer.assertIsDisplayed() }
|
||||||
|
}
|
||||||
|
step("Click 'More button'") {
|
||||||
|
onTokenDetailsTopBar { moreButton.clickWithAssertion() }
|
||||||
|
}
|
||||||
|
step("Click 'Hide token' button") {
|
||||||
|
onPopUpMenu {
|
||||||
|
popUpContainer.assertIsDisplayed()
|
||||||
|
hideTokenButton.clickWithAssertion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
step("Click 'Hide' button in dialog") {
|
||||||
|
onDialog {
|
||||||
|
dialogContainer.assertIsDisplayed()
|
||||||
|
hideButton.clickWithAssertion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
step("Assert token: '$tokenTitle' is not displayed") {
|
||||||
|
onMainScreen { assertTokenDoesNotExist(tokenTitle) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,8 @@
|
||||||
package com.tangem.tests
|
package com.tangem.tests
|
||||||
|
|
||||||
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
|
||||||
import com.tangem.common.BaseTestCase
|
import com.tangem.common.BaseTestCase
|
||||||
import com.tangem.scenarios.OpenMainScreenScenario
|
import com.tangem.scenarios.OpenMainScreenScenario
|
||||||
import com.tangem.tap.MainActivity
|
|
||||||
import dagger.hilt.android.testing.HiltAndroidTest
|
import dagger.hilt.android.testing.HiltAndroidTest
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
@HiltAndroidTest
|
@HiltAndroidTest
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,206 @@
|
||||||
|
package com.tangem.tests
|
||||||
|
|
||||||
|
import androidx.compose.ui.test.onAllNodesWithText
|
||||||
|
import com.tangem.common.BaseTestCase
|
||||||
|
import com.tangem.common.extensions.clickWithAssertion
|
||||||
|
import com.tangem.scenarios.OpenMainScreenScenario
|
||||||
|
import com.tangem.screens.onMainScreen
|
||||||
|
import com.tangem.screens.onOrganizeTokensScreen
|
||||||
|
import dagger.hilt.android.testing.HiltAndroidTest
|
||||||
|
import io.qameta.allure.kotlin.AllureId
|
||||||
|
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
@HiltAndroidTest
|
||||||
|
class OrganizeTokensTest : BaseTestCase() {
|
||||||
|
|
||||||
|
@AllureId("2755")
|
||||||
|
@DisplayName("Organize tokens: group tokens")
|
||||||
|
@Test
|
||||||
|
fun groupTokensTest() {
|
||||||
|
setupHooks().run {
|
||||||
|
val tokenTitle = "Ethereum"
|
||||||
|
val tokenNetwork = "Ethereum network"
|
||||||
|
step("Open 'Main Screen'") {
|
||||||
|
scenario(OpenMainScreenScenario(composeTestRule))
|
||||||
|
}
|
||||||
|
step("Click on 'Synchronize addresses' button" ) {
|
||||||
|
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||||
|
}
|
||||||
|
step("Click 'Organize tokens' button") {
|
||||||
|
onMainScreen { organizeTokensButton().clickWithAssertion() }
|
||||||
|
}
|
||||||
|
step("Assert 'Organize tokens' screen is opened") {
|
||||||
|
onOrganizeTokensScreen {
|
||||||
|
title.assertIsDisplayed()
|
||||||
|
tokenWithTitle(tokenTitle).assertIsDisplayed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
step("Click 'Group' button") {
|
||||||
|
onOrganizeTokensScreen { groupButton.clickWithAssertion() }
|
||||||
|
}
|
||||||
|
step("Assert tokens were grouped on 'Organize tokens' screen") {
|
||||||
|
onOrganizeTokensScreen { tokenNetworkGroupTitle(tokenNetwork).assertIsDisplayed() }
|
||||||
|
}
|
||||||
|
step("Click 'Apply' button") {
|
||||||
|
onOrganizeTokensScreen { applyButton.clickWithAssertion() }
|
||||||
|
}
|
||||||
|
step("Assert tokens were grouped on 'Main screen'") {
|
||||||
|
onMainScreen { tokenNetworkGroupTitle(tokenNetwork).assertIsDisplayed() }
|
||||||
|
}
|
||||||
|
step("Click 'Organize tokens' button") {
|
||||||
|
onMainScreen { organizeTokensButton().clickWithAssertion() }
|
||||||
|
}
|
||||||
|
step("Assert 'Organize tokens' screen is opened") {
|
||||||
|
onOrganizeTokensScreen {
|
||||||
|
title.assertIsDisplayed()
|
||||||
|
tokenWithTitle(tokenTitle).assertIsDisplayed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
step("Click 'Ungroup' button") {
|
||||||
|
onOrganizeTokensScreen { ungroupButton.clickWithAssertion() }
|
||||||
|
}
|
||||||
|
step("Assert tokens were ungrouped on 'Organize tokens' screen") {
|
||||||
|
onOrganizeTokensScreen { tokenNetworkGroupTitle(tokenNetwork).assertIsNotDisplayed() }
|
||||||
|
}
|
||||||
|
step("Click 'Apply' button") {
|
||||||
|
onOrganizeTokensScreen { applyButton.clickWithAssertion() }
|
||||||
|
}
|
||||||
|
step("Assert tokens were ungrouped on 'Main screen'") {
|
||||||
|
onMainScreen { tokenNetworkGroupTitle(tokenNetwork).assertIsNotDisplayed() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AllureId("2752")
|
||||||
|
@DisplayName("Organize tokens: check position of tokens")
|
||||||
|
@Test
|
||||||
|
fun checkPositionOfTokensTest() {
|
||||||
|
setupHooks().run {
|
||||||
|
val ethereumTitle = "Ethereum"
|
||||||
|
val bitcoinTitle = "Bitcoin"
|
||||||
|
step("Open 'Main Screen'") {
|
||||||
|
scenario(OpenMainScreenScenario(composeTestRule))
|
||||||
|
}
|
||||||
|
step("Click on 'Synchronize addresses' button" ) {
|
||||||
|
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||||
|
}
|
||||||
|
step("Check positions of tokens on 'Main Screen'") {
|
||||||
|
onMainScreen {
|
||||||
|
tokenWithTitleAndPosition(bitcoinTitle, 0).assertIsDisplayed()
|
||||||
|
tokenWithTitleAndPosition(ethereumTitle, 1).assertIsDisplayed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
step("Click 'Organize tokens' button") {
|
||||||
|
onMainScreen { organizeTokensButton().clickWithAssertion() }
|
||||||
|
}
|
||||||
|
step("Check positions of tokens on 'Organize tokens' screen") {
|
||||||
|
onOrganizeTokensScreen {
|
||||||
|
tokenWithTitleAndPosition(bitcoinTitle, 1).assertIsDisplayed()
|
||||||
|
tokenWithTitleAndPosition(ethereumTitle, 2).assertIsDisplayed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AllureId("2753")
|
||||||
|
@DisplayName("Organize tokens: check position of tokens")
|
||||||
|
// toDo: on test build there is not ability to drag element
|
||||||
|
// @Test
|
||||||
|
fun checkCustomTokensOrderTest() {
|
||||||
|
setupHooks().run {
|
||||||
|
val ethereumTitle = "Ethereum"
|
||||||
|
val bitcoinTitle = "Bitcoin"
|
||||||
|
step("Open 'Main Screen'") {
|
||||||
|
scenario(OpenMainScreenScenario(composeTestRule))
|
||||||
|
}
|
||||||
|
step("Click on 'Synchronize addresses' button" ) {
|
||||||
|
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||||
|
}
|
||||||
|
step("Check positions of tokens on 'Main Screen'") {
|
||||||
|
onMainScreen {
|
||||||
|
tokenWithTitleAndPosition(bitcoinTitle, 0).assertIsDisplayed()
|
||||||
|
tokenWithTitleAndPosition(ethereumTitle, 1).assertIsDisplayed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
step("Click 'Organize tokens' button") {
|
||||||
|
onMainScreen { organizeTokensButton().clickWithAssertion() }
|
||||||
|
}
|
||||||
|
step("Drag $bitcoinTitle down on 'Organize tokens' screen") {
|
||||||
|
composeTestRule.waitUntil(timeoutMillis = 100_000) {
|
||||||
|
composeTestRule.onAllNodesWithText("Data loaded").fetchSemanticsNodes().isNotEmpty()
|
||||||
|
}
|
||||||
|
onOrganizeTokensScreen {
|
||||||
|
tokenWithTitleAndPosition(bitcoinTitle, 2).assertIsDisplayed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
step("Click 'Apply' button") {
|
||||||
|
onOrganizeTokensScreen { applyButton.clickWithAssertion() }
|
||||||
|
}
|
||||||
|
step("Check positions of tokens on 'Main Screen'") {
|
||||||
|
onMainScreen {
|
||||||
|
tokenWithTitleAndPosition(bitcoinTitle, 1).assertIsDisplayed()
|
||||||
|
tokenWithTitleAndPosition(ethereumTitle, 0).assertIsDisplayed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AllureId("2754")
|
||||||
|
@DisplayName("Organize tokens: sort by balance")
|
||||||
|
@Test
|
||||||
|
fun checkSortByBalanceTest() {
|
||||||
|
setupHooks().run {
|
||||||
|
val ethereumTitle = "Ethereum"
|
||||||
|
val bitcoinTitle = "Bitcoin"
|
||||||
|
val polygonTitle = "Polygon"
|
||||||
|
step("Open 'Main Screen'") {
|
||||||
|
scenario(OpenMainScreenScenario(composeTestRule))
|
||||||
|
}
|
||||||
|
step("Click on 'Synchronize addresses' button" ) {
|
||||||
|
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||||
|
}
|
||||||
|
step("Check positions of tokens on 'Main Screen'") {
|
||||||
|
onMainScreen {
|
||||||
|
tokenWithTitleAndPosition(bitcoinTitle, 0).assertIsDisplayed()
|
||||||
|
tokenWithTitleAndPosition(ethereumTitle, 1).assertIsDisplayed()
|
||||||
|
tokenWithTitleAndPosition(polygonTitle, 2).assertIsDisplayed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
step("Click 'Organize tokens' button") {
|
||||||
|
onMainScreen { organizeTokensButton().clickWithAssertion() }
|
||||||
|
}
|
||||||
|
step("Check positions of tokens on 'Organize tokens' screen") {
|
||||||
|
onOrganizeTokensScreen {
|
||||||
|
tokenWithTitleAndPosition(bitcoinTitle, 1).assertIsDisplayed()
|
||||||
|
tokenWithTitleAndPosition(ethereumTitle, 2).assertIsDisplayed()
|
||||||
|
tokenWithTitleAndPosition(polygonTitle, 3).assertIsDisplayed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
step("Click 'By Balance' button") {
|
||||||
|
onOrganizeTokensScreen {
|
||||||
|
sortByBalanceButton.clickWithAssertion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
step("Check positions of tokens by balance on 'Organize tokens' screen") {
|
||||||
|
onOrganizeTokensScreen {
|
||||||
|
tokenWithTitleAndPosition(ethereumTitle, 1).assertIsDisplayed()
|
||||||
|
tokenWithTitleAndPosition(polygonTitle, 2).assertIsDisplayed()
|
||||||
|
tokenWithTitleAndPosition(bitcoinTitle, 3).assertIsDisplayed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
step("Click 'Apply' button") {
|
||||||
|
onOrganizeTokensScreen { applyButton.clickWithAssertion() }
|
||||||
|
}
|
||||||
|
step("Check positions of tokens by balance on 'Organize tokens' screen") {
|
||||||
|
onMainScreen {
|
||||||
|
tokenWithTitleAndPosition(ethereumTitle, 0).assertIsDisplayed()
|
||||||
|
tokenWithTitleAndPosition(polygonTitle, 1).assertIsDisplayed()
|
||||||
|
tokenWithTitleAndPosition(bitcoinTitle, 2).assertIsDisplayed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -2,36 +2,35 @@ package com.tangem.tests
|
||||||
|
|
||||||
import com.tangem.common.BaseTestCase
|
import com.tangem.common.BaseTestCase
|
||||||
import com.tangem.common.extensions.clickWithAssertion
|
import com.tangem.common.extensions.clickWithAssertion
|
||||||
import com.tangem.screens.DisclaimerTestScreen
|
import com.tangem.screens.onDisclaimerScreen
|
||||||
import com.tangem.screens.MainTestScreen
|
import com.tangem.screens.onMainScreen
|
||||||
import com.tangem.screens.StoriesTestScreen
|
import com.tangem.screens.onStoriesScreen
|
||||||
import com.tangem.tap.domain.sdk.mocks.MockProvider
|
import com.tangem.tap.domain.sdk.mocks.MockProvider
|
||||||
import dagger.hilt.android.testing.HiltAndroidTest
|
import dagger.hilt.android.testing.HiltAndroidTest
|
||||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
@HiltAndroidTest
|
@HiltAndroidTest
|
||||||
class ScanErrorTest : BaseTestCase() {
|
class ScanErrorTest : BaseTestCase() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun goToMain() =
|
fun goToMainTest() =
|
||||||
setupHooks().run {
|
setupHooks().run {
|
||||||
ComposeScreen.onComposeScreen<DisclaimerTestScreen>(composeTestRule) {
|
onDisclaimerScreen {
|
||||||
step("Click on \"Accept\" button") {
|
step("Click on 'Accept' button") {
|
||||||
acceptButton.clickWithAssertion()
|
acceptButton.clickWithAssertion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ComposeScreen.onComposeScreen<StoriesTestScreen>(composeTestRule) {
|
onStoriesScreen {
|
||||||
step("Click on \"Scan\" button emulating scan error") {
|
step("Click on 'Scan' button emulating scan error") {
|
||||||
MockProvider.setEmulateError()
|
MockProvider.setEmulateError()
|
||||||
scanButton.clickWithAssertion()
|
scanButton.clickWithAssertion()
|
||||||
}
|
}
|
||||||
step("Click on \"Scan\" button again without emulating error") {
|
step("Click on 'Scan' button again without emulating error") {
|
||||||
MockProvider.resetEmulateError()
|
MockProvider.resetEmulateError()
|
||||||
scanButton.clickWithAssertion()
|
scanButton.clickWithAssertion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ComposeScreen.onComposeScreen<MainTestScreen>(composeTestRule) {
|
onMainScreen {
|
||||||
step("Make sure wallet screen is visible") {
|
step("Make sure wallet screen is visible") {
|
||||||
assertIsDisplayed()
|
assertIsDisplayed()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,28 @@
|
||||||
package com.tangem.tests
|
package com.tangem.tests
|
||||||
|
|
||||||
import android.content.Intent.ACTION_VIEW
|
import android.content.Intent.ACTION_VIEW
|
||||||
import androidx.test.espresso.intent.matcher.UriMatchers
|
|
||||||
import com.tangem.common.BaseTestCase
|
import com.tangem.common.BaseTestCase
|
||||||
import com.tangem.common.extensions.clickWithAssertion
|
import com.tangem.common.extensions.clickWithAssertion
|
||||||
import com.tangem.screens.DisclaimerTestScreen
|
import com.tangem.screens.onDisclaimerScreen
|
||||||
import com.tangem.screens.StoriesTestScreen
|
import com.tangem.screens.onStoriesScreen
|
||||||
import com.tangem.tap.features.home.redux.HomeMiddleware.NEW_BUY_WALLET_URL
|
import com.tangem.tap.features.home.redux.HomeMiddleware.NEW_BUY_WALLET_URL
|
||||||
import dagger.hilt.android.testing.HiltAndroidTest
|
import dagger.hilt.android.testing.HiltAndroidTest
|
||||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
|
||||||
import io.github.kakaocup.kakao.intent.KIntent
|
import io.github.kakaocup.kakao.intent.KIntent
|
||||||
import org.hamcrest.Matchers
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
@HiltAndroidTest
|
@HiltAndroidTest
|
||||||
class StoriesTest : BaseTestCase() {
|
class StoriesTest : BaseTestCase() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun clickOnOrderButton() =
|
fun clickOnOrderButtonTest() =
|
||||||
setupHooks().run {
|
setupHooks().run {
|
||||||
ComposeScreen.onComposeScreen<DisclaimerTestScreen>(composeTestRule) {
|
onDisclaimerScreen {
|
||||||
step("Click on \"Accept\" button") {
|
step("Click on 'Accept' button") {
|
||||||
acceptButton.clickWithAssertion()
|
acceptButton.clickWithAssertion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ComposeScreen.onComposeScreen<StoriesTestScreen>(composeTestRule) {
|
onStoriesScreen {
|
||||||
step("Click on \"Order\" button") {
|
step("Click on 'Order' button") {
|
||||||
orderButton.clickWithAssertion()
|
orderButton.clickWithAssertion()
|
||||||
}
|
}
|
||||||
step("Assert: browser opened") {
|
step("Assert: browser opened") {
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,6 @@ import com.tangem.domain.wallets.builder.ColdUserWalletBuilder
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||||
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
|
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
|
||||||
import com.tangem.features.onramp.OnrampFeatureToggles
|
|
||||||
import com.tangem.operations.attestation.OnlineCardVerifier
|
|
||||||
import com.tangem.tap.common.analytics.handlers.BlockchainExceptionHandler
|
import com.tangem.tap.common.analytics.handlers.BlockchainExceptionHandler
|
||||||
import com.tangem.tap.common.log.TangemAppLoggerInitializer
|
import com.tangem.tap.common.log.TangemAppLoggerInitializer
|
||||||
import com.tangem.tap.domain.scanCard.CardScanningFeatureToggles
|
import com.tangem.tap.domain.scanCard.CardScanningFeatureToggles
|
||||||
|
|
@ -118,8 +116,6 @@ interface ApplicationEntryPoint {
|
||||||
|
|
||||||
fun getTransactionSignerFactory(): TransactionSignerFactory
|
fun getTransactionSignerFactory(): TransactionSignerFactory
|
||||||
|
|
||||||
fun getOnrampFeatureToggles(): OnrampFeatureToggles
|
|
||||||
|
|
||||||
fun getOnboardingV2FeatureToggles(): OnboardingV2FeatureToggles
|
fun getOnboardingV2FeatureToggles(): OnboardingV2FeatureToggles
|
||||||
|
|
||||||
fun getOnboardingRepository(): OnboardingRepository
|
fun getOnboardingRepository(): OnboardingRepository
|
||||||
|
|
@ -141,8 +137,6 @@ interface ApplicationEntryPoint {
|
||||||
|
|
||||||
fun getWorkerFactory(): HiltWorkerFactory
|
fun getWorkerFactory(): HiltWorkerFactory
|
||||||
|
|
||||||
fun getOnlineCardVerifier(): OnlineCardVerifier
|
|
||||||
|
|
||||||
fun getColdUserWalletBuilderFactory(): ColdUserWalletBuilder.Factory
|
fun getColdUserWalletBuilderFactory(): ColdUserWalletBuilder.Factory
|
||||||
|
|
||||||
fun getApiConfigsManager(): ApiConfigsManager
|
fun getApiConfigsManager(): ApiConfigsManager
|
||||||
|
|
|
||||||
|
|
@ -26,17 +26,13 @@ import androidx.lifecycle.flowWithLifecycle
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import arrow.core.getOrElse
|
import arrow.core.getOrElse
|
||||||
import com.tangem.common.routing.AppRoute
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.common.routing.RoutingFeatureToggle
|
import com.tangem.common.routing.deeplink.DeeplinkConst.WEBLINK_KEY
|
||||||
|
import com.tangem.common.routing.deeplink.PayloadToDeeplinkConverter
|
||||||
import com.tangem.common.routing.entity.SerializableIntent
|
import com.tangem.common.routing.entity.SerializableIntent
|
||||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||||
import com.tangem.core.decompose.context.AppComponentContext
|
import com.tangem.core.decompose.context.AppComponentContext
|
||||||
import com.tangem.core.decompose.di.RootAppComponentContext
|
import com.tangem.core.decompose.di.RootAppComponentContext
|
||||||
import com.tangem.core.deeplink.DeepLinksRegistry
|
|
||||||
import com.tangem.core.deeplink.WEBLINK_KEY
|
|
||||||
import com.tangem.core.deeplink.converter.PayloadToDeeplinkConverter
|
|
||||||
import com.tangem.core.navigation.email.EmailSender
|
|
||||||
import com.tangem.core.navigation.url.UrlOpener
|
import com.tangem.core.navigation.url.UrlOpener
|
||||||
import com.tangem.core.ui.UiDependencies
|
|
||||||
import com.tangem.data.balancehiding.DefaultDeviceFlipDetector
|
import com.tangem.data.balancehiding.DefaultDeviceFlipDetector
|
||||||
import com.tangem.data.card.sdk.CardSdkOwner
|
import com.tangem.data.card.sdk.CardSdkOwner
|
||||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||||
|
|
@ -53,6 +49,7 @@ import com.tangem.domain.tokens.GetPolkadotCheckHasResetUseCase
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
|
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
|
||||||
import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION
|
import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION
|
||||||
|
import com.tangem.features.tester.api.TesterMenuLauncher
|
||||||
import com.tangem.features.walletconnect.components.WalletConnectFeatureToggles
|
import com.tangem.features.walletconnect.components.WalletConnectFeatureToggles
|
||||||
import com.tangem.google.GoogleServicesHelper
|
import com.tangem.google.GoogleServicesHelper
|
||||||
import com.tangem.operations.backup.BackupService
|
import com.tangem.operations.backup.BackupService
|
||||||
|
|
@ -69,7 +66,6 @@ import com.tangem.tap.features.intentHandler.handlers.BackgroundScanIntentHandle
|
||||||
import com.tangem.tap.features.intentHandler.handlers.OnPushClickedIntentHandler
|
import com.tangem.tap.features.intentHandler.handlers.OnPushClickedIntentHandler
|
||||||
import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler
|
import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler
|
||||||
import com.tangem.tap.features.main.MainViewModel
|
import com.tangem.tap.features.main.MainViewModel
|
||||||
import com.tangem.tap.proxy.AppStateHolder
|
|
||||||
import com.tangem.tap.proxy.redux.DaggerGraphAction
|
import com.tangem.tap.proxy.redux.DaggerGraphAction
|
||||||
import com.tangem.tap.routing.component.RoutingComponent
|
import com.tangem.tap.routing.component.RoutingComponent
|
||||||
import com.tangem.tap.routing.configurator.AppRouterConfig
|
import com.tangem.tap.routing.configurator.AppRouterConfig
|
||||||
|
|
@ -103,9 +99,6 @@ val mainScope = CoroutineScope(mainCoroutineContext)
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var appStateHolder: AppStateHolder
|
|
||||||
|
|
||||||
/** Router for opening tester menu */
|
/** Router for opening tester menu */
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var cardSdkOwner: CardSdkOwner
|
lateinit var cardSdkOwner: CardSdkOwner
|
||||||
|
|
@ -122,9 +115,6 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var walletConnectInteractor: WalletConnectInteractor
|
lateinit var walletConnectInteractor: WalletConnectInteractor
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var deepLinksRegistry: DeepLinksRegistry
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var settingsRepository: SettingsRepository
|
lateinit var settingsRepository: SettingsRepository
|
||||||
|
|
||||||
|
|
@ -143,9 +133,6 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var userWalletsListManager: UserWalletsListManager
|
lateinit var userWalletsListManager: UserWalletsListManager
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var emailSender: EmailSender
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@RootAppComponentContext
|
@RootAppComponentContext
|
||||||
internal lateinit var rootComponentContext: AppComponentContext
|
internal lateinit var rootComponentContext: AppComponentContext
|
||||||
|
|
@ -174,15 +161,9 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var dispatchers: CoroutineDispatcherProvider
|
lateinit var dispatchers: CoroutineDispatcherProvider
|
||||||
|
|
||||||
@Inject
|
|
||||||
internal lateinit var uiDependencies: UiDependencies
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
internal lateinit var defaultDeviceFlipDetector: DefaultDeviceFlipDetector
|
internal lateinit var defaultDeviceFlipDetector: DefaultDeviceFlipDetector
|
||||||
|
|
||||||
@Inject
|
|
||||||
internal lateinit var routingFeatureToggle: RoutingFeatureToggle
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
internal lateinit var deeplinkFactory: DeepLinkFactory
|
internal lateinit var deeplinkFactory: DeepLinkFactory
|
||||||
|
|
||||||
|
|
@ -192,6 +173,9 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
||||||
@Inject
|
@Inject
|
||||||
internal lateinit var urlOpener: UrlOpener
|
internal lateinit var urlOpener: UrlOpener
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
internal lateinit var testerMenuLauncher: TesterMenuLauncher
|
||||||
|
|
||||||
internal val viewModel: MainViewModel by viewModels()
|
internal val viewModel: MainViewModel by viewModels()
|
||||||
|
|
||||||
private lateinit var appThemeModeFlow: SharedFlow<AppThemeMode>
|
private lateinit var appThemeModeFlow: SharedFlow<AppThemeMode>
|
||||||
|
|
@ -244,13 +228,12 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
||||||
sendStakingUnsubmittedHashes()
|
sendStakingUnsubmittedHashes()
|
||||||
checkGoogleServicesAvailability()
|
checkGoogleServicesAvailability()
|
||||||
|
|
||||||
if (routingFeatureToggle.isDeepLinkNavigationEnabled.not() && intent != null && savedInstanceState == null) {
|
|
||||||
// handle intent only on start, not on recreate
|
|
||||||
handleDeepLink(intent = intent, isFromOnNewIntent = false)
|
|
||||||
}
|
|
||||||
|
|
||||||
lifecycle.addObserver(WindowObscurationObserver)
|
lifecycle.addObserver(WindowObscurationObserver)
|
||||||
lifecycle.addObserver(defaultDeviceFlipDetector)
|
lifecycle.addObserver(defaultDeviceFlipDetector)
|
||||||
|
|
||||||
|
if (BuildConfig.TESTER_MENU_ENABLED) {
|
||||||
|
lifecycle.addObserver(testerMenuLauncher.launchOnShakeObserver)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setRootContent() {
|
private fun setRootContent() {
|
||||||
|
|
@ -481,7 +464,7 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (routingFeatureToggle.isDeepLinkNavigationEnabled && intent != null) {
|
if (intent != null) {
|
||||||
handleDeepLink(intent = intent, isFromOnNewIntent = false)
|
handleDeepLink(intent = intent, isFromOnNewIntent = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -489,26 +472,22 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleDeepLink(intent: Intent, isFromOnNewIntent: Boolean) {
|
private fun handleDeepLink(intent: Intent, isFromOnNewIntent: Boolean) {
|
||||||
if (routingFeatureToggle.isDeepLinkNavigationEnabled) {
|
val deepLinkExtras = PayloadToDeeplinkConverter.convertBundle(intent.extras)?.toUri()
|
||||||
val deepLinkExtras = PayloadToDeeplinkConverter.convertBundle(intent.extras)?.toUri()
|
val webLink = intent.getStringExtra(WEBLINK_KEY)
|
||||||
val webLink = intent.getStringExtra(WEBLINK_KEY)
|
|
||||||
|
|
||||||
val receivedDeepLink = intent.data ?: deepLinkExtras
|
val receivedDeepLink = intent.data ?: deepLinkExtras
|
||||||
|
|
||||||
when {
|
when {
|
||||||
receivedDeepLink != null -> {
|
receivedDeepLink != null -> {
|
||||||
deeplinkFactory.handleDeeplink(
|
deeplinkFactory.handleDeeplink(
|
||||||
deeplinkUri = receivedDeepLink,
|
deeplinkUri = receivedDeepLink,
|
||||||
coroutineScope = lifecycleScope,
|
coroutineScope = lifecycleScope,
|
||||||
isFromOnNewIntent = isFromOnNewIntent,
|
isFromOnNewIntent = isFromOnNewIntent,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
webLink?.uriValidate() == true -> {
|
webLink?.uriValidate() == true -> {
|
||||||
urlOpener.openUrl(webLink)
|
urlOpener.openUrl(webLink)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
deepLinksRegistry.launch(intent)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,8 +58,6 @@ import com.tangem.domain.wallets.builder.ColdUserWalletBuilder
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||||
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
|
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
|
||||||
import com.tangem.features.onramp.OnrampFeatureToggles
|
|
||||||
import com.tangem.operations.attestation.OnlineCardVerifier
|
|
||||||
import com.tangem.operations.attestation.api.TangemApiServiceSettings
|
import com.tangem.operations.attestation.api.TangemApiServiceSettings
|
||||||
import com.tangem.tap.common.analytics.AnalyticsFactory
|
import com.tangem.tap.common.analytics.AnalyticsFactory
|
||||||
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
|
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
|
||||||
|
|
@ -79,7 +77,6 @@ import com.tangem.wallet.BuildConfig
|
||||||
import dagger.hilt.EntryPoints
|
import dagger.hilt.EntryPoints
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import org.rekotlin.Store
|
import org.rekotlin.Store
|
||||||
import kotlin.collections.set
|
|
||||||
import com.tangem.tap.domain.walletconnect2.domain.LegacyWalletConnectRepository as WalletConnect2Repository
|
import com.tangem.tap.domain.walletconnect2.domain.LegacyWalletConnectRepository as WalletConnect2Repository
|
||||||
|
|
||||||
lateinit var store: Store<AppState>
|
lateinit var store: Store<AppState>
|
||||||
|
|
@ -186,9 +183,6 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
|
||||||
private val transactionSignerFactory: TransactionSignerFactory
|
private val transactionSignerFactory: TransactionSignerFactory
|
||||||
get() = entryPoint.getTransactionSignerFactory()
|
get() = entryPoint.getTransactionSignerFactory()
|
||||||
|
|
||||||
private val onrampFeatureToggles: OnrampFeatureToggles
|
|
||||||
get() = entryPoint.getOnrampFeatureToggles()
|
|
||||||
|
|
||||||
private val onboardingV2FeatureToggles: OnboardingV2FeatureToggles
|
private val onboardingV2FeatureToggles: OnboardingV2FeatureToggles
|
||||||
get() = entryPoint.getOnboardingV2FeatureToggles()
|
get() = entryPoint.getOnboardingV2FeatureToggles()
|
||||||
|
|
||||||
|
|
@ -224,9 +218,6 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
|
||||||
.setWorkerFactory(workerFactory)
|
.setWorkerFactory(workerFactory)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
private val onlineCardVerifier: OnlineCardVerifier
|
|
||||||
get() = entryPoint.getOnlineCardVerifier()
|
|
||||||
|
|
||||||
private val coldUserWalletBuilderFactory: ColdUserWalletBuilder.Factory
|
private val coldUserWalletBuilderFactory: ColdUserWalletBuilder.Factory
|
||||||
get() = entryPoint.getColdUserWalletBuilderFactory()
|
get() = entryPoint.getColdUserWalletBuilderFactory()
|
||||||
|
|
||||||
|
|
@ -363,7 +354,6 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
|
||||||
shareManager = shareManager,
|
shareManager = shareManager,
|
||||||
appRouter = appRouter,
|
appRouter = appRouter,
|
||||||
transactionSignerFactory = transactionSignerFactory,
|
transactionSignerFactory = transactionSignerFactory,
|
||||||
onrampFeatureToggles = onrampFeatureToggles,
|
|
||||||
environmentConfigStorage = environmentConfigStorage,
|
environmentConfigStorage = environmentConfigStorage,
|
||||||
onboardingV2FeatureToggles = onboardingV2FeatureToggles,
|
onboardingV2FeatureToggles = onboardingV2FeatureToggles,
|
||||||
onboardingRepository = onboardingRepository,
|
onboardingRepository = onboardingRepository,
|
||||||
|
|
@ -372,7 +362,6 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
|
||||||
clipboardManager = clipboardManager,
|
clipboardManager = clipboardManager,
|
||||||
settingsManager = settingsManager,
|
settingsManager = settingsManager,
|
||||||
uiMessageSender = uiMessageSender,
|
uiMessageSender = uiMessageSender,
|
||||||
onlineCardVerifier = onlineCardVerifier,
|
|
||||||
coldUserWalletBuilderFactory = coldUserWalletBuilderFactory,
|
coldUserWalletBuilderFactory = coldUserWalletBuilderFactory,
|
||||||
userTokensResponseStore = userTokensResponseStore,
|
userTokensResponseStore = userTokensResponseStore,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.common.extensions
|
||||||
|
|
||||||
import com.tangem.core.analytics.Analytics
|
import com.tangem.core.analytics.Analytics
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
||||||
import com.tangem.tap.common.analytics.paramsInterceptor.LinkedCardContextInterceptor
|
import com.tangem.tap.common.analytics.paramsInterceptor.LinkedCardContextInterceptor
|
||||||
|
|
||||||
|
|
@ -21,6 +22,15 @@ fun Analytics.setContext(scanResponse: ScanResponse) {
|
||||||
addParamsInterceptor(LinkedCardContextInterceptor(scanResponse))
|
addParamsInterceptor(LinkedCardContextInterceptor(scanResponse))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Analytics.setContext(userWallet: UserWallet) {
|
||||||
|
setUserId(userWallet.walletId.stringValue)
|
||||||
|
// TODO add product type for hot ([REDACTED_TASK_KEY])
|
||||||
|
|
||||||
|
if (userWallet is UserWallet.Cold) {
|
||||||
|
addParamsInterceptor(LinkedCardContextInterceptor(userWallet.scanResponse))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erases the context
|
* Erases the context
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import com.tangem.common.routing.AppRouter
|
||||||
import com.tangem.core.ui.extensions.stringReference
|
import com.tangem.core.ui.extensions.stringReference
|
||||||
import com.tangem.core.ui.message.SnackbarMessage
|
import com.tangem.core.ui.message.SnackbarMessage
|
||||||
import com.tangem.domain.common.extensions.withMainContext
|
import com.tangem.domain.common.extensions.withMainContext
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.redux.StateDialog
|
import com.tangem.domain.redux.StateDialog
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
|
||||||
import com.tangem.tap.common.redux.AppState
|
import com.tangem.tap.common.redux.AppState
|
||||||
import com.tangem.tap.common.redux.global.GlobalAction
|
import com.tangem.tap.common.redux.global.GlobalAction
|
||||||
import com.tangem.tap.domain.TapError
|
import com.tangem.tap.domain.TapError
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,11 @@ package com.tangem.tap.common.extensions
|
||||||
import com.tangem.blockchain.common.BlockchainSdkError
|
import com.tangem.blockchain.common.BlockchainSdkError
|
||||||
import com.tangem.blockchain.common.Wallet
|
import com.tangem.blockchain.common.Wallet
|
||||||
import com.tangem.blockchain.common.WalletManager
|
import com.tangem.blockchain.common.WalletManager
|
||||||
import com.tangem.blockchain.common.address.AddressType
|
|
||||||
import com.tangem.blockchainsdk.utils.amountToCreateAccount
|
import com.tangem.blockchainsdk.utils.amountToCreateAccount
|
||||||
import com.tangem.common.services.Result
|
import com.tangem.common.services.Result
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
|
||||||
import com.tangem.tap.common.TestActions
|
import com.tangem.tap.common.TestActions
|
||||||
import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder
|
|
||||||
import com.tangem.tap.domain.TapError
|
import com.tangem.tap.domain.TapError
|
||||||
import com.tangem.tap.domain.getFirstToken
|
import com.tangem.tap.domain.getFirstToken
|
||||||
import com.tangem.tap.domain.model.WalletAddressData
|
|
||||||
import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager
|
|
||||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
|
@ -57,43 +52,4 @@ suspend fun WalletManager.safeUpdate(isDemoCard: Boolean): Result<Wallet> = try
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
internal fun WalletManager.getTopUpUrl(cryptoCurrency: CryptoCurrency): String? {
|
|
||||||
val globalState = store.state.globalState
|
|
||||||
val defaultAddress = wallet.address
|
|
||||||
|
|
||||||
return globalState.exchangeManager.getUrl(
|
|
||||||
action = CurrencyExchangeManager.Action.Buy,
|
|
||||||
cryptoCurrency = cryptoCurrency,
|
|
||||||
fiatCurrencyName = globalState.appCurrency.code,
|
|
||||||
walletAddress = defaultAddress,
|
|
||||||
isDarkTheme = MutableAppThemeModeHolder.isDarkThemeActive,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun WalletManager?.getAddressData(): WalletAddressData? {
|
|
||||||
val wallet = this?.wallet ?: return null
|
|
||||||
|
|
||||||
val addressDataList = wallet.createAddressesData()
|
|
||||||
return if (addressDataList.isEmpty()) null else addressDataList[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Wallet.createAddressesData(): List<WalletAddressData> {
|
|
||||||
val listOfAddressData = mutableListOf<WalletAddressData>()
|
|
||||||
// put a defaultAddress at the first place
|
|
||||||
addresses.forEach {
|
|
||||||
val addressData = WalletAddressData(
|
|
||||||
it.value,
|
|
||||||
it.type,
|
|
||||||
getShareUri(it.value),
|
|
||||||
getExploreUrl(it.value),
|
|
||||||
)
|
|
||||||
if (it.type == AddressType.Default) {
|
|
||||||
listOfAddressData.add(0, addressData)
|
|
||||||
} else {
|
|
||||||
listOfAddressData.add(addressData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listOfAddressData
|
|
||||||
}
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ import android.util.Log
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import coil.decode.GifDecoder
|
import coil.decode.GifDecoder
|
||||||
import coil.decode.ImageDecoderDecoder
|
import coil.decode.ImageDecoderDecoder
|
||||||
|
import coil.decode.SvgDecoder
|
||||||
import coil.memory.MemoryCache
|
import coil.memory.MemoryCache
|
||||||
import coil.request.CachePolicy
|
import coil.request.CachePolicy
|
||||||
import coil.util.Logger
|
import coil.util.Logger
|
||||||
|
|
@ -36,6 +37,7 @@ fun createCoilImageLoader(context: Context, logEnabled: Boolean = false): ImageL
|
||||||
} else {
|
} else {
|
||||||
add(GifDecoder.Factory())
|
add(GifDecoder.Factory())
|
||||||
}
|
}
|
||||||
|
add(SvgDecoder.Factory())
|
||||||
}
|
}
|
||||||
.memoryCachePolicy(CachePolicy.ENABLED)
|
.memoryCachePolicy(CachePolicy.ENABLED)
|
||||||
.memoryCache {
|
.memoryCache {
|
||||||
|
|
|
||||||
|
|
@ -30,21 +30,5 @@ sealed class GlobalAction : Action {
|
||||||
data class Success(val appCurrency: AppCurrency) : GlobalAction()
|
data class Success(val appCurrency: AppCurrency) : GlobalAction()
|
||||||
}
|
}
|
||||||
|
|
||||||
data class UpdateWalletSignedHashes(
|
|
||||||
val walletSignedHashes: Int?,
|
|
||||||
val remainingSignatures: Int?,
|
|
||||||
val walletPublicKey: ByteArray,
|
|
||||||
) : GlobalAction()
|
|
||||||
|
|
||||||
data class IsSignWithRing(val isSignWithRing: Boolean) : GlobalAction()
|
data class IsSignWithRing(val isSignWithRing: Boolean) : GlobalAction()
|
||||||
|
|
||||||
object ExchangeManager : GlobalAction() {
|
|
||||||
object Init : GlobalAction() {
|
|
||||||
data class Success(
|
|
||||||
val exchangeManager: com.tangem.tap.network.exchangeServices.CurrencyExchangeManager,
|
|
||||||
) : GlobalAction()
|
|
||||||
}
|
|
||||||
|
|
||||||
object Update : GlobalAction()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -2,23 +2,14 @@ package com.tangem.tap.common.redux.global
|
||||||
|
|
||||||
import com.tangem.common.CompletionResult
|
import com.tangem.common.CompletionResult
|
||||||
import com.tangem.common.core.TangemSdkError
|
import com.tangem.common.core.TangemSdkError
|
||||||
import com.tangem.common.extensions.guard
|
|
||||||
import com.tangem.core.analytics.models.AnalyticsParam
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
import com.tangem.datasource.local.config.environment.EnvironmentConfig
|
|
||||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
import com.tangem.domain.common.LogConfig
|
|
||||||
import com.tangem.domain.models.scan.CardDTO
|
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
import com.tangem.domain.redux.StateDialog
|
import com.tangem.domain.redux.StateDialog
|
||||||
import com.tangem.domain.wallets.models.requireColdWallet
|
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||||
import com.tangem.tap.common.extensions.*
|
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||||
|
import com.tangem.tap.common.extensions.inject
|
||||||
import com.tangem.tap.common.redux.AppState
|
import com.tangem.tap.common.redux.AppState
|
||||||
import com.tangem.tap.network.exchangeServices.CardExchangeRules
|
|
||||||
import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager
|
|
||||||
import com.tangem.tap.network.exchangeServices.ExchangeService
|
|
||||||
import com.tangem.tap.network.exchangeServices.mercuryo.MercuryoEnvironment
|
|
||||||
import com.tangem.tap.network.exchangeServices.mercuryo.MercuryoService
|
|
||||||
import com.tangem.tap.network.exchangeServices.moonpay.MoonPayService
|
|
||||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||||
import com.tangem.tap.scope
|
import com.tangem.tap.scope
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
|
|
@ -31,17 +22,17 @@ object GlobalMiddleware {
|
||||||
val handler = globalMiddlewareHandler
|
val handler = globalMiddlewareHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
private val globalMiddlewareHandler: Middleware<AppState> = { dispatch, appState ->
|
private val globalMiddlewareHandler: Middleware<AppState> = { _, _ ->
|
||||||
{ nextDispatch ->
|
{ nextDispatch ->
|
||||||
{ action ->
|
{ action ->
|
||||||
handleAction(action, appState)
|
handleAction(action)
|
||||||
nextDispatch(action)
|
nextDispatch(action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("LongMethod", "ComplexMethod")
|
@Suppress("LongMethod", "ComplexMethod")
|
||||||
private fun handleAction(action: Action, appState: () -> AppState?) {
|
private fun handleAction(action: Action) {
|
||||||
when (action) {
|
when (action) {
|
||||||
is GlobalAction.ScanFailsCounter.ChooseBehavior -> {
|
is GlobalAction.ScanFailsCounter.ChooseBehavior -> {
|
||||||
when (action.result) {
|
when (action.result) {
|
||||||
|
|
@ -51,42 +42,7 @@ private fun handleAction(action: Action, appState: () -> AppState?) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is GlobalAction.RestoreAppCurrency -> {
|
is GlobalAction.RestoreAppCurrency -> restoreAppCurrency()
|
||||||
restoreAppCurrency()
|
|
||||||
}
|
|
||||||
is GlobalAction.ExchangeManager.Init -> {
|
|
||||||
val config = store.inject(DaggerGraphState::environmentConfigStorage).getConfigSync()
|
|
||||||
|
|
||||||
scope.launch {
|
|
||||||
val scanResponseProvider: () -> ScanResponse? = {
|
|
||||||
val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager)
|
|
||||||
userWalletsListManager.selectedUserWalletSync?.requireColdWallet()?.scanResponse // TODO [REDACTED_TASK_KEY]
|
|
||||||
}
|
|
||||||
val cardProvider: () -> CardDTO? = { scanResponseProvider.invoke()?.card }
|
|
||||||
|
|
||||||
val buyService = makeBuyExchangeService(config)
|
|
||||||
val sellService = makeSellExchangeService(config)
|
|
||||||
val exchangeManager = CurrencyExchangeManager(
|
|
||||||
buyService = buyService,
|
|
||||||
sellService = sellService,
|
|
||||||
primaryRules = CardExchangeRules(cardProvider),
|
|
||||||
)
|
|
||||||
// TODO: for refactoring (after remove old design refactor CurrencyExchangeManager and use 1 instance)
|
|
||||||
store.inject(DaggerGraphState::appStateHolder).buyService = buyService
|
|
||||||
store.inject(DaggerGraphState::appStateHolder).sellService = sellService
|
|
||||||
store.inject(DaggerGraphState::appStateHolder).exchangeService = exchangeManager
|
|
||||||
store.dispatchOnMain(GlobalAction.ExchangeManager.Init.Success(exchangeManager))
|
|
||||||
store.dispatchOnMain(GlobalAction.ExchangeManager.Update)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is GlobalAction.ExchangeManager.Init.Success -> {}
|
|
||||||
is GlobalAction.ExchangeManager.Update -> {
|
|
||||||
val exchangeManager = appState()?.globalState?.exchangeManager.guard {
|
|
||||||
store.dispatchDebugErrorNotification("exchangeManager is not initialized")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
scope.launch { exchangeManager.update() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,21 +75,4 @@ private fun restoreAppCurrency() {
|
||||||
|
|
||||||
store.dispatchWithMain(GlobalAction.RestoreAppCurrency.Success(currency))
|
store.dispatchWithMain(GlobalAction.RestoreAppCurrency.Success(currency))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun makeSellExchangeService(environmentConfig: EnvironmentConfig): ExchangeService {
|
|
||||||
return MoonPayService(
|
|
||||||
apiKey = environmentConfig.moonPayApiKey,
|
|
||||||
secretKey = environmentConfig.moonPayApiSecretKey,
|
|
||||||
logEnabled = LogConfig.network.moonPayService,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun makeBuyExchangeService(environmentConfig: EnvironmentConfig): ExchangeService {
|
|
||||||
return MercuryoService(
|
|
||||||
environment = MercuryoEnvironment.prod(
|
|
||||||
widgetId = environmentConfig.mercuryoWidgetId,
|
|
||||||
secret = environmentConfig.mercuryoSecret,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package com.tangem.tap.common.redux.global
|
package com.tangem.tap.common.redux.global
|
||||||
|
|
||||||
import com.tangem.tap.common.redux.AppState
|
import com.tangem.tap.common.redux.AppState
|
||||||
import com.tangem.utils.extensions.replaceBy
|
|
||||||
import org.rekotlin.Action
|
import org.rekotlin.Action
|
||||||
|
|
||||||
@Suppress("LongMethod", "ComplexMethod")
|
@Suppress("LongMethod", "ComplexMethod")
|
||||||
|
|
@ -26,24 +25,6 @@ fun globalReducer(action: Action, state: AppState): GlobalState {
|
||||||
is GlobalAction.RestoreAppCurrency.Success -> {
|
is GlobalAction.RestoreAppCurrency.Success -> {
|
||||||
globalState.copy(appCurrency = action.appCurrency)
|
globalState.copy(appCurrency = action.appCurrency)
|
||||||
}
|
}
|
||||||
is GlobalAction.UpdateWalletSignedHashes -> {
|
|
||||||
val card = globalState.scanResponse?.card ?: return globalState
|
|
||||||
val wallet = card.wallets
|
|
||||||
.firstOrNull { it.publicKey.contentEquals(action.walletPublicKey) }
|
|
||||||
?: return globalState
|
|
||||||
|
|
||||||
val newCardInstance = card.copy(
|
|
||||||
wallets = card.wallets.toMutableList().also { walletsMutable ->
|
|
||||||
walletsMutable.replaceBy(
|
|
||||||
item = wallet.copy(
|
|
||||||
totalSignedHashes = action.walletSignedHashes,
|
|
||||||
remainingSignatures = action.remainingSignatures,
|
|
||||||
),
|
|
||||||
) { it.index == wallet.index }
|
|
||||||
},
|
|
||||||
)
|
|
||||||
globalState.copy(scanResponse = globalState.scanResponse.copy(card = newCardInstance))
|
|
||||||
}
|
|
||||||
is GlobalAction.IsSignWithRing -> globalState.copy(isLastSignWithRing = action.isSignWithRing)
|
is GlobalAction.IsSignWithRing -> globalState.copy(isLastSignWithRing = action.isSignWithRing)
|
||||||
is GlobalAction.ShowDialog -> {
|
is GlobalAction.ShowDialog -> {
|
||||||
globalState.copy(dialog = action.stateDialog)
|
globalState.copy(dialog = action.stateDialog)
|
||||||
|
|
@ -51,9 +32,6 @@ fun globalReducer(action: Action, state: AppState): GlobalState {
|
||||||
is GlobalAction.HideDialog -> {
|
is GlobalAction.HideDialog -> {
|
||||||
globalState.copy(dialog = null)
|
globalState.copy(dialog = null)
|
||||||
}
|
}
|
||||||
is GlobalAction.ExchangeManager.Init.Success -> {
|
|
||||||
globalState.copy(exchangeManager = action.exchangeManager)
|
|
||||||
}
|
|
||||||
else -> globalState
|
else -> globalState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,8 +4,6 @@ import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
import com.tangem.domain.redux.StateDialog
|
import com.tangem.domain.redux.StateDialog
|
||||||
import com.tangem.tap.domain.TapWalletManager
|
import com.tangem.tap.domain.TapWalletManager
|
||||||
import com.tangem.tap.features.onboarding.OnboardingManager
|
|
||||||
import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager
|
|
||||||
import org.rekotlin.StateType
|
import org.rekotlin.StateType
|
||||||
|
|
||||||
data class GlobalState(
|
data class GlobalState(
|
||||||
|
|
@ -16,7 +14,6 @@ data class GlobalState(
|
||||||
val appCurrency: AppCurrency = AppCurrency.Default,
|
val appCurrency: AppCurrency = AppCurrency.Default,
|
||||||
val scanCardFailsCounter: Int = 0,
|
val scanCardFailsCounter: Int = 0,
|
||||||
val dialog: StateDialog? = null,
|
val dialog: StateDialog? = null,
|
||||||
val exchangeManager: CurrencyExchangeManager = CurrencyExchangeManager.dummy(),
|
|
||||||
val isLastSignWithRing: Boolean = false,
|
val isLastSignWithRing: Boolean = false,
|
||||||
) : StateType
|
) : StateType
|
||||||
|
|
||||||
|
|
@ -24,6 +21,5 @@ typealias CryptoCurrencyName = String
|
||||||
|
|
||||||
data class OnboardingState(
|
data class OnboardingState(
|
||||||
val onboardingStarted: Boolean = false,
|
val onboardingStarted: Boolean = false,
|
||||||
val onboardingManager: OnboardingManager? = null,
|
|
||||||
val shouldResetOnCreate: Boolean = false,
|
val shouldResetOnCreate: Boolean = false,
|
||||||
)
|
)
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package com.tangem.tap.common.redux.legacy
|
package com.tangem.tap.common.redux.legacy
|
||||||
|
|
||||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.redux.LegacyAction
|
import com.tangem.domain.redux.LegacyAction
|
||||||
import com.tangem.domain.wallets.models.requireColdWallet
|
|
||||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||||
import com.tangem.tap.common.extensions.inject
|
import com.tangem.tap.common.extensions.inject
|
||||||
import com.tangem.tap.common.redux.AppState
|
import com.tangem.tap.common.redux.AppState
|
||||||
|
|
@ -37,8 +37,7 @@ internal object LegacyMiddleware {
|
||||||
)
|
)
|
||||||
store.dispatchWithMain(
|
store.dispatchWithMain(
|
||||||
DetailsAction.PrepareScreen(
|
DetailsAction.PrepareScreen(
|
||||||
// TODO [REDACTED_TASK_KEY]
|
scanResponse = (selectedUserWallet as? UserWallet.Cold)?.scanResponse,
|
||||||
scanResponse = selectedUserWallet.requireColdWallet().scanResponse,
|
|
||||||
initializedAppSettingsState = initializedAppSettingsStateContent,
|
initializedAppSettingsState = initializedAppSettingsStateContent,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -67,7 +66,7 @@ internal object LegacyMiddleware {
|
||||||
?: AppThemeMode.DEFAULT,
|
?: AppThemeMode.DEFAULT,
|
||||||
isHidingEnabled = store.inject(DaggerGraphState::balanceHidingRepository)
|
isHidingEnabled = store.inject(DaggerGraphState::balanceHidingRepository)
|
||||||
.getBalanceHidingSettings().isHidingEnabledInSettings,
|
.getBalanceHidingSettings().isHidingEnabledInSettings,
|
||||||
needEnrollBiometrics = runCatching(tangemSdkManager::needEnrollBiometrics).getOrNull() ?: false,
|
needEnrollBiometrics = runCatching(tangemSdkManager::needEnrollBiometrics).getOrNull() == true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -16,16 +16,13 @@ import com.tangem.crypto.bip39.Wordlist
|
||||||
import com.tangem.data.card.sdk.CardSdkOwner
|
import com.tangem.data.card.sdk.CardSdkOwner
|
||||||
import com.tangem.data.card.sdk.CardSdkProvider
|
import com.tangem.data.card.sdk.CardSdkProvider
|
||||||
import com.tangem.datasource.api.common.config.ApiConfig
|
import com.tangem.datasource.api.common.config.ApiConfig
|
||||||
import com.tangem.datasource.api.common.config.ApiEnvironment
|
import com.tangem.datasource.api.common.config.ApiEnvironmentConfig
|
||||||
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
|
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
|
||||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
import com.tangem.datasource.api.common.config.managers.MutableApiConfigsManager
|
||||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
|
||||||
import com.tangem.datasource.local.preferences.utils.getObjectMap
|
|
||||||
import com.tangem.datasource.utils.AddHeadersInterceptor
|
import com.tangem.datasource.utils.AddHeadersInterceptor
|
||||||
import com.tangem.datasource.utils.RequestHeader
|
import com.tangem.datasource.utils.RequestHeader
|
||||||
import com.tangem.operations.attestation.api.TangemApiServiceSettings
|
import com.tangem.operations.attestation.api.TangemApiServiceSettings
|
||||||
import com.tangem.sdk.DefaultSessionViewDelegate
|
import com.tangem.sdk.DefaultSessionViewDelegate
|
||||||
import com.tangem.sdk.api.featuretoggles.CardSdkFeatureToggles
|
|
||||||
import com.tangem.sdk.extensions.*
|
import com.tangem.sdk.extensions.*
|
||||||
import com.tangem.sdk.nfc.AndroidNfcAvailabilityProvider
|
import com.tangem.sdk.nfc.AndroidNfcAvailabilityProvider
|
||||||
import com.tangem.sdk.nfc.NfcManager
|
import com.tangem.sdk.nfc.NfcManager
|
||||||
|
|
@ -34,13 +31,6 @@ import com.tangem.tap.foregroundActivityObserver
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import com.tangem.utils.info.AppInfoProvider
|
import com.tangem.utils.info.AppInfoProvider
|
||||||
import com.tangem.utils.version.AppVersionProvider
|
import com.tangem.utils.version.AppVersionProvider
|
||||||
import com.tangem.wallet.BuildConfig
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.SupervisorJob
|
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
@ -55,11 +45,9 @@ import javax.inject.Singleton
|
||||||
internal class DefaultCardSdkProvider @Inject constructor(
|
internal class DefaultCardSdkProvider @Inject constructor(
|
||||||
private val analyticsExceptionHandler: AnalyticsExceptionHandler,
|
private val analyticsExceptionHandler: AnalyticsExceptionHandler,
|
||||||
private val dispatchers: CoroutineDispatcherProvider,
|
private val dispatchers: CoroutineDispatcherProvider,
|
||||||
private val cardSdkFeatureToggles: CardSdkFeatureToggles,
|
|
||||||
private val apiConfigsManager: ApiConfigsManager,
|
private val apiConfigsManager: ApiConfigsManager,
|
||||||
appVersionProvider: AppVersionProvider,
|
appVersionProvider: AppVersionProvider,
|
||||||
appInfoProvider: AppInfoProvider,
|
appInfoProvider: AppInfoProvider,
|
||||||
appPreferencesStore: AppPreferencesStore,
|
|
||||||
) : CardSdkProvider, CardSdkOwner {
|
) : CardSdkProvider, CardSdkOwner {
|
||||||
|
|
||||||
private val observer = Observer()
|
private val observer = Observer()
|
||||||
|
|
@ -70,26 +58,15 @@ internal class DefaultCardSdkProvider @Inject constructor(
|
||||||
get() = holder?.sdk ?: tryToRegisterWithForegroundActivity()
|
get() = holder?.sdk ?: tryToRegisterWithForegroundActivity()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (BuildConfig.TESTER_MENU_ENABLED) {
|
val mutableManager = apiConfigsManager as? MutableApiConfigsManager
|
||||||
appPreferencesStore.getObjectMap<ApiEnvironment>(PreferencesKeys.apiConfigsEnvironmentKey)
|
|
||||||
.map {
|
mutableManager?.addListener(
|
||||||
when (it[ApiConfig.ID.Attestation.name]) {
|
object : MutableApiConfigsManager.ApiConfigEnvChangeListener(id = ApiConfig.ID.TangemTech) {
|
||||||
ApiEnvironment.DEV,
|
override fun onChange(environmentConfig: ApiEnvironmentConfig) {
|
||||||
ApiEnvironment.STAGE,
|
holder?.sdk?.config?.tangemApiBaseUrl = environmentConfig.baseUrl
|
||||||
-> false
|
|
||||||
ApiEnvironment.PROD,
|
|
||||||
null,
|
|
||||||
-> true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.distinctUntilChanged()
|
},
|
||||||
.onEach { isProd ->
|
)
|
||||||
holder?.let {
|
|
||||||
it.sdk.config.isTangemAttestationProdEnv = isProd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.launchIn(CoroutineScope(SupervisorJob() + dispatchers.main))
|
|
||||||
}
|
|
||||||
|
|
||||||
TangemApiServiceSettings.addInterceptors(
|
TangemApiServiceSettings.addInterceptors(
|
||||||
AddHeadersInterceptor(
|
AddHeadersInterceptor(
|
||||||
|
|
@ -187,10 +164,8 @@ internal class DefaultCardSdkProvider @Inject constructor(
|
||||||
keystoreManager = keystoreManager,
|
keystoreManager = keystoreManager,
|
||||||
wordlist = Wordlist.getWordlist(activity),
|
wordlist = Wordlist.getWordlist(activity),
|
||||||
config = config.apply {
|
config = config.apply {
|
||||||
isNewOnlineAttestationEnabled = cardSdkFeatureToggles.isNewAttestationEnabled
|
val apiConfig = apiConfigsManager.getEnvironmentConfig(id = ApiConfig.ID.TangemTech)
|
||||||
|
tangemApiBaseUrl = apiConfig.baseUrl
|
||||||
val apiConfig = apiConfigsManager.getEnvironmentConfig(id = ApiConfig.ID.Attestation)
|
|
||||||
isTangemAttestationProdEnv = apiConfig.environment == ApiEnvironment.PROD
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ package com.tangem.tap.data
|
||||||
|
|
||||||
import com.tangem.common.CompletionResult
|
import com.tangem.common.CompletionResult
|
||||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.firstOrNull
|
import kotlinx.coroutines.flow.firstOrNull
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import com.tangem.domain.tokens.GetPolkadotCheckHasImmortalUseCase
|
||||||
import com.tangem.domain.tokens.GetPolkadotCheckHasResetUseCase
|
import com.tangem.domain.tokens.GetPolkadotCheckHasResetUseCase
|
||||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
|
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
|
||||||
import com.tangem.features.onramp.OnrampFeatureToggles
|
|
||||||
import com.tangem.sdk.api.TangemSdkManager
|
import com.tangem.sdk.api.TangemSdkManager
|
||||||
import com.tangem.tap.domain.scanCard.repository.DefaultScanCardRepository
|
import com.tangem.tap.domain.scanCard.repository.DefaultScanCardRepository
|
||||||
import com.tangem.tap.network.exchangeServices.DefaultRampManager
|
import com.tangem.tap.network.exchangeServices.DefaultRampManager
|
||||||
|
|
@ -51,17 +50,13 @@ internal object ActivityModule {
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
excludedBlockchains: ExcludedBlockchains,
|
excludedBlockchains: ExcludedBlockchains,
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
onrampFeatureToggles: OnrampFeatureToggles,
|
|
||||||
): RampStateManager {
|
): RampStateManager {
|
||||||
return DefaultRampManager(
|
return DefaultRampManager(
|
||||||
exchangeService = appStateHolder.exchangeService,
|
|
||||||
buyService = Provider { requireNotNull(appStateHolder.buyService) },
|
|
||||||
sellService = Provider { requireNotNull(appStateHolder.sellService) },
|
sellService = Provider { requireNotNull(appStateHolder.sellService) },
|
||||||
expressServiceLoader = expressServiceLoader,
|
expressServiceLoader = expressServiceLoader,
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
excludedBlockchains = excludedBlockchains,
|
|
||||||
dispatchers = dispatchers,
|
dispatchers = dispatchers,
|
||||||
onrampFeatureToggles = onrampFeatureToggles,
|
excludedBlockchains = excludedBlockchains,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,6 @@ import com.tangem.domain.managetokens.repository.ManageTokensRepository
|
||||||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
||||||
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
||||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||||
import com.tangem.domain.staking.repositories.StakingRepository
|
|
||||||
import com.tangem.domain.tokens.TokensFeatureToggles
|
|
||||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
|
|
@ -71,22 +69,18 @@ internal object ManageTokensDomainModule {
|
||||||
walletManagersFacade: WalletManagersFacade,
|
walletManagersFacade: WalletManagersFacade,
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
derivationsRepository: DerivationsRepository,
|
derivationsRepository: DerivationsRepository,
|
||||||
stakingRepository: StakingRepository,
|
|
||||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||||
tokensFeatureToggles: TokensFeatureToggles,
|
|
||||||
): SaveManagedTokensUseCase {
|
): SaveManagedTokensUseCase {
|
||||||
return SaveManagedTokensUseCase(
|
return SaveManagedTokensUseCase(
|
||||||
customTokensRepository = customTokensRepository,
|
customTokensRepository = customTokensRepository,
|
||||||
walletManagersFacade = walletManagersFacade,
|
walletManagersFacade = walletManagersFacade,
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
derivationsRepository = derivationsRepository,
|
derivationsRepository = derivationsRepository,
|
||||||
stakingRepository = stakingRepository,
|
|
||||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||||
tokensFeatureToggles = tokensFeatureToggles,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,6 @@ import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
||||||
import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier
|
import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier
|
||||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||||
import com.tangem.domain.staking.repositories.StakingRepository
|
|
||||||
import com.tangem.domain.tokens.TokensFeatureToggles
|
|
||||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
|
|
@ -62,21 +60,17 @@ object MarketsDomainModule {
|
||||||
derivationsRepository: DerivationsRepository,
|
derivationsRepository: DerivationsRepository,
|
||||||
marketsTokenRepository: MarketsTokenRepository,
|
marketsTokenRepository: MarketsTokenRepository,
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
stakingRepository: StakingRepository,
|
|
||||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||||
tokensFeatureToggles: TokensFeatureToggles,
|
|
||||||
): SaveMarketTokensUseCase {
|
): SaveMarketTokensUseCase {
|
||||||
return SaveMarketTokensUseCase(
|
return SaveMarketTokensUseCase(
|
||||||
derivationsRepository = derivationsRepository,
|
derivationsRepository = derivationsRepository,
|
||||||
marketsTokenRepository = marketsTokenRepository,
|
marketsTokenRepository = marketsTokenRepository,
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
stakingRepository = stakingRepository,
|
|
||||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||||
tokensFeatureToggles = tokensFeatureToggles,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import com.tangem.domain.nft.*
|
||||||
import com.tangem.domain.nft.repository.NFTRepository
|
import com.tangem.domain.nft.repository.NFTRepository
|
||||||
import com.tangem.domain.quotes.single.SingleQuoteStatusFetcher
|
import com.tangem.domain.quotes.single.SingleQuoteStatusFetcher
|
||||||
import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier
|
import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier
|
||||||
|
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesSupplier
|
||||||
|
import com.tangem.domain.tokens.TokensFeatureToggles
|
||||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
|
|
@ -33,9 +35,13 @@ internal object NFTDomainModule {
|
||||||
fun providesFetchNFTCollectionsUseCase(
|
fun providesFetchNFTCollectionsUseCase(
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
nftRepository: NFTRepository,
|
nftRepository: NFTRepository,
|
||||||
|
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles: TokensFeatureToggles,
|
||||||
): FetchNFTCollectionsUseCase = FetchNFTCollectionsUseCase(
|
): FetchNFTCollectionsUseCase = FetchNFTCollectionsUseCase(
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
nftRepository = nftRepository,
|
nftRepository = nftRepository,
|
||||||
|
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles = tokensFeatureToggles,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
@ -43,9 +49,13 @@ internal object NFTDomainModule {
|
||||||
fun providesRefreshAllNFTUseCase(
|
fun providesRefreshAllNFTUseCase(
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
nftRepository: NFTRepository,
|
nftRepository: NFTRepository,
|
||||||
|
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles: TokensFeatureToggles,
|
||||||
): RefreshAllNFTUseCase = RefreshAllNFTUseCase(
|
): RefreshAllNFTUseCase = RefreshAllNFTUseCase(
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
nftRepository = nftRepository,
|
nftRepository = nftRepository,
|
||||||
|
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles = tokensFeatureToggles,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
@ -118,8 +128,16 @@ internal object NFTDomainModule {
|
||||||
walletsRepository: WalletsRepository,
|
walletsRepository: WalletsRepository,
|
||||||
nftRepository: NFTRepository,
|
nftRepository: NFTRepository,
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
|
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles: TokensFeatureToggles,
|
||||||
): DisableWalletNFTUseCase {
|
): DisableWalletNFTUseCase {
|
||||||
return DisableWalletNFTUseCase(walletsRepository, nftRepository, currenciesRepository)
|
return DisableWalletNFTUseCase(
|
||||||
|
walletsRepository = walletsRepository,
|
||||||
|
nftRepository = nftRepository,
|
||||||
|
currenciesRepository = currenciesRepository,
|
||||||
|
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles = tokensFeatureToggles,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
|
||||||
|
|
@ -94,12 +94,10 @@ internal object StakingDomainModule {
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideFetchStakingYieldBalanceUseCase(
|
fun provideFetchStakingYieldBalanceUseCase(
|
||||||
stakingRepository: StakingRepository,
|
|
||||||
stakingErrorResolver: StakingErrorResolver,
|
stakingErrorResolver: StakingErrorResolver,
|
||||||
singleYieldBalanceFetcher: SingleYieldBalanceFetcher,
|
singleYieldBalanceFetcher: SingleYieldBalanceFetcher,
|
||||||
): FetchStakingYieldBalanceUseCase {
|
): FetchStakingYieldBalanceUseCase {
|
||||||
return FetchStakingYieldBalanceUseCase(
|
return FetchStakingYieldBalanceUseCase(
|
||||||
stakingRepository = stakingRepository,
|
|
||||||
stakingErrorResolver = stakingErrorResolver,
|
stakingErrorResolver = stakingErrorResolver,
|
||||||
singleYieldBalanceFetcher = singleYieldBalanceFetcher,
|
singleYieldBalanceFetcher = singleYieldBalanceFetcher,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,7 @@ package com.tangem.tap.di.domain
|
||||||
import com.tangem.domain.swap.SwapErrorResolver
|
import com.tangem.domain.swap.SwapErrorResolver
|
||||||
import com.tangem.domain.swap.SwapRepositoryV2
|
import com.tangem.domain.swap.SwapRepositoryV2
|
||||||
import com.tangem.domain.swap.SwapTransactionRepository
|
import com.tangem.domain.swap.SwapTransactionRepository
|
||||||
import com.tangem.domain.swap.usecase.GetSwapPairsUseCase
|
import com.tangem.domain.swap.usecase.*
|
||||||
import com.tangem.domain.swap.usecase.GetSwapQuoteUseCase
|
|
||||||
import com.tangem.domain.swap.usecase.GetSwapSupportedPairsUseCase
|
|
||||||
import com.tangem.domain.swap.usecase.SelectInitialPairUseCase
|
|
||||||
import com.tangem.feature.swap.domain.GetAvailablePairsUseCase
|
import com.tangem.feature.swap.domain.GetAvailablePairsUseCase
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
|
|
@ -73,4 +70,30 @@ internal object SwapDomainModule {
|
||||||
swapErrorResolver = swapErrorResolver,
|
swapErrorResolver = swapErrorResolver,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideGetSwapDataUseCase(
|
||||||
|
swapRepositoryV2: SwapRepositoryV2,
|
||||||
|
swapErrorResolver: SwapErrorResolver,
|
||||||
|
): GetSwapDataUseCase {
|
||||||
|
return GetSwapDataUseCase(
|
||||||
|
swapRepositoryV2 = swapRepositoryV2,
|
||||||
|
swapErrorResolver = swapErrorResolver,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideSwapTransactionSentUseCase(
|
||||||
|
swapRepositoryV2: SwapRepositoryV2,
|
||||||
|
swapTransactionRepository: SwapTransactionRepository,
|
||||||
|
swapErrorResolver: SwapErrorResolver,
|
||||||
|
): SwapTransactionSentUseCase {
|
||||||
|
return SwapTransactionSentUseCase(
|
||||||
|
swapRepositoryV2 = swapRepositoryV2,
|
||||||
|
swapTransactionRepository = swapTransactionRepository,
|
||||||
|
swapErrorResolver = swapErrorResolver,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -22,6 +22,7 @@ import com.tangem.domain.tokens.operations.CachedCurrenciesStatusesOperations
|
||||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
|
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
|
||||||
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
|
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
|
||||||
|
import com.tangem.domain.tokens.wallet.WalletBalanceFetcher
|
||||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||||
import com.tangem.tap.domain.tokens.DefaultTokensFeatureToggles
|
import com.tangem.tap.domain.tokens.DefaultTokensFeatureToggles
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
|
|
@ -40,18 +41,18 @@ internal object TokensDomainModule {
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideAddCryptoCurrenciesUseCase(
|
fun provideAddCryptoCurrenciesUseCase(
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
stakingRepository: StakingRepository,
|
|
||||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||||
singleYieldBalanceFetcher: SingleYieldBalanceFetcher,
|
singleYieldBalanceFetcher: SingleYieldBalanceFetcher,
|
||||||
|
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||||
tokensFeatureToggles: TokensFeatureToggles,
|
tokensFeatureToggles: TokensFeatureToggles,
|
||||||
): AddCryptoCurrenciesUseCase {
|
): AddCryptoCurrenciesUseCase {
|
||||||
return AddCryptoCurrenciesUseCase(
|
return AddCryptoCurrenciesUseCase(
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
stakingRepository = stakingRepository,
|
|
||||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||||
singleYieldBalanceFetcher = singleYieldBalanceFetcher,
|
singleYieldBalanceFetcher = singleYieldBalanceFetcher,
|
||||||
|
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||||
tokensFeatureToggles = tokensFeatureToggles,
|
tokensFeatureToggles = tokensFeatureToggles,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -60,19 +61,15 @@ internal object TokensDomainModule {
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideFetchTokenListUseCase(
|
fun provideFetchTokenListUseCase(
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
stakingRepository: StakingRepository,
|
|
||||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||||
tokensFeatureToggles: TokensFeatureToggles,
|
|
||||||
): FetchTokenListUseCase {
|
): FetchTokenListUseCase {
|
||||||
return FetchTokenListUseCase(
|
return FetchTokenListUseCase(
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
stakingRepository = stakingRepository,
|
|
||||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||||
tokensFeatureToggles = tokensFeatureToggles,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,8 +104,15 @@ internal object TokensDomainModule {
|
||||||
fun provideRemoveCurrencyUseCase(
|
fun provideRemoveCurrencyUseCase(
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
walletManagersFacade: WalletManagersFacade,
|
walletManagersFacade: WalletManagersFacade,
|
||||||
|
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles: TokensFeatureToggles,
|
||||||
): RemoveCurrencyUseCase {
|
): RemoveCurrencyUseCase {
|
||||||
return RemoveCurrencyUseCase(currenciesRepository, walletManagersFacade)
|
return RemoveCurrencyUseCase(
|
||||||
|
currenciesRepository = currenciesRepository,
|
||||||
|
walletManagersFacade = walletManagersFacade,
|
||||||
|
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles = tokensFeatureToggles,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
@ -145,6 +149,8 @@ internal object TokensDomainModule {
|
||||||
currencyChecksRepository: CurrencyChecksRepository,
|
currencyChecksRepository: CurrencyChecksRepository,
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
baseCurrencyStatusOperations: BaseCurrencyStatusOperations,
|
baseCurrencyStatusOperations: BaseCurrencyStatusOperations,
|
||||||
|
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles: TokensFeatureToggles,
|
||||||
): GetCurrencyWarningsUseCase {
|
): GetCurrencyWarningsUseCase {
|
||||||
return GetCurrencyWarningsUseCase(
|
return GetCurrencyWarningsUseCase(
|
||||||
walletManagersFacade = walletManagersFacade,
|
walletManagersFacade = walletManagersFacade,
|
||||||
|
|
@ -152,6 +158,8 @@ internal object TokensDomainModule {
|
||||||
dispatchers = dispatchers,
|
dispatchers = dispatchers,
|
||||||
currencyChecksRepository = currencyChecksRepository,
|
currencyChecksRepository = currencyChecksRepository,
|
||||||
currencyStatusOperations = baseCurrencyStatusOperations,
|
currencyStatusOperations = baseCurrencyStatusOperations,
|
||||||
|
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles = tokensFeatureToggles,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,18 +167,18 @@ internal object TokensDomainModule {
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideFetchCurrencyStatusUseCase(
|
fun provideFetchCurrencyStatusUseCase(
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
stakingRepository: StakingRepository,
|
|
||||||
singleNetworkStatusFetcher: SingleNetworkStatusFetcher,
|
singleNetworkStatusFetcher: SingleNetworkStatusFetcher,
|
||||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||||
singleYieldBalanceFetcher: SingleYieldBalanceFetcher,
|
singleYieldBalanceFetcher: SingleYieldBalanceFetcher,
|
||||||
|
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||||
tokensFeatureToggles: TokensFeatureToggles,
|
tokensFeatureToggles: TokensFeatureToggles,
|
||||||
): FetchCurrencyStatusUseCase {
|
): FetchCurrencyStatusUseCase {
|
||||||
return FetchCurrencyStatusUseCase(
|
return FetchCurrencyStatusUseCase(
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
stakingRepository = stakingRepository,
|
|
||||||
singleNetworkStatusFetcher = singleNetworkStatusFetcher,
|
singleNetworkStatusFetcher = singleNetworkStatusFetcher,
|
||||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||||
singleYieldBalanceFetcher = singleYieldBalanceFetcher,
|
singleYieldBalanceFetcher = singleYieldBalanceFetcher,
|
||||||
|
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||||
tokensFeatureToggles = tokensFeatureToggles,
|
tokensFeatureToggles = tokensFeatureToggles,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -179,26 +187,26 @@ internal object TokensDomainModule {
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideFetchCardTokenListUseCase(
|
fun provideFetchCardTokenListUseCase(
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
stakingRepository: StakingRepository,
|
|
||||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||||
tokensFeatureToggles: TokensFeatureToggles,
|
|
||||||
): FetchCardTokenListUseCase {
|
): FetchCardTokenListUseCase {
|
||||||
return FetchCardTokenListUseCase(
|
return FetchCardTokenListUseCase(
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
stakingRepository = stakingRepository,
|
|
||||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||||
tokensFeatureToggles = tokensFeatureToggles,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideGetCryptoCurrencyUseCase(currenciesRepository: CurrenciesRepository): GetCryptoCurrencyUseCase {
|
fun provideGetCryptoCurrencyUseCase(
|
||||||
return GetCryptoCurrencyUseCase(currenciesRepository)
|
currenciesRepository: CurrenciesRepository,
|
||||||
|
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles: TokensFeatureToggles,
|
||||||
|
): GetCryptoCurrencyUseCase {
|
||||||
|
return GetCryptoCurrencyUseCase(currenciesRepository, multiWalletCryptoCurrenciesSupplier, tokensFeatureToggles)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
@ -219,9 +227,16 @@ internal object TokensDomainModule {
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideApplyTokenListSortingUseCase(
|
fun provideApplyTokenListSortingUseCase(
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
|
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles: TokensFeatureToggles,
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
): ApplyTokenListSortingUseCase {
|
): ApplyTokenListSortingUseCase {
|
||||||
return ApplyTokenListSortingUseCase(currenciesRepository, dispatchers)
|
return ApplyTokenListSortingUseCase(
|
||||||
|
currenciesRepository = currenciesRepository,
|
||||||
|
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles = tokensFeatureToggles,
|
||||||
|
dispatchers = dispatchers,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
@ -280,9 +295,13 @@ internal object TokensDomainModule {
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideIsCryptoCurrencyCoinCouldHideUseCase(
|
fun provideIsCryptoCurrencyCoinCouldHideUseCase(
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
|
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles: TokensFeatureToggles,
|
||||||
): IsCryptoCurrencyCoinCouldHideUseCase {
|
): IsCryptoCurrencyCoinCouldHideUseCase {
|
||||||
return IsCryptoCurrencyCoinCouldHideUseCase(
|
return IsCryptoCurrencyCoinCouldHideUseCase(
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
|
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles = tokensFeatureToggles,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -300,9 +319,16 @@ internal object TokensDomainModule {
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideGetBalanceNotEnoughForFeeWarningUseCase(
|
fun provideGetBalanceNotEnoughForFeeWarningUseCase(
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
|
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles: TokensFeatureToggles,
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
): GetBalanceNotEnoughForFeeWarningUseCase {
|
): GetBalanceNotEnoughForFeeWarningUseCase {
|
||||||
return GetBalanceNotEnoughForFeeWarningUseCase(currenciesRepository, dispatchers)
|
return GetBalanceNotEnoughForFeeWarningUseCase(
|
||||||
|
currenciesRepository = currenciesRepository,
|
||||||
|
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles = tokensFeatureToggles,
|
||||||
|
dispatchers = dispatchers,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
@ -343,10 +369,14 @@ internal object TokensDomainModule {
|
||||||
fun provideRefreshMultiCurrencyWalletQuotesUseCase(
|
fun provideRefreshMultiCurrencyWalletQuotesUseCase(
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||||
|
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles: TokensFeatureToggles,
|
||||||
): RefreshMultiCurrencyWalletQuotesUseCase {
|
): RefreshMultiCurrencyWalletQuotesUseCase {
|
||||||
return RefreshMultiCurrencyWalletQuotesUseCase(
|
return RefreshMultiCurrencyWalletQuotesUseCase(
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||||
|
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles = tokensFeatureToggles,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -374,6 +404,7 @@ internal object TokensDomainModule {
|
||||||
singleQuoteStatusSupplier: SingleQuoteStatusSupplier,
|
singleQuoteStatusSupplier: SingleQuoteStatusSupplier,
|
||||||
singleYieldBalanceSupplier: SingleYieldBalanceSupplier,
|
singleYieldBalanceSupplier: SingleYieldBalanceSupplier,
|
||||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||||
|
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||||
): BaseCurrenciesStatusesOperations {
|
): BaseCurrenciesStatusesOperations {
|
||||||
return CachedCurrenciesStatusesOperations(
|
return CachedCurrenciesStatusesOperations(
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
|
|
@ -388,6 +419,7 @@ internal object TokensDomainModule {
|
||||||
singleYieldBalanceSupplier = singleYieldBalanceSupplier,
|
singleYieldBalanceSupplier = singleYieldBalanceSupplier,
|
||||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||||
tokensFeatureToggles = tokensFeatureToggles,
|
tokensFeatureToggles = tokensFeatureToggles,
|
||||||
|
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -406,6 +438,7 @@ internal object TokensDomainModule {
|
||||||
singleQuoteStatusSupplier: SingleQuoteStatusSupplier,
|
singleQuoteStatusSupplier: SingleQuoteStatusSupplier,
|
||||||
singleYieldBalanceSupplier: SingleYieldBalanceSupplier,
|
singleYieldBalanceSupplier: SingleYieldBalanceSupplier,
|
||||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||||
|
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||||
): BaseCurrencyStatusOperations {
|
): BaseCurrencyStatusOperations {
|
||||||
return CachedCurrenciesStatusesOperations(
|
return CachedCurrenciesStatusesOperations(
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
|
|
@ -419,6 +452,7 @@ internal object TokensDomainModule {
|
||||||
singleQuoteStatusSupplier = singleQuoteStatusSupplier,
|
singleQuoteStatusSupplier = singleQuoteStatusSupplier,
|
||||||
singleYieldBalanceSupplier = singleYieldBalanceSupplier,
|
singleYieldBalanceSupplier = singleYieldBalanceSupplier,
|
||||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||||
|
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||||
tokensFeatureToggles = tokensFeatureToggles,
|
tokensFeatureToggles = tokensFeatureToggles,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -428,4 +462,26 @@ internal object TokensDomainModule {
|
||||||
fun provideGetCryptoCurrenciesUseCase(currenciesRepository: CurrenciesRepository): GetCryptoCurrenciesUseCase {
|
fun provideGetCryptoCurrenciesUseCase(currenciesRepository: CurrenciesRepository): GetCryptoCurrenciesUseCase {
|
||||||
return GetCryptoCurrenciesUseCase(currenciesRepository)
|
return GetCryptoCurrenciesUseCase(currenciesRepository)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideWalletBalanceFetcher(
|
||||||
|
currenciesRepository: CurrenciesRepository,
|
||||||
|
multiWalletCryptoCurrenciesFetcher: MultiWalletCryptoCurrenciesFetcher,
|
||||||
|
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||||
|
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||||
|
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||||
|
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||||
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
|
): WalletBalanceFetcher {
|
||||||
|
return WalletBalanceFetcher(
|
||||||
|
currenciesRepository = currenciesRepository,
|
||||||
|
multiWalletCryptoCurrenciesFetcher = multiWalletCryptoCurrenciesFetcher,
|
||||||
|
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||||
|
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||||
|
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||||
|
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||||
|
dispatchers = dispatchers,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,11 +4,14 @@ import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||||
import com.tangem.domain.demo.DemoConfig
|
import com.tangem.domain.demo.DemoConfig
|
||||||
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
|
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
|
||||||
import com.tangem.domain.networks.single.SingleNetworkStatusSupplier
|
import com.tangem.domain.networks.single.SingleNetworkStatusSupplier
|
||||||
|
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesSupplier
|
||||||
|
import com.tangem.domain.tokens.TokensFeatureToggles
|
||||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.transaction.FeeRepository
|
import com.tangem.domain.transaction.FeeRepository
|
||||||
import com.tangem.domain.transaction.TransactionRepository
|
import com.tangem.domain.transaction.TransactionRepository
|
||||||
import com.tangem.domain.transaction.usecase.*
|
import com.tangem.domain.transaction.usecase.*
|
||||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||||
|
import com.tangem.tap.domain.hot.TangemHotWalletSigner
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
|
|
@ -41,6 +44,7 @@ internal object TransactionDomainModule {
|
||||||
transactionRepository: TransactionRepository,
|
transactionRepository: TransactionRepository,
|
||||||
walletManagersFacade: WalletManagersFacade,
|
walletManagersFacade: WalletManagersFacade,
|
||||||
singleNetworkStatusFetcher: SingleNetworkStatusFetcher,
|
singleNetworkStatusFetcher: SingleNetworkStatusFetcher,
|
||||||
|
tangemHotWalletSignerFactory: TangemHotWalletSigner.Factory,
|
||||||
): SendTransactionUseCase {
|
): SendTransactionUseCase {
|
||||||
return SendTransactionUseCase(
|
return SendTransactionUseCase(
|
||||||
demoConfig = DemoConfig(),
|
demoConfig = DemoConfig(),
|
||||||
|
|
@ -48,6 +52,7 @@ internal object TransactionDomainModule {
|
||||||
transactionRepository = transactionRepository,
|
transactionRepository = transactionRepository,
|
||||||
walletManagersFacade = walletManagersFacade,
|
walletManagersFacade = walletManagersFacade,
|
||||||
singleNetworkStatusFetcher = singleNetworkStatusFetcher,
|
singleNetworkStatusFetcher = singleNetworkStatusFetcher,
|
||||||
|
getHotWalletSigner = tangemHotWalletSignerFactory::create,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,12 +63,16 @@ internal object TransactionDomainModule {
|
||||||
walletManagersFacade: WalletManagersFacade,
|
walletManagersFacade: WalletManagersFacade,
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
singleNetworkStatusSupplier: SingleNetworkStatusSupplier,
|
singleNetworkStatusSupplier: SingleNetworkStatusSupplier,
|
||||||
|
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles: TokensFeatureToggles,
|
||||||
): AssociateAssetUseCase {
|
): AssociateAssetUseCase {
|
||||||
return AssociateAssetUseCase(
|
return AssociateAssetUseCase(
|
||||||
cardSdkConfigRepository = cardSdkConfigRepository,
|
cardSdkConfigRepository = cardSdkConfigRepository,
|
||||||
walletManagersFacade = walletManagersFacade,
|
walletManagersFacade = walletManagersFacade,
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
singleNetworkStatusSupplier = singleNetworkStatusSupplier,
|
singleNetworkStatusSupplier = singleNetworkStatusSupplier,
|
||||||
|
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||||
|
tokensFeatureToggles = tokensFeatureToggles,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,7 @@ import com.tangem.domain.wallets.repository.WalletsRepository
|
||||||
import com.tangem.domain.wallets.usecase.*
|
import com.tangem.domain.wallets.usecase.*
|
||||||
import com.tangem.feature.wallet.presentation.wallet.domain.IsWalletNFTEnabledSyncUseCase
|
import com.tangem.feature.wallet.presentation.wallet.domain.IsWalletNFTEnabledSyncUseCase
|
||||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletNameMigrationUseCase
|
import com.tangem.feature.wallet.presentation.wallet.domain.WalletNameMigrationUseCase
|
||||||
import com.tangem.operations.attestation.OnlineCardVerifier
|
|
||||||
import com.tangem.features.nft.NFTFeatureToggles
|
|
||||||
import com.tangem.operations.attestation.CardArtworksProvider
|
import com.tangem.operations.attestation.CardArtworksProvider
|
||||||
import com.tangem.sdk.api.featuretoggles.CardSdkFeatureToggles
|
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
|
|
@ -191,28 +188,14 @@ internal object WalletsDomainModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideGetCardImageUseCase(
|
fun provideGetCardImageUseCase(cardArtworksProvider: CardArtworksProvider): GetCardImageUseCase {
|
||||||
onlineCardVerifier: OnlineCardVerifier,
|
return GetCardImageUseCase(cardArtworksProvider = cardArtworksProvider)
|
||||||
cardArtworksProvider: CardArtworksProvider,
|
|
||||||
cardSdkFeatureToggles: CardSdkFeatureToggles,
|
|
||||||
): GetCardImageUseCase {
|
|
||||||
return GetCardImageUseCase(
|
|
||||||
verifier = onlineCardVerifier,
|
|
||||||
cardArtworksProvider = cardArtworksProvider,
|
|
||||||
cardSdkFeatureToggles = cardSdkFeatureToggles,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun providesIsWalletNFTEnabledSyncUseCase(
|
fun providesIsWalletNFTEnabledSyncUseCase(walletsRepository: WalletsRepository): IsWalletNFTEnabledSyncUseCase {
|
||||||
walletsRepository: WalletsRepository,
|
return IsWalletNFTEnabledSyncUseCase(walletsRepository = walletsRepository)
|
||||||
nftFeatureToggles: NFTFeatureToggles,
|
|
||||||
): IsWalletNFTEnabledSyncUseCase {
|
|
||||||
return IsWalletNFTEnabledSyncUseCase(
|
|
||||||
walletsRepository = walletsRepository,
|
|
||||||
nftFeatureToggles = nftFeatureToggles,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.tangem.tap.di.hot
|
||||||
|
|
||||||
|
import com.tangem.hot.sdk.TangemHotSdk
|
||||||
|
import com.tangem.tap.domain.hot.HotWalletPasswordRequester
|
||||||
|
import com.tangem.tap.features.hot.DefaultHotWalletPasswordRequester
|
||||||
|
import com.tangem.tap.features.hot.TangemHotSDKProxy
|
||||||
|
import dagger.Binds
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.hilt.InstallIn
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@InstallIn(SingletonComponent::class)
|
||||||
|
internal interface TangemHotSdkModule {
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@Singleton
|
||||||
|
fun bindTangemHotSdk(proxy: TangemHotSDKProxy): TangemHotSdk
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@Singleton
|
||||||
|
fun bindHotWalletPasswordRequester(impl: DefaultHotWalletPasswordRequester): HotWalletPasswordRequester
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
package com.tangem.tap.di.routing
|
package com.tangem.tap.di.routing
|
||||||
|
|
||||||
import com.tangem.common.routing.AppRouter
|
import com.tangem.common.routing.AppRouter
|
||||||
import com.tangem.common.routing.RoutingFeatureToggle
|
|
||||||
import com.tangem.core.analytics.api.AnalyticsExceptionHandler
|
import com.tangem.core.analytics.api.AnalyticsExceptionHandler
|
||||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
|
||||||
import com.tangem.tap.routing.ProxyAppRouter
|
import com.tangem.tap.routing.ProxyAppRouter
|
||||||
import com.tangem.tap.routing.configurator.AppRouterConfig
|
import com.tangem.tap.routing.configurator.AppRouterConfig
|
||||||
import com.tangem.tap.routing.configurator.MutableAppRouterConfig
|
import com.tangem.tap.routing.configurator.MutableAppRouterConfig
|
||||||
|
|
@ -33,10 +31,4 @@ internal object AppRouterModule {
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideAppRouterConfigurator(): AppRouterConfig = MutableAppRouterConfig()
|
fun provideAppRouterConfigurator(): AppRouterConfig = MutableAppRouterConfig()
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun provideRoutingFeatureToggle(featureTogglesManager: FeatureTogglesManager): RoutingFeatureToggle {
|
|
||||||
return RoutingFeatureToggle(featureTogglesManager)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -4,8 +4,7 @@ import com.tangem.blockchain.common.Token
|
||||||
import com.tangem.blockchain.common.Wallet
|
import com.tangem.blockchain.common.Wallet
|
||||||
import com.tangem.core.analytics.Analytics
|
import com.tangem.core.analytics.Analytics
|
||||||
import com.tangem.domain.common.extensions.withMainContext
|
import com.tangem.domain.common.extensions.withMainContext
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.wallets.models.requireColdWallet
|
|
||||||
import com.tangem.tap.common.extensions.setContext
|
import com.tangem.tap.common.extensions.setContext
|
||||||
import com.tangem.tap.common.redux.global.GlobalAction
|
import com.tangem.tap.common.redux.global.GlobalAction
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
|
|
@ -35,14 +34,15 @@ class TapWalletManager(
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun loadUserWalletData(userWallet: UserWallet) {
|
private suspend fun loadUserWalletData(userWallet: UserWallet) {
|
||||||
Analytics.setContext(userWallet.requireColdWallet().scanResponse) // [REDACTED_TASK_KEY]
|
Analytics.setContext(userWallet)
|
||||||
val scanResponse = userWallet.scanResponse
|
|
||||||
|
|
||||||
tangemSdkManager.changeDisplayedCardIdNumbersCount(scanResponse)
|
if (userWallet is UserWallet.Cold) {
|
||||||
|
val scanResponse = userWallet.scanResponse
|
||||||
withMainContext {
|
tangemSdkManager.changeDisplayedCardIdNumbersCount(scanResponse)
|
||||||
// Order is important
|
withMainContext {
|
||||||
store.dispatch(GlobalAction.SaveScanResponse(scanResponse))
|
// Order is important
|
||||||
|
store.dispatch(GlobalAction.SaveScanResponse(scanResponse))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,9 @@ import com.tangem.domain.card.repository.DerivationsRepository
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.network.Network
|
import com.tangem.domain.models.network.Network
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.wallets.models.requireColdWallet
|
import com.tangem.domain.models.wallet.requireColdWallet
|
||||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||||
import com.tangem.sdk.api.TangemSdkManager
|
import com.tangem.sdk.api.TangemSdkManager
|
||||||
import com.tangem.tap.domain.tasks.UserWalletIdPreflightReadFilter
|
import com.tangem.tap.domain.tasks.UserWalletIdPreflightReadFilter
|
||||||
|
|
@ -50,7 +50,7 @@ internal class DefaultDerivationsRepository(
|
||||||
networkFactory.create(
|
networkFactory.create(
|
||||||
blockchain = Blockchain.fromNetworkId(it.value) ?: return@mapNotNull null,
|
blockchain = Blockchain.fromNetworkId(it.value) ?: return@mapNotNull null,
|
||||||
extraDerivationPath = null,
|
extraDerivationPath = null,
|
||||||
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
|
userWallet = userWallet,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -61,7 +61,11 @@ internal class DefaultDerivationsRepository(
|
||||||
userWalletsStore.getSyncOrNull(userWalletId) ?: error("User wallet not found")
|
userWalletsStore.getSyncOrNull(userWalletId) ?: error("User wallet not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
userWallet.requireColdWallet() // TODO [REDACTED_TASK_KEY]
|
if (userWallet is UserWallet.Hot) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userWallet.requireColdWallet()
|
||||||
|
|
||||||
if (!userWallet.scanResponse.card.settings.isHDWalletAllowed) {
|
if (!userWallet.scanResponse.card.settings.isHDWalletAllowed) {
|
||||||
Timber.d("Nothing to derive")
|
Timber.d("Nothing to derive")
|
||||||
|
|
@ -84,14 +88,18 @@ internal class DefaultDerivationsRepository(
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val userWallet = userWalletsStore.getSyncOrNull(userWalletId) ?: error("User wallet not found")
|
val userWallet = userWalletsStore.getSyncOrNull(userWalletId) ?: error("User wallet not found")
|
||||||
|
|
||||||
|
if (userWallet is UserWallet.Hot) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
val derivations =
|
val derivations =
|
||||||
MissedDerivationsFinder(scanResponse = userWallet.requireColdWallet().scanResponse) // TODO [REDACTED_TASK_KEY]
|
MissedDerivationsFinder(scanResponse = userWallet.requireColdWallet().scanResponse)
|
||||||
.findByNetworks(
|
.findByNetworks(
|
||||||
networksWithDerivationPath.mapNotNull { (backendId, extraDerivationPath) ->
|
networksWithDerivationPath.mapNotNull { (backendId, extraDerivationPath) ->
|
||||||
networkFactory.create(
|
networkFactory.create(
|
||||||
blockchain = Blockchain.fromNetworkId(backendId) ?: return@mapNotNull null,
|
blockchain = Blockchain.fromNetworkId(backendId) ?: return@mapNotNull null,
|
||||||
extraDerivationPath = extraDerivationPath,
|
extraDerivationPath = extraDerivationPath,
|
||||||
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
|
userWallet = userWallet,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import com.tangem.common.core.UserCodeRequestPolicy
|
||||||
import com.tangem.domain.card.ResetCardUseCase
|
import com.tangem.domain.card.ResetCardUseCase
|
||||||
import com.tangem.domain.card.ResetCardUserCodeParams
|
import com.tangem.domain.card.ResetCardUserCodeParams
|
||||||
import com.tangem.domain.card.models.ResetCardError
|
import com.tangem.domain.card.models.ResetCardError
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.sdk.api.TangemSdkManager
|
import com.tangem.sdk.api.TangemSdkManager
|
||||||
|
|
||||||
internal class DefaultResetCardUseCase(
|
internal class DefaultResetCardUseCase(
|
||||||
|
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
package com.tangem.tap.domain.extensions
|
|
||||||
|
|
||||||
import com.tangem.common.extensions.toHexString
|
|
||||||
import com.tangem.common.services.Result
|
|
||||||
import com.tangem.domain.common.TwinCardNumber
|
|
||||||
import com.tangem.domain.common.getTwinCardNumber
|
|
||||||
import com.tangem.domain.models.scan.CardDTO
|
|
||||||
import com.tangem.domain.wallets.models.Artwork
|
|
||||||
import com.tangem.operations.attestation.CardArtworksProvider
|
|
||||||
import com.tangem.operations.attestation.OnlineCardVerifier
|
|
||||||
import com.tangem.operations.attestation.api.models.CardVerifyAndGetInfo
|
|
||||||
|
|
||||||
fun CardDTO.signedHashesCount(): Int {
|
|
||||||
return wallets.sumOf { it.totalSignedHashes ?: 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun CardDTO.getOrLoadCardArtworkUrl(
|
|
||||||
cardInfo: Result<CardVerifyAndGetInfo.Response.Item>? = null,
|
|
||||||
onlineCardVerifier: OnlineCardVerifier,
|
|
||||||
): String {
|
|
||||||
fun ifAnyError(): String {
|
|
||||||
return when {
|
|
||||||
cardId.startsWith(Artwork.SERGIO_CARD_ID) -> Artwork.SERGIO_CARD_URL
|
|
||||||
cardId.startsWith(Artwork.MARTA_CARD_ID) -> Artwork.MARTA_CARD_URL
|
|
||||||
else -> {
|
|
||||||
when (getTwinCardNumber()) {
|
|
||||||
TwinCardNumber.First -> Artwork.TWIN_CARD_1_URL
|
|
||||||
TwinCardNumber.Second -> Artwork.TWIN_CARD_2_URL
|
|
||||||
else -> Artwork.DEFAULT_IMG_URL
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return when (val cardInfoResult = cardInfo ?: onlineCardVerifier.getCardInfo(cardId, cardPublicKey)) {
|
|
||||||
is Result.Success -> {
|
|
||||||
val artworkId = cardInfoResult.data.artwork?.id
|
|
||||||
if (artworkId.isNullOrEmpty()) {
|
|
||||||
ifAnyError()
|
|
||||||
} else {
|
|
||||||
CardArtworksProvider.getUrlForArtwork(cardId, cardPublicKey.toHexString(), artworkId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
is Result.Failure -> ifAnyError()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
113
app/src/main/java/com/tangem/tap/domain/hot/HotWalletAccessor.kt
Normal file
113
app/src/main/java/com/tangem/tap/domain/hot/HotWalletAccessor.kt
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
package com.tangem.tap.domain.hot
|
||||||
|
|
||||||
|
import com.tangem.common.core.TangemSdkError
|
||||||
|
import com.tangem.features.hotwallet.HotWalletPasswordRequester
|
||||||
|
import com.tangem.hot.sdk.TangemHotSdk
|
||||||
|
import com.tangem.hot.sdk.exception.WrongPasswordException
|
||||||
|
import com.tangem.hot.sdk.model.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class HotWalletAccessor @Inject constructor(
|
||||||
|
private val tangemHotSdk: TangemHotSdk,
|
||||||
|
private val hotWalletPasswordRequester: HotWalletPasswordRequester,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend fun signHashes(hotWalletId: HotWalletId, dataToSign: List<DataToSign>): List<SignedData> {
|
||||||
|
val auth = when (hotWalletId.authType) {
|
||||||
|
HotWalletId.AuthType.NoPassword -> HotAuth.NoAuth
|
||||||
|
HotWalletId.AuthType.Password -> requestPassword(false)
|
||||||
|
HotWalletId.AuthType.Biometry -> HotAuth.Biometry
|
||||||
|
}
|
||||||
|
|
||||||
|
return runCatchingSdkErrors(hotWalletId, auth) {
|
||||||
|
tangemHotSdk.signHashes(
|
||||||
|
unlockHotWallet = UnlockHotWallet(
|
||||||
|
walletId = hotWalletId,
|
||||||
|
auth = it,
|
||||||
|
),
|
||||||
|
dataToSign = dataToSign,
|
||||||
|
).also {
|
||||||
|
hotWalletPasswordRequester.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun <T> runCatchingSdkErrors(
|
||||||
|
hotWalletId: HotWalletId,
|
||||||
|
auth: HotAuth,
|
||||||
|
block: suspend (auth: HotAuth) -> T,
|
||||||
|
): T {
|
||||||
|
return runCatchingWrongPassInternal(
|
||||||
|
originalAuth = auth,
|
||||||
|
auth = auth,
|
||||||
|
block = { blockAuth ->
|
||||||
|
block(blockAuth).also {
|
||||||
|
// TODO [REDACTED_TASK_KEY] if user has biometry enabled, we set it as the new auth method
|
||||||
|
if (blockAuth is HotAuth.Password /*&& has biometry enabled */) {
|
||||||
|
tangemHotSdk.changeAuth(
|
||||||
|
unlockHotWallet = UnlockHotWallet(
|
||||||
|
walletId = hotWalletId,
|
||||||
|
auth = blockAuth,
|
||||||
|
),
|
||||||
|
auth = HotAuth.Biometry,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun <T> runCatchingWrongPassInternal(
|
||||||
|
originalAuth: HotAuth,
|
||||||
|
auth: HotAuth,
|
||||||
|
block: suspend (auth: HotAuth) -> T,
|
||||||
|
): T = runCatching {
|
||||||
|
block(auth)
|
||||||
|
}.getOrElse { exception ->
|
||||||
|
if (auth is HotAuth.Biometry && exception.isBiometryError()) {
|
||||||
|
// fallback to password if biometry fails
|
||||||
|
val passAuth = requestPassword(true)
|
||||||
|
|
||||||
|
return@getOrElse runCatchingWrongPassInternal(
|
||||||
|
originalAuth = originalAuth,
|
||||||
|
auth = passAuth,
|
||||||
|
block = block,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exception !is WrongPasswordException) {
|
||||||
|
throw exception
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the exception is a wrong password, we need to request the password again
|
||||||
|
|
||||||
|
hotWalletPasswordRequester.wrongPassword()
|
||||||
|
val passResult = requestPassword(originalAuth is HotAuth.Biometry)
|
||||||
|
|
||||||
|
runCatchingWrongPassInternal(
|
||||||
|
originalAuth = originalAuth,
|
||||||
|
auth = passResult,
|
||||||
|
block = block,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun requestPassword(hasBiometry: Boolean): HotAuth {
|
||||||
|
return hotWalletPasswordRequester.requestPassword(hasBiometry).toAuth() ?: throw TangemSdkError.UserCancelled()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Throwable.isBiometryError(): Boolean {
|
||||||
|
return this is TangemSdkError.AuthenticationFailed ||
|
||||||
|
this is TangemSdkError.AuthenticationCanceled ||
|
||||||
|
this is TangemSdkError.AuthenticationLockout ||
|
||||||
|
this is TangemSdkError.AuthenticationUnavailable ||
|
||||||
|
this is TangemSdkError.AuthenticationAlreadyInProgress ||
|
||||||
|
this is TangemSdkError.AuthenticationNotInitialized ||
|
||||||
|
this is TangemSdkError.AuthenticationPermanentLockout
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun HotWalletPasswordRequester.Result.toAuth() = when (this) {
|
||||||
|
HotWalletPasswordRequester.Result.UseBiometry -> HotAuth.Biometry
|
||||||
|
HotWalletPasswordRequester.Result.Dismiss -> null
|
||||||
|
is HotWalletPasswordRequester.Result.EnteredPassword -> this.password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.tangem.tap.domain.hot
|
||||||
|
|
||||||
|
import com.tangem.hot.sdk.model.HotAuth
|
||||||
|
import com.tangem.hot.sdk.model.HotWalletId
|
||||||
|
|
||||||
|
interface HotWalletPasswordRequester {
|
||||||
|
|
||||||
|
suspend fun requestPassword(hotWalletId: HotWalletId): HotAuth.Password
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
package com.tangem.tap.domain.hot
|
||||||
|
|
||||||
|
import com.tangem.blockchain.common.TransactionSigner
|
||||||
|
import com.tangem.blockchain.common.Wallet
|
||||||
|
import com.tangem.common.CompletionResult
|
||||||
|
import com.tangem.common.core.TangemSdkError
|
||||||
|
import com.tangem.common.map
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.hot.sdk.model.DataToSign
|
||||||
|
import com.tangem.operations.sign.SignData
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedFactory
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
|
||||||
|
class TangemHotSigner @AssistedInject constructor(
|
||||||
|
@Assisted private val userWallet: UserWallet.Hot,
|
||||||
|
private val hotWalletAccessor: HotWalletAccessor,
|
||||||
|
) : TransactionSigner {
|
||||||
|
|
||||||
|
override suspend fun sign(hash: ByteArray, publicKey: Wallet.PublicKey): CompletionResult<ByteArray> {
|
||||||
|
return sign(listOf(hash), publicKey).map { it.first() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun sign(
|
||||||
|
hashes: List<ByteArray>,
|
||||||
|
publicKey: Wallet.PublicKey,
|
||||||
|
): CompletionResult<List<ByteArray>> {
|
||||||
|
val wallet = userWallet.wallets.orEmpty().firstOrNull { it.publicKey == publicKey.seedKey }
|
||||||
|
?: return CompletionResult.Failure(
|
||||||
|
TangemSdkError.ExceptionError(IllegalStateException("wallet is locked")),
|
||||||
|
)
|
||||||
|
|
||||||
|
val result = hotWalletAccessor.signHashes(
|
||||||
|
hotWalletId = userWallet.hotWalletId,
|
||||||
|
dataToSign = listOf(
|
||||||
|
DataToSign(
|
||||||
|
curve = wallet.curve,
|
||||||
|
hashes = hashes,
|
||||||
|
derivationPath = publicKey.derivationPath,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
return CompletionResult.Success(result.map { it.signatures }.flatten())
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun multiSign(
|
||||||
|
dataToSign: List<SignData>,
|
||||||
|
publicKey: Wallet.PublicKey,
|
||||||
|
): CompletionResult<Map<ByteArray, ByteArray>> {
|
||||||
|
val result = hotWalletAccessor.signHashes(
|
||||||
|
hotWalletId = userWallet.hotWalletId,
|
||||||
|
dataToSign = dataToSign.map { signData ->
|
||||||
|
val wallet = userWallet.wallets.orEmpty().firstOrNull { it.publicKey == signData.publicKey }
|
||||||
|
?: return CompletionResult.Failure(
|
||||||
|
TangemSdkError.ExceptionError(IllegalStateException("wallet is locked")),
|
||||||
|
)
|
||||||
|
|
||||||
|
DataToSign(
|
||||||
|
curve = wallet.curve,
|
||||||
|
hashes = listOf(signData.hash),
|
||||||
|
derivationPath = signData.derivationPath,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return CompletionResult.Success(
|
||||||
|
result.mapIndexed { index, data ->
|
||||||
|
dataToSign[index].publicKey to data.signatures.first()
|
||||||
|
}.toMap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
interface Factory {
|
||||||
|
fun create(@Assisted userWallet: UserWallet.Hot): TangemHotSigner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
package com.tangem.tap.domain.hot
|
||||||
|
|
||||||
|
import com.tangem.blockchain.common.TransactionSigner
|
||||||
|
import com.tangem.blockchain.common.Wallet
|
||||||
|
import com.tangem.common.CompletionResult
|
||||||
|
import com.tangem.common.core.TangemSdkError
|
||||||
|
import com.tangem.common.map
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.hot.sdk.model.DataToSign
|
||||||
|
import com.tangem.operations.sign.SignData
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedFactory
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class TangemHotWalletSigner @AssistedInject constructor(
|
||||||
|
@Assisted private val userWallet: UserWallet.Hot,
|
||||||
|
private val hotWalletAccessor: HotWalletAccessor,
|
||||||
|
) : TransactionSigner {
|
||||||
|
|
||||||
|
override suspend fun sign(hash: ByteArray, publicKey: Wallet.PublicKey): CompletionResult<ByteArray> {
|
||||||
|
return sign(listOf(hash), publicKey).map { it.first() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun sign(
|
||||||
|
hashes: List<ByteArray>,
|
||||||
|
publicKey: Wallet.PublicKey,
|
||||||
|
): CompletionResult<List<ByteArray>> {
|
||||||
|
val wallet = userWallet.wallets.orEmpty().firstOrNull { it.publicKey.contentEquals(publicKey.seedKey) }
|
||||||
|
?: return CompletionResult.Failure(
|
||||||
|
TangemSdkError.ExceptionError(IllegalStateException("wallet is locked")),
|
||||||
|
)
|
||||||
|
|
||||||
|
val result = runCatching {
|
||||||
|
hotWalletAccessor.signHashes(
|
||||||
|
hotWalletId = userWallet.hotWalletId,
|
||||||
|
dataToSign = listOf(
|
||||||
|
DataToSign(
|
||||||
|
curve = wallet.curve,
|
||||||
|
hashes = hashes,
|
||||||
|
derivationPath = publicKey.derivationPath,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}.getOrElse {
|
||||||
|
Timber.e(it)
|
||||||
|
return if (it is TangemSdkError) {
|
||||||
|
CompletionResult.Failure(it)
|
||||||
|
} else {
|
||||||
|
CompletionResult.Failure(TangemSdkError.ExceptionError(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CompletionResult.Success(result.map { it.signatures }.flatten())
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun multiSign(
|
||||||
|
dataToSign: List<SignData>,
|
||||||
|
publicKey: Wallet.PublicKey,
|
||||||
|
): CompletionResult<Map<ByteArray, ByteArray>> {
|
||||||
|
val result = runCatching {
|
||||||
|
hotWalletAccessor.signHashes(
|
||||||
|
hotWalletId = userWallet.hotWalletId,
|
||||||
|
dataToSign = dataToSign.map { signData ->
|
||||||
|
val wallet =
|
||||||
|
userWallet.wallets.orEmpty().firstOrNull { it.publicKey.contentEquals(signData.publicKey) }
|
||||||
|
?: return CompletionResult.Failure(
|
||||||
|
TangemSdkError.ExceptionError(IllegalStateException("wallet is locked")),
|
||||||
|
)
|
||||||
|
|
||||||
|
DataToSign(
|
||||||
|
curve = wallet.curve,
|
||||||
|
hashes = listOf(signData.hash),
|
||||||
|
derivationPath = signData.derivationPath,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}.getOrElse {
|
||||||
|
Timber.e(it)
|
||||||
|
return if (it is TangemSdkError) {
|
||||||
|
CompletionResult.Failure(it)
|
||||||
|
} else {
|
||||||
|
CompletionResult.Failure(TangemSdkError.ExceptionError(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CompletionResult.Success(
|
||||||
|
result.mapIndexed { index, data ->
|
||||||
|
dataToSign[index].publicKey to data.signatures.first()
|
||||||
|
}.toMap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
interface Factory {
|
||||||
|
fun create(@Assisted userWallet: UserWallet.Hot): TangemHotWalletSigner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,10 +23,10 @@ import com.tangem.domain.common.util.cardTypesResolver
|
||||||
import com.tangem.domain.common.util.derivationStyleProvider
|
import com.tangem.domain.common.util.derivationStyleProvider
|
||||||
import com.tangem.domain.models.scan.CardDTO
|
import com.tangem.domain.models.scan.CardDTO
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.visa.model.VisaActivationInput
|
import com.tangem.domain.visa.model.VisaActivationInput
|
||||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||||
import com.tangem.domain.visa.model.VisaSignedDataByCustomerWallet
|
import com.tangem.domain.visa.model.VisaSignedDataByCustomerWallet
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
|
||||||
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
|
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
|
||||||
import com.tangem.operations.ScanTask
|
import com.tangem.operations.ScanTask
|
||||||
import com.tangem.operations.derivation.DerivationTaskResponse
|
import com.tangem.operations.derivation.DerivationTaskResponse
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,10 @@ import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||||
import com.tangem.domain.models.scan.CardDTO
|
import com.tangem.domain.models.scan.CardDTO
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.visa.model.VisaActivationInput
|
import com.tangem.domain.visa.model.VisaActivationInput
|
||||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||||
import com.tangem.domain.visa.model.VisaSignedDataByCustomerWallet
|
import com.tangem.domain.visa.model.VisaSignedDataByCustomerWallet
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
|
||||||
import com.tangem.operations.derivation.DerivationTaskResponse
|
import com.tangem.operations.derivation.DerivationTaskResponse
|
||||||
import com.tangem.operations.preflightread.PreflightReadFilter
|
import com.tangem.operations.preflightread.PreflightReadFilter
|
||||||
import com.tangem.operations.wallet.CreateWalletResponse
|
import com.tangem.operations.wallet.CreateWalletResponse
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,13 @@ object WalletMockContent : MockContent {
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
|
DerivationPath("m/84'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||||
|
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||||
|
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||||
|
depth = 0,
|
||||||
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
|
childNumber = 0,
|
||||||
|
),
|
||||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import com.tangem.common.card.Card
|
||||||
import com.tangem.common.core.SessionEnvironment
|
import com.tangem.common.core.SessionEnvironment
|
||||||
import com.tangem.common.core.TangemSdkError
|
import com.tangem.common.core.TangemSdkError
|
||||||
import com.tangem.domain.models.scan.CardDTO
|
import com.tangem.domain.models.scan.CardDTO
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
|
||||||
import com.tangem.operations.preflightread.PreflightReadFilter
|
import com.tangem.operations.preflightread.PreflightReadFilter
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ import com.tangem.datasource.local.token.UserTokensResponseStore
|
||||||
import com.tangem.domain.common.DerivationStyleProvider
|
import com.tangem.domain.common.DerivationStyleProvider
|
||||||
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
|
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
|
||||||
import com.tangem.domain.models.scan.CardDTO
|
import com.tangem.domain.models.scan.CardDTO
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
|
||||||
import com.tangem.tap.features.demo.DemoHelper
|
import com.tangem.tap.features.demo.DemoHelper
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import com.tangem.common.CompletionResult
|
||||||
import com.tangem.common.core.CardSession
|
import com.tangem.common.core.CardSession
|
||||||
import com.tangem.common.core.CardSessionRunnable
|
import com.tangem.common.core.CardSessionRunnable
|
||||||
import com.tangem.common.core.CompletionCallback
|
import com.tangem.common.core.CompletionCallback
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.operations.PreflightReadMode
|
import com.tangem.operations.PreflightReadMode
|
||||||
import com.tangem.operations.PreflightReadTask
|
import com.tangem.operations.PreflightReadTask
|
||||||
import com.tangem.tap.domain.tasks.UserWalletIdPreflightReadFilter
|
import com.tangem.tap.domain.tasks.UserWalletIdPreflightReadFilter
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,6 @@ internal class DefaultTokensFeatureToggles(
|
||||||
private val featureTogglesManager: FeatureTogglesManager,
|
private val featureTogglesManager: FeatureTogglesManager,
|
||||||
) : TokensFeatureToggles {
|
) : TokensFeatureToggles {
|
||||||
|
|
||||||
override val isStakingLoadingRefactoringEnabled: Boolean
|
|
||||||
get() = featureTogglesManager.isFeatureEnabled(name = "STAKING_LOADING_REFACTORING_ENABLED")
|
|
||||||
|
|
||||||
override val isWalletBalanceFetcherEnabled: Boolean
|
override val isWalletBalanceFetcherEnabled: Boolean
|
||||||
get() = featureTogglesManager.isFeatureEnabled(name = "WALLET_BALANCE_FETCHER_ENABLED")
|
get() = featureTogglesManager.isFeatureEnabled(name = "WALLET_BALANCE_FETCHER_ENABLED")
|
||||||
}
|
}
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
package com.tangem.tap.domain.userWalletList.implementation
|
package com.tangem.tap.domain.userWalletList.implementation
|
||||||
|
|
||||||
import com.tangem.common.*
|
import com.tangem.common.*
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
import com.tangem.domain.models.wallet.isLocked
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager.Lockable.UnlockType
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager.Lockable.UnlockType
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
|
||||||
import com.tangem.domain.wallets.models.isLocked
|
|
||||||
import com.tangem.domain.wallets.models.requireColdWallet
|
|
||||||
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
||||||
import com.tangem.tap.domain.userWalletList.repository.SelectedUserWalletRepository
|
import com.tangem.tap.domain.userWalletList.repository.SelectedUserWalletRepository
|
||||||
import com.tangem.tap.domain.userWalletList.repository.UserWalletsKeysRepository
|
import com.tangem.tap.domain.userWalletList.repository.UserWalletsKeysRepository
|
||||||
|
|
@ -213,8 +212,7 @@ internal class BiometricUserWalletsListManager(
|
||||||
changeSelectedUserWallet: Boolean,
|
changeSelectedUserWallet: Boolean,
|
||||||
canOverridePublicInfo: Boolean,
|
canOverridePublicInfo: Boolean,
|
||||||
): CompletionResult<Unit> {
|
): CompletionResult<Unit> {
|
||||||
userWallet.requireColdWallet() // TODO [REDACTED_TASK_KEY]
|
val encryptionKey = userWallet.encryptionKey
|
||||||
val encryptionKey = userWallet.scanResponse.card.encryptionKey
|
|
||||||
?.let { UserWalletEncryptionKey(userWallet.walletId, it) }
|
?.let { UserWalletEncryptionKey(userWallet.walletId, it) }
|
||||||
?: return CompletionResult.Success(Unit) // No encryption key, no need to save
|
?: return CompletionResult.Success(Unit) // No encryption key, no need to save
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@ import com.tangem.common.CompletionResult
|
||||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||||
import com.tangem.datasource.local.preferences.utils.get
|
import com.tangem.datasource.local.preferences.utils.get
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@ package com.tangem.tap.domain.userWalletList.implementation
|
||||||
|
|
||||||
import com.tangem.common.CompletionResult
|
import com.tangem.common.CompletionResult
|
||||||
import com.tangem.common.catching
|
import com.tangem.common.catching
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.tangem.tap.domain.userWalletList.model
|
package com.tangem.tap.domain.userWalletList.model
|
||||||
|
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
internal data class UserWalletEncryptionKey(
|
internal data class UserWalletEncryptionKey(
|
||||||
|
|
|
||||||
|
|
@ -2,31 +2,44 @@ package com.tangem.tap.domain.userWalletList.model
|
||||||
|
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
|
import com.tangem.domain.models.MobileWallet
|
||||||
import com.tangem.domain.models.scan.CardDTO
|
import com.tangem.domain.models.scan.CardDTO
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.visa.model.VisaCardActivationStatus
|
import com.tangem.domain.visa.model.VisaCardActivationStatus
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.hot.sdk.model.HotWalletId
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
internal data class UserWalletSensitiveInformation(
|
internal data class UserWalletSensitiveInformation(
|
||||||
|
// Cold
|
||||||
@Json(name = "wallets")
|
@Json(name = "wallets")
|
||||||
val wallets: List<CardDTO.Wallet>,
|
val wallets: List<CardDTO.Wallet>?,
|
||||||
@Json(name = "visaCardActivationStatus")
|
@Json(name = "visaCardActivationStatus")
|
||||||
val visaCardActivationStatus: VisaCardActivationStatus? = null,
|
val visaCardActivationStatus: VisaCardActivationStatus? = null,
|
||||||
|
// Hot
|
||||||
|
@Json(name = "mobileWallets")
|
||||||
|
val mobileWallets: List<MobileWallet>? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
internal data class UserWalletPublicInformation(
|
internal data class UserWalletPublicInformation(
|
||||||
|
// Common
|
||||||
@Json(name = "name")
|
@Json(name = "name")
|
||||||
val name: String,
|
val name: String,
|
||||||
@Json(name = "walletId")
|
@Json(name = "walletId")
|
||||||
val walletId: UserWalletId,
|
val walletId: UserWalletId,
|
||||||
|
// Cold
|
||||||
@Json(name = "cardsInWallet")
|
@Json(name = "cardsInWallet")
|
||||||
val cardsInWallet: Set<String>,
|
val cardsInWallet: Set<String>,
|
||||||
@Json(name = "scanResponse")
|
@Json(name = "scanResponse")
|
||||||
val scanResponse: ScanResponse,
|
val scanResponse: ScanResponse?,
|
||||||
@Json(name = "isMultiCurrency")
|
@Json(name = "isMultiCurrency")
|
||||||
val isMultiCurrency: Boolean,
|
val isMultiCurrency: Boolean,
|
||||||
@Json(name = "hasBackupError")
|
@Json(name = "hasBackupError")
|
||||||
val hasBackupError: Boolean = false,
|
val hasBackupError: Boolean = false,
|
||||||
|
// Hot
|
||||||
|
@Json(name = "hotWalletId")
|
||||||
|
val hotWalletId: HotWalletId? = null,
|
||||||
|
@Json(name = "backedUp")
|
||||||
|
val backedUp: Boolean? = null,
|
||||||
)
|
)
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package com.tangem.tap.domain.userWalletList.repository
|
package com.tangem.tap.domain.userWalletList.repository
|
||||||
|
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
|
||||||
internal interface SelectedUserWalletRepository {
|
internal interface SelectedUserWalletRepository {
|
||||||
suspend fun get(): UserWalletId?
|
suspend fun get(): UserWalletId?
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.tangem.tap.domain.userWalletList.repository
|
package com.tangem.tap.domain.userWalletList.repository
|
||||||
|
|
||||||
import com.tangem.common.CompletionResult
|
import com.tangem.common.CompletionResult
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
||||||
|
|
||||||
internal interface UserWalletsKeysRepository {
|
internal interface UserWalletsKeysRepository {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package com.tangem.tap.domain.userWalletList.repository
|
package com.tangem.tap.domain.userWalletList.repository
|
||||||
|
|
||||||
import com.tangem.common.CompletionResult
|
import com.tangem.common.CompletionResult
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.tap.domain.userWalletList.model.UserWalletPublicInformation
|
import com.tangem.tap.domain.userWalletList.model.UserWalletPublicInformation
|
||||||
|
|
||||||
internal interface UserWalletsPublicInformationRepository {
|
internal interface UserWalletsPublicInformationRepository {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package com.tangem.tap.domain.userWalletList.repository
|
package com.tangem.tap.domain.userWalletList.repository
|
||||||
|
|
||||||
import com.tangem.common.CompletionResult
|
import com.tangem.common.CompletionResult
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
||||||
import com.tangem.tap.domain.userWalletList.model.UserWalletSensitiveInformation
|
import com.tangem.tap.domain.userWalletList.model.UserWalletSensitiveInformation
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ import com.tangem.common.services.secure.SecureStorage
|
||||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||||
import com.tangem.core.analytics.models.AnalyticsParam
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
import com.tangem.core.analytics.models.Basic
|
import com.tangem.core.analytics.models.Basic
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
|
||||||
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
||||||
import com.tangem.tap.domain.userWalletList.repository.UserWalletsKeysRepository
|
import com.tangem.tap.domain.userWalletList.repository.UserWalletsKeysRepository
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.tangem.tap.domain.userWalletList.repository.implementation
|
package com.tangem.tap.domain.userWalletList.repository.implementation
|
||||||
|
|
||||||
import com.tangem.common.services.secure.SecureStorage
|
import com.tangem.common.services.secure.SecureStorage
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.tap.domain.userWalletList.repository.SelectedUserWalletRepository
|
import com.tangem.tap.domain.userWalletList.repository.SelectedUserWalletRepository
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ import com.tangem.common.CompletionResult
|
||||||
import com.tangem.common.catching
|
import com.tangem.common.catching
|
||||||
import com.tangem.common.flatMap
|
import com.tangem.common.flatMap
|
||||||
import com.tangem.common.services.secure.SecureStorage
|
import com.tangem.common.services.secure.SecureStorage
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.tap.domain.userWalletList.model.UserWalletPublicInformation
|
import com.tangem.tap.domain.userWalletList.model.UserWalletPublicInformation
|
||||||
import com.tangem.tap.domain.userWalletList.repository.UserWalletsPublicInformationRepository
|
import com.tangem.tap.domain.userWalletList.repository.UserWalletsPublicInformationRepository
|
||||||
import com.tangem.tap.domain.userWalletList.utils.publicInformation
|
import com.tangem.tap.domain.userWalletList.utils.publicInformation
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ import com.tangem.common.CompletionResult
|
||||||
import com.tangem.common.catching
|
import com.tangem.common.catching
|
||||||
import com.tangem.common.services.secure.SecureStorage
|
import com.tangem.common.services.secure.SecureStorage
|
||||||
import com.tangem.crypto.operations.AESCipherOperations
|
import com.tangem.crypto.operations.AESCipherOperations
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.tap.common.extensions.filterNotNull
|
import com.tangem.tap.common.extensions.filterNotNull
|
||||||
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
||||||
import com.tangem.tap.domain.userWalletList.model.UserWalletSensitiveInformation
|
import com.tangem.tap.domain.userWalletList.model.UserWalletSensitiveInformation
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
package com.tangem.tap.domain.userWalletList.utils
|
package com.tangem.tap.domain.userWalletList.utils
|
||||||
|
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
import com.tangem.domain.models.wallet.isMultiCurrency
|
||||||
import com.tangem.tap.domain.userWalletList.model.UserWalletPublicInformation
|
import com.tangem.tap.domain.userWalletList.model.UserWalletPublicInformation
|
||||||
import com.tangem.tap.domain.userWalletList.model.UserWalletSensitiveInformation
|
import com.tangem.tap.domain.userWalletList.model.UserWalletSensitiveInformation
|
||||||
|
|
||||||
|
|
@ -10,8 +11,12 @@ internal val UserWallet.sensitiveInformation: UserWalletSensitiveInformation
|
||||||
is UserWallet.Cold -> UserWalletSensitiveInformation(
|
is UserWallet.Cold -> UserWalletSensitiveInformation(
|
||||||
wallets = scanResponse.card.wallets,
|
wallets = scanResponse.card.wallets,
|
||||||
visaCardActivationStatus = scanResponse.visaCardActivationStatus,
|
visaCardActivationStatus = scanResponse.visaCardActivationStatus,
|
||||||
|
mobileWallets = null,
|
||||||
|
)
|
||||||
|
is UserWallet.Hot -> UserWalletSensitiveInformation(
|
||||||
|
wallets = null,
|
||||||
|
mobileWallets = this.wallets,
|
||||||
)
|
)
|
||||||
is UserWallet.Hot -> TODO("[REDACTED_TASK_KEY]")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val UserWallet.publicInformation: UserWalletPublicInformation
|
internal val UserWallet.publicInformation: UserWalletPublicInformation
|
||||||
|
|
@ -28,19 +33,39 @@ internal val UserWallet.publicInformation: UserWalletPublicInformation
|
||||||
visaCardActivationStatus = null,
|
visaCardActivationStatus = null,
|
||||||
),
|
),
|
||||||
hasBackupError = hasBackupError,
|
hasBackupError = hasBackupError,
|
||||||
|
hotWalletId = null,
|
||||||
|
backedUp = null,
|
||||||
|
)
|
||||||
|
is UserWallet.Hot -> UserWalletPublicInformation(
|
||||||
|
name = name,
|
||||||
|
walletId = walletId,
|
||||||
|
isMultiCurrency = isMultiCurrency,
|
||||||
|
cardsInWallet = emptySet(),
|
||||||
|
scanResponse = null,
|
||||||
|
hotWalletId = hotWalletId,
|
||||||
|
backedUp = backedUp,
|
||||||
)
|
)
|
||||||
is UserWallet.Hot -> TODO("[REDACTED_TASK_KEY]")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun UserWalletPublicInformation.toUserWallet(): UserWallet {
|
internal fun UserWalletPublicInformation.toUserWallet(): UserWallet {
|
||||||
return UserWallet.Cold(
|
return if (hotWalletId != null) {
|
||||||
name = name,
|
UserWallet.Hot(
|
||||||
walletId = walletId,
|
name = name,
|
||||||
cardsInWallet = cardsInWallet,
|
walletId = walletId,
|
||||||
scanResponse = scanResponse,
|
hotWalletId = hotWalletId,
|
||||||
isMultiCurrency = isMultiCurrency,
|
wallets = null,
|
||||||
hasBackupError = hasBackupError,
|
backedUp = backedUp!!,
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
UserWallet.Cold(
|
||||||
|
name = name,
|
||||||
|
walletId = walletId,
|
||||||
|
cardsInWallet = cardsInWallet,
|
||||||
|
scanResponse = scanResponse!!,
|
||||||
|
isMultiCurrency = isMultiCurrency,
|
||||||
|
hasBackupError = hasBackupError,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun List<UserWalletPublicInformation>.toUserWallets(): List<UserWallet> {
|
internal fun List<UserWalletPublicInformation>.toUserWallets(): List<UserWallet> {
|
||||||
|
|
@ -53,13 +78,15 @@ internal fun UserWallet.updateWith(sensitiveInformation: UserWalletSensitiveInfo
|
||||||
copy(
|
copy(
|
||||||
scanResponse = scanResponse.copy(
|
scanResponse = scanResponse.copy(
|
||||||
card = scanResponse.card.copy(
|
card = scanResponse.card.copy(
|
||||||
wallets = sensitiveInformation.wallets,
|
wallets = sensitiveInformation.wallets!!,
|
||||||
),
|
),
|
||||||
visaCardActivationStatus = sensitiveInformation.visaCardActivationStatus,
|
visaCardActivationStatus = sensitiveInformation.visaCardActivationStatus,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is UserWallet.Hot -> TODO("[REDACTED_TASK_KEY]")
|
is UserWallet.Hot -> copy(
|
||||||
|
wallets = sensitiveInformation.mobileWallets,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,5 +117,5 @@ internal fun UserWallet.lock(): UserWallet = when (this) {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is UserWallet.Hot -> TODO("[REDACTED_TASK_KEY]")
|
is UserWallet.Hot -> copy(wallets = null)
|
||||||
}
|
}
|
||||||
|
|
@ -1,11 +1,16 @@
|
||||||
package com.tangem.tap.domain.userWalletList.utils
|
package com.tangem.tap.domain.userWalletList.utils
|
||||||
|
|
||||||
import com.tangem.common.extensions.calculateSha256
|
import com.tangem.common.extensions.calculateSha256
|
||||||
import com.tangem.domain.models.scan.CardDTO
|
|
||||||
import com.tangem.domain.common.extensions.calculateHmacSha256
|
import com.tangem.domain.common.extensions.calculateHmacSha256
|
||||||
|
import com.tangem.domain.models.MobileWallet
|
||||||
|
import com.tangem.domain.models.scan.CardDTO
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
|
||||||
internal val CardDTO.encryptionKey: ByteArray?
|
internal val UserWallet.encryptionKey: ByteArray?
|
||||||
get() = findPublicKey(wallets)?.let { calculateEncryptionKey(it) }
|
get() = when (this) {
|
||||||
|
is UserWallet.Cold -> findPublicKey(this.scanResponse.card.wallets)
|
||||||
|
is UserWallet.Hot -> findPublicKey(this.wallets.orEmpty())
|
||||||
|
}?.let { calculateEncryptionKey(it) }
|
||||||
|
|
||||||
private fun calculateEncryptionKey(publicKey: ByteArray): ByteArray {
|
private fun calculateEncryptionKey(publicKey: ByteArray): ByteArray {
|
||||||
val message = MESSAGE_FOR_ENCRYPTION_KEY.toByteArray()
|
val message = MESSAGE_FOR_ENCRYPTION_KEY.toByteArray()
|
||||||
|
|
@ -15,8 +20,12 @@ private fun calculateEncryptionKey(publicKey: ByteArray): ByteArray {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findPublicKey(wallets: List<CardDTO.Wallet>): ByteArray? {
|
private fun findPublicKey(wallets: List<CardDTO.Wallet>): ByteArray? {
|
||||||
return wallets.firstOrNull()
|
return wallets.firstOrNull()?.publicKey
|
||||||
?.publicKey
|
}
|
||||||
|
|
||||||
|
@JvmName("findPublicKeyInMobileWallets")
|
||||||
|
private fun findPublicKey(wallets: List<MobileWallet>): ByteArray? {
|
||||||
|
return wallets.firstOrNull()?.publicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val MESSAGE_FOR_ENCRYPTION_KEY = "UserWalletEncryptionKey"
|
private const val MESSAGE_FOR_ENCRYPTION_KEY = "UserWalletEncryptionKey"
|
||||||
|
|
@ -17,7 +17,7 @@ import com.tangem.core.analytics.Analytics
|
||||||
import com.tangem.core.analytics.models.Basic
|
import com.tangem.core.analytics.models.Basic
|
||||||
import com.tangem.core.analytics.models.Basic.TransactionSent.MemoType
|
import com.tangem.core.analytics.models.Basic.TransactionSent.MemoType
|
||||||
import com.tangem.data.walletconnect.network.ethereum.LegacySdkHelper
|
import com.tangem.data.walletconnect.network.ethereum.LegacySdkHelper
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.operations.sign.SignHashCommand
|
import com.tangem.operations.sign.SignHashCommand
|
||||||
import com.tangem.tap.common.extensions.inject
|
import com.tangem.tap.common.extensions.inject
|
||||||
import com.tangem.tap.common.extensions.safeUpdate
|
import com.tangem.tap.common.extensions.safeUpdate
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,12 @@ import com.reown.android.relay.ConnectionType
|
||||||
import com.reown.walletkit.client.Wallet
|
import com.reown.walletkit.client.Wallet
|
||||||
import com.reown.walletkit.client.WalletKit
|
import com.reown.walletkit.client.WalletKit
|
||||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||||
import com.tangem.data.walletconnect.pair.unsupportedDApps
|
import com.tangem.data.walletconnect.pair.UnsupportedDApps
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.walletconnect.WcPairService
|
import com.tangem.domain.walletconnect.WcPairService
|
||||||
import com.tangem.domain.walletconnect.model.WcPairRequest
|
import com.tangem.domain.walletconnect.model.WcPairRequest
|
||||||
import com.tangem.domain.walletconnect.model.legacy.Account
|
import com.tangem.domain.walletconnect.model.legacy.Account
|
||||||
import com.tangem.domain.walletconnect.usecase.initialize.WcInitializeUseCase
|
import com.tangem.domain.walletconnect.usecase.initialize.WcInitializeUseCase
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
|
||||||
import com.tangem.features.walletconnect.components.WalletConnectFeatureToggles
|
import com.tangem.features.walletconnect.components.WalletConnectFeatureToggles
|
||||||
import com.tangem.tap.common.analytics.events.WalletConnect
|
import com.tangem.tap.common.analytics.events.WalletConnect
|
||||||
import com.tangem.tap.domain.walletconnect2.app.TangemWcBlockchainHelper
|
import com.tangem.tap.domain.walletconnect2.app.TangemWcBlockchainHelper
|
||||||
|
|
@ -216,7 +216,7 @@ internal class DefaultLegacyWalletConnectRepository(
|
||||||
Timber.i("sessionProposal: $sessionProposal")
|
Timber.i("sessionProposal: $sessionProposal")
|
||||||
this@DefaultLegacyWalletConnectRepository.sessionProposal = sessionProposal
|
this@DefaultLegacyWalletConnectRepository.sessionProposal = sessionProposal
|
||||||
|
|
||||||
if (sessionProposal.name in unsupportedDApps) {
|
if (sessionProposal.name in UnsupportedDApps.list) {
|
||||||
Timber.i("Unsupported DApp")
|
Timber.i("Unsupported DApp")
|
||||||
scope.launch {
|
scope.launch {
|
||||||
_events.emit(
|
_events.emit(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.tangem.tap.domain.walletconnect2.domain
|
package com.tangem.tap.domain.walletconnect2.domain
|
||||||
|
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.walletconnect.model.legacy.Account
|
import com.tangem.domain.walletconnect.model.legacy.Account
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
|
||||||
import com.tangem.tap.domain.walletconnect2.domain.models.*
|
import com.tangem.tap.domain.walletconnect2.domain.models.*
|
||||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction.OpenSession.SourceType
|
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction.OpenSession.SourceType
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,15 @@ import com.tangem.blockchainsdk.utils.toBlockchain
|
||||||
import com.tangem.blockchainsdk.utils.toNetworkId
|
import com.tangem.blockchainsdk.utils.toNetworkId
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.network.Network
|
import com.tangem.domain.models.network.Network
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
import com.tangem.domain.models.wallet.isMultiCurrency
|
||||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.walletconnect.model.legacy.Account
|
import com.tangem.domain.walletconnect.model.legacy.Account
|
||||||
import com.tangem.domain.walletconnect.model.legacy.Session
|
import com.tangem.domain.walletconnect.model.legacy.Session
|
||||||
import com.tangem.domain.walletconnect.model.legacy.WalletConnectSessionsRepository
|
import com.tangem.domain.walletconnect.model.legacy.WalletConnectSessionsRepository
|
||||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
|
||||||
import com.tangem.domain.wallets.models.isMultiCurrency
|
|
||||||
import com.tangem.domain.wallets.models.requireColdWallet
|
|
||||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
|
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
|
||||||
import com.tangem.features.walletconnect.components.WalletConnectFeatureToggles
|
import com.tangem.features.walletconnect.components.WalletConnectFeatureToggles
|
||||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||||
|
|
@ -422,8 +421,7 @@ class WalletConnectInteractor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCardId(userWallet: UserWallet): String? {
|
private fun getCardId(userWallet: UserWallet): String? {
|
||||||
userWallet.requireColdWallet() // [REDACTED_TASK_KEY]
|
return if (userWallet is UserWallet.Cold && userWallet.scanResponse.card.backupStatus?.isActive != true) {
|
||||||
return if (userWallet.scanResponse.card.backupStatus?.isActive != true) {
|
|
||||||
userWallet.cardId
|
userWallet.cardId
|
||||||
} else { // if wallet has backup, any card from wallet can be used to sign
|
} else { // if wallet has backup, any card from wallet can be used to sign
|
||||||
null
|
null
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,6 @@ object DemoHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getScanResponse(appState: () -> AppState?): ScanResponse? {
|
private fun getScanResponse(appState: () -> AppState?): ScanResponse? {
|
||||||
val state = appState() ?: return null
|
return appState()?.globalState?.scanResponse
|
||||||
|
|
||||||
return state.globalState.onboardingState.onboardingManager?.scanResponse
|
|
||||||
?: state.globalState.scanResponse
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -9,7 +9,7 @@ import org.rekotlin.Action
|
||||||
sealed class DetailsAction : Action {
|
sealed class DetailsAction : Action {
|
||||||
|
|
||||||
data class PrepareScreen(
|
data class PrepareScreen(
|
||||||
val scanResponse: ScanResponse,
|
val scanResponse: ScanResponse?,
|
||||||
val initializedAppSettingsState: AppSettingsState,
|
val initializedAppSettingsState: AppSettingsState,
|
||||||
) : DetailsAction()
|
) : DetailsAction()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package com.tangem.tap.features.details.redux.walletconnect
|
package com.tangem.tap.features.details.redux.walletconnect
|
||||||
|
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.tap.domain.walletconnect2.domain.WcPreparedRequest
|
import com.tangem.tap.domain.walletconnect2.domain.WcPreparedRequest
|
||||||
import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectError
|
import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectError
|
||||||
import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectEvents
|
import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectEvents
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package com.tangem.tap.features.details.ui.cardsettings.api
|
||||||
|
|
||||||
import com.tangem.core.decompose.factory.ComponentFactory
|
import com.tangem.core.decompose.factory.ComponentFactory
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
|
||||||
interface CardSettingsComponent : ComposableContentComponent {
|
interface CardSettingsComponent : ComposableContentComponent {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,9 @@ import com.tangem.domain.common.util.cardTypesResolver
|
||||||
import com.tangem.domain.common.util.getBackupCardsCount
|
import com.tangem.domain.common.util.getBackupCardsCount
|
||||||
import com.tangem.domain.models.scan.CardDTO
|
import com.tangem.domain.models.scan.CardDTO
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
|
import com.tangem.domain.models.wallet.requireColdWallet
|
||||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||||
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
||||||
import com.tangem.domain.wallets.models.requireColdWallet
|
|
||||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||||
import com.tangem.sdk.api.TangemSdkManager
|
import com.tangem.sdk.api.TangemSdkManager
|
||||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||||
|
|
@ -27,7 +27,6 @@ import com.tangem.tap.common.analytics.events.Settings
|
||||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||||
import com.tangem.tap.common.redux.AppDialog
|
import com.tangem.tap.common.redux.AppDialog
|
||||||
import com.tangem.tap.domain.extensions.signedHashesCount
|
|
||||||
import com.tangem.tap.features.details.ui.cardsettings.CardInfo
|
import com.tangem.tap.features.details.ui.cardsettings.CardInfo
|
||||||
import com.tangem.tap.features.details.ui.cardsettings.CardSettingsScreenState
|
import com.tangem.tap.features.details.ui.cardsettings.CardSettingsScreenState
|
||||||
import com.tangem.tap.features.details.ui.cardsettings.api.CardSettingsComponent
|
import com.tangem.tap.features.details.ui.cardsettings.api.CardSettingsComponent
|
||||||
|
|
@ -171,6 +170,8 @@ internal class CardSettingsModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun CardDTO.signedHashesCount(): Int = wallets.sumOf { it.totalSignedHashes ?: 0 }
|
||||||
|
|
||||||
private fun handleClickingItem(item: CardInfo) {
|
private fun handleClickingItem(item: CardInfo) {
|
||||||
when (item) {
|
when (item) {
|
||||||
is CardInfo.ChangeAccessCode -> {
|
is CardInfo.ChangeAccessCode -> {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package com.tangem.tap.features.details.ui.resetcard.api
|
||||||
|
|
||||||
import com.tangem.core.decompose.factory.ComponentFactory
|
import com.tangem.core.decompose.factory.ComponentFactory
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
|
||||||
interface ResetCardComponent : ComposableContentComponent {
|
interface ResetCardComponent : ComposableContentComponent {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@ import com.tangem.domain.card.DeleteSavedAccessCodesUseCase
|
||||||
import com.tangem.domain.card.ResetCardUseCase
|
import com.tangem.domain.card.ResetCardUseCase
|
||||||
import com.tangem.domain.card.ResetCardUserCodeParams
|
import com.tangem.domain.card.ResetCardUserCodeParams
|
||||||
import com.tangem.domain.common.util.cardTypesResolver
|
import com.tangem.domain.common.util.cardTypesResolver
|
||||||
|
import com.tangem.domain.models.wallet.requireColdWallet
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
import com.tangem.domain.wallets.legacy.asLockable
|
import com.tangem.domain.wallets.legacy.asLockable
|
||||||
import com.tangem.domain.wallets.models.requireColdWallet
|
|
||||||
import com.tangem.domain.wallets.usecase.DeleteWalletUseCase
|
import com.tangem.domain.wallets.usecase.DeleteWalletUseCase
|
||||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package com.tangem.tap.features.details.ui.securitymode.api
|
||||||
|
|
||||||
import com.tangem.core.decompose.factory.ComponentFactory
|
import com.tangem.core.decompose.factory.ComponentFactory
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
|
||||||
interface SecurityModeComponent : ComposableContentComponent {
|
interface SecurityModeComponent : ComposableContentComponent {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import arrow.core.getOrElse
|
||||||
import com.tangem.core.decompose.di.ModelScoped
|
import com.tangem.core.decompose.di.ModelScoped
|
||||||
import com.tangem.core.decompose.model.Model
|
import com.tangem.core.decompose.model.Model
|
||||||
import com.tangem.core.decompose.model.ParamsContainer
|
import com.tangem.core.decompose.model.ParamsContainer
|
||||||
|
import com.tangem.domain.qrscanning.models.QrResultSource
|
||||||
import com.tangem.domain.qrscanning.models.SourceType
|
import com.tangem.domain.qrscanning.models.SourceType
|
||||||
import com.tangem.domain.qrscanning.usecases.ListenToQrScanningUseCase
|
import com.tangem.domain.qrscanning.usecases.ListenToQrScanningUseCase
|
||||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
|
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
|
||||||
|
|
@ -31,12 +32,18 @@ internal class WalletConnectModel @Inject constructor(
|
||||||
|
|
||||||
init {
|
init {
|
||||||
modelScope.launch {
|
modelScope.launch {
|
||||||
listenToQrScanningUseCase(SourceType.WALLET_CONNECT)
|
listenToQrScanningUseCase.listen(SourceType.WALLET_CONNECT)
|
||||||
.getOrElse { emptyFlow() }
|
.getOrElse { emptyFlow() }
|
||||||
.map {
|
.map { result ->
|
||||||
|
val source = when (result.resultSource) {
|
||||||
|
QrResultSource.CLIPBOARD -> WalletConnectAction.OpenSession.SourceType.CLIPBOARD
|
||||||
|
QrResultSource.CAMERA,
|
||||||
|
QrResultSource.GALLERY,
|
||||||
|
-> WalletConnectAction.OpenSession.SourceType.QR
|
||||||
|
}
|
||||||
WalletConnectAction.OpenSession(
|
WalletConnectAction.OpenSession(
|
||||||
wcUri = it,
|
wcUri = result.qrCode,
|
||||||
source = WalletConnectAction.OpenSession.SourceType.QR,
|
source = source,
|
||||||
userWalletId = params.userWalletId,
|
userWalletId = params.userWalletId,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package com.tangem.tap.features.details.ui.walletconnect.api
|
||||||
|
|
||||||
import com.tangem.core.decompose.factory.ComponentFactory
|
import com.tangem.core.decompose.factory.ComponentFactory
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
|
||||||
interface WalletConnectComponent : ComposableContentComponent {
|
interface WalletConnectComponent : ComposableContentComponent {
|
||||||
data class Params(val userWalletId: UserWalletId)
|
data class Params(val userWalletId: UserWalletId)
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import com.tangem.core.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.ui.components.SystemBarsIconsDisposable
|
import com.tangem.core.ui.components.SystemBarsIconsDisposable
|
||||||
import com.tangem.core.ui.utils.ChangeRootBackgroundColorEffect
|
import com.tangem.core.ui.utils.ChangeRootBackgroundColorEffect
|
||||||
import com.tangem.core.ui.utils.findActivity
|
import com.tangem.core.ui.utils.findActivity
|
||||||
|
import com.tangem.features.hotwallet.HotWalletFeatureToggles
|
||||||
import com.tangem.tap.common.redux.AppState
|
import com.tangem.tap.common.redux.AppState
|
||||||
import com.tangem.tap.features.home.api.HomeComponent
|
import com.tangem.tap.features.home.api.HomeComponent
|
||||||
import com.tangem.tap.features.home.compose.StoriesScreen
|
import com.tangem.tap.features.home.compose.StoriesScreen
|
||||||
|
|
@ -29,6 +30,7 @@ import org.rekotlin.StoreSubscriber
|
||||||
internal class DefaultHomeComponent @AssistedInject constructor(
|
internal class DefaultHomeComponent @AssistedInject constructor(
|
||||||
@Assisted appComponentContext: AppComponentContext,
|
@Assisted appComponentContext: AppComponentContext,
|
||||||
@Assisted params: Unit,
|
@Assisted params: Unit,
|
||||||
|
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
||||||
) : HomeComponent, AppComponentContext by appComponentContext, StoreSubscriber<HomeState> {
|
) : HomeComponent, AppComponentContext by appComponentContext, StoreSubscriber<HomeState> {
|
||||||
|
|
||||||
private val model: HomeModel = getOrCreateModel()
|
private val model: HomeModel = getOrCreateModel()
|
||||||
|
|
@ -58,7 +60,7 @@ internal class DefaultHomeComponent @AssistedInject constructor(
|
||||||
val activity = LocalContext.current.findActivity()
|
val activity = LocalContext.current.findActivity()
|
||||||
BackHandler(onBack = activity::finish)
|
BackHandler(onBack = activity::finish)
|
||||||
SystemBarsIconsDisposable(darkIcons = false)
|
SystemBarsIconsDisposable(darkIcons = false)
|
||||||
if (homeState.value.isV2StoriesEnabled) {
|
if (hotWalletFeatureToggles.isHotWalletEnabled) {
|
||||||
StoriesScreenV2(
|
StoriesScreenV2(
|
||||||
homeState = homeState,
|
homeState = homeState,
|
||||||
onCreateNewWalletButtonClick = model::onCreateNewWalletScreen,
|
onCreateNewWalletButtonClick = model::onCreateNewWalletScreen,
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.core.ui.res.TangemThemePreview
|
import com.tangem.core.ui.res.TangemThemePreview
|
||||||
import com.tangem.core.ui.test.TestTags
|
import com.tangem.core.ui.test.StoriesScreenTestTags
|
||||||
import com.tangem.tap.features.home.compose.content.*
|
import com.tangem.tap.features.home.compose.content.*
|
||||||
import com.tangem.tap.features.home.compose.views.HomeButtons
|
import com.tangem.tap.features.home.compose.views.HomeButtons
|
||||||
import com.tangem.tap.features.home.compose.views.SearchCurrenciesButton
|
import com.tangem.tap.features.home.compose.views.SearchCurrenciesButton
|
||||||
|
|
@ -61,7 +61,7 @@ internal fun StoriesScreen(
|
||||||
StoriesScreenContent(
|
StoriesScreenContent(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.testTag(TestTags.STORIES_SCREEN),
|
.testTag(StoriesScreenTestTags.SCREEN_CONTAINER),
|
||||||
config = StoriesScreenContentConfig(
|
config = StoriesScreenContentConfig(
|
||||||
storiesSize = state.stories.lastIndex,
|
storiesSize = state.stories.lastIndex,
|
||||||
currentStoryIndex = currentStoryIndex,
|
currentStoryIndex = currentStoryIndex,
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.core.ui.res.TangemThemePreview
|
import com.tangem.core.ui.res.TangemThemePreview
|
||||||
import com.tangem.core.ui.test.TestTags
|
import com.tangem.core.ui.test.StoriesScreenTestTags
|
||||||
import com.tangem.tap.features.home.compose.content.*
|
import com.tangem.tap.features.home.compose.content.*
|
||||||
import com.tangem.tap.features.home.compose.views.HomeButtonsV2
|
import com.tangem.tap.features.home.compose.views.HomeButtonsV2
|
||||||
import com.tangem.tap.features.home.compose.views.StoriesProgressBar
|
import com.tangem.tap.features.home.compose.views.StoriesProgressBar
|
||||||
|
|
@ -57,7 +57,7 @@ internal fun StoriesScreenV2(
|
||||||
StoriesScreenContentV2(
|
StoriesScreenContentV2(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.testTag(TestTags.STORIES_SCREEN),
|
.testTag(StoriesScreenTestTags.SCREEN_CONTAINER),
|
||||||
config = StoriesScreenContentV2Config(
|
config = StoriesScreenContentV2Config(
|
||||||
storiesSize = state.stories.lastIndex,
|
storiesSize = state.stories.lastIndex,
|
||||||
currentStoryIndex = currentStoryIndex,
|
currentStoryIndex = currentStoryIndex,
|
||||||
|
|
|
||||||
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